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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorLukas Tönne <lukas.toenne@gmail.com>2017-07-16 13:48:39 +0300
committerLukas Tönne <lukas.toenne@gmail.com>2017-07-16 13:48:39 +0300
commit65d2374c806ecf42ccf106cd28380e7a7071f789 (patch)
treed5344de03da74108de00a94b9c227296f25dd2cb /source
parentd3349e5e3fb4e5ddc7b7524aa806f726ae4728f6 (diff)
parenta3d9ef2ea50671267792df4a2c220ae157ea7a4c (diff)
Merge branch 'blender2.8' into strand_editmode2.8
Diffstat (limited to 'source')
-rw-r--r--source/CMakeLists.txt4
-rw-r--r--source/blender/CMakeLists.txt4
-rw-r--r--source/blender/alembic/ABC_alembic.h72
-rw-r--r--source/blender/alembic/CMakeLists.txt11
-rw-r--r--source/blender/alembic/intern/abc_archive.cc208
-rw-r--r--source/blender/alembic/intern/abc_archive.h75
-rw-r--r--source/blender/alembic/intern/abc_camera.cc44
-rw-r--r--source/blender/alembic/intern/abc_camera.h7
-rw-r--r--source/blender/alembic/intern/abc_curves.cc132
-rw-r--r--source/blender/alembic/intern/abc_curves.h15
-rw-r--r--source/blender/alembic/intern/abc_customdata.cc172
-rw-r--r--source/blender/alembic/intern/abc_customdata.h10
-rw-r--r--source/blender/alembic/intern/abc_exporter.cc408
-rw-r--r--source/blender/alembic/intern/abc_exporter.h45
-rw-r--r--source/blender/alembic/intern/abc_hair.cc52
-rw-r--r--source/blender/alembic/intern/abc_hair.h2
-rw-r--r--source/blender/alembic/intern/abc_mesh.cc610
-rw-r--r--source/blender/alembic/intern/abc_mesh.h42
-rw-r--r--source/blender/alembic/intern/abc_nurbs.cc9
-rw-r--r--source/blender/alembic/intern/abc_nurbs.h2
-rw-r--r--source/blender/alembic/intern/abc_object.cc233
-rw-r--r--source/blender/alembic/intern/abc_object.h68
-rw-r--r--source/blender/alembic/intern/abc_points.cc64
-rw-r--r--source/blender/alembic/intern/abc_points.h15
-rw-r--r--source/blender/alembic/intern/abc_transform.cc60
-rw-r--r--source/blender/alembic/intern/abc_transform.h11
-rw-r--r--source/blender/alembic/intern/abc_util.cc474
-rw-r--r--source/blender/alembic/intern/abc_util.h156
-rw-r--r--source/blender/alembic/intern/alembic_capi.cc1043
-rw-r--r--source/blender/blenfont/BLF_api.h36
-rw-r--r--source/blender/blenfont/intern/blf.c237
-rw-r--r--source/blender/blenfont/intern/blf_font.c44
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c147
-rw-r--r--source/blender/blenfont/intern/blf_internal.h5
-rw-r--r--source/blender/blenfont/intern/blf_internal_types.h8
-rw-r--r--source/blender/blenfont/intern/blf_thumbs.c4
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h32
-rw-r--r--source/blender/blenkernel/BKE_action.h4
-rw-r--r--source/blender/blenkernel/BKE_animsys.h10
-rw-r--r--source/blender/blenkernel/BKE_appdir.h5
-rw-r--r--source/blender/blenkernel/BKE_armature.h4
-rw-r--r--source/blender/blenkernel/BKE_blender.h13
-rw-r--r--source/blender/blenkernel/BKE_blender_copybuffer.h1
-rw-r--r--source/blender/blenkernel/BKE_blender_undo.h1
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h4
-rw-r--r--source/blender/blenkernel/BKE_blendfile.h24
-rw-r--r--source/blender/blenkernel/BKE_boids.h2
-rw-r--r--source/blender/blenkernel/BKE_brush.h2
-rw-r--r--source/blender/blenkernel/BKE_bvhutils.h16
-rw-r--r--source/blender/blenkernel/BKE_cachefile.h9
-rw-r--r--source/blender/blenkernel/BKE_camera.h5
-rw-r--r--source/blender/blenkernel/BKE_cdderivedmesh.h1
-rw-r--r--source/blender/blenkernel/BKE_cloth.h6
-rw-r--r--source/blender/blenkernel/BKE_collection.h100
-rw-r--r--source/blender/blenkernel/BKE_collision.h4
-rw-r--r--source/blender/blenkernel/BKE_colortools.h4
-rw-r--r--source/blender/blenkernel/BKE_constraint.h1
-rw-r--r--source/blender/blenkernel/BKE_context.h11
-rw-r--r--source/blender/blenkernel/BKE_curve.h26
-rw-r--r--source/blender/blenkernel/BKE_customdata.h11
-rw-r--r--source/blender/blenkernel/BKE_deform.h13
-rw-r--r--source/blender/blenkernel/BKE_depsgraph.h181
-rw-r--r--source/blender/blenkernel/BKE_dynamicpaint.h6
-rw-r--r--source/blender/blenkernel/BKE_editmesh.h1
-rw-r--r--source/blender/blenkernel/BKE_editmesh_tangent.h40
-rw-r--r--source/blender/blenkernel/BKE_effect.h18
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h14
-rw-r--r--source/blender/blenkernel/BKE_font.h3
-rw-r--r--source/blender/blenkernel/BKE_freestyle.h3
-rw-r--r--source/blender/blenkernel/BKE_global.h8
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h4
-rw-r--r--source/blender/blenkernel/BKE_group.h7
-rw-r--r--source/blender/blenkernel/BKE_icons.h7
-rw-r--r--source/blender/blenkernel/BKE_idprop.h13
-rw-r--r--source/blender/blenkernel/BKE_image.h2
-rw-r--r--source/blender/blenkernel/BKE_key.h2
-rw-r--r--source/blender/blenkernel/BKE_lamp.h2
-rw-r--r--source/blender/blenkernel/BKE_lattice.h10
-rw-r--r--source/blender/blenkernel/BKE_layer.h257
-rw-r--r--source/blender/blenkernel/BKE_library.h29
-rw-r--r--source/blender/blenkernel/BKE_library_query.h41
-rw-r--r--source/blender/blenkernel/BKE_library_remap.h8
-rw-r--r--source/blender/blenkernel/BKE_lightprobe.h45
-rw-r--r--source/blender/blenkernel/BKE_linestyle.h18
-rw-r--r--source/blender/blenkernel/BKE_main.h25
-rw-r--r--source/blender/blenkernel/BKE_mask.h8
-rw-r--r--source/blender/blenkernel/BKE_material.h19
-rw-r--r--source/blender/blenkernel/BKE_mball.h2
-rw-r--r--source/blender/blenkernel/BKE_mesh.h33
-rw-r--r--source/blender/blenkernel/BKE_mesh_tangent.h61
-rw-r--r--source/blender/blenkernel/BKE_modifier.h15
-rw-r--r--source/blender/blenkernel/BKE_movieclip.h2
-rw-r--r--source/blender/blenkernel/BKE_node.h23
-rw-r--r--source/blender/blenkernel/BKE_object.h45
-rw-r--r--source/blender/blenkernel/BKE_object_deform.h2
-rw-r--r--source/blender/blenkernel/BKE_object_facemap.h53
-rw-r--r--source/blender/blenkernel/BKE_outliner_treehash.h3
-rw-r--r--source/blender/blenkernel/BKE_paint.h11
-rw-r--r--source/blender/blenkernel/BKE_particle.h13
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h5
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h2
-rw-r--r--source/blender/blenkernel/BKE_property.h4
-rw-r--r--source/blender/blenkernel/BKE_rigidbody.h7
-rw-r--r--source/blender/blenkernel/BKE_sca.h18
-rw-r--r--source/blender/blenkernel/BKE_scene.h49
-rw-r--r--source/blender/blenkernel/BKE_screen.h26
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h2
-rw-r--r--source/blender/blenkernel/BKE_smoke.h2
-rw-r--r--source/blender/blenkernel/BKE_softbody.h3
-rw-r--r--source/blender/blenkernel/BKE_sound.h2
-rw-r--r--source/blender/blenkernel/BKE_speaker.h2
-rw-r--r--source/blender/blenkernel/BKE_text.h2
-rw-r--r--source/blender/blenkernel/BKE_texture.h17
-rw-r--r--source/blender/blenkernel/BKE_tracking.h6
-rw-r--r--source/blender/blenkernel/BKE_workspace.h121
-rw-r--r--source/blender/blenkernel/BKE_world.h2
-rw-r--r--source/blender/blenkernel/CMakeLists.txt22
-rw-r--r--source/blender/blenkernel/depsgraph_private.h159
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.c2
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c4
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c644
-rw-r--r--source/blender/blenkernel/intern/action.c21
-rw-r--r--source/blender/blenkernel/intern/anim.c59
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c101
-rw-r--r--source/blender/blenkernel/intern/appdir.c178
-rw-r--r--source/blender/blenkernel/intern/armature.c33
-rw-r--r--source/blender/blenkernel/intern/armature_update.c37
-rw-r--r--source/blender/blenkernel/intern/blender.c133
-rw-r--r--source/blender/blenkernel/intern/blender_copybuffer.c36
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c18
-rw-r--r--source/blender/blenkernel/intern/blendfile.c207
-rw-r--r--source/blender/blenkernel/intern/boids.c2
-rw-r--r--source/blender/blenkernel/intern/bpath.c2
-rw-r--r--source/blender/blenkernel/intern/brush.c9
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c422
-rw-r--r--source/blender/blenkernel/intern/cachefile.c75
-rw-r--r--source/blender/blenkernel/intern/camera.c12
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c651
-rw-r--r--source/blender/blenkernel/intern/cloth.c51
-rw-r--r--source/blender/blenkernel/intern/collection.c648
-rw-r--r--source/blender/blenkernel/intern/collision.c37
-rw-r--r--source/blender/blenkernel/intern/colortools.c6
-rw-r--r--source/blender/blenkernel/intern/constraint.c69
-rw-r--r--source/blender/blenkernel/intern/context.c95
-rw-r--r--source/blender/blenkernel/intern/curve.c90
-rw-r--r--source/blender/blenkernel/intern/customdata.c188
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c38
-rw-r--r--source/blender/blenkernel/intern/deform.c194
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c3695
-rw-r--r--source/blender/blenkernel/intern/displist.c20
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c661
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c725
-rw-r--r--source/blender/blenkernel/intern/editmesh.c20
-rw-r--r--source/blender/blenkernel/intern/editmesh_tangent.c428
-rw-r--r--source/blender/blenkernel/intern/editstrands.c6
-rw-r--r--source/blender/blenkernel/intern/effect.c100
-rw-r--r--source/blender/blenkernel/intern/fcurve.c153
-rw-r--r--source/blender/blenkernel/intern/fmodifier.c14
-rw-r--r--source/blender/blenkernel/intern/font.c10
-rw-r--r--source/blender/blenkernel/intern/freestyle.c23
-rw-r--r--source/blender/blenkernel/intern/gpencil.c20
-rw-r--r--source/blender/blenkernel/intern/group.c25
-rw-r--r--source/blender/blenkernel/intern/icons.c28
-rw-r--r--source/blender/blenkernel/intern/idcode.c9
-rw-r--r--source/blender/blenkernel/intern/idprop.c202
-rw-r--r--source/blender/blenkernel/intern/image.c87
-rw-r--r--source/blender/blenkernel/intern/ipo.c1
-rw-r--r--source/blender/blenkernel/intern/key.c3
-rw-r--r--source/blender/blenkernel/intern/lamp.c13
-rw-r--r--source/blender/blenkernel/intern/lattice.c25
-rw-r--r--source/blender/blenkernel/intern/layer.c1828
-rw-r--r--source/blender/blenkernel/intern/library.c863
-rw-r--r--source/blender/blenkernel/intern/library_query.c727
-rw-r--r--source/blender/blenkernel/intern/library_remap.c300
-rw-r--r--source/blender/blenkernel/intern/lightprobe.c88
-rw-r--r--source/blender/blenkernel/intern/linestyle.c43
-rw-r--r--source/blender/blenkernel/intern/mask.c14
-rw-r--r--source/blender/blenkernel/intern/material.c552
-rw-r--r--source/blender/blenkernel/intern/mball.c42
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c20
-rw-r--r--source/blender/blenkernel/intern/mesh.c592
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c692
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.c2
-rw-r--r--source/blender/blenkernel/intern/mesh_sample.c8
-rw-r--r--source/blender/blenkernel/intern/mesh_tangent.c692
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c88
-rw-r--r--source/blender/blenkernel/intern/modifier.c3
-rw-r--r--source/blender/blenkernel/intern/movieclip.c11
-rw-r--r--source/blender/blenkernel/intern/nla.c2
-rw-r--r--source/blender/blenkernel/intern/node.c95
-rw-r--r--source/blender/blenkernel/intern/object.c311
-rw-r--r--source/blender/blenkernel/intern/object_deform.c28
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c61
-rw-r--r--source/blender/blenkernel/intern/object_facemap.c257
-rw-r--r--source/blender/blenkernel/intern/object_update.c98
-rw-r--r--source/blender/blenkernel/intern/ocean.c18
-rw-r--r--source/blender/blenkernel/intern/outliner_treehash.c39
-rw-r--r--source/blender/blenkernel/intern/packedFile.c4
-rw-r--r--source/blender/blenkernel/intern/paint.c44
-rw-r--r--source/blender/blenkernel/intern/particle.c141
-rw-r--r--source/blender/blenkernel/intern/particle_child.c10
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c36
-rw-r--r--source/blender/blenkernel/intern/particle_system.c35
-rw-r--r--source/blender/blenkernel/intern/pbvh.c173
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c19
-rw-r--r--source/blender/blenkernel/intern/pointcache.c29
-rw-r--r--source/blender/blenkernel/intern/property.c4
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c141
-rw-r--r--source/blender/blenkernel/intern/sca.c229
-rw-r--r--source/blender/blenkernel/intern/scene.c1065
-rw-r--r--source/blender/blenkernel/intern/screen.c84
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c53
-rw-r--r--source/blender/blenkernel/intern/seqmodifier.c17
-rw-r--r--source/blender/blenkernel/intern/sequencer.c124
-rw-r--r--source/blender/blenkernel/intern/smoke.c82
-rw-r--r--source/blender/blenkernel/intern/softbody.c74
-rw-r--r--source/blender/blenkernel/intern/sound.c39
-rw-r--r--source/blender/blenkernel/intern/speaker.c2
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c426
-rw-r--r--source/blender/blenkernel/intern/text.c27
-rw-r--r--source/blender/blenkernel/intern/texture.c55
-rw-r--r--source/blender/blenkernel/intern/tracking.c102
-rw-r--r--source/blender/blenkernel/intern/tracking_auto.c17
-rw-r--r--source/blender/blenkernel/intern/tracking_stabilize.c1644
-rw-r--r--source/blender/blenkernel/intern/tracking_util.c86
-rw-r--r--source/blender/blenkernel/intern/workspace.c432
-rw-r--r--source/blender/blenkernel/intern/world.c4
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c127
-rw-r--r--source/blender/blenkernel/intern/writeframeserver.c4
-rw-r--r--source/blender/blenkernel/tracking_private.h11
-rw-r--r--source/blender/blenlib/BLI_alloca.h4
-rw-r--r--source/blender/blenlib/BLI_array.h4
-rw-r--r--source/blender/blenlib/BLI_bitmap_draw_2d.h37
-rw-r--r--source/blender/blenlib/BLI_callbacks.h2
-rw-r--r--source/blender/blenlib/BLI_compiler_attrs.h8
-rw-r--r--source/blender/blenlib/BLI_compiler_compat.h5
-rw-r--r--source/blender/blenlib/BLI_dynlib.h2
-rw-r--r--source/blender/blenlib/BLI_dynstr.h6
-rw-r--r--source/blender/blenlib/BLI_fileops.h4
-rw-r--r--source/blender/blenlib/BLI_fileops_types.h6
-rw-r--r--source/blender/blenlib/BLI_ghash.h22
-rw-r--r--source/blender/blenlib/BLI_hash.h66
-rw-r--r--source/blender/blenlib/BLI_iterator.h55
-rw-r--r--source/blender/blenlib/BLI_kdopbvh.h20
-rw-r--r--source/blender/blenlib/BLI_listbase.h8
-rw-r--r--source/blender/blenlib/BLI_math_base.h57
-rw-r--r--source/blender/blenlib/BLI_math_color.h4
-rw-r--r--source/blender/blenlib/BLI_math_geom.h37
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h193
-rw-r--r--source/blender/blenlib/BLI_math_rotation.h11
-rw-r--r--source/blender/blenlib/BLI_math_vector.h10
-rw-r--r--source/blender/blenlib/BLI_path_util.h34
-rw-r--r--source/blender/blenlib/BLI_rect.h3
-rw-r--r--source/blender/blenlib/BLI_stack.h8
-rw-r--r--source/blender/blenlib/BLI_strict_flags.h2
-rw-r--r--source/blender/blenlib/BLI_string_utf8.h4
-rw-r--r--source/blender/blenlib/BLI_string_utils.h63
-rw-r--r--source/blender/blenlib/BLI_sys_types.h9
-rw-r--r--source/blender/blenlib/BLI_system.h5
-rw-r--r--source/blender/blenlib/BLI_task.h17
-rw-r--r--source/blender/blenlib/BLI_utildefines.h5
-rw-r--r--source/blender/blenlib/BLI_winstuff.h29
-rw-r--r--source/blender/blenlib/CMakeLists.txt6
-rw-r--r--source/blender/blenlib/PIL_time_utildefines.h5
-rw-r--r--source/blender/blenlib/intern/BLI_dynstr.c70
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c19
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c624
-rw-r--r--source/blender/blenlib/intern/array_store.c79
-rw-r--r--source/blender/blenlib/intern/astar.c2
-rw-r--r--source/blender/blenlib/intern/bitmap_draw_2d.c336
-rw-r--r--source/blender/blenlib/intern/dynlib.c4
-rw-r--r--source/blender/blenlib/intern/fileops.c5
-rw-r--r--source/blender/blenlib/intern/hash_mm2a.c6
-rw-r--r--source/blender/blenlib/intern/listbase.c102
-rw-r--r--source/blender/blenlib/intern/math_color.c6
-rw-r--r--source/blender/blenlib/intern/math_color_blend_inline.c2
-rw-r--r--source/blender/blenlib/intern/math_color_inline.c10
-rw-r--r--source/blender/blenlib/intern/math_geom.c479
-rw-r--r--source/blender/blenlib/intern/math_matrix.c381
-rw-r--r--source/blender/blenlib/intern/math_rotation.c62
-rw-r--r--source/blender/blenlib/intern/math_vector.c109
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c29
-rw-r--r--source/blender/blenlib/intern/noise.c10
-rw-r--r--source/blender/blenlib/intern/path_util.c354
-rw-r--r--source/blender/blenlib/intern/polyfill2d.c113
-rw-r--r--source/blender/blenlib/intern/polyfill2d_beautify.c5
-rw-r--r--source/blender/blenlib/intern/rct.c36
-rw-r--r--source/blender/blenlib/intern/scanfill_utils.c14
-rw-r--r--source/blender/blenlib/intern/smallhash.c2
-rw-r--r--source/blender/blenlib/intern/storage.c32
-rw-r--r--source/blender/blenlib/intern/string.c4
-rw-r--r--source/blender/blenlib/intern/string_utf8.c163
-rw-r--r--source/blender/blenlib/intern/string_utils.c385
-rw-r--r--source/blender/blenlib/intern/system.c3
-rw-r--r--source/blender/blenlib/intern/task.c470
-rw-r--r--source/blender/blenlib/intern/threads.c44
-rw-r--r--source/blender/blenlib/intern/winstuff.c2
-rw-r--r--source/blender/blenloader/BLO_readfile.h45
-rw-r--r--source/blender/blenloader/CMakeLists.txt8
-rw-r--r--source/blender/blenloader/intern/readblenentry.c15
-rw-r--r--source/blender/blenloader/intern/readfile.c2027
-rw-r--r--source/blender/blenloader/intern/readfile.h8
-rw-r--r--source/blender/blenloader/intern/versioning_250.c4
-rw-r--r--source/blender/blenloader/intern/versioning_260.c4
-rw-r--r--source/blender/blenloader/intern/versioning_270.c412
-rw-r--r--source/blender/blenloader/intern/versioning_280.c451
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c60
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c84
-rw-r--r--source/blender/blenloader/intern/writefile.c2453
-rw-r--r--source/blender/blentranslation/BLT_translation.h4
-rw-r--r--source/blender/blentranslation/CMakeLists.txt2
-rw-r--r--source/blender/blentranslation/msgfmt/CMakeLists.txt50
-rw-r--r--source/blender/blentranslation/msgfmt/msgfmt.c464
-rw-r--r--source/blender/bmesh/CMakeLists.txt2
-rw-r--r--source/blender/bmesh/bmesh.h5
-rw-r--r--source/blender/bmesh/bmesh_class.h6
-rw-r--r--source/blender/bmesh/bmesh_tools.h1
-rw-r--r--source/blender/bmesh/intern/bmesh_callback_generic.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.c40
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.h9
-rw-r--r--source/blender/bmesh/intern/bmesh_core.c416
-rw-r--r--source/blender/bmesh/intern/bmesh_core.h52
-rw-r--r--source/blender/bmesh/intern/bmesh_edgeloop.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.c8
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.h4
-rw-r--r--source/blender/bmesh/intern/bmesh_log.c70
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c142
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c161
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.h8
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_conv.c49
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_conv.h8
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_validate.c15
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.c157
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.h9
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c10
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.c18
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.h17
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c34
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.h2
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon_edgenet.c103
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon_edgenet.h4
-rw-r--r--source/blender/bmesh/intern/bmesh_private.h2
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.c147
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.h10
-rw-r--r--source/blender/bmesh/intern/bmesh_strands_conv.c21
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.c114
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.h6
-rw-r--r--source/blender/bmesh/operators/bmo_bevel.c2
-rw-r--r--source/blender/bmesh/operators/bmo_bisect_plane.c7
-rw-r--r--source/blender/bmesh/operators/bmo_bridge.c6
-rw-r--r--source/blender/bmesh/operators/bmo_connect.c2
-rw-r--r--source/blender/bmesh/operators/bmo_connect_nonplanar.c4
-rw-r--r--source/blender/bmesh/operators/bmo_connect_pair.c24
-rw-r--r--source/blender/bmesh/operators/bmo_create.c24
-rw-r--r--source/blender/bmesh/operators/bmo_dissolve.c14
-rw-r--r--source/blender/bmesh/operators/bmo_dupe.c6
-rw-r--r--source/blender/bmesh/operators/bmo_fill_attribute.c4
-rw-r--r--source/blender/bmesh/operators/bmo_fill_edgeloop.c2
-rw-r--r--source/blender/bmesh/operators/bmo_fill_grid.c20
-rw-r--r--source/blender/bmesh/operators/bmo_fill_holes.c2
-rw-r--r--source/blender/bmesh/operators/bmo_hull.c3
-rw-r--r--source/blender/bmesh/operators/bmo_inset.c16
-rw-r--r--source/blender/bmesh/operators/bmo_join_triangles.c22
-rw-r--r--source/blender/bmesh/operators/bmo_offset_edgeloops.c4
-rw-r--r--source/blender/bmesh/operators/bmo_primitive.c743
-rw-r--r--source/blender/bmesh/operators/bmo_removedoubles.c23
-rw-r--r--source/blender/bmesh/operators/bmo_similar.c64
-rw-r--r--source/blender/bmesh/operators/bmo_smooth_laplacian.c6
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide_edgering.c26
-rw-r--r--source/blender/bmesh/operators/bmo_triangulate.c15
-rw-r--r--source/blender/bmesh/tools/bmesh_beautify.c4
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c217
-rw-r--r--source/blender/bmesh/tools/bmesh_bisect_plane.c55
-rw-r--r--source/blender/bmesh/tools/bmesh_bisect_plane.h2
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_collapse.c10
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_dissolve.c4
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c30
-rw-r--r--source/blender/bmesh/tools/bmesh_edgenet.c40
-rw-r--r--source/blender/bmesh/tools/bmesh_edgesplit.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.c83
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.h2
-rw-r--r--source/blender/bmesh/tools/bmesh_path.h4
-rw-r--r--source/blender/bmesh/tools/bmesh_region_match.c98
-rw-r--r--source/blender/bmesh/tools/bmesh_region_match.h2
-rw-r--r--source/blender/bmesh/tools/bmesh_separate.c133
-rw-r--r--source/blender/bmesh/tools/bmesh_separate.h32
-rw-r--r--source/blender/collada/AnimationExporter.cpp2
-rw-r--r--source/blender/collada/AnimationImporter.cpp10
-rw-r--r--source/blender/collada/ArmatureExporter.cpp89
-rw-r--r--source/blender/collada/ArmatureExporter.h2
-rw-r--r--source/blender/collada/ArmatureImporter.cpp191
-rw-r--r--source/blender/collada/ArmatureImporter.h12
-rw-r--r--source/blender/collada/CMakeLists.txt1
-rw-r--r--source/blender/collada/ControllerExporter.cpp120
-rw-r--r--source/blender/collada/ControllerExporter.h2
-rw-r--r--source/blender/collada/DocumentImporter.cpp25
-rw-r--r--source/blender/collada/EffectExporter.cpp67
-rw-r--r--source/blender/collada/ErrorHandler.cpp9
-rw-r--r--source/blender/collada/ExportSettings.h4
-rw-r--r--source/blender/collada/ImageExporter.cpp56
-rw-r--r--source/blender/collada/ImageExporter.h1
-rw-r--r--source/blender/collada/ImportSettings.h1
-rw-r--r--source/blender/collada/MeshImporter.cpp61
-rw-r--r--source/blender/collada/MeshImporter.h10
-rw-r--r--source/blender/collada/SkinInfo.cpp7
-rw-r--r--source/blender/collada/TransformReader.cpp23
-rw-r--r--source/blender/collada/TransformReader.h5
-rw-r--r--source/blender/collada/TransformWriter.cpp13
-rw-r--r--source/blender/collada/TransformWriter.h3
-rw-r--r--source/blender/collada/collada.cpp16
-rw-r--r--source/blender/collada/collada.h15
-rw-r--r--source/blender/collada/collada_internal.cpp26
-rw-r--r--source/blender/collada/collada_internal.h7
-rw-r--r--source/blender/collada/collada_utils.cpp267
-rw-r--r--source/blender/collada/collada_utils.h34
-rw-r--r--source/blender/compositor/CMakeLists.txt4
-rw-r--r--source/blender/compositor/COM_compositor.h13
-rw-r--r--source/blender/compositor/intern/COM_ExecutionGroup.cpp2
-rw-r--r--source/blender/compositor/intern/COM_WorkScheduler.cpp105
-rw-r--r--source/blender/compositor/nodes/COM_BrightnessNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp1
-rw-r--r--source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp17
-rw-r--r--source/blender/compositor/nodes/COM_ImageNode.cpp45
-rw-r--r--source/blender/compositor/nodes/COM_MovieClipNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_RenderLayersNode.cpp87
-rw-r--r--source/blender/compositor/nodes/COM_RenderLayersNode.h8
-rw-r--r--source/blender/compositor/operations/COM_BrightnessOperation.cpp14
-rw-r--r--source/blender/compositor/operations/COM_BrightnessOperation.h3
-rw-r--r--source/blender/compositor/operations/COM_ChangeHSVOperation.cpp19
-rw-r--r--source/blender/compositor/operations/COM_ChangeHSVOperation.h11
-rw-r--r--source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_DifferenceMatteOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp7
-rw-r--r--source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp16
-rw-r--r--source/blender/compositor/operations/COM_GlareStreaksOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_PlaneTrackOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.cpp186
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.h122
-rw-r--r--source/blender/compositor/operations/COM_SunBeamsOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.cpp43
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp6
-rw-r--r--source/blender/datatoc/CMakeLists.txt5
-rw-r--r--source/blender/depsgraph/CMakeLists.txt19
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h63
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h116
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h78
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc94
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.h7
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cycle.cc77
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc1065
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h88
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_layer.cc127
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc336
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc147
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc1528
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h218
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc204
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_layer.cc127
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc452
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc141
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_transitive.cc6
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc139
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc174
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h55
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc189
-rw-r--r--source/blender/depsgraph/intern/depsgraph_debug.cc10
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc48
-rw-r--r--source/blender/depsgraph/intern/depsgraph_intern.h12
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query.cc197
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc126
-rw-r--r--source/blender/depsgraph/intern/depsgraph_type_defines.cc29
-rw-r--r--source/blender/depsgraph/intern/depsgraph_types.h206
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc191
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.h3
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc664
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h84
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_debug.cc29
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_debug.h4
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.cc149
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node.cc176
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node.h87
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_component.cc153
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_component.h73
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_operation.cc25
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_operation.h20
-rw-r--r--source/blender/depsgraph/util/deg_util_foreach.h30
-rw-r--r--source/blender/depsgraph/util/deg_util_function.h61
-rw-r--r--source/blender/draw/CMakeLists.txt199
-rw-r--r--source/blender/draw/DRW_engine.h97
-rw-r--r--source/blender/draw/engines/basic/basic_engine.c257
-rw-r--r--source/blender/draw/engines/basic/basic_engine.h32
-rw-r--r--source/blender/draw/engines/clay/clay_engine.c945
-rw-r--r--source/blender/draw/engines/clay/clay_engine.h36
-rw-r--r--source/blender/draw/engines/clay/shaders/clay_frag.glsl201
-rw-r--r--source/blender/draw/engines/clay/shaders/clay_particle_strand_frag.glsl144
-rw-r--r--source/blender/draw/engines/clay/shaders/clay_particle_vert.glsl34
-rw-r--r--source/blender/draw/engines/clay/shaders/clay_vert.glsl17
-rw-r--r--source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl78
-rw-r--r--source/blender/draw/engines/clay/shaders/ssao_groundtruth.glsl122
-rw-r--r--source/blender/draw/engines/eevee/eevee_data.c128
-rw-r--r--source/blender/draw/engines/eevee/eevee_effects.c895
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c251
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.h31
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightprobes.c1345
-rw-r--r--source/blender/draw/engines/eevee/eevee_lights.c821
-rw-r--r--source/blender/draw/engines/eevee/eevee_lut.h5400
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c1158
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h534
-rw-r--r--source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl242
-rw-r--r--source/blender/draw/engines/eevee/shaders/background_vert.glsl20
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl414
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl180
-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.glsl73
-rw-r--r--source/blender/draw/engines/eevee/shaders/default_frag.glsl20
-rw-r--r--source/blender/draw/engines/eevee/shaders/default_world_frag.glsl9
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl210
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl261
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_geom.glsl55
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_vert.glsl99
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl66
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl65
-rw-r--r--source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl141
-rw-r--r--source/blender/draw/engines/eevee/shaders/lamps_lib.glsl195
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl15
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl22
-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.glsl86
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_geom.glsl33
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_frag.glsl11
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl35
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl245
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_frag.glsl29
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl13
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl27
-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.glsl489
-rw-r--r--source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl40
-rw-r--r--source/blender/draw/engines/eevee/shaders/ltc_lib.glsl234
-rw-r--r--source/blender/draw/engines/eevee/shaders/octahedron_lib.glsl38
-rw-r--r--source/blender/draw/engines/eevee/shaders/prepass_frag.glsl94
-rw-r--r--source/blender/draw/engines/eevee/shaders/prepass_vert.glsl18
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_frag.glsl17
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_geom.glsl50
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl113
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_store_geom.glsl24
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_store_vert.glsl8
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_vert.glsl29
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl396
-rw-r--r--source/blender/draw/engines/external/external_engine.c232
-rw-r--r--source/blender/draw/engines/external/external_engine.h31
-rw-r--r--source/blender/draw/intern/DRW_render.h416
-rw-r--r--source/blender/draw/intern/draw_armature.c1442
-rw-r--r--source/blender/draw/intern/draw_cache.c2586
-rw-r--r--source/blender/draw/intern/draw_cache.h159
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h105
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curve.c1047
-rw-r--r--source/blender/draw/intern/draw_cache_impl_displist.c168
-rw-r--r--source/blender/draw/intern/draw_cache_impl_lattice.c587
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c3472
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c519
-rw-r--r--source/blender/draw/intern/draw_common.c449
-rw-r--r--source/blender/draw/intern/draw_common.h131
-rw-r--r--source/blender/draw/intern/draw_manager.c3580
-rw-r--r--source/blender/draw/intern/draw_manager_text.c199
-rw-r--r--source/blender/draw/intern/draw_manager_text.h54
-rw-r--r--source/blender/draw/intern/draw_view.c732
-rw-r--r--source/blender/draw/intern/draw_view.h35
-rw-r--r--source/blender/draw/modes/draw_mode_engines.h44
-rw-r--r--source/blender/draw/modes/edit_armature_mode.c151
-rw-r--r--source/blender/draw/modes/edit_curve_mode.c329
-rw-r--r--source/blender/draw/modes/edit_lattice_mode.c292
-rw-r--r--source/blender/draw/modes/edit_mesh_mode.c584
-rw-r--r--source/blender/draw/modes/edit_metaball_mode.c268
-rw-r--r--source/blender/draw/modes/edit_surface_mode.c268
-rw-r--r--source/blender/draw/modes/edit_text_mode.c311
-rw-r--r--source/blender/draw/modes/object_mode.c1908
-rw-r--r--source/blender/draw/modes/paint_texture_mode.c416
-rw-r--r--source/blender/draw/modes/paint_vertex_mode.c215
-rw-r--r--source/blender/draw/modes/paint_weight_mode.c253
-rw-r--r--source/blender/draw/modes/particle_mode.c263
-rw-r--r--source/blender/draw/modes/pose_mode.c197
-rw-r--r--source/blender/draw/modes/sculpt_mode.c299
-rw-r--r--source/blender/draw/modes/shaders/common_globals_lib.glsl58
-rw-r--r--source/blender/draw/modes/shaders/edit_curve_overlay_frag.glsl22
-rw-r--r--source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl39
-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_facedot_frag.glsl12
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_vert.glsl14
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl29
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_vert.glsl29
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl187
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_geom_edge.glsl143
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl277
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_loosevert_vert.glsl59
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_mix_frag.glsl24
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl23
-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_image_frag.glsl21
-rw-r--r--source/blender/draw/modes/shaders/object_empty_image_vert.glsl38
-rw-r--r--source/blender/draw/modes/shaders/object_grid_frag.glsl189
-rw-r--r--source/blender/draw/modes/shaders/object_grid_vert.glsl63
-rw-r--r--source/blender/draw/modes/shaders/object_outline_detect_frag.glsl61
-rw-r--r--source/blender/draw/modes/shaders/object_outline_expand_frag.glsl45
-rw-r--r--source/blender/draw/modes/shaders/object_outline_resolve_frag.glsl11
-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_frag.glsl9
-rw-r--r--source/blender/draw/modes/shaders/object_particle_prim_vert.glsl54
-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_wire_frag.glsl24
-rw-r--r--source/blender/draw/modes/shaders/paint_wire_vert.glsl14
-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.c310
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c33
-rw-r--r--source/blender/editors/animation/anim_deps.c35
-rw-r--r--source/blender/editors/animation/anim_draw.c183
-rw-r--r--source/blender/editors/animation/anim_filter.c133
-rw-r--r--source/blender/editors/animation/anim_markers.c84
-rw-r--r--source/blender/editors/animation/anim_ops.c35
-rw-r--r--source/blender/editors/animation/drivers.c7
-rw-r--r--source/blender/editors/animation/keyframes_draw.c234
-rw-r--r--source/blender/editors/animation/keyframes_edit.c4
-rw-r--r--source/blender/editors/animation/keyframes_general.c3
-rw-r--r--source/blender/editors/animation/keyframing.c26
-rw-r--r--source/blender/editors/animation/keyingsets.c23
-rw-r--r--source/blender/editors/armature/CMakeLists.txt1
-rw-r--r--source/blender/editors/armature/armature_add.c11
-rw-r--r--source/blender/editors/armature/armature_edit.c2
-rw-r--r--source/blender/editors/armature/armature_intern.h9
-rw-r--r--source/blender/editors/armature/armature_naming.c76
-rw-r--r--source/blender/editors/armature/armature_ops.c1
-rw-r--r--source/blender/editors/armature/armature_relations.c34
-rw-r--r--source/blender/editors/armature/armature_select.c149
-rw-r--r--source/blender/editors/armature/armature_skinning.c3
-rw-r--r--source/blender/editors/armature/armature_utils.c8
-rw-r--r--source/blender/editors/armature/editarmature_sketch.c202
-rw-r--r--source/blender/editors/armature/pose_edit.c31
-rw-r--r--source/blender/editors/armature/pose_group.c58
-rw-r--r--source/blender/editors/armature/pose_lib.c100
-rw-r--r--source/blender/editors/armature/pose_select.c39
-rw-r--r--source/blender/editors/armature/pose_slide.c287
-rw-r--r--source/blender/editors/armature/pose_transform.c147
-rw-r--r--source/blender/editors/armature/pose_utils.c5
-rw-r--r--source/blender/editors/armature/reeb.c236
-rw-r--r--source/blender/editors/curve/CMakeLists.txt1
-rw-r--r--source/blender/editors/curve/editcurve.c179
-rw-r--r--source/blender/editors/curve/editcurve_add.c7
-rw-r--r--source/blender/editors/curve/editcurve_paint.c115
-rw-r--r--source/blender/editors/curve/editfont.c16
-rw-r--r--source/blender/editors/gpencil/CMakeLists.txt2
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c1245
-rw-r--r--source/blender/editors/gpencil/gpencil_brush.c75
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c21
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c512
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c1091
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h113
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c1137
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c23
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c275
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c49
-rw-r--r--source/blender/editors/gpencil/gpencil_undo.c52
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c176
-rw-r--r--source/blender/editors/hair/CMakeLists.txt1
-rw-r--r--source/blender/editors/hair/hair_cursor.c43
-rw-r--r--source/blender/editors/hair/hair_edit.c25
-rw-r--r--source/blender/editors/hair/hair_intern.h19
-rw-r--r--source/blender/editors/hair/hair_select.c29
-rw-r--r--source/blender/editors/hair/hair_stroke.c54
-rw-r--r--source/blender/editors/include/BIF_gl.h53
-rw-r--r--source/blender/editors/include/BIF_glutil.h159
-rw-r--r--source/blender/editors/include/ED_anim_api.h7
-rw-r--r--source/blender/editors/include/ED_armature.h16
-rw-r--r--source/blender/editors/include/ED_clip.h2
-rw-r--r--source/blender/editors/include/ED_gpencil.h35
-rw-r--r--source/blender/editors/include/ED_image.h5
-rw-r--r--source/blender/editors/include/ED_info.h4
-rw-r--r--source/blender/editors/include/ED_keyframes_draw.h6
-rw-r--r--source/blender/editors/include/ED_keyframing.h1
-rw-r--r--source/blender/editors/include/ED_manipulator_library.h131
-rw-r--r--source/blender/editors/include/ED_mesh.h5
-rw-r--r--source/blender/editors/include/ED_node.h4
-rw-r--r--source/blender/editors/include/ED_numinput.h2
-rw-r--r--source/blender/editors/include/ED_object.h26
-rw-r--r--source/blender/editors/include/ED_particle.h21
-rw-r--r--source/blender/editors/include/ED_scene.h43
-rw-r--r--source/blender/editors/include/ED_screen.h61
-rw-r--r--source/blender/editors/include/ED_sculpt.h3
-rw-r--r--source/blender/editors/include/ED_transform.h18
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h11
-rw-r--r--source/blender/editors/include/ED_util.h6
-rw-r--r--source/blender/editors/include/ED_uvedit.h8
-rw-r--r--source/blender/editors/include/ED_view3d.h81
-rw-r--r--source/blender/editors/include/UI_icons.h15
-rw-r--r--source/blender/editors/include/UI_interface.h72
-rw-r--r--source/blender/editors/include/UI_interface_icons.h1
-rw-r--r--source/blender/editors/include/UI_resources.h28
-rw-r--r--source/blender/editors/interface/CMakeLists.txt1
-rw-r--r--source/blender/editors/interface/interface.c153
-rw-r--r--source/blender/editors/interface/interface_align.c6
-rw-r--r--source/blender/editors/interface/interface_anim.c55
-rw-r--r--source/blender/editors/interface/interface_draw.c1527
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c142
-rw-r--r--source/blender/editors/interface/interface_handlers.c555
-rw-r--r--source/blender/editors/interface/interface_icons.c421
-rw-r--r--source/blender/editors/interface/interface_intern.h43
-rw-r--r--source/blender/editors/interface/interface_layout.c320
-rw-r--r--source/blender/editors/interface/interface_ops.c185
-rw-r--r--source/blender/editors/interface/interface_panel.c412
-rw-r--r--source/blender/editors/interface/interface_regions.c139
-rw-r--r--source/blender/editors/interface/interface_style.c27
-rw-r--r--source/blender/editors/interface/interface_templates.c507
-rw-r--r--source/blender/editors/interface/interface_utils.c109
-rw-r--r--source/blender/editors/interface/interface_widgets.c694
-rw-r--r--source/blender/editors/interface/resources.c229
-rw-r--r--source/blender/editors/interface/view2d.c330
-rw-r--r--source/blender/editors/interface/view2d_ops.c15
-rw-r--r--source/blender/editors/io/io_alembic.c164
-rw-r--r--source/blender/editors/io/io_cache.c37
-rw-r--r--source/blender/editors/io/io_collada.c116
-rw-r--r--source/blender/editors/manipulator_library/CMakeLists.txt58
-rw-r--r--source/blender/editors/manipulator_library/geometry/geom_arrow_manipulator.c141
-rw-r--r--source/blender/editors/manipulator_library/geometry/geom_cube_manipulator.c75
-rw-r--r--source/blender/editors/manipulator_library/geometry/geom_dial_manipulator.c813
-rw-r--r--source/blender/editors/manipulator_library/manipulator_draw_utils.c131
-rw-r--r--source/blender/editors/manipulator_library/manipulator_geometry.h54
-rw-r--r--source/blender/editors/manipulator_library/manipulator_library_intern.h105
-rw-r--r--source/blender/editors/manipulator_library/manipulator_library_presets.c151
-rw-r--r--source/blender/editors/manipulator_library/manipulator_library_utils.c154
-rw-r--r--source/blender/editors/manipulator_library/manipulator_types/arrow2d_manipulator.c215
-rw-r--r--source/blender/editors/manipulator_library/manipulator_types/arrow3d_manipulator.c494
-rw-r--r--source/blender/editors/manipulator_library/manipulator_types/cage2d_manipulator.c624
-rw-r--r--source/blender/editors/manipulator_library/manipulator_types/dial3d_manipulator.c467
-rw-r--r--source/blender/editors/manipulator_library/manipulator_types/grab3d_manipulator.c259
-rw-r--r--source/blender/editors/manipulator_library/manipulator_types/primitive3d_manipulator.c195
-rw-r--r--source/blender/editors/mask/CMakeLists.txt1
-rw-r--r--source/blender/editors/mask/mask_add.c19
-rw-r--r--source/blender/editors/mask/mask_draw.c471
-rw-r--r--source/blender/editors/mask/mask_ops.c29
-rw-r--r--source/blender/editors/mask/mask_relationships.c7
-rw-r--r--source/blender/editors/mask/mask_shapekey.c11
-rw-r--r--source/blender/editors/mesh/CMakeLists.txt1
-rw-r--r--source/blender/editors/mesh/editface.c25
-rw-r--r--source/blender/editors/mesh/editmesh_add.c11
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c1
-rw-r--r--source/blender/editors/mesh/editmesh_bisect.c344
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c400
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c52
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c172
-rw-r--r--source/blender/editors/mesh/editmesh_loopcut.c41
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c6
-rw-r--r--source/blender/editors/mesh/editmesh_select.c13
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c117
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c4
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c26
-rw-r--r--source/blender/editors/mesh/mesh_data.c77
-rw-r--r--source/blender/editors/mesh/mesh_navmesh.c20
-rw-r--r--source/blender/editors/mesh/meshtools.c460
-rw-r--r--source/blender/editors/metaball/CMakeLists.txt1
-rw-r--r--source/blender/editors/metaball/mball_edit.c18
-rw-r--r--source/blender/editors/object/CMakeLists.txt2
-rw-r--r--source/blender/editors/object/object_add.c567
-rw-r--r--source/blender/editors/object/object_bake.c73
-rw-r--r--source/blender/editors/object/object_bake_api.c67
-rw-r--r--source/blender/editors/object/object_constraint.c53
-rw-r--r--source/blender/editors/object/object_data_transfer.c19
-rw-r--r--source/blender/editors/object/object_edit.c311
-rw-r--r--source/blender/editors/object/object_facemap_ops.c493
-rw-r--r--source/blender/editors/object/object_group.c49
-rw-r--r--source/blender/editors/object/object_hook.c39
-rw-r--r--source/blender/editors/object/object_intern.h16
-rw-r--r--source/blender/editors/object/object_lattice.c7
-rw-r--r--source/blender/editors/object/object_modifier.c144
-rw-r--r--source/blender/editors/object/object_ops.c35
-rw-r--r--source/blender/editors/object/object_relations.c724
-rw-r--r--source/blender/editors/object/object_select.c327
-rw-r--r--source/blender/editors/object/object_shapekey.c20
-rw-r--r--source/blender/editors/object/object_transform.c28
-rw-r--r--source/blender/editors/object/object_vgroup.c172
-rw-r--r--source/blender/editors/object/object_warp.c3
-rw-r--r--source/blender/editors/physics/CMakeLists.txt1
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c51
-rw-r--r--source/blender/editors/physics/particle_boids.c20
-rw-r--r--source/blender/editors/physics/particle_edit.c252
-rw-r--r--source/blender/editors/physics/particle_object.c126
-rw-r--r--source/blender/editors/physics/physics_fluid.c124
-rw-r--r--source/blender/editors/physics/physics_intern.h1
-rw-r--r--source/blender/editors/physics/physics_ops.c4
-rw-r--r--source/blender/editors/physics/physics_pointcache.c56
-rw-r--r--source/blender/editors/physics/rigidbody_constraint.c26
-rw-r--r--source/blender/editors/physics/rigidbody_object.c20
-rw-r--r--source/blender/editors/render/CMakeLists.txt1
-rw-r--r--source/blender/editors/render/render_internal.c51
-rw-r--r--source/blender/editors/render/render_opengl.c395
-rw-r--r--source/blender/editors/render/render_preview.c166
-rw-r--r--source/blender/editors/render/render_shading.c118
-rw-r--r--source/blender/editors/render/render_update.c54
-rw-r--r--source/blender/editors/render/render_view.c34
-rw-r--r--source/blender/editors/scene/CMakeLists.txt44
-rw-r--r--source/blender/editors/scene/scene_edit.c267
-rw-r--r--source/blender/editors/screen/CMakeLists.txt4
-rw-r--r--source/blender/editors/screen/area.c482
-rw-r--r--source/blender/editors/screen/glutil.c646
-rw-r--r--source/blender/editors/screen/screen_context.c165
-rw-r--r--source/blender/editors/screen/screen_draw.c496
-rw-r--r--source/blender/editors/screen/screen_edit.c788
-rw-r--r--source/blender/editors/screen/screen_intern.h19
-rw-r--r--source/blender/editors/screen/screen_ops.c424
-rw-r--r--source/blender/editors/screen/screendump.c31
-rw-r--r--source/blender/editors/screen/workspace_edit.c439
-rw-r--r--source/blender/editors/screen/workspace_layout_edit.c198
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt1
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c392
-rw-r--r--source/blender/editors/sculpt_paint/paint_hide.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c52
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c8
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c93
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h1
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c13
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c64
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c20
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c44
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c53
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c24
-rw-r--r--source/blender/editors/sound/sound_ops.c83
-rw-r--r--source/blender/editors/space_action/action_buttons.c1
-rw-r--r--source/blender/editors/space_action/action_data.c4
-rw-r--r--source/blender/editors/space_action/action_draw.c118
-rw-r--r--source/blender/editors/space_action/action_ops.c2
-rw-r--r--source/blender/editors/space_action/space_action.c38
-rw-r--r--source/blender/editors/space_api/spacetypes.c24
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c67
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c4
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c20
-rw-r--r--source/blender/editors/space_clip/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_clip/clip_buttons.c7
-rw-r--r--source/blender/editors/space_clip/clip_dopesheet_draw.c261
-rw-r--r--source/blender/editors/space_clip/clip_draw.c873
-rw-r--r--source/blender/editors/space_clip/clip_editor.c23
-rw-r--r--source/blender/editors/space_clip/clip_graph_draw.c150
-rw-r--r--source/blender/editors/space_clip/clip_graph_ops.c5
-rw-r--r--source/blender/editors/space_clip/clip_intern.h11
-rw-r--r--source/blender/editors/space_clip/clip_ops.c6
-rw-r--r--source/blender/editors/space_clip/clip_utils.c91
-rw-r--r--source/blender/editors/space_clip/space_clip.c70
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c37
-rw-r--r--source/blender/editors/space_clip/tracking_ops_orient.c38
-rw-r--r--source/blender/editors/space_clip/tracking_ops_plane.c10
-rw-r--r--source/blender/editors/space_clip/tracking_ops_solve.c7
-rw-r--r--source/blender/editors/space_clip/tracking_ops_stabilize.c150
-rw-r--r--source/blender/editors/space_console/console_draw.c22
-rw-r--r--source/blender/editors/space_console/space_console.c4
-rw-r--r--source/blender/editors/space_file/file_draw.c125
-rw-r--r--source/blender/editors/space_file/file_intern.h1
-rw-r--r--source/blender/editors/space_file/file_ops.c9
-rw-r--r--source/blender/editors/space_file/file_utils.c15
-rw-r--r--source/blender/editors/space_file/filelist.c50
-rw-r--r--source/blender/editors/space_file/filelist.h1
-rw-r--r--source/blender/editors/space_file/filesel.c7
-rw-r--r--source/blender/editors/space_file/fsmenu.c57
-rw-r--r--source/blender/editors/space_file/space_file.c15
-rw-r--r--source/blender/editors/space_graph/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c36
-rw-r--r--source/blender/editors/space_graph/graph_draw.c749
-rw-r--r--source/blender/editors/space_graph/graph_edit.c5
-rw-r--r--source/blender/editors/space_graph/graph_ops.c2
-rw-r--r--source/blender/editors/space_graph/space_graph.c92
-rw-r--r--source/blender/editors/space_image/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_image/image_buttons.c36
-rw-r--r--source/blender/editors/space_image/image_draw.c478
-rw-r--r--source/blender/editors/space_image/image_edit.c10
-rw-r--r--source/blender/editors/space_image/image_intern.h2
-rw-r--r--source/blender/editors/space_image/image_ops.c82
-rw-r--r--source/blender/editors/space_image/space_image.c97
-rw-r--r--source/blender/editors/space_info/info_ops.c1
-rw-r--r--source/blender/editors/space_info/info_stats.c54
-rw-r--r--source/blender/editors/space_info/space_info.c11
-rw-r--r--source/blender/editors/space_info/textview.c46
-rw-r--r--source/blender/editors/space_logic/logic_ops.c1
-rw-r--r--source/blender/editors/space_logic/logic_window.c27
-rw-r--r--source/blender/editors/space_logic/space_logic.c6
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c18
-rw-r--r--source/blender/editors/space_nla/nla_channels.c17
-rw-r--r--source/blender/editors/space_nla/nla_draw.c457
-rw-r--r--source/blender/editors/space_nla/nla_edit.c4
-rw-r--r--source/blender/editors/space_nla/nla_ops.c2
-rw-r--r--source/blender/editors/space_nla/space_nla.c19
-rw-r--r--source/blender/editors/space_node/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_node/drawnode.c554
-rw-r--r--source/blender/editors/space_node/node_add.c26
-rw-r--r--source/blender/editors/space_node/node_buttons.c11
-rw-r--r--source/blender/editors/space_node/node_draw.c473
-rw-r--r--source/blender/editors/space_node/node_edit.c40
-rw-r--r--source/blender/editors/space_node/node_group.c12
-rw-r--r--source/blender/editors/space_node/node_intern.h7
-rw-r--r--source/blender/editors/space_node/node_manipulators.c119
-rw-r--r--source/blender/editors/space_node/node_ops.c2
-rw-r--r--source/blender/editors/space_node/node_relationships.c15
-rw-r--r--source/blender/editors/space_node/node_templates.c24
-rw-r--r--source/blender/editors/space_node/node_view.c14
-rw-r--r--source/blender/editors/space_node/space_node.c95
-rw-r--r--source/blender/editors/space_outliner/CMakeLists.txt3
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.c469
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c1193
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c450
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h130
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c302
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c473
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c293
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c438
-rw-r--r--source/blender/editors/space_outliner/outliner_utils.c234
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c27
-rw-r--r--source/blender/editors/space_script/space_script.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c3
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c741
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c34
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_ops.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c2
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c15
-rw-r--r--source/blender/editors/space_text/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_text/space_text.c6
-rw-r--r--source/blender/editors/space_text/text_autocomplete.c6
-rw-r--r--source/blender/editors/space_text/text_draw.c272
-rw-r--r--source/blender/editors/space_text/text_format.h2
-rw-r--r--source/blender/editors/space_text/text_format_pov.c809
-rw-r--r--source/blender/editors/space_text/text_format_pov_ini.c488
-rw-r--r--source/blender/editors/space_text/text_ops.c16
-rw-r--r--source/blender/editors/space_time/space_time.c273
-rw-r--r--source/blender/editors/space_time/time_ops.c2
-rw-r--r--source/blender/editors/space_userpref/space_userpref.c8
-rw-r--r--source/blender/editors/space_view3d/CMakeLists.txt7
-rw-r--r--source/blender/editors/space_view3d/drawanimviz.c282
-rw-r--r--source/blender/editors/space_view3d/drawarmature.c1465
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c1028
-rw-r--r--source/blender/editors/space_view3d/drawobject.c4940
-rw-r--r--source/blender/editors/space_view3d/drawsimdebug.c129
-rw-r--r--source/blender/editors/space_view3d/drawvolume.c669
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c313
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c56
-rw-r--r--source/blender/editors/space_view3d/view3d_camera_control.c10
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c4588
-rw-r--r--source/blender/editors/space_view3d/view3d_draw_legacy.c2160
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c422
-rw-r--r--source/blender/editors/space_view3d/view3d_fly.c84
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c78
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h106
-rw-r--r--source/blender/editors/space_view3d/view3d_iterators.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_manipulators.c375
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c24
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c59
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c258
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c318
-rw-r--r--source/blender/editors/space_view3d/view3d_snap.c11
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c621
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c71
-rw-r--r--source/blender/editors/transform/CMakeLists.txt5
-rw-r--r--source/blender/editors/transform/transform.c479
-rw-r--r--source/blender/editors/transform/transform.h21
-rw-r--r--source/blender/editors/transform/transform_constraints.c64
-rw-r--r--source/blender/editors/transform/transform_conversions.c492
-rw-r--r--source/blender/editors/transform/transform_generics.c117
-rw-r--r--source/blender/editors/transform/transform_input.c17
-rw-r--r--source/blender/editors/transform/transform_manipulator.c1945
-rw-r--r--source/blender/editors/transform/transform_manipulator2d.c274
-rw-r--r--source/blender/editors/transform/transform_ops.c27
-rw-r--r--source/blender/editors/transform/transform_orientations.c164
-rw-r--r--source/blender/editors/transform/transform_snap.c100
-rw-r--r--source/blender/editors/transform/transform_snap_object.c2334
-rw-r--r--source/blender/editors/util/CMakeLists.txt3
-rw-r--r--source/blender/editors/util/ed_transverts.c5
-rw-r--r--source/blender/editors/util/ed_util.c48
-rw-r--r--source/blender/editors/util/editmode_undo.c5
-rw-r--r--source/blender/editors/util/numinput.c6
-rw-r--r--source/blender/editors/util/undo.c63
-rw-r--r--source/blender/editors/uvedit/CMakeLists.txt1
-rw-r--r--source/blender/editors/uvedit/uvedit_buttons.c10
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c666
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h2
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c344
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c143
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c46
-rw-r--r--source/blender/freestyle/CMakeLists.txt1
-rw-r--r--source/blender/freestyle/FRS_freestyle.h3
-rw-r--r--source/blender/freestyle/intern/application/AppView.cpp6
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp2
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp42
-rw-r--r--source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp38
-rw-r--r--source/blender/freestyle/intern/geometry/GeomUtils.cpp2
-rw-r--r--source/blender/freestyle/intern/geometry/matrix_util.h6
-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/stroke/StrokeRep.cpp14
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp40
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapBuilder.h2
-rw-r--r--source/blender/gpu/CMakeLists.txt112
-rw-r--r--source/blender/gpu/GPU_basic_shader.h9
-rw-r--r--source/blender/gpu/GPU_batch.h51
-rw-r--r--source/blender/gpu/GPU_buffers.h47
-rw-r--r--source/blender/gpu/GPU_debug.h22
-rw-r--r--source/blender/gpu/GPU_draw.h39
-rw-r--r--source/blender/gpu/GPU_extensions.h10
-rw-r--r--source/blender/gpu/GPU_framebuffer.h19
-rw-r--r--source/blender/gpu/GPU_glew.h4
-rw-r--r--source/blender/gpu/GPU_immediate.h58
-rw-r--r--source/blender/gpu/GPU_immediate_util.h59
-rw-r--r--source/blender/gpu/GPU_lamp.h77
-rw-r--r--source/blender/gpu/GPU_legacy_stubs.h457
-rw-r--r--source/blender/gpu/GPU_material.h53
-rw-r--r--source/blender/gpu/GPU_matrix.h180
-rw-r--r--source/blender/gpu/GPU_select.h15
-rw-r--r--source/blender/gpu/GPU_shader.h109
-rw-r--r--source/blender/gpu/GPU_texture.h128
-rw-r--r--source/blender/gpu/GPU_uniformbuffer.h62
-rw-r--r--source/blender/gpu/GPU_viewport.h118
-rw-r--r--source/blender/gpu/intern/gpu_basic_shader.c415
-rw-r--r--source/blender/gpu/intern/gpu_batch.c171
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c856
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c526
-rw-r--r--source/blender/gpu/intern/gpu_codegen.h20
-rw-r--r--source/blender/gpu/intern/gpu_compositing.c345
-rw-r--r--source/blender/gpu/intern/gpu_debug.c739
-rw-r--r--source/blender/gpu/intern/gpu_draw.c664
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c133
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.c506
-rw-r--r--source/blender/gpu/intern/gpu_immediate.c88
-rw-r--r--source/blender/gpu/intern/gpu_immediate_util.c344
-rw-r--r--source/blender/gpu/intern/gpu_init_exit.c11
-rw-r--r--source/blender/gpu/intern/gpu_lamp.c483
-rw-r--r--source/blender/gpu/intern/gpu_lamp_private.h84
-rw-r--r--source/blender/gpu/intern/gpu_material.c587
-rw-r--r--source/blender/gpu/intern/gpu_matrix.c624
-rw-r--r--source/blender/gpu/intern/gpu_select.c283
-rw-r--r--source/blender/gpu/intern/gpu_select_pick.c742
-rw-r--r--source/blender/gpu/intern/gpu_select_private.h53
-rw-r--r--source/blender/gpu/intern/gpu_select_sample_query.c215
-rw-r--r--source/blender/gpu/intern/gpu_shader.c623
-rw-r--r--source/blender/gpu/intern/gpu_shader_private.h45
-rw-r--r--source/blender/gpu/intern/gpu_texture.c879
-rw-r--r--source/blender/gpu/intern/gpu_uniformbuffer.c301
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c584
-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_vert.glsl13
-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_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_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_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.glsl37
-rw-r--r--source/blender/gpu/shaders/gpu_shader_basic_geom.glsl6
-rw-r--r--source/blender/gpu/shaders/gpu_shader_basic_vert.glsl12
-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.glsl15
-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_fullscreen_vert.glsl10
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_depth_resolve.glsl5
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl111
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl68
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl39
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl34
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl45
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_lib.glsl7
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl28
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_vert.glsl9
-rw-r--r--source/blender/gpu/shaders/gpu_shader_geometry.glsl25
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_alpha_color_frag.glsl11
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl11
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_depth_linear_frag.glsl16
-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_rect_modulate_alpha_frag.glsl12
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_shuffle_color_frag.glsl16
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_solid_vert.glsl122
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_wire_vert.glsl103
-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.glsl29
-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.glsl22
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_vert.glsl13
-rw-r--r--source/blender/gpu/shaders/gpu_shader_keyframe_diamond_frag.glsl31
-rw-r--r--source/blender/gpu/shaders/gpu_shader_keyframe_diamond_vert.glsl34
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl852
-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_sep_gaussian_blur_frag.glsl19
-rw-r--r--source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl10
-rw-r--r--source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl17
-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.glsl31
-rw-r--r--source/blender/gpu/shaders/gpu_shader_smoke_vert.glsl7
-rw-r--r--source/blender/gpu/shaders/gpu_shader_text_frag.glsl15
-rw-r--r--source/blender/gpu/shaders/gpu_shader_text_vert.glsl16
-rw-r--r--source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl9
-rw-r--r--source/blender/gpu/shaders/gpu_shader_vertex.glsl15
-rw-r--r--source/blender/gpu/shaders/gpu_shader_vertex_world.glsl5
-rw-r--r--source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl6
-rw-r--r--source/blender/gpu/shaders/gpu_shader_vsm_store_vert.glsl7
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.cpp11
-rw-r--r--source/blender/imbuf/IMB_colormanagement.h14
-rw-r--r--source/blender/imbuf/IMB_imbuf.h2
-rw-r--r--source/blender/imbuf/IMB_imbuf_types.h22
-rw-r--r--source/blender/imbuf/intern/IMB_anim.h7
-rw-r--r--source/blender/imbuf/intern/IMB_colormanagement_intern.h2
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c15
-rw-r--r--source/blender/imbuf/intern/anim_movie.c19
-rw-r--r--source/blender/imbuf/intern/cineon/dpxlib.c2
-rw-r--r--source/blender/imbuf/intern/cineon/logImageCore.c15
-rw-r--r--source/blender/imbuf/intern/colormanagement.c255
-rw-r--r--source/blender/imbuf/intern/dds/dds_api.cpp4
-rw-r--r--source/blender/imbuf/intern/filter.c6
-rw-r--r--source/blender/imbuf/intern/imbuf.h2
-rw-r--r--source/blender/imbuf/intern/metadata.c2
-rw-r--r--source/blender/imbuf/intern/oiio/CMakeLists.txt5
-rw-r--r--source/blender/imbuf/intern/oiio/openimageio_api.cpp4
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp16
-rw-r--r--source/blender/imbuf/intern/png.c3
-rw-r--r--source/blender/imbuf/intern/radiance_hdr.c3
-rw-r--r--source/blender/imbuf/intern/thumbs_blend.c1
-rw-r--r--source/blender/makesdna/DNA_ID.h49
-rw-r--r--source/blender/makesdna/DNA_action_types.h26
-rw-r--r--source/blender/makesdna/DNA_anim_types.h5
-rw-r--r--source/blender/makesdna/DNA_cachefile_types.h7
-rw-r--r--source/blender/makesdna/DNA_camera_types.h7
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h1
-rw-r--r--source/blender/makesdna/DNA_curve_types.h1
-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_fileglobal_types.h6
-rw-r--r--source/blender/makesdna/DNA_genfile.h1
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h15
-rw-r--r--source/blender/makesdna/DNA_gpu_types.h2
-rw-r--r--source/blender/makesdna/DNA_lamp_types.h2
-rw-r--r--source/blender/makesdna/DNA_lattice_types.h1
-rw-r--r--source/blender/makesdna/DNA_layer_types.h146
-rw-r--r--source/blender/makesdna/DNA_lightprobe_types.h106
-rw-r--r--source/blender/makesdna/DNA_material_types.h48
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h2
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h80
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h56
-rw-r--r--source/blender/makesdna/DNA_movieclip_types.h1
-rw-r--r--source/blender/makesdna/DNA_node_types.h13
-rw-r--r--source/blender/makesdna/DNA_object_fluidsim.h1
-rw-r--r--source/blender/makesdna/DNA_object_force.h7
-rw-r--r--source/blender/makesdna/DNA_object_types.h50
-rw-r--r--source/blender/makesdna/DNA_outliner_types.h21
-rw-r--r--source/blender/makesdna/DNA_particle_types.h9
-rw-r--r--source/blender/makesdna/DNA_rigidbody_types.h12
-rw-r--r--source/blender/makesdna/DNA_scene_types.h240
-rw-r--r--source/blender/makesdna/DNA_screen_types.h22
-rw-r--r--source/blender/makesdna/DNA_smoke_types.h56
-rw-r--r--source/blender/makesdna/DNA_space_types.h51
-rw-r--r--source/blender/makesdna/DNA_tracking_types.h27
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h42
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h40
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h10
-rw-r--r--source/blender/makesdna/DNA_workspace_types.h135
-rw-r--r--source/blender/makesdna/DNA_world_types.h4
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c7
-rw-r--r--source/blender/makesdna/intern/makesdna.c19
-rw-r--r--source/blender/makesrna/RNA_access.h32
-rw-r--r--source/blender/makesrna/RNA_define.h16
-rw-r--r--source/blender/makesrna/RNA_enum_types.h1
-rw-r--r--source/blender/makesrna/RNA_types.h56
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt16
-rw-r--r--source/blender/makesrna/intern/makesrna.c93
-rw-r--r--source/blender/makesrna/intern/rna_ID.c171
-rw-r--r--source/blender/makesrna/intern/rna_access.c252
-rw-r--r--source/blender/makesrna/intern/rna_action.c33
-rw-r--r--source/blender/makesrna/intern/rna_actuator.c3
-rw-r--r--source/blender/makesrna/intern/rna_actuator_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_animation.c44
-rw-r--r--source/blender/makesrna/intern/rna_animviz.c29
-rw-r--r--source/blender/makesrna/intern/rna_armature.c29
-rw-r--r--source/blender/makesrna/intern/rna_armature_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_boid.c14
-rw-r--r--source/blender/makesrna/intern/rna_brush.c36
-rw-r--r--source/blender/makesrna/intern/rna_cachefile.c26
-rw-r--r--source/blender/makesrna/intern/rna_camera.c10
-rw-r--r--source/blender/makesrna/intern/rna_cloth.c38
-rw-r--r--source/blender/makesrna/intern/rna_color.c48
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c24
-rw-r--r--source/blender/makesrna/intern/rna_context.c57
-rw-r--r--source/blender/makesrna/intern/rna_controller.c1
-rw-r--r--source/blender/makesrna/intern/rna_curve.c30
-rw-r--r--source/blender/makesrna/intern/rna_curve_api.c12
-rw-r--r--source/blender/makesrna/intern/rna_define.c63
-rw-r--r--source/blender/makesrna/intern/rna_depsgraph.c260
-rw-r--r--source/blender/makesrna/intern/rna_dynamicpaint.c11
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c82
-rw-r--r--source/blender/makesrna/intern/rna_fcurve_api.c8
-rw-r--r--source/blender/makesrna/intern/rna_fluidsim.c13
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c133
-rw-r--r--source/blender/makesrna/intern/rna_group.c16
-rw-r--r--source/blender/makesrna/intern/rna_image.c11
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c14
-rw-r--r--source/blender/makesrna/intern/rna_internal.h15
-rw-r--r--source/blender/makesrna/intern/rna_internal_types.h35
-rw-r--r--source/blender/makesrna/intern/rna_key.c14
-rw-r--r--source/blender/makesrna/intern/rna_lamp.c20
-rw-r--r--source/blender/makesrna/intern/rna_lattice.c9
-rw-r--r--source/blender/makesrna/intern/rna_lattice_api.c12
-rw-r--r--source/blender/makesrna/intern/rna_lightprobe.c188
-rw-r--r--source/blender/makesrna/intern/rna_linestyle.c67
-rw-r--r--source/blender/makesrna/intern/rna_main.c89
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c555
-rw-r--r--source/blender/makesrna/intern/rna_mask.c27
-rw-r--r--source/blender/makesrna/intern/rna_material.c80
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c420
-rw-r--r--source/blender/makesrna/intern/rna_mesh_api.c40
-rw-r--r--source/blender/makesrna/intern/rna_mesh_utils.h11
-rw-r--r--source/blender/makesrna/intern/rna_meta.c17
-rw-r--r--source/blender/makesrna/intern/rna_meta_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c148
-rw-r--r--source/blender/makesrna/intern/rna_movieclip.c6
-rw-r--r--source/blender/makesrna/intern/rna_nla.c25
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c310
-rw-r--r--source/blender/makesrna/intern/rna_object.c437
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c211
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c55
-rw-r--r--source/blender/makesrna/intern/rna_palette.c4
-rw-r--r--source/blender/makesrna/intern/rna_particle.c177
-rw-r--r--source/blender/makesrna/intern/rna_pose.c48
-rw-r--r--source/blender/makesrna/intern/rna_pose_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_property.c1
-rw-r--r--source/blender/makesrna/intern/rna_render.c350
-rw-r--r--source/blender/makesrna/intern/rna_rigidbody.c187
-rw-r--r--source/blender/makesrna/intern/rna_rna.c14
-rw-r--r--source/blender/makesrna/intern/rna_scene.c2549
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c188
-rw-r--r--source/blender/makesrna/intern/rna_screen.c104
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c124
-rw-r--r--source/blender/makesrna/intern/rna_sensor.c1
-rw-r--r--source/blender/makesrna/intern/rna_sensor_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c85
-rw-r--r--source/blender/makesrna/intern/rna_sequencer_api.c68
-rw-r--r--source/blender/makesrna/intern/rna_smoke.c144
-rw-r--r--source/blender/makesrna/intern/rna_space.c556
-rw-r--r--source/blender/makesrna/intern/rna_space_api.c18
-rw-r--r--source/blender/makesrna/intern/rna_speaker.c1
-rw-r--r--source/blender/makesrna/intern/rna_text_api.c6
-rw-r--r--source/blender/makesrna/intern/rna_texture.c32
-rw-r--r--source/blender/makesrna/intern/rna_texture_api.c6
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c198
-rw-r--r--source/blender/makesrna/intern/rna_ui.c45
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c171
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c289
-rw-r--r--source/blender/makesrna/intern/rna_vfont.c7
-rw-r--r--source/blender/makesrna/intern/rna_wm.c412
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c188
-rw-r--r--source/blender/makesrna/intern/rna_wm_manipulator.c1234
-rw-r--r--source/blender/makesrna/intern/rna_wm_manipulator_api.c254
-rw-r--r--source/blender/makesrna/intern/rna_workspace.c183
-rw-r--r--source/blender/makesrna/intern/rna_world.c10
-rw-r--r--source/blender/modifiers/CMakeLists.txt4
-rw-r--r--source/blender/modifiers/MOD_modifiertypes.h1
-rw-r--r--source/blender/modifiers/intern/MOD_armature.c21
-rw-r--r--source/blender/modifiers/intern/MOD_array.c96
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c1
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c22
-rw-r--r--source/blender/modifiers/intern/MOD_build.c1
-rw-r--r--source/blender/modifiers/intern/MOD_cast.c25
-rw-r--r--source/blender/modifiers/intern/MOD_cloth.c43
-rw-r--r--source/blender/modifiers/intern/MOD_collision.c18
-rw-r--r--source/blender/modifiers/intern/MOD_correctivesmooth.c1
-rw-r--r--source/blender/modifiers/intern/MOD_curve.c28
-rw-r--r--source/blender/modifiers/intern/MOD_datatransfer.c30
-rw-r--r--source/blender/modifiers/intern/MOD_decimate.c1
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c223
-rw-r--r--source/blender/modifiers/intern/MOD_dynamicpaint.c62
-rw-r--r--source/blender/modifiers/intern/MOD_edgesplit.c1
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c5
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim.c49
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim_util.c31
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c27
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciandeform.c1
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciansmooth.c1
-rw-r--r--source/blender/modifiers/intern/MOD_lattice.c21
-rw-r--r--source/blender/modifiers/intern/MOD_mask.c22
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache.c1
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache_mdd.c5
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache_pc2.c6
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c28
-rw-r--r--source/blender/modifiers/intern/MOD_meshsequencecache.c43
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c23
-rw-r--r--source/blender/modifiers/intern/MOD_multires.c1
-rw-r--r--source/blender/modifiers/intern/MOD_none.c1
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c95
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c31
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c22
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.c1
-rw-r--r--source/blender/modifiers/intern/MOD_remesh.c1
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c28
-rw-r--r--source/blender/modifiers/intern/MOD_shapekey.c1
-rw-r--r--source/blender/modifiers/intern/MOD_shrinkwrap.c24
-rw-r--r--source/blender/modifiers/intern/MOD_simpledeform.c18
-rw-r--r--source/blender/modifiers/intern/MOD_skin.c1
-rw-r--r--source/blender/modifiers/intern/MOD_smoke.c226
-rw-r--r--source/blender/modifiers/intern/MOD_smooth.c1
-rw-r--r--source/blender/modifiers/intern/MOD_softbody.c22
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c1
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c17
-rw-r--r--source/blender/modifiers/intern/MOD_surface.c2
-rw-r--r--source/blender/modifiers/intern/MOD_surfacedeform.c1213
-rw-r--r--source/blender/modifiers/intern/MOD_triangulate.c1
-rw-r--r--source/blender/modifiers/intern/MOD_util.c1
-rw-r--r--source/blender/modifiers/intern/MOD_uvproject.c59
-rw-r--r--source/blender/modifiers/intern/MOD_uvwarp.c42
-rw-r--r--source/blender/modifiers/intern/MOD_warp.c36
-rw-r--r--source/blender/modifiers/intern/MOD_wave.c32
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgedit.c29
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgmix.c29
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c34
-rw-r--r--source/blender/modifiers/intern/MOD_wireframe.c1
-rw-r--r--source/blender/nodes/CMakeLists.txt8
-rw-r--r--source/blender/nodes/NOD_composite.h4
-rw-r--r--source/blender/nodes/NOD_shader.h4
-rw-r--r--source/blender/nodes/NOD_static_types.h8
-rw-r--r--source/blender/nodes/composite/node_composite_tree.c35
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bilateralblur.c1
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_brightness.c5
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_directionalblur.c1
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_glare.c3
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_hueSatVal.c16
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_image.c541
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_outputFile.c2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_switchview.c1
-rw-r--r--source/blender/nodes/intern/node_common.c13
-rw-r--r--source/blender/nodes/intern/node_exec.c3
-rw-r--r--source/blender/nodes/shader/node_shader_tree.c8
-rw-r--r--source/blender/nodes/shader/node_shader_util.c52
-rw-r--r--source/blender/nodes/shader/node_shader_util.h2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_add_shader.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_attribute.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_background.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_brightness.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c141
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bump.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_camera.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_curves.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_eevee_metallic.c88
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_eevee_specular.c87
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_emission.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_fresnel.c33
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_gamma.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_geom.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_geometry.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_hueSatVal.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_invert.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_lamp.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_layer_weight.c38
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_light_falloff.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_light_path.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mapping.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_material.c41
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_math.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mixRgb.c3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mix_shader.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal_map.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_object_info.c14
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output.c10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_eevee_material.c66
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_material.c10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_world.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_particle_info.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_rgb.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_squeeze.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tangent.c23
-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.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_coord.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_environment.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_gradient.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_magic.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_noise.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_sky.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_wave.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_texture.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_uvmap.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_valToRgb.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_value.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vectMath.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_absorption.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_scatter.c4
-rw-r--r--source/blender/nodes/texture/node_texture_tree.c3
-rw-r--r--source/blender/physics/intern/BPH_mass_spring.cpp51
-rw-r--r--source/blender/physics/intern/hair_volume.cpp4
-rw-r--r--source/blender/physics/intern/implicit.h10
-rw-r--r--source/blender/physics/intern/implicit_blender.c34
-rw-r--r--source/blender/python/BPY_extern.h3
-rw-r--r--source/blender/python/bmesh/CMakeLists.txt1
-rw-r--r--source/blender/python/bmesh/bmesh_py_api.c5
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c13
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_customdata.c15
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_meshdata.c91
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_meshdata.h4
-rw-r--r--source/blender/python/generic/bgl.c1215
-rw-r--r--source/blender/python/generic/blf_py_api.c4
-rw-r--r--source/blender/python/generic/idprop_py_api.c440
-rw-r--r--source/blender/python/generic/py_capi_utils.c51
-rw-r--r--source/blender/python/generic/py_capi_utils.h7
-rw-r--r--source/blender/python/intern/CMakeLists.txt13
-rw-r--r--source/blender/python/intern/bpy.c3
-rw-r--r--source/blender/python/intern/bpy_app.c27
-rw-r--r--source/blender/python/intern/bpy_app_handlers.c14
-rw-r--r--source/blender/python/intern/bpy_app_opensubdiv.c109
-rw-r--r--source/blender/python/intern/bpy_app_opensubdiv.h (renamed from source/blender/depsgraph/util/deg_util_hash.h)23
-rw-r--r--source/blender/python/intern/bpy_app_sdl.c2
-rw-r--r--source/blender/python/intern/bpy_interface.c64
-rw-r--r--source/blender/python/intern/bpy_intern_string.c44
-rw-r--r--source/blender/python/intern/bpy_intern_string.h21
-rw-r--r--source/blender/python/intern/bpy_library_load.c14
-rw-r--r--source/blender/python/intern/bpy_library_write.c2
-rw-r--r--source/blender/python/intern/bpy_manipulator_wrap.c242
-rw-r--r--source/blender/python/intern/bpy_manipulator_wrap.h36
-rw-r--r--source/blender/python/intern/bpy_operator_wrap.c4
-rw-r--r--source/blender/python/intern/bpy_operator_wrap.h4
-rw-r--r--source/blender/python/intern/bpy_props.c172
-rw-r--r--source/blender/python/intern/bpy_props.h4
-rw-r--r--source/blender/python/intern/bpy_rna.c157
-rw-r--r--source/blender/python/intern/bpy_rna.h1
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c104
-rw-r--r--source/blender/python/intern/bpy_rna_id_collection.c34
-rw-r--r--source/blender/python/intern/bpy_rna_manipulator.c353
-rw-r--r--source/blender/python/intern/bpy_rna_manipulator.h32
-rw-r--r--source/blender/python/intern/bpy_utils_units.c2
-rw-r--r--source/blender/python/intern/gpu.c1
-rw-r--r--source/blender/python/intern/gpu_offscreen.c16
-rw-r--r--source/blender/python/mathutils/mathutils.c35
-rw-r--r--source/blender/python/mathutils/mathutils_Color.c2
-rw-r--r--source/blender/python/mathutils/mathutils_Euler.c4
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c30
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.c2
-rw-r--r--source/blender/python/mathutils/mathutils_bvhtree.c5
-rw-r--r--source/blender/render/CMakeLists.txt7
-rw-r--r--source/blender/render/extern/include/RE_engine.h30
-rw-r--r--source/blender/render/extern/include/RE_multires_bake.h6
-rw-r--r--source/blender/render/extern/include/RE_pipeline.h27
-rw-r--r--source/blender/render/extern/include/RE_shader_ext.h6
-rw-r--r--source/blender/render/intern/include/render_result.h7
-rw-r--r--source/blender/render/intern/include/render_types.h6
-rw-r--r--source/blender/render/intern/include/rendercore.h8
-rw-r--r--source/blender/render/intern/include/shading.h2
-rw-r--r--source/blender/render/intern/raytrace/rayobject.cpp84
-rw-r--r--source/blender/render/intern/raytrace/rayobject_rtbuild.cpp12
-rw-r--r--source/blender/render/intern/source/bake.c7
-rw-r--r--source/blender/render/intern/source/bake_api.c28
-rw-r--r--source/blender/render/intern/source/convertblender.c69
-rw-r--r--source/blender/render/intern/source/envmap.c32
-rw-r--r--source/blender/render/intern/source/external_engine.c167
-rw-r--r--source/blender/render/intern/source/initrender.c7
-rw-r--r--source/blender/render/intern/source/multires_bake.c57
-rw-r--r--source/blender/render/intern/source/occlusion.c13
-rw-r--r--source/blender/render/intern/source/pipeline.c130
-rw-r--r--source/blender/render/intern/source/pointdensity.c20
-rw-r--r--source/blender/render/intern/source/render_result.c750
-rw-r--r--source/blender/render/intern/source/render_texture.c63
-rw-r--r--source/blender/render/intern/source/rendercore.c410
-rw-r--r--source/blender/render/intern/source/renderdatabase.c9
-rw-r--r--source/blender/render/intern/source/shadeinput.c45
-rw-r--r--source/blender/render/intern/source/shadeoutput.c60
-rw-r--r--source/blender/render/intern/source/sunsky.c2
-rw-r--r--source/blender/render/intern/source/volume_precache.c10
-rw-r--r--source/blender/render/intern/source/volumetric.c6
-rw-r--r--source/blender/render/intern/source/zbuf.c229
-rw-r--r--source/blender/windowmanager/CMakeLists.txt22
-rw-r--r--source/blender/windowmanager/WM_api.h43
-rw-r--r--source/blender/windowmanager/WM_types.h24
-rw-r--r--source/blender/windowmanager/intern/wm.c47
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c18
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c251
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c272
-rw-r--r--source/blender/windowmanager/intern/wm_files.c420
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c115
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c265
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c35
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c15
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c397
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c90
-rw-r--r--source/blender/windowmanager/intern/wm_stereo.c226
-rw-r--r--source/blender/windowmanager/intern/wm_subwindow.c33
-rw-r--r--source/blender/windowmanager/intern/wm_window.c424
-rw-r--r--source/blender/windowmanager/manipulators/WM_manipulator_api.h264
-rw-r--r--source/blender/windowmanager/manipulators/WM_manipulator_types.h367
-rw-r--r--source/blender/windowmanager/manipulators/intern/wm_manipulator.c675
-rw-r--r--source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c723
-rw-r--r--source/blender/windowmanager/manipulators/intern/wm_manipulator_group_type.c186
-rw-r--r--source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h130
-rw-r--r--source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c909
-rw-r--r--source/blender/windowmanager/manipulators/intern/wm_manipulator_target_props.c274
-rw-r--r--source/blender/windowmanager/manipulators/intern/wm_manipulator_type.c166
-rw-r--r--source/blender/windowmanager/manipulators/wm_manipulator_fn.h85
-rw-r--r--source/blender/windowmanager/manipulators/wm_manipulator_wmapi.h93
-rw-r--r--source/blender/windowmanager/wm.h3
-rw-r--r--source/blender/windowmanager/wm_draw.h2
-rw-r--r--source/blender/windowmanager/wm_event_system.h5
-rw-r--r--source/blender/windowmanager/wm_event_types.h2
-rw-r--r--source/blender/windowmanager/wm_files.h6
-rw-r--r--source/blender/windowmanager/wm_window.h15
-rw-r--r--source/blenderplayer/CMakeLists.txt38
-rw-r--r--source/blenderplayer/bad_level_call_stubs/CMakeLists.txt7
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c181
-rw-r--r--source/creator/CMakeLists.txt240
-rw-r--r--source/creator/creator.c9
-rw-r--r--source/creator/creator_args.c71
-rw-r--r--source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp22
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp5
-rw-r--r--source/gameengine/Converter/BL_ArmatureObject.cpp3
-rw-r--r--source/gameengine/Converter/BL_BlenderDataConversion.cpp31
-rw-r--r--source/gameengine/Expressions/intern/HashedPtr.cpp4
-rw-r--r--source/gameengine/Expressions/intern/InputParser.cpp2
-rw-r--r--source/gameengine/Expressions/intern/PyObjectPlus.cpp8
-rw-r--r--source/gameengine/GameLogic/SCA_PropertySensor.cpp4
-rw-r--r--source/gameengine/GamePlayer/common/GPC_Canvas.h2
-rw-r--r--source/gameengine/GamePlayer/common/GPC_MouseDevice.h2
-rw-r--r--source/gameengine/GamePlayer/ghost/CMakeLists.txt5
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_Application.cpp13
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_ghost.cpp13
-rw-r--r--source/gameengine/Ketsji/BL_BlenderShader.cpp2
-rw-r--r--source/gameengine/Ketsji/BL_Material.cpp1
-rw-r--r--source/gameengine/Ketsji/BL_Material.h1
-rw-r--r--source/gameengine/Ketsji/BL_Shader.cpp2
-rw-r--r--source/gameengine/Ketsji/BL_Texture.cpp11
-rw-r--r--source/gameengine/Ketsji/KX_BlenderMaterial.cpp25
-rw-r--r--source/gameengine/Ketsji/KX_BlenderMaterial.h1
-rw-r--r--source/gameengine/Ketsji/KX_Camera.cpp49
-rw-r--r--source/gameengine/Ketsji/KX_Dome.cpp10
-rw-r--r--source/gameengine/Ketsji/KX_Dome.h2
-rw-r--r--source/gameengine/Ketsji/KX_IPO_SGController.cpp4
-rw-r--r--source/gameengine/Ketsji/KX_KetsjiEngine.cpp6
-rw-r--r--source/gameengine/Ketsji/KX_Light.cpp2
-rw-r--r--source/gameengine/Ketsji/KX_Light.h4
-rw-r--r--source/gameengine/Ketsji/KX_NavMeshObject.cpp7
-rw-r--r--source/gameengine/Ketsji/KX_ObstacleSimulation.cpp1
-rw-r--r--source/gameengine/Ketsji/KX_PythonInit.cpp2
-rw-r--r--source/gameengine/Ketsji/KX_SoundActuator.cpp4
-rw-r--r--source/gameengine/Physics/Bullet/CMakeLists.txt1
-rw-r--r--source/gameengine/Physics/Bullet/CcdPhysicsController.cpp8
-rw-r--r--source/gameengine/Rasterizer/CMakeLists.txt1
-rw-r--r--source/gameengine/Rasterizer/RAS_2DFilterManager.cpp4
-rw-r--r--source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp4
-rw-r--r--source/gameengine/Rasterizer/RAS_IPolygonMaterial.h2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp3
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp46
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp4
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp5
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h2
-rw-r--r--source/gameengine/VideoTexture/FilterColor.cpp2
-rw-r--r--source/gameengine/VideoTexture/FilterColor.h4
-rw-r--r--source/gameengine/VideoTexture/ImageBase.cpp2
-rw-r--r--source/gameengine/VideoTexture/ImageBase.h2
-rw-r--r--source/gameengine/VideoTexture/ImageRender.cpp3
-rw-r--r--source/gameengine/VideoTexture/ImageViewport.cpp2
-rw-r--r--source/gameengine/VideoTexture/Texture.cpp2
-rw-r--r--source/gameengine/VideoTexture/VideoDeckLink.cpp4
-rw-r--r--source/gameengine/VideoTexture/VideoDeckLink.h2
m---------source/tools0
1638 files changed, 148156 insertions, 61594 deletions
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index c696719e650..4e4724771f3 100644
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -23,6 +23,10 @@
#
# ***** END GPL LICENSE BLOCK *****
+if(WITH_LEGACY_OPENGL)
+ add_definitions(-DWITH_LEGACY_OPENGL)
+endif()
+
add_subdirectory(blender)
if(WITH_GAMEENGINE)
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index 6f2b78e0845..564ca473903 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -54,6 +54,8 @@ set(SRC_DNA_INC
${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_material_types.h
@@ -88,6 +90,7 @@ set(SRC_DNA_INC
${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
@@ -100,6 +103,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)
diff --git a/source/blender/alembic/ABC_alembic.h b/source/blender/alembic/ABC_alembic.h
index cf121f8488c..70250310213 100644
--- a/source/blender/alembic/ABC_alembic.h
+++ b/source/blender/alembic/ABC_alembic.h
@@ -28,6 +28,7 @@ extern "C" {
#endif
struct bContext;
+struct CacheReader;
struct DerivedMesh;
struct ListBase;
struct Object;
@@ -46,63 +47,88 @@ struct AlembicExportParams {
double frame_start;
double frame_end;
- double frame_step_xform;
- double frame_step_shape;
+ unsigned int frame_samples_xform;
+ unsigned int frame_samples_shape;
double shutter_open;
double shutter_close;
- /* bools */
- unsigned int selected_only : 1;
- unsigned int uvs : 1;
- unsigned int normals : 1;
- unsigned int vcolors : 1;
- unsigned int apply_subdiv : 1;
- unsigned int flatten_hierarchy : 1;
- unsigned int visible_layers_only : 1;
- unsigned int renderable_only : 1;
- unsigned int face_sets : 1;
- unsigned int use_subdiv_schema : 1;
- unsigned int packuv : 1;
+ bool selected_only;
+ bool uvs;
+ bool normals;
+ bool vcolors;
+ bool apply_subdiv;
+ bool flatten_hierarchy;
+ bool visible_layers_only;
+ bool renderable_only;
+ bool face_sets;
+ bool use_subdiv_schema;
+ bool packuv;
+ bool triangulate;
+ bool export_hair;
+ bool export_particles;
unsigned int compression_type : 1;
+
+ /* See MOD_TRIANGULATE_NGON_xxx and MOD_TRIANGULATE_QUAD_xxx
+ * in DNA_modifier_types.h */
+ int quad_method;
+ int ngon_method;
+
float global_scale;
};
-void ABC_export(
+/* The ABC_export and ABC_import functions both take a as_background_job
+ * parameter, and return a boolean.
+ *
+ * When as_background_job=true, returns false immediately after scheduling
+ * a background job.
+ *
+ * When as_background_job=false, performs the export synchronously, and returns
+ * true when the export was ok, and false if there were any errors.
+ */
+
+bool ABC_export(
struct Scene *scene,
struct bContext *C,
const char *filepath,
- const struct AlembicExportParams *params);
+ const struct AlembicExportParams *params,
+ bool as_background_job);
-void ABC_import(struct bContext *C,
+bool ABC_import(struct bContext *C,
const char *filepath,
float scale,
bool is_sequence,
bool set_frame_range,
int sequence_len,
int offset,
- bool validate_meshes);
+ bool validate_meshes,
+ bool as_background_job);
AbcArchiveHandle *ABC_create_handle(const char *filename, struct ListBase *object_paths);
void ABC_free_handle(AbcArchiveHandle *handle);
-void ABC_get_transform(AbcArchiveHandle *handle,
- struct Object *ob,
- const char *object_path,
+void ABC_get_transform(struct CacheReader *reader,
float r_mat[4][4],
float time,
float scale);
-struct DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle,
+struct DerivedMesh *ABC_read_mesh(struct CacheReader *reader,
struct Object *ob,
struct DerivedMesh *dm,
- const char *object_path,
const float time,
const char **err_str,
int flags);
+void CacheReader_incref(struct CacheReader *reader);
+void CacheReader_free(struct CacheReader *reader);
+
+struct CacheReader *CacheReader_open_alembic_object(struct AbcArchiveHandle *handle,
+ struct CacheReader *reader,
+ struct Object *object,
+ const char *object_path);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/alembic/CMakeLists.txt b/source/blender/alembic/CMakeLists.txt
index 42bd6a9c340..aa12b726d6b 100644
--- a/source/blender/alembic/CMakeLists.txt
+++ b/source/blender/alembic/CMakeLists.txt
@@ -28,25 +28,25 @@ set(INC
../blenkernel
../blenlib
../blenloader
+ ../bmesh
+ ../depsgraph
../editors/include
../makesdna
../makesrna
../windowmanager
../../../intern/guardedalloc
+ ../../../intern/utfconv
)
set(INC_SYS
${ALEMBIC_INCLUDE_DIRS}
+ ${BOOST_INCLUDE_DIR}
${HDF5_INCLUDE_DIRS}
${OPENEXR_INCLUDE_DIRS}
)
-if(APPLE OR WIN32)
- list(APPEND INC_SYS
- ${BOOST_INCLUDE_DIR}
- )
-endif()
set(SRC
+ intern/abc_archive.cc
intern/abc_camera.cc
intern/abc_customdata.cc
intern/abc_curves.cc
@@ -61,6 +61,7 @@ set(SRC
intern/alembic_capi.cc
ABC_alembic.h
+ intern/abc_archive.h
intern/abc_camera.h
intern/abc_customdata.h
intern/abc_curves.h
diff --git a/source/blender/alembic/intern/abc_archive.cc b/source/blender/alembic/intern/abc_archive.cc
new file mode 100644
index 00000000000..bd16196cb78
--- /dev/null
+++ b/source/blender/alembic/intern/abc_archive.cc
@@ -0,0 +1,208 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Kévin Dietrich.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#include "abc_archive.h"
+extern "C"
+{
+ #include "BKE_blender_version.h"
+}
+
+#ifdef WIN32
+# include "utfconv.h"
+#endif
+
+#include <fstream>
+
+using Alembic::Abc::Exception;
+using Alembic::Abc::ErrorHandler;
+using Alembic::Abc::IArchive;
+using Alembic::Abc::kWrapExisting;
+using Alembic::Abc::OArchive;
+
+static IArchive open_archive(const std::string &filename,
+ const std::vector<std::istream *> &input_streams,
+ bool &is_hdf5)
+{
+ is_hdf5 = false;
+
+ try {
+ Alembic::AbcCoreOgawa::ReadArchive archive_reader(input_streams);
+
+ return IArchive(archive_reader(filename),
+ kWrapExisting,
+ ErrorHandler::kThrowPolicy);
+ }
+ catch (const Exception &e) {
+ std::cerr << e.what() << '\n';
+
+#ifdef WITH_ALEMBIC_HDF5
+ try {
+ is_hdf5 = true;
+ Alembic::AbcCoreAbstract::ReadArraySampleCachePtr cache_ptr;
+
+ return IArchive(Alembic::AbcCoreHDF5::ReadArchive(),
+ filename.c_str(), ErrorHandler::kThrowPolicy,
+ cache_ptr);
+ }
+ catch (const Exception &) {
+ std::cerr << e.what() << '\n';
+ return IArchive();
+ }
+#else
+ /* Inspect the file to see whether it's really a HDF5 file. */
+ char header[4]; /* char(0x89) + "HDF" */
+ std::ifstream the_file(filename.c_str(), std::ios::in | std::ios::binary);
+ if (!the_file) {
+ std::cerr << "Unable to open " << filename << std::endl;
+ }
+ else if (!the_file.read(header, sizeof(header))) {
+ std::cerr << "Unable to read from " << filename << std::endl;
+ }
+ else if (strncmp(header + 1, "HDF", 3)) {
+ std::cerr << filename << " has an unknown file format, unable to read." << std::endl;
+ }
+ else {
+ is_hdf5 = true;
+ std::cerr << filename << " is in the obsolete HDF5 format, unable to read." << std::endl;
+ }
+
+ if (the_file.is_open()) {
+ the_file.close();
+ }
+
+ return IArchive();
+#endif
+ }
+
+ return IArchive();
+}
+
+ArchiveReader::ArchiveReader(const char *filename)
+{
+#ifdef WIN32
+ UTF16_ENCODE(filename);
+ std::wstring wstr(filename_16);
+ m_infile.open(wstr.c_str(), std::ios::in | std::ios::binary);
+ UTF16_UN_ENCODE(filename);
+#else
+ m_infile.open(filename, std::ios::in | std::ios::binary);
+#endif
+
+ m_streams.push_back(&m_infile);
+
+ m_archive = open_archive(filename, m_streams, m_is_hdf5);
+
+ /* We can't open an HDF5 file from a stream, so close it. */
+ if (m_is_hdf5) {
+ m_infile.close();
+ m_streams.clear();
+ }
+}
+
+bool ArchiveReader::is_hdf5() const
+{
+ return m_is_hdf5;
+}
+
+bool ArchiveReader::valid() const
+{
+ return m_archive.valid();
+}
+
+Alembic::Abc::IObject ArchiveReader::getTop()
+{
+ return m_archive.getTop();
+}
+
+/* ************************************************************************** */
+
+/* This kinda duplicates CreateArchiveWithInfo, but Alembic does not seem to
+ * have a version supporting streams. */
+static OArchive create_archive(std::ostream *ostream,
+ const std::string &filename,
+ const std::string &scene_name,
+ Alembic::Abc::MetaData &md,
+ bool ogawa)
+{
+ md.set(Alembic::Abc::kApplicationNameKey, "Blender");
+ md.set(Alembic::Abc::kUserDescriptionKey, scene_name);
+ md.set("blender_version", versionstr);
+
+ time_t raw_time;
+ time(&raw_time);
+ char buffer[128];
+
+#if defined _WIN32 || defined _WIN64
+ ctime_s(buffer, 128, &raw_time);
+#else
+ ctime_r(&raw_time, buffer);
+#endif
+
+ const std::size_t buffer_len = strlen(buffer);
+ if (buffer_len > 0 && buffer[buffer_len - 1] == '\n') {
+ buffer[buffer_len - 1] = '\0';
+ }
+
+ md.set(Alembic::Abc::kDateWrittenKey, buffer);
+
+ ErrorHandler::Policy policy = ErrorHandler::kThrowPolicy;
+
+#ifdef WITH_ALEMBIC_HDF5
+ if (!ogawa) {
+ return OArchive(Alembic::AbcCoreHDF5::WriteArchive(), filename, md, policy);
+ }
+#else
+ static_cast<void>(filename);
+ static_cast<void>(ogawa);
+#endif
+
+ Alembic::AbcCoreOgawa::WriteArchive archive_writer;
+ return OArchive(archive_writer(ostream, md), kWrapExisting, policy);
+}
+
+ArchiveWriter::ArchiveWriter(const char *filename, const char *scene, bool do_ogawa, Alembic::Abc::MetaData &md)
+{
+ /* Use stream to support unicode character paths on Windows. */
+ if (do_ogawa) {
+#ifdef WIN32
+ UTF16_ENCODE(filename);
+ std::wstring wstr(filename_16);
+ m_outfile.open(wstr.c_str(), std::ios::out | std::ios::binary);
+ UTF16_UN_ENCODE(filename);
+#else
+ m_outfile.open(filename, std::ios::out | std::ios::binary);
+#endif
+ }
+
+ m_archive = create_archive(&m_outfile,
+ filename,
+ scene,
+ md,
+ do_ogawa);
+}
+
+OArchive &ArchiveWriter::archive()
+{
+ return m_archive;
+}
diff --git a/source/blender/alembic/intern/abc_archive.h b/source/blender/alembic/intern/abc_archive.h
new file mode 100644
index 00000000000..84309fbc9df
--- /dev/null
+++ b/source/blender/alembic/intern/abc_archive.h
@@ -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 Kévin Dietrich.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef __ABC_ARCHIVE_H__
+#define __ABC_ARCHIVE_H__
+
+#include <Alembic/Abc/All.h>
+
+#ifdef WITH_ALEMBIC_HDF5
+# include <Alembic/AbcCoreHDF5/All.h>
+#endif
+
+#include <Alembic/AbcCoreOgawa/All.h>
+
+#include <fstream>
+
+/* Wrappers around input and output archives. The goal is to be able to use
+ * streams so that unicode paths work on Windows (T49112), and to make sure that
+ * the stream objects remain valid as long as the archives are open.
+ */
+
+class ArchiveReader {
+ Alembic::Abc::IArchive m_archive;
+ std::ifstream m_infile;
+ std::vector<std::istream *> m_streams;
+ bool m_is_hdf5;
+
+public:
+ explicit ArchiveReader(const char *filename);
+
+ bool valid() const;
+
+ /**
+ * Returns true when either Blender is compiled with HDF5 support and
+ * the archive was succesfully opened (valid() will also return true),
+ * or when Blender was built without HDF5 support but a HDF5 file was
+ * detected (valid() will return false).
+ */
+ bool is_hdf5() const;
+
+ Alembic::Abc::IObject getTop();
+};
+
+class ArchiveWriter {
+ std::ofstream m_outfile;
+ Alembic::Abc::OArchive m_archive;
+
+public:
+ explicit ArchiveWriter(const char *filename, const char *scene, bool do_ogawa, Alembic::Abc::MetaData &md);
+
+ Alembic::Abc::OArchive &archive();
+};
+
+#endif /* __ABC_ARCHIVE_H__ */
diff --git a/source/blender/alembic/intern/abc_camera.cc b/source/blender/alembic/intern/abc_camera.cc
index 38a6d3d33cf..16416205983 100644
--- a/source/blender/alembic/intern/abc_camera.cc
+++ b/source/blender/alembic/intern/abc_camera.cc
@@ -109,7 +109,7 @@ AbcCameraReader::AbcCameraReader(const Alembic::Abc::IObject &object, ImportSett
ICamera abc_cam(m_iobject, kWrapExisting);
m_schema = abc_cam.getSchema();
- get_min_max_time(m_schema, m_min_time, m_max_time);
+ get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time);
}
bool AbcCameraReader::valid() const
@@ -117,11 +117,27 @@ bool AbcCameraReader::valid() const
return m_schema.valid();
}
-void AbcCameraReader::readObjectData(Main *bmain, float time)
+bool AbcCameraReader::accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const
{
- Camera *bcam = static_cast<Camera *>(BKE_camera_add(bmain, "abc_camera"));
+ if (!Alembic::AbcGeom::ICamera::matches(alembic_header)) {
+ *err_str = "Object type mismatch, Alembic object path pointed to Camera when importing, but not any more.";
+ return false;
+ }
+
+ if (ob->type != OB_CAMERA) {
+ *err_str = "Object type mismatch, Alembic object path points to Camera.";
+ return false;
+ }
+
+ return true;
+}
+
+void AbcCameraReader::readObjectData(Main *bmain, const ISampleSelector &sample_sel)
+{
+ Camera *bcam = static_cast<Camera *>(BKE_camera_add(bmain, m_data_name.c_str()));
- ISampleSelector sample_sel(time);
CameraSample cam_sample;
m_schema.get(cam_sample, sample_sel);
@@ -138,11 +154,11 @@ void AbcCameraReader::readObjectData(Main *bmain, float time)
bcam->stereo.convergence_distance = convergence_plane.getValue(sample_sel);
}
- const float lens = cam_sample.getFocalLength();
- const float apperture_x = cam_sample.getHorizontalAperture();
- const float apperture_y = cam_sample.getVerticalAperture();
- const float h_film_offset = cam_sample.getHorizontalFilmOffset();
- const float v_film_offset = cam_sample.getVerticalFilmOffset();
+ const float lens = static_cast<float>(cam_sample.getFocalLength());
+ const float apperture_x = static_cast<float>(cam_sample.getHorizontalAperture());
+ const float apperture_y = static_cast<float>(cam_sample.getVerticalAperture());
+ const float h_film_offset = static_cast<float>(cam_sample.getHorizontalFilmOffset());
+ const float v_film_offset = static_cast<float>(cam_sample.getVerticalFilmOffset());
const float film_aspect = apperture_x / apperture_y;
bcam->lens = lens;
@@ -150,12 +166,10 @@ void AbcCameraReader::readObjectData(Main *bmain, float time)
bcam->sensor_y = apperture_y * 10;
bcam->shiftx = h_film_offset / apperture_x;
bcam->shifty = v_film_offset / apperture_y / film_aspect;
- bcam->clipsta = max_ff(0.1f, cam_sample.getNearClippingPlane());
- bcam->clipend = cam_sample.getFarClippingPlane();
- bcam->gpu_dof.focus_distance = cam_sample.getFocusDistance();
- bcam->gpu_dof.fstop = cam_sample.getFStop();
-
- BLI_strncpy(bcam->id.name + 2, m_data_name.c_str(), m_data_name.size() + 1);
+ bcam->clipsta = max_ff(0.1f, static_cast<float>(cam_sample.getNearClippingPlane()));
+ bcam->clipend = static_cast<float>(cam_sample.getFarClippingPlane());
+ bcam->gpu_dof.focus_distance = static_cast<float>(cam_sample.getFocusDistance());
+ bcam->gpu_dof.fstop = static_cast<float>(cam_sample.getFStop());
m_object = BKE_object_add_only_object(bmain, OB_CAMERA, m_object_name.c_str());
m_object->data = bcam;
diff --git a/source/blender/alembic/intern/abc_camera.h b/source/blender/alembic/intern/abc_camera.h
index fafb4d3eb39..16c5cccd5ea 100644
--- a/source/blender/alembic/intern/abc_camera.h
+++ b/source/blender/alembic/intern/abc_camera.h
@@ -54,8 +54,11 @@ public:
AbcCameraReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
bool valid() const;
+ bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const;
- void readObjectData(Main *bmain, float time);
+ void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel);
};
-#endif /* __ABC_CAMERA_H__ */ \ No newline at end of file
+#endif /* __ABC_CAMERA_H__ */
diff --git a/source/blender/alembic/intern/abc_curves.cc b/source/blender/alembic/intern/abc_curves.cc
index 4e1e4e7e490..f73fe957fea 100644
--- a/source/blender/alembic/intern/abc_curves.cc
+++ b/source/blender/alembic/intern/abc_curves.cc
@@ -37,6 +37,7 @@ extern "C" {
#include "BLI_listbase.h"
+#include "BKE_cdderivedmesh.h"
#include "BKE_curve.h"
#include "BKE_object.h"
@@ -48,19 +49,26 @@ using Alembic::Abc::Int32ArraySamplePtr;
using Alembic::Abc::FloatArraySamplePtr;
using Alembic::Abc::P3fArraySamplePtr;
using Alembic::Abc::UcharArraySamplePtr;
+using Alembic::Abc::PropertyHeader;
+using Alembic::AbcGeom::ICompoundProperty;
using Alembic::AbcGeom::ICurves;
using Alembic::AbcGeom::ICurvesSchema;
using Alembic::AbcGeom::IFloatGeomParam;
+using Alembic::AbcGeom::IInt16Property;
using Alembic::AbcGeom::ISampleSelector;
using Alembic::AbcGeom::kWrapExisting;
using Alembic::AbcGeom::CurvePeriodicity;
+using Alembic::AbcGeom::OCompoundProperty;
using Alembic::AbcGeom::OCurves;
using Alembic::AbcGeom::OCurvesSchema;
+using Alembic::AbcGeom::OInt16Property;
using Alembic::AbcGeom::ON3fGeomParam;
using Alembic::AbcGeom::OV2fGeomParam;
+#define ABC_CURVE_RESOLUTION_U_PROPNAME "blender:resolution"
+
/* ************************************************************************** */
AbcCurveWriter::AbcCurveWriter(Scene *scene,
@@ -72,6 +80,11 @@ AbcCurveWriter::AbcCurveWriter(Scene *scene,
{
OCurves curves(parent->alembicXform(), m_name, m_time_sampling);
m_schema = curves.getSchema();
+
+ Curve *cu = static_cast<Curve *>(m_object->data);
+ OCompoundProperty user_props = m_schema.getUserProperties();
+ OInt16Property user_prop_resolu(user_props, ABC_CURVE_RESOLUTION_U_PROPNAME);
+ user_prop_resolu.set(cu->resolu);
}
void AbcCurveWriter::do_write()
@@ -94,14 +107,14 @@ void AbcCurveWriter::do_write()
for (; nurbs; nurbs = nurbs->next) {
if (nurbs->bp) {
curve_basis = Alembic::AbcGeom::kNoBasis;
- curve_type = Alembic::AbcGeom::kLinear;
+ curve_type = Alembic::AbcGeom::kVariableOrder;
const int totpoint = nurbs->pntsu * nurbs->pntsv;
const BPoint *point = nurbs->bp;
for (int i = 0; i < totpoint; ++i, ++point) {
- copy_zup_yup(temp_vert.getValue(), point->vec);
+ copy_yup_from_zup(temp_vert.getValue(), point->vec);
verts.push_back(temp_vert);
weights.push_back(point->vec[3]);
widths.push_back(point->radius);
@@ -117,7 +130,7 @@ void AbcCurveWriter::do_write()
/* TODO(kevin): store info about handles, Alembic doesn't have this. */
for (int i = 0; i < totpoint; ++i, ++bezier) {
- copy_zup_yup(temp_vert.getValue(), bezier->vec[1]);
+ copy_yup_from_zup(temp_vert.getValue(), bezier->vec[1]);
verts.push_back(temp_vert);
widths.push_back(bezier->radius);
}
@@ -159,7 +172,7 @@ void AbcCurveWriter::do_write()
}
}
- orders.push_back(nurbs->orderu + 1);
+ orders.push_back(nurbs->orderu);
vert_counts.push_back(verts.size());
}
@@ -190,7 +203,7 @@ AbcCurveReader::AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettin
ICurves abc_curves(object, kWrapExisting);
m_curves_schema = abc_curves.getSchema();
- get_min_max_time(m_curves_schema, m_min_time, m_max_time);
+ get_min_max_time(m_iobject, m_curves_schema, m_min_time, m_max_time);
}
bool AbcCurveReader::valid() const
@@ -198,17 +211,44 @@ bool AbcCurveReader::valid() const
return m_curves_schema.valid();
}
-void AbcCurveReader::readObjectData(Main *bmain, float time)
+bool AbcCurveReader::accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const
+{
+ if (!Alembic::AbcGeom::ICurves::matches(alembic_header)) {
+ *err_str = "Object type mismatch, Alembic object path pointed to Curves when importing, but not any more.";
+ return false;
+ }
+
+ if (ob->type != OB_CURVE) {
+ *err_str = "Object type mismatch, Alembic object path points to Curves.";
+ return false;
+ }
+
+ return true;
+}
+
+void AbcCurveReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
{
Curve *cu = BKE_curve_add(bmain, m_data_name.c_str(), OB_CURVE);
cu->flag |= CU_DEFORM_FILL | CU_3D;
cu->actvert = CU_ACT_NONE;
+ cu->resolu = 1;
+
+ ICompoundProperty user_props = m_curves_schema.getUserProperties();
+ if (user_props) {
+ const PropertyHeader *header = user_props.getPropertyHeader(ABC_CURVE_RESOLUTION_U_PROPNAME);
+ if (header != NULL && header->isScalar() && IInt16Property::matches(*header)) {
+ IInt16Property resolu(user_props, header->getName());
+ cu->resolu = resolu.getValue(sample_sel);
+ }
+ }
m_object = BKE_object_add_only_object(bmain, OB_CURVE, m_object_name.c_str());
m_object->data = cu;
- read_curve_sample(cu, m_curves_schema, time);
+ read_curve_sample(cu, m_curves_schema, sample_sel);
if (has_animations(m_curves_schema, m_settings)) {
addCacheModifier();
@@ -217,9 +257,8 @@ void AbcCurveReader::readObjectData(Main *bmain, float time)
/* ************************************************************************** */
-void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time)
+void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const ISampleSelector &sample_sel)
{
- const ISampleSelector sample_sel(time);
ICurvesSchema::Sample smp = schema.getValue(sample_sel);
const Int32ArraySamplePtr num_vertices = smp.getCurvesNumVertices();
const P3fArraySamplePtr positions = smp.getPositions();
@@ -249,13 +288,19 @@ void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time)
nu->pntsv = 1;
nu->flag |= CU_SMOOTH;
- nu->orderu = num_verts;
-
- if (smp.getType() == Alembic::AbcGeom::kCubic) {
- nu->orderu = 3;
- }
- else if (orders && orders->size() > i) {
- nu->orderu = static_cast<short>((*orders)[i] - 1);
+ switch (smp.getType()) {
+ case Alembic::AbcGeom::kCubic:
+ nu->orderu = 4;
+ break;
+ case Alembic::AbcGeom::kVariableOrder:
+ if (orders && orders->size() > i) {
+ nu->orderu = static_cast<short>((*orders)[i]);
+ break;
+ }
+ ATTR_FALLTHROUGH;
+ case Alembic::AbcGeom::kLinear:
+ default:
+ nu->orderu = 2;
}
if (periodicity == Alembic::AbcGeom::kNonPeriodic) {
@@ -321,7 +366,7 @@ void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time)
weight = (*weights)[idx];
}
- copy_yup_zup(bp->vec, pos.getValue());
+ copy_zup_from_yup(bp->vec, pos.getValue());
bp->vec[3] = weight;
bp->f1 = SELECT;
bp->radius = radius;
@@ -353,3 +398,56 @@ void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time)
BLI_addtail(BKE_curve_nurbs_get(cu), nu);
}
}
+
+/* NOTE: Alembic only stores data about control points, but the DerivedMesh
+ * passed from the cache modifier contains the displist, which has more data
+ * than the control points, so to avoid corrupting the displist we modify the
+ * object directly and create a new DerivedMesh from that. Also we might need to
+ * create new or delete existing NURBS in the curve.
+ */
+DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh * /*dm*/,
+ const ISampleSelector &sample_sel,
+ int /*read_flag*/,
+ const char ** /*err_str*/)
+{
+ const ICurvesSchema::Sample sample = m_curves_schema.getValue(sample_sel);
+
+ const P3fArraySamplePtr &positions = sample.getPositions();
+ const Int32ArraySamplePtr num_vertices = sample.getCurvesNumVertices();
+
+ int vertex_idx = 0;
+ int curve_idx = 0;
+ Curve *curve = static_cast<Curve *>(m_object->data);
+
+ const int curve_count = BLI_listbase_count(&curve->nurb);
+
+ if (curve_count != num_vertices->size()) {
+ BKE_nurbList_free(&curve->nurb);
+ read_curve_sample(curve, m_curves_schema, sample_sel);
+ }
+ else {
+ Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
+ for (; nurbs; nurbs = nurbs->next, ++curve_idx) {
+ const int totpoint = (*num_vertices)[curve_idx];
+
+ if (nurbs->bp) {
+ BPoint *point = nurbs->bp;
+
+ for (int i = 0; i < totpoint; ++i, ++point, ++vertex_idx) {
+ const Imath::V3f &pos = (*positions)[vertex_idx];
+ copy_zup_from_yup(point->vec, pos.getValue());
+ }
+ }
+ else if (nurbs->bezt) {
+ BezTriple *bezier = nurbs->bezt;
+
+ for (int i = 0; i < totpoint; ++i, ++bezier, ++vertex_idx) {
+ const Imath::V3f &pos = (*positions)[vertex_idx];
+ copy_zup_from_yup(bezier->vec[1], pos.getValue());
+ }
+ }
+ }
+ }
+
+ return CDDM_from_curve(m_object);
+}
diff --git a/source/blender/alembic/intern/abc_curves.h b/source/blender/alembic/intern/abc_curves.h
index ee47f1931ea..a9231f947b2 100644
--- a/source/blender/alembic/intern/abc_curves.h
+++ b/source/blender/alembic/intern/abc_curves.h
@@ -54,12 +54,21 @@ public:
AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
bool valid() const;
+ bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const;
- void readObjectData(Main *bmain, float time);
+ 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);
};
/* ************************************************************************** */
-void read_curve_sample(Curve *cu, const Alembic::AbcGeom::ICurvesSchema &schema, const float time);
+void read_curve_sample(Curve *cu,
+ const Alembic::AbcGeom::ICurvesSchema &schema,
+ const Alembic::Abc::ISampleSelector &sample_selector);
-#endif /* __ABC_CURVES_H__ */ \ No newline at end of file
+#endif /* __ABC_CURVES_H__ */
diff --git a/source/blender/alembic/intern/abc_customdata.cc b/source/blender/alembic/intern/abc_customdata.cc
index ebf1b2ba96e..1d2bc689027 100644
--- a/source/blender/alembic/intern/abc_customdata.cc
+++ b/source/blender/alembic/intern/abc_customdata.cc
@@ -227,48 +227,6 @@ using Alembic::AbcGeom::IC3fGeomParam;
using Alembic::AbcGeom::IC4fGeomParam;
using Alembic::AbcGeom::IV2fGeomParam;
-static void read_mcols(const CDStreamConfig &config, void *data,
- const C3fArraySamplePtr &c3f_ptr, const C4fArraySamplePtr &c4f_ptr)
-{
- MCol *cfaces = static_cast<MCol *>(data);
- MPoly *polys = config.mpoly;
- MLoop *mloops = config.mloop;
-
- if (c3f_ptr) {
- for (int i = 0; i < config.totpoly; ++i) {
- MPoly *p = &polys[i];
- MCol *cface = &cfaces[p->loopstart + p->totloop];
- MLoop *mloop = &mloops[p->loopstart + p->totloop];
-
- for (int j = 0; j < p->totloop; ++j) {
- cface--;
- mloop--;
- const Imath::C3f &color = (*c3f_ptr)[mloop->v];
- cface->a = FTOCHAR(color[0]);
- cface->r = FTOCHAR(color[1]);
- cface->g = FTOCHAR(color[2]);
- cface->b = 255;
- }
- }
- }
- else if (c4f_ptr) {
- for (int i = 0; i < config.totpoly; ++i) {
- MPoly *p = &polys[i];
- MCol *cface = &cfaces[p->loopstart + p->totloop];
- MLoop *mloop = &mloops[p->loopstart + p->totloop];
-
- for (int j = 0; j < p->totloop; ++j) {
- cface--;
- mloop--;
- const Imath::C4f &color = (*c4f_ptr)[mloop->v];
- cface->a = FTOCHAR(color[0]);
- cface->r = FTOCHAR(color[1]);
- cface->g = FTOCHAR(color[2]);
- cface->b = FTOCHAR(color[3]);
- }
- }
- }
-}
static void read_uvs(const CDStreamConfig &config, void *data,
const Alembic::AbcGeom::V2fArraySamplePtr &uvs,
@@ -294,52 +252,108 @@ static void read_uvs(const CDStreamConfig &config, void *data,
}
}
-static void read_custom_data_ex(const ICompoundProperty &prop,
- const PropertyHeader &prop_header,
- const CDStreamConfig &config,
- const Alembic::Abc::ISampleSelector &iss,
- int data_type)
+static void read_custom_data_mcols(const ICompoundProperty &arbGeomParams,
+ const PropertyHeader &prop_header,
+ const CDStreamConfig &config,
+ const Alembic::Abc::ISampleSelector &iss)
{
- if (data_type == CD_MLOOPCOL) {
- C3fArraySamplePtr c3f_ptr = C3fArraySamplePtr();
- C4fArraySamplePtr c4f_ptr = C4fArraySamplePtr();
+ C3fArraySamplePtr c3f_ptr = C3fArraySamplePtr();
+ C4fArraySamplePtr c4f_ptr = C4fArraySamplePtr();
+ bool use_c3f_ptr;
+ bool is_facevarying;
+
+ /* Find the correct interpretation of the data */
+ if (IC3fGeomParam::matches(prop_header)) {
+ IC3fGeomParam color_param(arbGeomParams, prop_header.getName());
+ IC3fGeomParam::Sample sample;
+ BLI_assert(!strcmp("rgb", color_param.getInterpretation()));
+
+ color_param.getIndexed(sample, iss);
+ is_facevarying = sample.getScope() == kFacevaryingScope &&
+ config.totloop == sample.getIndices()->size();
+
+ c3f_ptr = sample.getVals();
+ use_c3f_ptr = true;
+ }
+ else if (IC4fGeomParam::matches(prop_header)) {
+ IC4fGeomParam color_param(arbGeomParams, prop_header.getName());
+ IC4fGeomParam::Sample sample;
+ BLI_assert(!strcmp("rgba", color_param.getInterpretation()));
- if (IC3fGeomParam::matches(prop_header)) {
- IC3fGeomParam color_param(prop, prop_header.getName());
- IC3fGeomParam::Sample sample;
- color_param.getIndexed(sample, iss);
+ color_param.getIndexed(sample, iss);
+ is_facevarying = sample.getScope() == kFacevaryingScope &&
+ config.totloop == sample.getIndices()->size();
- c3f_ptr = sample.getVals();
- }
- else if (IC4fGeomParam::matches(prop_header)) {
- IC4fGeomParam color_param(prop, prop_header.getName());
- IC4fGeomParam::Sample sample;
- color_param.getIndexed(sample, iss);
+ c4f_ptr = sample.getVals();
+ use_c3f_ptr = false;
+ }
+ else {
+ /* this won't happen due to the checks in read_custom_data() */
+ return;
+ }
+ BLI_assert(c3f_ptr || c4f_ptr);
- c4f_ptr = sample.getVals();
- }
+ /* Read the vertex colors */
+ void *cd_data = config.add_customdata_cb(config.user_data,
+ prop_header.getName().c_str(),
+ CD_MLOOPCOL);
+ MCol *cfaces = static_cast<MCol *>(cd_data);
+ MPoly *mpolys = config.mpoly;
+ MLoop *mloops = config.mloop;
- void *cd_data = config.add_customdata_cb(config.user_data,
- prop_header.getName().c_str(),
- data_type);
+ size_t face_index = 0;
+ size_t color_index;
+ for (int i = 0; i < config.totpoly; ++i) {
+ MPoly *poly = &mpolys[i];
+ MCol *cface = &cfaces[poly->loopstart + poly->totloop];
+ MLoop *mloop = &mloops[poly->loopstart + poly->totloop];
- read_mcols(config, cd_data, c3f_ptr, c4f_ptr);
- }
- else if (data_type == CD_MLOOPUV) {
- IV2fGeomParam uv_param(prop, prop_header.getName());
- IV2fGeomParam::Sample sample;
- uv_param.getIndexed(sample, iss);
+ for (int j = 0; j < poly->totloop; ++j, ++face_index) {
+ --cface;
+ --mloop;
+ color_index = is_facevarying ? face_index : mloop->v;
- if (uv_param.getScope() != kFacevaryingScope) {
- return;
+ if (use_c3f_ptr) {
+ const Imath::C3f &color = (*c3f_ptr)[color_index];
+ cface->a = FTOCHAR(color[0]);
+ cface->r = FTOCHAR(color[1]);
+ cface->g = FTOCHAR(color[2]);
+ cface->b = 255;
+ }
+ else {
+ const Imath::C4f &color = (*c4f_ptr)[color_index];
+ cface->a = FTOCHAR(color[0]);
+ cface->r = FTOCHAR(color[1]);
+ cface->g = FTOCHAR(color[2]);
+ cface->b = FTOCHAR(color[3]);
+ }
}
+ }
+}
- void *cd_data = config.add_customdata_cb(config.user_data,
- prop_header.getName().c_str(),
- data_type);
+static void read_custom_data_uvs(const ICompoundProperty &prop,
+ const PropertyHeader &prop_header,
+ const CDStreamConfig &config,
+ const Alembic::Abc::ISampleSelector &iss)
+{
+ IV2fGeomParam uv_param(prop, prop_header.getName());
- read_uvs(config, cd_data, sample.getVals(), sample.getIndices());
+ if (!uv_param.isIndexed()) {
+ return;
}
+
+ IV2fGeomParam::Sample sample;
+ uv_param.getIndexed(sample, iss);
+
+ if (uv_param.getScope() != kFacevaryingScope) {
+ return;
+ }
+
+ void *cd_data = config.add_customdata_cb(config.user_data,
+ prop_header.getName().c_str(),
+ CD_MLOOPUV);
+
+ read_uvs(config, cd_data, sample.getVals(), sample.getIndices());
}
void read_custom_data(const ICompoundProperty &prop, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss)
@@ -362,7 +376,7 @@ void read_custom_data(const ICompoundProperty &prop, const CDStreamConfig &confi
continue;
}
- read_custom_data_ex(prop, prop_header, config, iss, CD_MLOOPUV);
+ read_custom_data_uvs(prop, prop_header, config, iss);
continue;
}
@@ -372,7 +386,7 @@ void read_custom_data(const ICompoundProperty &prop, const CDStreamConfig &confi
continue;
}
- read_custom_data_ex(prop, prop_header, config, iss, CD_MLOOPCOL);
+ read_custom_data_mcols(prop, prop_header, config, iss);
continue;
}
}
diff --git a/source/blender/alembic/intern/abc_customdata.h b/source/blender/alembic/intern/abc_customdata.h
index 3b16c0d9796..9e671fde386 100644
--- a/source/blender/alembic/intern/abc_customdata.h
+++ b/source/blender/alembic/intern/abc_customdata.h
@@ -26,6 +26,7 @@
#define __ABC_CUSTOMDATA_H__
#include <Alembic/Abc/All.h>
+#include <Alembic/AbcGeom/All.h>
struct CustomData;
struct MLoop;
@@ -63,6 +64,11 @@ struct CDStreamConfig {
void *user_data;
void *(*add_customdata_cb)(void *user_data, const char *name, int data_type);
+ float weight;
+ float time;
+ Alembic::AbcGeom::index_t index;
+ Alembic::AbcGeom::index_t ceil_index;
+
CDStreamConfig()
: mloop(NULL)
, totloop(0)
@@ -72,6 +78,10 @@ struct CDStreamConfig {
, pack_uvs(false)
, user_data(NULL)
, add_customdata_cb(NULL)
+ , weight(0.0f)
+ , time(0.0f)
+ , index(0)
+ , ceil_index(0)
{}
};
diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc
index 127e8853789..680913e45ea 100644
--- a/source/blender/alembic/intern/abc_exporter.cc
+++ b/source/blender/alembic/intern/abc_exporter.cc
@@ -24,12 +24,7 @@
#include <cmath>
-#ifdef WITH_ALEMBIC_HDF5
-# include <Alembic/AbcCoreHDF5/All.h>
-#endif
-
-#include <Alembic/AbcCoreOgawa/All.h>
-
+#include "abc_archive.h"
#include "abc_camera.h"
#include "abc_curves.h"
#include "abc_hair.h"
@@ -44,6 +39,7 @@ extern "C" {
#include "DNA_curve_types.h"
#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_space_types.h" /* for FILE_MAX */
@@ -51,7 +47,7 @@ extern "C" {
#ifdef WIN32
/* needed for MSCV because of snprintf from BLI_string */
-# include "BLI_winstuff.h"
+# include "BLI_winstuff.h"
#endif
#include "BKE_anim.h"
@@ -70,13 +66,14 @@ using Alembic::Abc::OBox3dProperty;
ExportSettings::ExportSettings()
: scene(NULL)
+ , logger()
, selected_only(false)
, visible_layers_only(false)
, renderable_only(false)
, frame_start(1)
, frame_end(1)
- , frame_step_xform(1)
- , frame_step_shape(1)
+ , frame_samples_xform(1)
+ , frame_samples_shape(1)
, shutter_open(0.0)
, shutter_close(1.0)
, global_scale(1.0f)
@@ -86,11 +83,16 @@ ExportSettings::ExportSettings()
, export_vcols(false)
, export_face_sets(false)
, export_vweigths(false)
+ , export_hair(true)
+ , export_particles(true)
, apply_subdiv(false)
, use_subdiv_schema(false)
, export_child_hairs(true)
, export_ogawa(true)
, pack_uv(false)
+ , triangulate(false)
+ , quad_method(0)
+ , ngon_method(0)
, do_convert_axis(false)
{}
@@ -106,7 +108,7 @@ static bool object_is_smoke_sim(Object *ob)
return false;
}
-static bool object_is_shape(Object *ob)
+static bool object_type_is_exportable(Object *ob)
{
switch (ob->type) {
case OB_MESH:
@@ -115,6 +117,7 @@ static bool object_is_shape(Object *ob)
}
return true;
+ case OB_EMPTY:
case OB_CURVE:
case OB_SURF:
case OB_CAMERA:
@@ -124,19 +127,36 @@ static bool object_is_shape(Object *ob)
}
}
-static bool export_object(const ExportSettings * const settings, Object *ob)
-{
- if (settings->selected_only && !parent_selected(ob)) {
- return false;
- }
- if (settings->visible_layers_only && !(settings->scene->lay & ob->lay)) {
- return false;
+/**
+ * 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'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, 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 && !object_selected(ob_base)) {
+ return false;
+ }
+ // FIXME Sybren: handle these cleanly (maybe just remove code), now using active scene layer instead.
+ if (settings->visible_layers_only && (ob_base->flag & BASE_VISIBLED) == 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;
}
@@ -149,74 +169,75 @@ AbcExporter::AbcExporter(Scene *scene, const char *filename, ExportSettings &set
, m_trans_sampling_index(0)
, m_shape_sampling_index(0)
, m_scene(scene)
+ , m_writer(NULL)
{}
AbcExporter::~AbcExporter()
{
- std::map<std::string, AbcTransformWriter*>::iterator it, e;
- for (it = m_xforms.begin(), e = m_xforms.end(); it != e; ++it) {
- delete it->second;
+ /* Free xforms map */
+ m_xforms_type::iterator it_x, e_x;
+ for (it_x = m_xforms.begin(), e_x = m_xforms.end(); it_x != e_x; ++it_x) {
+ delete it_x->second;
}
+ /* Free shapes vector */
for (int i = 0, e = m_shapes.size(); i != e; ++i) {
delete m_shapes[i];
}
+
+ delete m_writer;
}
-void AbcExporter::getShutterSamples(double step, bool time_relative,
+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 */
samples.clear();
- const double time_factor = time_relative ? m_scene->r.frs_sec : 1.0;
- const double shutter_open = m_settings.shutter_open;
- const double shutter_close = m_settings.shutter_close;
+ unsigned int frame_offset = time_relative ? m_settings.frame_start : 0;
+ double time_factor = time_relative ? FPS : 1.0;
+ double shutter_open = m_settings.shutter_open;
+ double shutter_close = m_settings.shutter_close;
+ double time_inc = (shutter_close - shutter_open) / nr_of_samples;
- /* sample all frame */
- if (shutter_open == 0.0 && shutter_close == 1.0) {
- for (double t = 0; t < 1.0; t += step) {
- samples.push_back(t / time_factor);
- }
- }
- else {
- /* sample between shutter open & close */
- const int nsamples = std::max((1.0 / step) - 1.0, 1.0);
- const double time_inc = (shutter_close - shutter_open) / nsamples;
+ /* sample between shutter open & close */
+ for (int sample=0; sample < nr_of_samples; ++sample) {
+ double sample_time = shutter_open + time_inc * sample;
+ double time = (frame_offset + sample_time) / time_factor;
- for (double t = shutter_open; t <= shutter_close; t += time_inc) {
- samples.push_back(t / time_factor);
- }
+ samples.push_back(time);
}
}
Alembic::Abc::TimeSamplingPtr AbcExporter::createTimeSampling(double step)
{
- TimeSamplingPtr time_sampling;
std::vector<double> samples;
if (m_settings.frame_start == m_settings.frame_end) {
- time_sampling.reset(new Alembic::Abc::TimeSampling());
- return time_sampling;
+ return TimeSamplingPtr(new Alembic::Abc::TimeSampling());
}
getShutterSamples(step, true, samples);
- Alembic::Abc::TimeSamplingType ts(static_cast<uint32_t>(samples.size()), 1.0 / m_scene->r.frs_sec);
- time_sampling.reset(new Alembic::Abc::TimeSampling(ts, samples));
+ Alembic::Abc::TimeSamplingType ts(
+ static_cast<uint32_t>(samples.size()),
+ 1.0 / m_scene->r.frs_sec);
- return time_sampling;
+ return TimeSamplingPtr(new Alembic::Abc::TimeSampling(ts, samples));
}
-void AbcExporter::getFrameSet(double step, std::set<double> &frames)
+void AbcExporter::getFrameSet(unsigned int nr_of_samples,
+ std::set<double> &frames)
{
frames.clear();
std::vector<double> shutter_samples;
- getShutterSamples(step, false, shutter_samples);
+ getShutterSamples(nr_of_samples, false, shutter_samples);
- for (int frame = m_settings.frame_start; frame <= m_settings.frame_end; ++frame) {
- for (int j = 0, e = shutter_samples.size(); j < e; ++j) {
+ for (double frame = m_settings.frame_start; frame <= m_settings.frame_end; frame += 1.0) {
+ for (size_t j = 0; j < nr_of_samples; ++j) {
frames.insert(frame + shutter_samples[j]);
}
}
@@ -236,76 +257,49 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled)
}
Scene *scene = m_scene;
- const int fps = FPS;
+ const double fps = FPS;
char buf[16];
- snprintf(buf, 15, "%d", fps);
+ snprintf(buf, 15, "%f", fps);
const std::string str_fps = buf;
Alembic::AbcCoreAbstract::MetaData md;
md.set("FramesPerTimeUnit", str_fps);
- Alembic::Abc::Argument arg(md);
-
-#ifdef WITH_ALEMBIC_HDF5
- if (!m_settings.export_ogawa) {
- m_archive = Alembic::Abc::CreateArchiveWithInfo(Alembic::AbcCoreHDF5::WriteArchive(),
- m_filename,
- "Blender",
- scene_name,
- Alembic::Abc::ErrorHandler::kThrowPolicy,
- arg);
- }
- else
-#endif
- {
- m_archive = Alembic::Abc::CreateArchiveWithInfo(Alembic::AbcCoreOgawa::WriteArchive(),
- m_filename,
- "Blender",
- scene_name,
- Alembic::Abc::ErrorHandler::kThrowPolicy,
- arg);
- }
+ m_writer = new ArchiveWriter(m_filename, scene_name.c_str(), m_settings.export_ogawa, md);
/* Create time samplings for transforms and shapes. */
- TimeSamplingPtr trans_time = createTimeSampling(m_settings.frame_step_xform);
+ TimeSamplingPtr trans_time = createTimeSampling(m_settings.frame_samples_xform);
- m_trans_sampling_index = m_archive.addTimeSampling(*trans_time);
+ m_trans_sampling_index = m_writer->archive().addTimeSampling(*trans_time);
TimeSamplingPtr shape_time;
- if ((m_settings.frame_step_shape == m_settings.frame_step_xform) ||
+ if ((m_settings.frame_samples_shape == m_settings.frame_samples_xform) ||
(m_settings.frame_start == m_settings.frame_end))
{
shape_time = trans_time;
m_shape_sampling_index = m_trans_sampling_index;
}
else {
- shape_time = createTimeSampling(m_settings.frame_step_shape);
- m_shape_sampling_index = m_archive.addTimeSampling(*shape_time);
+ shape_time = createTimeSampling(m_settings.frame_samples_shape);
+ m_shape_sampling_index = m_writer->archive().addTimeSampling(*shape_time);
}
- OBox3dProperty archive_bounds_prop = Alembic::AbcGeom::CreateOArchiveBounds(m_archive, m_trans_sampling_index);
-
- if (m_settings.flatten_hierarchy) {
- createTransformWritersFlat();
- }
- else {
- createTransformWritersHierarchy(bmain->eval_ctx);
- }
+ OBox3dProperty archive_bounds_prop = Alembic::AbcGeom::CreateOArchiveBounds(m_writer->archive(), m_trans_sampling_index);
+ createTransformWritersHierarchy(bmain->eval_ctx);
createShapeWriters(bmain->eval_ctx);
/* Make a list of frames to export. */
std::set<double> xform_frames;
- getFrameSet(m_settings.frame_step_xform, xform_frames);
+ getFrameSet(m_settings.frame_samples_xform, xform_frames);
std::set<double> shape_frames;
- getFrameSet(m_settings.frame_step_shape, shape_frames);
+ getFrameSet(m_settings.frame_samples_shape, shape_frames);
/* Merge all frames needed. */
-
std::set<double> frames(xform_frames);
frames.insert(shape_frames.begin(), shape_frames.end());
@@ -325,20 +319,22 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled)
break;
}
- double f = *begin;
- setCurrentFrame(bmain, f);
+ const double frame = *begin;
- if (shape_frames.count(f) != 0) {
+ /* 'frame' is offset by start frame, so need to cancel the offset. */
+ setCurrentFrame(bmain, frame);
+
+ if (shape_frames.count(frame) != 0) {
for (int i = 0, e = m_shapes.size(); i != e; ++i) {
m_shapes[i]->write();
}
}
- if (xform_frames.count(f) == 0) {
+ if (xform_frames.count(frame) == 0) {
continue;
}
- std::map<std::string, AbcTransformWriter *>::iterator xit, xe;
+ m_xforms_type::iterator xit, xe;
for (xit = m_xforms.begin(), xe = m_xforms.end(); xit != xe; ++xit) {
xit->second->write();
}
@@ -357,13 +353,11 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled)
void AbcExporter::createTransformWritersHierarchy(EvaluationContext *eval_ctx)
{
- Base *base = static_cast<Base *>(m_scene->base.first);
-
- while (base) {
+ for (Base *base = static_cast<Base *>(m_settings.sl->object_bases.first); base; base = base->next) {
Object *ob = base->object;
- if (export_object(&m_settings, ob)) {
- switch(ob->type) {
+ if (export_object(&m_settings, base, false)) {
+ switch (ob->type) {
case OB_LAMP:
case OB_LATTICE:
case OB_MBALL:
@@ -372,133 +366,193 @@ void AbcExporter::createTransformWritersHierarchy(EvaluationContext *eval_ctx)
break;
default:
- exploreTransform(eval_ctx, ob, ob->parent, NULL);
+ exploreTransform(eval_ctx, base, ob->parent, NULL);
}
}
-
- base = base->next;
}
}
-void AbcExporter::createTransformWritersFlat()
+void AbcExporter::exploreTransform(EvaluationContext *eval_ctx, Base *ob_base, Object *parent, Object *dupliObParent)
{
- Base *base = static_cast<Base *>(m_scene->base.first);
-
- while (base) {
- Object *ob = base->object;
-
- if (export_object(&m_settings, ob) && object_is_shape(ob)) {
- std::string name = get_id_name(ob);
- m_xforms[name] = new AbcTransformWriter(ob, m_archive.getTop(), 0, m_trans_sampling_index, m_settings);
- }
+ Object *ob = ob_base->object;
- base = base->next;
+ /* If an object isn't exported itself, its duplilist shouldn't be
+ * exported either. */
+ if (!export_object(&m_settings, ob_base, dupliObParent != NULL)) {
+ return;
}
-}
-void AbcExporter::exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent)
-{
- createTransformWriter(ob, parent, dupliObParent);
+ if (object_type_is_exportable(ob)) {
+ createTransformWriter(ob, parent, dupliObParent);
+ }
ListBase *lb = object_duplilist(eval_ctx, m_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;
- while (link) {
+ for (; link; link = link->next) {
+ /* This skips things like custom bone shapes. */
+ if (m_settings.renderable_only && link->no_draw) {
+ continue;
+ }
+
if (link->type == OB_DUPLIGROUP) {
dupli_ob = link->ob;
dupli_parent = (dupli_ob->parent) ? dupli_ob->parent : ob;
- exploreTransform(eval_ctx, dupli_ob, dupli_parent, ob);
+ fake_base.object = dupli_ob;
+ exploreTransform(eval_ctx, &fake_base, dupli_parent, ob);
}
-
- link = link->next;
}
}
free_object_duplilist(lb);
}
-void AbcExporter::createTransformWriter(Object *ob, Object *parent, Object *dupliObParent)
+AbcTransformWriter * AbcExporter::createTransformWriter(Object *ob, Object *parent, Object *dupliObParent)
{
- const std::string name = get_object_dag_path_name(ob, dupliObParent);
+ /* An object should not be its own parent, or we'll get infinite loops. */
+ BLI_assert(ob != parent);
+ BLI_assert(ob != dupliObParent);
- /* check if we have already created a transform writer for this object */
- if (m_xforms.find(name) != m_xforms.end()){
- std::cerr << "xform " << name << " already exists\n";
- return;
+ std::string name;
+ if (m_settings.flatten_hierarchy) {
+ name = get_id_name(ob);
+ }
+ else {
+ name = get_object_dag_path_name(ob, dupliObParent);
}
- AbcTransformWriter *parent_xform = NULL;
+ /* check if we have already created a transform writer for this object */
+ AbcTransformWriter *my_writer = getXForm(name);
+ if (my_writer != NULL) {
+ return my_writer;
+ }
- if (parent) {
- const std::string parentname = get_object_dag_path_name(parent, dupliObParent);
- parent_xform = getXForm(parentname);
+ AbcTransformWriter *parent_writer = NULL;
+ Alembic::Abc::OObject alembic_parent;
- if (!parent_xform) {
- if (parent->parent) {
- createTransformWriter(parent, parent->parent, dupliObParent);
+ if (m_settings.flatten_hierarchy || parent == NULL) {
+ /* Parentless objects still have the "top object" as parent
+ * in Alembic. */
+ alembic_parent = m_writer->archive().getTop();
+ }
+ else {
+ /* Since there are so many different ways to find parents (as evident
+ * in the number of conditions below), we can't really look up the
+ * parent by name. We'll just call createTransformWriter(), which will
+ * return the parent's AbcTransformWriter pointer. */
+ if (parent->parent) {
+ if (parent == dupliObParent) {
+ parent_writer = createTransformWriter(parent, parent->parent, NULL);
}
else {
- createTransformWriter(parent, dupliObParent, dupliObParent);
+ parent_writer = createTransformWriter(parent, parent->parent, dupliObParent);
}
-
- parent_xform = getXForm(parentname);
}
- }
+ else if (parent == dupliObParent) {
+ if (dupliObParent->parent == NULL) {
+ parent_writer = createTransformWriter(parent, NULL, NULL);
+ }
+ else {
+ parent_writer = createTransformWriter(parent, dupliObParent->parent, dupliObParent->parent);
+ }
+ }
+ else {
+ parent_writer = createTransformWriter(parent, dupliObParent, dupliObParent);
+ }
- if (parent_xform) {
- m_xforms[name] = new AbcTransformWriter(ob, parent_xform->alembicXform(), parent_xform, m_trans_sampling_index, m_settings);
- m_xforms[name]->setParent(parent);
+ BLI_assert(parent_writer);
+ alembic_parent = parent_writer->alembicXform();
}
- else {
- m_xforms[name] = new AbcTransformWriter(ob, m_archive.getTop(), NULL, m_trans_sampling_index, m_settings);
+
+ my_writer = new AbcTransformWriter(ob, alembic_parent, parent_writer,
+ m_trans_sampling_index, m_settings);
+
+ /* When flattening, the matrix of the dupliobject has to be added. */
+ if (m_settings.flatten_hierarchy && dupliObParent) {
+ my_writer->m_proxy_from = dupliObParent;
}
+
+ m_xforms[name] = my_writer;
+ return my_writer;
}
void AbcExporter::createShapeWriters(EvaluationContext *eval_ctx)
{
- Base *base = static_cast<Base *>(m_scene->base.first);
-
- while (base) {
- Object *ob = base->object;
- exploreObject(eval_ctx, ob, NULL);
-
- base = base->next;
+ for (Base *base = static_cast<Base *>(m_settings.sl->object_bases.first); base; base = base->next) {
+ exploreObject(eval_ctx, base, NULL);
}
}
-void AbcExporter::exploreObject(EvaluationContext *eval_ctx, Object *ob, Object *dupliObParent)
+void AbcExporter::exploreObject(EvaluationContext *eval_ctx, Base *ob_base, Object *dupliObParent)
{
- ListBase *lb = object_duplilist(eval_ctx, m_scene, ob);
-
- createShapeWriter(ob, dupliObParent);
+ /* If an object isn't exported itself, its duplilist shouldn't be
+ * exported either. */
+ if (!export_object(&m_settings, ob_base, dupliObParent != NULL)) {
+ return;
+ }
+
+ createShapeWriter(ob_base, dupliObParent);
+ Object *ob = ob_base->object;
+ ListBase *lb = object_duplilist(eval_ctx, m_scene, ob);
+
if (lb) {
- DupliObject *dupliob = static_cast<DupliObject *>(lb->first);
+ Base fake_base = *ob_base; // copy flags (like selection state) from the real object.
+ fake_base.next = fake_base.prev = NULL;
- while (dupliob) {
- if (dupliob->type == OB_DUPLIGROUP) {
- exploreObject(eval_ctx, dupliob->ob, ob);
- }
+ DupliObject *link = static_cast<DupliObject *>(lb->first);
- dupliob = dupliob->next;
+ for (; link; link = link->next) {
+ /* This skips things like custom bone shapes. */
+ if (m_settings.renderable_only && link->no_draw) {
+ continue;
+ }
+ if (link->type == OB_DUPLIGROUP) {
+ fake_base.object = link->ob;
+ exploreObject(eval_ctx, &fake_base, ob);
+ }
}
}
free_object_duplilist(lb);
}
-void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent)
+void AbcExporter::createParticleSystemsWriters(Object *ob, AbcTransformWriter *xform)
{
- if (!object_is_shape(ob)) {
+ if (!m_settings.export_hair && !m_settings.export_particles) {
return;
}
- if (!export_object(&m_settings, ob)) {
+ ParticleSystem *psys = static_cast<ParticleSystem *>(ob->particlesystem.first);
+
+ for (; psys; psys = psys->next) {
+ if (!psys_check_enabled(ob, psys, G.is_rendering) || !psys->part) {
+ continue;
+ }
+
+ if (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));
+ }
+ 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));
+ }
+ }
+}
+
+void AbcExporter::createShapeWriter(Base *ob_base, Object *dupliObParent)
+{
+ Object *ob = ob_base->object;
+
+ if (!object_type_is_exportable(ob)) {
return;
}
@@ -514,32 +568,18 @@ void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent)
AbcTransformWriter *xform = getXForm(name);
if (!xform) {
- std::cerr << __func__ << ": xform " << name << " is NULL\n";
+ ABC_LOG(m_settings.logger) << __func__ << ": xform " << name << " is NULL\n";
return;
}
- ParticleSystem *psys = static_cast<ParticleSystem *>(ob->particlesystem.first);
-
- for (; psys; psys = psys->next) {
- if (!psys_check_enabled(ob, psys, G.is_rendering) || !psys->part) {
- continue;
- }
-
- if (psys->part->type == PART_HAIR) {
- m_settings.export_child_hairs = true;
- m_shapes.push_back(new AbcHairWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys));
- }
- else if (psys->part->type == PART_EMITTER) {
- m_shapes.push_back(new AbcPointsWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys));
- }
- }
+ createParticleSystemsWriters(ob, xform);
- switch(ob->type) {
+ switch (ob->type) {
case OB_MESH:
{
Mesh *me = static_cast<Mesh *>(ob->data);
- if (!me || me->totvert == 0) {
+ if (!me) {
return;
}
@@ -594,7 +634,7 @@ AbcTransformWriter *AbcExporter::getXForm(const std::string &name)
void AbcExporter::setCurrentFrame(Main *bmain, double t)
{
- m_scene->r.cfra = std::floor(t);
- m_scene->r.subframe = t - m_scene->r.cfra;
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, m_scene, m_scene->lay);
+ 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);
}
diff --git a/source/blender/alembic/intern/abc_exporter.h b/source/blender/alembic/intern/abc_exporter.h
index 070eb9ea81a..15158a9ef51 100644
--- a/source/blender/alembic/intern/abc_exporter.h
+++ b/source/blender/alembic/intern/abc_exporter.h
@@ -28,26 +28,33 @@
#include <set>
#include <vector>
+#include "abc_util.h"
+
class AbcObjectWriter;
class AbcTransformWriter;
+class ArchiveWriter;
struct EvaluationContext;
struct Main;
struct Object;
struct Scene;
+struct SceneLayer;
+struct Base;
struct ExportSettings {
ExportSettings();
Scene *scene;
+ SceneLayer *sl; // Scene layer to export; all its objects will be exported, unless selected_only=true
+ SimpleLogger logger;
bool selected_only;
bool visible_layers_only;
bool renderable_only;
double frame_start, frame_end;
- double frame_step_xform;
- double frame_step_shape;
+ double frame_samples_xform;
+ double frame_samples_shape;
double shutter_open;
double shutter_close;
float global_scale;
@@ -59,12 +66,18 @@ struct ExportSettings {
bool export_vcols;
bool export_face_sets;
bool export_vweigths;
+ bool export_hair;
+ bool export_particles;
bool apply_subdiv;
bool use_subdiv_schema;
bool export_child_hairs;
bool export_ogawa;
bool pack_uv;
+ bool triangulate;
+
+ int quad_method;
+ int ngon_method;
bool do_convert_axis;
float convert_matrix[3][3];
@@ -75,12 +88,16 @@ class AbcExporter {
const char *m_filename;
- Alembic::Abc::OArchive m_archive;
unsigned int m_trans_sampling_index, m_shape_sampling_index;
Scene *m_scene;
- std::map<std::string, AbcTransformWriter *> m_xforms;
+ ArchiveWriter *m_writer;
+
+ /* mapping from name to transform writer */
+ typedef std::map<std::string, AbcTransformWriter *> m_xforms_type;
+ m_xforms_type m_xforms;
+
std::vector<AbcObjectWriter *> m_shapes;
public:
@@ -89,20 +106,22 @@ public:
void operator()(Main *bmain, float &progress, bool &was_canceled);
-private:
- void getShutterSamples(double step, bool time_relative, std::vector<double> &samples);
+protected:
+ void getShutterSamples(unsigned int nr_of_samples,
+ bool time_relative,
+ std::vector<double> &samples);
+ void getFrameSet(unsigned int nr_of_samples, std::set<double> &frames);
+private:
Alembic::Abc::TimeSamplingPtr createTimeSampling(double step);
- void getFrameSet(double step, std::set<double> &frames);
-
void createTransformWritersHierarchy(EvaluationContext *eval_ctx);
- void createTransformWritersFlat();
- void createTransformWriter(Object *ob, Object *parent, Object *dupliObParent);
- void exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent = NULL);
- void exploreObject(EvaluationContext *eval_ctx, Object *ob, Object *dupliObParent);
+ AbcTransformWriter * createTransformWriter(Object *ob, Object *parent, Object *dupliObParent);
+ void exploreTransform(EvaluationContext *eval_ctx, Base *ob_base, Object *parent, Object *dupliObParent);
+ void exploreObject(EvaluationContext *eval_ctx, Base *ob_base, Object *dupliObParent);
void createShapeWriters(EvaluationContext *eval_ctx);
- void createShapeWriter(Object *ob, Object *dupliObParent);
+ void createShapeWriter(Base *ob_base, Object *dupliObParent);
+ void createParticleSystemsWriters(Object *ob, AbcTransformWriter *xform);
AbcTransformWriter *getXForm(const std::string &name);
diff --git a/source/blender/alembic/intern/abc_hair.cc b/source/blender/alembic/intern/abc_hair.cc
index 45bf9b7ab8a..8f8ed2019d5 100644
--- a/source/blender/alembic/intern/abc_hair.cc
+++ b/source/blender/alembic/intern/abc_hair.cc
@@ -56,10 +56,11 @@ AbcHairWriter::AbcHairWriter(Scene *scene,
ExportSettings &settings,
ParticleSystem *psys)
: AbcObjectWriter(scene, ob, time_sampling, settings, parent)
+ , m_uv_warning_shown(false)
{
m_psys = psys;
- OCurves curves(parent->alembicXform(), m_name, m_time_sampling);
+ OCurves curves(parent->alembicXform(), psys->name, m_time_sampling);
m_schema = curves.getSchema();
}
@@ -75,9 +76,8 @@ void AbcHairWriter::do_write()
return;
}
- DerivedMesh *dm = mesh_create_derived_view(m_scene, m_object, CD_MASK_MESH);
+ DerivedMesh *dm = mesh_create_derived_render(m_scene, m_object, CD_MASK_MESH);
DM_ensure_tessface(dm);
- DM_update_tessface_data(dm);
std::vector<Imath::V3f> verts;
std::vector<int32_t> hvertices;
@@ -133,8 +133,10 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
MFace *mface = dm->getTessFaceArray(dm);
MVert *mverts = dm->getVertArray(dm);
- if (!mtface || !mface) {
- std::fprintf(stderr, "Warning, no UV set found for underlying geometry.\n");
+ if ((!mtface || !mface) && !m_uv_warning_shown) {
+ std::fprintf(stderr, "Warning, no UV set found for underlying geometry of %s.\n",
+ m_object->id.name + 2);
+ m_uv_warning_shown = true;
}
ParticleData * pa = m_psys->particles;
@@ -164,7 +166,7 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, normal, NULL, NULL, NULL, NULL);
- copy_zup_yup(tmp_nor.getValue(), normal);
+ copy_yup_from_zup(tmp_nor.getValue(), normal);
norm_values.push_back(tmp_nor);
}
}
@@ -198,7 +200,7 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
MVert *mv = mverts + vtx[o];
normal_short_to_float_v3(normal, mv->no);
- copy_zup_yup(tmp_nor.getValue(), normal);
+ copy_yup_from_zup(tmp_nor.getValue(), normal);
norm_values.push_back(tmp_nor);
found = true;
break;
@@ -239,13 +241,8 @@ void AbcHairWriter::write_hair_child_sample(DerivedMesh *dm,
invert_m4_m4_safe(inv_mat, m_object->obmat);
MTFace *mtface = static_cast<MTFace *>(CustomData_get_layer(&dm->faceData, CD_MTFACE));
- MFace *mface = dm->getTessFaceArray(dm);
MVert *mverts = dm->getVertArray(dm);
- if (!mtface || !mface) {
- std::fprintf(stderr, "Warning, no UV set found for underlying geometry.\n");
- }
-
ParticleCacheKey **cache = m_psys->childcache;
ParticleCacheKey *path;
@@ -254,22 +251,37 @@ void AbcHairWriter::write_hair_child_sample(DerivedMesh *dm,
for (int p = 0; p < m_psys->totchild; ++p, ++pc) {
path = cache[p];
- if (part->from == PART_FROM_FACE) {
+ if (part->from == PART_FROM_FACE &&
+ part->childtype != PART_CHILD_PARTICLES &&
+ mtface) {
const int num = pc->num;
+ if (num < 0) {
+ ABC_LOG(m_settings.logger)
+ << "Warning, child particle of hair system " << m_psys->name
+ << " has unknown face index of geometry of "<< (m_object->id.name + 2)
+ << ", skipping child hair." << std::endl;
+ continue;
+ }
MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, num, CD_MFACE));
MTFace *tface = mtface + num;
- if (mface && mtface) {
- float r_uv[2], tmpnor[3], mapfw[4], vec[3];
+ float r_uv[2], tmpnor[3], mapfw[4], vec[3];
- psys_interpolate_uvs(tface, face->v4, pc->fuv, r_uv);
- uv_values.push_back(Imath::V2f(r_uv[0], r_uv[1]));
+ psys_interpolate_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, NULL);
- /* Convert Z-up to Y-up. */
- norm_values.push_back(Imath::V3f(tmpnor[0], tmpnor[2], -tmpnor[1]));
+ /* Convert Z-up to Y-up. */
+ norm_values.push_back(Imath::V3f(tmpnor[0], tmpnor[2], -tmpnor[1]));
+ }
+ else {
+ if (uv_values.size()) {
+ uv_values.push_back(uv_values[pc->parent]);
+ }
+ if (norm_values.size()) {
+ norm_values.push_back(norm_values[pc->parent]);
}
}
diff --git a/source/blender/alembic/intern/abc_hair.h b/source/blender/alembic/intern/abc_hair.h
index d132b60be12..61f5fe361f8 100644
--- a/source/blender/alembic/intern/abc_hair.h
+++ b/source/blender/alembic/intern/abc_hair.h
@@ -37,6 +37,8 @@ class AbcHairWriter : public AbcObjectWriter {
Alembic::AbcGeom::OCurvesSchema m_schema;
Alembic::AbcGeom::OCurvesSchema::Sample m_sample;
+ bool m_uv_warning_shown;
+
public:
AbcHairWriter(Scene *scene,
Object *ob,
diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc
index f1c7b6b3aa3..bc62db5702c 100644
--- a/source/blender/alembic/intern/abc_mesh.cc
+++ b/source/blender/alembic/intern/abc_mesh.cc
@@ -37,8 +37,7 @@ extern "C" {
#include "BLI_math_geom.h"
#include "BLI_string.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
+#include "BKE_cdderivedmesh.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
@@ -49,6 +48,9 @@ extern "C" {
#include "WM_types.h"
#include "ED_mesh.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
}
using Alembic::Abc::FloatArraySample;
@@ -109,7 +111,7 @@ static void get_vertices(DerivedMesh *dm, std::vector<Imath::V3f> &points)
MVert *verts = dm->getVertArray(dm);
for (int i = 0, e = dm->getNumVerts(dm); i < e; ++i) {
- copy_zup_yup(points[i].getValue(), verts[i].co);
+ copy_yup_from_zup(points[i].getValue(), verts[i].co);
}
}
@@ -143,19 +145,6 @@ static void get_topology(DerivedMesh *dm,
}
}
-static void get_material_indices(DerivedMesh *dm, std::vector<int32_t> &indices)
-{
- indices.clear();
- indices.reserve(dm->getNumTessFaces(dm));
-
- MPoly *mpolys = dm->getPolyArray(dm);
-
- for (int i = 1, e = dm->getNumPolys(dm); i < e; ++i) {
- MPoly *mpoly = &mpolys[i];
- indices.push_back(mpoly->mat_nr);
- }
-}
-
static void get_creases(DerivedMesh *dm,
std::vector<int32_t> &indices,
std::vector<int32_t> &lengths,
@@ -192,7 +181,7 @@ static void get_vertex_normals(DerivedMesh *dm, std::vector<Imath::V3f> &normals
for (int i = 0, e = dm->getNumVerts(dm); i < e; ++i) {
normal_short_to_float_v3(no, verts[i].no);
- copy_zup_yup(normals[i].getValue(), no);
+ copy_yup_from_zup(normals[i].getValue(), no);
}
}
@@ -221,7 +210,7 @@ static void get_loop_normals(DerivedMesh *dm, std::vector<Imath::V3f> &normals)
for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) {
const int index = ml->v;
- copy_zup_yup(normals[loop_index].getValue(), lnors[index]);
+ copy_yup_from_zup(normals[loop_index].getValue(), lnors[index]);
}
}
}
@@ -236,14 +225,14 @@ static void get_loop_normals(DerivedMesh *dm, std::vector<Imath::V3f> &normals)
BKE_mesh_calc_poly_normal(mp, ml - (mp->totloop - 1), verts, no);
for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) {
- copy_zup_yup(normals[loop_index].getValue(), no);
+ copy_yup_from_zup(normals[loop_index].getValue(), no);
}
}
else {
/* Smooth shaded, use individual vert normals. */
for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) {
normal_short_to_float_v3(no, verts[ml->v].no);
- copy_zup_yup(normals[loop_index].getValue(), no);
+ copy_yup_from_zup(normals[loop_index].getValue(), no);
}
}
}
@@ -306,7 +295,6 @@ AbcMeshWriter::AbcMeshWriter(Scene *scene,
{
m_is_animated = isAnimated();
m_subsurf_mod = NULL;
- m_has_per_face_materials = false;
m_is_subd = false;
/* If the object is static, use the default static time sampling. */
@@ -366,7 +354,7 @@ bool AbcMeshWriter::isAnimated() const
md = md->next;
}
- return false;
+ return me->adt != NULL;
}
void AbcMeshWriter::do_write()
@@ -403,8 +391,8 @@ void AbcMeshWriter::writeMesh(DerivedMesh *dm)
get_vertices(dm, points);
get_topology(dm, poly_verts, loop_counts, smooth_normal);
- if (m_first_frame) {
- writeCommonData(dm, m_mesh_schema);
+ if (m_first_frame && m_settings.export_face_sets) {
+ writeFaceSets(dm, m_mesh_schema);
}
m_mesh_sample = OPolyMeshSchema::Sample(V3fArraySample(points),
@@ -412,7 +400,7 @@ void AbcMeshWriter::writeMesh(DerivedMesh *dm)
Int32ArraySample(loop_counts));
UVSample sample;
- if (m_settings.export_uvs) {
+ if (m_first_frame && m_settings.export_uvs) {
const char *name = get_uv_sample(sample, m_custom_data_config, &dm->loopData);
if (!sample.indices.empty() && !sample.uvs.empty()) {
@@ -472,9 +460,8 @@ void AbcMeshWriter::writeSubD(DerivedMesh *dm)
get_topology(dm, poly_verts, loop_counts, smooth_normal);
get_creases(dm, crease_indices, crease_lengths, crease_sharpness);
- if (m_first_frame) {
- /* create materials' face_sets */
- writeCommonData(dm, m_subdiv_schema);
+ if (m_first_frame && m_settings.export_face_sets) {
+ writeFaceSets(dm, m_subdiv_schema);
}
m_subdiv_sample = OSubDSchema::Sample(V3fArraySample(points),
@@ -482,7 +469,7 @@ void AbcMeshWriter::writeSubD(DerivedMesh *dm)
Int32ArraySample(loop_counts));
UVSample sample;
- if (m_settings.export_uvs) {
+ if (m_first_frame && m_settings.export_uvs) {
const char *name = get_uv_sample(sample, m_custom_data_config, &dm->loopData);
if (!sample.indices.empty() && !sample.uvs.empty()) {
@@ -511,7 +498,7 @@ void AbcMeshWriter::writeSubD(DerivedMesh *dm)
}
template <typename Schema>
-void AbcMeshWriter::writeCommonData(DerivedMesh *dm, Schema &schema)
+void AbcMeshWriter::writeFaceSets(DerivedMesh *dm, Schema &schema)
{
std::map< std::string, std::vector<int32_t> > geo_groups;
getGeoGroups(dm, geo_groups);
@@ -538,6 +525,23 @@ DerivedMesh *AbcMeshWriter::getFinalMesh()
m_subsurf_mod->mode &= ~eModifierMode_DisableTemporary;
}
+ if (m_settings.triangulate) {
+ const bool tag_only = false;
+ const int quad_method = m_settings.quad_method;
+ const int ngon_method = m_settings.ngon_method;
+
+ BMesh *bm = DM_to_bmesh(dm, true);
+
+ BM_mesh_triangulate(bm, quad_method, ngon_method, tag_only, NULL, NULL, NULL);
+
+ DerivedMesh *result = CDDM_from_bmesh(bm, false);
+ BM_mesh_free(bm);
+
+ freeMesh(dm);
+
+ dm = result;
+ }
+
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);
@@ -560,7 +564,7 @@ void AbcMeshWriter::writeArbGeoParams(DerivedMesh *dm)
return;
}
- if (m_settings.export_vcols) {
+ 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);
}
@@ -568,18 +572,6 @@ void AbcMeshWriter::writeArbGeoParams(DerivedMesh *dm)
write_custom_data(m_mesh_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPCOL);
}
}
-
- if (m_first_frame && m_has_per_face_materials) {
- std::vector<int32_t> material_indices;
-
- if (m_settings.export_face_sets) {
- get_material_indices(dm, material_indices);
-
- OFaceSetSchema::Sample samp;
- samp.setFaces(Int32ArraySample(material_indices));
- m_face_set.getSchema().set(samp);
- }
- }
}
void AbcMeshWriter::getVelocities(DerivedMesh *dm, std::vector<Imath::V3f> &vels)
@@ -597,7 +589,7 @@ void AbcMeshWriter::getVelocities(DerivedMesh *dm, std::vector<Imath::V3f> &vels
float *mesh_vels = reinterpret_cast<float *>(fss->meshVelocities);
for (int i = 0; i < totverts; ++i) {
- copy_zup_yup(vels[i].getValue(), mesh_vels);
+ copy_yup_from_zup(vels[i].getValue(), mesh_vels);
mesh_vels += 3;
}
}
@@ -653,75 +645,6 @@ void AbcMeshWriter::getGeoGroups(
/* Some helpers for mesh generation */
namespace utils {
-void mesh_add_verts(Mesh *mesh, size_t len)
-{
- if (len == 0) {
- return;
- }
-
- const int totvert = mesh->totvert + len;
- CustomData vdata;
- CustomData_copy(&mesh->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert);
- CustomData_copy_data(&mesh->vdata, &vdata, 0, 0, mesh->totvert);
-
- if (!CustomData_has_layer(&vdata, CD_MVERT)) {
- CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert);
- }
-
- CustomData_free(&mesh->vdata, mesh->totvert);
- mesh->vdata = vdata;
- BKE_mesh_update_customdata_pointers(mesh, false);
-
- mesh->totvert = totvert;
-}
-
-static void mesh_add_mloops(Mesh *mesh, size_t len)
-{
- if (len == 0) {
- return;
- }
-
- /* new face count */
- const int totloops = mesh->totloop + len;
-
- CustomData ldata;
- CustomData_copy(&mesh->ldata, &ldata, CD_MASK_MESH, CD_DEFAULT, totloops);
- CustomData_copy_data(&mesh->ldata, &ldata, 0, 0, mesh->totloop);
-
- if (!CustomData_has_layer(&ldata, CD_MLOOP)) {
- CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, NULL, totloops);
- }
-
- CustomData_free(&mesh->ldata, mesh->totloop);
- mesh->ldata = ldata;
- BKE_mesh_update_customdata_pointers(mesh, false);
-
- mesh->totloop = totloops;
-}
-
-static void mesh_add_mpolygons(Mesh *mesh, size_t len)
-{
- if (len == 0) {
- return;
- }
-
- const int totpolys = mesh->totpoly + len;
-
- CustomData pdata;
- CustomData_copy(&mesh->pdata, &pdata, CD_MASK_MESH, CD_DEFAULT, totpolys);
- CustomData_copy_data(&mesh->pdata, &pdata, 0, 0, mesh->totpoly);
-
- if (!CustomData_has_layer(&pdata, CD_MPOLY)) {
- CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, NULL, totpolys);
- }
-
- CustomData_free(&mesh->pdata, mesh->totpoly);
- mesh->pdata = pdata;
- BKE_mesh_update_customdata_pointers(mesh, false);
-
- mesh->totpoly = totpolys;
-}
-
static void build_mat_map(const Main *bmain, std::map<std::string, Material *> &mat_map)
{
Material *material = static_cast<Material *>(bmain->mat.first);
@@ -767,7 +690,7 @@ static void assign_materials(Main *bmain, Object *ob, const std::map<std::string
assigned_name = mat_iter->second;
}
- assign_material(ob, assigned_name, it->second, BKE_MAT_ASSIGN_OBJECT);
+ assign_material(ob, assigned_name, it->second, BKE_MAT_ASSIGN_OBDATA);
}
}
}
@@ -784,6 +707,7 @@ struct AbcMeshData {
Int32ArraySamplePtr face_counts;
P3fArraySamplePtr positions;
+ P3fArraySamplePtr ceil_positions;
N3fArraySamplePtr vertex_normals;
N3fArraySamplePtr face_normals;
@@ -792,43 +716,19 @@ struct AbcMeshData {
UInt32ArraySamplePtr uvs_indices;
};
-static void *add_customdata_cb(void *user_data, const char *name, int data_type)
+static void read_mverts_interp(MVert *mverts, const P3fArraySamplePtr &positions, const P3fArraySamplePtr &ceil_positions, const float weight)
{
- Mesh *mesh = static_cast<Mesh *>(user_data);
- CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
- void *cd_ptr = NULL;
+ float tmp[3];
+ for (int i = 0; i < positions->size(); ++i) {
+ MVert &mvert = mverts[i];
+ const Imath::V3f &floor_pos = (*positions)[i];
+ const Imath::V3f &ceil_pos = (*ceil_positions)[i];
- int index = -1;
- if (cd_data_type == CD_MLOOPUV) {
- index = ED_mesh_uv_texture_add(mesh, name, true);
- cd_ptr = CustomData_get_layer(&mesh->ldata, cd_data_type);
- }
- else if (cd_data_type == CD_MLOOPCOL) {
- index = ED_mesh_color_add(mesh, name, true);
- cd_ptr = CustomData_get_layer(&mesh->ldata, cd_data_type);
- }
+ interp_v3_v3v3(tmp, floor_pos.getValue(), ceil_pos.getValue(), weight);
+ copy_zup_from_yup(mvert.co, tmp);
- if (index == -1) {
- return NULL;
+ mvert.bweight = 0;
}
-
- return cd_ptr;
-}
-
-CDStreamConfig create_config(Mesh *mesh)
-{
- CDStreamConfig config;
-
- config.mvert = mesh->mvert;
- config.mpoly = mesh->mpoly;
- config.mloop = mesh->mloop;
- config.totpoly = mesh->totpoly;
- config.totloop = mesh->totloop;
- config.user_data = mesh;
- config.loopdata = &mesh->ldata;
- config.add_customdata_cb = add_customdata_cb;
-
- return config;
}
static void read_mverts(CDStreamConfig &config, const AbcMeshData &mesh_data)
@@ -837,6 +737,14 @@ static void read_mverts(CDStreamConfig &config, const AbcMeshData &mesh_data)
const P3fArraySamplePtr &positions = mesh_data.positions;
const N3fArraySamplePtr &normals = mesh_data.vertex_normals;
+ if ( config.weight != 0.0f
+ && mesh_data.ceil_positions != NULL
+ && mesh_data.ceil_positions->size() == positions->size())
+ {
+ read_mverts_interp(mverts, positions, mesh_data.ceil_positions, config.weight);
+ return;
+ }
+
read_mverts(mverts, positions, normals);
}
@@ -846,7 +754,7 @@ void read_mverts(MVert *mverts, const P3fArraySamplePtr &positions, const N3fArr
MVert &mvert = mverts[i];
Imath::V3f pos_in = (*positions)[i];
- copy_yup_zup(mvert.co, pos_in.getValue());
+ copy_zup_from_yup(mvert.co, pos_in.getValue());
mvert.bweight = 0;
@@ -856,7 +764,7 @@ void read_mverts(MVert *mverts, const P3fArraySamplePtr &positions, const N3fArr
short no[3];
normal_float_to_short_v3(no, nor_in.getValue());
- copy_yup_zup(mvert.no, no);
+ copy_zup_from_yup(mvert.no, no);
}
}
}
@@ -959,6 +867,135 @@ ABC_INLINE void read_normals_params(AbcMeshData &abc_data,
}
}
+static bool check_smooth_poly_flag(DerivedMesh *dm)
+{
+ MPoly *mpolys = dm->getPolyArray(dm);
+
+ for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) {
+ MPoly &poly = mpolys[i];
+
+ if ((poly.flag & ME_SMOOTH) != 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void set_smooth_poly_flag(DerivedMesh *dm)
+{
+ MPoly *mpolys = dm->getPolyArray(dm);
+
+ for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) {
+ MPoly &poly = mpolys[i];
+ poly.flag |= ME_SMOOTH;
+ }
+}
+
+static void *add_customdata_cb(void *user_data, const char *name, int data_type)
+{
+ DerivedMesh *dm = static_cast<DerivedMesh *>(user_data);
+ CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
+ void *cd_ptr;
+ CustomData *loopdata;
+ int numloops;
+
+ /* unsupported custom data type -- don't do anything. */
+ if (!ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) {
+ return NULL;
+ }
+
+ loopdata = dm->getLoopDataLayout(dm);
+ cd_ptr = CustomData_get_layer_named(loopdata, cd_data_type, name);
+ if (cd_ptr != NULL) {
+ /* layer already exists, so just return it. */
+ return cd_ptr;
+ }
+
+ /* 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);
+ cd_ptr = CustomData_add_layer_named(loopdata, cd_data_type, CD_DEFAULT,
+ NULL, numloops, name);
+ return cd_ptr;
+}
+
+static void get_weight_and_index(CDStreamConfig &config,
+ Alembic::AbcCoreAbstract::TimeSamplingPtr time_sampling,
+ size_t samples_number)
+{
+ Alembic::AbcGeom::index_t i0, i1;
+
+ config.weight = get_weight_and_index(config.time,
+ time_sampling,
+ samples_number,
+ i0,
+ i1);
+
+ config.index = i0;
+ config.ceil_index = i1;
+}
+
+static void read_mesh_sample(ImportSettings *settings,
+ const IPolyMeshSchema &schema,
+ const ISampleSelector &selector,
+ CDStreamConfig &config,
+ bool &do_normals)
+{
+ const IPolyMeshSchema::Sample sample = schema.getValue(selector);
+
+ AbcMeshData abc_mesh_data;
+ abc_mesh_data.face_counts = sample.getFaceCounts();
+ abc_mesh_data.face_indices = sample.getFaceIndices();
+ abc_mesh_data.positions = sample.getPositions();
+
+ read_normals_params(abc_mesh_data, schema.getNormalsParam(), selector);
+
+ do_normals = (abc_mesh_data.face_normals != NULL);
+
+ get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples());
+
+ if (config.weight != 0.0f) {
+ Alembic::AbcGeom::IPolyMeshSchema::Sample ceil_sample;
+ schema.get(ceil_sample, Alembic::Abc::ISampleSelector(config.ceil_index));
+ abc_mesh_data.ceil_positions = ceil_sample.getPositions();
+ }
+
+ if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) {
+ read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector);
+ }
+
+ if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) {
+ read_mverts(config, abc_mesh_data);
+ }
+
+ if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
+ read_mpolys(config, abc_mesh_data);
+ }
+
+ if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
+ read_custom_data(schema.getArbGeomParams(), config, selector);
+ }
+
+ /* TODO: face sets */
+}
+
+CDStreamConfig get_config(DerivedMesh *dm)
+{
+ CDStreamConfig config;
+
+ config.user_data = dm;
+ config.mvert = dm->getVertArray(dm);
+ config.mloop = dm->getLoopArray(dm);
+ config.mpoly = dm->getPolyArray(dm);
+ config.totloop = dm->getNumLoops(dm);
+ config.totpoly = dm->getNumPolys(dm);
+ config.loopdata = dm->getLoopDataLayout(dm);
+ config.add_customdata_cb = add_customdata_cb;
+
+ return config;
+}
+
/* ************************************************************************** */
AbcMeshReader::AbcMeshReader(const IObject &object, ImportSettings &settings)
@@ -968,7 +1005,8 @@ AbcMeshReader::AbcMeshReader(const IObject &object, ImportSettings &settings)
IPolyMesh ipoly_mesh(m_iobject, kWrapExisting);
m_schema = ipoly_mesh.getSchema();
- get_min_max_time(m_schema, m_min_time, m_max_time);
+
+ get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time);
}
bool AbcMeshReader::valid() const
@@ -976,31 +1014,21 @@ bool AbcMeshReader::valid() const
return m_schema.valid();
}
-void AbcMeshReader::readObjectData(Main *bmain, float time)
+void AbcMeshReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
{
Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
m_object->data = mesh;
- const ISampleSelector sample_sel(time);
- const IPolyMeshSchema::Sample sample = m_schema.getValue(sample_sel);
+ DerivedMesh *dm = CDDM_from_mesh(mesh);
+ DerivedMesh *ndm = this->read_derivedmesh(dm, sample_sel, MOD_MESHSEQ_READ_ALL, NULL);
- const P3fArraySamplePtr &positions = sample.getPositions();
- const Int32ArraySamplePtr &face_indices = sample.getFaceIndices();
- const Int32ArraySamplePtr &face_counts = sample.getFaceCounts();
-
- utils::mesh_add_verts(mesh, positions->size());
- utils::mesh_add_mpolygons(mesh, face_counts->size());
- utils::mesh_add_mloops(mesh, face_indices->size());
-
- m_mesh_data = create_config(mesh);
+ if (ndm != dm) {
+ dm->release(dm);
+ }
- bool has_smooth_normals = false;
- read_mesh_sample(m_settings, m_schema, sample_sel, m_mesh_data, has_smooth_normals);
-
- BKE_mesh_calc_normals(mesh);
- BKE_mesh_calc_edges(mesh, false, false);
+ DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true);
if (m_settings->validate_meshes) {
BKE_mesh_validate(mesh, false, false);
@@ -1013,6 +1041,91 @@ void AbcMeshReader::readObjectData(Main *bmain, float time)
}
}
+bool AbcMeshReader::accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const
+{
+ if (!Alembic::AbcGeom::IPolyMesh::matches(alembic_header)) {
+ *err_str = "Object type mismatch, Alembic object path pointed to PolyMesh when importing, but not any more.";
+ return false;
+ }
+
+ if (ob->type != OB_MESH) {
+ *err_str = "Object type mismatch, Alembic object path points to PolyMesh.";
+ return false;
+ }
+
+ return true;
+}
+
+DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm,
+ const ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str)
+{
+ const IPolyMeshSchema::Sample sample = m_schema.getValue(sample_sel);
+
+ const P3fArraySamplePtr &positions = sample.getPositions();
+ const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices();
+ const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts();
+
+ DerivedMesh *new_dm = NULL;
+
+ /* Only read point data when streaming meshes, unless we need to create new ones. */
+ ImportSettings settings;
+ settings.read_flag |= read_flag;
+
+ if (dm->getNumVerts(dm) != positions->size()) {
+ new_dm = CDDM_from_template(dm,
+ positions->size(),
+ 0,
+ 0,
+ face_indices->size(),
+ face_counts->size());
+
+ settings.read_flag |= MOD_MESHSEQ_READ_ALL;
+ }
+ else {
+ /* 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))
+ {
+ settings.read_flag = MOD_MESHSEQ_READ_VERT;
+
+ if (err_str) {
+ *err_str = "Topology has changed, perhaps by triangulating the"
+ " mesh. Only vertices will be read!";
+ }
+ }
+ }
+
+ CDStreamConfig config = get_config(new_dm ? new_dm : dm);
+ config.time = sample_sel.getRequestedTime();
+
+ bool do_normals = false;
+ read_mesh_sample(&settings, m_schema, sample_sel, config, do_normals);
+
+ if (new_dm) {
+ /* 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);
+ }
+
+ CDDM_calc_normals(new_dm);
+ CDDM_calc_edges(new_dm);
+
+ return new_dm;
+ }
+
+ if (do_normals) {
+ CDDM_calc_normals(dm);
+ }
+
+ return dm;
+}
+
void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start,
const ISampleSelector &sample_sel)
{
@@ -1062,22 +1175,42 @@ void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_star
utils::assign_materials(bmain, m_object, mat_map);
}
-void read_mesh_sample(ImportSettings *settings,
- const IPolyMeshSchema &schema,
- const ISampleSelector &selector,
- CDStreamConfig &config,
- bool &do_normals)
+/* ************************************************************************** */
+
+ABC_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2)
{
- const IPolyMeshSchema::Sample sample = schema.getValue(selector);
+ for (int i = 0, e = totedge; i < e; ++i) {
+ MEdge &edge = edges[i];
+
+ if (edge.v1 == v1 && edge.v2 == v2) {
+ return &edge;
+ }
+ }
+
+ return NULL;
+}
+
+static void read_subd_sample(ImportSettings *settings,
+ const ISubDSchema &schema,
+ const ISampleSelector &selector,
+ CDStreamConfig &config)
+{
+ const ISubDSchema::Sample sample = schema.getValue(selector);
AbcMeshData abc_mesh_data;
abc_mesh_data.face_counts = sample.getFaceCounts();
abc_mesh_data.face_indices = sample.getFaceIndices();
+ abc_mesh_data.vertex_normals = N3fArraySamplePtr();
+ abc_mesh_data.face_normals = N3fArraySamplePtr();
abc_mesh_data.positions = sample.getPositions();
- read_normals_params(abc_mesh_data, schema.getNormalsParam(), selector);
+ get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples());
- do_normals = (abc_mesh_data.face_normals != NULL);
+ if (config.weight != 0.0f) {
+ Alembic::AbcGeom::ISubDSchema::Sample ceil_sample;
+ schema.get(ceil_sample, Alembic::Abc::ISampleSelector(config.ceil_index));
+ abc_mesh_data.ceil_positions = ceil_sample.getPositions();
+ }
if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) {
read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector);
@@ -1100,19 +1233,6 @@ void read_mesh_sample(ImportSettings *settings,
/* ************************************************************************** */
-ABC_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2)
-{
- for (int i = 0, e = totedge; i < e; ++i) {
- MEdge &edge = edges[i];
-
- if (edge.v1 == v1 && edge.v2 == v2) {
- return &edge;
- }
- }
-
- return NULL;
-}
-
AbcSubDReader::AbcSubDReader(const IObject &object, ImportSettings &settings)
: AbcObjectReader(object, settings)
{
@@ -1120,7 +1240,8 @@ AbcSubDReader::AbcSubDReader(const IObject &object, ImportSettings &settings)
ISubD isubd_mesh(m_iobject, kWrapExisting);
m_schema = isubd_mesh.getSchema();
- get_min_max_time(m_schema, m_min_time, m_max_time);
+
+ get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time);
}
bool AbcSubDReader::valid() const
@@ -1128,28 +1249,40 @@ bool AbcSubDReader::valid() const
return m_schema.valid();
}
-void AbcSubDReader::readObjectData(Main *bmain, float time)
+bool AbcSubDReader::accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const
+{
+ if (!Alembic::AbcGeom::ISubD::matches(alembic_header)) {
+ *err_str = "Object type mismatch, Alembic object path pointed to SubD when importing, but not any more.";
+ return false;
+ }
+
+ if (ob->type != OB_MESH) {
+ *err_str = "Object type mismatch, Alembic object path points to SubD.";
+ return false;
+ }
+
+ return true;
+}
+
+void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
{
Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
m_object->data = mesh;
- const ISampleSelector sample_sel(time);
- const ISubDSchema::Sample sample = m_schema.getValue(sample_sel);
-
- const P3fArraySamplePtr &positions = sample.getPositions();
- const Int32ArraySamplePtr &face_indices = sample.getFaceIndices();
- const Int32ArraySamplePtr &face_counts = sample.getFaceCounts();
-
- utils::mesh_add_verts(mesh, positions->size());
- utils::mesh_add_mpolygons(mesh, face_counts->size());
- utils::mesh_add_mloops(mesh, face_indices->size());
+ DerivedMesh *dm = CDDM_from_mesh(mesh);
+ DerivedMesh *ndm = this->read_derivedmesh(dm, sample_sel, MOD_MESHSEQ_READ_ALL, NULL);
- m_mesh_data = create_config(mesh);
+ if (ndm != dm) {
+ dm->release(dm);
+ }
- read_subd_sample(m_settings, m_schema, sample_sel, m_mesh_data);
+ 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();
@@ -1179,35 +1312,64 @@ void AbcSubDReader::readObjectData(Main *bmain, float time)
}
}
-void read_subd_sample(ImportSettings *settings,
- const ISubDSchema &schema,
- const ISampleSelector &selector,
- CDStreamConfig &config)
+DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm,
+ const ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str)
{
- const ISubDSchema::Sample sample = schema.getValue(selector);
+ const ISubDSchema::Sample sample = m_schema.getValue(sample_sel);
- AbcMeshData abc_mesh_data;
- abc_mesh_data.face_counts = sample.getFaceCounts();
- abc_mesh_data.face_indices = sample.getFaceIndices();
- abc_mesh_data.vertex_normals = N3fArraySamplePtr();
- abc_mesh_data.face_normals = N3fArraySamplePtr();
- abc_mesh_data.positions = sample.getPositions();
+ const P3fArraySamplePtr &positions = sample.getPositions();
+ const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices();
+ const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts();
- if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) {
- read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector);
- }
+ DerivedMesh *new_dm = NULL;
- if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) {
- read_mverts(config, abc_mesh_data);
- }
+ ImportSettings settings;
+ settings.read_flag |= read_flag;
- if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
- read_mpolys(config, abc_mesh_data);
+ if (dm->getNumVerts(dm) != positions->size()) {
+ new_dm = CDDM_from_template(dm,
+ positions->size(),
+ 0,
+ 0,
+ face_indices->size(),
+ face_counts->size());
+
+ settings.read_flag |= MOD_MESHSEQ_READ_ALL;
+ }
+ else {
+ /* 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))
+ {
+ settings.read_flag = MOD_MESHSEQ_READ_VERT;
+
+ if (err_str) {
+ *err_str = "Topology has changed, perhaps by triangulating the"
+ " mesh. Only vertices will be read!";
+ }
+ }
}
- if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
- read_custom_data(schema.getArbGeomParams(), config, selector);
+ /* Only read point data when streaming meshes, unless we need to create new ones. */
+ CDStreamConfig config = get_config(new_dm ? new_dm : dm);
+ config.time = sample_sel.getRequestedTime();
+ read_subd_sample(&settings, m_schema, sample_sel, config);
+
+ if (new_dm) {
+ /* Check if we had ME_SMOOTH flag set to restore it. */
+ if (check_smooth_poly_flag(dm)) {
+ set_smooth_poly_flag(new_dm);
+ }
+
+ CDDM_calc_normals(new_dm);
+ CDDM_calc_edges(new_dm);
+
+ return new_dm;
}
- /* TODO: face sets */
+ return dm;
}
diff --git a/source/blender/alembic/intern/abc_mesh.h b/source/blender/alembic/intern/abc_mesh.h
index 9dc222e5206..6bf1dde3d1d 100644
--- a/source/blender/alembic/intern/abc_mesh.h
+++ b/source/blender/alembic/intern/abc_mesh.h
@@ -39,8 +39,6 @@ class AbcMeshWriter : public AbcObjectWriter {
Alembic::AbcGeom::OSubDSchema m_subdiv_schema;
Alembic::AbcGeom::OSubDSchema::Sample m_subdiv_sample;
- bool m_has_per_face_materials;
- Alembic::AbcGeom::OFaceSet m_face_set;
Alembic::Abc::OArrayProperty m_mat_indices;
bool m_is_animated;
@@ -87,7 +85,7 @@ private:
void getVelocities(DerivedMesh *dm, std::vector<Imath::V3f> &vels);
template <typename Schema>
- void writeCommonData(DerivedMesh *dm, Schema &schema);
+ void writeFaceSets(DerivedMesh *dm, Schema &schema);
};
/* ************************************************************************** */
@@ -101,20 +99,21 @@ public:
AbcMeshReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
bool valid() const;
+ bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const;
+ void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel);
- void readObjectData(Main *bmain, float time);
+ DerivedMesh *read_derivedmesh(DerivedMesh *dm,
+ const Alembic::Abc::ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str);
private:
void readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start,
const Alembic::AbcGeom::ISampleSelector &sample_sel);
};
-void read_mesh_sample(ImportSettings *settings,
- const Alembic::AbcGeom::IPolyMeshSchema &schema,
- const Alembic::AbcGeom::ISampleSelector &selector,
- CDStreamConfig &config,
- bool &do_normals);
-
/* ************************************************************************** */
class AbcSubDReader : public AbcObjectReader {
@@ -126,27 +125,22 @@ public:
AbcSubDReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
bool valid() const;
-
- void readObjectData(Main *bmain, float time);
+ bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ 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);
};
-void read_subd_sample(ImportSettings *settings,
- const Alembic::AbcGeom::ISubDSchema &schema,
- const Alembic::AbcGeom::ISampleSelector &selector,
- CDStreamConfig &config);
-
/* ************************************************************************** */
-namespace utils {
-
-void mesh_add_verts(struct Mesh *mesh, size_t len);
-
-}
-
void read_mverts(MVert *mverts,
const Alembic::AbcGeom::P3fArraySamplePtr &positions,
const Alembic::AbcGeom::N3fArraySamplePtr &normals);
-CDStreamConfig create_config(Mesh *mesh);
+CDStreamConfig get_config(DerivedMesh *dm);
#endif /* __ABC_MESH_H__ */
diff --git a/source/blender/alembic/intern/abc_nurbs.cc b/source/blender/alembic/intern/abc_nurbs.cc
index a3c18ad6301..eaef06fd6d1 100644
--- a/source/blender/alembic/intern/abc_nurbs.cc
+++ b/source/blender/alembic/intern/abc_nurbs.cc
@@ -153,7 +153,7 @@ void AbcNurbsWriter::do_write()
const BPoint *bp = nu->bp;
for (int i = 0; i < size; ++i, ++bp) {
- copy_zup_yup(positions[i].getValue(), bp->vec);
+ copy_yup_from_zup(positions[i].getValue(), bp->vec);
weights[i] = bp->vec[3];
}
@@ -201,7 +201,7 @@ AbcNurbsReader::AbcNurbsReader(const IObject &object, ImportSettings &settings)
: AbcObjectReader(object, settings)
{
getNurbsPatches(m_iobject);
- get_min_max_time(m_schemas[0].first, m_min_time, m_max_time);
+ get_min_max_time(m_iobject, m_schemas[0].first, m_min_time, m_max_time);
}
bool AbcNurbsReader::valid() const
@@ -239,7 +239,7 @@ static bool set_knots(const FloatArraySamplePtr &knots, float *&nu_knots)
return true;
}
-void AbcNurbsReader::readObjectData(Main *bmain, float time)
+void AbcNurbsReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
{
Curve *cu = static_cast<Curve *>(BKE_curve_add(bmain, "abc_curve", OB_SURF));
cu->actvert = CU_ACT_NONE;
@@ -253,7 +253,6 @@ void AbcNurbsReader::readObjectData(Main *bmain, float time)
nu->resolu = cu->resolu;
nu->resolv = cu->resolv;
- const ISampleSelector sample_sel(time);
const INuPatchSchema &schema = it->first;
const INuPatchSchema::Sample smp = schema.getValue(sample_sel);
@@ -281,7 +280,7 @@ void AbcNurbsReader::readObjectData(Main *bmain, float time)
posw_in = (*weights)[i];
}
- copy_yup_zup(bp->vec, pos_in.getValue());
+ copy_zup_from_yup(bp->vec, pos_in.getValue());
bp->vec[3] = posw_in;
bp->f1 = SELECT;
bp->radius = 1.0f;
diff --git a/source/blender/alembic/intern/abc_nurbs.h b/source/blender/alembic/intern/abc_nurbs.h
index 1b2e7a8391f..abe460a8988 100644
--- a/source/blender/alembic/intern/abc_nurbs.h
+++ b/source/blender/alembic/intern/abc_nurbs.h
@@ -54,7 +54,7 @@ public:
bool valid() const;
- void readObjectData(Main *bmain, float time);
+ void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel);
private:
void getNurbsPatches(const Alembic::Abc::IObject &obj);
diff --git a/source/blender/alembic/intern/abc_object.cc b/source/blender/alembic/intern/abc_object.cc
index 5b7b85f10ea..9f8960c827f 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"
@@ -91,20 +90,20 @@ Imath::Box3d AbcObjectWriter::bounds()
if (!bb) {
if (this->m_object->type != OB_CAMERA) {
- std::cerr << "Boundbox is null!\n";
+ ABC_LOG(m_settings.logger) << "Bounding box is null!\n";
}
return Imath::Box3d();
}
- /* Convert Z-up to Y-up. */
+ /* Convert Z-up to Y-up. This also changes which vector goes into which min/max property. */
this->m_bounds.min.x = bb->vec[0][0];
this->m_bounds.min.y = bb->vec[0][2];
- this->m_bounds.min.z = -bb->vec[0][1];
+ this->m_bounds.min.z = -bb->vec[6][1];
this->m_bounds.max.x = bb->vec[6][0];
this->m_bounds.max.y = bb->vec[6][2];
- this->m_bounds.max.z = -bb->vec[6][1];
+ this->m_bounds.max.z = -bb->vec[0][1];
return this->m_bounds;
}
@@ -126,6 +125,8 @@ AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings
, m_settings(&settings)
, m_min_time(std::numeric_limits<chrono_t>::max())
, m_max_time(std::numeric_limits<chrono_t>::min())
+ , m_refcount(0)
+ , parent_reader(NULL)
{
m_name = object.getFullName();
std::vector<std::string> parts;
@@ -138,6 +139,38 @@ AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings
else {
m_object_name = m_data_name = parts[parts.size() - 1];
}
+
+ determine_inherits_xform();
+}
+
+/* Determine whether we can inherit our parent's XForm */
+void AbcObjectReader::determine_inherits_xform()
+{
+ m_inherits_xform = false;
+
+ IXform ixform = xform();
+ if (!ixform) {
+ return;
+ }
+
+ const IXformSchema & schema(ixform.getSchema());
+ if (!schema.valid()) {
+ std::cerr << "Alembic object " << ixform.getFullName()
+ << " has an invalid schema." << std::endl;
+ return;
+ }
+
+ m_inherits_xform = schema.getInheritsXforms();
+
+ IObject ixform_parent = ixform.getParent();
+ if (!ixform_parent.getParent()) {
+ /* The archive top object certainly is not a transform itself, so handle
+ * it as "no parent". */
+ m_inherits_xform = false;
+ }
+ else {
+ m_inherits_xform = ixform_parent && m_inherits_xform;
+ }
}
AbcObjectReader::~AbcObjectReader()
@@ -153,68 +186,161 @@ Object *AbcObjectReader::object() const
return m_object;
}
-void AbcObjectReader::readObjectMatrix(const float time)
+void AbcObjectReader::object(Object *ob)
{
- IXform ixform;
- bool has_alembic_parent = false;
+ m_object = ob;
+}
- /* Check that we have an empty object (locator, bone head/tail...). */
- if (IXform::matches(m_iobject.getMetaData())) {
- ixform = IXform(m_iobject, Alembic::AbcGeom::kWrapExisting);
-
- /* See comment below. */
- has_alembic_parent = m_iobject.getParent().getParent().valid();
- }
- /* Check that we have an object with actual data. */
- else if (IXform::matches(m_iobject.getParent().getMetaData())) {
- ixform = IXform(m_iobject.getParent(), Alembic::AbcGeom::kWrapExisting);
-
- /* This is a bit hackish, but we need to make sure that extra
- * transformations added to the matrix (rotation/scale) are only applied
- * to root objects. The way objects and their hierarchy are created will
- * need to be revisited at some point but for now this seems to do the
- * trick.
- *
- * Explanation of the trick:
- * The first getParent() will return this object's transformation matrix.
- * The second getParent() will get the parent of the transform, but this
- * might be the archive root ('/') which is valid, so we go passed it to
- * make sure that there is no parent.
- */
- has_alembic_parent = m_iobject.getParent().getParent().getParent().valid();
+static Imath::M44d blend_matrices(const Imath::M44d &m0, const Imath::M44d &m1, const float weight)
+{
+ float mat0[4][4], mat1[4][4], ret[4][4];
+
+ /* Cannot use Imath::M44d::getValue() since this returns a pointer to
+ * doubles and interp_m4_m4m4 expects pointers to floats. So need to convert
+ * the matrices manually.
+ */
+
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ mat0[i][j] = static_cast<float>(m0[i][j]);
+ }
}
- /* Should not happen. */
- else {
- return;
+
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ mat1[i][j] = static_cast<float>(m1[i][j]);
+ }
}
- const IXformSchema &schema(ixform.getSchema());
+ interp_m4_m4m4(ret, mat0, mat1, weight);
- if (!schema.valid()) {
- return;
+ Imath::M44d m;
+
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ m[i][j] = ret[i][j];
+ }
+ }
+
+ return m;
+}
+
+Imath::M44d get_matrix(const IXformSchema &schema, const float time)
+{
+ Alembic::AbcGeom::index_t i0, i1;
+ Alembic::AbcGeom::XformSample s0, s1;
+
+ const float weight = get_weight_and_index(time,
+ schema.getTimeSampling(),
+ schema.getNumSamples(),
+ i0,
+ i1);
+
+ schema.get(s0, Alembic::AbcGeom::ISampleSelector(i0));
+
+ if (i0 != i1) {
+ schema.get(s1, Alembic::AbcGeom::ISampleSelector(i1));
+ return blend_matrices(s0.getMatrix(), s1.getMatrix(), weight);
}
- Alembic::AbcGeom::ISampleSelector sample_sel(time);
- Alembic::AbcGeom::XformSample xs;
- schema.get(xs, sample_sel);
+ 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))
+{
+ return dm;
+}
- create_input_transform(sample_sel, ixform, m_object, m_object->obmat, m_settings->scale, has_alembic_parent);
+void AbcObjectReader::setupObjectTransform(const float time)
+{
+ bool is_constant = false;
+ this->read_matrix(m_object->obmat, time, m_settings->scale, is_constant);
invert_m4_m4(m_object->imat, m_object->obmat);
BKE_object_apply_mat4(m_object, m_object->obmat, false, false);
- if (!schema.isConstant()) {
+ if (!is_constant) {
bConstraint *con = BKE_constraint_add_for_object(m_object, NULL, CONSTRAINT_TYPE_TRANSFORM_CACHE);
bTransformCacheConstraint *data = static_cast<bTransformCacheConstraint *>(con->data);
BLI_strncpy(data->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
data->cache_file = m_settings->cache_file;
id_us_plus(&data->cache_file->id);
+
+ data->reader = reinterpret_cast<CacheReader *>(this);
+ this->incref();
}
}
-void AbcObjectReader::addCacheModifier() const
+Alembic::AbcGeom::IXform AbcObjectReader::xform()
+{
+ /* Check that we have an empty object (locator, bone head/tail...). */
+ if (IXform::matches(m_iobject.getMetaData())) {
+ return IXform(m_iobject, Alembic::AbcGeom::kWrapExisting);
+ }
+
+ /* Check that we have an object with actual data, in which case the
+ * parent Alembic object should contain the transform. */
+ IObject abc_parent = m_iobject.getParent();
+
+ /* The archive's top object can be recognised by not having a parent. */
+ if (abc_parent.getParent()
+ && IXform::matches(abc_parent.getMetaData())) {
+ return IXform(abc_parent, Alembic::AbcGeom::kWrapExisting);
+ }
+
+ /* Should not happen. */
+ std::cerr << "AbcObjectReader::xform(): "
+ << "unable to find IXform for Alembic object '"
+ << m_iobject.getFullName() << "'\n";
+ BLI_assert(false);
+
+ return IXform();
+}
+
+void AbcObjectReader::read_matrix(float r_mat[4][4], const float time,
+ const float scale, bool &is_constant)
+{
+ IXform ixform = xform();
+ if (!ixform) {
+ return;
+ }
+
+ const IXformSchema & schema(ixform.getSchema());
+ if (!schema.valid()) {
+ std::cerr << "Alembic object " << ixform.getFullName()
+ << " has an invalid schema." << std::endl;
+ return;
+ }
+
+ const Imath::M44d matrix = get_matrix(schema, time);
+ convert_matrix(matrix, m_object, r_mat);
+
+ if (m_inherits_xform) {
+ /* In this case, the matrix in Alembic is in local coordinates, so
+ * convert to world matrix. To prevent us from reading and accumulating
+ * all parent matrices in the Alembic file, we assume that the Blender
+ * parent object is already updated for the current timekey, and use its
+ * world matrix. */
+ BLI_assert(m_object->parent);
+ mul_m4_m4m4(r_mat, m_object->parent->obmat, r_mat);
+ }
+ else {
+ /* Only apply scaling to root objects, parenting will propagate it. */
+ float scale_mat[4][4];
+ scale_m4_fl(scale_mat, scale);
+ scale_mat[3][3] = scale; /* scale translations too */
+ mul_m4_m4m4(r_mat, r_mat, scale_mat);
+ }
+
+ is_constant = schema.isConstant();
+}
+
+void AbcObjectReader::addCacheModifier()
{
ModifierData *md = modifier_new(eModifierType_MeshSequenceCache);
BLI_addtail(&m_object->modifiers, md);
@@ -225,6 +351,9 @@ void AbcObjectReader::addCacheModifier() const
id_us_plus(&mcmd->cache_file->id);
BLI_strncpy(mcmd->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
+
+ mcmd->reader = reinterpret_cast<CacheReader *>(this);
+ this->incref();
}
chrono_t AbcObjectReader::minTime() const
@@ -236,3 +365,19 @@ chrono_t AbcObjectReader::maxTime() const
{
return m_max_time;
}
+
+int AbcObjectReader::refcount() const
+{
+ return m_refcount;
+}
+
+void AbcObjectReader::incref()
+{
+ ++m_refcount;
+}
+
+void AbcObjectReader::decref()
+{
+ --m_refcount;
+ BLI_assert(m_refcount >= 0);
+}
diff --git a/source/blender/alembic/intern/abc_object.h b/source/blender/alembic/intern/abc_object.h
index 2e885f296b1..852ef451f23 100644
--- a/source/blender/alembic/intern/abc_object.h
+++ b/source/blender/alembic/intern/abc_object.h
@@ -76,7 +76,7 @@ private:
/* ************************************************************************** */
-class CacheFile;
+struct CacheFile;
struct ImportSettings {
bool do_convert_mat;
@@ -90,7 +90,7 @@ struct ImportSettings {
/* Length and frame offset of file sequences. */
int sequence_len;
- int offset;
+ int sequence_offset;
/* From MeshSeqCacheModifierData.read_flag */
int read_flag;
@@ -107,7 +107,7 @@ struct ImportSettings {
, is_sequence(false)
, set_frame_range(false)
, sequence_len(1)
- , offset(0)
+ , sequence_offset(0)
, read_flag(0)
, validate_meshes(false)
, cache_file(NULL)
@@ -117,19 +117,13 @@ struct ImportSettings {
template <typename Schema>
static bool has_animations(Schema &schema, ImportSettings *settings)
{
- if (settings->is_sequence) {
- return true;
- }
-
- if (!schema.isConstant()) {
- return true;
- }
-
- return false;
+ return settings->is_sequence || !schema.isConstant();
}
/* ************************************************************************** */
+struct DerivedMesh;
+
using Alembic::AbcCoreAbstract::chrono_t;
class AbcObjectReader {
@@ -145,6 +139,15 @@ protected:
chrono_t m_min_time;
chrono_t m_max_time;
+ /* Use reference counting since the same reader may be used by multiple
+ * modifiers and/or constraints. */
+ int m_refcount;
+
+ bool m_inherits_xform;
+
+public:
+ AbcObjectReader *parent_reader;
+
public:
explicit AbcObjectReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
@@ -152,18 +155,53 @@ public:
const Alembic::Abc::IObject &iobject() const;
+ typedef std::vector<AbcObjectReader *> ptr_vector;
+
+ /**
+ * Returns the transform of this object. This can be the Alembic object
+ * itself (in case of an Empty) or it can be the parent Alembic object.
+ */
+ virtual Alembic::AbcGeom::IXform xform();
+
Object *object() const;
+ void object(Object *ob);
+
+ const std::string & name() const { return m_name; }
+ const std::string & object_name() const { return m_object_name; }
+ const std::string & data_name() const { return m_data_name; }
+ bool inherits_xform() const { return m_inherits_xform; }
virtual bool valid() const = 0;
+ virtual bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const = 0;
- virtual void readObjectData(Main *bmain, float time) = 0;
+ virtual void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) = 0;
- void readObjectMatrix(const float time);
+ virtual DerivedMesh *read_derivedmesh(DerivedMesh *dm,
+ const Alembic::Abc::ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str);
- void addCacheModifier() const;
+ /** Reads the object matrix and sets up an object transform if animated. */
+ void setupObjectTransform(const float time);
+
+ void addCacheModifier();
chrono_t minTime() const;
chrono_t maxTime() const;
+
+ int refcount() const;
+ void incref();
+ void decref();
+
+ void read_matrix(float r_mat[4][4], const float time,
+ const float scale, bool &is_constant);
+
+protected:
+ void determine_inherits_xform();
};
+Imath::M44d get_matrix(const Alembic::AbcGeom::IXformSchema &schema, const float time);
+
#endif /* __ABC_OBJECT_H__ */
diff --git a/source/blender/alembic/intern/abc_points.cc b/source/blender/alembic/intern/abc_points.cc
index fa5b71ac094..80567cd6bf0 100644
--- a/source/blender/alembic/intern/abc_points.cc
+++ b/source/blender/alembic/intern/abc_points.cc
@@ -30,7 +30,9 @@
extern "C" {
#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "BKE_cdderivedmesh.h"
#include "BKE_lattice.h"
#include "BKE_mesh.h"
#include "BKE_object.h"
@@ -66,7 +68,7 @@ AbcPointsWriter::AbcPointsWriter(Scene *scene,
{
m_psys = psys;
- OPoints points(parent->alembicXform(), m_name, m_time_sampling);
+ OPoints points(parent->alembicXform(), psys->name, m_time_sampling);
m_schema = points.getSchema();
}
@@ -141,7 +143,7 @@ AbcPointsReader::AbcPointsReader(const Alembic::Abc::IObject &object, ImportSett
{
IPoints ipoints(m_iobject, kWrapExisting);
m_schema = ipoints.getSchema();
- get_min_max_time(m_schema, m_min_time, m_max_time);
+ get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time);
}
bool AbcPointsReader::valid() const
@@ -149,18 +151,35 @@ bool AbcPointsReader::valid() const
return m_schema.valid();
}
-void AbcPointsReader::readObjectData(Main *bmain, float time)
+bool AbcPointsReader::accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const
+{
+ if (!Alembic::AbcGeom::IPoints::matches(alembic_header)) {
+ *err_str = "Object type mismatch, Alembic object path pointed to Points when importing, but not any more.";
+ return false;
+ }
+
+ if (ob->type != OB_MESH) {
+ *err_str = "Object type mismatch, Alembic object path points to Points.";
+ return false;
+ }
+
+ return true;
+}
+
+void AbcPointsReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
{
Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
- const ISampleSelector sample_sel(time);
- m_sample = m_schema.getValue(sample_sel);
+ DerivedMesh *dm = CDDM_from_mesh(mesh);
+ DerivedMesh *ndm = this->read_derivedmesh(dm, sample_sel, 0, NULL);
- const P3fArraySamplePtr &positions = m_sample.getPositions();
- utils::mesh_add_verts(mesh, positions->size());
+ if (ndm != dm) {
+ dm->release(dm);
+ }
- CDStreamConfig config = create_config(mesh);
- read_points_sample(m_schema, sample_sel, config, time);
+ DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true);
if (m_settings->validate_meshes) {
BKE_mesh_validate(mesh, false, false);
@@ -176,8 +195,7 @@ void AbcPointsReader::readObjectData(Main *bmain, float time)
void read_points_sample(const IPointsSchema &schema,
const ISampleSelector &selector,
- CDStreamConfig &config,
- float time)
+ CDStreamConfig &config)
{
Alembic::AbcGeom::IPointsSchema::Sample sample = schema.getValue(selector);
@@ -187,7 +205,8 @@ void read_points_sample(const IPointsSchema &schema,
N3fArraySamplePtr vnormals;
if (has_property(prop, "N")) {
- const IN3fArrayProperty &normals_prop = IN3fArrayProperty(prop, "N", time);
+ const Alembic::Util::uint32_t itime = static_cast<Alembic::Util::uint32_t>(selector.getRequestedTime());
+ const IN3fArrayProperty &normals_prop = IN3fArrayProperty(prop, "N", itime);
if (normals_prop) {
vnormals = normals_prop.getValue(selector);
@@ -196,3 +215,24 @@ 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*/)
+{
+ const IPointsSchema::Sample sample = m_schema.getValue(sample_sel);
+
+ const P3fArraySamplePtr &positions = sample.getPositions();
+
+ DerivedMesh *new_dm = NULL;
+
+ if (dm->getNumVerts(dm) != positions->size()) {
+ new_dm = CDDM_new(positions->size(), 0, 0, 0, 0);
+ }
+
+ CDStreamConfig config = get_config(new_dm ? new_dm : dm);
+ read_points_sample(m_schema, sample_sel, config);
+
+ return new_dm ? new_dm : dm;
+}
diff --git a/source/blender/alembic/intern/abc_points.h b/source/blender/alembic/intern/abc_points.h
index 51f3103bd8b..369a802d763 100644
--- a/source/blender/alembic/intern/abc_points.h
+++ b/source/blender/alembic/intern/abc_points.h
@@ -28,7 +28,7 @@
#include "abc_object.h"
#include "abc_customdata.h"
-class ParticleSystem;
+struct ParticleSystem;
/* ************************************************************************** */
@@ -58,13 +58,20 @@ public:
AbcPointsReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
bool valid() const;
+ bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const;
- void readObjectData(Main *bmain, float time);
+ 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);
};
void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema,
const Alembic::AbcGeom::ISampleSelector &selector,
- CDStreamConfig &config,
- float time);
+ CDStreamConfig &config);
#endif /* __ABC_POINTS_H__ */
diff --git a/source/blender/alembic/intern/abc_transform.cc b/source/blender/alembic/intern/abc_transform.cc
index 3326ae0ed84..5392387663f 100644
--- a/source/blender/alembic/intern/abc_transform.cc
+++ b/source/blender/alembic/intern/abc_transform.cc
@@ -36,6 +36,7 @@ extern "C" {
using Alembic::AbcGeom::OObject;
using Alembic::AbcGeom::OXform;
+using Alembic::Abc::ISampleSelector;
/* ************************************************************************** */
@@ -62,9 +63,9 @@ AbcTransformWriter::AbcTransformWriter(Object *ob,
unsigned int time_sampling,
ExportSettings &settings)
: AbcObjectWriter(NULL, ob, time_sampling, settings, parent)
+ , m_proxy_from(NULL)
{
m_is_animated = hasAnimation(m_object);
- m_parent = NULL;
if (!m_is_animated) {
time_sampling = 0;
@@ -72,6 +73,9 @@ AbcTransformWriter::AbcTransformWriter(Object *ob,
m_xform = OXform(abc_parent, get_id_name(m_object), time_sampling);
m_schema = m_xform.getSchema();
+
+ /* Blender objects can't have a parent without inheriting the transform. */
+ m_inherits_xform = parent != NULL;
}
void AbcTransformWriter::do_write()
@@ -86,28 +90,30 @@ void AbcTransformWriter::do_write()
return;
}
- float mat[4][4];
- create_transform_matrix(m_object, mat);
+ float yup_mat[4][4];
+ create_transform_matrix(m_object, 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 && !has_parent_camera(m_object)) {
+ if (m_object->type == OB_CAMERA && (!m_inherits_xform || !has_parent_camera(m_object))) {
float rot_mat[4][4];
- unit_m4(rot_mat);
- rotate_m4(rot_mat, 'X', -M_PI_2);
- mul_m4_m4m4(mat, mat, rot_mat);
+ axis_angle_to_mat4_single(rot_mat, 'X', -M_PI_2);
+ mul_m4_m4m4(yup_mat, yup_mat, rot_mat);
}
- if (!m_object->parent) {
+ if (!m_object->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);
- mul_m4_m4m4(mat, mat, scale_mat);
- mul_v3_fl(mat[3], m_settings.global_scale);
+ scale_mat[3][3] = m_settings.global_scale; /* also scale translation */
+ mul_m4_m4m4(yup_mat, yup_mat, scale_mat);
+ yup_mat[3][3] /= m_settings.global_scale; /* normalise the homogeneous component */
}
- m_matrix = convert_matrix(mat);
-
+ m_matrix = convert_matrix(yup_mat);
m_sample.setMatrix(m_matrix);
+ m_sample.setInheritsXforms(m_inherits_xform);
m_schema.set(m_sample);
}
@@ -123,7 +129,7 @@ Imath::Box3d AbcTransformWriter::bounds()
return Imath::transform(bounds, m_matrix);
}
-bool AbcTransformWriter::hasAnimation(Object */*ob*/) const
+bool AbcTransformWriter::hasAnimation(Object * /*ob*/) const
{
/* TODO(kevin): implement this. */
return true;
@@ -134,10 +140,14 @@ bool AbcTransformWriter::hasAnimation(Object */*ob*/) const
AbcEmptyReader::AbcEmptyReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
: AbcObjectReader(object, settings)
{
+ /* Empties have no data. It makes the import of Alembic files easier to
+ * understand when we name the empty after its name in Alembic. */
+ m_object_name = object.getName();
+
Alembic::AbcGeom::IXform xform(object, Alembic::AbcGeom::kWrapExisting);
m_schema = xform.getSchema();
- get_min_max_time(m_schema, m_min_time, m_max_time);
+ get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time);
}
bool AbcEmptyReader::valid() const
@@ -145,8 +155,26 @@ bool AbcEmptyReader::valid() const
return m_schema.valid();
}
-void AbcEmptyReader::readObjectData(Main *bmain, float /*time*/)
+bool AbcEmptyReader::accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const
+{
+ if (!Alembic::AbcGeom::IXform::matches(alembic_header)) {
+ *err_str = "Object type mismatch, Alembic object path pointed to XForm when importing, but not any more.";
+ return false;
+ }
+
+ if (ob->type != OB_EMPTY) {
+ *err_str = "Object type mismatch, Alembic object path points to XForm.";
+ return false;
+ }
+
+ return true;
+}
+
+void AbcEmptyReader::readObjectData(Main *bmain, const ISampleSelector &UNUSED(sample_sel))
{
- m_object = BKE_object_add_only_object(bmain, OB_EMPTY, m_object_name.c_str());
+ m_object = BKE_object_add_only_object(bmain, OB_EMPTY,
+ m_object_name.c_str());
m_object->data = NULL;
}
diff --git a/source/blender/alembic/intern/abc_transform.h b/source/blender/alembic/intern/abc_transform.h
index 6a3aae216f2..753a4247e9f 100644
--- a/source/blender/alembic/intern/abc_transform.h
+++ b/source/blender/alembic/intern/abc_transform.h
@@ -37,8 +37,11 @@ class AbcTransformWriter : public AbcObjectWriter {
Alembic::Abc::M44d m_matrix;
bool m_is_animated;
- Object *m_parent;
bool m_visible;
+ bool m_inherits_xform;
+
+public:
+ Object *m_proxy_from;
public:
AbcTransformWriter(Object *ob,
@@ -49,7 +52,6 @@ public:
Alembic::AbcGeom::OXform &alembicXform() { return m_xform;}
virtual Imath::Box3d bounds();
- void setParent(Object *p) { m_parent = p; }
private:
virtual void do_write();
@@ -66,8 +68,11 @@ public:
AbcEmptyReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
bool valid() const;
+ bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const;
- void readObjectData(Main *bmain, float time);
+ void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel);
};
#endif /* __ABC_TRANSFORM_H__ */
diff --git a/source/blender/alembic/intern/abc_util.cc b/source/blender/alembic/intern/abc_util.cc
index fbab0bcdf34..8601dff54ed 100644
--- a/source/blender/alembic/intern/abc_util.cc
+++ b/source/blender/alembic/intern/abc_util.cc
@@ -22,15 +22,27 @@
#include "abc_util.h"
+#include "abc_camera.h"
+#include "abc_curves.h"
+#include "abc_mesh.h"
+#include "abc_nurbs.h"
+#include "abc_points.h"
+#include "abc_transform.h"
+
+#include <Alembic/AbcMaterial/IMaterial.h>
+
#include <algorithm>
extern "C" {
#include "DNA_object_types.h"
+#include "DNA_layer_types.h"
#include "BLI_math.h"
+
+#include "PIL_time.h"
}
-std::string get_id_name(Object *ob)
+std::string get_id_name(const Object * const ob)
{
if (!ob) {
return "";
@@ -39,7 +51,7 @@ std::string get_id_name(Object *ob)
return get_id_name(&ob->id);
}
-std::string get_id_name(ID *id)
+std::string get_id_name(const ID * const id)
{
std::string name(id->name + 2);
std::replace(name.begin(), name.end(), ' ', '_');
@@ -49,7 +61,16 @@ std::string get_id_name(ID *id)
return name;
}
-std::string get_object_dag_path_name(Object *ob, Object *dupli_parent)
+/**
+ * @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);
@@ -67,31 +88,9 @@ std::string get_object_dag_path_name(Object *ob, Object *dupli_parent)
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])
@@ -121,15 +120,28 @@ void split(const std::string &s, const char delim, std::vector<std::string> &tok
}
}
-/* Create a rotation matrix for each axis from euler angles.
- * Euler angles are swaped to change coordinate system. */
-static void create_rotation_matrix(
+void create_swapped_rotation_matrix(
float rot_x_mat[3][3], float rot_y_mat[3][3],
- float rot_z_mat[3][3], const float euler[3], const bool to_yup)
+ float rot_z_mat[3][3], const float euler[3],
+ AbcAxisSwapMode mode)
{
const float rx = euler[0];
- const float ry = (to_yup) ? euler[2] : -euler[2];
- const float rz = (to_yup) ? -euler[1] : euler[1];
+ float ry;
+ float rz;
+
+ /* Apply transformation */
+ switch (mode) {
+ case ABC_ZUP_FROM_YUP:
+ ry = -euler[2];
+ rz = euler[1];
+ break;
+ case ABC_YUP_FROM_ZUP:
+ ry = euler[2];
+ rz = -euler[1];
+ break;
+ default:
+ BLI_assert(false);
+ }
unit_m3(rot_x_mat);
unit_m3(rot_y_mat);
@@ -151,287 +163,247 @@ static void create_rotation_matrix(
rot_z_mat[1][1] = cos(rz);
}
-/* Recompute transform matrix of object in new coordinate system
- * (from Y-Up to Z-Up). */
-void create_transform_matrix(float r_mat[4][4])
+/* Convert matrix from Z=up to Y=up or vice versa. Use yup_mat = zup_mat for in-place conversion. */
+void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMode mode)
{
- float rot_mat[3][3], rot[3][3], scale_mat[4][4], invmat[4][4], transform_mat[4][4];
+ float dst_rot[3][3], src_rot[3][3], dst_scale_mat[4][4];
float rot_x_mat[3][3], rot_y_mat[3][3], rot_z_mat[3][3];
- float loc[3], scale[3], euler[3];
+ float src_trans[3], dst_scale[3], src_scale[3], euler[3];
- zero_v3(loc);
- zero_v3(scale);
+ zero_v3(src_trans);
+ zero_v3(dst_scale);
+ zero_v3(src_scale);
zero_v3(euler);
- unit_m3(rot);
- unit_m3(rot_mat);
- unit_m4(scale_mat);
- unit_m4(transform_mat);
- unit_m4(invmat);
+ unit_m3(src_rot);
+ unit_m3(dst_rot);
+ unit_m4(dst_scale_mat);
- /* Compute rotation matrix. */
+ /* 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);
- /* Extract location, rotation, and scale from matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, r_mat);
+ /* Extract translation, rotation, and scale form matrix. */
+ mat4_to_loc_rot_size(src_trans, src_rot, src_scale, src_mat);
/* Get euler angles from rotation matrix. */
- mat3_to_eulO(euler, ROT_MODE_XYZ, rot);
+ mat3_to_eulO(euler, ROT_MODE_XZY, src_rot);
/* Create X, Y, Z rotation matrices from euler angles. */
- create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, false);
+ create_swapped_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, mode);
/* Concatenate rotation matrices. */
- mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
+ mul_m3_m3m3(dst_rot, dst_rot, rot_z_mat);
+ mul_m3_m3m3(dst_rot, dst_rot, rot_y_mat);
+ mul_m3_m3m3(dst_rot, dst_rot, rot_x_mat);
- /* Add rotation matrix to transformation matrix. */
- copy_m4_m3(transform_mat, rot_mat);
+ mat3_to_eulO(euler, ROT_MODE_XZY, dst_rot);
- /* Add translation to transformation matrix. */
- copy_yup_zup(transform_mat[3], loc);
+ /* Start construction of dst_mat from rotation matrix */
+ unit_m4(dst_mat);
+ copy_m4_m3(dst_mat, dst_rot);
- /* Create scale matrix. */
- scale_mat[0][0] = scale[0];
- scale_mat[1][1] = scale[2];
- scale_mat[2][2] = scale[1];
+ /* Apply translation */
+ switch (mode) {
+ case ABC_ZUP_FROM_YUP:
+ copy_zup_from_yup(dst_mat[3], src_trans);
+ break;
+ case ABC_YUP_FROM_ZUP:
+ copy_yup_from_zup(dst_mat[3], src_trans);
+ break;
+ default:
+ BLI_assert(false);
+ }
- /* Add scale to transformation matrix. */
- mul_m4_m4m4(transform_mat, transform_mat, scale_mat);
+ /* Apply scale matrix. Swaps y and z, but does not
+ * negate like translation does. */
+ dst_scale[0] = src_scale[0];
+ dst_scale[1] = src_scale[2];
+ dst_scale[2] = src_scale[1];
- copy_m4_m4(r_mat, transform_mat);
+ size_to_mat4(dst_scale_mat, dst_scale);
+ mul_m4_m4m4(dst_mat, dst_mat, dst_scale_mat);
}
-void create_input_transform(const Alembic::AbcGeom::ISampleSelector &sample_sel,
- const Alembic::AbcGeom::IXform &ixform, Object *ob,
- float r_mat[4][4], float scale, bool has_alembic_parent)
+void convert_matrix(const Imath::M44d &xform, Object *ob, float r_mat[4][4])
{
-
- const Alembic::AbcGeom::IXformSchema &ixform_schema = ixform.getSchema();
- Alembic::AbcGeom::XformSample xs;
- ixform_schema.get(xs, sample_sel);
- const Imath::M44d &xform = xs.getMatrix();
-
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
- r_mat[i][j] = xform[i][j];
+ r_mat[i][j] = static_cast<float>(xform[i][j]);
}
}
if (ob->type == OB_CAMERA) {
float cam_to_yup[4][4];
- unit_m4(cam_to_yup);
- rotate_m4(cam_to_yup, 'X', M_PI_2);
+ axis_angle_to_mat4_single(cam_to_yup, 'X', M_PI_2);
mul_m4_m4m4(r_mat, r_mat, cam_to_yup);
}
- create_transform_matrix(r_mat);
-
- if (ob->parent) {
- mul_m4_m4m4(r_mat, ob->parent->obmat, r_mat);
- }
- /* TODO(kevin) */
- else if (!has_alembic_parent) {
- /* Only apply scaling to root objects, parenting will propagate it. */
- float scale_mat[4][4];
- scale_m4_fl(scale_mat, scale);
- mul_m4_m4m4(r_mat, r_mat, scale_mat);
- mul_v3_fl(r_mat[3], scale);
- }
+ copy_m44_axis_swap(r_mat, r_mat, ABC_ZUP_FROM_YUP);
}
-/* Recompute transform matrix of object in new coordinate system (from Z-Up to Y-Up). */
-void create_transform_matrix(Object *obj, float transform_mat[4][4])
+/* Recompute transform matrix of object in new coordinate system
+ * (from Z-Up to Y-Up). */
+void create_transform_matrix(Object *obj, float r_yup_mat[4][4], AbcMatrixMode mode,
+ Object *proxy_from)
{
- float rot_mat[3][3], rot[3][3], scale_mat[4][4], invmat[4][4], mat[4][4];
- float rot_x_mat[3][3], rot_y_mat[3][3], rot_z_mat[3][3];
- float loc[3], scale[3], euler[3];
-
- zero_v3(loc);
- zero_v3(scale);
- zero_v3(euler);
- unit_m3(rot);
- unit_m3(rot_mat);
- unit_m4(scale_mat);
- unit_m4(transform_mat);
- unit_m4(invmat);
- unit_m4(mat);
-
- /* get local matrix. */
- if (obj->parent) {
- invert_m4_m4(invmat, obj->parent->obmat);
- mul_m4_m4m4(mat, invmat, obj->obmat);
+ float zup_mat[4][4];
+
+ /* get local or world matrix. */
+ if (mode == ABC_MATRIX_LOCAL && obj->parent) {
+ /* Note that this produces another matrix than the local matrix, due to
+ * constraints and modifiers as well as the obj->parentinv matrix. */
+ invert_m4_m4(obj->parent->imat, obj->parent->obmat);
+ mul_m4_m4m4(zup_mat, obj->parent->imat, obj->obmat);
}
else {
- copy_m4_m4(mat, obj->obmat);
+ copy_m4_m4(zup_mat, obj->obmat);
}
- /* Compute rotation matrix. */
- switch (obj->rotmode) {
- case ROT_MODE_AXISANGLE:
- {
- /* Get euler angles from axis angle rotation. */
- axis_angle_to_eulO(euler, ROT_MODE_XYZ, obj->rotAxis, obj->rotAngle);
-
- /* Create X, Y, Z rotation matrices from euler angles. */
- create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
-
- /* Concatenate rotation matrices. */
- mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
-
- /* Extract location and scale from matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, mat);
-
- break;
- }
- case ROT_MODE_QUAT:
- {
- float q[4];
- copy_v4_v4(q, obj->quat);
-
- /* Swap axis. */
- q[2] = obj->quat[3];
- q[3] = -obj->quat[2];
-
- /* Compute rotation matrix from quaternion. */
- quat_to_mat3(rot_mat, q);
-
- /* Extract location and scale from matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, mat);
-
- break;
- }
- case ROT_MODE_XYZ:
- {
- /* Extract location, rotation, and scale form matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, mat);
-
- /* Get euler angles from rotation matrix. */
- mat3_to_eulO(euler, ROT_MODE_XYZ, rot);
-
- /* Create X, Y, Z rotation matrices from euler angles. */
- create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
-
- /* Concatenate rotation matrices. */
- mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
-
- break;
- }
- case ROT_MODE_XZY:
- {
- /* Extract location, rotation, and scale form matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, mat);
+ if (proxy_from) {
+ mul_m4_m4m4(zup_mat, proxy_from->obmat, zup_mat);
+ }
- /* Get euler angles from rotation matrix. */
- mat3_to_eulO(euler, ROT_MODE_XZY, rot);
+ copy_m44_axis_swap(r_yup_mat, zup_mat, ABC_YUP_FROM_ZUP);
+}
- /* Create X, Y, Z rotation matrices from euler angles. */
- create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
+bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name)
+{
+ if (!prop.valid()) {
+ return false;
+ }
- /* Concatenate rotation matrices. */
- mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
+ return prop.getPropertyHeader(name) != NULL;
+}
- break;
- }
- case ROT_MODE_YXZ:
- {
- /* Extract location, rotation, and scale form matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, mat);
+typedef std::pair<Alembic::AbcCoreAbstract::index_t, float> index_time_pair_t;
- /* Get euler angles from rotation matrix. */
- mat3_to_eulO(euler, ROT_MODE_YXZ, rot);
+float get_weight_and_index(float time,
+ const Alembic::AbcCoreAbstract::TimeSamplingPtr &time_sampling,
+ int samples_number,
+ Alembic::AbcGeom::index_t &i0,
+ Alembic::AbcGeom::index_t &i1)
+{
+ samples_number = std::max(samples_number, 1);
- /* Create X, Y, Z rotation matrices from euler angles. */
- create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
+ index_time_pair_t t0 = time_sampling->getFloorIndex(time, samples_number);
+ i0 = i1 = t0.first;
- /* Concatenate rotation matrices. */
- mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
+ if (samples_number == 1 || (fabs(time - t0.second) < 0.0001f)) {
+ return 0.0f;
+ }
- break;
- }
- case ROT_MODE_YZX:
- {
- /* Extract location, rotation, and scale form matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, mat);
+ index_time_pair_t t1 = time_sampling->getCeilIndex(time, samples_number);
+ i1 = t1.first;
- /* Get euler angles from rotation matrix. */
- mat3_to_eulO(euler, ROT_MODE_YZX, rot);
+ if (i0 == i1) {
+ return 0.0f;
+ }
- /* Create X, Y, Z rotation matrices from euler angles. */
- create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
+ const float bias = (time - t0.second) / (t1.second - t0.second);
- /* Concatenate rotation matrices. */
- mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
+ if (fabs(1.0f - bias) < 0.0001f) {
+ i0 = i1;
+ return 0.0f;
+ }
- break;
- }
- case ROT_MODE_ZXY:
- {
- /* Extract location, rotation, and scale form matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, mat);
+ return bias;
+}
- /* Get euler angles from rotation matrix. */
- mat3_to_eulO(euler, ROT_MODE_ZXY, rot);
+//#define USE_NURBS
- /* Create X, Y, Z rotation matrices from euler angles. */
- create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
+AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSettings &settings)
+{
+ AbcObjectReader *reader = NULL;
- /* Concatenate rotation matrices. */
- mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
+ const Alembic::AbcGeom::MetaData &md = object.getMetaData();
- break;
- }
- case ROT_MODE_ZYX:
- {
- /* Extract location, rotation, and scale form matrix. */
- mat4_to_loc_rot_size(loc, rot, scale, mat);
+ if (Alembic::AbcGeom::IXform::matches(md)) {
+ reader = new AbcEmptyReader(object, settings);
+ }
+ else if (Alembic::AbcGeom::IPolyMesh::matches(md)) {
+ reader = new AbcMeshReader(object, settings);
+ }
+ else if (Alembic::AbcGeom::ISubD::matches(md)) {
+ reader = new AbcSubDReader(object, settings);
+ }
+ else if (Alembic::AbcGeom::INuPatch::matches(md)) {
+#ifdef USE_NURBS
+ /* TODO(kevin): importing cyclic NURBS from other software crashes
+ * at the moment. This is due to the fact that NURBS in other
+ * software have duplicated points which causes buffer overflows in
+ * Blender. Need to figure out exactly how these points are
+ * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV).
+ * Until this is fixed, disabling NURBS reading. */
+ reader = new AbcNurbsReader(child, settings);
+#endif
+ }
+ else if (Alembic::AbcGeom::ICamera::matches(md)) {
+ reader = new AbcCameraReader(object, settings);
+ }
+ else if (Alembic::AbcGeom::IPoints::matches(md)) {
+ reader = new AbcPointsReader(object, settings);
+ }
+ else if (Alembic::AbcMaterial::IMaterial::matches(md)) {
+ /* Pass for now. */
+ }
+ else if (Alembic::AbcGeom::ILight::matches(md)) {
+ /* Pass for now. */
+ }
+ else if (Alembic::AbcGeom::IFaceSet::matches(md)) {
+ /* Pass, those are handled in the mesh reader. */
+ }
+ else if (Alembic::AbcGeom::ICurves::matches(md)) {
+ reader = new AbcCurveReader(object, settings);
+ }
+ else {
+ std::cerr << "Alembic: unknown how to handle objects of schema "
+ << md.get("schemaObjTitle")
+ << ", skipping object "
+ << object.getFullName() << std::endl;
+ }
- /* Get euler angles from rotation matrix. */
- mat3_to_eulO(euler, ROT_MODE_ZYX, rot);
+ return reader;
+}
- /* Create X, Y, Z rotation matrices from euler angles. */
- create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
+/* ********************** */
- /* Concatenate rotation matrices. */
- mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
- mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
+ScopeTimer::ScopeTimer(const char *message)
+ : m_message(message)
+ , m_start(PIL_check_seconds_timer())
+{}
- break;
- }
- }
+ScopeTimer::~ScopeTimer()
+{
+ fprintf(stderr, "%s: %fs\n", m_message, PIL_check_seconds_timer() - m_start);
+}
- /* Add rotation matrix to transformation matrix. */
- copy_m4_m3(transform_mat, rot_mat);
+/* ********************** */
- /* Add translation to transformation matrix. */
- copy_zup_yup(transform_mat[3], loc);
+bool SimpleLogger::empty()
+{
+ return ((size_t)m_stream.tellp()) == 0ul;
+}
- /* Create scale matrix. */
- scale_mat[0][0] = scale[0];
- scale_mat[1][1] = scale[2];
- scale_mat[2][2] = scale[1];
+std::string SimpleLogger::str() const
+{
+ return m_stream.str();
+}
- /* Add scale to transformation matrix. */
- mul_m4_m4m4(transform_mat, transform_mat, scale_mat);
+void SimpleLogger::clear()
+{
+ m_stream.clear();
+ m_stream.str("");
}
-bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name)
+std::ostringstream &SimpleLogger::stream()
{
- if (!prop.valid()) {
- return false;
- }
+ return m_stream;
+}
- return prop.getPropertyHeader(name) != NULL;
+std::ostream &operator<<(std::ostream &os, const SimpleLogger &logger)
+{
+ os << logger.str();
+ return os;
}
diff --git a/source/blender/alembic/intern/abc_util.h b/source/blender/alembic/intern/abc_util.h
index 688a25d85f6..fcc3b19c48b 100644
--- a/source/blender/alembic/intern/abc_util.h
+++ b/source/blender/alembic/intern/abc_util.h
@@ -32,23 +32,38 @@
# define ABC_INLINE static inline
#endif
+/**
+ * \brief The CacheReader struct is only used for anonymous pointers,
+ * to interface between C and C++ code. This library only creates
+ * pointers to AbcObjectReader (or subclasses thereof).
+ */
+struct CacheReader {
+ int unused;
+};
+
using Alembic::Abc::chrono_t;
-class ImportSettings;
+class AbcObjectReader;
+struct ImportSettings;
struct ID;
struct Object;
+struct Base;
-std::string get_id_name(ID *id);
-std::string get_id_name(Object *ob);
-std::string get_object_dag_path_name(Object *ob, Object *dupli_parent);
+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]);
-void create_transform_matrix(float r_mat[4][4]);
-void create_transform_matrix(Object *obj, float transform_mat[4][4]);
+
+typedef enum {
+ ABC_MATRIX_WORLD = 1,
+ ABC_MATRIX_LOCAL = 2,
+} AbcMatrixMode;
+void create_transform_matrix(Object *obj, float r_transform_mat[4][4],
+ AbcMatrixMode mode, Object *proxy_from);
void split(const std::string &s, const char delim, std::vector<std::string> &tokens);
@@ -59,12 +74,10 @@ bool begins_with(const TContainer &input, const TContainer &match)
&& std::equal(match.begin(), match.end(), input.begin());
}
-void create_input_transform(const Alembic::AbcGeom::ISampleSelector &sample_sel,
- const Alembic::AbcGeom::IXform &ixform, Object *ob,
- float r_mat[4][4], float scale, bool has_alembic_parent = false);
+void convert_matrix(const Imath::M44d &xform, Object *ob, float r_mat[4][4]);
template <typename Schema>
-void get_min_max_time(const Schema &schema, chrono_t &min, chrono_t &max)
+void get_min_max_time_ex(const Schema &schema, chrono_t &min, chrono_t &max)
{
const Alembic::Abc::TimeSamplingPtr &time_samp = schema.getTimeSampling();
@@ -81,8 +94,28 @@ void get_min_max_time(const Schema &schema, chrono_t &min, chrono_t &max)
}
}
+template <typename Schema>
+void get_min_max_time(const Alembic::AbcGeom::IObject &object, const Schema &schema, chrono_t &min, chrono_t &max)
+{
+ get_min_max_time_ex(schema, min, max);
+
+ const Alembic::AbcGeom::IObject &parent = object.getParent();
+ if (parent.valid() && Alembic::AbcGeom::IXform::matches(parent.getMetaData())) {
+ Alembic::AbcGeom::IXform xform(parent, Alembic::AbcGeom::kWrapExisting);
+ get_min_max_time_ex(xform.getSchema(), min, max);
+ }
+}
+
bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name);
+float get_weight_and_index(float time,
+ const Alembic::AbcCoreAbstract::TimeSamplingPtr &time_sampling,
+ int samples_number,
+ Alembic::AbcGeom::index_t &i0,
+ Alembic::AbcGeom::index_t &i1);
+
+AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSettings &settings);
+
/* ************************** */
/* TODO(kevin): for now keeping these transformations hardcoded to make sure
@@ -92,34 +125,117 @@ bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string
/* Copy from Y-up to Z-up. */
-ABC_INLINE void copy_yup_zup(float zup[3], const float yup[3])
+ABC_INLINE void copy_zup_from_yup(float zup[3], const float yup[3])
{
+ const float old_yup1 = yup[1]; /* in case zup == yup */
zup[0] = yup[0];
zup[1] = -yup[2];
- zup[2] = yup[1];
+ zup[2] = old_yup1;
}
-ABC_INLINE void copy_yup_zup(short zup[3], const short yup[3])
+ABC_INLINE void copy_zup_from_yup(short zup[3], const short yup[3])
{
+ const short old_yup1 = yup[1]; /* in case zup == yup */
zup[0] = yup[0];
zup[1] = -yup[2];
- zup[2] = yup[1];
+ zup[2] = old_yup1;
}
/* Copy from Z-up to Y-up. */
-ABC_INLINE void copy_zup_yup(float yup[3], const float zup[3])
+ABC_INLINE void copy_yup_from_zup(float yup[3], const float zup[3])
{
+ const float old_zup1 = zup[1]; /* in case yup == zup */
yup[0] = zup[0];
yup[1] = zup[2];
- yup[2] = -zup[1];
+ yup[2] = -old_zup1;
}
-ABC_INLINE void copy_zup_yup(short yup[3], const short zup[3])
+ABC_INLINE void copy_yup_from_zup(short yup[3], const short zup[3])
{
+ const short old_zup1 = zup[1]; /* in case yup == zup */
yup[0] = zup[0];
yup[1] = zup[2];
- yup[2] = -zup[1];
+ yup[2] = -old_zup1;
}
+/* Names are given in (dst, src) order, just like
+ * the parameters of copy_m44_axis_swap() */
+typedef enum {
+ ABC_ZUP_FROM_YUP = 1,
+ ABC_YUP_FROM_ZUP = 2,
+} AbcAxisSwapMode;
+
+/* Create a rotation matrix for each axis from euler angles.
+ * Euler angles are swaped to change coordinate system. */
+void create_swapped_rotation_matrix(
+ float rot_x_mat[3][3], float rot_y_mat[3][3],
+ float rot_z_mat[3][3], const float euler[3],
+ AbcAxisSwapMode mode);
+
+void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMode mode);
+
+/* *************************** */
+
+#undef ABC_DEBUG_TIME
+
+class ScopeTimer {
+ const char *m_message;
+ double m_start;
+
+public:
+ ScopeTimer(const char *message);
+ ~ScopeTimer();
+};
+
+#ifdef ABC_DEBUG_TIME
+# define SCOPE_TIMER(message) ScopeTimer prof(message)
+#else
+# define SCOPE_TIMER(message)
+#endif
+
+/* *************************** */
+
+/**
+ * Utility class whose purpose is to more easily log related informations. An
+ * instance of the SimpleLogger can be created in any context, and will hold a
+ * copy of all the strings passed to its output stream.
+ *
+ * Different instances of the class may be accessed from different threads,
+ * although accessing the same instance from different threads will lead to race
+ * conditions.
+ */
+class SimpleLogger {
+ std::ostringstream m_stream;
+
+public:
+ /**
+ * Check whether or not the SimpleLogger's stream is empty.
+ */
+ bool empty();
+
+ /**
+ * Return a copy of the string contained in the SimpleLogger's stream.
+ */
+ std::string str() const;
+
+ /**
+ * Remove the bits set on the SimpleLogger's stream and clear its string.
+ */
+ void clear();
+
+ /**
+ * Return a reference to the SimpleLogger's stream, in order to e.g. push
+ * content into it.
+ */
+ std::ostringstream &stream();
+};
+
+#define ABC_LOG(logger) logger.stream()
+
+/**
+ * Pass the content of the logger's stream to the specified std::ostream.
+ */
+std::ostream &operator<<(std::ostream &os, const SimpleLogger &logger);
+
#endif /* __ABC_UTIL_H__ */
diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc
index 0e96ac22e11..692fc203706 100644
--- a/source/blender/alembic/intern/alembic_capi.cc
+++ b/source/blender/alembic/intern/alembic_capi.cc
@@ -21,14 +21,11 @@
*/
#include "../ABC_alembic.h"
+#include <boost/foreach.hpp>
-#ifdef WITH_ALEMBIC_HDF5
-# include <Alembic/AbcCoreHDF5/All.h>
-#endif
-
-#include <Alembic/AbcCoreOgawa/All.h>
#include <Alembic/AbcMaterial/IMaterial.h>
+#include "abc_archive.h"
#include "abc_camera.h"
#include "abc_curves.h"
#include "abc_hair.h"
@@ -51,12 +48,15 @@ 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
@@ -77,13 +77,10 @@ extern "C" {
using Alembic::Abc::Int32ArraySamplePtr;
using Alembic::Abc::ObjectHeader;
-using Alembic::AbcGeom::ErrorHandler;
-using Alembic::AbcGeom::Exception;
using Alembic::AbcGeom::MetaData;
using Alembic::AbcGeom::P3fArraySamplePtr;
using Alembic::AbcGeom::kWrapExisting;
-using Alembic::AbcGeom::IArchive;
using Alembic::AbcGeom::ICamera;
using Alembic::AbcGeom::ICurves;
using Alembic::AbcGeom::ICurvesSchema;
@@ -113,143 +110,84 @@ struct AbcArchiveHandle {
int unused;
};
-ABC_INLINE IArchive *archive_from_handle(AbcArchiveHandle *handle)
+ABC_INLINE ArchiveReader *archive_from_handle(AbcArchiveHandle *handle)
{
- return reinterpret_cast<IArchive *>(handle);
+ return reinterpret_cast<ArchiveReader *>(handle);
}
-ABC_INLINE AbcArchiveHandle *handle_from_archive(IArchive *archive)
+ABC_INLINE AbcArchiveHandle *handle_from_archive(ArchiveReader *archive)
{
return reinterpret_cast<AbcArchiveHandle *>(archive);
}
-static IArchive *open_archive(const std::string &filename)
-{
- Alembic::AbcCoreAbstract::ReadArraySampleCachePtr cache_ptr;
- IArchive *archive;
-
- try {
- archive = new IArchive(Alembic::AbcCoreOgawa::ReadArchive(),
- filename.c_str(), ErrorHandler::kThrowPolicy,
- cache_ptr);
- }
- catch (const Exception &e) {
- std::cerr << e.what() << '\n';
-
-#ifdef WITH_ALEMBIC_HDF5
- try {
- archive = new IArchive(Alembic::AbcCoreHDF5::ReadArchive(),
- filename.c_str(), ErrorHandler::kThrowPolicy,
- cache_ptr);
- }
- catch (const Exception &) {
- std::cerr << e.what() << '\n';
- return NULL;
- }
-#else
- return NULL;
-#endif
- }
-
- return archive;
-}
-
//#define USE_NURBS
/* NOTE: this function is similar to visit_objects below, need to keep them in
* sync. */
-static void gather_objects_paths(const IObject &object, ListBase *object_paths)
+static bool gather_objects_paths(const IObject &object, ListBase *object_paths)
{
if (!object.valid()) {
- return;
+ return false;
}
- for (int i = 0; i < object.getNumChildren(); ++i) {
- IObject child = object.getChild(i);
- if (!child.valid()) {
- continue;
- }
+ size_t children_claiming_this_object = 0;
+ size_t num_children = object.getNumChildren();
- bool get_path = false;
+ for (size_t i = 0; i < num_children; ++i) {
+ bool child_claims_this_object = gather_objects_paths(object.getChild(i), object_paths);
+ children_claiming_this_object += child_claims_this_object ? 1 : 0;
+ }
- const MetaData &md = child.getMetaData();
+ const MetaData &md = object.getMetaData();
+ bool get_path = false;
+ bool parent_is_part_of_this_object = false;
- if (IXform::matches(md)) {
- /* Check whether or not this object is a Maya locator, which is
- * similar to empties used as parent object in Blender. */
- if (has_property(child.getProperties(), "locator")) {
- get_path = true;
- }
- else {
- /* Avoid creating an empty object if the child of this transform
- * is not a transform (that is an empty). */
- if (child.getNumChildren() == 1) {
- if (IXform::matches(child.getChild(0).getMetaData())) {
- get_path = true;
- }
-#if 0
- else {
- std::cerr << "Skipping " << child.getFullName() << '\n';
- }
-#endif
- }
- else {
- get_path = true;
- }
- }
- }
- else if (IPolyMesh::matches(md)) {
- get_path = true;
- }
- else if (ISubD::matches(md)) {
- get_path = true;
- }
- else if (INuPatch::matches(md)) {
-#ifdef USE_NURBS
- get_path = true;
-#endif
- }
- else if (ICamera::matches(md)) {
- get_path = true;
- }
- else if (IPoints::matches(md)) {
- get_path = true;
- }
- else if (IMaterial::matches(md)) {
- /* Pass for now. */
- }
- else if (ILight::matches(md)) {
- /* Pass for now. */
- }
- else if (IFaceSet::matches(md)) {
- /* Pass, those are handled in the mesh reader. */
- }
- else if (ICurves::matches(md)) {
+ if (!object.getParent()) {
+ /* The root itself is not an object we should import. */
+ }
+ else if (IXform::matches(md)) {
+ if (has_property(object.getProperties(), "locator")) {
get_path = true;
}
else {
- assert(false);
+ get_path = children_claiming_this_object == 0;
}
- if (get_path) {
- AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(
- MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath"));
-
- BLI_strncpy(abc_path->path, child.getFullName().c_str(), PATH_MAX);
+ /* Transforms are never "data" for their parent. */
+ parent_is_part_of_this_object = false;
+ }
+ else {
+ /* These types are "data" for their parent. */
+ get_path =
+ IPolyMesh::matches(md) ||
+ ISubD::matches(md) ||
+#ifdef USE_NURBS
+ INuPatch::matches(md) ||
+#endif
+ ICamera::matches(md) ||
+ IPoints::matches(md) ||
+ ICurves::matches(md);
+ parent_is_part_of_this_object = get_path;
+ }
- BLI_addtail(object_paths, abc_path);
- }
+ if (get_path) {
+ void *abc_path_void = MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath");
+ AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(abc_path_void);
- gather_objects_paths(child, object_paths);
+ BLI_strncpy(abc_path->path, object.getFullName().c_str(), sizeof(abc_path->path));
+ BLI_addtail(object_paths, abc_path);
}
+
+ return parent_is_part_of_this_object;
}
AbcArchiveHandle *ABC_create_handle(const char *filename, ListBase *object_paths)
{
- IArchive *archive = open_archive(filename);
+ ArchiveReader *archive = new ArchiveReader(filename);
- if (!archive) {
+ if (!archive->valid()) {
+ delete archive;
return NULL;
}
@@ -303,6 +241,7 @@ struct ExportJobData {
float *progress;
bool was_canceled;
+ bool export_ok;
};
static void export_startjob(void *customdata, short *stop, short *do_update, float *progress)
@@ -333,15 +272,16 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo
if (CFRA != orig_frame) {
CFRA = orig_frame;
- BKE_scene_update_for_newframe(data->bmain->eval_ctx, data->bmain,
- scene, scene->lay);
+ BKE_scene_update_for_newframe(data->bmain->eval_ctx, data->bmain, scene);
}
+
+ data->export_ok = !data->was_canceled;
}
catch (const std::exception &e) {
- std::cerr << "Abc Export error: " << e.what() << '\n';
+ ABC_LOG(data->settings.logger) << "Abc Export error: " << e.what() << '\n';
}
catch (...) {
- std::cerr << "Abc Export error\n";
+ ABC_LOG(data->settings.logger) << "Abc Export: unknown error...\n";
}
}
@@ -353,185 +293,342 @@ static void export_endjob(void *customdata)
BLI_delete(data->filename, false, false);
}
+ if (!data->settings.logger.empty()) {
+ std::cerr << data->settings.logger;
+ WM_report(RPT_ERROR, "Errors occured during the export, look in the console to know more...");
+ }
+
G.is_rendering = false;
BKE_spacedata_draw_locks(false);
}
-void ABC_export(
+bool ABC_export(
Scene *scene,
bContext *C,
const char *filepath,
- const struct AlembicExportParams *params)
+ const struct AlembicExportParams *params,
+ bool as_background_job)
{
ExportJobData *job = static_cast<ExportJobData *>(MEM_mallocN(sizeof(ExportJobData), "ExportJobData"));
job->scene = scene;
job->bmain = CTX_data_main(C);
+ job->export_ok = false;
BLI_strncpy(job->filename, filepath, 1024);
+ /* Alright, alright, alright....
+ *
+ * ExportJobData contains an ExportSettings containing a SimpleLogger.
+ *
+ * Since ExportJobData is a C-style struct dynamically allocated with
+ * MEM_mallocN (see above), its construtor is never called, therefore the
+ * ExportSettings constructor is not called which implies that the
+ * SimpleLogger one is not called either. SimpleLogger in turn does not call
+ * the constructor of its data members which ultimately means that its
+ * std::ostringstream member has a NULL pointer. To be able to properly use
+ * the stream's operator<<, the pointer needs to be set, therefore we have
+ * to properly construct everything. And this is done using the placement
+ * new operator as here below. It seems hackish, but I'm too lazy to
+ * 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;
+
+ /* 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.sl = CTX_data_scene_layer(C);
+
job->settings.frame_start = params->frame_start;
job->settings.frame_end = params->frame_end;
- job->settings.frame_step_xform = params->frame_step_xform;
- job->settings.frame_step_shape = params->frame_step_shape;
+ job->settings.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;
job->settings.export_vcols = params->vcolors;
+ job->settings.export_hair = params->export_hair;
+ 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;
job->settings.global_scale = params->global_scale;
+ job->settings.triangulate = params->triangulate;
+ job->settings.quad_method = params->quad_method;
+ job->settings.ngon_method = params->ngon_method;
if (job->settings.frame_start > job->settings.frame_end) {
std::swap(job->settings.frame_start, job->settings.frame_end);
}
- wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
- CTX_wm_window(C),
- job->scene,
- "Alembic Export",
- WM_JOB_PROGRESS,
- WM_JOB_TYPE_ALEMBIC);
+ bool export_ok = false;
+ if (as_background_job) {
+ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ job->scene,
+ "Alembic Export",
+ WM_JOB_PROGRESS,
+ WM_JOB_TYPE_ALEMBIC);
+
+ /* setup job */
+ WM_jobs_customdata_set(wm_job, job, MEM_freeN);
+ WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME);
+ WM_jobs_callbacks(wm_job, export_startjob, NULL, NULL, export_endjob);
+
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+ }
+ else {
+ /* Fake a job context, so that we don't need NULL pointer checks while exporting. */
+ short stop = 0, do_update = 0;
+ float progress = 0.f;
+
+ export_startjob(job, &stop, &do_update, &progress);
+ export_endjob(job);
+ export_ok = job->export_ok;
- /* setup job */
- WM_jobs_customdata_set(wm_job, job, MEM_freeN);
- WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME);
- WM_jobs_callbacks(wm_job, export_startjob, NULL, NULL, export_endjob);
+ MEM_freeN(job);
+ }
- WM_jobs_start(CTX_wm_manager(C), wm_job);
+ return export_ok;
}
/* ********************** Import file ********************** */
-static void visit_object(const IObject &object,
- std::vector<AbcObjectReader *> &readers,
- GHash *parent_map,
- ImportSettings &settings)
+/**
+ * Generates an AbcObjectReader for this Alembic object and its children.
+ *
+ * \param object The Alembic IObject to visit.
+ * \param readers The created AbcObjectReader * will be appended to this vector.
+ * \param settings Import settings, not used directly but passed to the
+ * AbcObjectReader subclass constructors.
+ * \param r_assign_as_parent Return parameter, contains a list of reader
+ * pointers, whose parent pointer should still be set.
+ * This is filled when this call to visit_object() didn't create
+ * a reader that should be the parent.
+ * \return A pair of boolean and reader pointer. The boolean indicates whether
+ * this IObject claims its parent as part of the same object
+ * (for example an IPolyMesh object would claim its parent, as the mesh
+ * is interpreted as the object's data, and the parent IXform as its
+ * Blender object). The pointer is the AbcObjectReader that represents
+ * the IObject parameter.
+ *
+ * NOTE: this function is similar to gather_object_paths above, need to keep
+ * them in sync. */
+static std::pair<bool, AbcObjectReader *> visit_object(
+ const IObject &object,
+ AbcObjectReader::ptr_vector &readers,
+ ImportSettings &settings,
+ AbcObjectReader::ptr_vector &r_assign_as_parent)
{
+ const std::string & full_name = object.getFullName();
+
if (!object.valid()) {
- return;
+ std::cerr << " - "
+ << full_name
+ << ": object is invalid, skipping it and all its children.\n";
+ return std::make_pair(false, static_cast<AbcObjectReader *>(NULL));
}
- for (int i = 0; i < object.getNumChildren(); ++i) {
- IObject child = object.getChild(i);
-
- if (!child.valid()) {
- continue;
+ /* The interpretation of data by the children determine the role of this
+ * object. This is especially important for Xform objects, as they can be
+ * either part of a Blender object or a Blender object (Empty) themselves.
+ */
+ size_t children_claiming_this_object = 0;
+ size_t num_children = object.getNumChildren();
+ AbcObjectReader::ptr_vector claiming_child_readers;
+ AbcObjectReader::ptr_vector nonclaiming_child_readers;
+ AbcObjectReader::ptr_vector assign_as_parent;
+ for (size_t i = 0; i < num_children; ++i) {
+ const IObject ichild = object.getChild(i);
+
+ /* TODO: When we only support C++11, use std::tie() instead. */
+ std::pair<bool, AbcObjectReader *> child_result;
+ child_result = visit_object(ichild, readers, settings, assign_as_parent);
+
+ bool child_claims_this_object = child_result.first;
+ AbcObjectReader *child_reader = child_result.second;
+
+ if (child_reader == NULL) {
+ BLI_assert(!child_claims_this_object);
+ }
+ else {
+ if (child_claims_this_object) {
+ claiming_child_readers.push_back(child_reader);
+ }
+ else {
+ nonclaiming_child_readers.push_back(child_reader);
+ }
}
- AbcObjectReader *reader = NULL;
+ children_claiming_this_object += child_claims_this_object ? 1 : 0;
+ }
+ BLI_assert(children_claiming_this_object == claiming_child_readers.size());
- const MetaData &md = child.getMetaData();
+ AbcObjectReader *reader = NULL;
+ const MetaData &md = object.getMetaData();
+ bool parent_is_part_of_this_object = false;
- if (IXform::matches(md)) {
- bool create_xform = false;
+ if (!object.getParent()) {
+ /* The root itself is not an object we should import. */
+ }
+ else if (IXform::matches(md)) {
+ bool create_empty;
- /* Check whether or not this object is a Maya locator, which is
- * similar to empties used as parent object in Blender. */
- if (has_property(child.getProperties(), "locator")) {
- create_xform = true;
- }
- else {
- /* Avoid creating an empty object if the child of this transform
- * is not a transform (that is an empty). */
- if (child.getNumChildren() == 1) {
- if (IXform::matches(child.getChild(0).getMetaData())) {
- create_xform = true;
- }
-#if 0
- else {
- std::cerr << "Skipping " << child.getFullName() << '\n';
- }
-#endif
- }
- else {
- create_xform = true;
- }
- }
+ /* An xform can either be a Blender Object (if it contains a mesh, for
+ * example), but it can also be an Empty. Its correct translation to
+ * Blender's data model depends on its children. */
- if (create_xform) {
- reader = new AbcEmptyReader(child, settings);
- }
+ /* Check whether or not this object is a Maya locator, which is
+ * similar to empties used as parent object in Blender. */
+ if (has_property(object.getProperties(), "locator")) {
+ create_empty = true;
}
- else if (IPolyMesh::matches(md)) {
- reader = new AbcMeshReader(child, settings);
+ else {
+ create_empty = claiming_child_readers.empty();
}
- else if (ISubD::matches(md)) {
- reader = new AbcSubDReader(child, settings);
+
+ if (create_empty) {
+ reader = new AbcEmptyReader(object, settings);
}
- else if (INuPatch::matches(md)) {
+ }
+ else if (IPolyMesh::matches(md)) {
+ reader = new AbcMeshReader(object, settings);
+ parent_is_part_of_this_object = true;
+ }
+ else if (ISubD::matches(md)) {
+ reader = new AbcSubDReader(object, settings);
+ parent_is_part_of_this_object = true;
+ }
+ else if (INuPatch::matches(md)) {
#ifdef USE_NURBS
- /* TODO(kevin): importing cyclic NURBS from other software crashes
- * at the moment. This is due to the fact that NURBS in other
- * software have duplicated points which causes buffer overflows in
- * Blender. Need to figure out exactly how these points are
- * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV).
- * Until this is fixed, disabling NURBS reading. */
- reader = new AbcNurbsReader(child, settings);
+ /* TODO(kevin): importing cyclic NURBS from other software crashes
+ * at the moment. This is due to the fact that NURBS in other
+ * software have duplicated points which causes buffer overflows in
+ * Blender. Need to figure out exactly how these points are
+ * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV).
+ * Until this is fixed, disabling NURBS reading. */
+ reader = new AbcNurbsReader(object, settings);
+ parent_is_part_of_this_object = true;
#endif
- }
- else if (ICamera::matches(md)) {
- reader = new AbcCameraReader(child, settings);
- }
- else if (IPoints::matches(md)) {
- reader = new AbcPointsReader(child, settings);
- }
- else if (IMaterial::matches(md)) {
- /* Pass for now. */
- }
- else if (ILight::matches(md)) {
- /* Pass for now. */
- }
- else if (IFaceSet::matches(md)) {
- /* Pass, those are handled in the mesh reader. */
- }
- else if (ICurves::matches(md)) {
- reader = new AbcCurveReader(child, settings);
- }
- else {
- assert(false);
- }
-
- if (reader) {
- readers.push_back(reader);
+ }
+ else if (ICamera::matches(md)) {
+ reader = new AbcCameraReader(object, settings);
+ parent_is_part_of_this_object = true;
+ }
+ else if (IPoints::matches(md)) {
+ reader = new AbcPointsReader(object, settings);
+ parent_is_part_of_this_object = true;
+ }
+ else if (IMaterial::matches(md)) {
+ /* Pass for now. */
+ }
+ else if (ILight::matches(md)) {
+ /* Pass for now. */
+ }
+ else if (IFaceSet::matches(md)) {
+ /* Pass, those are handled in the mesh reader. */
+ }
+ else if (ICurves::matches(md)) {
+ reader = new AbcCurveReader(object, settings);
+ parent_is_part_of_this_object = true;
+ }
+ else {
+ std::cerr << "Alembic object " << full_name
+ << " is of unsupported schema type '"
+ << object.getMetaData().get("schemaObjTitle") << "'"
+ << std::endl;
+ }
- AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(
- MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath"));
+ if (reader) {
+ /* We have created a reader, which should imply that this object is
+ * not claimed as part of any child Alembic object. */
+ BLI_assert(claiming_child_readers.empty());
- BLI_strncpy(abc_path->path, child.getFullName().c_str(), PATH_MAX);
+ readers.push_back(reader);
+ reader->incref();
- BLI_addtail(&settings.cache_file->object_paths, abc_path);
+ AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(
+ MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath"));
+ BLI_strncpy(abc_path->path, full_name.c_str(), sizeof(abc_path->path));
+ BLI_addtail(&settings.cache_file->object_paths, abc_path);
- /* Cast to `void *` explicitly to avoid compiler errors because it
- * is a `const char *` which the compiler cast to `const void *`
- * instead of the expected `void *`. */
- BLI_ghash_insert(parent_map, (void *)child.getFullName().c_str(), reader);
+ /* We can now assign this reader as parent for our children. */
+ if (nonclaiming_child_readers.size() + assign_as_parent.size() > 0) {
+ /* TODO: When we only support C++11, use for (a: b) instead. */
+ BOOST_FOREACH(AbcObjectReader *child_reader, nonclaiming_child_readers) {
+ child_reader->parent_reader = reader;
+ }
+ BOOST_FOREACH(AbcObjectReader *child_reader, assign_as_parent) {
+ child_reader->parent_reader = reader;
+ }
+ }
+ }
+ else if (object.getParent()) {
+ if (claiming_child_readers.size() > 0) {
+ /* The first claiming child will serve just fine as parent to
+ * our non-claiming children. Since all claiming children share
+ * the same XForm, it doesn't really matter which one we pick. */
+ AbcObjectReader *claiming_child = claiming_child_readers[0];
+ BOOST_FOREACH(AbcObjectReader *child_reader, nonclaiming_child_readers) {
+ child_reader->parent_reader = claiming_child;
+ }
+ BOOST_FOREACH(AbcObjectReader *child_reader, assign_as_parent) {
+ child_reader->parent_reader = claiming_child;
+ }
+ /* Claiming children should have our parent set as their parent. */
+ BOOST_FOREACH(AbcObjectReader *child_reader, claiming_child_readers) {
+ r_assign_as_parent.push_back(child_reader);
+ }
+ }
+ else {
+ /* This object isn't claimed by any child, and didn't produce
+ * a reader. Odd situation, could be the top Alembic object, or
+ * an unsupported Alembic schema. Delegate to our parent. */
+ BOOST_FOREACH(AbcObjectReader *child_reader, claiming_child_readers) {
+ r_assign_as_parent.push_back(child_reader);
+ }
+ BOOST_FOREACH(AbcObjectReader *child_reader, nonclaiming_child_readers) {
+ r_assign_as_parent.push_back(child_reader);
+ }
+ BOOST_FOREACH(AbcObjectReader *child_reader, assign_as_parent) {
+ r_assign_as_parent.push_back(child_reader);
+ }
}
-
- visit_object(child, readers, parent_map, settings);
}
+
+ return std::make_pair(parent_is_part_of_this_object, reader);
}
enum {
ABC_NO_ERROR = 0,
ABC_ARCHIVE_FAIL,
+ ABC_UNSUPPORTED_HDF5,
};
struct ImportJobData {
Main *bmain;
Scene *scene;
+ SceneLayer *scene_layer;
char filename[1024];
ImportSettings settings;
- GHash *parent_map;
std::vector<AbcObjectReader *> readers;
short *stop;
@@ -540,14 +637,11 @@ struct ImportJobData {
char error_code;
bool was_cancelled;
+ bool import_ok;
};
ABC_INLINE bool is_mesh_and_strands(const IObject &object)
{
- if (object.getNumChildren() != 2) {
- return false;
- }
-
bool has_mesh = false;
bool has_curve = false;
@@ -569,6 +663,9 @@ ABC_INLINE bool is_mesh_and_strands(const IObject &object)
else if (ICurves::matches(md)) {
has_curve = true;
}
+ else if (IPoints::matches(md)) {
+ has_curve = true;
+ }
}
return has_mesh && has_curve;
@@ -576,16 +673,23 @@ ABC_INLINE bool is_mesh_and_strands(const IObject &object)
static void import_startjob(void *user_data, short *stop, short *do_update, float *progress)
{
+ SCOPE_TIMER("Alembic import, objects reading and creation");
+
ImportJobData *data = static_cast<ImportJobData *>(user_data);
data->stop = stop;
data->do_update = do_update;
data->progress = progress;
- IArchive *archive = open_archive(data->filename);
+ ArchiveReader *archive = new ArchiveReader(data->filename);
- if (!archive || !archive->valid()) {
+ if (!archive->valid()) {
+#ifndef WITH_ALEMBIC_HDF5
+ data->error_code = archive->is_hdf5() ? ABC_UNSUPPORTED_HDF5 : ABC_ARCHIVE_FAIL;
+#else
data->error_code = ABC_ARCHIVE_FAIL;
+#endif
+ delete archive;
return;
}
@@ -606,11 +710,12 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
*data->do_update = true;
*data->progress = 0.05f;
- data->parent_map = BLI_ghash_str_new("alembic parent ghash");
-
/* Parse Alembic Archive. */
+ AbcObjectReader::ptr_vector assign_as_parent;
+ visit_object(archive->getTop(), data->readers, data->settings, assign_as_parent);
- visit_object(archive->getTop(), data->readers, data->parent_map, data->settings);
+ /* There shouldn't be any orphans. */
+ BLI_assert(assign_as_parent.size() == 0);
if (G.is_break) {
data->was_cancelled = true;
@@ -628,19 +733,23 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
chrono_t min_time = std::numeric_limits<chrono_t>::max();
chrono_t max_time = std::numeric_limits<chrono_t>::min();
+ ISampleSelector sample_sel(0.0f);
std::vector<AbcObjectReader *>::iterator iter;
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
AbcObjectReader *reader = *iter;
if (reader->valid()) {
- reader->readObjectData(data->bmain, 0.0f);
- reader->readObjectMatrix(0.0f);
+ reader->readObjectData(data->bmain, sample_sel);
min_time = std::min(min_time, reader->minTime());
max_time = std::max(max_time, reader->maxTime());
}
+ else {
+ std::cerr << "Object " << reader->name() << " in Alembic file "
+ << data->filename << " is invalid.\n";
+ }
- *data->progress = 0.1f + 0.6f * (++i / size);
+ *data->progress = 0.1f + 0.3f * (++i / size);
*data->do_update = true;
if (G.is_break) {
@@ -653,50 +762,36 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
Scene *scene = data->scene;
if (data->settings.is_sequence) {
- SFRA = data->settings.offset;
+ SFRA = data->settings.sequence_offset;
EFRA = SFRA + (data->settings.sequence_len - 1);
CFRA = SFRA;
}
else if (min_time < max_time) {
- SFRA = min_time * FPS;
- EFRA = max_time * FPS;
+ SFRA = static_cast<int>(round(min_time * FPS));
+ EFRA = static_cast<int>(round(max_time * FPS));
CFRA = SFRA;
}
}
- /* Setup parentship. */
-
- i = 0;
+ /* Setup parenthood. */
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
const AbcObjectReader *reader = *iter;
- const AbcObjectReader *parent_reader = NULL;
- const IObject &iobject = reader->iobject();
-
- IObject parent = iobject.getParent();
+ const AbcObjectReader *parent_reader = reader->parent_reader;
+ Object *ob = reader->object();
- if (!IXform::matches(iobject.getHeader())) {
- /* In the case of an non XForm node, the parent is the transform
- * matrix of the data itself, so we get the its grand parent.
- */
-
- /* Special case with object only containing a mesh and some strands,
- * we want both objects to be parented to the same object. */
- if (!is_mesh_and_strands(parent)) {
- parent = parent.getParent();
- }
+ if (parent_reader == NULL || !reader->inherits_xform()) {
+ ob->parent = NULL;
}
-
- parent_reader = reinterpret_cast<AbcObjectReader *>(
- BLI_ghash_lookup(data->parent_map, parent.getFullName().c_str()));
-
- if (parent_reader) {
- Object *parent = parent_reader->object();
-
- if (parent != NULL && reader->object() != parent) {
- Object *ob = reader->object();
- ob->parent = parent;
- }
+ else {
+ ob->parent = parent_reader->object();
}
+ }
+
+ /* Setup transformations and constraints. */
+ i = 0;
+ for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
+ AbcObjectReader *reader = *iter;
+ reader->setupObjectTransform(0.0f);
*data->progress = 0.7f + 0.3f * (++i / size);
*data->do_update = true;
@@ -710,6 +805,8 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
static void import_endjob(void *user_data)
{
+ SCOPE_TIMER("Alembic import, cleanup");
+
ImportJobData *data = static_cast<ImportJobData *>(user_data);
std::vector<AbcObjectReader *>::iterator iter;
@@ -719,45 +816,64 @@ static void import_endjob(void *user_data)
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
Object *ob = (*iter)->object();
- if (ob->data) {
- BKE_libblock_free_us(data->bmain, ob->data);
- ob->data = NULL;
- }
+ /* It's possible that cancellation occured between the creation of
+ * the reader and the creation of the Blender object. */
+ if (ob == NULL) continue;
BKE_libblock_free_us(data->bmain, ob);
}
}
else {
/* Add object to scene. */
- BKE_scene_base_deselect_all(data->scene);
+ Base *base;
+ LayerCollection *lc;
+ SceneLayer *sl = data->scene_layer;
+
+ BKE_scene_layer_base_deselect_all(sl);
+
+ lc = BKE_layer_collection_get_active(sl);
+ if (lc == NULL) {
+ BLI_assert(BLI_listbase_count_ex(&sl->layer_collections, 1) == 0);
+ /* when there is no collection linked to this SceneLayer, create one */
+ SceneCollection *sc = BKE_collection_add(data->scene, NULL, NULL);
+ lc = BKE_collection_link(sl, sc);
+ }
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
Object *ob = (*iter)->object();
ob->lay = data->scene->lay;
- BKE_scene_base_add(data->scene, ob);
+ BKE_collection_object_add(data->scene, lc->scene_collection, ob);
+
+ base = BKE_scene_layer_base_find(sl, ob);
+ BKE_scene_layer_base_select(sl, base);
- DAG_id_tag_update_ex(data->bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update_ex(data->bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
}
- DAG_relations_tag_update(data->bmain);
+ DEG_relations_tag_update(data->bmain);
}
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
- delete *iter;
- }
+ AbcObjectReader *reader = *iter;
+ reader->decref();
- if (data->parent_map) {
- BLI_ghash_free(data->parent_map, NULL, NULL);
+ if (reader->refcount() == 0) {
+ delete reader;
+ }
}
switch (data->error_code) {
default:
case ABC_NO_ERROR:
+ data->import_ok = !data->was_cancelled;
break;
case ABC_ARCHIVE_FAIL:
WM_report(RPT_ERROR, "Could not open Alembic archive for reading! See console for detail.");
break;
+ case ABC_UNSUPPORTED_HDF5:
+ WM_report(RPT_ERROR, "Alembic archive in obsolete HDF5 format is not supported.");
+ break;
}
WM_main_add_notifier(NC_SCENE | ND_FRAME, data->scene);
@@ -769,368 +885,145 @@ static void import_freejob(void *user_data)
delete data;
}
-void ABC_import(bContext *C, const char *filepath, float scale, bool is_sequence, bool set_frame_range, int sequence_len, int offset, bool validate_meshes)
+bool ABC_import(bContext *C, const char *filepath, float scale, bool is_sequence,
+ bool set_frame_range, int sequence_len, int offset,
+ bool validate_meshes, bool as_background_job)
{
/* Using new here since MEM_* funcs do not call ctor to properly initialize
* data. */
ImportJobData *job = new ImportJobData();
job->bmain = CTX_data_main(C);
job->scene = CTX_data_scene(C);
+ job->scene_layer = CTX_data_scene_layer(C);
+ job->import_ok = false;
BLI_strncpy(job->filename, filepath, 1024);
job->settings.scale = scale;
job->settings.is_sequence = is_sequence;
job->settings.set_frame_range = set_frame_range;
job->settings.sequence_len = sequence_len;
- job->settings.offset = offset;
+ job->settings.sequence_offset = offset;
job->settings.validate_meshes = validate_meshes;
- job->parent_map = NULL;
job->error_code = ABC_NO_ERROR;
job->was_cancelled = false;
G.is_break = false;
- wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
- CTX_wm_window(C),
- job->scene,
- "Alembic Import",
- WM_JOB_PROGRESS,
- WM_JOB_TYPE_ALEMBIC);
-
- /* setup job */
- WM_jobs_customdata_set(wm_job, job, import_freejob);
- WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME);
- WM_jobs_callbacks(wm_job, import_startjob, NULL, NULL, import_endjob);
-
- WM_jobs_start(CTX_wm_manager(C), wm_job);
-}
-
-/* ******************************* */
-
-void ABC_get_transform(AbcArchiveHandle *handle, Object *ob, const char *object_path, float r_mat[4][4], float time, float scale)
-{
- IArchive *archive = archive_from_handle(handle);
-
- if (!archive || !archive->valid()) {
- return;
- }
-
- IObject tmp;
- find_iobject(archive->getTop(), tmp, object_path);
-
- IXform ixform;
-
- if (IXform::matches(tmp.getHeader())) {
- ixform = IXform(tmp, kWrapExisting);
+ bool import_ok = false;
+ if (as_background_job) {
+ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ job->scene,
+ "Alembic Import",
+ WM_JOB_PROGRESS,
+ WM_JOB_TYPE_ALEMBIC);
+
+ /* setup job */
+ WM_jobs_customdata_set(wm_job, job, import_freejob);
+ WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME);
+ WM_jobs_callbacks(wm_job, import_startjob, NULL, NULL, import_endjob);
+
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
}
else {
- ixform = IXform(tmp.getParent(), kWrapExisting);
- }
+ /* Fake a job context, so that we don't need NULL pointer checks while importing. */
+ short stop = 0, do_update = 0;
+ float progress = 0.f;
- IXformSchema schema = ixform.getSchema();
+ import_startjob(job, &stop, &do_update, &progress);
+ import_endjob(job);
+ import_ok = job->import_ok;
- if (!schema.valid()) {
- return;
+ import_freejob(job);
}
- ISampleSelector sample_sel(time);
-
- create_input_transform(sample_sel, ixform, ob, r_mat, scale);
+ return import_ok;
}
-/* ***************************************** */
-
-static bool check_smooth_poly_flag(DerivedMesh *dm)
-{
- MPoly *mpolys = dm->getPolyArray(dm);
-
- for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) {
- MPoly &poly = mpolys[i];
-
- if ((poly.flag & ME_SMOOTH) != 0) {
- return true;
- }
- }
-
- return false;
-}
+/* ************************************************************************** */
-static void set_smooth_poly_flag(DerivedMesh *dm)
+void ABC_get_transform(CacheReader *reader, float r_mat[4][4], float time, float scale)
{
- MPoly *mpolys = dm->getPolyArray(dm);
-
- for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) {
- MPoly &poly = mpolys[i];
- poly.flag |= ME_SMOOTH;
+ if (!reader) {
+ return;
}
-}
-static void *add_customdata_cb(void *user_data, const char *name, int data_type)
-{
- DerivedMesh *dm = static_cast<DerivedMesh *>(user_data);
- CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
- void *cd_ptr = NULL;
-
- if (ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) {
- cd_ptr = CustomData_get_layer_named(dm->getLoopDataLayout(dm), cd_data_type, name);
-
- if (cd_ptr == NULL) {
- cd_ptr = CustomData_add_layer_named(dm->getLoopDataLayout(dm),
- cd_data_type,
- CD_DEFAULT,
- NULL,
- dm->getNumLoops(dm),
- name);
- }
- }
+ AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader);
- return cd_ptr;
+ bool is_constant = false;
+ abc_reader->read_matrix(r_mat, time, scale, is_constant);
}
-ABC_INLINE CDStreamConfig get_config(DerivedMesh *dm)
-{
- CDStreamConfig config;
-
- config.user_data = dm;
- config.mvert = dm->getVertArray(dm);
- config.mloop = dm->getLoopArray(dm);
- config.mpoly = dm->getPolyArray(dm);
- config.totloop = dm->getNumLoops(dm);
- config.totpoly = dm->getNumPolys(dm);
- config.loopdata = dm->getLoopDataLayout(dm);
- config.add_customdata_cb = add_customdata_cb;
-
- return config;
-}
+/* ************************************************************************** */
-static DerivedMesh *read_mesh_sample(DerivedMesh *dm, const IObject &iobject, const float time, int read_flag)
+DerivedMesh *ABC_read_mesh(CacheReader *reader,
+ Object *ob,
+ DerivedMesh *dm,
+ const float time,
+ const char **err_str,
+ int read_flag)
{
- IPolyMesh mesh(iobject, kWrapExisting);
- IPolyMeshSchema schema = mesh.getSchema();
- ISampleSelector sample_sel(time);
- const IPolyMeshSchema::Sample sample = schema.getValue(sample_sel);
-
- const P3fArraySamplePtr &positions = sample.getPositions();
- const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices();
- const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts();
-
- DerivedMesh *new_dm = NULL;
-
- /* Only read point data when streaming meshes, unless we need to create new ones. */
- ImportSettings settings;
- settings.read_flag |= read_flag;
+ AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader);
+ IObject iobject = abc_reader->iobject();
- if (dm->getNumVerts(dm) != positions->size()) {
- new_dm = CDDM_from_template(dm,
- positions->size(),
- 0,
- 0,
- face_indices->size(),
- face_counts->size());
-
- settings.read_flag |= MOD_MESHSEQ_READ_ALL;
+ if (!iobject.valid()) {
+ *err_str = "Invalid object: verify object path";
+ return NULL;
}
- CDStreamConfig config = get_config(new_dm ? new_dm : dm);
-
- bool has_loop_normals = false;
- read_mesh_sample(&settings, schema, sample_sel, config, has_loop_normals);
-
- if (new_dm) {
- /* Check if we had ME_SMOOTH flag set to restore it. */
- if (!has_loop_normals && check_smooth_poly_flag(dm)) {
- set_smooth_poly_flag(new_dm);
- }
-
- CDDM_calc_normals(new_dm);
- CDDM_calc_edges(new_dm);
-
- return new_dm;
+ const ObjectHeader &header = iobject.getHeader();
+ if (!abc_reader->accepts_object_type(header, ob, err_str)) {
+ /* err_str is set by acceptsObjectType() */
+ return NULL;
}
- return dm;
+ /* 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);
}
-using Alembic::AbcGeom::ISubDSchema;
+/* ************************************************************************** */
-static DerivedMesh *read_subd_sample(DerivedMesh *dm, const IObject &iobject, const float time, int read_flag)
+void CacheReader_free(CacheReader *reader)
{
- ISubD mesh(iobject, kWrapExisting);
- ISubDSchema schema = mesh.getSchema();
- ISampleSelector sample_sel(time);
- const ISubDSchema::Sample sample = schema.getValue(sample_sel);
-
- const P3fArraySamplePtr &positions = sample.getPositions();
- const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices();
- const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts();
+ AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader);
+ abc_reader->decref();
- DerivedMesh *new_dm = NULL;
-
- ImportSettings settings;
- settings.read_flag |= read_flag;
-
- if (dm->getNumVerts(dm) != positions->size()) {
- new_dm = CDDM_from_template(dm,
- positions->size(),
- 0,
- 0,
- face_indices->size(),
- face_counts->size());
-
- settings.read_flag |= MOD_MESHSEQ_READ_ALL;
+ if (abc_reader->refcount() == 0) {
+ delete abc_reader;
}
-
- /* Only read point data when streaming meshes, unless we need to create new ones. */
- CDStreamConfig config = get_config(new_dm ? new_dm : dm);
- read_subd_sample(&settings, schema, sample_sel, config);
-
- if (new_dm) {
- /* Check if we had ME_SMOOTH flag set to restore it. */
- if (check_smooth_poly_flag(dm)) {
- set_smooth_poly_flag(new_dm);
- }
-
- CDDM_calc_normals(new_dm);
- CDDM_calc_edges(new_dm);
-
- return new_dm;
- }
-
- return dm;
}
-static DerivedMesh *read_points_sample(DerivedMesh *dm, const IObject &iobject, const float time)
+void CacheReader_incref(CacheReader *reader)
{
- IPoints points(iobject, kWrapExisting);
- IPointsSchema schema = points.getSchema();
- ISampleSelector sample_sel(time);
- const IPointsSchema::Sample sample = schema.getValue(sample_sel);
-
- const P3fArraySamplePtr &positions = sample.getPositions();
-
- DerivedMesh *new_dm = NULL;
-
- if (dm->getNumVerts(dm) != positions->size()) {
- new_dm = CDDM_new(positions->size(), 0, 0, 0, 0);
- }
-
- CDStreamConfig config = get_config(new_dm ? new_dm : dm);
- read_points_sample(schema, sample_sel, config, time);
-
- return new_dm ? new_dm : dm;
+ AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader);
+ abc_reader->incref();
}
-/* NOTE: Alembic only stores data about control points, but the DerivedMesh
- * passed from the cache modifier contains the displist, which has more data
- * than the control points, so to avoid corrupting the displist we modify the
- * object directly and create a new DerivedMesh from that. Also we might need to
- * create new or delete existing NURBS in the curve.
- */
-static DerivedMesh *read_curves_sample(Object *ob, const IObject &iobject, const float time)
+CacheReader *CacheReader_open_alembic_object(AbcArchiveHandle *handle, CacheReader *reader, Object *object, const char *object_path)
{
- ICurves points(iobject, kWrapExisting);
- ICurvesSchema schema = points.getSchema();
- ISampleSelector sample_sel(time);
- const ICurvesSchema::Sample sample = schema.getValue(sample_sel);
-
- const P3fArraySamplePtr &positions = sample.getPositions();
- const Int32ArraySamplePtr num_vertices = sample.getCurvesNumVertices();
-
- int vertex_idx = 0;
- int curve_idx = 0;
- Curve *curve = static_cast<Curve *>(ob->data);
-
- const int curve_count = BLI_listbase_count(&curve->nurb);
-
- if (curve_count != num_vertices->size()) {
- BKE_nurbList_free(&curve->nurb);
- read_curve_sample(curve, schema, time);
+ if (object_path[0] == '\0') {
+ return reader;
}
- else {
- Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
- for (; nurbs; nurbs = nurbs->next, ++curve_idx) {
- const int totpoint = (*num_vertices)[curve_idx];
- if (nurbs->bp) {
- BPoint *point = nurbs->bp;
-
- for (int i = 0; i < totpoint; ++i, ++point, ++vertex_idx) {
- const Imath::V3f &pos = (*positions)[vertex_idx];
- copy_yup_zup(point->vec, pos.getValue());
- }
- }
- else if (nurbs->bezt) {
- BezTriple *bezier = nurbs->bezt;
-
- for (int i = 0; i < totpoint; ++i, ++bezier, ++vertex_idx) {
- const Imath::V3f &pos = (*positions)[vertex_idx];
- copy_yup_zup(bezier->vec[1], pos.getValue());
- }
- }
- }
- }
-
- return CDDM_from_curve(ob);
-}
-
-DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle,
- Object *ob,
- DerivedMesh *dm,
- const char *object_path,
- const float time,
- const char **err_str,
- int read_flag)
-{
- IArchive *archive = archive_from_handle(handle);
+ ArchiveReader *archive = archive_from_handle(handle);
if (!archive || !archive->valid()) {
- *err_str = "Invalid archive!";
- return NULL;
+ return reader;
}
IObject iobject;
find_iobject(archive->getTop(), iobject, object_path);
- if (!iobject.valid()) {
- *err_str = "Invalid object: verify object path";
- return NULL;
- }
-
- const ObjectHeader &header = iobject.getHeader();
-
- if (IPolyMesh::matches(header)) {
- if (ob->type != OB_MESH) {
- *err_str = "Object type mismatch: object path points to a mesh!";
- return NULL;
- }
-
- return read_mesh_sample(dm, iobject, time, read_flag);
+ if (reader) {
+ CacheReader_free(reader);
}
- else if (ISubD::matches(header)) {
- if (ob->type != OB_MESH) {
- *err_str = "Object type mismatch: object path points to a subdivision mesh!";
- return NULL;
- }
- return read_subd_sample(dm, iobject, time, read_flag);
- }
- else if (IPoints::matches(header)) {
- if (ob->type != OB_MESH) {
- *err_str = "Object type mismatch: object path points to a point cloud (requires a mesh object)!";
- return NULL;
- }
-
- return read_points_sample(dm, iobject, time);
- }
- else if (ICurves::matches(header)) {
- if (ob->type != OB_CURVE) {
- *err_str = "Object type mismatch: object path points to a curve!";
- return NULL;
- }
-
- return read_curves_sample(ob, iobject, time);
- }
+ ImportSettings settings;
+ AbcObjectReader *abc_reader = create_reader(iobject, settings);
+ abc_reader->object(object);
+ abc_reader->incref();
- *err_str = "Unsupported object type: verify object path"; // or poke developer
- return NULL;
+ return reinterpret_cast<CacheReader *>(abc_reader);
}
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h
index 1f38d64924c..22559edad22 100644
--- a/source/blender/blenfont/BLF_api.h
+++ b/source/blender/blenfont/BLF_api.h
@@ -34,14 +34,18 @@
#include "BLI_compiler_attrs.h"
+/* enable this only if needed (unused circa 2016) */
+#define BLF_BLUR_ENABLE 0
+
struct rctf;
struct ColorManagedDisplay;
struct ResultBLF;
-int BLF_init(int points, int dpi);
+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_cache_clear(void);
@@ -61,6 +65,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.
@@ -122,29 +137,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 132a0ec3808..24347d57917 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"
@@ -96,15 +97,16 @@ static FontBLF *blf_get(int fontid)
return NULL;
}
-int BLF_init(int points, int dpi)
+int BLF_init(void)
{
int i;
for (i = 0; i < BLF_MAX_FONT; i++)
global_font[i] = NULL;
- global_font_points = points;
- global_font_dpi = dpi;
+ global_font_points = 11;
+ global_font_dpi = 72;
+
return blf_font_init();
}
@@ -174,6 +176,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;
@@ -357,24 +365,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);
@@ -453,6 +443,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);
@@ -461,6 +452,77 @@ 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_draw_default(float x, float y, float z, const char *str, size_t len)
{
@@ -481,16 +543,7 @@ 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)
-{
- FontBLF *font = blf_get(global_font_default);
-
- if (font) {
- font->angle = angle;
- }
-}
-
-static void blf_draw_gl__start(FontBLF *font, GLint *mode)
+static void blf_draw_gl__start(FontBLF *font)
{
/*
* The pixmap alignment hack is handle
@@ -500,52 +553,46 @@ static void blf_draw_gl__start(FontBLF *font, GLint *mode)
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
+ gpuPushMatrix();
- /* Save the current matrix mode. */
- glGetIntegerv(GL_MATRIX_MODE, mode);
+ if (font->flags & BLF_MATRIX)
+ gpuMultMatrix(font->m);
- glMatrixMode(GL_TEXTURE);
- glPushMatrix();
- glLoadIdentity();
+ gpuTranslate3fv(font->pos);
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
+ if (font->flags & BLF_ASPECT)
+ gpuScale3fv(font->aspect);
- if (font->flags & BLF_MATRIX)
- glMultMatrixf(font->m);
+ if (font->flags & BLF_ROTATION)
+ gpuRotate2D(RAD2DEG(font->angle));
- glTranslate3fv(font->pos);
+#ifndef BLF_STANDALONE
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int texCoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
- if (font->flags & BLF_ASPECT)
- glScalef(font->aspect[0], font->aspect[1], font->aspect[2]);
+ BLI_assert(pos == BLF_POS_ID);
+ BLI_assert(texCoord == BLF_COORD_ID);
+ BLI_assert(color == BLF_COLOR_ID);
- if (font->flags & BLF_ROTATION) /* radians -> degrees */
- glRotatef(font->angle * (float)(180.0 / M_PI), 0.0f, 0.0f, 1.0f);
+ UNUSED_VARS_NDEBUG(pos, texCoord, color);
- if (font->shadow || font->blur)
- glGetFloatv(GL_CURRENT_COLOR, font->orig_col);
+ immBindBuiltinProgram(GPU_SHADER_TEXT);
+#endif
/* always bind the texture for the first glyph */
font->tex_bind_state = -1;
}
-static void blf_draw_gl__end(GLint mode)
+static void blf_draw_gl__end(void)
{
- glMatrixMode(GL_TEXTURE);
- glPopMatrix();
-
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
-
- if (mode != GL_MODELVIEW)
- glMatrixMode(mode);
+ gpuPopMatrix();
#ifndef BLF_STANDALONE
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ immUnbindProgram();
#endif
+
glDisable(GL_BLEND);
}
@@ -554,23 +601,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();
}
}
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);
}
@@ -579,12 +629,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);
@@ -592,24 +641,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();
}
}
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();
}
return columns;
@@ -689,14 +745,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)
@@ -727,14 +775,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)
@@ -798,15 +838,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);
@@ -828,18 +859,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);
@@ -855,7 +874,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_font.c b/source/blender/blenfont/intern/blf_font.c
index 44a1d08f1fd..03f62cbb6ea 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -58,6 +58,8 @@
#include "BIF_gl.h"
#include "BLF_api.h"
+#include "GPU_immediate.h"
+
#include "blf_internal_types.h"
#include "blf_internal.h"
@@ -172,6 +174,23 @@ static void blf_font_ensure_ascii_table(FontBLF *font)
} \
} (void)0
+static unsigned int verts_needed(const FontBLF *font, const char *str, size_t len)
+{
+ unsigned int length = (unsigned int)((len == INT_MAX) ? strlen(str) : len);
+ unsigned int quad_ct = 1;
+
+ if (font->flags & BLF_SHADOW) {
+ if (font->shadow == 0)
+ quad_ct += 1;
+ if (font->shadow <= 4)
+ quad_ct += 9; /* 3x3 kernel */
+ else
+ quad_ct += 25; /* 5x5 kernel */
+ }
+
+ return length * quad_ct * 6;
+}
+
static void blf_font_draw_ex(
FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info,
int pen_y)
@@ -187,6 +206,9 @@ static void blf_font_draw_ex(
blf_font_ensure_ascii_table(font);
+ immBeginAtMost(GWN_PRIM_TRIS, verts_needed(font, str, len));
+ /* at most because some glyphs might be clipped & not drawn */
+
while ((i < len) && str[i]) {
BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
@@ -204,6 +226,8 @@ static void blf_font_draw_ex(
g_prev = g;
}
+ immEnd();
+
if (r_info) {
r_info->lines = 1;
r_info->width = pen_x;
@@ -229,6 +253,8 @@ static void blf_font_draw_ascii_ex(
blf_font_ensure_ascii_table(font);
+ immBeginAtMost(GWN_PRIM_TRIS, verts_needed(font, str, len));
+
while ((c = *(str++)) && len--) {
BLI_assert(c < 128);
if ((g = glyph_ascii_table[c]) == NULL)
@@ -243,6 +269,8 @@ static void blf_font_draw_ascii_ex(
g_prev = g;
}
+ immEnd();
+
if (r_info) {
r_info->lines = 1;
r_info->width = pen_x;
@@ -265,6 +293,8 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth)
blf_font_ensure_ascii_table(font);
+ immBeginAtMost(GWN_PRIM_TRIS, verts_needed(font, str, len));
+
while ((i < len) && str[i]) {
BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
@@ -284,6 +314,8 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth)
pen_x += cwidth * col;
}
+ immEnd();
+
return columns;
}
@@ -901,8 +933,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 +940,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;
@@ -922,7 +958,9 @@ static void blf_font_fill(FontBLF *font)
font->size = 0;
BLI_listbase_clear(&font->cache);
font->glyph_cache = NULL;
+#if BLF_BLUR_ENABLE
font->blur = 0;
+#endif
font->max_tex_size = -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 aa7d539538b..a7d52e96800 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -56,7 +56,7 @@
#include "BLF_api.h"
#ifndef BLF_STANDALONE
-#include "GPU_basic_shader.h"
+#include "GPU_immediate.h"
#endif
#include "blf_internal_types.h"
@@ -135,6 +135,7 @@ void blf_glyph_cache_clear(FontBLF *font)
while ((gc = BLI_pophead(&font->cache))) {
blf_glyph_cache_free(gc);
}
+ font->glyph_cache = NULL;
}
void blf_glyph_cache_free(GlyphCacheBLF *gc)
@@ -182,18 +183,7 @@ static void blf_glyph_cache_texture(FontBLF *font, GlyphCacheBLF *gc)
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);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, gc->p2_width, gc->p2_height, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
}
GlyphBLF *blf_glyph_search(GlyphCacheBLF *gc, unsigned int c)
@@ -326,73 +316,83 @@ void blf_glyph_free(GlyphBLF *g)
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], float uv[2][2], float dx, float y1, float dx1, 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();
+ /* First triangle. */
+ immAttrib2f(BLF_COORD_ID, uv[0][0], uv[0][1]);
+ immSkipAttrib(BLF_COLOR_ID); /* skip color of most vertices */
+ immVertex2f(BLF_POS_ID, dx, y1);
+
+ immAttrib2f(BLF_COORD_ID, uv[0][0], uv[1][1]);
+ immSkipAttrib(BLF_COLOR_ID);
+ immVertex2f(BLF_POS_ID, dx, y2);
+
+ immAttrib2f(BLF_COORD_ID, uv[1][0], uv[1][1]);
+ immAttrib4ubv(BLF_COLOR_ID, color); /* set color of provoking vertex */
+ immVertex2f(BLF_POS_ID, dx1, y2);
+
+ /* Second triangle. */
+ immAttrib2f(BLF_COORD_ID, uv[0][0], uv[0][1]);
+ immSkipAttrib(BLF_COLOR_ID); /* skip color of most vertices */
+ immVertex2f(BLF_POS_ID, dx, y1);
+
+ immAttrib2f(BLF_COORD_ID, uv[1][0], uv[1][1]);
+ immSkipAttrib(BLF_COLOR_ID);
+ immVertex2f(BLF_POS_ID, dx1, y2);
+
+ immAttrib2f(BLF_COORD_ID, uv[1][0], uv[0][1]);
+ immAttrib4ubv(BLF_COLOR_ID, color); /* set color of provoking vertex */
+ immVertex2f(BLF_POS_ID, dx1, y1);
}
-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], 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];
+ unsigned char color[4];
float dx, dy;
- color[0] = shadow_col[0];
- color[1] = shadow_col[1];
- color[2] = shadow_col[2];
-
+ color[0] = color_in[0];
+ color[1] = color_in[1];
+ color[2] = color_in[2];
+
+ const float alpha_in = (1 / 255.0f) * color_in[3];
+
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);
+ color[3] = FTOCHAR(*fp * alpha_in);
+ blf_texture_draw(color, uv, x1 + dx, y1 + dy, x2 + dx, y2 + dy);
}
}
-
- glColor4fv(color);
}
-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], 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];
+ unsigned char color[4];
float dx, dy;
- color[0] = shadow_col[0];
- color[1] = shadow_col[1];
- color[2] = shadow_col[2];
+ color[0] = color_in[0];
+ color[1] = color_in[1];
+ color[2] = color_in[2];
+
+ const float alpha_in = (1 / 255.0f) * color_in[3];
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);
+ color[3] = FTOCHAR(*fp * alpha_in);
+ blf_texture_draw(color, uv, x1 + dx, y1 + dy, x2 + dx, y2 + dy);
}
}
-
- glColor4fv(color);
}
static void blf_glyph_calc_rect(rctf *rect, GlyphBLF *g, float x, float y)
@@ -449,14 +449,21 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
}
- glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
+ GLint lsb_first, row_length, alignment;
+ glGetIntegerv(GL_UNPACK_LSB_FIRST, &lsb_first);
+ glGetIntegerv(GL_UNPACK_ROW_LENGTH, &row_length);
+ glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
+
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->xoff, g->yoff, g->width, g->height, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap);
- glPopClientAttrib();
+ glTexSubImage2D(GL_TEXTURE_2D, 0, g->xoff, g->yoff, g->width, g->height, GL_RED, GL_UNSIGNED_BYTE, g->bitmap);
+
+ glPixelStorei(GL_UNPACK_LSB_FIRST, lsb_first);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
g->uv[0][0] = ((float)g->xoff) / ((float)gc->p2_width);
g->uv[0][1] = ((float)g->yoff) / ((float)gc->p2_height);
@@ -486,39 +493,37 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
glBindTexture(GL_TEXTURE_2D, (font->tex_bind_state = g->tex));
}
+ /* TODO: blur & shadow in shader, single quad per glyph */
+
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, g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax);
+ }
+ else {
+ blf_texture5_draw(font->shadow_color, 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, 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, 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 d9d758ce548..ba17e050399 100644
--- a/source/blender/blenfont/intern/blf_internal.h
+++ b/source/blender/blenfont/intern/blf_internal.h
@@ -37,6 +37,11 @@ struct GlyphBLF;
struct GlyphCacheBLF;
struct rctf;
+/* vertex attribute IDs (fixed IDs so we don't have to pass them around) */
+#define BLF_POS_ID 0
+#define BLF_COORD_ID 1
+#define BLF_COLOR_ID 2
+
unsigned int blf_next_p2(unsigned int x);
unsigned int blf_hash(unsigned int val);
diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h
index 0fac576a8cc..9164a02b2cc 100644
--- a/source/blender/blenfont/intern/blf_internal_types.h
+++ b/source/blender/blenfont/intern/blf_internal_types.h
@@ -175,8 +175,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 +188,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.
diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c
index 133168fccf2..b6f5ffbb092 100644
--- a/source/blender/blenfont/intern/blf_thumbs.c
+++ b/source/blender/blenfont/intern/blf_thumbs.c
@@ -98,6 +98,10 @@ void BLF_thumb_preview(
blf_font_size(font, (unsigned int)MAX2(font_size_min, font_size_curr), dpi);
+ /* font->glyph_cache remains NULL if blf_font_size() failed to set font size */
+ if (!font->glyph_cache)
+ break;
+
/* decrease font size each time */
font_size_curr -= (font_size_curr / font_shrink);
font_shrink += 1;
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 606488f85cc..78c2efcc8a2 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -142,8 +142,6 @@ 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),
@@ -201,7 +199,7 @@ struct DerivedMesh {
/* use for converting to BMesh which doesn't store bevel weight and edge crease by default */
char cd_flag;
- char tangent_mask; /* which tangent layers are calculated */
+ short tangent_mask; /* which tangent layers are calculated */
/** Calculate vert and face normals */
void (*calcNormals)(DerivedMesh *dm);
@@ -387,9 +385,6 @@ struct DerivedMesh {
/** 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
@@ -409,14 +404,6 @@ struct DerivedMesh {
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
@@ -443,14 +430,6 @@ struct DerivedMesh {
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
@@ -783,21 +762,20 @@ void DM_vertex_attributes_from_gpu(
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);
-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, char *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 */
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index 6527ba7f94f..5db0c3c9130 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -58,7 +58,7 @@ extern "C" {
struct bAction *add_empty_action(struct Main *bmain, const char name[]);
/* Allocate a copy of the given Action and all its data */
-struct bAction *BKE_action_copy(struct Main *bmain, struct bAction *src);
+struct bAction *BKE_action_copy(struct Main *bmain, const struct bAction *src);
/* Deallocate all of the Action's data, but not the Action itself */
void BKE_action_free(struct bAction *act);
@@ -150,7 +150,7 @@ void BKE_pose_free_data_ex(struct bPose *pose, bool do_id_user);
void BKE_pose_free_data(struct bPose *pose);
void BKE_pose_free(struct bPose *pose);
void BKE_pose_free_ex(struct bPose *pose, bool do_id_user);
-void BKE_pose_copy_data(struct bPose **dst, struct bPose *src, const bool copy_constraints);
+void BKE_pose_copy_data(struct bPose **dst, const struct bPose *src, const bool copy_constraints);
void BKE_pose_channel_copy_data(struct bPoseChannel *pchan, const struct bPoseChannel *pchan_from);
struct bPoseChannel *BKE_pose_channel_find_name(const struct bPose *pose, const char *name);
struct bPoseChannel *BKE_pose_channel_active(struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index 00ea323f934..3e6e24a28b0 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -73,7 +73,7 @@ struct AnimData *BKE_animdata_copy(struct AnimData *adt, const bool do_action);
bool BKE_animdata_copy_id(struct ID *id_to, struct ID *id_from, const bool do_action);
/* Copy AnimData Actions */
-void BKE_animdata_copy_id_action(struct ID *id);
+void BKE_animdata_copy_id_action(struct ID *id, const bool set_newid);
/* Merge copies of data from source AnimData block */
typedef enum eAnimData_MergeCopy_Modes {
@@ -89,12 +89,6 @@ typedef enum eAnimData_MergeCopy_Modes {
void BKE_animdata_merge_copy(struct ID *dst_id, struct ID *src_id, eAnimData_MergeCopy_Modes action_mode, bool fix_drivers);
-/* Make Local */
-void BKE_animdata_make_local(struct AnimData *adt);
-
-/* Re-Assign ID's */
-void BKE_animdata_relink(struct AnimData *adt);
-
/* ************************************* */
/* KeyingSets API */
@@ -153,7 +147,7 @@ char *BKE_animdata_driver_path_hack(struct bContext *C, struct PointerRNA *ptr,
char *base_path);
/* ************************************* */
-/* Batch AnimData API */
+/* Gwn_Batch 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);
diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h
index 077fe2a629c..ffbdc6972f4 100644
--- a/source/blender/blenkernel/BKE_appdir.h
+++ b/source/blender/blenkernel/BKE_appdir.h
@@ -27,11 +27,15 @@
/* note on naming: typical _get() suffix is omitted here,
* since its the main purpose of the API. */
const char *BKE_appdir_folder_default(void);
+const char *BKE_appdir_folder_id_ex(const int folder_id, const char *subfolder, char *path, size_t path_len);
const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder);
const char *BKE_appdir_folder_id_create(const int folder_id, const char *subfolder);
const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *subfolder);
const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, const bool do_check);
+bool BKE_appdir_app_template_any(void);
+bool BKE_appdir_app_template_id_search(const char *app_template, char *path, size_t path_len);
+
/* Initialize path to program executable */
void BKE_appdir_program_path_init(const char *argv0);
@@ -78,6 +82,7 @@ enum {
#define BLENDER_STARTUP_FILE "startup.blend"
#define BLENDER_USERPREF_FILE "userpref.blend"
+#define BLENDER_WORKSPACES_FILE "workspaces.blend"
#define BLENDER_QUIT_FILE "quit.blend"
#define BLENDER_BOOKMARK_FILE "bookmarks.txt"
#define BLENDER_HISTORY_FILE "recent-files.txt"
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index c2323100205..fa3bf0e79c9 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -33,6 +33,7 @@
* \author nzc
*/
+struct bPose;
struct Bone;
struct GHash;
struct Main;
@@ -77,7 +78,7 @@ int BKE_armature_bonelist_count(struct ListBase *lb);
void BKE_armature_bonelist_free(struct ListBase *lb);
void BKE_armature_free(struct bArmature *arm);
void BKE_armature_make_local(struct Main *bmain, struct bArmature *arm, const bool lib_local);
-struct bArmature *BKE_armature_copy(struct Main *bmain, struct bArmature *arm);
+struct bArmature *BKE_armature_copy(struct Main *bmain, const struct bArmature *arm);
/* Bounding box. */
struct BoundBox *BKE_armature_boundbox_get(struct Object *ob);
@@ -176,6 +177,7 @@ void BKE_pose_eval_bone(struct EvaluationContext *eval_ctx,
struct bPoseChannel *pchan);
void BKE_pose_constraints_evaluate(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
struct Object *ob,
struct bPoseChannel *pchan);
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index d2d9c763031..ec0bfa6f5fa 100644
--- a/source/blender/blenkernel/BKE_blender.h
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -38,14 +38,21 @@
extern "C" {
#endif
+struct UserDef;
+
void BKE_blender_free(void);
void BKE_blender_globals_init(void);
void BKE_blender_globals_clear(void);
+void BKE_blender_version_string(
+ char *version_str, size_t maxncpy,
+ short version, short subversion, bool v_prefix, bool include_subversion);
+
+void BKE_blender_userdef_set_data(struct UserDef *userdef);
+void BKE_blender_userdef_free_data(struct UserDef *userdef);
+
+void BKE_blender_userdef_set_app_template(struct UserDef *userdef);
-void BKE_blender_userdef_free(void);
-void BKE_blender_userdef_refresh(void);
-
/* set this callback when a UI is running */
void BKE_blender_callback_test_break_set(void (*func)(void));
int BKE_blender_test_break(void);
diff --git a/source/blender/blenkernel/BKE_blender_copybuffer.h b/source/blender/blenkernel/BKE_blender_copybuffer.h
index 8aaf295c33a..02bd96217f6 100644
--- a/source/blender/blenkernel/BKE_blender_copybuffer.h
+++ b/source/blender/blenkernel/BKE_blender_copybuffer.h
@@ -37,6 +37,7 @@ struct ID;
void BKE_copybuffer_begin(struct Main *bmain_src);
void BKE_copybuffer_tag_ID(struct ID *id);
bool BKE_copybuffer_save(struct Main *bmain_src, const char *filename, struct ReportList *reports);
+bool BKE_copybuffer_read(struct Main *bmain_dst, const char *libname, struct ReportList *reports);
bool BKE_copybuffer_paste(struct bContext *C, const char *libname, const short flag, struct ReportList *reports);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_blender_undo.h b/source/blender/blenkernel/BKE_blender_undo.h
index 9547eeb9838..84a6d07be7d 100644
--- a/source/blender/blenkernel/BKE_blender_undo.h
+++ b/source/blender/blenkernel/BKE_blender_undo.h
@@ -42,6 +42,7 @@ extern bool BKE_undo_is_valid(const char *name);
extern void BKE_undo_reset(void);
extern void BKE_undo_number(struct bContext *C, int nr);
extern const char *BKE_undo_get_name(int nr, bool *r_active);
+extern const char *BKE_undo_get_name_last(void);
extern bool BKE_undo_save_file(const char *filename);
extern struct Main *BKE_undo_get_main(struct Scene **r_scene);
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 483fefbd89c..ae87f1097d1 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -27,8 +27,8 @@
/* 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 277
-#define BLENDER_SUBVERSION 3
+#define BLENDER_VERSION 280
+#define BLENDER_SUBVERSION 1
/* Several breakages with 270, e.g. constraint deg vs rad */
#define BLENDER_MINVERSION 270
#define BLENDER_MINSUBVERSION 6
diff --git a/source/blender/blenkernel/BKE_blendfile.h b/source/blender/blenkernel/BKE_blendfile.h
index 6767fce3abd..d9fff5343b0 100644
--- a/source/blender/blenkernel/BKE_blendfile.h
+++ b/source/blender/blenkernel/BKE_blendfile.h
@@ -33,8 +33,7 @@ struct ID;
struct Main;
struct MemFile;
struct ReportList;
-
-int BKE_blendfile_read(struct bContext *C, const char *filepath, struct ReportList *reports);
+struct UserDef;
enum {
BKE_BLENDFILE_READ_FAIL = 0, /* no load */
@@ -42,15 +41,28 @@ enum {
BKE_BLENDFILE_READ_OK_USERPREFS = 2, /* OK, and with new user settings */
};
+int BKE_blendfile_read(
+ struct bContext *C, const char *filepath,
+ struct ReportList *reports, int skip_flag);
bool BKE_blendfile_read_from_memory(
- struct bContext *C, const void *filebuf,
- int filelength, struct ReportList *reports, bool update_defaults);
+ struct bContext *C, const void *filebuf, int filelength,
+ struct ReportList *reports, int skip_flag, bool update_defaults);
bool BKE_blendfile_read_from_memfile(
struct bContext *C, struct MemFile *memfile,
+ struct ReportList *reports, int skip_flag);
+void BKE_blendfile_read_make_empty(struct bContext *C);
+
+struct UserDef *BKE_blendfile_userdef_read(
+ const char *filepath, struct ReportList *reports);
+struct UserDef *BKE_blendfile_userdef_read_from_memory(
+ const void *filebuf, int filelength,
struct ReportList *reports);
-int BKE_blendfile_read_userdef(const char *filepath, struct ReportList *reports);
-int BKE_blendfile_write_userdef(const char *filepath, struct ReportList *reports);
+int BKE_blendfile_userdef_write(const char *filepath, struct ReportList *reports);
+
+struct WorkspaceConfigFileData *BKE_blendfile_workspace_config_read(const char *filepath, 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 */
diff --git a/source/blender/blenkernel/BKE_boids.h b/source/blender/blenkernel/BKE_boids.h
index 582cd0cef8d..24f19951efe 100644
--- a/source/blender/blenkernel/BKE_boids.h
+++ b/source/blender/blenkernel/BKE_boids.h
@@ -61,6 +61,6 @@ BoidRule *boid_new_rule(int type);
BoidState *boid_new_state(BoidSettings *boids);
BoidState *boid_duplicate_state(BoidSettings *boids, BoidState *state);
void boid_free_settings(BoidSettings *boids);
-BoidSettings *boid_copy_settings(BoidSettings *boids);
+BoidSettings *boid_copy_settings(const BoidSettings *boids);
BoidState *boid_get_current_state(BoidSettings *boids);
#endif
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index 8bd4bdf89e1..42e4e73f2d5 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -44,7 +44,7 @@ void BKE_brush_system_exit(void);
void BKE_brush_init(struct Brush *brush);
struct Brush *BKE_brush_add(struct Main *bmain, const char *name, short ob_mode);
struct Brush *BKE_brush_first_search(struct Main *bmain, short ob_mode);
-struct Brush *BKE_brush_copy(struct Main *bmain, struct Brush *brush);
+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);
diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h
index 07db2217bac..cb72f0859d5 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -54,7 +54,6 @@ typedef struct BVHTreeFromEditMesh {
/* default callbacks to bvh nearest and raycast */
BVHTree_NearestPointCallback nearest_callback;
BVHTree_RayCastCallback raycast_callback;
- BVHTree_NearestToRayCallback nearest_to_ray_callback;
struct BMEditMesh *em;
@@ -75,7 +74,6 @@ typedef struct BVHTreeFromMesh {
/* default callbacks to bvh nearest and raycast */
BVHTree_NearestPointCallback nearest_callback;
BVHTree_RayCastCallback raycast_callback;
- BVHTree_NearestToRayCallback nearest_to_ray_callback;
/* Vertex array, so that callbacks have instante access to data */
const struct MVert *vert;
@@ -104,7 +102,7 @@ typedef struct BVHTreeFromMesh {
* The tree is build in mesh space coordinates, this means special care must be made on queries
* so that the coordinates and rays are first translated on the mesh local coordinates.
* Reason for this is that bvh_from_mesh_* can use a cache in some cases and so it becomes possible to reuse a BVHTree.
- *
+ *
* free_bvhtree_from_mesh should be called when the tree is no longer needed.
*/
BVHTree *bvhtree_from_editmesh_verts(
@@ -118,7 +116,7 @@ BVHTree *bvhtree_from_editmesh_verts_ex(
BVHTree *bvhtree_from_mesh_verts(
struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis);
BVHTree *bvhtree_from_mesh_verts_ex(
- struct BVHTreeFromMesh *data, struct MVert *vert, const int numVerts,
+ struct BVHTreeFromMesh *data, const struct MVert *vert, const int numVerts,
const bool vert_allocated, const BLI_bitmap *mask, int verts_num_active,
float epsilon, int tree_type, int axis);
@@ -133,14 +131,20 @@ BVHTree *bvhtree_from_editmesh_edges_ex(
BVHTree *bvhtree_from_mesh_edges(
struct BVHTreeFromMesh *data, struct DerivedMesh *mesh,
float epsilon, int tree_type, int axis);
+BVHTree *bvhtree_from_mesh_edges_ex(
+ struct BVHTreeFromMesh *data,
+ const struct MVert *vert, const bool vert_allocated,
+ const struct MEdge *edge, const int edges_num, const bool edge_allocated,
+ const BLI_bitmap *edges_mask, int edges_num_active,
+ float epsilon, int tree_type, int axis);
BVHTree *bvhtree_from_mesh_faces(
struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon,
int tree_type, int axis);
BVHTree *bvhtree_from_mesh_faces_ex(
struct BVHTreeFromMesh *data,
- struct MVert *vert, const bool vert_allocated,
- struct MFace *face, const int numFaces, const bool face_allocated,
+ const struct MVert *vert, const bool vert_allocated,
+ const struct MFace *face, const int numFaces, const bool face_allocated,
const BLI_bitmap *mask, int numFaces_active,
float epsilon, int tree_type, int axis);
diff --git a/source/blender/blenkernel/BKE_cachefile.h b/source/blender/blenkernel/BKE_cachefile.h
index 51b161f1a06..db8ddb2ba68 100644
--- a/source/blender/blenkernel/BKE_cachefile.h
+++ b/source/blender/blenkernel/BKE_cachefile.h
@@ -38,13 +38,16 @@ struct CacheFile;
struct Main;
struct Scene;
+void BKE_cachefiles_init(void);
+void BKE_cachefiles_exit(void);
+
void *BKE_cachefile_add(struct Main *bmain, const char *name);
void BKE_cachefile_init(struct CacheFile *cache_file);
void BKE_cachefile_free(struct CacheFile *cache_file);
-struct CacheFile *BKE_cachefile_copy(struct Main *bmain, struct CacheFile *cache_file);
+struct CacheFile *BKE_cachefile_copy(struct Main *bmain, const struct CacheFile *cache_file);
void BKE_cachefile_make_local(struct Main *bmain, struct CacheFile *cache_file, const bool lib_local);
@@ -52,7 +55,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, float ctime, const float fps);
+void BKE_cachefile_update_frame(struct Main *bmain, 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,
@@ -60,6 +63,8 @@ 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 Main *bmain, struct CacheFile *cache_file);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h
index 31a732cf7e5..22165212ed8 100644
--- a/source/blender/blenkernel/BKE_camera.h
+++ b/source/blender/blenkernel/BKE_camera.h
@@ -44,6 +44,7 @@ struct Object;
struct RegionView3D;
struct RenderData;
struct Scene;
+struct SceneLayer;
struct rctf;
struct View3D;
struct GPUFXSettings;
@@ -52,7 +53,7 @@ struct GPUFXSettings;
void BKE_camera_init(struct Camera *cam);
void *BKE_camera_add(struct Main *bmain, const char *name);
-struct Camera *BKE_camera_copy(struct Main *bmain, struct Camera *cam);
+struct Camera *BKE_camera_copy(struct Main *bmain, const struct Camera *cam);
void BKE_camera_make_local(struct Main *bmain, struct Camera *cam, const bool lib_local);
void BKE_camera_free(struct Camera *ca);
@@ -127,7 +128,7 @@ void BKE_camera_view_frame(
float r_vec[4][3]);
bool BKE_camera_view_frame_fit_to_scene(
- struct Scene *scene, struct View3D *v3d, struct Object *camera_ob,
+ struct Scene *scene, struct SceneLayer *sl, struct Object *camera_ob,
float r_co[3], float *r_scale);
bool BKE_camera_view_frame_fit_to_coords(
const struct Scene *scene,
diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h b/source/blender/blenkernel/BKE_cdderivedmesh.h
index 9948f21ba90..4876461bfe0 100644
--- a/source/blender/blenkernel/BKE_cdderivedmesh.h
+++ b/source/blender/blenkernel/BKE_cdderivedmesh.h
@@ -79,6 +79,7 @@ DerivedMesh *CDDM_from_curve_displist(struct Object *ob, struct ListBase *dispba
*/
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.
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h
index 36330242f18..6c517bd02df 100644
--- a/source/blender/blenkernel/BKE_cloth.h
+++ b/source/blender/blenkernel/BKE_cloth.h
@@ -136,9 +136,6 @@ typedef struct ClothSpring {
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 dfdx[3][3];
- float dfdv[3][3];
- float f[3];
float stiffness; /* stiffness factor from the vertex groups */
float editrestlen;
@@ -240,9 +237,6 @@ void bvhselftree_update_from_cloth(struct ClothModifierData *clmd, bool moving);
// needed for button_object.c
void cloth_clear_cache (struct Object *ob, struct ClothModifierData *clmd, float framenr );
-// needed for cloth.c
-int cloth_add_spring (struct ClothModifierData *clmd, unsigned int indexA, unsigned int indexB, float restlength, int spring_type);
-
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..0adac4500f8
--- /dev/null
+++ b/source/blender/blenkernel/BKE_collection.h
@@ -0,0 +1,100 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_ghash.h"
+#include "BLI_iterator.h"
+#include "DNA_listBase.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct BLI_Iterator;
+struct SceneCollection;
+struct Object;
+struct Base;
+struct Main;
+struct Scene;
+
+struct SceneCollection *BKE_collection_add(struct Scene *scene, struct SceneCollection *sc_parent, const char *name);
+bool BKE_collection_remove(struct Scene *scene, struct SceneCollection *sc);
+struct SceneCollection *BKE_collection_master(const struct Scene *scene);
+void BKE_collection_rename(const struct Scene *scene, struct SceneCollection *sc, const char *name);
+void BKE_collection_master_free(struct Scene *scene, const bool do_id_user);
+void BKE_collection_object_add(const struct Scene *scene, struct SceneCollection *sc, struct Object *object);
+void BKE_collection_object_add_from(struct Scene *scene, struct Object *ob_src, struct Object *ob_dst);
+void BKE_collection_object_remove(struct Main *bmain, const struct Scene *scene, struct SceneCollection *sc, struct Object *object, const bool free_us);
+void BKE_collections_object_remove(struct Main *bmain, struct Scene *scene, struct Object *object, const bool free_us);
+void BKE_collection_object_move(const struct Scene *scene, struct SceneCollection *sc_dst, struct SceneCollection *sc_src, struct Object *ob);
+
+void BKE_collection_reinsert_after(const struct Scene *scene, struct SceneCollection *sc_reinsert, struct SceneCollection *sc_after);
+void BKE_collection_reinsert_into(struct SceneCollection *sc_reinsert, struct SceneCollection *sc_into);
+
+bool BKE_collection_move_above(const struct Scene *scene, struct SceneCollection *sc_dst, struct SceneCollection *sc_src);
+bool BKE_collection_move_below(const struct Scene *scene, struct SceneCollection *sc_dst, struct SceneCollection *sc_src);
+bool BKE_collection_move_into(const struct Scene *scene, struct SceneCollection *sc_dst, struct SceneCollection *sc_src);
+
+typedef void (*BKE_scene_objects_Cb)(struct Object *ob, void *data);
+typedef void (*BKE_scene_collections_Cb)(struct SceneCollection *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);
+
+/* iterators */
+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(scene, _instance) \
+ ITER_BEGIN(BKE_scene_collections_iterator_begin, \
+ BKE_scene_collections_iterator_next, \
+ BKE_scene_collections_iterator_end, \
+ scene, SceneCollection *, _instance)
+
+#define FOREACH_SCENE_COLLECTION_END \
+ ITER_END
+
+#define FOREACH_SCENE_OBJECT(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 d5b4a584ec6..0bf7f657f70 100644
--- a/source/blender/blenkernel/BKE_collision.h
+++ b/source/blender/blenkernel/BKE_collision.h
@@ -146,6 +146,10 @@ void collision_get_collider_velocity(float vel_old[3], float vel_new[3], struct
/////////////////////////////////////////////////
// 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, unsigned int *numcollobj, unsigned int modifier_type, bool dupli);
+
struct Object **get_collisionobjects(struct Scene *scene, struct Object *self, struct Group *group, unsigned int *numcollobj, unsigned int modifier_type);
typedef struct ColliderCache {
diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h
index 5b4f5910821..f68c4a2757b 100644
--- a/source/blender/blenkernel/BKE_colortools.h
+++ b/source/blender/blenkernel/BKE_colortools.h
@@ -46,8 +46,8 @@ void curvemapping_set_defaults(struct CurveMapping *cumap, int to
struct CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, float maxy);
void curvemapping_free_data(struct CurveMapping *cumap);
void curvemapping_free(struct CurveMapping *cumap);
-void curvemapping_copy_data(struct CurveMapping *target, struct CurveMapping *cumap);
-struct CurveMapping *curvemapping_copy(struct CurveMapping *cumap);
+void curvemapping_copy_data(struct CurveMapping *target, const struct CurveMapping *cumap);
+struct CurveMapping *curvemapping_copy(const struct CurveMapping *cumap);
void curvemapping_set_black_white_ex(const float black[3], const float white[3], float r_bwmul[3]);
void curvemapping_set_black_white(struct CurveMapping *cumap, const float black[3], const float white[3]);
diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h
index f3cfb901154..047d1787f76 100644
--- a/source/blender/blenkernel/BKE_constraint.h
+++ b/source/blender/blenkernel/BKE_constraint.h
@@ -120,7 +120,6 @@ void BKE_constraint_unique_name(struct bConstraint *con, struct ListBase *list);
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);
-void BKE_constraints_relink(struct ListBase *list);
void BKE_constraints_id_loop(struct ListBase *list, ConstraintIDFunc func, void *userdata);
void BKE_constraint_free_data(struct bConstraint *con);
void BKE_constraint_free_data_ex(struct bConstraint *con, bool do_id_user);
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index bcc0c58c44e..63e83aaa967 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -40,12 +40,17 @@ extern "C" {
struct ARegion;
struct bScreen;
struct CacheFile;
+struct Depsgraph;
+struct LayerCollection;
struct ListBase;
struct Main;
struct Object;
+struct Base;
struct PointerRNA;
struct ReportList;
struct Scene;
+struct SceneCollection;
+struct SceneLayer;
struct ScrArea;
struct SpaceLink;
struct View3D;
@@ -141,6 +146,7 @@ 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);
@@ -240,9 +246,13 @@ 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 SceneCollection *CTX_data_scene_collection(const bContext *C);
+struct SceneLayer *CTX_data_scene_layer(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);
int CTX_data_mode_enum(const bContext *C);
void CTX_data_main_set(bContext *C, struct Main *bmain);
@@ -297,6 +307,7 @@ 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);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 5558786d254..5a65646efe0 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 GHash;
struct ListBase;
struct Main;
struct Nurb;
@@ -52,6 +53,13 @@ typedef struct CurveCache {
struct Path *path;
} CurveCache;
+/* Definitions needed for shape keys */
+typedef struct CVKeyIndex {
+ void *orig_cv;
+ int key_index, nu_index, pt_index, vertex_index;
+ bool switched;
+} CVKeyIndex;
+
#define KNOTSU(nu) ( (nu)->orderu + (nu)->pntsu + (((nu)->flagu & CU_NURB_CYCLIC) ? ((nu)->orderu - 1) : 0) )
#define KNOTSV(nu) ( (nu)->orderv + (nu)->pntsv + (((nu)->flagv & CU_NURB_CYCLIC) ? ((nu)->orderv - 1) : 0) )
@@ -70,7 +78,7 @@ void BKE_curve_free(struct Curve *cu);
void BKE_curve_editfont_free(struct Curve *cu);
void BKE_curve_init(struct Curve *cu);
struct Curve *BKE_curve_add(struct Main *bmain, const char *name, int type);
-struct Curve *BKE_curve_copy(struct Main *bmain, struct Curve *cu);
+struct Curve *BKE_curve_copy(struct Main *bmain, const struct Curve *cu);
void BKE_curve_make_local(struct Main *bmain, struct Curve *cu, const bool lib_local);
short BKE_curve_type_get(struct Curve *cu);
void BKE_curve_type_test(struct Object *ob);
@@ -108,7 +116,8 @@ void BK_curve_nurbs_vertexCos_apply(struct ListBase *lb, float (*vertexCos)[3]);
float (*BKE_curve_nurbs_keyVertexCos_get(struct ListBase *lb, float *key))[3];
void BKE_curve_nurbs_keyVertexTilts_apply(struct ListBase *lb, float *key);
-void BKE_curve_editNurb_keyIndex_free(struct EditNurb *editnurb);
+void BKE_curve_editNurb_keyIndex_delCV(struct GHash *keyindex, const void *cv);
+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);
@@ -133,7 +142,7 @@ int BKE_nurbList_verts_count(struct ListBase *nurb);
int BKE_nurbList_verts_count_without_handles(struct ListBase *nurb);
void BKE_nurbList_free(struct ListBase *lb);
-void BKE_nurbList_duplicate(struct ListBase *lb1, struct ListBase *lb2);
+void BKE_nurbList_duplicate(struct ListBase *lb1, const struct ListBase *lb2);
void BKE_nurbList_handles_set(struct ListBase *editnurb, const char code);
void BKE_nurbList_handles_recalculate(struct ListBase *editnurb, const bool calc_length, const char flag);
@@ -141,7 +150,7 @@ void BKE_nurbList_handles_autocalc(ListBase *editnurb, int flag);
void BKE_nurbList_flag_set(ListBase *editnurb, short flag);
void BKE_nurb_free(struct Nurb *nu);
-struct Nurb *BKE_nurb_duplicate(struct Nurb *nu);
+struct Nurb *BKE_nurb_duplicate(const struct Nurb *nu);
struct Nurb *BKE_nurb_copy(struct Nurb *src, int pntsu, int pntsv);
void BKE_nurb_test2D(struct Nurb *nu);
@@ -189,6 +198,7 @@ void BKE_nurb_bezt_calc_normal(struct Nurb *nu, struct BezTriple *bezt, float r_
void BKE_nurb_bezt_calc_plane(struct Nurb *nu, struct BezTriple *bezt, float r_plane[3]);
void BKE_nurb_bpoint_calc_normal(struct Nurb *nu, struct BPoint *bp, float r_normal[3]);
+void BKE_nurb_bpoint_calc_plane(struct Nurb *nu, struct BPoint *bp, float r_plane[3]);
void BKE_nurb_handle_calc(struct BezTriple *bezt, struct BezTriple *prev, struct BezTriple *next,
const bool is_fcurve);
@@ -210,4 +220,12 @@ void BKE_curve_eval_geometry(struct EvaluationContext *eval_ctx,
void BKE_curve_eval_path(struct EvaluationContext *eval_ctx,
struct Curve *curve);
+/* Draw Cache */
+enum {
+ BKE_CURVE_BATCH_DIRTY_ALL = 0,
+ BKE_CURVE_BATCH_DIRTY_SELECT,
+};
+void BKE_curve_batch_cache_dirty(struct Curve *cu, int mode);
+void BKE_curve_batch_cache_free(struct Curve *cu);
+
#endif /* __BKE_CURVE_H__ */
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 61c000625a1..cc5927e072e 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -379,15 +379,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_deform.h b/source/blender/blenkernel/BKE_deform.h
index 8756f73df72..a20c5a4240c 100644
--- a/source/blender/blenkernel/BKE_deform.h
+++ b/source/blender/blenkernel/BKE_deform.h
@@ -44,8 +44,8 @@ struct MLoop;
struct MPoly;
struct bDeformGroup *BKE_defgroup_new(struct Object *ob, const char *name);
-void defgroup_copy_list(struct ListBase *lb1, struct ListBase *lb2);
-struct bDeformGroup *defgroup_duplicate(struct bDeformGroup *ingroup);
+void defgroup_copy_list(struct ListBase *lb1, const struct ListBase *lb2);
+struct bDeformGroup *defgroup_duplicate(const struct bDeformGroup *ingroup);
struct bDeformGroup *defgroup_find_name(struct Object *ob, const char *name);
int *defgroup_flip_map(struct Object *ob, int *flip_map_len, const bool use_default);
int *defgroup_flip_map_single(struct Object *ob, int *flip_map_len, const bool use_default, int defgroup);
@@ -116,13 +116,4 @@ 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);
-/* utility function, note that MAX_VGROUP_NAME chars is the maximum string length since its only
- * used with defgroups currently */
-
-void BKE_deform_split_suffix(const char string[MAX_VGROUP_NAME], char base[MAX_VGROUP_NAME], char ext[MAX_VGROUP_NAME]);
-void BKE_deform_split_prefix(const char string[MAX_VGROUP_NAME], char base[MAX_VGROUP_NAME], char ext[MAX_VGROUP_NAME]);
-
-void BKE_deform_flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[MAX_VGROUP_NAME],
- const bool strip_number);
-
#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 40564aeabe9..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_dynamicpaint.h b/source/blender/blenkernel/BKE_dynamicpaint.h
index 5abb53d4c52..b22f5fa7630 100644
--- a/source/blender/blenkernel/BKE_dynamicpaint.h
+++ b/source/blender/blenkernel/BKE_dynamicpaint.h
@@ -28,6 +28,7 @@
*/
struct Scene;
+struct SceneLayer;
/* Actual surface point */
typedef struct PaintSurfaceData {
@@ -60,7 +61,8 @@ typedef struct PaintWavePoint {
short state;
} PaintWavePoint;
-struct DerivedMesh *dynamicPaint_Modifier_do(struct DynamicPaintModifierData *pmd, struct Scene *scene, struct Object *ob, struct DerivedMesh *dm);
+struct DerivedMesh *dynamicPaint_Modifier_do(struct DynamicPaintModifierData *pmd, struct Scene *scene,
+ struct SceneLayer *sl, struct Object *ob, struct DerivedMesh *dm);
void dynamicPaint_Modifier_free(struct DynamicPaintModifierData *pmd);
void dynamicPaint_Modifier_copy(struct DynamicPaintModifierData *pmd, struct DynamicPaintModifierData *tsmd);
@@ -83,7 +85,7 @@ 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 DynamicPaintSurface *surface, struct Scene *scene, struct Object *cObject, int frame);
+int dynamicPaint_calculateFrame(struct DynamicPaintSurface *surface, struct Scene *scene, struct SceneLayer *sl, 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 55a9db9b1e5..9ee1bcf2d37 100644
--- a/source/blender/blenkernel/BKE_editmesh.h
+++ b/source/blender/blenkernel/BKE_editmesh.h
@@ -88,7 +88,6 @@ 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);
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 f8fee444d91..aa45132cbe9 100644
--- a/source/blender/blenkernel/BKE_effect.h
+++ b/source/blender/blenkernel/BKE_effect.h
@@ -110,7 +110,7 @@ typedef struct EffectorCache {
} 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 precalc);
+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);
@@ -172,6 +172,7 @@ typedef struct SimDebugElement {
float color[3];
float v1[3], v2[3];
+ char str[64];
} SimDebugElement;
typedef enum eSimDebugElement_Type {
@@ -179,6 +180,7 @@ typedef enum eSimDebugElement_Type {
SIM_DEBUG_ELEM_CIRCLE,
SIM_DEBUG_ELEM_LINE,
SIM_DEBUG_ELEM_VECTOR,
+ SIM_DEBUG_ELEM_STRING,
} eSimDebugElement_Type;
typedef struct SimDebugData {
@@ -191,26 +193,30 @@ void BKE_sim_debug_data_set_enabled(bool enable);
bool BKE_sim_debug_data_get_enabled(void);
void BKE_sim_debug_data_free(void);
-void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[3],
+void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[3], const char *str,
float r, float g, float b, const char *category, unsigned int hash);
void BKE_sim_debug_data_remove_element(unsigned int hash);
#define BKE_sim_debug_data_add_dot(p, r, g, b, category, ...) { \
const float v2[3] = { 0.0f, 0.0f, 0.0f }; \
- BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_DOT, p, v2, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \
+ BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_DOT, p, v2, NULL, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \
}
#define BKE_sim_debug_data_add_circle(p, radius, r, g, b, category, ...) { \
const float v2[3] = { radius, 0.0f, 0.0f }; \
- BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_CIRCLE, p, v2, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \
+ BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_CIRCLE, p, v2, NULL, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \
}
#define BKE_sim_debug_data_add_line(p1, p2, r, g, b, category, ...) { \
- BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_LINE, p1, p2, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \
+ BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_LINE, p1, p2, NULL, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \
}
#define BKE_sim_debug_data_add_vector(p, d, r, g, b, category, ...) { \
- BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_VECTOR, p, d, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \
+ BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_VECTOR, p, d, NULL, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \
+}
+
+#define BKE_sim_debug_data_add_string(p, str, r, g, b, category, ...) { \
+ BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_STRING, p, NULL, str, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \
}
#define BKE_sim_debug_data_remove(...) \
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index 3a45097efc5..b38f1299763 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -92,7 +92,7 @@ void bezt_add_to_cfra_elem(ListBase *lb, struct BezTriple *bezt);
/* ---------------------- */
void fcurve_free_driver(struct FCurve *fcu);
-struct ChannelDriver *fcurve_copy_driver(struct ChannelDriver *driver);
+struct ChannelDriver *fcurve_copy_driver(const struct ChannelDriver *driver);
void driver_variables_copy(struct ListBase *dst_list, const struct ListBase *src_list);
@@ -138,7 +138,7 @@ typedef struct FModifierTypeInfo {
/* free any data that is allocated separately (optional) */
void (*free_data)(struct FModifier *fcm);
/* copy any special data that is allocated separately (optional) */
- void (*copy_data)(struct FModifier *fcm, struct FModifier *src);
+ void (*copy_data)(struct FModifier *fcm, const struct FModifier *src);
/* set settings for data that will be used for FCuModifier.data (memory already allocated using MEM_callocN) */
void (*new_data)(void *mdata);
/* verifies that the modifier settings are valid */
@@ -183,14 +183,14 @@ typedef enum eFMI_Requirement_Flags {
} eFMI_Requirement_Flags;
/* Function Prototypes for FModifierTypeInfo's */
-const FModifierTypeInfo *fmodifier_get_typeinfo(struct FModifier *fcm);
-const FModifierTypeInfo *get_fmodifier_typeinfo(int type);
+const FModifierTypeInfo *fmodifier_get_typeinfo(const struct FModifier *fcm);
+const FModifierTypeInfo *get_fmodifier_typeinfo(const int type);
/* ---------------------- */
struct FModifier *add_fmodifier(ListBase *modifiers, int type);
-struct FModifier *copy_fmodifier(struct FModifier *src);
-void copy_fmodifiers(ListBase *dst, ListBase *src);
+struct FModifier *copy_fmodifier(const struct FModifier *src);
+void copy_fmodifiers(ListBase *dst, const ListBase *src);
bool remove_fmodifier(ListBase *modifiers, struct FModifier *fcm);
void free_fmodifiers(ListBase *modifiers);
@@ -216,7 +216,7 @@ int BKE_fcm_envelope_find_index(struct FCM_EnvelopeData *array, float frame, int
/* -------- Data Management -------- */
void free_fcurve(struct FCurve *fcu);
-struct FCurve *copy_fcurve(struct FCurve *fcu);
+struct FCurve *copy_fcurve(const struct FCurve *fcu);
void free_fcurves(ListBase *list);
void copy_fcurves(ListBase *dst, ListBase *src);
diff --git a/source/blender/blenkernel/BKE_font.h b/source/blender/blenkernel/BKE_font.h
index 6775639125f..e7ae0f606e7 100644
--- a/source/blender/blenkernel/BKE_font.h
+++ b/source/blender/blenkernel/BKE_font.h
@@ -60,8 +60,9 @@ typedef struct EditFont {
struct CharInfo *textbufinfo;
/* array of rectangles & rotation */
- EditFontSelBox *selboxes;
float textcurs[4][2];
+ EditFontSelBox *selboxes;
+ int selboxes_len;
/* positional vars relative to the textbuf, textbufinfo (not utf8 bytes)
* a copy of these is kept in Curve, but use these in editmode */
diff --git a/source/blender/blenkernel/BKE_freestyle.h b/source/blender/blenkernel/BKE_freestyle.h
index e10594634f0..50407f3bdfc 100644
--- a/source/blender/blenkernel/BKE_freestyle.h
+++ b/source/blender/blenkernel/BKE_freestyle.h
@@ -55,8 +55,7 @@ void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *con
/* FreestyleConfig.modules */
FreestyleModuleConfig *BKE_freestyle_module_add(FreestyleConfig *config);
bool BKE_freestyle_module_delete(FreestyleConfig *config, FreestyleModuleConfig *module_conf);
-bool BKE_freestyle_module_move_up(FreestyleConfig *config, FreestyleModuleConfig *module_conf);
-bool BKE_freestyle_module_move_down(FreestyleConfig *config, FreestyleModuleConfig *module_conf);
+bool BKE_freestyle_module_move(FreestyleConfig *config, FreestyleModuleConfig *module_conf, int direction);
/* FreestyleConfig.linesets */
FreestyleLineSet *BKE_freestyle_lineset_add(struct Main *bmain, FreestyleConfig *config, const char *name);
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index 5ef5a807f63..830518906ab 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -129,10 +129,11 @@ enum {
G_DEBUG_GPU_MEM = (1 << 10), /* gpu memory in status bar */
G_DEBUG_DEPSGRAPH_NO_THREADS = (1 << 11), /* single threaded depsgraph */
G_DEBUG_GPU = (1 << 12), /* gpu debug */
+ G_DEBUG_IO = (1 << 13), /* IO Debugging (for Collada, ...)*/
};
#define G_DEBUG_ALL (G_DEBUG | G_DEBUG_FFMPEG | G_DEBUG_PYTHON | G_DEBUG_EVENTS | G_DEBUG_WM | G_DEBUG_JOBS | \
- G_DEBUG_FREESTYLE | G_DEBUG_DEPSGRAPH | G_DEBUG_GPU_MEM)
+ G_DEBUG_FREESTYLE | G_DEBUG_DEPSGRAPH | G_DEBUG_GPU_MEM | G_DEBUG_IO)
/* G.fileflags */
@@ -188,11 +189,6 @@ enum {
# error Either __BIG_ENDIAN__ or __LITTLE_ENDIAN__ must be defined.
#endif
-/* there is really no good place for this */
-#if defined(FREE_WINDOWS) && ((__GNUC__ < 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ < 6)))
-# error "Mingw requires GCC 4.6 minimum"
-#endif
-
#define L_ENDIAN 1
#define B_ENDIAN 0
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index ab8b83f8271..bdd28baf137 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -60,7 +60,7 @@ struct bGPdata *BKE_gpencil_data_addnew(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);
-struct bGPdata *BKE_gpencil_data_duplicate(struct Main *bmain, struct bGPdata *gpd, bool internal_copy);
+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);
@@ -104,7 +104,7 @@ void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl);
struct bGPDbrush *BKE_gpencil_brush_getactive(struct ToolSettings *ts);
void BKE_gpencil_brush_setactive(struct ToolSettings *ts, struct bGPDbrush *active);
-void BKE_gpencil_brush_delete(struct ToolSettings *ts, struct bGPDbrush *palette);
+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);
diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h
index 09a069ee36f..4555bbf076d 100644
--- a/source/blender/blenkernel/BKE_group.h
+++ b/source/blender/blenkernel/BKE_group.h
@@ -33,6 +33,7 @@
* \author nzc
*/
+struct BaseLegacy;
struct Base;
struct EvaluationContext;
struct Group;
@@ -42,10 +43,10 @@ struct Scene;
void BKE_group_free(struct Group *group);
struct Group *BKE_group_add(struct Main *bmain, const char *name);
-struct Group *BKE_group_copy(struct Main *bmain, struct Group *group);
+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 Group *group, struct Object *ob, struct Scene *scene, struct Base *base);
+bool BKE_group_object_add(struct Group *group, struct Object *ob);
+bool BKE_group_object_unlink(struct Group *group, struct Object *ob);
struct Group *BKE_group_object_find(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);
diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h
index efef8d4be78..39e6b145755 100644
--- a/source/blender/blenkernel/BKE_icons.h
+++ b/source/blender/blenkernel/BKE_icons.h
@@ -88,7 +88,7 @@ void BKE_previewimg_clear(struct PreviewImage *prv);
void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size);
/* get the preview from any pointer */
-struct PreviewImage **BKE_previewimg_id_get_p(struct ID *id);
+struct PreviewImage **BKE_previewimg_id_get_p(const struct ID *id);
/* free the preview image belonging to the id */
void BKE_previewimg_id_free(struct ID *id);
@@ -97,9 +97,9 @@ void BKE_previewimg_id_free(struct ID *id);
struct PreviewImage *BKE_previewimg_create(void);
/* create a copy of the preview image */
-struct PreviewImage *BKE_previewimg_copy(struct PreviewImage *prv);
+struct PreviewImage *BKE_previewimg_copy(const struct PreviewImage *prv);
-void BKE_previewimg_id_copy(struct ID *new_id, struct ID *old_id);
+void BKE_previewimg_id_copy(struct ID *new_id, const struct ID *old_id);
/* retrieve existing or create new preview image */
struct PreviewImage *BKE_previewimg_id_ensure(struct ID *id);
@@ -114,6 +114,7 @@ struct PreviewImage *BKE_previewimg_cached_thumbnail_read(
const char *name, const char *path, const int source, bool force_update);
void BKE_previewimg_cached_release(const char *name);
+void BKE_previewimg_cached_release_pointer(struct PreviewImage *prv);
#define ICON_RENDER_DEFAULT_HEIGHT 32
diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h
index 5b10d7ebc06..ab8728faedb 100644
--- a/source/blender/blenkernel/BKE_idprop.h
+++ b/source/blender/blenkernel/BKE_idprop.h
@@ -60,8 +60,6 @@ typedef union IDPropertyTemplate {
IDProperty *IDP_NewIDPArray(const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
IDProperty *IDP_CopyIDPArray(const IDProperty *array) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-void IDP_FreeIDPArray(IDProperty *prop);
-
/* shallow copies item */
void IDP_SetIndexArray(struct IDProperty *prop, int index, struct IDProperty *item) ATTR_NONNULL();
struct IDProperty *IDP_GetIndexArray(struct IDProperty *prop, int index) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -81,8 +79,8 @@ void IDP_ConcatString(struct IDProperty *str1, struct IDProperty *append) ATTR_N
void IDP_FreeString(struct IDProperty *prop) ATTR_NONNULL();
/*-------- ID Type -------*/
-void IDP_LinkID(struct IDProperty *prop, ID *id);
-void IDP_UnlinkID(struct IDProperty *prop);
+
+typedef void(*IDPWalkFunc)(void *userData, IDProperty *idp);
/*-------- Group Functions -------*/
@@ -112,11 +110,12 @@ bool IDP_EqualsProperties(struct IDProperty *prop1, struct IDProperty *prop2) AT
struct IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void IDP_FreeProperty_ex(struct IDProperty *prop, const bool do_id_user);
void IDP_FreeProperty(struct IDProperty *prop);
void IDP_ClearProperty(IDProperty *prop);
-void IDP_UnlinkProperty(struct IDProperty *prop);
+void IDP_RelinkProperty(struct IDProperty *prop);
#define IDP_Int(prop) ((prop)->data.val)
#define IDP_Array(prop) ((prop)->data.pointer)
@@ -134,11 +133,15 @@ void IDP_UnlinkProperty(struct IDProperty *prop);
# define IDP_IDPArray(prop) _Generic((prop), \
IDProperty *: ((IDProperty *) (prop)->data.pointer), \
const IDProperty *: ((const IDProperty *) (prop)->data.pointer))
+# define IDP_Id(prop) _Generic((prop), \
+ IDProperty *: ((ID *) (prop)->data.pointer), \
+ const IDProperty *: ((const ID *) (prop)->data.pointer))
#else
# define IDP_Float(prop) (*(float *)&(prop)->data.val)
# define IDP_Double(prop) (*(double *)&(prop)->data.val)
# define IDP_String(prop) ((char *) (prop)->data.pointer)
# define IDP_IDPArray(prop) ((IDProperty *) (prop)->data.pointer)
+# define IDP_Id(prop) ((ID *) (prop)->data.pointer)
#endif
#ifndef NDEBUG
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index 132c73209d1..e155b0719cc 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -250,7 +250,7 @@ void BKE_image_packfiles_from_mem(struct ReportList *reports, struct Image *ima,
void BKE_image_print_memlist(void);
/* empty image block, of similar type and filename */
-struct Image *BKE_image_copy(struct Main *bmain, struct Image *ima);
+struct Image *BKE_image_copy(struct Main *bmain, const struct Image *ima);
/* merge source into dest, and free source */
void BKE_image_merge(struct Image *dest, struct Image *source);
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index e590ff148d7..94e8a24fbc5 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -51,7 +51,7 @@ extern "C" {
void BKE_key_free(struct Key *sc);
void BKE_key_free_nolib(struct Key *key);
struct Key *BKE_key_add(struct ID *id);
-struct Key *BKE_key_copy(struct Main *bmain, struct Key *key);
+struct Key *BKE_key_copy(struct Main *bmain, const struct Key *key);
struct Key *BKE_key_copy_nolib(struct Key *key);
void BKE_key_sort(struct Key *key);
diff --git a/source/blender/blenkernel/BKE_lamp.h b/source/blender/blenkernel/BKE_lamp.h
index 4d53850c572..713ca80fb1a 100644
--- a/source/blender/blenkernel/BKE_lamp.h
+++ b/source/blender/blenkernel/BKE_lamp.h
@@ -44,7 +44,7 @@ struct Scene;
void BKE_lamp_init(struct Lamp *la);
struct Lamp *BKE_lamp_add(struct Main *bmain, const char *name) ATTR_WARN_UNUSED_RESULT;
-struct Lamp *BKE_lamp_copy(struct Main *bmain, struct Lamp *la) ATTR_WARN_UNUSED_RESULT;
+struct Lamp *BKE_lamp_copy(struct Main *bmain, const struct Lamp *la) ATTR_WARN_UNUSED_RESULT;
struct Lamp *localize_lamp(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);
diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h
index 226c82da295..3c66d29e6ac 100644
--- a/source/blender/blenkernel/BKE_lattice.h
+++ b/source/blender/blenkernel/BKE_lattice.h
@@ -47,7 +47,7 @@ struct MDeformVert;
void BKE_lattice_resize(struct Lattice *lt, int u, int v, int w, struct Object *ltOb);
void BKE_lattice_init(struct Lattice *lt);
struct Lattice *BKE_lattice_add(struct Main *bmain, const char *name);
-struct Lattice *BKE_lattice_copy(struct Main *bmain, struct Lattice *lt);
+struct Lattice *BKE_lattice_copy(struct Main *bmain, const struct Lattice *lt);
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);
@@ -103,4 +103,12 @@ struct EvaluationContext;
void BKE_lattice_eval_geometry(struct EvaluationContext *eval_ctx,
struct Lattice *latt);
+/* Draw Cache */
+enum {
+ BKE_LATTICE_BATCH_DIRTY_ALL = 0,
+ BKE_LATTICE_BATCH_DIRTY_SELECT,
+};
+void BKE_lattice_batch_cache_dirty(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..2e3ff12de13
--- /dev/null
+++ b/source/blender/blenkernel/BKE_layer.h
@@ -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.
+ *
+ * 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"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TODO_LAYER_SYNC /* syncing of SceneCollection and LayerCollection trees*/
+#define TODO_LAYER_SYNC_FILTER /* syncing of filter_objects across all trees */
+#define TODO_LAYER_OVERRIDE /* CollectionOverride */
+#define TODO_LAYER_CONTEXT /* get/set current (context) SceneLayer */
+#define TODO_LAYER_BASE /* BaseLegacy to Base related TODO */
+#define TODO_LAYER_OPERATORS /* collection mamanger and property panel operators */
+#define TODO_LAYER_DEPSGRAPH /* placeholder for real Depsgraph fix */
+#define TODO_LAYER /* generic todo */
+
+#define ROOT_PROP "root"
+
+struct EvaluationContext;
+struct LayerCollection;
+struct ID;
+struct IDProperty;
+struct ListBase;
+struct Main;
+struct Object;
+struct Base;
+struct RenderEngine;
+struct Scene;
+struct SceneCollection;
+struct SceneLayer;
+struct WorkSpace;
+
+void BKE_layer_exit(void);
+
+struct SceneLayer *BKE_scene_layer_from_scene_get(const struct Scene *scene);
+struct SceneLayer *BKE_scene_layer_from_workspace_get(const struct WorkSpace *workspace);
+struct SceneLayer *BKE_scene_layer_add(struct Scene *scene, const char *name);
+
+/* DEPRECATED */
+struct SceneLayer *BKE_scene_layer_context_active_ex_PLACEHOLDER(const struct Main *bmain, const struct Scene *scene);
+/* DEPRECATED */
+struct SceneLayer *BKE_scene_layer_context_active_PLACEHOLDER(const struct Scene *scene);
+
+void BKE_scene_layer_free(struct SceneLayer *sl);
+
+void BKE_scene_layer_engine_set(struct SceneLayer *sl, const char *engine);
+
+void BKE_scene_layer_selected_objects_tag(struct SceneLayer *sl, const int tag);
+
+struct SceneLayer *BKE_scene_layer_find_from_collection(const struct Scene *scene, struct LayerCollection *lc);
+struct Base *BKE_scene_layer_base_find(struct SceneLayer *sl, struct Object *ob);
+void BKE_scene_layer_base_deselect_all(struct SceneLayer *sl);
+void BKE_scene_layer_base_select(struct SceneLayer *sl, struct Base *selbase);
+
+void BKE_layer_collection_free(struct SceneLayer *sl, struct LayerCollection *lc);
+
+struct LayerCollection *BKE_layer_collection_get_active(struct SceneLayer *sl);
+struct LayerCollection *BKE_layer_collection_get_active_ensure(struct Scene *scene, struct SceneLayer *sl);
+
+int BKE_layer_collection_count(struct SceneLayer *sl);
+
+int BKE_layer_collection_findindex(struct SceneLayer *sl, const struct LayerCollection *lc);
+
+bool BKE_layer_collection_move_above(const struct Scene *scene, struct LayerCollection *lc_dst, struct LayerCollection *lc_src);
+bool BKE_layer_collection_move_below(const struct Scene *scene, struct LayerCollection *lc_dst, struct LayerCollection *lc_src);
+bool BKE_layer_collection_move_into(const struct Scene *scene, struct LayerCollection *lc_dst, struct LayerCollection *lc_src);
+
+void BKE_layer_collection_resync(const struct Scene *scene, const struct SceneCollection *sc);
+
+struct LayerCollection *BKE_collection_link(struct SceneLayer *sl, struct SceneCollection *sc);
+
+void BKE_collection_unlink(struct SceneLayer *sl, struct LayerCollection *lc);
+
+bool BKE_scene_layer_has_collection(struct SceneLayer *sl, const struct SceneCollection *sc);
+bool BKE_scene_has_object(struct Scene *scene, struct Object *ob);
+
+/* syncing */
+
+void BKE_layer_sync_new_scene_collection(struct Scene *scene, const struct SceneCollection *sc_parent, struct SceneCollection *sc);
+void BKE_layer_sync_object_link(const struct Scene *scene, struct SceneCollection *sc, struct Object *ob);
+void BKE_layer_sync_object_unlink(const struct Scene *scene, struct SceneCollection *sc, struct Object *ob);
+
+/* override */
+
+void BKE_collection_override_datablock_add(struct LayerCollection *lc, const char *data_path, struct ID *id);
+
+/* engine settings */
+typedef void (*EngineSettingsCB)(struct RenderEngine *engine, struct IDProperty *props);
+
+struct IDProperty *BKE_layer_collection_engine_evaluated_get(struct Object *ob, const int type, const char *engine_name);
+struct IDProperty *BKE_layer_collection_engine_collection_get(struct LayerCollection *lc, const int type, const char *engine_name);
+struct IDProperty *BKE_layer_collection_engine_scene_get(struct Scene *scene, const int type, const char *engine_name);
+void BKE_layer_collection_engine_settings_callback_register(struct Main *bmain, const char *engine_name, EngineSettingsCB func);
+void BKE_layer_collection_engine_settings_callback_free(void);
+void BKE_layer_collection_engine_settings_create(struct IDProperty *root);
+void BKE_layer_collection_engine_settings_validate_scene(struct Scene *scene);
+void BKE_layer_collection_engine_settings_validate_collection(struct LayerCollection *lc);
+
+struct IDProperty *BKE_scene_layer_engine_evaluated_get(struct SceneLayer *sl, const int type, const char *engine_name);
+struct IDProperty *BKE_scene_layer_engine_layer_get(struct SceneLayer *sl, const int type, const char *engine_name);
+struct IDProperty *BKE_scene_layer_engine_scene_get(struct Scene *scene, const int type, const char *engine_name);
+void BKE_scene_layer_engine_settings_callback_register(struct Main *bmain, const char *engine_name, EngineSettingsCB func);
+void BKE_scene_layer_engine_settings_callback_free(void);
+void BKE_scene_layer_engine_settings_validate_scene(struct Scene *scene);
+void BKE_scene_layer_engine_settings_validate_layer(struct SceneLayer *sl);
+void BKE_scene_layer_engine_settings_create(struct IDProperty *root);
+
+void BKE_collection_engine_property_add_float(struct IDProperty *props, const char *name, float value);
+void BKE_collection_engine_property_add_float_array(
+ struct IDProperty *props, const char *name, const float *values, const int array_length);
+void BKE_collection_engine_property_add_int(struct IDProperty *props, const char *name, int value);
+void BKE_collection_engine_property_add_bool(struct IDProperty *props, const char *name, bool value);
+
+int BKE_collection_engine_property_value_get_int(struct IDProperty *props, const char *name);
+float BKE_collection_engine_property_value_get_float(struct IDProperty *props, const char *name);
+const float *BKE_collection_engine_property_value_get_float_array(struct IDProperty *props, const char *name);
+bool BKE_collection_engine_property_value_get_bool(struct IDProperty *props, const char *name);
+void BKE_collection_engine_property_value_set_int(struct IDProperty *props, const char *name, int value);
+void BKE_collection_engine_property_value_set_float(struct IDProperty *props, const char *name, float value);
+void BKE_collection_engine_property_value_set_float_array(struct IDProperty *props, const char *name, const float *values);
+void BKE_collection_engine_property_value_set_bool(struct IDProperty *props, const char *name, bool value);
+
+/* evaluation */
+
+void BKE_layer_eval_layer_collection_pre(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct SceneLayer *scene_layer);
+void BKE_layer_eval_layer_collection(struct EvaluationContext *eval_ctx,
+ struct LayerCollection *layer_collection,
+ struct LayerCollection *parent_layer_collection);
+void BKE_layer_eval_layer_collection_post(struct EvaluationContext *eval_ctx,
+ struct SceneLayer *scene_layer);
+
+/* iterators */
+
+void BKE_selected_objects_iterator_begin(BLI_Iterator *iter, void *data_in);
+void BKE_selected_objects_iterator_next(BLI_Iterator *iter);
+void BKE_selected_objects_iterator_end(BLI_Iterator *iter);
+
+void BKE_visible_objects_iterator_begin(BLI_Iterator *iter, void *data_in);
+void BKE_visible_objects_iterator_next(BLI_Iterator *iter);
+void BKE_visible_objects_iterator_end(BLI_Iterator *iter);
+
+void BKE_selected_bases_iterator_begin(BLI_Iterator *iter, void *data_in);
+void BKE_selected_bases_iterator_next(BLI_Iterator *iter);
+void BKE_selected_bases_iterator_end(BLI_Iterator *iter);
+
+void BKE_visible_bases_iterator_begin(BLI_Iterator *iter, void *data_in);
+void BKE_visible_bases_iterator_next(BLI_Iterator *iter);
+void BKE_visible_bases_iterator_end(BLI_Iterator *iter);
+
+#define FOREACH_SELECTED_OBJECT(sl, _instance) \
+ ITER_BEGIN(BKE_selected_objects_iterator_begin, \
+ BKE_selected_objects_iterator_next, \
+ BKE_selected_objects_iterator_end, \
+ sl, Object *, _instance)
+
+#define FOREACH_SELECTED_OBJECT_END \
+ ITER_END
+
+#define FOREACH_VISIBLE_OBJECT(sl, _instance) \
+ ITER_BEGIN(BKE_visible_objects_iterator_begin, \
+ BKE_visible_objects_iterator_next, \
+ BKE_visible_objects_iterator_end, \
+ sl, Object *, _instance)
+
+#define FOREACH_VISIBLE_OBJECT_END \
+ ITER_END
+
+#define FOREACH_SELECTED_BASE(sl, _instance) \
+ ITER_BEGIN(BKE_selected_bases_iterator_begin, \
+ BKE_selected_bases_iterator_next, \
+ BKE_selected_bases_iterator_end, \
+ sl, Base *, _instance)
+
+#define FOREACH_SELECTED_BASE_END \
+ ITER_END
+
+#define FOREACH_VISIBLE_BASE(sl, _instance) \
+ ITER_BEGIN(BKE_visible_bases_iterator_begin, \
+ BKE_visible_bases_iterator_next, \
+ BKE_visible_bases_iterator_end, \
+ sl, Base *, _instance)
+
+#define FOREACH_VISIBLE_BASE_END \
+ ITER_END
+
+
+#define FOREACH_OBJECT(sl, _instance) \
+{ \
+ Object *_instance; \
+ Base *base; \
+ for (base = (sl)->object_bases.first; base; base = base->next) { \
+ _instance = base->object;
+
+#define FOREACH_OBJECT_END \
+ } \
+}
+
+#define FOREACH_OBJECT_FLAG(scene, sl, flag, _instance) \
+{ \
+ IteratorBeginCb func_begin; \
+ IteratorCb func_next, func_end; \
+ void *data_in; \
+ \
+ if (flag == SELECT) { \
+ func_begin = &BKE_selected_objects_iterator_begin; \
+ func_next = &BKE_selected_objects_iterator_next; \
+ func_end = &BKE_selected_objects_iterator_end; \
+ data_in = (sl); \
+ } \
+ 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 \
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_LAYER_H__ */
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index e49019fcfae..bfe8cea7519 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -39,6 +39,7 @@ extern "C" {
#include "BLI_compiler_attrs.h"
struct BlendThumbnail;
+struct GHash;
struct ListBase;
struct ID;
struct ImBuf;
@@ -49,13 +50,13 @@ struct bContext;
struct PointerRNA;
struct PropertyRNA;
+size_t BKE_libblock_get_alloc_info(short type, const char **name);
void *BKE_libblock_alloc_notest(short type);
void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BKE_libblock_init_empty(struct ID *id);
-void *BKE_libblock_copy(struct Main *bmain, struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-void *BKE_libblock_copy_nolib(struct ID *id, const bool do_action) ATTR_NONNULL();
+void *BKE_libblock_copy(struct Main *bmain, const struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void *BKE_libblock_copy_nolib(const struct ID *id, const bool do_action) ATTR_NONNULL();
void BKE_libblock_copy_data(struct ID *id, const struct ID *id_from, const bool do_action);
-void BKE_libblock_relink(struct ID *id);
void BKE_libblock_rename(struct Main *bmain, struct ID *id, const char *name) ATTR_NONNULL();
void BLI_libblock_ensure_unique_name(struct Main *bmain, const char *name) ATTR_NONNULL();
@@ -64,9 +65,10 @@ struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_
/* library_remap.c (keep here since they're general functions) */
void BKE_libblock_free(struct Main *bmain, void *idv) ATTR_NONNULL();
-void BKE_libblock_free_ex(struct Main *bmain, void *idv, bool do_id_user) ATTR_NONNULL();
+void BKE_libblock_free_datablock(struct ID *id) ATTR_NONNULL();
+void BKE_libblock_free_ex(struct Main *bmain, void *idv, const bool do_id_user, const bool do_ui_user) ATTR_NONNULL();
void BKE_libblock_free_us(struct Main *bmain, void *idv) ATTR_NONNULL();
-void BKE_libblock_free_data(struct Main *bmain, struct ID *id) ATTR_NONNULL();
+void BKE_libblock_free_data(struct ID *id, const bool do_id_user) ATTR_NONNULL();
void BKE_libblock_delete(struct Main *bmain, void *idv) ATTR_NONNULL();
void BKE_id_lib_local_paths(struct Main *bmain, struct Library *lib, struct ID *id);
@@ -79,14 +81,15 @@ void id_us_plus(struct ID *id);
void id_us_min(struct ID *id);
void id_fake_user_set(struct ID *id);
void id_fake_user_clear(struct ID *id);
+void BKE_id_clear_newpoin(struct ID *id);
void BKE_id_make_local_generic(struct Main *bmain, struct ID *id, const bool id_in_mainlist, const bool lib_local);
bool id_make_local(struct Main *bmain, struct ID *id, const bool test, const bool force_local);
bool id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, struct PropertyRNA *prop);
-bool id_copy(struct Main *bmain, struct ID *id, struct ID **newid, bool test);
+bool id_copy(struct Main *bmain, const struct ID *id, struct ID **newid, bool test);
void id_sort_by_name(struct ListBase *lb, struct ID *id);
-void BKE_id_expand_local(struct ID *id);
-void BKE_id_copy_ensure_local(struct Main *bmain, struct ID *old_id, struct ID *new_id);
+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);
bool new_id(struct ListBase *lb, struct ID *id, const char *name);
void id_clear_lib_data(struct Main *bmain, struct ID *id);
@@ -94,7 +97,7 @@ void id_clear_lib_data_ex(struct Main *bmain, struct ID *id, const bool id_in_ma
struct ListBase *which_libbase(struct Main *mainlib, short type);
-#define MAX_LIBARRAY 35
+#define MAX_LIBARRAY 37
int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]);
/* Main API */
@@ -104,6 +107,9 @@ 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);
@@ -125,8 +131,11 @@ void BKE_id_ui_prefix(char name[66 + 1], const struct ID *id);
void BKE_library_free(struct Library *lib);
void BKE_library_make_local(
- struct Main *bmain, const struct Library *lib, const bool untagged_only, const bool set_fake);
+ struct Main *bmain, const struct Library *lib, struct GHash *old_to_new_ids,
+ const bool untagged_only, const bool set_fake);
+void BKE_id_tag_set_atomic(struct ID *id, int tag);
+void BKE_id_tag_clear_atomic(struct ID *id, int tag);
/* use when "" is given to new_id() */
#define ID_FALLBACK_NAME N_("Untitled")
diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h
index c5f575c8c0f..d6e7d98f371 100644
--- a/source/blender/blenkernel/BKE_library_query.h
+++ b/source/blender/blenkernel/BKE_library_query.h
@@ -36,25 +36,33 @@ struct Main;
/* Tips for the callback for cases it's gonna to modify the pointer. */
enum {
- IDWALK_NOP = 0,
- IDWALK_NEVER_NULL = (1 << 0),
- IDWALK_NEVER_SELF = (1 << 1),
+ IDWALK_CB_NOP = 0,
+ IDWALK_CB_NEVER_NULL = (1 << 0),
+ IDWALK_CB_NEVER_SELF = (1 << 1),
/**
* Indicates whether this is direct (i.e. by local data) or indirect (i.e. by linked data) usage.
* \note Object proxies are half-local, half-linked...
*/
- IDWALK_INDIRECT_USAGE = (1 << 2),
+ IDWALK_CB_INDIRECT_USAGE = (1 << 2),
+
+ /** That ID is used as mere sub-data by its owner
+ * (only case currently: those f***ing nodetrees in materials etc.).
+ * This means callback shall not *do* anything, only use this as informative data if it needs it. */
+ IDWALK_CB_PRIVATE = (1 << 3),
+
+ /** That ID is not really used by its owner, it's just an internal hint/helper.
+ * This addresses Their Highest Ugliness the 'from' pointers: Object->from_proxy and Key->from.
+ * How to handle that kind of cases totally depends on what caller code is doing... */
+ IDWALK_CB_LOOPBACK = (1 << 4),
/**
* Adjusts #ID.us reference-count.
* \note keep in sync with 'newlibadr_us' use in readfile.c
*/
- IDWALK_USER = (1 << 8),
- /**
- * Ensure #ID.us is at least 1 on use.
- */
- IDWALK_USER_ONE = (1 << 9),
+ IDWALK_CB_USER = (1 << 8),
+ /** Ensure #ID.us is at least 1 on use. */
+ IDWALK_CB_USER_ONE = (1 << 9),
};
enum {
@@ -68,24 +76,31 @@ enum {
*
* \return a set of flags to control further iteration (0 to keep going).
*/
-typedef int (*LibraryIDLinkCallback) (void *user_data, struct ID *id_self, struct ID **id_pointer, int cd_flag);
+typedef int (*LibraryIDLinkCallback) (void *user_data, struct ID *id_self, struct ID **id_pointer, int cb_flag);
/* Flags for the foreach function itself. */
enum {
+ IDWALK_NOP = 0,
IDWALK_READONLY = (1 << 0),
IDWALK_RECURSE = (1 << 1), /* Also implies IDWALK_READONLY. */
+
+ IDWALK_NO_INDIRECT_PROXY_DATA_USAGE = (1 << 8), /* Ugly special case :(((( */
};
/* Loop over all of the ID's this datablock links to. */
-void BKE_library_foreach_ID_link(struct ID *id, LibraryIDLinkCallback callback, void *user_data, int flag);
-void BKE_library_update_ID_link_user(struct ID *id_dst, struct ID *id_src, const int cd_flag);
+void BKE_library_foreach_ID_link(
+ struct Main *bmain, struct ID *id, LibraryIDLinkCallback callback, void *user_data, int flag);
+void BKE_library_update_ID_link_user(struct ID *id_dst, struct ID *id_src, const int cb_flag);
int BKE_library_ID_use_ID(struct ID *id_user, struct ID *id_used);
-bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id_type_used);
+bool BKE_library_id_can_use_idtype(struct ID *id_owner, const short id_type_used);
bool BKE_library_ID_is_locally_used(struct Main *bmain, void *idv);
bool BKE_library_ID_is_indirectly_used(struct Main *bmain, void *idv);
void BKE_library_ID_test_usages(struct Main *bmain, void *idv, bool *is_used_local, bool *is_used_linked);
+void BKE_library_unused_linked_data_set_tag(struct Main *bmain, const bool do_init_tag);
+void BKE_library_indirectly_used_data_tag_clear(struct Main *bmain);
+
#endif /* __BKE_LIBRARY_QUERY_H__ */
diff --git a/source/blender/blenkernel/BKE_library_remap.h b/source/blender/blenkernel/BKE_library_remap.h
index e974b79ee66..fd37fd762f4 100644
--- a/source/blender/blenkernel/BKE_library_remap.h
+++ b/source/blender/blenkernel/BKE_library_remap.h
@@ -44,8 +44,13 @@ enum {
* (like e.g. Object->data). */
ID_REMAP_FLAG_NEVER_NULL_USAGE = 1 << 2,
/* This tells the callback func to force setting IDs using target one with a 'never NULL' pointer to NULL.
- * WARNING! Use with extreme care, this will leave database in broken state! */
+ * WARNING! Use with extreme care, this will leave database in broken state and can cause crashes very easily! */
ID_REMAP_FORCE_NEVER_NULL_USAGE = 1 << 3,
+ /* Do not consider proxy/_group pointers of local objects as indirect usages...
+ * Our oh-so-beloved proxies again... Do not consider data used by local proxy object as indirect usage.
+ * 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,
};
/* Note: Requiring new_id to be non-null, this *may* not be the case ultimately, but makes things simpler for now. */
@@ -64,6 +69,7 @@ void BKE_libblock_relink_ex(
struct Main *bmain, void *idv, void *old_idv, void *new_idv,
const bool us_min_never_null) ATTR_NONNULL(1, 2);
+void BKE_libblock_relink_to_newid(struct ID *id) ATTR_NONNULL();
typedef void (*BKE_library_free_window_manager_cb)(struct bContext *, struct wmWindowManager *);
typedef void (*BKE_library_free_notifier_reference_cb)(const void *);
diff --git a/source/blender/blenkernel/BKE_lightprobe.h b/source/blender/blenkernel/BKE_lightprobe.h
new file mode 100644
index 00000000000..ae7df75345d
--- /dev/null
+++ b/source/blender/blenkernel/BKE_lightprobe.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) Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BKE_LIGHTPROBE_H__
+#define __BKE_LIGHTPROBE_H__
+
+/** \file BKE_lightprobe.h
+ * \ingroup bke
+ * \brief General operations for probes.
+ */
+
+struct Main;
+struct LightProbe;
+
+void BKE_lightprobe_init(struct LightProbe *probe);
+void *BKE_lightprobe_add(struct Main *bmain, const char *name);
+struct LightProbe *BKE_lightprobe_copy(struct Main *bmain, 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 /* __BKE_LIGHTPROBE_H__ */
diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h
index e96ef4e7be3..c7b323d0f6e 100644
--- a/source/blender/blenkernel/BKE_linestyle.h
+++ b/source/blender/blenkernel/BKE_linestyle.h
@@ -52,7 +52,7 @@ struct bContext;
void BKE_linestyle_init(struct FreestyleLineStyle *linestyle);
FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name);
void BKE_linestyle_free(FreestyleLineStyle *linestyle);
-FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *linestyle);
+FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, const FreestyleLineStyle *linestyle);
void BKE_linestyle_make_local(struct Main *bmain, struct FreestyleLineStyle *linestyle, const bool lib_local);
@@ -63,20 +63,20 @@ LineStyleModifier *BKE_linestyle_alpha_modifier_add(FreestyleLineStyle *linestyl
LineStyleModifier *BKE_linestyle_thickness_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type);
LineStyleModifier *BKE_linestyle_geometry_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type);
-LineStyleModifier *BKE_linestyle_color_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m);
-LineStyleModifier *BKE_linestyle_alpha_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m);
-LineStyleModifier *BKE_linestyle_thickness_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m);
-LineStyleModifier *BKE_linestyle_geometry_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m);
+LineStyleModifier *BKE_linestyle_color_modifier_copy(FreestyleLineStyle *linestyle, const LineStyleModifier *m);
+LineStyleModifier *BKE_linestyle_alpha_modifier_copy(FreestyleLineStyle *linestyle, const LineStyleModifier *m);
+LineStyleModifier *BKE_linestyle_thickness_modifier_copy(FreestyleLineStyle *linestyle, const LineStyleModifier *m);
+LineStyleModifier *BKE_linestyle_geometry_modifier_copy(FreestyleLineStyle *linestyle, const LineStyleModifier *m);
int BKE_linestyle_color_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *modifier);
int BKE_linestyle_alpha_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *modifier);
int BKE_linestyle_thickness_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *modifier);
int BKE_linestyle_geometry_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *modifier);
-void BKE_linestyle_color_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
-void BKE_linestyle_alpha_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
-void BKE_linestyle_thickness_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
-void BKE_linestyle_geometry_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
+bool BKE_linestyle_color_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
+bool BKE_linestyle_alpha_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
+bool BKE_linestyle_thickness_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
+bool BKE_linestyle_geometry_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
void BKE_linestyle_modifier_list_color_ramps(FreestyleLineStyle *linestyle, ListBase *listbase);
char *BKE_linestyle_path_to_color_ramp(FreestyleLineStyle *linestyle, struct ColorBand *color_ramp);
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index a4f5c425282..faa91fd4f79 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -51,6 +51,8 @@ extern "C" {
struct EvaluationContext;
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. */
@@ -59,6 +61,22 @@ typedef struct BlendThumbnail {
char rect[0];
} BlendThumbnail;
+/* Structs caching relations between data-blocks in a given Main. */
+typedef struct MainIDRelationsEntry {
+ struct MainIDRelationsEntry *next;
+ /* WARNING! for user_to_used, that pointer is really an ID** one, but for used_to_user, it’s only an ID* one! */
+ struct ID **id_pointer;
+ int usage_flag; /* Using IDWALK_ enums, in BKE_library_query.h */
+} MainIDRelationsEntry;
+
+typedef struct MainIDRelations {
+ struct GHash *id_user_to_used;
+ struct GHash *id_used_to_user;
+
+ /* Private... */
+ struct BLI_mempool *entry_pool;
+} MainIDRelations;
+
typedef struct Main {
struct Main *next, *prev;
char name[1024]; /* 1024 = FILE_MAX */
@@ -90,6 +108,7 @@ typedef struct Main {
ListBase vfont;
ListBase text;
ListBase speaker;
+ ListBase lightprobe;
ListBase sound;
ListBase group;
ListBase armature;
@@ -105,12 +124,18 @@ typedef struct Main {
ListBase mask;
ListBase linestyle;
ListBase cachefiles;
+ ListBase workspaces;
char id_tag_update[MAX_LIBARRAY];
/* Evaluation context used by viewport */
struct EvaluationContext *eval_ctx;
+ /* 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.
+ * Used by code doing a lot of remapping etc. at once to speed things up. */
+ struct MainIDRelations *relations;
+
struct MainLock *lock;
} Main;
diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h
index 3349bffac85..0735d2d97a1 100644
--- a/source/blender/blenkernel/BKE_mask.h
+++ b/source/blender/blenkernel/BKE_mask.h
@@ -77,14 +77,14 @@ void BKE_mask_layer_free(struct MaskLayer *masklay);
void BKE_mask_layer_free_list(struct ListBase *masklayers);
void BKE_mask_spline_free(struct MaskSpline *spline);
void BKE_mask_spline_free_list(struct ListBase *splines);
-struct MaskSpline *BKE_mask_spline_copy(struct MaskSpline *spline);
+struct MaskSpline *BKE_mask_spline_copy(const struct MaskSpline *spline);
void BKE_mask_point_free(struct MaskSplinePoint *point);
void BKE_mask_layer_unique_name(struct Mask *mask, struct MaskLayer *masklay);
void BKE_mask_layer_rename(struct Mask *mask, struct MaskLayer *masklay, char *oldname, char *newname);
-struct MaskLayer *BKE_mask_layer_copy(struct MaskLayer *layer);
-void BKE_mask_layer_copy_list(struct ListBase *masklayers_new, struct ListBase *masklayers);
+struct MaskLayer *BKE_mask_layer_copy(const struct MaskLayer *layer);
+void BKE_mask_layer_copy_list(struct ListBase *masklayers_new, const struct ListBase *masklayers);
/* splines */
struct MaskSpline *BKE_mask_spline_add(struct MaskLayer *masklay);
@@ -123,7 +123,7 @@ void BKE_mask_point_select_set_handle(struct MaskSplinePoint *point, const eMask
/* general */
struct Mask *BKE_mask_new(struct Main *bmain, const char *name);
struct Mask *BKE_mask_copy_nolib(struct Mask *mask);
-struct Mask *BKE_mask_copy(struct Main *bmain, struct Mask *mask);
+struct Mask *BKE_mask_copy(struct Main *bmain, const struct Mask *mask);
void BKE_mask_make_local(struct Main *bmain, struct Mask *mask, const bool lib_local);
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index df739996c54..85c649bbd3d 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -49,12 +49,12 @@ void BKE_material_free(struct Material *ma);
void BKE_material_free_ex(struct Material *ma, bool do_id_user);
void test_object_materials(struct Object *ob, struct ID *id);
void test_all_objects_materials(struct Main *bmain, struct ID *id);
-void BKE_material_resize_object(struct Object *ob, const short totcol, bool do_id_user);
+void BKE_material_resize_object(struct Main *bmain, struct Object *ob, const short totcol, bool do_id_user);
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_copy(struct Main *bmain, struct Material *ma);
+struct Material *BKE_material_copy(struct Main *bmain, const struct Material *ma);
struct Material *localize_material(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);
@@ -86,14 +86,18 @@ short BKE_object_material_slot_find_index(struct Object *ob, struct Material *ma
bool BKE_object_material_slot_add(struct Object *ob);
bool BKE_object_material_slot_remove(struct Object *ob);
+struct Image *BKE_object_material_edit_image_get(struct Object *ob, short mat_nr);
+struct Image **BKE_object_material_edit_image_get_array(struct Object *ob);
+bool BKE_object_material_edit_image_set(struct Object *ob, short mat_nr, struct Image *image);
+
void BKE_texpaint_slot_refresh_cache(struct Scene *scene, struct Material *ma);
void BKE_texpaint_slots_refresh_object(struct Scene *scene, struct Object *ob);
/* rna api */
-void BKE_material_resize_id(struct ID *id, short totcol, bool do_id_user);
-void BKE_material_append_id(struct ID *id, struct Material *ma);
-struct Material *BKE_material_pop_id(struct ID *id, int index, bool update_data); /* index is an int because of RNA */
-void BKE_material_clear_id(struct ID *id, bool update_data);
+void BKE_material_resize_id(struct Main *bmain, struct ID *id, short totcol, bool do_id_user);
+void BKE_material_append_id(struct Main *bmain, struct ID *id, struct Material *ma);
+struct Material *BKE_material_pop_id(struct Main *bmain, struct ID *id, int index, bool update_data); /* index is an int because of RNA */
+void BKE_material_clear_id(struct Main *bmain, struct ID *id, bool update_data);
/* rendering */
void init_render_material(struct Material *, int, float *);
@@ -114,9 +118,6 @@ void free_matcopybuf(void);
void copy_matcopybuf(struct Material *ma);
void paste_matcopybuf(struct Material *ma);
-/* handle backward compatibility for tface/materials called from doversion */
-int do_version_tface(struct Main *main);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h
index 64320a20281..c00a0743ebb 100644
--- a/source/blender/blenkernel/BKE_mball.h
+++ b/source/blender/blenkernel/BKE_mball.h
@@ -41,7 +41,7 @@ struct MetaElem;
void BKE_mball_free(struct MetaBall *mb);
void BKE_mball_init(struct MetaBall *mb);
struct MetaBall *BKE_mball_add(struct Main *bmain, const char *name);
-struct MetaBall *BKE_mball_copy(struct Main *bmain, struct MetaBall *mb);
+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);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index d41878825bb..9a94b9513f4 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -87,7 +87,7 @@ int BKE_mesh_edge_other_vert(const struct MEdge *e, int v);
void BKE_mesh_free(struct Mesh *me);
void BKE_mesh_init(struct Mesh *me);
struct Mesh *BKE_mesh_add(struct Main *bmain, const char *name);
-struct Mesh *BKE_mesh_copy(struct Main *bmain, struct Mesh *me);
+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);
@@ -110,7 +110,8 @@ int BKE_mesh_nurbs_displist_to_mdata(
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 Object *ob, struct ListBase *dispbase, const bool use_orco_uv);
+void BKE_mesh_from_nurbs_displist(
+ struct Object *ob, struct ListBase *dispbase, const bool use_orco_uv, const char *obdata_name);
void BKE_mesh_from_nurbs(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 Scene *scene, struct Object *ob);
@@ -123,6 +124,7 @@ 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]);
+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,
@@ -131,8 +133,7 @@ bool BKE_mesh_uv_cdlayer_rename(struct Mesh *me, const char *old_name, const cha
float (*BKE_mesh_vertexCos_get(const struct Mesh *me, int *r_numVerts))[3];
-void BKE_mesh_calc_normals_split(struct Mesh *mesh);
-void BKE_mesh_split_faces(struct Mesh *mesh);
+void BKE_mesh_split_faces(struct Mesh *mesh, bool free_loop_normals);
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);
@@ -187,13 +188,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);
/**
* References a contiguous loop-fan with normal offset vars.
@@ -228,6 +222,9 @@ void BKE_lnor_space_custom_normal_to_data(MLoopNorSpace *lnor_space, const float
bool BKE_mesh_has_custom_loop_normals(struct Mesh *me);
+void BKE_mesh_calc_normals_split(struct Mesh *mesh);
+void BKE_mesh_calc_normals_split_ex(struct Mesh *mesh, struct MLoopNorSpaceArray *r_lnors_spacearr);
+
void BKE_mesh_normals_loop_split(
const struct MVert *mverts, const int numVerts, struct MEdge *medges, const int numEdges,
struct MLoop *mloops, float (*r_loopnors)[3], const int numLoops,
@@ -292,7 +289,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,
@@ -370,7 +367,6 @@ void BKE_mesh_calc_relative_deform(
/* *** mesh_validate.c *** */
int BKE_mesh_validate(struct Mesh *me, const int do_verbose, const int cddata_check_mask);
-void BKE_mesh_cd_validate(struct Mesh *me);
int BKE_mesh_validate_material_indices(struct Mesh *me);
bool BKE_mesh_validate_arrays(
@@ -405,6 +401,17 @@ struct EvaluationContext;
void BKE_mesh_eval_geometry(struct EvaluationContext *eval_ctx,
struct Mesh *mesh);
+/* Draw Cache */
+enum {
+ BKE_MESH_BATCH_DIRTY_ALL = 0,
+ BKE_MESH_BATCH_DIRTY_SELECT,
+ BKE_MESH_BATCH_DIRTY_NOCHECK,
+ BKE_MESH_BATCH_DIRTY_SHADING,
+ BKE_MESH_BATCH_DIRTY_SCULPT_COORDS,
+};
+void BKE_mesh_batch_cache_dirty(struct Mesh *me, int mode);
+void BKE_mesh_batch_cache_free(struct Mesh *me);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_mesh_tangent.h b/source/blender/blenkernel/BKE_mesh_tangent.h
new file mode 100644
index 00000000000..cb3100c1c2f
--- /dev/null
+++ b/source/blender/blenkernel/BKE_mesh_tangent.h
@@ -0,0 +1,61 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_MESH_TANGENT_H__
+#define __BKE_MESH_TANGENT_H__
+
+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);
+
+/* 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 f6c08909d23..95f28f8fa6f 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -38,6 +38,7 @@ struct DagForest;
struct DagNode;
struct Object;
struct Scene;
+struct SceneLayer;
struct ListBase;
struct bArmature;
struct Main;
@@ -106,8 +107,8 @@ typedef enum {
} ModifierTypeFlag;
/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */
-typedef void (*ObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin, int cd_flag);
-typedef void (*IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cd_flag);
+typedef void (*ObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin, int cb_flag);
+typedef void (*IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag);
typedef void (*TexWalkFunc)(void *userData, struct Object *ob, struct ModifierData *md, const char *propname);
typedef enum ModifierApplyFlag {
@@ -260,20 +261,10 @@ typedef struct ModifierTypeInfo {
*/
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, struct DagForest *forest,
- struct Main *bmain, struct Scene *scene,
- struct Object *ob, struct DagNode *obNode);
-
/* Add the appropriate relations to the dependency graph.
*
* This function is optional.
*/
- /* TODO(sergey): Remove once we finalyl switched to the new depsgraph. */
void (*updateDepsgraph)(struct ModifierData *md,
struct Main *bmain,
struct Scene *scene,
diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h
index 3237c146bc5..69fdad5ef7b 100644
--- a/source/blender/blenkernel/BKE_movieclip.h
+++ b/source/blender/blenkernel/BKE_movieclip.h
@@ -41,7 +41,7 @@ struct MovieDistortion;
void BKE_movieclip_free(struct MovieClip *clip);
-struct MovieClip *BKE_movieclip_copy(struct Main *bmain, struct MovieClip *clip);
+struct MovieClip *BKE_movieclip_copy(struct Main *bmain, const struct MovieClip *clip);
void BKE_movieclip_make_local(struct Main *bmain, struct MovieClip *clip, const bool lib_local);
struct MovieClip *BKE_movieclip_file_add(struct Main *bmain, const char *name);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 95f06e9f695..a668ae9a7af 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -49,7 +49,7 @@
#include "RNA_types.h"
/* not very important, but the stack solver likes to know a maximum */
-#define MAX_SOCKET 64
+#define MAX_SOCKET 512
struct bContext;
struct bNode;
@@ -253,6 +253,7 @@ typedef struct bNodeType {
/* nodetype->compatibility */
#define NODE_OLD_SHADING 1
#define NODE_NEW_SHADING 2
+#define NODE_NEWER_SHADING 3
/* node resize directions */
#define NODE_RESIZE_TOP 1
@@ -335,10 +336,8 @@ struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char
/* copy/free funcs, need to manage ID users */
void ntreeFreeTree(struct bNodeTree *ntree);
-struct bNodeTree *ntreeCopyTree_ex(struct bNodeTree *ntree, struct Main *bmain, const bool do_id_user);
-struct bNodeTree *ntreeCopyTree(struct Main *bmain, struct bNodeTree *ntree);
-void ntreeSwitchID_ex(struct bNodeTree *ntree, struct ID *sce_from, struct ID *sce_to, const bool do_id_user);
-void ntreeSwitchID(struct bNodeTree *ntree, struct ID *sce_from, struct ID *sce_to);
+struct bNodeTree *ntreeCopyTree_ex(const struct bNodeTree *ntree, struct Main *bmain, const bool do_id_user);
+struct bNodeTree *ntreeCopyTree(struct Main *bmain, const struct bNodeTree *ntree);
/* node->id user count */
void ntreeUserIncrefID(struct bNodeTree *ntree);
void ntreeUserDecrefID(struct bNodeTree *ntree);
@@ -689,6 +688,13 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter,
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Tree
+ */
+
+void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, const int layer_index);
+
/* -------------------------------------------------------------------- */
/** \name Shader Nodes
*/
@@ -787,6 +793,10 @@ struct ShadeResult;
#define SH_NODE_OUTPUT_LINESTYLE 190
#define SH_NODE_UVALONGSTROKE 191
#define SH_NODE_TEX_POINTDENSITY 192
+#define SH_NODE_BSDF_PRINCIPLED 193
+#define SH_NODE_EEVEE_METALLIC 194
+#define SH_NODE_EEVEE_SPECULAR 195
+#define SH_NODE_OUTPUT_EEVEE_MATERIAL 196
/* custom defines options for Material node */
#define SH_NODE_MAT_DIFF 1
@@ -974,7 +984,8 @@ void ntreeCompositExecTree(struct Scene *scene, struct bNodeTree *ntree, struct
void ntreeCompositTagRender(struct Scene *sce);
int ntreeCompositTagAnimated(struct bNodeTree *ntree);
void ntreeCompositTagGenerators(struct bNodeTree *ntree);
-void ntreeCompositForceHidden(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 ntreeCompositClearTags(struct bNodeTree *ntree);
struct bNodeSocket *ntreeCompositOutputFileAddSocket(struct bNodeTree *ntree, struct bNode *node,
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 1b3e05d11ae..c3de20d7089 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -35,9 +35,10 @@ extern "C" {
#include "BLI_compiler_attrs.h"
-struct Base;
+struct BaseLegacy;
struct EvaluationContext;
struct Scene;
+struct SceneLayer;
struct Object;
struct BoundBox;
struct View3D;
@@ -54,7 +55,7 @@ void BKE_object_workob_calc_parent(struct Scene *scene, struct Object *ob, struc
void BKE_object_transform_copy(struct Object *ob_tar, const struct Object *ob_src);
struct SoftBody *copy_softbody(const struct SoftBody *sb, bool copy_caches);
-struct BulletSoftBody *copy_bulletsoftbody(struct BulletSoftBody *sb);
+struct BulletSoftBody *copy_bulletsoftbody(const struct BulletSoftBody *sb);
struct ParticleSystem *BKE_object_copy_particlesystem(struct ParticleSystem *psys);
void BKE_object_copy_particlesystems(struct Object *ob_dst, const struct Object *ob_src);
void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src);
@@ -89,9 +90,9 @@ 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 SceneLayer *sl,
int type, const char *name)
- ATTR_NONNULL(1, 2) ATTR_RETURNS_NONNULL;
+ ATTR_NONNULL(1, 2, 3) ATTR_RETURNS_NONNULL;
void *BKE_object_obdata_add_from_type(
struct Main *bmain,
int type, const char *name)
@@ -101,13 +102,14 @@ 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);
+bool BKE_object_lod_is_usable(struct Object *ob, struct SceneLayer *sl);
+struct Object *BKE_object_lod_meshob_get(struct Object *ob, struct SceneLayer *sl);
+struct Object *BKE_object_lod_matob_get(struct Object *ob, struct SceneLayer *sl);
-struct Object *BKE_object_copy_ex(struct Main *bmain, struct Object *ob, bool copy_caches);
-struct Object *BKE_object_copy(struct Main *bmain, struct Object *ob);
+struct Object *BKE_object_copy_ex(struct Main *bmain, const struct Object *ob, bool copy_caches);
+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);
+void BKE_object_make_local_ex(struct Main *bmain, struct Object *ob, const bool lib_local, const bool clear_proxy);
bool BKE_object_is_libdata(struct Object *ob);
bool BKE_object_obdata_is_libdata(struct Object *ob);
@@ -135,16 +137,9 @@ void BKE_object_where_is_calc_mat4(struct Scene *scene, struct Object *ob, float
/* possibly belong in own moduke? */
struct BoundBox *BKE_boundbox_alloc_unit(void);
void BKE_boundbox_init_from_minmax(struct BoundBox *bb, const float min[3], const float max[3]);
-bool BKE_boundbox_ray_hit_check(
- const struct BoundBox *bb,
- const float ray_start[3], const float ray_normal[3],
- float *r_lambda);
void BKE_boundbox_calc_center_aabb(const struct BoundBox *bb, float r_cent[3]);
void BKE_boundbox_calc_size_aabb(const struct BoundBox *bb, float r_size[3]);
void BKE_boundbox_minmax(const struct BoundBox *bb, float obmat[4][4], float r_min[3], float r_max[3]);
-void BKE_boundbox_scale(struct BoundBox *bb_dst, const struct BoundBox *bb_src, float scale);
-struct BoundBox *BKE_boundbox_ensure_minimum_dimensions(
- struct BoundBox *bb, struct BoundBox *bb_temp, const float epsilon);
struct BoundBox *BKE_object_boundbox_get(struct Object *ob);
void BKE_object_dimensions_get(struct Object *ob, float vec[3]);
@@ -158,8 +153,7 @@ bool BKE_object_minmax_dupli(struct Scene *scene, struct Object *ob, float r_min
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 Scene *scene,
- struct View3D *v3d,
- const short flag,
+ struct SceneLayer *sl,
void (*func_cb)(const float[3], void *), void *user_data);
bool BKE_object_parent_loop_check(const struct Object *parent, const struct Object *ob);
@@ -195,10 +189,6 @@ void BKE_object_eval_constraints(struct EvaluationContext *eval_ctx,
struct Object *ob);
void BKE_object_eval_done(struct EvaluationContext *eval_ctx, struct Object *ob);
-void BKE_object_eval_modifier(struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob,
- struct ModifierData *md);
void BKE_object_eval_uber_transform(struct EvaluationContext *eval_ctx,
struct Scene *scene,
struct Object *ob);
@@ -206,6 +196,13 @@ void BKE_object_eval_uber_data(struct EvaluationContext *eval_ctx,
struct Scene *scene,
struct Object *ob);
+void BKE_object_eval_cloth(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *object);
+
+void BKE_object_eval_update_shading(struct EvaluationContext *eval_ctx,
+ struct Object *object);
+
void BKE_object_handle_data_update(struct EvaluationContext *eval_ctx,
struct Scene *scene,
struct Object *ob);
@@ -256,9 +253,9 @@ typedef enum eObjectSet {
OB_SET_ALL /* All Objects */
} eObjectSet;
-struct LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectSet, eObRelationTypes includeFilter);
+struct LinkNode *BKE_object_relational_superset(struct SceneLayer *scene_layer, eObjectSet objectSet, eObRelationTypes includeFilter);
struct LinkNode *BKE_object_groups(struct Object *ob);
-void BKE_object_groups_clear(struct Scene *scene, struct Base *base, struct Object *object);
+void BKE_object_groups_clear(struct Object *object);
struct KDTree *BKE_object_as_kdtree(struct Object *ob, int *r_tot);
diff --git a/source/blender/blenkernel/BKE_object_deform.h b/source/blender/blenkernel/BKE_object_deform.h
index a0a885c2a04..19a2220006a 100644
--- a/source/blender/blenkernel/BKE_object_deform.h
+++ b/source/blender/blenkernel/BKE_object_deform.h
@@ -51,9 +51,11 @@ bool BKE_object_defgroup_clear(struct Object *ob, struct bDeformGroup *dg, const
bool BKE_object_defgroup_clear_all(struct Object *ob, const bool use_selection);
void BKE_object_defgroup_remove(struct Object *ob, struct bDeformGroup *defgroup);
+void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked);
void BKE_object_defgroup_remove_all(struct Object *ob);
+
/* Select helpers */
enum eVGroupSelect;
bool *BKE_object_defgroup_subset_from_select_type(
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_outliner_treehash.h b/source/blender/blenkernel/BKE_outliner_treehash.h
index 454edb40c4e..b82bc692402 100644
--- a/source/blender/blenkernel/BKE_outliner_treehash.h
+++ b/source/blender/blenkernel/BKE_outliner_treehash.h
@@ -36,8 +36,9 @@ 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 */
+/* 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 0a3cc950f32..787a67170c2 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -52,6 +52,7 @@ struct PaletteColor;
struct PBVH;
struct ReportList;
struct Scene;
+struct SceneLayer;
struct Sculpt;
struct StrokeCache;
struct Tex;
@@ -89,8 +90,8 @@ typedef enum OverlayControlFlags {
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 SceneLayer *sl, const struct Tex *tex);
+void BKE_paint_invalidate_cursor_overlay(struct Scene *scene, struct SceneLayer *sl, struct CurveMapping *curve);
void BKE_paint_invalidate_overlay_all(void);
OverlayControlFlags BKE_paint_get_overlay_flags(void);
void BKE_paint_reset_overlay_invalid(OverlayControlFlags flag);
@@ -99,7 +100,7 @@ void BKE_paint_set_overlay_override(enum OverlayFlags flag);
/* palettes */
void BKE_palette_free(struct Palette *palette);
struct Palette *BKE_palette_add(struct Main *bmain, const char *name);
-struct Palette *BKE_palette_copy(struct Main *bmain, struct Palette *palette);
+struct Palette *BKE_palette_copy(struct Main *bmain, const struct Palette *palette);
void BKE_palette_make_local(struct Main *bmain, struct Palette *palette, const bool lib_local);
struct PaletteColor *BKE_palette_color_add(struct Palette *palette);
bool BKE_palette_is_empty(const struct Palette *palette);
@@ -109,7 +110,7 @@ void BKE_palette_clear(struct Palette *palette);
/* paint curves */
struct PaintCurve *BKE_paint_curve_add(struct Main *bmain, const char *name);
void BKE_paint_curve_free(struct PaintCurve *pc);
-struct PaintCurve *BKE_paint_curve_copy(struct Main *bmain, struct PaintCurve *pc);
+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);
void BKE_paint_init(struct Scene *sce, PaintMode mode, const char col[3]);
@@ -120,7 +121,7 @@ void BKE_paint_cavity_curve_preset(struct Paint *p, int preset);
short BKE_paint_object_mode_from_paint_mode(PaintMode mode);
struct Paint *BKE_paint_get_active_from_paintmode(struct Scene *sce, PaintMode mode);
-struct Paint *BKE_paint_get_active(struct Scene *sce);
+struct Paint *BKE_paint_get_active(struct Scene *sce, struct SceneLayer *sl);
struct Paint *BKE_paint_get_active_from_context(const struct bContext *C);
PaintMode BKE_paintmode_get_active_from_context(const struct bContext *C);
struct Brush *BKE_paint_brush(struct Paint *paint);
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index dc0858b381f..4951ecc7f9e 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -207,7 +207,7 @@ typedef struct ParticleCollisionElement {
typedef struct ParticleCollision {
struct Object *current;
struct Object *hit;
- struct Object *skip[PARTICLE_COLLISION_MAX_COLLISIONS+1];
+ struct Object *skip[PARTICLE_COLLISION_MAX_COLLISIONS + 1];
struct Object *emitter;
struct CollisionModifierData *md; // collision modifier for current object;
@@ -324,7 +324,7 @@ struct ParticleSystemModifierData *psys_get_modifier(struct Object *ob, struct P
struct ModifierData *object_add_particle_system(struct Scene *scene, struct Object *ob, const char *name);
void object_remove_particle_system(struct Scene *scene, struct Object *ob);
struct ParticleSettings *psys_new_settings(const char *name, struct Main *main);
-struct ParticleSettings *BKE_particlesettings_copy(struct Main *bmain, struct ParticleSettings *part);
+struct ParticleSettings *BKE_particlesettings_copy(struct Main *bmain, const struct ParticleSettings *part);
void BKE_particlesettings_make_local(struct Main *bmain, struct ParticleSettings *part, const bool lib_local);
void psys_reset(struct ParticleSystem *psys, int mode);
@@ -384,7 +384,7 @@ void psys_get_birth_coords(struct ParticleSimulationData *sim, struct ParticleDa
void particle_system_update(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 cd_flag);
+typedef void (*ParticleSystemIDFunc)(struct ParticleSystem *psys, struct ID **idpoin, void *userdata, int cb_flag);
void BKE_particlesystem_id_loop(struct ParticleSystem *psys, ParticleSystemIDFunc func, void *userdata);
@@ -480,3 +480,10 @@ void BKE_particle_system_eval(struct EvaluationContext *eval_ctx,
struct ParticleSystem *psys);
#endif
+
+/* Draw Cache */
+enum {
+ BKE_PARTICLE_BATCH_DIRTY_ALL = 0,
+};
+void BKE_particle_batch_cache_dirty(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 927303f8b3c..905eb677612 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 Gwn_Batch;
struct CCGElem;
struct CCGKey;
struct CustomData;
@@ -118,6 +119,9 @@ void BKE_pbvh_raycast_project_ray_root(
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_cb(
+ PBVH *bvh, float (*planes)[4], float (*fnors)[3], bool fast,
+ void (*draw_fn)(void *user_data, struct Gwn_Batch *batch), void *user_data);
/* PBVH Access */
typedef enum {
@@ -354,6 +358,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);
#endif /* __BKE_PBVH_H__ */
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index 8238ea64242..02f6c435ee2 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -304,7 +304,7 @@ void BKE_ptcache_mem_pointers_incr(struct PTCacheMem *pm);
int BKE_ptcache_mem_pointers_seek(int point_index, struct PTCacheMem *pm);
/* Main cache reading call. */
-int BKE_ptcache_read(PTCacheID *pid, float cfra);
+int BKE_ptcache_read(PTCacheID *pid, float cfra, bool no_extrapolate_old);
/* Main cache writing call. */
int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra);
diff --git a/source/blender/blenkernel/BKE_property.h b/source/blender/blenkernel/BKE_property.h
index 99e60757f15..c787e8e8ed1 100644
--- a/source/blender/blenkernel/BKE_property.h
+++ b/source/blender/blenkernel/BKE_property.h
@@ -37,8 +37,8 @@ struct Object;
void BKE_bproperty_free(struct bProperty *prop);
void BKE_bproperty_free_list(struct ListBase *lb);
-struct bProperty *BKE_bproperty_copy(struct bProperty *prop);
-void BKE_bproperty_copy_list(struct ListBase *lbn, struct ListBase *lbo);
+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);
diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h
index 272abc42899..c72f067a111 100644
--- a/source/blender/blenkernel/BKE_rigidbody.h
+++ b/source/blender/blenkernel/BKE_rigidbody.h
@@ -49,12 +49,11 @@ void BKE_rigidbody_free_constraint(struct Object *ob);
/* ...... */
-struct RigidBodyOb *BKE_rigidbody_copy_object(struct Object *ob);
-struct RigidBodyCon *BKE_rigidbody_copy_constraint(struct Object *ob);
-void BKE_rigidbody_relink_constraint(struct RigidBodyCon *rbc);
+struct RigidBodyOb *BKE_rigidbody_copy_object(const struct Object *ob);
+struct RigidBodyCon *BKE_rigidbody_copy_constraint(const struct Object *ob);
/* Callback format for performing operations on ID-pointers for rigidbody world. */
-typedef void (*RigidbodyWorldIDFunc)(struct RigidBodyWorld *rbw, struct ID **idpoin, void *userdata, int cd_flag);
+typedef void (*RigidbodyWorldIDFunc)(struct RigidBodyWorld *rbw, struct ID **idpoin, void *userdata, int cb_flag);
void BKE_rigidbody_world_id_loop(struct RigidBodyWorld *rbw, RigidbodyWorldIDFunc func, void *userdata);
diff --git a/source/blender/blenkernel/BKE_sca.h b/source/blender/blenkernel/BKE_sca.h
index 1743a4431fd..10cddd7b454 100644
--- a/source/blender/blenkernel/BKE_sca.h
+++ b/source/blender/blenkernel/BKE_sca.h
@@ -31,8 +31,9 @@
* \ingroup bke
*/
-struct bSensor;
+struct Main;
struct Object;
+struct bSensor;
struct bController;
struct bActuator;
@@ -52,15 +53,15 @@ 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);
-void copy_sensors(struct ListBase *lbn, struct ListBase *lbo);
+void copy_sensors(struct ListBase *lbn, const struct ListBase *lbo);
void init_sensor(struct bSensor *sens);
struct bSensor *new_sensor(int type);
struct bController *copy_controller(struct bController *cont);
-void copy_controllers(struct ListBase *lbn, struct ListBase *lbo);
+void copy_controllers(struct ListBase *lbn, const struct ListBase *lbo);
void init_controller(struct bController *cont);
struct bController *new_controller(int type);
struct bActuator *copy_actuator(struct bActuator *act);
-void copy_actuators(struct ListBase *lbn, struct ListBase *lbo);
+void copy_actuators(struct ListBase *lbn, const struct ListBase *lbo);
void init_actuator(struct bActuator *act);
struct bActuator *new_actuator(int type);
void clear_sca_new_poins_ob(struct Object *ob);
@@ -68,14 +69,17 @@ 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);
+
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 cd_flag);
-typedef void (*SCAControllerIDFunc)(struct bController *controller, struct ID **idpoin, void *userdata, int cd_flag);
-typedef void (*SCAActuatorIDFunc)(struct bActuator *actuator, struct ID **idpoin, void *userdata, int cd_flag);
+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);
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index d2152950bff..6ca79d8c7cd 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -38,22 +38,29 @@ extern "C" {
#endif
struct AviCodecData;
-struct Base;
+struct BaseLegacy;
+struct Depsgraph;
struct EvaluationContext;
struct Main;
struct Object;
+struct Base;
struct QuicktimeCodecData;
struct RenderData;
+struct SceneLayer;
struct SceneRenderLayer;
struct Scene;
+struct SceneCollection;
+struct SceneLayer;
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
+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) \
@@ -66,17 +73,20 @@ struct Base *_setlooper_base_step(struct Scene **sce_iter, struct Base *base);
void free_avicodecdata(struct AviCodecData *acd);
void free_qtcodecdata(struct QuicktimeCodecData *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);
+void BKE_scene_remove_rigidbody_object(struct Scene *scene, struct Object *ob);
+
/* 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);
+struct BaseLegacy *BKE_scene_base_find_by_name(struct Scene *scene, const char *name);
+struct BaseLegacy *BKE_scene_base_find(struct Scene *scene, struct Object *ob);
+struct BaseLegacy *BKE_scene_base_add(struct Scene *sce, struct Object *ob);
+void BKE_scene_base_unlink(struct Scene *sce, struct BaseLegacy *base);
void BKE_scene_base_deselect_all(struct Scene *sce);
-void BKE_scene_base_select(struct Scene *sce, struct Base *selbase);
+void BKE_scene_base_select(struct Scene *sce, struct BaseLegacy *selbase);
/* Scene base iteration function.
* Define struct here, so no need to bother with alloc/free it.
@@ -90,10 +100,14 @@ typedef struct SceneBaseIter {
} SceneBaseIter;
int BKE_scene_base_iter_next(struct EvaluationContext *eval_ctx, struct SceneBaseIter *iter,
- struct Scene **scene, int val, struct Base **base, struct Object **ob);
+ struct Scene **scene, int val, struct BaseLegacy **base, struct Object **ob);
-void BKE_scene_base_flag_to_objects(struct Scene *scene);
+void BKE_scene_base_flag_to_objects(struct SceneLayer *sl);
void BKE_scene_base_flag_from_objects(struct Scene *scene);
+void BKE_scene_base_flag_sync_from_base(struct BaseLegacy *base);
+void BKE_scene_base_flag_sync_from_object(struct BaseLegacy *base);
+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);
@@ -103,6 +117,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 Scene *BKE_scene_find_from_collection(const struct Main *bmain, const struct SceneCollection *scene_collection);
+
struct Object *BKE_scene_camera_find(struct Scene *sc);
#ifdef DURIAN_CAMERA_SWITCH
struct Object *BKE_scene_camera_switch_find(struct Scene *scene); // DURIAN_CAMERA_SWITCH
@@ -121,8 +137,7 @@ 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);
+void BKE_scene_update_for_newframe(struct EvaluationContext *eval_ctx, struct Main *bmain, struct Scene *sce);
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);
@@ -143,6 +158,7 @@ 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);
void BKE_scene_disable_color_management(struct Scene *scene);
bool BKE_scene_check_color_management_enabled(const struct Scene *scene);
@@ -170,6 +186,9 @@ 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 */
+struct Depsgraph* BKE_scene_get_depsgraph(struct Scene *scene, struct SceneLayer *scene_layer);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index 14e978b23f2..6ff344fea38 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -42,6 +42,7 @@ struct Panel;
struct Scene;
struct ScrArea;
struct SpaceType;
+struct TransformOrientation;
struct View3D;
struct bContext;
struct bContextDataResult;
@@ -49,9 +50,11 @@ struct bScreen;
struct uiLayout;
struct uiList;
struct wmKeyConfig;
+struct wmManipulatorMap;
struct wmNotifier;
struct wmWindow;
struct wmWindowManager;
+struct WorkSpace;
struct GPUFXSettings;
#include "BLI_compiler_attrs.h"
@@ -81,7 +84,8 @@ typedef struct SpaceType {
/* exit is called when the area is hidden or removed */
void (*exit)(struct wmWindowManager *, struct ScrArea *);
/* Listeners can react to bContext changes */
- void (*listener)(struct bScreen *sc, struct ScrArea *, struct wmNotifier *);
+ void (*listener)(struct bScreen *sc, struct ScrArea *,
+ struct wmNotifier *, const struct Scene *scene);
/* refresh context, called after filereads, ED_area_tag_refresh() */
void (*refresh)(const struct bContext *, struct ScrArea *);
@@ -96,6 +100,9 @@ typedef struct SpaceType {
/* on startup, define dropboxes for spacetype+regions */
void (*dropboxes)(void);
+ /* initialize manipulator-map-types and manipulator-group-types with the region */
+ void (*manipulators)(void);
+
/* return context data */
int (*context)(const struct bContext *, const char *, struct bContextDataResult *);
@@ -129,8 +136,9 @@ typedef struct ARegionType {
/* draw entirely, view changes should be handled here */
void (*draw)(const struct bContext *, struct ARegion *);
/* contextual changes should be handled here */
- void (*listener)(struct bScreen *sc, struct ScrArea *, struct ARegion *, struct wmNotifier *);
-
+ void (*listener)(struct bScreen *, struct ScrArea *, struct ARegion *,
+ struct wmNotifier *, const struct Scene *scene);
+
void (*free)(struct ARegion *);
/* split region, copy data optionally */
@@ -284,6 +292,8 @@ void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID
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_screen_area_free(struct ScrArea *sa);
+/* Manipulator-maps of a region need to be freed with the region. Uses callback to avoid low-level call. */
+void BKE_region_callback_free_manipulatormap_set(void (*callback)(struct wmManipulatorMap *));
struct ARegion *BKE_area_find_region_type(struct ScrArea *sa, int type);
struct ARegion *BKE_area_find_region_active_win(struct ScrArea *sa);
@@ -300,11 +310,13 @@ unsigned int BKE_screen_view3d_layer_active(
unsigned int BKE_screen_view3d_layer_all(const struct bScreen *sc) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
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_view3d_scene_sync(struct bScreen *sc, struct Scene *scene);
+void BKE_screen_transform_orientation_remove(
+ const struct bScreen *screen, const struct WorkSpace *workspace,
+ const struct TransformOrientation *orientation) ATTR_NONNULL();
void BKE_screen_gpu_fx_validate(struct GPUFXSettings *fx_settings);
+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);
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index 811e9136fc9..7c09cafaf64 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -421,7 +421,7 @@ struct Sequence *BKE_sequencer_add_movie_strip(struct bContext *C, ListBase *seq
/* view3d draw callback, run when not in background view */
typedef struct ImBuf *(*SequencerDrawView)(
- struct Scene *, struct Object *, int, int,
+ struct Scene *, struct SceneLayer *sl, struct Object *, int, int,
unsigned int, int, bool, bool, bool,
int, int, bool, const char *,
struct GPUFX *, struct GPUOffScreen *, char[256]);
diff --git a/source/blender/blenkernel/BKE_smoke.h b/source/blender/blenkernel/BKE_smoke.h
index 20366f00df6..33d7acdd864 100644
--- a/source/blender/blenkernel/BKE_smoke.h
+++ b/source/blender/blenkernel/BKE_smoke.h
@@ -35,7 +35,7 @@
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 DerivedMesh *smokeModifier_do(struct SmokeModifierData *smd, struct Scene *scene, struct SceneLayer *sl, struct Object *ob, struct DerivedMesh *dm);
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);
diff --git a/source/blender/blenkernel/BKE_softbody.h b/source/blender/blenkernel/BKE_softbody.h
index 486fe8ed5a8..75c5faf4088 100644
--- a/source/blender/blenkernel/BKE_softbody.h
+++ b/source/blender/blenkernel/BKE_softbody.h
@@ -59,7 +59,8 @@ extern void sbFree(struct SoftBody *sb);
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 Scene *scene, struct SceneLayer *sl, 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 28b15b2a310..a5c626e74d7 100644
--- a/source/blender/blenkernel/BKE_sound.h
+++ b/source/blender/blenkernel/BKE_sound.h
@@ -90,6 +90,8 @@ void BKE_sound_create_scene(struct Scene *scene);
void BKE_sound_destroy_scene(struct Scene *scene);
+void BKE_sound_reset_scene_specs(struct Scene *scene);
+
void BKE_sound_mute_scene(struct Scene *scene, int muted);
void BKE_sound_update_fps(struct Scene *scene);
diff --git a/source/blender/blenkernel/BKE_speaker.h b/source/blender/blenkernel/BKE_speaker.h
index b91b64c4b74..907558f9203 100644
--- a/source/blender/blenkernel/BKE_speaker.h
+++ b/source/blender/blenkernel/BKE_speaker.h
@@ -33,7 +33,7 @@ struct Speaker;
void BKE_speaker_init(struct Speaker *spk);
void *BKE_speaker_add(struct Main *bmain, const char *name);
-struct Speaker *BKE_speaker_copy(struct Main *bmain, struct Speaker *spk);
+struct Speaker *BKE_speaker_copy(struct Main *bmain, const struct Speaker *spk);
void BKE_speaker_make_local(struct Main *bmain, struct Speaker *spk, const bool lib_local);
void BKE_speaker_free(struct Speaker *spk);
diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h
index 081b7589af6..c8fb483cdf2 100644
--- a/source/blender/blenkernel/BKE_text.h
+++ b/source/blender/blenkernel/BKE_text.h
@@ -52,7 +52,7 @@ bool BKE_text_reload(struct Text *text);
struct Text *BKE_text_load_ex(struct Main *bmain, const char *file, const char *relpath,
const bool is_internal);
struct Text *BKE_text_load (struct Main *bmain, const char *file, const char *relpath);
-struct Text *BKE_text_copy (struct Main *bmain, struct Text *ta);
+struct Text *BKE_text_copy (struct Main *bmain, const struct Text *ta);
void BKE_text_make_local (struct Main *bmain, struct Text *text, const bool lib_local);
void BKE_text_clear (struct Text *text);
void BKE_text_write (struct Text *text, const char *str);
diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h
index 1c5ea946f59..190fdeafaec 100644
--- a/source/blender/blenkernel/BKE_texture.h
+++ b/source/blender/blenkernel/BKE_texture.h
@@ -42,6 +42,7 @@ struct Brush;
struct ColorBand;
struct EnvMap;
struct FreestyleLineStyle;
+struct ImagePool;
struct Lamp;
struct Main;
struct Material;
@@ -69,7 +70,7 @@ void colorband_update_sort(struct ColorBand *coba);
void BKE_texture_free(struct Tex *tex);
void BKE_texture_default(struct Tex *tex);
-struct Tex *BKE_texture_copy(struct Main *bmain, struct Tex *tex);
+struct Tex *BKE_texture_copy(struct Main *bmain, const struct Tex *tex);
struct Tex *BKE_texture_add(struct Main *bmain, const char *name);
struct Tex *BKE_texture_localize(struct Tex *tex);
void BKE_texture_make_local(struct Main *bmain, struct Tex *tex, const bool lib_local);
@@ -113,13 +114,13 @@ void BKE_texture_colormapping_default(struct ColorMapping *color
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(struct EnvMap *env);
+struct EnvMap *BKE_texture_envmap_copy(const struct EnvMap *env);
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(struct PointDensity *pd);
+struct PointDensity *BKE_texture_pointdensity_copy(const struct PointDensity *pd);
void BKE_texture_voxeldata_free_data(struct VoxelData *vd);
void BKE_texture_voxeldata_free(struct VoxelData *vd);
@@ -128,15 +129,23 @@ 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(struct OceanTex *ot);
+struct OceanTex *BKE_texture_ocean_copy(const struct OceanTex *ot);
bool BKE_texture_dependsOnTime(const struct Tex *texture);
bool BKE_texture_is_image_user(const struct Tex *tex);
+void BKE_texture_get_value_ex(
+ const struct Scene *scene, struct Tex *texture,
+ float *tex_co, struct TexResult *texres,
+ struct ImagePool *pool,
+ bool use_color_management);
+
void BKE_texture_get_value(
const struct Scene *scene, struct Tex *texture,
float *tex_co, struct TexResult *texres, bool use_color_management);
+void BKE_texture_fetch_images_for_pool(struct Tex *texture, struct ImagePool *pool);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h
index 1938bb08395..b48be382073 100644
--- a/source/blender/blenkernel/BKE_tracking.h
+++ b/source/blender/blenkernel/BKE_tracking.h
@@ -52,7 +52,7 @@ struct rcti;
/* **** Common functions **** */
void BKE_tracking_free(struct MovieTracking *tracking);
-void BKE_tracking_copy(struct MovieTracking *tracking_dst, struct MovieTracking *tracking_src);
+void BKE_tracking_copy(struct MovieTracking *tracking_dst, const struct MovieTracking *tracking_src);
void BKE_tracking_settings_init(struct MovieTracking *tracking);
@@ -277,9 +277,9 @@ void BKE_tracking_detect_harris(struct MovieTracking *tracking, struct ListBase
bool place_outside_layer);
/* **** 2D stabilization **** */
-void BKE_tracking_stabilization_data_get(struct MovieTracking *tracking, int framenr, int width, int height,
+void BKE_tracking_stabilization_data_get(struct MovieClip *clip, int framenr, int width, int height,
float translation[2], float *scale, float *angle);
-struct ImBuf *BKE_tracking_stabilize_frame(struct MovieTracking *tracking, int framenr, struct ImBuf *ibuf,
+struct ImBuf *BKE_tracking_stabilize_frame(struct MovieClip *clip, int framenr, struct ImBuf *ibuf,
float translation[2], float *scale, float *angle);
void BKE_tracking_stabilization_data_to_mat4(int width, int height, float aspect, float translation[2],
float scale, float angle, float mat[4][4]);
diff --git a/source/blender/blenkernel/BKE_workspace.h b/source/blender/blenkernel/BKE_workspace.h
new file mode 100644
index 00000000000..43962c2eb35
--- /dev/null
+++ b/source/blender/blenkernel/BKE_workspace.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 *****
+ */
+
+/** \file BKE_workspace.h
+ * \ingroup bke
+ */
+
+#ifndef __BKE_WORKSPACE_H__
+#define __BKE_WORKSPACE_H__
+
+#include "BLI_compiler_attrs.h"
+
+struct bScreen;
+struct TransformOrientation;
+
+/**
+ * Plan is to store the object-mode per workspace, not per object anymore.
+ * However, there's quite some work to be done for that, so for now, there is just a basic
+ * implementation of an object <-> workspace object-mode syncing for testing, with some known
+ * problems. Main problem being that the modes can get out of sync when changing object selection.
+ * Would require a pile of temporary changes to always sync modes when changing selection. So just
+ * leaving this here for some testing until object-mode is really a workspace level setting.
+ */
+#define USE_WORKSPACE_MODE
+
+
+/* -------------------------------------------------------------------- */
+/* 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 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();
+
+
+/* -------------------------------------------------------------------- */
+/* General Utils */
+
+void BKE_workspace_transform_orientation_remove(
+ struct WorkSpace *workspace, struct TransformOrientation *orientation) ATTR_NONNULL();
+struct TransformOrientation *BKE_workspace_transform_orientation_find(
+ const struct WorkSpace *workspace, const int index) ATTR_NONNULL();
+int BKE_workspace_transform_orientation_get_index(
+ const struct WorkSpace *workspace, const struct TransformOrientation *orientation) ATTR_NONNULL();
+
+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);
+
+
+/* -------------------------------------------------------------------- */
+/* 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;
+enum ObjectMode BKE_workspace_object_mode_get(const struct WorkSpace *workspace) GETTER_ATTRS;
+#ifdef USE_WORKSPACE_MODE
+void BKE_workspace_object_mode_set(struct WorkSpace *workspace, const enum ObjectMode mode) SETTER_ATTRS;
+#endif
+struct ListBase *BKE_workspace_transform_orientations_get(struct WorkSpace *workspace) GETTER_ATTRS;
+struct SceneLayer *BKE_workspace_render_layer_get(const struct WorkSpace *workspace) GETTER_ATTRS;
+void BKE_workspace_render_layer_set(struct WorkSpace *workspace, struct SceneLayer *layer) 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();
+
+#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 23bf9ec3d22..18ae61f7653 100644
--- a/source/blender/blenkernel/BKE_world.h
+++ b/source/blender/blenkernel/BKE_world.h
@@ -39,7 +39,7 @@ struct World;
void BKE_world_free(struct World *sc);
void BKE_world_init(struct World *wrld);
struct World *add_world(struct Main *bmian, const char *name);
-struct World *BKE_world_copy(struct Main *bmain, struct World *wrld);
+struct World *BKE_world_copy(struct Main *bmain, const struct World *wrld);
struct World *localize_world(struct World *wrld);
void BKE_world_make_local(struct Main *bmain, struct World *wrld, const bool lib_local);
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 45a10cb33b5..8d0dedd9f72 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
@@ -85,6 +86,7 @@ set(SRC
intern/camera.c
intern/cdderivedmesh.c
intern/cloth.c
+ intern/collection.c
intern/collision.c
intern/colortools.c
intern/constraint.c
@@ -95,12 +97,12 @@ 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/editmesh.c
intern/editmesh_bvh.c
+ intern/editmesh_tangent.c
intern/editstrands.c
intern/effect.c
intern/fcurve.c
@@ -135,6 +137,7 @@ set(SRC
intern/mesh_mapping.c
intern/mesh_remap.c
intern/mesh_sample.c
+ intern/mesh_tangent.c
intern/mesh_validate.c
intern/modifier.c
intern/modifiers_bmesh.c
@@ -143,6 +146,7 @@ set(SRC
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
@@ -158,6 +162,8 @@ set(SRC
intern/pbvh_bmesh.c
intern/pointcache.c
intern/property.c
+ intern/layer.c
+ intern/lightprobe.c
intern/report.c
intern/rigidbody.c
intern/sca.c
@@ -186,6 +192,7 @@ set(SRC
intern/tracking_stabilize.c
intern/tracking_util.c
intern/unit.c
+ intern/workspace.c
intern/world.c
intern/writeavi.c
intern/writeframeserver.c
@@ -215,6 +222,7 @@ set(SRC
BKE_ccg.h
BKE_cdderivedmesh.h
BKE_cloth.h
+ BKE_collection.h
BKE_collision.h
BKE_colortools.h
BKE_constraint.h
@@ -225,12 +233,12 @@ set(SRC
BKE_customdata_file.h
BKE_data_transfer.h
BKE_deform.h
- BKE_depsgraph.h
BKE_displist.h
BKE_dynamicpaint.h
BKE_editstrands.h
BKE_editmesh.h
BKE_editmesh_bvh.h
+ BKE_editmesh_tangent.h
BKE_effect.h
BKE_fcurve.h
BKE_fluidsim.h
@@ -261,12 +269,14 @@ set(SRC
BKE_mesh_mapping.h
BKE_mesh_remap.h
BKE_mesh_sample.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
@@ -276,6 +286,8 @@ set(SRC
BKE_pbvh.h
BKE_pointcache.h
BKE_property.h
+ BKE_layer.h
+ BKE_lightprobe.h
BKE_report.h
BKE_rigidbody.h
BKE_sca.h
@@ -295,11 +307,11 @@ set(SRC
BKE_tracking.h
BKE_unit.h
BKE_utildefines.h
+ BKE_workspace.h
BKE_world.h
BKE_writeavi.h
BKE_writeframeserver.h
- depsgraph_private.h
nla_private.h
tracking_private.h
intern/CCGSubSurf.h
@@ -539,8 +551,8 @@ endif()
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")
#endif()
-if(WITH_LEGACY_DEPSGRAPH)
- add_definitions(-DWITH_LEGACY_DEPSGRAPH)
+if(WITH_DEPSGRAPH_COPY_ON_WRITE)
+ add_definitions(-DWITH_COPY_ON_WRITE)
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 7b3199efb41..00000000000
--- a/source/blender/blenkernel/depsgraph_private.h
+++ /dev/null
@@ -1,159 +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"
-
-/* **** 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);
-
-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 792e9195f12..68bcfa878ac 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf.c
@@ -42,7 +42,7 @@
# include "opensubdiv_converter_capi.h"
#endif
-#include "GL/glew.h"
+#include "GPU_glew.h"
/***/
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
index 65cf899b42b..9c86a22a1f8 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
@@ -43,7 +43,7 @@
#include "opensubdiv_capi.h"
#include "opensubdiv_converter_capi.h"
-#include "GL/glew.h"
+#include "GPU_glew.h"
#include "GPU_extensions.h"
#define OSD_LOG if (false) printf
@@ -993,7 +993,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/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 79e500f8ceb..a26fdd85d52 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -54,11 +54,13 @@
#include "BKE_cdderivedmesh.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_mapping.h"
+#include "BKE_mesh_tangent.h"
#include "BKE_object.h"
#include "BKE_object_deform.h"
#include "BKE_paint.h"
@@ -76,10 +78,12 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm);
#include "BLI_sys_types.h" /* for intptr_t support */
#include "GPU_buffers.h"
-#include "GPU_glew.h"
#include "GPU_shader.h"
+#include "GPU_immediate.h"
#ifdef WITH_OPENSUBDIV
+# include "DEG_depsgraph.h"
+# include "DEG_depsgraph_query.h"
# include "DNA_userdef_types.h"
#endif
@@ -229,7 +233,9 @@ static MPoly *dm_dupPolyArray(DerivedMesh *dm)
static int dm_getNumLoopTri(DerivedMesh *dm)
{
- return dm->looptris.num;
+ const int numlooptris = poly_to_tri_count(dm->getNumPolys(dm), dm->getNumLoops(dm));
+ BLI_assert(ELEM(dm->looptris.num, 0, numlooptris));
+ return numlooptris;
}
static CustomData *dm_getVertCData(DerivedMesh *dm)
@@ -314,7 +320,7 @@ void DM_init(
dm->numPolyData = numPolys;
DM_init_funcs(dm);
-
+
dm->needsFree = 1;
dm->auto_bump_scale = -1.0f;
dm->dirty = 0;
@@ -374,6 +380,7 @@ 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);
@@ -526,7 +533,6 @@ void DM_update_tessface_data(DerivedMesh *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);
@@ -539,7 +545,7 @@ void DM_update_tessface_data(DerivedMesh *dm)
if (!polyindex)
return;
- CustomData_from_bmeshpoly(fdata, pdata, ldata, totface);
+ CustomData_from_bmeshpoly(fdata, ldata, totface);
if (CustomData_has_layer(fdata, CD_MTFACE) ||
CustomData_has_layer(fdata, CD_MCOL) ||
@@ -571,7 +577,7 @@ void DM_update_tessface_data(DerivedMesh *dm)
* 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);
+ BKE_mesh_loops_to_tessdata(fdata, ldata, mface, polyindex, loopindex, totface);
MEM_freeN(loopindex);
}
@@ -589,7 +595,6 @@ void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate)
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);
@@ -606,7 +611,7 @@ void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool 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);
+ CustomData_bmesh_update_active_layers(fdata, ldata);
if (!loopindex) {
loopindex = MEM_mallocN(sizeof(*loopindex) * totface, __func__);
@@ -636,7 +641,7 @@ void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate)
}
if (loopindex)
MEM_freeN(loopindex);
- BLI_assert(CustomData_from_bmeshpoly_test(fdata, pdata, ldata, true));
+ BLI_assert(CustomData_from_bmeshpoly_test(fdata, ldata, true));
}
if (G.debug & G_DEBUG)
@@ -2120,6 +2125,8 @@ static void mesh_calc_modifiers(
DM_update_weight_mcol(ob, dm, draw_flag, NULL, 0, NULL);
append_mask |= CD_MASK_PREVIEW_MLOOPCOL;
}
+
+ dm->deformedOnly = false;
}
isPrevDeform = (mti->type == eModifierTypeType_OnlyDeform);
@@ -2212,6 +2219,12 @@ static void mesh_calc_modifiers(
}
}
+ /* 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);
+ }
+
#ifdef WITH_GAMEENGINE
/* NavMesh - this is a hack but saves having a NavMesh modifier */
if ((ob->gameflag & OB_NAVMESH) && (finaldm->type == DM_TYPE_CDDM)) {
@@ -2282,7 +2295,7 @@ static void editbmesh_calc_modifiers(
{
ModifierData *md, *previewmd = NULL;
float (*deformedVerts)[3] = NULL;
- CustomDataMask mask, previewmask = 0, append_mask = 0;
+ CustomDataMask mask = 0, previewmask = 0, append_mask = 0;
DerivedMesh *dm = NULL, *orcodm = NULL;
int i, numVerts = 0, cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
CDMaskLink *datamasks, *curr;
@@ -2454,6 +2467,8 @@ static void editbmesh_calc_modifiers(
deformedVerts = NULL;
}
}
+
+ dm->deformedOnly = false;
}
/* In case of active preview modifier, make sure preview mask remains for following modifiers. */
@@ -2547,6 +2562,15 @@ 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);
+
+ /* 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 (r_cage && CustomData_has_layer(&(*r_cage)->loopData, CD_NORMAL)) {
+ CustomData_free_layers(&(*r_cage)->loopData, CD_NORMAL, (*r_cage)->numLoopData);
+ }
}
/* add an orco layer if needed */
@@ -2565,15 +2589,29 @@ static void editbmesh_calc_modifiers(
* 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(const Object *ob)
+static bool calc_modifiers_skip_orco(Scene *scene,
+ Object *ob,
+ bool use_render_params)
{
- const ModifierData *last_md = ob->modifiers.last;
+ 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)
+ 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;
+ }
+ /* TODO(sergey): How do we get depsgraph here? */
+ else if ((DEG_get_eval_flags_for_id(scene->depsgraph_legacy, &ob->id) & 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 && U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE;
+ return smd->use_opensubdiv != 0;
}
return false;
}
@@ -2589,7 +2627,7 @@ static void mesh_build_data(
BKE_object_sculpt_modifiers_changed(ob);
#ifdef WITH_OPENSUBDIV
- if (calc_modifiers_skip_orco(ob)) {
+ if (calc_modifiers_skip_orco(scene, ob, false)) {
dataMask &= ~(CD_MASK_ORCO | CD_MASK_PREVIEW_MCOL);
}
#endif
@@ -2624,7 +2662,7 @@ static void editbmesh_build_data(Scene *scene, Object *obedit, BMEditMesh *em, C
BKE_editmesh_free_derivedmesh(em);
#ifdef WITH_OPENSUBDIV
- if (calc_modifiers_skip_orco(obedit)) {
+ if (calc_modifiers_skip_orco(scene, obedit, false)) {
dataMask &= ~(CD_MASK_ORCO | CD_MASK_PREVIEW_MCOL);
}
#endif
@@ -2644,7 +2682,9 @@ static void editbmesh_build_data(Scene *scene, Object *obedit, BMEditMesh *em, C
static CustomDataMask object_get_datamask(const Scene *scene, Object *ob, bool *r_need_mapping)
{
- Object *actob = scene->basact ? scene->basact->object : NULL;
+ /* TODO(sergey): Avoid this linear list lookup. */
+ SceneLayer *sl = BKE_scene_layer_context_active_PLACEHOLDER(scene);
+ Object *actob = sl->basact ? sl->basact->object : NULL;
CustomDataMask mask = ob->customdata_mask;
if (r_need_mapping) {
@@ -2881,9 +2921,6 @@ DerivedMesh *editbmesh_get_derived_base(Object *obedit, BMEditMesh *em, CustomDa
/* get derived mesh from an object, using editbmesh if available. */
DerivedMesh *object_get_derived_final(Object *ob, const bool for_render)
{
- Mesh *me = ob->data;
- BMEditMesh *em = me->edit_btmesh;
-
if (for_render) {
/* TODO(sergey): use proper derived render here in the future. */
return ob->derivedFinal;
@@ -2891,9 +2928,13 @@ DerivedMesh *object_get_derived_final(Object *ob, const bool for_render)
/* only return the editmesh if its from this object because
* we don't a mesh from another object's modifier stack: T43122 */
- if (em && (em->ob == ob)) {
- DerivedMesh *dm = em->derivedFinal;
- return dm;
+ 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;
@@ -3001,234 +3042,6 @@ void mesh_get_mapped_verts_coords(DerivedMesh *dm, float (*r_cos)[3], const int
/* ******************* 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)
@@ -3242,28 +3055,6 @@ void DM_calc_tangents_names_from_gpu(
*r_tangent_names_count = count;
}
-static void DM_calc_loop_tangents_thread(TaskPool *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(
CustomData *uv_data, CustomData *tan_data, int numLoopData,
const char *layer_name)
@@ -3277,202 +3068,26 @@ 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, char *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;
- }
-}
-
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)
{
- if (CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV) == 0)
- return;
- 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];
- char 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 (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_mallocN(sizeof(int) * totface, __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->faceData, CD_NORMAL);
-
- mesh2tangent->orco = NULL;
- mesh2tangent->mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, dm->loopData.layers[index].name);
- if (!mesh2tangent->mloopuv) {
- mesh2tangent->orco = dm->getVertDataArray(dm, CD_ORCO);
- if (!mesh2tangent->orco)
- continue;
- }
- mesh2tangent->tangent = dm->loopData.layers[index].data;
-
- /* Fill the resulting tangent_mask */
- 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);
- 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
-
- int uv_index, tan_index;
-
- /* Update active layer index */
- uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, act_uv_n);
- tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[uv_index].name);
- CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index);
-
- /* Update render layer index */
- uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, ren_uv_n);
- tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[uv_index].name);
- CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index);
- }
+ 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_calc_auto_bump_scale(DerivedMesh *dm)
{
/* int totvert = dm->getNumVerts(dm); */ /* UNUSED */
@@ -3657,15 +3272,15 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
* We do it based on the specified name.
*/
if (gattribs->layer[b].name[0]) {
- layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name);
- type = CD_TANGENT;
+ 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(ldata, CD_MLOOPUV, gattribs->layer[b].name);
- type = CD_MTFACE;
+ layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name);
+ type = CD_TANGENT;
}
if (layer == -1) {
continue;
@@ -3793,7 +3408,6 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
glTexCoord3fv(orco);
else
glVertexAttrib3fv(attribs->orco.gl_index, orco);
- glUniform1i(attribs->orco.gl_info_index, 0);
}
/* uv texture coordinates */
@@ -3812,7 +3426,6 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
glTexCoord2fv(uv);
else
glVertexAttrib2fv(attribs->tface[b].gl_index, uv);
- glUniform1i(attribs->tface[b].gl_info_index, 0);
}
/* vertex colors */
@@ -3828,17 +3441,33 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
}
glVertexAttrib4fv(attribs->mcol[b].gl_index, col);
- glUniform1i(attribs->mcol[b].gl_info_index, GPU_ATTR_INFO_SRGB);
}
/* 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[a * 4 + vert] : zero;
+ const float *tang = (array) ? array[loop] : zero;
glVertexAttrib4fv(attribs->tang[b].gl_index, tang);
}
- glUniform1i(attribs->tang[b].gl_info_index, 0);
+ }
+}
+
+void DM_draw_attrib_vertex_uniforms(const DMVertexAttribs *attribs)
+{
+ int i;
+ if (attribs->totorco) {
+ glUniform1i(attribs->orco.gl_info_index, 0);
+ }
+ for (i = 0; i < attribs->tottface; i++) {
+ glUniform1i(attribs->tface[i].gl_info_index, 0);
+ }
+ for (i = 0; i < attribs->totmcol; i++) {
+ glUniform1i(attribs->mcol[i].gl_info_index, GPU_ATTR_INFO_SRGB);
+ }
+
+ for (i = 0; i < attribs->tottang; i++) {
+ glUniform1i(attribs->tang[i].gl_info_index, 0);
}
}
@@ -3887,7 +3516,6 @@ BLI_INLINE void navmesh_intToCol(int i, float col[3])
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);
@@ -3902,43 +3530,42 @@ static void navmesh_drawColored(DerivedMesh *dm)
dm->drawEdges(dm, 0, 1);
#endif
- /* 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);
- }
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
- 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);
- }
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
+
+ /* Note: batch drawing API would let us share vertices */
+ immBeginAtMost(GWN_PRIM_TRIS, dm->numTessFaceData * 6);
+ for (int a = 0; a < dm->numTessFaceData; a++, mface++) {
+ int pi = polygonIdx[a];
+ if (pi <= 0) {
+ zero_v3(col);
+ }
+ else {
+ navmesh_intToCol(pi, col);
}
- glEnd();
- }
-}
-static void navmesh_DM_drawFacesTex(
- DerivedMesh *dm,
- DMSetDrawOptionsTex UNUSED(setDrawOptions),
- DMCompareDrawOptions UNUSED(compareDrawOptions),
- void *UNUSED(userData), DMDrawFlag UNUSED(flag))
-{
- navmesh_drawColored(dm);
+ immSkipAttrib(color);
+ immVertex3fv(pos, mvert[mface->v1].co);
+ immSkipAttrib(color);
+ immVertex3fv(pos, mvert[mface->v2].co);
+ immAttrib3fv(color, col);
+ immVertex3fv(pos, mvert[mface->v3].co);
+
+ if (mface->v4) {
+ /* this tess face is a quad, so draw the other triangle */
+ immSkipAttrib(color);
+ immVertex3fv(pos, mvert[mface->v1].co);
+ immSkipAttrib(color);
+ immVertex3fv(pos, mvert[mface->v3].co);
+ immAttrib3fv(color, col);
+ immVertex3fv(pos, mvert[mface->v4].co);
+ }
+ }
+ immEnd();
+ immUnbindProgram();
}
static void navmesh_DM_drawFacesSolid(
@@ -3974,7 +3601,6 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm)
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;
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 470098f8c7c..8a94d4b8666 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -44,6 +44,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -54,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"
@@ -64,6 +64,8 @@
#include "BKE_main.h"
#include "BKE_object.h"
+#include "DEG_depsgraph_build.h"
+
#include "BIK_api.h"
#include "RNA_access.h"
@@ -119,7 +121,7 @@ void BKE_action_free(bAction *act)
/* .................................. */
-bAction *BKE_action_copy(Main *bmain, bAction *src)
+bAction *BKE_action_copy(Main *bmain, const bAction *src)
{
bAction *dst = NULL;
bActionGroup *dgrp, *sgrp;
@@ -433,8 +435,8 @@ bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name)
chan->scaleIn = chan->scaleOut = 1.0f;
- chan->limitmin[0] = chan->limitmin[1] = chan->limitmin[2] = -180.0f;
- chan->limitmax[0] = chan->limitmax[1] = chan->limitmax[2] = 180.0f;
+ chan->limitmin[0] = chan->limitmin[1] = chan->limitmin[2] = -M_PI;
+ chan->limitmax[0] = chan->limitmax[1] = chan->limitmax[2] = M_PI;
chan->stiffness[0] = chan->stiffness[1] = chan->stiffness[2] = 0.0f;
chan->ikrotweight = chan->iklinweight = 0.0f;
unit_m4(chan->constinv);
@@ -494,7 +496,7 @@ bPoseChannel *BKE_pose_channel_get_mirrored(const bPose *pose, const char *name)
{
char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, name, false);
+ BLI_string_flip_side_name(name_flip, name, false, sizeof(name_flip));
if (!STREQ(name_flip, name)) {
return BKE_pose_channel_find_name(pose, name_flip);
@@ -522,7 +524,7 @@ const char *BKE_pose_ikparam_get_name(bPose *pose)
*
* \param dst Should be freed already, makes entire duplicate.
*/
-void BKE_pose_copy_data(bPose **dst, bPose *src, const bool copy_constraints)
+void BKE_pose_copy_data(bPose **dst, const bPose *src, const bool copy_constraints)
{
bPose *outPose;
bPoseChannel *pchan;
@@ -577,6 +579,8 @@ void BKE_pose_copy_data(bPose **dst, bPose *src, const bool copy_constraints)
if (pchan->prop) {
pchan->prop = IDP_CopyProperty(pchan->prop);
}
+
+ pchan->draw_data = NULL; /* Drawing cache, no need to copy. */
}
/* for now, duplicate Bone Groups too when doing this */
@@ -765,6 +769,9 @@ 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);
}
void BKE_pose_channel_free(bPoseChannel *pchan)
@@ -1402,7 +1409,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
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c
index 7d3d12ac112..59484724aee 100644
--- a/source/blender/blenkernel/intern/anim.c
+++ b/source/blender/blenkernel/intern/anim.c
@@ -44,7 +44,6 @@
#include "DNA_scene_types.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_key.h"
#include "BKE_main.h"
@@ -54,6 +53,8 @@
#include "BKE_anim.h"
#include "BKE_report.h"
+#include "DEG_depsgraph_build.h"
+
// XXX bad level call...
/* --------------------- */
@@ -201,7 +202,15 @@ bMotionPath *animviz_verify_motionpaths(ReportList *reports, Scene *scene, Objec
mpath->flag |= MOTIONPATH_FLAG_BHEAD;
else
mpath->flag &= ~MOTIONPATH_FLAG_BHEAD;
-
+
+ /* set default custom values */
+ mpath->color[0] = 1.0; /* Red */
+ mpath->color[1] = 0.0;
+ mpath->color[2] = 0.0;
+
+ mpath->line_thickness = 1;
+ mpath->flag |= MOTIONPATH_FLAG_LINES; /* draw lines by default */
+
/* allocate a cache */
mpath->points = MEM_callocN(sizeof(bMotionPathVert) * mpath->length, "bMotionPathVerts");
@@ -275,7 +284,7 @@ void animviz_get_object_motionpaths(Object *ob, ListBase *targets)
/* tweak the object ordering to trick depsgraph into making MotionPath calculations run faster */
static void motionpaths_calc_optimise_depsgraph(Scene *scene, ListBase *targets)
{
- Base *base, *baseNext;
+ BaseLegacy *base, *baseNext;
MPathTarget *mpt;
/* make sure our temp-tag isn't already in use */
@@ -300,53 +309,21 @@ static void motionpaths_calc_optimise_depsgraph(Scene *scene, ListBase *targets)
}
/* "brew me a list that's sorted a bit faster now depsy" */
- DAG_scene_relations_rebuild(G.main, scene);
+ DEG_scene_relations_rebuild(G.main, scene);
}
/* update scene for current frame */
static void motionpaths_calc_update_scene(Scene *scene)
{
-#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(G.main->eval_ctx, G.main, 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(G.main, 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(G.main->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
+ /* 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.
*/
- BKE_scene_update_for_newframe(G.main->eval_ctx, G.main, scene, scene->lay); /* XXX this is the best way we can get anything moving */
-#endif
+ BKE_scene_update_for_newframe(G.main->eval_ctx, G.main, scene);
}
/* ........ */
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 1a5d77bbc07..3b3dff21206 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -43,6 +43,7 @@
#include "BLI_alloca.h"
#include "BLI_dynstr.h"
#include "BLI_listbase.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -59,7 +60,6 @@
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_nla.h"
#include "BKE_global.h"
@@ -69,6 +69,8 @@
#include "BKE_report.h"
#include "BKE_texture.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "nla_private.h"
@@ -92,6 +94,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:
@@ -308,17 +311,19 @@ bool BKE_animdata_copy_id(ID *id_to, ID *id_from, const bool do_action)
return true;
}
-void BKE_animdata_copy_id_action(ID *id)
+void BKE_animdata_copy_id_action(ID *id, const bool set_newid)
{
AnimData *adt = BKE_animdata_from_id(id);
if (adt) {
if (adt->action) {
id_us_min((ID *)adt->action);
- adt->action = BKE_action_copy(G.main, adt->action);
+ adt->action = set_newid ? ID_NEW_SET(adt->action, BKE_action_copy(G.main, adt->action)) :
+ BKE_action_copy(G.main, adt->action);
}
if (adt->tmpact) {
id_us_min((ID *)adt->tmpact);
- adt->tmpact = BKE_action_copy(G.main, adt->tmpact);
+ adt->tmpact = set_newid ? ID_NEW_SET(adt->tmpact, BKE_action_copy(G.main, adt->tmpact)) :
+ BKE_action_copy(G.main, adt->tmpact);
}
}
}
@@ -394,73 +399,6 @@ void BKE_animdata_merge_copy(ID *dst_id, ID *src_id, eAnimData_MergeCopy_Modes a
}
}
-/* Make Local -------------------------------------------- */
-
-static void make_local_strips(ListBase *strips)
-{
- NlaStrip *strip;
-
- for (strip = strips->first; strip; strip = strip->next) {
- if (strip->act) BKE_action_make_local(G.main, strip->act, false);
- if (strip->remap && strip->remap->target) BKE_action_make_local(G.main, strip->remap->target, false);
-
- make_local_strips(&strip->strips);
- }
-}
-
-/* Use local copy instead of linked copy of various ID-blocks */
-void BKE_animdata_make_local(AnimData *adt)
-{
- NlaTrack *nlt;
-
- /* Actions - Active and Temp */
- if (adt->action) BKE_action_make_local(G.main, adt->action, false);
- if (adt->tmpact) BKE_action_make_local(G.main, adt->tmpact, false);
- /* Remaps */
- if (adt->remap && adt->remap->target) BKE_action_make_local(G.main, adt->remap->target, false);
-
- /* Drivers */
- /* TODO: need to remap the ID-targets too? */
-
- /* NLA Data */
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next)
- make_local_strips(&nlt->strips);
-}
-
-
-/* When duplicating data (i.e. objects), drivers referring to the original data will
- * get updated to point to the duplicated data (if drivers belong to the new data)
- */
-void BKE_animdata_relink(AnimData *adt)
-{
- /* sanity check */
- if (adt == NULL)
- return;
-
- /* drivers */
- if (adt->drivers.first) {
- FCurve *fcu;
-
- /* check each driver against all the base paths to see if any should go */
- for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
- ChannelDriver *driver = fcu->driver;
- DriverVar *dvar;
-
- /* driver variables */
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- /* only change the used targets, since the others will need fixing manually anyway */
- DRIVER_TARGETS_USED_LOOPER(dvar)
- {
- if (dtar->id && dtar->id->newid) {
- dtar->id = dtar->id->newid;
- }
- }
- DRIVER_TARGETS_LOOPER_END
- }
- }
- }
-}
-
/* Sub-ID Regrouping ------------------------------------------- */
/**
@@ -1513,7 +1451,7 @@ static bool animsys_store_rna_setting(
if (array_len && array_index >= array_len) {
if (G.debug & G_DEBUG) {
printf("Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d\n",
- (ptr && ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>",
+ (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>",
path, array_index, array_len - 1);
}
}
@@ -1583,7 +1521,8 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
}
case PROP_INT:
{
- const int value_coerce = (int)value;
+ 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);
@@ -1600,15 +1539,17 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
}
case PROP_FLOAT:
{
+ 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) {
- RNA_property_float_set_index(ptr, prop, array_index, value);
+ 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;
}
}
else {
- if (RNA_property_float_get(ptr, prop) != value) {
- RNA_property_float_set(ptr, prop, value);
+ if (RNA_property_float_get(ptr, prop) != value_coerce) {
+ RNA_property_float_set(ptr, prop, value_coerce);
written = true;
}
}
@@ -1657,8 +1598,8 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
/* for cases like duplifarmes it's only a temporary so don't
* notify anyone of updates */
if (!(id->tag & LIB_TAG_ANIM_NO_RECALC)) {
- id->tag |= LIB_TAG_ID_RECALC;
- DAG_id_type_tag(G.main, GS(id->name));
+ BKE_id_tag_set_atomic(id, LIB_TAG_ID_RECALC);
+ DEG_id_type_tag(G.main, GS(id->name));
}
}
@@ -2613,7 +2554,7 @@ static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData
ID *id = ptr->id.data;
if (!(id->tag & LIB_TAG_ANIM_NO_RECALC)) {
id->tag |= LIB_TAG_ID_RECALC;
- DAG_id_type_tag(G.main, GS(id->name));
+ DEG_id_type_tag(G.main, GS(id->name));
}
}
}
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index b1dcc40279f..43fd47981b1 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -114,18 +114,26 @@ static char *blender_version_decimal(const int ver)
* Concatenates path_base, (optional) path_sep and (optional) folder_name into targetpath,
* returning true if result points to a directory.
*/
-static bool test_path(char *targetpath, const char *path_base, const char *path_sep, const char *folder_name)
+static bool test_path(
+ char *targetpath, size_t targetpath_len,
+ const char *path_base, const char *path_sep, const char *folder_name)
{
char tmppath[FILE_MAX];
- if (path_sep) BLI_join_dirfile(tmppath, sizeof(tmppath), path_base, path_sep);
- else BLI_strncpy(tmppath, path_base, sizeof(tmppath));
-
- /* rare cases folder_name is omitted (when looking for ~/.blender/2.xx dir only) */
- if (folder_name)
- BLI_make_file_string("/", targetpath, tmppath, folder_name);
- else
- BLI_strncpy(targetpath, tmppath, sizeof(tmppath));
+ if (path_sep) {
+ BLI_join_dirfile(tmppath, sizeof(tmppath), path_base, path_sep);
+ }
+ else {
+ BLI_strncpy(tmppath, path_base, sizeof(tmppath));
+ }
+
+ /* rare cases folder_name is omitted (when looking for ~/.config/blender/2.xx dir only) */
+ if (folder_name) {
+ BLI_join_dirfile(targetpath, targetpath_len, tmppath, folder_name);
+ }
+ else {
+ BLI_strncpy(targetpath, tmppath, targetpath_len);
+ }
/* FIXME: why is "//" on front of tmppath expanded to "/" (by BLI_join_dirfile)
* if folder_name is specified but not otherwise? */
@@ -179,7 +187,9 @@ static bool test_env_path(char *path, const char *envvar)
* \param ver To construct name of version-specific directory within bprogdir
* \return true if such a directory exists.
*/
-static bool get_path_local(char *targetpath, const char *folder_name, const char *subfolder_name, const int ver)
+static bool get_path_local(
+ char *targetpath, size_t targetpath_len,
+ const char *folder_name, const char *subfolder_name, const int ver)
{
char relfolder[FILE_MAX];
@@ -201,11 +211,12 @@ static bool get_path_local(char *targetpath, const char *folder_name, const char
/* try EXECUTABLE_DIR/2.5x/folder_name - new default directory for local blender installed files */
#ifdef __APPLE__
- static char osx_resourses[FILE_MAX]; /* due new codesign situation in OSX > 10.9.5 we must move the blender_version dir with contents to Resources */
+ /* due new codesign situation in OSX > 10.9.5 we must move the blender_version dir with contents to Resources */
+ static char osx_resourses[FILE_MAX];
sprintf(osx_resourses, "%s../Resources", bprogdir);
- return test_path(targetpath, osx_resourses, blender_version_decimal(ver), relfolder);
+ return test_path(targetpath, targetpath_len, osx_resourses, blender_version_decimal(ver), relfolder);
#else
- return test_path(targetpath, bprogdir, blender_version_decimal(ver), relfolder);
+ return test_path(targetpath, targetpath_len, bprogdir, blender_version_decimal(ver), relfolder);
#endif
}
@@ -219,7 +230,7 @@ static bool is_portable_install(void)
const int ver = BLENDER_VERSION;
char path[FILE_MAX];
- return get_path_local(path, "config", NULL, ver);
+ return get_path_local(path, sizeof(path), "config", NULL, ver);
}
/**
@@ -233,20 +244,22 @@ static bool is_portable_install(void)
* \param ver Blender version, used to construct a subdirectory name
* \return true if it was able to construct such a path.
*/
-static bool get_path_user(char *targetpath, const char *folder_name, const char *subfolder_name, const char *envvar, const int ver)
+static bool get_path_user(
+ char *targetpath, size_t targetpath_len, const char *folder_name, const char *subfolder_name,
+ const char *envvar, const int ver)
{
char user_path[FILE_MAX];
const char *user_base_path;
/* for portable install, user path is always local */
- if (is_portable_install())
- return get_path_local(targetpath, folder_name, subfolder_name, ver);
-
+ if (is_portable_install()) {
+ return get_path_local(targetpath, targetpath_len, folder_name, subfolder_name, ver);
+ }
user_path[0] = '\0';
if (test_env_path(user_path, envvar)) {
if (subfolder_name) {
- return test_path(targetpath, user_path, NULL, subfolder_name);
+ return test_path(targetpath, targetpath_len, user_path, NULL, subfolder_name);
}
else {
BLI_strncpy(targetpath, user_path, FILE_MAX);
@@ -266,10 +279,10 @@ static bool get_path_user(char *targetpath, const char *folder_name, const char
#endif
if (subfolder_name) {
- return test_path(targetpath, user_path, folder_name, subfolder_name);
+ return test_path(targetpath, targetpath_len, user_path, folder_name, subfolder_name);
}
else {
- return test_path(targetpath, user_path, NULL, folder_name);
+ return test_path(targetpath, targetpath_len, user_path, NULL, folder_name);
}
}
@@ -283,7 +296,9 @@ static bool get_path_user(char *targetpath, const char *folder_name, const char
* \param ver Blender version, used to construct a subdirectory name
* \return true if it was able to construct such a path.
*/
-static bool get_path_system(char *targetpath, const char *folder_name, const char *subfolder_name, const char *envvar, const int ver)
+static bool get_path_system(
+ char *targetpath, size_t targetpath_len, const char *folder_name, const char *subfolder_name,
+ const char *envvar, const int ver)
{
char system_path[FILE_MAX];
const char *system_base_path;
@@ -307,13 +322,13 @@ static bool get_path_system(char *targetpath, const char *folder_name, const cha
/* try CWD/release/folder_name */
if (BLI_current_working_dir(cwd, sizeof(cwd))) {
- if (test_path(targetpath, cwd, "release", relfolder)) {
+ if (test_path(targetpath, targetpath_len, cwd, "release", relfolder)) {
return true;
}
}
/* try EXECUTABLE_DIR/release/folder_name */
- if (test_path(targetpath, bprogdir, "release", relfolder))
+ if (test_path(targetpath, targetpath_len, bprogdir, "release", relfolder))
return true;
/* end developer overrides */
@@ -324,7 +339,7 @@ static bool get_path_system(char *targetpath, const char *folder_name, const cha
if (test_env_path(system_path, envvar)) {
if (subfolder_name) {
- return test_path(targetpath, system_path, NULL, subfolder_name);
+ return test_path(targetpath, targetpath_len, system_path, NULL, subfolder_name);
}
else {
BLI_strncpy(targetpath, system_path, FILE_MAX);
@@ -345,57 +360,63 @@ static bool get_path_system(char *targetpath, const char *folder_name, const cha
if (subfolder_name) {
/* try $BLENDERPATH/folder_name/subfolder_name */
- return test_path(targetpath, system_path, folder_name, subfolder_name);
+ return test_path(targetpath, targetpath_len, system_path, folder_name, subfolder_name);
}
else {
/* try $BLENDERPATH/folder_name */
- return test_path(targetpath, system_path, NULL, folder_name);
+ return test_path(targetpath, targetpath_len, system_path, NULL, folder_name);
}
}
-/* get a folder out of the 'folder_id' presets for paths */
-/* returns the path if found, NULL string if not */
-const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder)
+/**
+ * Get a folder out of the 'folder_id' presets for paths.
+ * returns the path if found, NULL string if not
+ *
+ * \param subfolder: The name of a directory to check for,
+ * this may contain path separators but must resolve to a directory, checked with #BLI_is_dir.
+ */
+const char *BKE_appdir_folder_id_ex(
+ const int folder_id, const char *subfolder,
+ char *path, size_t path_len)
{
const int ver = BLENDER_VERSION;
- static char path[FILE_MAX] = "";
-
+
switch (folder_id) {
case BLENDER_DATAFILES: /* general case */
- if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
- if (get_path_local(path, "datafiles", subfolder, ver)) break;
- if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break;
+ if (get_path_user(path, path_len, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
+ if (get_path_local(path, path_len, "datafiles", subfolder, ver)) break;
+ if (get_path_system(path, path_len, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break;
return NULL;
case BLENDER_USER_DATAFILES:
- if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
+ if (get_path_user(path, path_len, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
return NULL;
case BLENDER_SYSTEM_DATAFILES:
- if (get_path_local(path, "datafiles", subfolder, ver)) break;
- if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break;
+ if (get_path_local(path, path_len, "datafiles", subfolder, ver)) break;
+ if (get_path_system(path, path_len, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break;
return NULL;
case BLENDER_USER_AUTOSAVE:
- if (get_path_user(path, "autosave", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
+ if (get_path_user(path, path_len, "autosave", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
return NULL;
case BLENDER_USER_CONFIG:
- if (get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG", ver)) break;
+ if (get_path_user(path, path_len, "config", subfolder, "BLENDER_USER_CONFIG", ver)) break;
return NULL;
case BLENDER_USER_SCRIPTS:
- if (get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver)) break;
+ if (get_path_user(path, path_len, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver)) break;
return NULL;
case BLENDER_SYSTEM_SCRIPTS:
- if (get_path_local(path, "scripts", subfolder, ver)) break;
- if (get_path_system(path, "scripts", subfolder, "BLENDER_SYSTEM_SCRIPTS", ver)) break;
+ if (get_path_local(path, path_len, "scripts", subfolder, ver)) break;
+ if (get_path_system(path, path_len, "scripts", subfolder, "BLENDER_SYSTEM_SCRIPTS", ver)) break;
return NULL;
case BLENDER_SYSTEM_PYTHON:
- if (get_path_local(path, "python", subfolder, ver)) break;
- if (get_path_system(path, "python", subfolder, "BLENDER_SYSTEM_PYTHON", ver)) break;
+ if (get_path_local(path, path_len, "python", subfolder, ver)) break;
+ if (get_path_system(path, path_len, "python", subfolder, "BLENDER_SYSTEM_PYTHON", ver)) break;
return NULL;
default:
@@ -406,6 +427,13 @@ const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder)
return path;
}
+const char *BKE_appdir_folder_id(
+ const int folder_id, const char *subfolder)
+{
+ static char path[FILE_MAX] = "";
+ return BKE_appdir_folder_id_ex(folder_id, subfolder, path, sizeof(path));
+}
+
/**
* Returns the path to a folder in the user area without checking that it actually exists first.
*/
@@ -416,16 +444,16 @@ const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *su
switch (folder_id) {
case BLENDER_USER_DATAFILES:
- get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver);
+ get_path_user(path, sizeof(path), "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver);
break;
case BLENDER_USER_CONFIG:
- get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG", ver);
+ get_path_user(path, sizeof(path), "config", subfolder, "BLENDER_USER_CONFIG", ver);
break;
case BLENDER_USER_AUTOSAVE:
- get_path_user(path, "autosave", subfolder, "BLENDER_USER_AUTOSAVE", ver);
+ get_path_user(path, sizeof(path), "autosave", subfolder, "BLENDER_USER_AUTOSAVE", ver);
break;
case BLENDER_USER_SCRIPTS:
- get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver);
+ get_path_user(path, sizeof(path), "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver);
break;
default:
BLI_assert(0);
@@ -469,13 +497,13 @@ const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, con
bool ok;
switch (folder_id) {
case BLENDER_RESOURCE_PATH_USER:
- ok = get_path_user(path, NULL, NULL, NULL, ver);
+ ok = get_path_user(path, sizeof(path), NULL, NULL, NULL, ver);
break;
case BLENDER_RESOURCE_PATH_LOCAL:
- ok = get_path_local(path, NULL, NULL, ver);
+ ok = get_path_local(path, sizeof(path), NULL, NULL, ver);
break;
case BLENDER_RESOURCE_PATH_SYSTEM:
- ok = get_path_system(path, NULL, NULL, NULL, ver);
+ ok = get_path_system(path, sizeof(path), NULL, NULL, NULL, ver);
break;
default:
path[0] = '\0'; /* in case do_check is false */
@@ -655,6 +683,48 @@ bool BKE_appdir_program_python_search(
return is_found;
}
+static const char *app_template_directory_search[2] = {
+ "startup" SEP_STR "bl_app_templates_user",
+ "startup" SEP_STR "bl_app_templates_system",
+};
+
+static const int app_template_directory_id[2] = {
+ BLENDER_USER_SCRIPTS,
+ BLENDER_SYSTEM_SCRIPTS,
+};
+
+/**
+ * Return true if templates exist
+ */
+bool BKE_appdir_app_template_any(void)
+{
+ char temp_dir[FILE_MAX];
+ for (int i = 0; i < 2; i++) {
+ if (BKE_appdir_folder_id_ex(
+ app_template_directory_id[i], app_template_directory_search[i],
+ temp_dir, sizeof(temp_dir)))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool BKE_appdir_app_template_id_search(const char *app_template, char *path, size_t path_len)
+{
+ for (int i = 0; i < 2; i++) {
+ char subdir[FILE_MAX];
+ BLI_join_dirfile(subdir, sizeof(subdir), app_template_directory_search[i], app_template);
+ if (BKE_appdir_folder_id_ex(
+ app_template_directory_id[i], subdir,
+ path, path_len))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
/**
* Gets the temp directory when blender first runs.
* If the default path is not found, use try $TEMP
@@ -713,7 +783,8 @@ static void where_is_temp(char *fullname, char *basename, const size_t maxlen, c
BLI_add_slash(fullname);
#ifdef WIN32
if (userdir && userdir != fullname) {
- BLI_strncpy(userdir, fullname, maxlen); /* also set user pref to show %TEMP%. /tmp/ is just plain confusing for Windows users. */
+ /* also set user pref to show %TEMP%. /tmp/ is just plain confusing for Windows users. */
+ BLI_strncpy(userdir, fullname, maxlen);
}
#endif
}
@@ -755,7 +826,6 @@ static void where_is_temp(char *fullname, char *basename, const size_t maxlen, c
void BKE_tempdir_init(char *userdir)
{
where_is_temp(btempdir_session, btempdir_base, FILE_MAX, userdir);
-;
}
/**
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index c644fe09364..38b98f1eee6 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -60,7 +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"
@@ -87,6 +86,7 @@ bArmature *BKE_armature_add(Main *bmain, const char *name)
arm->deformflag = ARM_DEF_VGROUP | ARM_DEF_ENVELOPE;
arm->flag = ARM_COL_CUSTOM; /* custom bone-group colors */
arm->layer = 1;
+ arm->ghostsize = 1;
return arm;
}
@@ -149,7 +149,7 @@ void BKE_armature_make_local(Main *bmain, bArmature *arm, const bool lib_local)
BKE_id_make_local_generic(bmain, &arm->id, true, lib_local);
}
-static void copy_bonechildren(Bone *newBone, Bone *oldBone, Bone *actBone, Bone **newActBone)
+static void copy_bonechildren(Bone *newBone, const Bone *oldBone, const Bone *actBone, Bone **newActBone)
{
Bone *curBone, *newChildBone;
@@ -171,7 +171,7 @@ static void copy_bonechildren(Bone *newBone, Bone *oldBone, Bone *actBone, Bone
}
}
-bArmature *BKE_armature_copy(Main *bmain, bArmature *arm)
+bArmature *BKE_armature_copy(Main *bmain, const bArmature *arm)
{
bArmature *newArm;
Bone *oldBone, *newBone;
@@ -981,6 +981,11 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
return;
}
+ if ((armOb->pose->flag & POSE_RECALC) != 0) {
+ printf("ERROR! Trying to evaluate influence of armature '%s' which needs Pose recalc!", armOb->id.name);
+ BLI_assert(0);
+ }
+
invert_m4_m4(obinv, target->obmat);
copy_m4_m4(premat, target->obmat);
mul_m4_m4m4(postmat, obinv, armOb->obmat);
@@ -1036,6 +1041,17 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
if (use_dverts) {
defnrToPC = MEM_callocN(sizeof(*defnrToPC) * defbase_tot, "defnrToBone");
defnrToPCIndex = MEM_callocN(sizeof(*defnrToPCIndex) * defbase_tot, "defnrToIndex");
+ /* TODO(sergey): Some considerations here:
+ *
+ * - Make it more generic function, maybe even keep together with chanhash.
+ * - Check whether keeping this consistent across frames gives speedup.
+ * - Don't use hash for small armatures.
+ */
+ GHash *idx_hash = BLI_ghash_ptr_new("pose channel index by name");
+ int pchan_index = 0;
+ for (pchan = armOb->pose->chanbase.first; pchan != NULL; pchan = pchan->next, ++pchan_index) {
+ BLI_ghash_insert(idx_hash, pchan, SET_INT_IN_POINTER(pchan_index));
+ }
for (i = 0, dg = target->defbase.first; dg; i++, dg = dg->next) {
defnrToPC[i] = BKE_pose_channel_find_name(armOb->pose, dg->name);
/* exclude non-deforming bones */
@@ -1044,10 +1060,11 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
defnrToPC[i] = NULL;
}
else {
- defnrToPCIndex[i] = BLI_findindex(&armOb->pose->chanbase, defnrToPC[i]);
+ defnrToPCIndex[i] = GET_INT_FROM_POINTER(BLI_ghash_lookup(idx_hash, defnrToPC[i]));
}
}
}
+ BLI_ghash_free(idx_hash, NULL, NULL);
}
}
}
@@ -1794,6 +1811,7 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected
/* copy posechannel to temp, but restore important pointers */
pchanw = *pchanp;
+ pchanw.bone = pchan->bone;
pchanw.prev = pchan->prev;
pchanw.next = pchan->next;
pchanw.parent = pchan->parent;
@@ -1960,13 +1978,6 @@ void BKE_pose_rebuild(Object *ob, bArmature *arm)
BKE_pose_update_constraint_flags(ob->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)
- DAG_pose_sort(ob);
-#endif
-
ob->pose->flag &= ~POSE_RECALC;
ob->pose->flag |= POSE_WAS_REBUILT;
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index aebd564ca58..73e9f5d0774 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -41,7 +41,6 @@
#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_scene.h"
@@ -51,13 +50,7 @@
#include "BKE_global.h"
#include "BKE_main.h"
-#include "DEG_depsgraph.h"
-
-#ifdef WITH_LEGACY_DEPSGRAPH
-# define DEBUG_PRINT if (!DEG_depsgraph_use_legacy() && G.debug & G_DEBUG_DEPSGRAPH) printf
-#else
-# define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
-#endif
+#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
/* ********************** SPLINE IK SOLVER ******************* */
@@ -558,7 +551,7 @@ void BKE_splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_roo
/* *************** Depsgraph evaluation callbacks ************ */
-void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_eval_init(struct EvaluationContext *UNUSED(eval_ctx),
Scene *scene,
Object *ob,
bPose *pose)
@@ -592,7 +585,7 @@ void BKE_pose_eval_init(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 EvaluationContext *UNUSED(eval_ctx),
Scene *scene,
Object *ob,
bPoseChannel *pchan)
@@ -617,9 +610,9 @@ void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx),
/* pass */
}
else {
- /* TODO(sergey): Use time source node for time. */
- float ctime = BKE_scene_frame_get(scene); /* not accurate... */
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);
}
}
@@ -627,11 +620,11 @@ void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx),
}
}
-void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_constraints_evaluate(struct EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
Object *ob,
bPoseChannel *pchan)
{
- Scene *scene = G.main->scene.first;
DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name);
bArmature *arm = (bArmature *)ob->data;
if (arm->flag & ARM_RESTPOS) {
@@ -641,14 +634,14 @@ void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx),
/* IK are being solved separately/ */
}
else {
- float ctime = BKE_scene_frame_get(scene); /* not accurate... */
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);
}
}
}
-void BKE_pose_bone_done(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_bone_done(struct EvaluationContext *UNUSED(eval_ctx),
bPoseChannel *pchan)
{
float imat[4][4];
@@ -659,7 +652,7 @@ void BKE_pose_bone_done(EvaluationContext *UNUSED(eval_ctx),
}
}
-void BKE_pose_iktree_evaluate(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_iktree_evaluate(struct EvaluationContext *UNUSED(eval_ctx),
Scene *scene,
Object *ob,
bPoseChannel *rootchan)
@@ -669,7 +662,7 @@ void BKE_pose_iktree_evaluate(EvaluationContext *UNUSED(eval_ctx),
BIK_execute_tree(scene, ob, rootchan, ctime);
}
-void BKE_pose_splineik_evaluate(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_splineik_evaluate(struct EvaluationContext *UNUSED(eval_ctx),
Scene *scene,
Object *ob,
bPoseChannel *rootchan)
@@ -679,7 +672,7 @@ void BKE_pose_splineik_evaluate(EvaluationContext *UNUSED(eval_ctx),
BKE_splineik_execute_tree(scene, ob, rootchan, ctime);
}
-void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_eval_flush(struct EvaluationContext *UNUSED(eval_ctx),
Scene *scene,
Object *ob,
bPose *UNUSED(pose))
@@ -694,7 +687,7 @@ void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx),
ob->recalc &= ~OB_RECALC_ALL;
}
-void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob)
+void BKE_pose_eval_proxy_copy(struct EvaluationContext *UNUSED(eval_ctx), Object *ob)
{
BLI_assert(ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from != NULL);
DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
@@ -702,4 +695,8 @@ void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob)
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.
+ */
+ ob->recalc &= ~OB_RECALC_ALL;
}
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index 0805335da66..1f75c85291d 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -49,11 +49,12 @@
#include "BKE_blender_version.h" /* own include */
#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_node.h"
#include "BKE_report.h"
@@ -61,6 +62,8 @@
#include "BKE_screen.h"
#include "BKE_sequencer.h"
+#include "DEG_depsgraph.h"
+
#include "RE_pipeline.h"
#include "RE_render_ext.h"
@@ -84,8 +87,9 @@ void BKE_blender_free(void)
BKE_spacetypes_free(); /* after free main, it uses space callbacks */
IMB_exit();
+ BKE_cachefiles_exit();
BKE_images_exit();
- DAG_exit();
+ DEG_free_node_types();
BKE_brush_system_exit();
RE_texture_rng_exit();
@@ -94,10 +98,24 @@ void BKE_blender_free(void)
BKE_sequencer_cache_destruct();
IMB_moviecache_destruct();
+
+ BKE_layer_exit();
free_nodesystem();
}
+void BKE_blender_version_string(char *version_str, size_t maxncpy, short version, short subversion, bool v_prefix, bool include_subversion)
+{
+ const char *prefix = v_prefix ? "v" : "";
+
+ if (include_subversion && subversion > 0) {
+ BLI_snprintf(version_str, maxncpy, "%s%d.%02d.%d", prefix, version / 100, version % 100, subversion);
+ }
+ else {
+ BLI_snprintf(version_str, maxncpy, "%s%d.%02d", prefix, version / 100, version % 100);
+ }
+}
+
void BKE_blender_globals_init(void)
{
memset(&G, 0, sizeof(Global));
@@ -108,10 +126,7 @@ void BKE_blender_globals_init(void)
strcpy(G.ima, "//");
- if (BLENDER_SUBVERSION)
- BLI_snprintf(versionstr, sizeof(versionstr), "v%d.%02d.%d", BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION);
- else
- BLI_snprintf(versionstr, sizeof(versionstr), "v%d.%02d", BLENDER_VERSION / 100, BLENDER_VERSION % 100);
+ BKE_blender_version_string(versionstr, sizeof(versionstr), BLENDER_VERSION, BLENDER_SUBVERSION, true, true);
#ifndef WITH_PYTHON_SECURITY /* default */
G.f |= G_SCRIPT_AUTOEXEC;
@@ -139,20 +154,18 @@ static void keymap_item_free(wmKeyMapItem *kmi)
MEM_freeN(kmi->ptr);
}
-/**
- * When loading a new userdef from file,
- * or when exiting Blender.
- */
-void BKE_blender_userdef_free(void)
+void BKE_blender_userdef_set_data(UserDef *userdef)
+{
+ /* only here free userdef themes... */
+ BKE_blender_userdef_free_data(&U);
+ U = *userdef;
+}
+
+static void userdef_free_keymaps(UserDef *userdef)
{
- wmKeyMap *km;
- wmKeyMapItem *kmi;
- wmKeyMapDiffItem *kmdi;
- bAddon *addon, *addon_next;
- uiFont *font;
-
- for (km = U.user_keymaps.first; km; km = km->next) {
- for (kmdi = km->diff_items.first; kmdi; kmdi = kmdi->next) {
+ for (wmKeyMap *km = userdef->user_keymaps.first, *km_next; km; km = km_next) {
+ km_next = km->next;
+ for (wmKeyMapDiffItem *kmdi = km->diff_items.first; kmdi; kmdi = kmdi->next) {
if (kmdi->add_item) {
keymap_item_free(kmdi->add_item);
MEM_freeN(kmdi->add_item);
@@ -163,14 +176,21 @@ void BKE_blender_userdef_free(void)
}
}
- for (kmi = km->items.first; kmi; kmi = kmi->next)
+ for (wmKeyMapItem *kmi = km->items.first; kmi; kmi = kmi->next) {
keymap_item_free(kmi);
+ }
BLI_freelistN(&km->diff_items);
BLI_freelistN(&km->items);
+
+ MEM_freeN(km);
}
-
- for (addon = U.addons.first; addon; addon = addon_next) {
+ BLI_listbase_clear(&userdef->user_keymaps);
+}
+
+static void userdef_free_addons(UserDef *userdef)
+{
+ for (bAddon *addon = userdef->addons.first, *addon_next; addon; addon = addon_next) {
addon_next = addon->next;
if (addon->prop) {
IDP_FreeProperty(addon->prop);
@@ -178,32 +198,73 @@ void BKE_blender_userdef_free(void)
}
MEM_freeN(addon);
}
+ BLI_listbase_clear(&userdef->addons);
+}
+
+/**
+ * When loading a new userdef from file,
+ * or when exiting Blender.
+ */
+void BKE_blender_userdef_free_data(UserDef *userdef)
+{
+#define U _invalid_access_ /* ensure no accidental global access */
+#ifdef U /* quiet warning */
+#endif
- for (font = U.uifonts.first; font; font = font->next) {
+ userdef_free_keymaps(userdef);
+ userdef_free_addons(userdef);
+
+ for (uiFont *font = userdef->uifonts.first; font; font = font->next) {
BLF_unload_id(font->blf_id);
}
BLF_default_set(-1);
- BLI_freelistN(&U.autoexec_paths);
+ BLI_freelistN(&userdef->autoexec_paths);
+
+ BLI_freelistN(&userdef->uistyles);
+ BLI_freelistN(&userdef->uifonts);
+ BLI_freelistN(&userdef->themes);
- BLI_freelistN(&U.uistyles);
- BLI_freelistN(&U.uifonts);
- BLI_freelistN(&U.themes);
- BLI_freelistN(&U.user_keymaps);
+#undef U
}
/**
- * Handle changes in settings that need refreshing.
+ * Write U from userdef.
+ * This function defines which settings a template will override for the user preferences.
*/
-void BKE_blender_userdef_refresh(void)
+void BKE_blender_userdef_set_app_template(UserDef *userdef)
{
- /* prevent accidents */
- if (U.pixelsize == 0) U.pixelsize = 1;
-
- BLF_default_dpi(U.pixelsize * U.dpi);
- U.widget_unit = (U.pixelsize * U.dpi * 20 + 36) / 72;
+ /* TODO:
+ * - keymaps
+ * - various minor settings (add as needed).
+ */
+
+#define LIST_OVERRIDE(id) { \
+ BLI_freelistN(&U.id); \
+ BLI_movelisttolist(&U.id, &userdef->id); \
+} ((void)0)
+
+#define MEMCPY_OVERRIDE(id) \
+ memcpy(U.id, userdef->id, sizeof(U.id));
+
+ /* for some types we need custom free functions */
+ userdef_free_addons(&U);
+ userdef_free_keymaps(&U);
+
+ LIST_OVERRIDE(uistyles);
+ LIST_OVERRIDE(uifonts);
+ LIST_OVERRIDE(themes);
+ LIST_OVERRIDE(addons);
+ LIST_OVERRIDE(user_keymaps);
+
+ MEMCPY_OVERRIDE(light);
+
+ MEMCPY_OVERRIDE(font_path_ui);
+ MEMCPY_OVERRIDE(font_path_ui_mono);
+#undef LIST_OVERRIDE
+#undef MEMCPY_OVERRIDE
}
/* ***************** testing for break ************* */
@@ -232,7 +293,7 @@ int BKE_blender_test_break(void)
* \note Don't use MEM_mallocN so functions can be registered at any time.
* \{ */
-struct AtExitData {
+static struct AtExitData {
struct AtExitData *next;
void (*func)(void *user_data);
diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c
index ad01fac2144..206b0f2a8cc 100644
--- a/source/blender/blenkernel/intern/blender_copybuffer.c
+++ b/source/blender/blenkernel/intern/blender_copybuffer.c
@@ -44,12 +44,13 @@
#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_library.h"
#include "BKE_main.h"
#include "BKE_scene.h"
+#include "DEG_depsgraph_build.h"
+
#include "BLO_readfile.h"
#include "BLO_writefile.h"
@@ -85,6 +86,31 @@ bool BKE_copybuffer_save(Main *bmain_src, const char *filename, ReportList *repo
return retval;
}
+bool BKE_copybuffer_read(Main *bmain_dst, const char *libname, ReportList *reports)
+{
+ BlendHandle *bh = BLO_blendhandle_from_file(libname, reports);
+ if (bh == NULL) {
+ /* Error reports will have been made by BLO_blendhandle_from_file(). */
+ return false;
+ }
+ /* 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);
+ /* Mark all library linked objects to be updated. */
+ BKE_main_lib_objects_recalc_all(bmain_dst);
+ IMB_colormanagement_check_file_config(bmain_dst);
+ /* Append, rather than linking. */
+ Library *lib = BLI_findstring(&bmain_dst->library, libname, offsetof(Library, filepath));
+ BKE_library_make_local(bmain_dst, lib, NULL, true, false);
+ /* Important we unset, otherwise these object wont
+ * link into other scenes from this blend file.
+ */
+ BKE_main_id_tag_all(bmain_dst, LIB_TAG_PRE_EXISTING, false);
+ BLO_blendhandle_close(bh);
+ return true;
+}
+
/**
* \return Success.
*/
@@ -92,7 +118,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);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Main *mainl = NULL;
Library *lib;
BlendHandle *bh;
@@ -117,7 +143,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, scene, sl);
/* mark all library linked objects to be updated */
BKE_main_lib_objects_recalc_all(bmain);
@@ -125,14 +151,14 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re
/* append, rather than linking */
lib = BLI_findstring(&bmain->library, libname, offsetof(Library, filepath));
- BKE_library_make_local(bmain, lib, true, false);
+ BKE_library_make_local(bmain, lib, NULL, true, false);
/* important we unset, otherwise these object wont
* 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 */
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
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 d64bf7ecf43..b8f46756445 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -56,7 +56,6 @@
#include "BKE_appdir.h"
#include "BKE_brush.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_main.h"
@@ -66,6 +65,8 @@
#include "BLO_readfile.h"
#include "BLO_writefile.h"
+#include "DEG_depsgraph.h"
+
/* -------------------------------------------------------------------- */
/** \name Global Undo
@@ -108,9 +109,9 @@ static int read_undosave(bContext *C, UndoElem *uel)
G.fileflags |= G_FILE_NO_UI;
if (UNDO_DISK)
- success = (BKE_blendfile_read(C, uel->str, NULL) != BKE_BLENDFILE_READ_FAIL);
+ success = (BKE_blendfile_read(C, uel->str, NULL, 0) != BKE_BLENDFILE_READ_FAIL);
else
- success = BKE_blendfile_read_from_memfile(C, &uel->memfile, NULL);
+ success = BKE_blendfile_read_from_memfile(C, &uel->memfile, NULL, 0);
/* restore */
BLI_strncpy(G.main->name, mainstr, sizeof(G.main->name)); /* restore */
@@ -118,7 +119,7 @@ static int read_undosave(bContext *C, UndoElem *uel)
if (success) {
/* important not to update time here, else non keyed tranforms are lost */
- DAG_on_visible_update(G.main, false);
+ DEG_on_visible_update(G.main, false);
}
return success;
@@ -319,6 +320,13 @@ const char *BKE_undo_get_name(int nr, bool *r_active)
return NULL;
}
+/* return the name of the last item */
+const char *BKE_undo_get_name_last(void)
+{
+ UndoElem *uel = undobase.last;
+ return (uel ? uel->name : NULL);
+}
+
/**
* Saves .blend using undo buffer.
*
@@ -382,7 +390,7 @@ bool BKE_undo_save_file(const char *filename)
Main *BKE_undo_get_main(Scene **r_scene)
{
Main *mainp = NULL;
- BlendFileData *bfd = BLO_read_from_memfile(G.main, G.main->name, &curundo->memfile, NULL);
+ BlendFileData *bfd = BLO_read_from_memfile(G.main, G.main->name, &curundo->memfile, NULL, BLO_READ_SKIP_NONE);
if (bfd) {
mainp = bfd->main;
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index bedf262541f..6ac41c72815 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;
}
}
@@ -121,7 +124,12 @@ static void setup_app_data(
LOAD_UNDO,
} mode;
- if (BLI_listbase_is_empty(&bfd->main->screen)) {
+ /* may happen with library files - UNDO file should never have NULL cursccene... */
+ if (ELEM(NULL, bfd->curscreen, bfd->curscene)) {
+ BKE_report(reports, RPT_WARNING, "Library file, loading empty scene");
+ mode = LOAD_UI_OFF;
+ }
+ else if (BLI_listbase_is_empty(&bfd->main->screen)) {
mode = LOAD_UNDO;
}
else if (G.fileflags & G_FILE_NO_UI) {
@@ -131,14 +139,6 @@ static void setup_app_data(
mode = LOAD_UI;
}
- if (mode != LOAD_UNDO) {
- /* may happen with library files */
- if (ELEM(NULL, bfd->curscreen, bfd->curscene)) {
- BKE_report(reports, RPT_WARNING, "Library file, loading empty scene");
- mode = LOAD_UI_OFF;
- }
- }
-
/* Free all render results, without this stale data gets displayed after loading files */
if (mode != LOAD_UNDO) {
RE_FreeAllRenderResults();
@@ -165,17 +165,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;
+ SceneLayer *cur_render_layer;
bool track_undo_scene;
/* comes from readfile.c */
SWAP(ListBase, G.main->wm, bfd->main->wm);
+ SWAP(ListBase, G.main->workspaces, bfd->main->workspaces);
SWAP(ListBase, G.main->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_render_layer = bfd->cur_render_layer;
track_undo_scene = (mode == LOAD_UNDO && curscreen && curscene && bfd->main->wm.first);
@@ -186,32 +191,31 @@ static void setup_app_data(
if (curscene == NULL) {
curscene = BKE_scene_add(bfd->main, "Empty");
}
+ if (cur_render_layer == NULL) {
+ /* fallback to scene layer */
+ cur_render_layer = BKE_scene_layer_from_scene_get(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_render_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);
+ BKE_screen_view3d_scene_sync(curscreen, curscene);
}
}
}
@@ -230,7 +234,7 @@ static void setup_app_data(
if (bfd->user) {
/* only here free userdef themes... */
- BKE_blender_userdef_free();
+ BKE_blender_userdef_free_data(&U);
U = *bfd->user;
@@ -265,12 +269,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 (!G.main->scene.first)
BKE_scene_add(G.main, "Empty");
CTX_data_scene_set(C, G.main->scene.first);
- CTX_wm_screen(C)->scene = CTX_data_scene(C);
+ win->scene = CTX_data_scene(C);
curscene = CTX_data_scene(C);
}
@@ -319,12 +325,10 @@ static void setup_app_data(
wmWindowManager *wm = G.main->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(G.main, win->screen->scene);
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (win->scene && win->scene != curscene) {
+ BKE_scene_set_background(G.main, win->scene);
+ }
}
}
}
@@ -352,17 +356,23 @@ static int handle_subversion_warning(Main *main, ReportList *reports)
return 1;
}
-int BKE_blendfile_read(bContext *C, const char *filepath, ReportList *reports)
+int BKE_blendfile_read(
+ bContext *C, const char *filepath,
+ ReportList *reports, int skip_flags)
{
BlendFileData *bfd;
int retval = BKE_BLENDFILE_READ_OK;
- if (strstr(filepath, BLENDER_STARTUP_FILE) == NULL) /* don't print user-pref loading */
- printf("read blend: %s\n", filepath);
+ /* don't print user-pref loading */
+ if (strstr(filepath, BLENDER_STARTUP_FILE) == NULL) {
+ printf("Read blend: %s\n", filepath);
+ }
- bfd = BLO_read_from_file(filepath, reports);
+ bfd = BLO_read_from_file(filepath, reports, skip_flags);
if (bfd) {
- if (bfd->user) retval = BKE_BLENDFILE_READ_OK_USERPREFS;
+ if (bfd->user) {
+ retval = BKE_BLENDFILE_READ_OK_USERPREFS;
+ }
if (0 == handle_subversion_warning(bfd->main, reports)) {
BKE_main_free(bfd->main);
@@ -382,11 +392,11 @@ int BKE_blendfile_read(bContext *C, const char *filepath, ReportList *reports)
bool BKE_blendfile_read_from_memory(
bContext *C, const void *filebuf, int filelength,
- ReportList *reports, bool update_defaults)
+ ReportList *reports, int skip_flags, bool update_defaults)
{
BlendFileData *bfd;
- bfd = BLO_read_from_memory(filebuf, filelength, reports);
+ bfd = BLO_read_from_memory(filebuf, filelength, reports, skip_flags);
if (bfd) {
if (update_defaults)
BLO_update_defaults_startup_blend(bfd->main);
@@ -402,17 +412,17 @@ bool BKE_blendfile_read_from_memory(
/* memfile is the undo buffer */
bool BKE_blendfile_read_from_memfile(
bContext *C, struct MemFile *memfile,
- ReportList *reports)
+ ReportList *reports, int skip_flags)
{
BlendFileData *bfd;
- bfd = BLO_read_from_memfile(CTX_data_main(C), G.main->name, memfile, reports);
+ bfd = BLO_read_from_memfile(CTX_data_main(C), G.main->name, memfile, reports, skip_flags);
if (bfd) {
/* remove the unused screens and wm */
while (bfd->main->wm.first)
- BKE_libblock_free_ex(bfd->main, bfd->main->wm.first, true);
+ BKE_libblock_free(bfd->main, bfd->main->wm.first);
while (bfd->main->screen.first)
- BKE_libblock_free_ex(bfd->main, bfd->main->screen.first, true);
+ BKE_libblock_free(bfd->main, bfd->main->screen.first);
setup_app_data(C, bfd, "<memory1>", reports);
}
@@ -423,32 +433,76 @@ bool BKE_blendfile_read_from_memfile(
return (bfd != NULL);
}
+/**
+ * Utility to make a file 'empty' used for startup to optionally give an empty file.
+ * Handy for tests.
+ */
+void BKE_blendfile_read_make_empty(bContext *C)
+{
+ Main *bmain = CTX_data_main(C);
+
+ ListBase *lbarray[MAX_LIBARRAY];
+ ID *id;
+ int a;
+
+ a = set_listbasepointers(bmain, lbarray);
+ while (a--) {
+ id = lbarray[a]->first;
+ if (id != NULL) {
+ if (ELEM(GS(id->name), ID_SCE, ID_SCR, ID_WM)) {
+ continue;
+ }
+ while ((id = lbarray[a]->first)) {
+ BKE_libblock_delete(bmain, id);
+ }
+ }
+ }
+}
+
/* only read the userdef from a .blend */
-int BKE_blendfile_read_userdef(const char *filepath, ReportList *reports)
+UserDef *BKE_blendfile_userdef_read(const char *filepath, ReportList *reports)
{
BlendFileData *bfd;
- int retval = BKE_BLENDFILE_READ_FAIL;
+ UserDef *userdef = NULL;
- bfd = BLO_read_from_file(filepath, reports);
+ bfd = BLO_read_from_file(filepath, reports, BLO_READ_SKIP_ALL & ~BLO_READ_SKIP_USERDEF);
if (bfd) {
if (bfd->user) {
- retval = BKE_BLENDFILE_READ_OK_USERPREFS;
+ userdef = bfd->user;
+ }
+ BKE_main_free(bfd->main);
+ MEM_freeN(bfd);
+ }
+
+ return userdef;
+}
- /* only here free userdef themes... */
- BKE_blender_userdef_free();
- U = *bfd->user;
- MEM_freeN(bfd->user);
+UserDef *BKE_blendfile_userdef_read_from_memory(
+ const void *filebuf, int filelength,
+ ReportList *reports)
+{
+ BlendFileData *bfd;
+ UserDef *userdef = NULL;
+
+ bfd = BLO_read_from_memory(filebuf, filelength, reports, BLO_READ_SKIP_ALL & ~BLO_READ_SKIP_USERDEF);
+ if (bfd) {
+ if (bfd->user) {
+ userdef = bfd->user;
}
BKE_main_free(bfd->main);
MEM_freeN(bfd);
}
+ else {
+ BKE_reports_prepend(reports, "Loading failed: ");
+ }
- return retval;
+ return userdef;
}
+
/* only write the userdef in a .blend */
-int BKE_blendfile_write_userdef(const char *filepath, ReportList *reports)
+int BKE_blendfile_userdef_write(const char *filepath, ReportList *reports)
{
Main *mainb = MEM_callocN(sizeof(Main), "empty main");
int retval = 0;
@@ -462,6 +516,49 @@ int BKE_blendfile_write_userdef(const char *filepath, ReportList *reports)
return retval;
}
+WorkspaceConfigFileData *BKE_blendfile_workspace_config_read(const char *filepath, ReportList *reports)
+{
+ BlendFileData *bfd;
+ WorkspaceConfigFileData *workspace_config = NULL;
+
+ bfd = BLO_read_from_file(filepath, reports, BLO_READ_SKIP_USERDEF);
+ 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_AUTOPLAY | 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);
+}
+
/** \} */
@@ -511,6 +608,10 @@ bool BKE_blendfile_write_partial(
void *path_list_backup = NULL;
const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);
+ /* This is needed to be able to load that file as a real one later
+ * (otherwise main->name will not be set at read time). */
+ BLI_strncpy(bmain_dst->name, bmain_src->name, sizeof(bmain_dst->name));
+
if (write_flags & G_FILE_RELATIVE_REMAP) {
path_list_backup = BKE_bpath_list_backup(bmain_src, path_list_flag);
}
diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c
index b4bc83bf94c..7ca4e07076d 100644
--- a/source/blender/blenkernel/intern/boids.c
+++ b/source/blender/blenkernel/intern/boids.c
@@ -1581,7 +1581,7 @@ void boid_free_settings(BoidSettings *boids)
MEM_freeN(boids);
}
}
-BoidSettings *boid_copy_settings(BoidSettings *boids)
+BoidSettings *boid_copy_settings(const BoidSettings *boids)
{
BoidSettings *nboids = NULL;
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index 487b8ffa2b5..f210c6aa7f3 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -243,7 +243,7 @@ static bool missing_files_find__recursive(
continue; /* cant stat, don't bother with this file, could print debug info here */
if (S_ISREG(status.st_mode)) { /* is file */
- if (STREQLEN(filename, de->d_name, FILE_MAX)) { /* name matches */
+ if (BLI_path_ncmp(filename, de->d_name, FILE_MAX) == 0) { /* name matches */
/* open the file to read its size */
size = status.st_size;
if ((size > 0) && (size > *r_filesize)) { /* find the biggest file */
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 84e5336617e..5219148a414 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -172,7 +172,7 @@ struct Brush *BKE_brush_first_search(struct Main *bmain, short ob_mode)
return NULL;
}
-Brush *BKE_brush_copy(Main *bmain, Brush *brush)
+Brush *BKE_brush_copy(Main *bmain, const Brush *brush)
{
Brush *brushn;
@@ -195,7 +195,7 @@ Brush *BKE_brush_copy(Main *bmain, Brush *brush)
brushn->curve = curvemapping_copy(brush->curve);
/* enable fake user by default */
- id_fake_user_set(&brush->id);
+ id_fake_user_set(&brushn->id);
BKE_id_copy_ensure_local(bmain, &brush->id, &brushn->id);
@@ -239,7 +239,7 @@ void BKE_brush_make_local(Main *bmain, Brush *brush, const bool lib_local)
if (lib_local || is_local) {
if (!is_lib) {
id_clear_lib_data(bmain, &brush->id);
- BKE_id_expand_local(&brush->id);
+ BKE_id_expand_local(bmain, &brush->id);
/* enable fake user by default */
id_fake_user_set(&brush->id);
@@ -249,6 +249,9 @@ void BKE_brush_make_local(Main *bmain, Brush *brush, const bool lib_local)
brush_new->id.us = 0;
+ /* setting newid is mandatory for complex make_lib_local logic... */
+ ID_NEW_SET(brush, brush_new);
+
if (!lib_local) {
BKE_libblock_remap(bmain, brush, brush_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index 264d87b86f3..c1fad4f80c8 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -393,8 +393,6 @@ static BVHTree *bvhtree_from_editmesh_verts_create_tree(
BMEditMesh *em, const int verts_num,
const BLI_bitmap *verts_mask, int verts_num_active)
{
- BVHTree *tree = NULL;
- int i;
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
if (verts_mask) {
BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
@@ -403,15 +401,14 @@ static BVHTree *bvhtree_from_editmesh_verts_create_tree(
verts_num_active = verts_num;
}
- tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
+ BVHTree *tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
if (tree) {
- BMIter iter;
- BMVert *eve;
- BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+ for (int i = 0; i < verts_num; i++) {
if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
continue;
}
+ BMVert *eve = BM_vert_at_index(em->bm, i);
BLI_bvhtree_insert(tree, i, eve->co, 1);
}
BLI_assert(BLI_bvhtree_get_size(tree) == verts_num_active);
@@ -423,31 +420,28 @@ static BVHTree *bvhtree_from_editmesh_verts_create_tree(
static BVHTree *bvhtree_from_mesh_verts_create_tree(
float epsilon, int tree_type, int axis,
- MVert *vert, const int verts_num,
+ const MVert *vert, const int verts_num,
const BLI_bitmap *verts_mask, int verts_num_active)
{
- BVHTree *tree = NULL;
- int i;
- if (vert) {
- if (verts_mask) {
- BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
- }
- else {
- verts_num_active = verts_num;
- }
+ BLI_assert(vert != NULL);
+ if (verts_mask) {
+ BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
+ }
+ else {
+ verts_num_active = verts_num;
+ }
- tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
+ BVHTree *tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
- if (tree) {
- for (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);
+ if (tree) {
+ for (int i = 0; i < verts_num; i++) {
+ if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
+ continue;
}
- BLI_assert(BLI_bvhtree_get_size(tree) == verts_num_active);
- BLI_bvhtree_balance(tree);
+ BLI_bvhtree_insert(tree, i, vert[i].co, 1);
}
+ BLI_assert(BLI_bvhtree_get_size(tree) == verts_num_active);
+ BLI_bvhtree_balance(tree);
}
return tree;
@@ -455,31 +449,23 @@ static BVHTree *bvhtree_from_mesh_verts_create_tree(
static void bvhtree_from_mesh_verts_setup_data(
BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached, float epsilon,
- MVert *vert, const bool vert_allocated)
+ const MVert *vert, const bool vert_allocated)
{
memset(data, 0, sizeof(*data));
- if (tree) {
- data->tree = tree;
- data->cached = is_cached;
+ data->tree = tree;
+ data->cached = is_cached;
- /* a NULL nearest callback works fine
- * remember the min distance to point is the same as the min distance to BV of point */
- data->nearest_callback = NULL;
- data->raycast_callback = mesh_verts_spherecast;
- data->nearest_to_ray_callback = NULL;
+ /* a NULL nearest callback works fine
+ * remember the min distance to point is the same as the min distance to BV of point */
+ data->nearest_callback = NULL;
+ data->raycast_callback = mesh_verts_spherecast;
- data->vert = vert;
- data->vert_allocated = vert_allocated;
- //data->face = DM_get_tessface_array(dm, &data->face_allocated); /* XXX WHY???? */
+ data->vert = vert;
+ data->vert_allocated = vert_allocated;
+ //data->face = DM_get_tessface_array(dm, &data->face_allocated); /* XXX WHY???? */
- data->sphere_radius = epsilon;
- }
- else {
- if (vert_allocated) {
- MEM_freeN(vert);
- }
- }
+ data->sphere_radius = epsilon;
}
/* Builds a bvh tree where nodes are the vertices of the given em */
@@ -488,11 +474,9 @@ BVHTree *bvhtree_from_editmesh_verts_ex(
const BLI_bitmap *verts_mask, int verts_num_active,
float epsilon, int tree_type, int axis)
{
- int vert_num = em->bm->totvert;
-
BVHTree *tree = bvhtree_from_editmesh_verts_create_tree(
epsilon, tree_type, axis,
- em, vert_num, verts_mask, verts_num_active);
+ em, em->bm->totvert, verts_mask, verts_num_active);
if (tree) {
memset(data, 0, sizeof(*data));
@@ -500,11 +484,11 @@ BVHTree *bvhtree_from_editmesh_verts_ex(
data->em = em;
data->nearest_callback = NULL;
data->raycast_callback = editmesh_verts_spherecast;
- data->nearest_to_ray_callback = NULL;
}
return tree;
}
+
BVHTree *bvhtree_from_editmesh_verts(
BVHTreeFromEditMesh *data, BMEditMesh *em,
float epsilon, int tree_type, int axis)
@@ -515,8 +499,8 @@ BVHTree *bvhtree_from_editmesh_verts(
epsilon, tree_type, axis);
}
-
-/* Builds a bvh tree where nodes are the vertices of the given dm */
+/* Builds a bvh tree where nodes are the vertices of the given dm
+ * and stores the BVHTree in dm->bvhCache */
BVHTree *bvhtree_from_mesh_verts(
BVHTreeFromMesh *data, DerivedMesh *dm,
float epsilon, int tree_type, int axis)
@@ -556,10 +540,18 @@ BVHTree *bvhtree_from_mesh_verts(
/* printf("BVHTree is already build, using cached tree\n"); */
}
- /* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_verts_setup_data(data, tree, true, epsilon, vert, vert_allocated);
-
- return data->tree;
+ if (tree) {
+ /* Setup BVHTreeFromMesh */
+ bvhtree_from_mesh_verts_setup_data(
+ data, tree, true, epsilon, vert, vert_allocated);
+ }
+ else {
+ if (vert_allocated) {
+ MEM_freeN(vert);
+ }
+ memset(data, 0, sizeof(*data));
+ }
+ return tree;
}
/**
@@ -569,7 +561,7 @@ BVHTree *bvhtree_from_mesh_verts(
* \param verts_num_active if >= 0, number of active verts to add to BVH tree (else will be computed from mask).
*/
BVHTree *bvhtree_from_mesh_verts_ex(
- BVHTreeFromMesh *data, MVert *vert, const int verts_num, const bool vert_allocated,
+ BVHTreeFromMesh *data, const MVert *vert, const int verts_num, const bool vert_allocated,
const BLI_bitmap *verts_mask, int verts_num_active,
float epsilon, int tree_type, int axis)
{
@@ -577,9 +569,10 @@ BVHTree *bvhtree_from_mesh_verts_ex(
epsilon, tree_type, axis, vert, verts_num, verts_mask, verts_num_active);
/* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_verts_setup_data(data, tree, false, epsilon, vert, vert_allocated);
+ bvhtree_from_mesh_verts_setup_data(
+ data, tree, false, epsilon, vert, vert_allocated);
- return data->tree;
+ return tree;
}
/** \} */
@@ -595,8 +588,6 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree(
BMEditMesh *em, const int edges_num,
const BLI_bitmap *edges_mask, int edges_num_active)
{
- BVHTree *tree = NULL;
- int i;
BM_mesh_elem_table_ensure(em->bm, BM_EDGE);
if (edges_mask) {
BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edges_num));
@@ -605,9 +596,10 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree(
edges_num_active = edges_num;
}
- tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
+ BVHTree *tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
if (tree) {
+ int i;
BMIter iter;
BMEdge *eed;
BM_ITER_MESH_INDEX (eed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
@@ -627,6 +619,62 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree(
return tree;
}
+static BVHTree *bvhtree_from_mesh_edges_create_tree(
+ const MVert *vert, const MEdge *edge, const int edge_num,
+ const BLI_bitmap *edges_mask, int edges_num_active,
+ float epsilon, int tree_type, int axis)
+{
+ 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);
+
+ BLI_bvhtree_insert(tree, i, co[0], 2);
+ }
+ BLI_bvhtree_balance(tree);
+ }
+
+ return tree;
+}
+
+static void bvhtree_from_mesh_edges_setup_data(
+ BVHTreeFromMesh *data, BVHTree *tree,
+ const bool is_cached, float epsilon,
+ const MVert *vert, const bool vert_allocated,
+ const MEdge *edge, const bool edge_allocated)
+{
+ memset(data, 0, sizeof(*data));
+
+ data->tree = tree;
+
+ data->cached = is_cached;
+
+ data->nearest_callback = mesh_edges_nearest_point;
+ data->raycast_callback = mesh_edges_spherecast;
+
+ data->vert = vert;
+ data->vert_allocated = vert_allocated;
+ data->edge = edge;
+ data->edge_allocated = edge_allocated;
+
+ data->sphere_radius = epsilon;
+}
+
/* Builds a bvh tree where nodes are the edges of the given em */
BVHTree *bvhtree_from_editmesh_edges_ex(
BVHTreeFromEditMesh *data, BMEditMesh *em,
@@ -645,12 +693,11 @@ BVHTree *bvhtree_from_editmesh_edges_ex(
data->em = em;
data->nearest_callback = NULL; /* TODO */
data->raycast_callback = NULL; /* TODO */
- /* TODO: not urgent however since users currently define own callbacks */
- data->nearest_to_ray_callback = NULL;
}
return tree;
}
+
BVHTree *bvhtree_from_editmesh_edges(
BVHTreeFromEditMesh *data, BMEditMesh *em,
float epsilon, int tree_type, int axis)
@@ -683,27 +730,13 @@ BVHTree *bvhtree_from_mesh_edges(
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_EDGES);
if (tree == NULL) {
- int i;
- int numEdges = dm->getNumEdges(dm);
-
- if (vert != NULL && edge != NULL) {
- /* Create a bvh-tree of the given target */
- tree = BLI_bvhtree_new(numEdges, epsilon, tree_type, axis);
- if (tree != NULL) {
- for (i = 0; i < numEdges; i++) {
- 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_balance(tree);
+ tree = bvhtree_from_mesh_edges_create_tree(
+ vert, edge, dm->getNumEdges(dm),
+ NULL, -1, epsilon, tree_type, axis);
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_EDGES);
- }
- }
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_EDGES);
}
BLI_rw_mutex_unlock(&cache_rwlock);
}
@@ -711,24 +744,10 @@ BVHTree *bvhtree_from_mesh_edges(
/* printf("BVHTree is already build, using cached tree\n"); */
}
-
- /* Setup BVHTreeFromMesh */
- memset(data, 0, sizeof(*data));
- data->tree = tree;
-
- if (data->tree) {
- data->cached = true;
-
- data->nearest_callback = mesh_edges_nearest_point;
- data->raycast_callback = mesh_edges_spherecast;
- data->nearest_to_ray_callback = NULL;
-
- data->vert = vert;
- data->vert_allocated = vert_allocated;
- data->edge = edge;
- data->edge_allocated = edge_allocated;
-
- data->sphere_radius = epsilon;
+ if (tree) {
+ /* Setup BVHTreeFromMesh */
+ bvhtree_from_mesh_edges_setup_data(
+ data, tree, true, epsilon, vert, vert_allocated, edge, edge_allocated);
}
else {
if (vert_allocated) {
@@ -737,8 +756,33 @@ BVHTree *bvhtree_from_mesh_edges(
if (edge_allocated) {
MEM_freeN(edge);
}
+ memset(data, 0, sizeof(*data));
}
- return data->tree;
+ return tree;
+}
+
+/**
+ * Builds a bvh tree where nodes are the given edges .
+ * \param vert/edge_allocated if true, elem freeing will be done when freeing data.
+ * \param edges_mask if not null, true elements give which vert to add to BVH tree.
+ * \param edges_num_active if >= 0, number of active edges to add to BVH tree (else will be computed from mask).
+ */
+BVHTree *bvhtree_from_mesh_edges_ex(
+ BVHTreeFromMesh *data,
+ const MVert *vert, const bool vert_allocated,
+ const MEdge *edge, const int edges_num, const bool edge_allocated,
+ const BLI_bitmap *edges_mask, int edges_num_active,
+ float epsilon, int tree_type, int axis)
+{
+ BVHTree *tree = bvhtree_from_mesh_edges_create_tree(
+ vert, edge, edges_num, edges_mask, edges_num_active,
+ epsilon, tree_type, axis);
+
+ /* Setup BVHTreeFromMesh */
+ bvhtree_from_mesh_edges_setup_data(
+ data, tree, false, epsilon, vert, vert_allocated, edge, edge_allocated);
+
+ return tree;
}
/** \} */
@@ -751,7 +795,7 @@ BVHTree *bvhtree_from_mesh_edges(
static BVHTree *bvhtree_from_mesh_faces_create_tree(
float epsilon, int tree_type, int axis,
- MVert *vert, MFace *face, const int faces_num,
+ const MVert *vert, const MFace *face, const int faces_num,
const BLI_bitmap *faces_mask, int faces_num_active)
{
BVHTree *tree = NULL;
@@ -795,34 +839,23 @@ static BVHTree *bvhtree_from_mesh_faces_create_tree(
static void bvhtree_from_mesh_faces_setup_data(
BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached, float epsilon,
- MVert *vert, const bool vert_allocated,
- MFace *face, const bool face_allocated)
+ const MVert *vert, const bool vert_allocated,
+ const MFace *face, const bool face_allocated)
{
memset(data, 0, sizeof(*data));
- if (tree) {
- data->tree = tree;
- data->cached = is_cached;
+ data->tree = tree;
+ data->cached = is_cached;
- data->nearest_callback = mesh_faces_nearest_point;
- data->raycast_callback = mesh_faces_spherecast;
- data->nearest_to_ray_callback = NULL;
+ data->nearest_callback = mesh_faces_nearest_point;
+ data->raycast_callback = mesh_faces_spherecast;
- data->vert = vert;
- data->vert_allocated = vert_allocated;
- data->face = face;
- data->face_allocated = face_allocated;
+ data->vert = vert;
+ data->vert_allocated = vert_allocated;
+ data->face = face;
+ data->face_allocated = face_allocated;
- data->sphere_radius = epsilon;
- }
- else {
- if (vert_allocated) {
- MEM_freeN(vert);
- }
- if (face_allocated) {
- MEM_freeN(face);
- }
- }
+ data->sphere_radius = epsilon;
}
/* Builds a bvh tree where nodes are the tesselated faces of the given dm */
@@ -865,22 +898,33 @@ BVHTree *bvhtree_from_mesh_faces(
/* printf("BVHTree is already build, using cached tree\n"); */
}
- /* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_faces_setup_data(data, tree, true, epsilon, vert, vert_allocated, face, face_allocated);
-
- return data->tree;
+ if (tree) {
+ /* Setup BVHTreeFromMesh */
+ bvhtree_from_mesh_faces_setup_data(
+ data, tree, true, epsilon, vert, vert_allocated, face, face_allocated);
+ }
+ else {
+ if (vert_allocated) {
+ MEM_freeN(vert);
+ }
+ if (face_allocated) {
+ MEM_freeN(face);
+ }
+ memset(data, 0, sizeof(*data));
+ }
+ return tree;
}
/**
* Builds a bvh tree where nodes are the given tessellated faces (note: does not copy given mfaces!).
- * \param vert_allocated if true, vert freeing will be done when freeing data.
- * \param face_allocated if true, face freeing will be done when freeing data.
+ * \param vert_allocated: if true, vert freeing will be done when freeing data.
+ * \param face_allocated: if true, face freeing will be done when freeing data.
* \param faces_mask: if not null, true elements give which faces to add to BVH tree.
- * \param numFaces_active if >= 0, number of active faces to add to BVH tree (else will be computed from mask).
+ * \param faces_num_active: if >= 0, number of active faces to add to BVH tree (else will be computed from mask).
*/
BVHTree *bvhtree_from_mesh_faces_ex(
- BVHTreeFromMesh *data, MVert *vert, const bool vert_allocated,
- MFace *face, const int numFaces, const bool face_allocated,
+ BVHTreeFromMesh *data, const MVert *vert, const bool vert_allocated,
+ const MFace *face, const int numFaces, const bool face_allocated,
const BLI_bitmap *faces_mask, int faces_num_active,
float epsilon, int tree_type, int axis)
{
@@ -890,9 +934,10 @@ BVHTree *bvhtree_from_mesh_faces_ex(
faces_mask, faces_num_active);
/* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_faces_setup_data(data, tree, false, epsilon, vert, vert_allocated, face, face_allocated);
+ bvhtree_from_mesh_faces_setup_data(
+ data, tree, false, epsilon, vert, vert_allocated, face, face_allocated);
- return data->tree;
+ return tree;
}
/** \} */
@@ -1003,34 +1048,20 @@ static void bvhtree_from_mesh_looptri_setup_data(
{
memset(data, 0, sizeof(*data));
- if (tree) {
- data->tree = tree;
- data->cached = is_cached;
+ data->tree = tree;
+ data->cached = is_cached;
- data->nearest_callback = mesh_looptri_nearest_point;
- data->raycast_callback = mesh_looptri_spherecast;
- data->nearest_to_ray_callback = NULL;
+ data->nearest_callback = mesh_looptri_nearest_point;
+ data->raycast_callback = mesh_looptri_spherecast;
- data->vert = vert;
- data->vert_allocated = vert_allocated;
- data->loop = mloop;
- data->loop_allocated = loop_allocated;
- data->looptri = looptri;
- data->looptri_allocated = looptri_allocated;
+ data->vert = vert;
+ data->vert_allocated = vert_allocated;
+ data->loop = mloop;
+ data->loop_allocated = loop_allocated;
+ data->looptri = looptri;
+ data->looptri_allocated = looptri_allocated;
- data->sphere_radius = epsilon;
- }
- else {
- if (vert_allocated) {
- MEM_freeN((void *)vert);
- }
- if (loop_allocated) {
- MEM_freeN((void *)mloop);
- }
- if (looptri_allocated) {
- MEM_freeN((void *)looptri);
- }
- }
+ data->sphere_radius = epsilon;
}
/**
@@ -1075,7 +1106,6 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(
data->tree = tree;
data->nearest_callback = editmesh_looptri_nearest_point;
data->raycast_callback = editmesh_looptri_spherecast;
- data->nearest_to_ray_callback = NULL;
data->sphere_radius = 0.0f;
data->em = em;
data->cached = bvhCache != NULL;
@@ -1157,14 +1187,28 @@ BVHTree *bvhtree_from_mesh_looptri(
/* printf("BVHTree is already build, using cached tree\n"); */
}
- /* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_looptri_setup_data(
- data, tree, true, epsilon,
- mvert, vert_allocated,
- mloop, loop_allocated,
- looptri, looptri_allocated);
+ if (tree) {
+ /* Setup BVHTreeFromMesh */
+ bvhtree_from_mesh_looptri_setup_data(
+ data, tree, true, epsilon,
+ mvert, vert_allocated,
+ mloop, loop_allocated,
+ looptri, looptri_allocated);
+ }
+ else {
+ if (vert_allocated) {
+ MEM_freeN(mvert);
+ }
+ if (loop_allocated) {
+ MEM_freeN(mloop);
+ }
+ if (looptri_allocated) {
+ MEM_freeN((void *)looptri);
+ }
+ memset(data, 0, sizeof(*data));
+ }
- return data->tree;
+ return tree;
}
BVHTree *bvhtree_from_mesh_looptri_ex(
@@ -1187,7 +1231,7 @@ BVHTree *bvhtree_from_mesh_looptri_ex(
mloop, loop_allocated,
looptri, looptri_allocated);
- return data->tree;
+ return tree;
}
/** \} */
@@ -1207,29 +1251,27 @@ void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data)
/* Frees data allocated by a call to bvhtree_from_mesh_*. */
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
{
- if (data->tree) {
- if (!data->cached) {
- BLI_bvhtree_free(data->tree);
- }
-
- if (data->vert_allocated) {
- MEM_freeN((void *)data->vert);
- }
- if (data->edge_allocated) {
- MEM_freeN((void *)data->edge);
- }
- if (data->face_allocated) {
- MEM_freeN((void *)data->face);
- }
- if (data->loop_allocated) {
- MEM_freeN((void *)data->loop);
- }
- if (data->looptri_allocated) {
- MEM_freeN((void *)data->looptri);
- }
+ if (data->tree && !data->cached) {
+ BLI_bvhtree_free(data->tree);
+ }
- memset(data, 0, sizeof(*data));
+ if (data->vert_allocated) {
+ MEM_freeN((void *)data->vert);
}
+ if (data->edge_allocated) {
+ MEM_freeN((void *)data->edge);
+ }
+ if (data->face_allocated) {
+ MEM_freeN((void *)data->face);
+ }
+ if (data->loop_allocated) {
+ MEM_freeN((void *)data->loop);
+ }
+ if (data->looptri_allocated) {
+ MEM_freeN((void *)data->looptri);
+ }
+
+ memset(data, 0, sizeof(*data));
}
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index 16f263791db..2294e23d4d5 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -29,12 +29,15 @@
#include "DNA_anim_types.h"
#include "DNA_cachefile_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BLI_fileops.h"
#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "BKE_animsys.h"
@@ -42,12 +45,25 @@
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_modifier.h"
#include "BKE_scene.h"
#ifdef WITH_ALEMBIC
# include "ABC_alembic.h"
#endif
+static SpinLock spin;
+
+void BKE_cachefiles_init(void)
+{
+ BLI_spin_init(&spin);
+}
+
+void BKE_cachefiles_exit(void)
+{
+ BLI_spin_end(&spin);
+}
+
void *BKE_cachefile_add(Main *bmain, const char *name)
{
CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, name);
@@ -65,6 +81,8 @@ void BKE_cachefile_init(CacheFile *cache_file)
cache_file->frame = 0.0f;
cache_file->is_sequence = false;
cache_file->scale = 1.0f;
+ cache_file->handle_mutex = BLI_mutex_alloc();
+ BLI_listbase_clear(&cache_file->object_paths);
}
/** Free (or release) any data used by this cachefile (does not free the cachefile itself). */
@@ -76,15 +94,18 @@ void BKE_cachefile_free(CacheFile *cache_file)
ABC_free_handle(cache_file->handle);
#endif
+ if (cache_file->handle_mutex) {
+ BLI_mutex_free(cache_file->handle_mutex);
+ }
BLI_freelistN(&cache_file->object_paths);
}
-CacheFile *BKE_cachefile_copy(Main *bmain, CacheFile *cache_file)
+CacheFile *BKE_cachefile_copy(Main *bmain, const CacheFile *cache_file)
{
CacheFile *new_cache_file = BKE_libblock_copy(bmain, &cache_file->id);
new_cache_file->handle = NULL;
- BLI_listbase_clear(&cache_file->object_paths);
+ BLI_listbase_clear(&new_cache_file->object_paths);
BKE_id_copy_ensure_local(bmain, &cache_file->id, &new_cache_file->id);
@@ -114,9 +135,19 @@ void BKE_cachefile_reload(const Main *bmain, CacheFile *cache_file)
void BKE_cachefile_ensure_handle(const Main *bmain, CacheFile *cache_file)
{
+ BLI_spin_lock(&spin);
+ if (cache_file->handle_mutex == NULL) {
+ cache_file->handle_mutex = BLI_mutex_alloc();
+ }
+ BLI_spin_unlock(&spin);
+
+ BLI_mutex_lock(cache_file->handle_mutex);
+
if (cache_file->handle == NULL) {
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)
@@ -135,10 +166,12 @@ 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(bmain, cache_file);
#ifdef WITH_ALEMBIC
ABC_free_handle(cache_file->handle);
cache_file->handle = ABC_create_handle(filename, NULL);
#endif
+ break;
}
}
}
@@ -171,3 +204,41 @@ float BKE_cachefile_time_offset(CacheFile *cache_file, const float time, const f
const float frame = (cache_file->override_frame ? cache_file->frame : time);
return cache_file->is_sequence ? frame : frame / fps;
}
+
+/* TODO(kevin): replace this with some depsgraph mechanism, or something similar. */
+void BKE_cachefile_clean(struct Main *bmain, CacheFile *cache_file)
+{
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);
+
+ if (md) {
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+
+ if (cache_file == mcmd->cache_file) {
+#ifdef WITH_ALEMBIC
+ if (mcmd->reader != NULL) {
+ CacheReader_free(mcmd->reader);
+ }
+#endif
+ mcmd->reader = NULL;
+ }
+ }
+
+ for (bConstraint *con = ob->constraints.first; con; con = con->next) {
+ if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) {
+ continue;
+ }
+
+ bTransformCacheConstraint *data = con->data;
+
+ if (cache_file == data->cache_file) {
+#ifdef WITH_ALEMBIC
+ if (data->reader != NULL) {
+ CacheReader_free(data->reader);
+ }
+#endif
+ data->reader = NULL;
+ }
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index 85ce399b770..2e36de4e8d4 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -93,7 +93,7 @@ void *BKE_camera_add(Main *bmain, const char *name)
return cam;
}
-Camera *BKE_camera_copy(Main *bmain, Camera *cam)
+Camera *BKE_camera_copy(Main *bmain, const Camera *cam)
{
Camera *camn;
@@ -252,7 +252,7 @@ void BKE_camera_params_from_view3d(CameraParams *params, const View3D *v3d, cons
}
else if (rv3d->persp == RV3D_ORTHO) {
/* orthographic view */
- int sensor_size = BKE_camera_sensor_size(params->sensor_fit, params->sensor_x, params->sensor_y);
+ float sensor_size = BKE_camera_sensor_size(params->sensor_fit, params->sensor_x, params->sensor_y);
params->clipend *= 0.5f; // otherwise too extreme low zbuffer quality
params->clipsta = -params->clipend;
@@ -337,6 +337,8 @@ void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int win
viewplane.ymin *= pixsize;
viewplane.ymax *= pixsize;
+ /* Used for rendering (offset by near-clip with perspective views), passed to RE_SetPixelSize.
+ * For viewport drawing 'RegionView3D.pixsize'. */
params->viewdx = pixsize;
params->viewdy = params->ycor * pixsize;
params->viewplane = viewplane;
@@ -631,7 +633,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(
- Scene *scene, struct View3D *v3d, Object *camera_ob, float r_co[3], float *r_scale)
+ Scene *scene, SceneLayer *sl, Object *camera_ob, float r_co[3], float *r_scale)
{
CameraParams params;
CameraViewFrameData data_cb;
@@ -642,7 +644,7 @@ 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(scene, v3d, BA_SELECT, camera_to_frame_view_cb, &data_cb);
+ BKE_scene_foreach_display_point(scene, sl, camera_to_frame_view_cb, &data_cb);
return camera_frame_fit_calc_from_data(&params, &data_cb, r_co, r_scale);
}
@@ -851,7 +853,7 @@ 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);
+ BaseLegacy *base = BKE_scene_base_find_by_name(scene, name);
if (base) {
return base->object;
}
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index d257a1cfcae..155634c9d9c 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -58,6 +58,7 @@
#include "GPU_buffers.h"
#include "GPU_draw.h"
#include "GPU_glew.h"
+#include "GPU_immediate.h"
#include "GPU_shader.h"
#include "GPU_basic_shader.h"
@@ -372,40 +373,10 @@ static void cdDM_drawVerts(DerivedMesh *dm)
GPU_buffers_unbind();
}
-static void cdDM_drawUVEdges(DerivedMesh *dm)
+static void cdDM_drawEdges(DerivedMesh *dm, bool UNUSED(drawLooseEdges), bool UNUSED(drawAllEdges))
{
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)
{
@@ -413,22 +384,37 @@ static void cdDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdg
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);
+
+ MVert *vert = cddm->mvert;
+ MEdge *edge = cddm->medge;
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ /* NOTE: This is active object color, which is not really perfect.
+ * But we can't query color set by glColor() :(
+ */
+ float color[4] = {1.0f, 0.667f, 0.251f, 1.0f};
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor4fv(color);
+
+ const int chunk_size = 1024;
+ const int num_chunks = (dm->numEdgeData + chunk_size - 1) / chunk_size;
+
+ for (int chunk = 0; chunk < num_chunks; ++chunk) {
+ const int num_current_edges = (chunk < num_chunks - 1)
+ ? chunk_size
+ : dm->numEdgeData - chunk_size * (num_chunks - 1);
+ immBeginAtMost(GWN_PRIM_LINES, num_current_edges * 2);
+ for (int i = 0; i < num_current_edges; i++, edge++) {
+ immVertex3fv(pos, vert[edge->v1].co);
+ immVertex3fv(pos, vert[edge->v2].co);
}
+ immEnd();
}
- GPU_buffers_unbind();
+
+ immUnbindProgram();
}
static void cdDM_drawLooseEdges(DerivedMesh *dm)
@@ -451,8 +437,9 @@ static void cdDM_drawLooseEdges(DerivedMesh *dm)
static void cdDM_drawFacesSolid(
DerivedMesh *dm,
float (*partial_redraw_planes)[4],
- bool UNUSED(fast), DMSetMaterial setMaterial)
+ bool fast, DMSetMaterial setMaterial)
{
+ UNUSED_VARS(partial_redraw_planes, fast, setMaterial);
CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
int a;
@@ -465,177 +452,79 @@ static void cdDM_drawFacesSolid(
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 MVert *mvert = cddm->mvert;
+ const MLoop *mloop = cddm->mloop;
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);
- }
- }
+ const int num_looptris = dm->getNumLoopTri(dm);
+ const MLoopTri *looptri = dm->getLoopTriArray(dm);
+ const float (*nors)[3] = dm->getPolyDataArray(dm, CD_NORMAL);
+ const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- 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);
- }
- }
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ unsigned int nor = GWN_vertformat_attr_add(format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
- 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);
- }
+ float color[4] = {0.8f, 0.8f, 0.8f, 1.0f};
+ const float light_vec[3] = {0.0f, 0.0f, 1.0f};
- /* 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;
+ immBindBuiltinProgram(GPU_SHADER_SIMPLE_LIGHTING);
+ immUniformColor4fv(color);
+ immUniform3fv("light", light_vec);
- tot_element = 0;
- tot_drawn = 0;
- start_element = 0;
+ const int chunk_size = 1024;
+ const int num_chunks = (num_looptris + chunk_size - 1) / chunk_size;
- 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;
+ for (int chunk = 0; chunk < num_chunks; ++chunk) {
+ const int num_current_looptris = (chunk < num_chunks - 1)
+ ? chunk_size
+ : num_looptris - chunk_size * (num_chunks - 1);
- if (i != totpoly - 1)
- next_actualFace = bufmat->polys[i + 1];
+ immBeginAtMost(GWN_PRIM_TRIS, num_current_looptris * 3);
- 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);
- }
+ for (a = 0; a < num_current_looptris; a++, looptri++) {
+ const MPoly *mp = &mpoly[looptri->poly];
+ const bool smoothnormal = (lnors != NULL) || (mp->flag & ME_SMOOTH);
+ const unsigned int vtri[3] = {mloop[looptri->tri[0]].v,
+ mloop[looptri->tri[1]].v,
+ mloop[looptri->tri[2]].v};
+ const unsigned int *ltri = looptri->tri;
+ float normals[3][3];
+ if (!smoothnormal) {
+ if (nors != NULL) {
+ copy_v3_v3(normals[0], nors[looptri->poly]);
}
- else if (drawParamsMapped) {
- draw_option = drawParamsMapped(userData, actualFace, mpoly[actualFace].mat_nr);
+ else {
+ normal_tri_v3(normals[0],
+ mvert[vtri[0]].co,
+ mvert[vtri[1]].co,
+ mvert[vtri[2]].co);
}
+ copy_v3_v3(normals[1], normals[0]);
+ copy_v3_v3(normals[2], normals[0]);
}
-
- /* 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 if (lnors != NULL) {
+ copy_v3_v3(normals[0], lnors[ltri[0]]);
+ copy_v3_v3(normals[1], lnors[ltri[1]]);
+ copy_v3_v3(normals[2], lnors[ltri[2]]);
}
else {
- tot_drawn += tot_tri_verts;
+ normal_short_to_float_v3(normals[0], mvert[vtri[0]].no);
+ normal_short_to_float_v3(normals[1], mvert[vtri[1]].no);
+ normal_short_to_float_v3(normals[2], mvert[vtri[2]].no);
}
+
+ immAttrib3fv(nor, normals[0]);
+ immVertex3fv(pos, mvert[vtri[0]].co);
+ immAttrib3fv(nor, normals[1]);
+ immVertex3fv(pos, mvert[vtri[1]].co);
+ immAttrib3fv(nor, normals[2]);
+ immVertex3fv(pos, mvert[vtri[2]].co);
}
+ immEnd();
}
- 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);
+ immUnbindProgram();
}
static void cdDM_drawMappedFaces(
@@ -687,20 +576,24 @@ static void cdDM_drawMappedFaces(
const int orig = (index_mp_to_orig) ? index_mp_to_orig[i] : i;
bool is_hidden;
- 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;
+ 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 {
- is_hidden = (me->mpoly[orig].flag & ME_HIDE) != 0;
- }
-
- if ((orig != ORIGINDEX_NONE) && !is_hidden)
GPU_select_index_get(orig + 1, &selcol);
+ }
}
- else if (orig != ORIGINDEX_NONE)
- GPU_select_index_get(orig + 1, &selcol);
for (j = 0; j < mpoly->totloop; j++)
fi_map[start_element++] = selcol;
@@ -838,15 +731,6 @@ static void cdDM_drawMappedFaces(
}
-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)
@@ -937,8 +821,10 @@ static void cdDM_drawMappedFacesGLSL(
matnr = new_matnr;
do_draw = setMaterial(matnr + 1, &gattribs);
- if (do_draw)
+ if (do_draw) {
DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
+ DM_draw_attrib_vertex_uniforms(&attribs);
+ }
glBegin(GL_TRIANGLES);
}
@@ -1206,6 +1092,7 @@ static void cdDM_drawMappedFacesMat(
setMaterial(userData, matnr = new_matnr, &gattribs);
DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
+ DM_draw_attrib_vertex_uniforms(&attribs);
glBegin(GL_TRIANGLES);
}
@@ -1897,7 +1784,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)
@@ -2001,16 +1888,13 @@ static CDDerivedMesh *cdDM_create(const char *desc)
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;
@@ -2147,7 +2031,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);
}
@@ -2162,22 +2045,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];
@@ -2231,7 +2110,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;
@@ -2261,7 +2140,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);
@@ -2333,7 +2212,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);
}
}
@@ -2391,21 +2270,28 @@ 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, int faces_from_tessfaces)
+static DerivedMesh *cddm_copy_ex(DerivedMesh *source,
+ const bool need_tessface_data,
+ const bool faces_from_tessfaces)
{
+ 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 = source->numTessFaceData;
+ int numTessFaces = copy_tessface_data ? source->numTessFaceData : 0;
int numLoops = source->numLoopData;
int numPolys = source->numPolyData;
+ /* NOTE: Don't copy tessellation faces if not requested explicitly. */
+
/* ensure these are created if they are made on demand */
source->getVertDataArray(source, CD_ORIGINDEX);
source->getEdgeDataArray(source, CD_ORIGINDEX);
- source->getTessFaceDataArray(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,
@@ -2414,23 +2300,37 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source, int faces_from_tessfaces)
dm->cd_flag = source->cd_flag;
dm->dirty = source->dirty;
+ /* 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;
+ }
+
CustomData_copy_data(&source->vertData, &dm->vertData, 0, 0, numVerts);
CustomData_copy_data(&source->edgeData, &dm->edgeData, 0, 0, numEdges);
- CustomData_copy_data(&source->faceData, &dm->faceData, 0, 0, numTessFaces);
+ 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);
cddm->medge = source->dupEdgeArray(source);
- cddm->mface = source->dupTessFaceArray(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);
- CustomData_add_layer(&dm->faceData, CD_MFACE, CD_ASSIGN, cddm->mface, numTessFaces);
-
- if (!faces_from_tessfaces)
+
+ 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
+ }
+ else {
CDDM_tessfaces_to_faces(dm);
+ }
cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
@@ -2440,12 +2340,17 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source, int faces_from_tessfaces)
DerivedMesh *CDDM_copy(DerivedMesh *source)
{
- return cddm_copy_ex(source, 0);
+ return cddm_copy_ex(source, false, false);
}
DerivedMesh *CDDM_copy_from_tessface(DerivedMesh *source)
{
- return cddm_copy_ex(source, 1);
+ 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
@@ -2959,9 +2864,12 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
STACK_DECLARE(mvert);
STACK_DECLARE(oldv);
- MEdge *med, *medge = MEM_mallocN(sizeof(*medge) * totedge, __func__);
- int *olde = MEM_mallocN(sizeof(*olde) * totedge, __func__);
- int *newe = MEM_mallocN(sizeof(*newe) * totedge, __func__);
+ /* 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_mallocN(sizeof(*medge) * (totedge + totloop), __func__);
+ int *olde = MEM_mallocN(sizeof(*olde) * (totedge + totloop), __func__);
+ int *newe = MEM_mallocN(sizeof(*newe) * (totedge + totloop), __func__);
STACK_DECLARE(medge);
STACK_DECLARE(olde);
@@ -2995,7 +2903,7 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
STACK_INIT(mloop, totloop);
STACK_INIT(mpoly, totpoly);
- /* fill newl with destination vertex indices */
+ /* fill newv with destination vertex indices */
mv = cddm->mvert;
c = 0;
for (i = 0; i < totvert; i++, mv++) {
@@ -3084,83 +2992,80 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
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;
+ bool all_vertices_merged = true;
- for (j = 0; j < mp->totloop; j++, ml++) {
- if (vtargetmap[ml->v] == -1) {
- all_vertices_merged = false;
- break;
- }
+ 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;
+ 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++;
}
- 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, v_prev;
- 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 */
+ 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;
- pkey.hash_sum = pkey.hash_xor = 0;
- pkey.totloops = 0;
- v_prev = vtargetmap[(ml + mp->totloop -1)->v]; /* since it loops around, the prev of first is the last */
- for (j = 0; j < mp->totloop; j++, ml++) {
- v_target = vtargetmap[ml->v]; /* Cannot be -1, they are all mapped */
- if (v_target == v_prev) {
- /* consecutive vertices in loop map to the same target: discard */
- /* but what about last to first ? */
- continue;
+ /* 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;
}
- pkey.hash_sum += v_target;
- pkey.hash_xor ^= v_target;
- pkey.totloops++;
- v_prev = v_target;
}
- 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;
- }
+ if (found) {
+ /* Current poly's vertices are mapped to a poly that is strictly identical */
+ /* Current poly is dumped */
+ continue;
}
}
}
@@ -3174,32 +3079,121 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
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++) {
- unsigned int v1, v2;
+ 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 = GET_INT_FROM_POINTER(*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 = SET_INT_IN_POINTER(new_eidx);
+ created_edges++;
+
+ last_valid_ml->e = new_eidx;
+ }
+ need_edge_from_last_valid_ml = false;
+ }
- med = cddm->medge + ml->e;
- v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1;
- v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2;
- if (LIKELY(v1 != v2)) {
#ifdef USE_LOOPS
newl[j + mp->loopstart] = STACK_SIZE(mloop);
#endif
STACK_PUSH(oldl, j + mp->loopstart);
- STACK_PUSH(mloop, *ml);
+ 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 = GET_INT_FROM_POINTER(*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 = SET_INT_IN_POINTER(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;
@@ -3224,10 +3218,10 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
/*update edge indices and copy customdata*/
med = medge;
for (i = 0; i < cddm2->dm.numEdgeData; i++, med++) {
- if (newv[med->v1] != -1)
- med->v1 = newv[med->v1];
- if (newv[med->v2] != -1)
- med->v2 = newv[med->v2];
+ 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);
@@ -3238,11 +3232,10 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
/*update loop indices and copy customdata*/
ml = mloop;
for (i = 0; i < cddm2->dm.numLoopData; i++, ml++) {
- if (newe[ml->e] != -1)
- ml->e = newe[ml->e];
- if (newv[ml->v] != -1)
- ml->v = newv[ml->v];
-
+ /* 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);
}
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 681b93172b2..6d0ad3255a2 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -81,8 +81,10 @@ void cloth_init(ClothModifierData *clmd )
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->bending = 0.5;
+ clmd->sim_parms->max_bend = 0.5;
clmd->sim_parms->bending_damping = 0.5;
clmd->sim_parms->Cdis = 5.0;
clmd->sim_parms->Cvi = 1.0;
@@ -449,9 +451,12 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
}
/* try to read from cache */
- cache_result = BKE_ptcache_read(&pid, (float)framenr+scene->r.subframe);
+ bool can_simulate = (framenr == clmd->clothObject->last_frame+1) && !(cache->flag & PTCACHE_BAKED);
- if (cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED) {
+ cache_result = BKE_ptcache_read(&pid, (float)framenr+scene->r.subframe, can_simulate);
+
+ if (cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED ||
+ (!can_simulate && cache_result == PTCACHE_READ_OLD)) {
BKE_cloth_solver_set_positions(clmd);
cloth_to_object (ob, clmd, vertexCos);
@@ -473,7 +478,6 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
return;
}
- if (framenr!=clmd->clothObject->last_frame+1)
return;
/* if on second frame, write cache for first frame */
@@ -864,12 +868,6 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
return 0;
}
- for ( i = 0; i < dm->getNumVerts(dm); i++) {
- if ((!(cloth->verts[i].flags & CLOTH_VERT_FLAG_PINNED)) && (cloth->verts[i].goal > ALMOST_ZERO)) {
- cloth_add_spring (clmd, i, i, 0.0, CLOTH_SPRING_TYPE_GOAL);
- }
- }
-
// init our solver
BPH_cloth_solver_init(ob, clmd);
@@ -924,7 +922,7 @@ static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm )
}
/***************************************************************************************
- * SPRING NETWORK BUILDING IMPLEMENTATION BEGIN
+ * SPRING NETWORK GWN_BATCH_BUILDING IMPLEMENTATION BEGIN
***************************************************************************************/
BLI_INLINE void spring_verts_ordered_set(ClothSpring *spring, int v0, int v1)
@@ -939,37 +937,6 @@ BLI_INLINE void spring_verts_ordered_set(ClothSpring *spring, int v0, int v1)
}
}
-// be careful: implicit solver has to be resettet when using this one!
-// --> only for implicit handling of this spring!
-int cloth_add_spring(ClothModifierData *clmd, unsigned int indexA, unsigned int indexB, float restlength, int spring_type)
-{
- Cloth *cloth = clmd->clothObject;
- ClothSpring *spring = NULL;
-
- if (cloth) {
- // TODO: look if this spring is already there
-
- spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
-
- if (!spring)
- return 0;
-
- spring->ij = indexA;
- spring->kl = indexB;
- spring->restlen = restlength;
- spring->type = spring_type;
- spring->flags = 0;
- spring->stiffness = 0;
-
- cloth->numsprings++;
-
- BLI_linklist_prepend ( &cloth->springs, spring );
-
- return 1;
- }
- return 0;
-}
-
static void cloth_free_edgelist(LinkNodePair *edgelist, unsigned int mvert_num)
{
if (edgelist) {
@@ -1537,6 +1504,6 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
} /* cloth_build_springs */
/***************************************************************************************
- * SPRING NETWORK BUILDING IMPLEMENTATION END
+ * SPRING NETWORK GWN_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..38534f03123
--- /dev/null
+++ b/source/blender/blenkernel/intern/collection.c
@@ -0,0 +1,648 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "BLT_translation.h"
+#include "BLI_string_utils.h"
+
+#include "BKE_collection.h"
+#include "BKE_idprop.h"
+#include "BKE_layer.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+
+#include "DNA_ID.h"
+#include "DNA_layer_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+
+/**
+ * Add a collection to a collection ListBase and syncronize all render layers
+ * The ListBase is NULL when the collection is to be added to the master collection
+ */
+SceneCollection *BKE_collection_add(Scene *scene, SceneCollection *sc_parent, const char *name)
+{
+ SceneCollection *sc_master = BKE_collection_master(scene);
+ SceneCollection *sc = MEM_callocN(sizeof(SceneCollection), "New Collection");
+
+ if (!name) {
+ name = DATA_("New Collection");
+ }
+
+ if (!sc_parent) {
+ sc_parent = sc_master;
+ }
+
+ BKE_collection_rename(scene, sc, name);
+ BLI_addtail(&sc_parent->scene_collections, sc);
+
+ BKE_layer_sync_new_scene_collection(scene, sc_parent, sc);
+ return sc;
+}
+
+/**
+ * Free the collection items recursively
+ */
+static void collection_free(SceneCollection *sc, const bool do_id_user)
+{
+ if (do_id_user) {
+ for (LinkData *link = sc->objects.first; link; link = link->next) {
+ id_us_min(link->data);
+ }
+ for (LinkData *link = sc->filter_objects.first; link; link = link->next) {
+ id_us_min(link->data);
+ }
+ }
+
+ BLI_freelistN(&sc->objects);
+ BLI_freelistN(&sc->filter_objects);
+
+ for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
+ collection_free(nsc, do_id_user);
+ }
+ BLI_freelistN(&sc->scene_collections);
+}
+
+/**
+ * Unlink the collection recursively
+ * \return true if unlinked.
+ */
+static bool collection_remlink(SceneCollection *sc_parent, SceneCollection *sc_gone)
+{
+ for (SceneCollection *sc = sc_parent->scene_collections.first; sc; sc = sc->next) {
+ if (sc == sc_gone) {
+ BLI_remlink(&sc_parent->scene_collections, sc_gone);
+ return true;
+ }
+
+ if (collection_remlink(sc, sc_gone)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Recursively remove any instance of this SceneCollection
+ */
+static void layer_collection_remove(SceneLayer *sl, ListBase *lb, const SceneCollection *sc)
+{
+ LayerCollection *lc = lb->first;
+ while (lc) {
+ if (lc->scene_collection == sc) {
+ BKE_layer_collection_free(sl, lc);
+ BLI_remlink(lb, lc);
+
+ LayerCollection *lc_next = lc->next;
+ MEM_freeN(lc);
+ lc = lc_next;
+
+ /* only the "top-level" layer collections may have the
+ * same SceneCollection in a sibling tree.
+ */
+ if (lb != &sl->layer_collections) {
+ return;
+ }
+ }
+
+ else {
+ layer_collection_remove(sl, &lc->layer_collections, sc);
+ lc = lc->next;
+ }
+ }
+}
+
+/**
+ * Remove a collection from the scene, and syncronize all render layers
+ */
+bool BKE_collection_remove(Scene *scene, SceneCollection *sc)
+{
+ SceneCollection *sc_master = BKE_collection_master(scene);
+
+ /* the master collection cannot be removed */
+ if (sc == sc_master) {
+ return false;
+ }
+
+ /* unlink from the respective collection tree */
+ if (!collection_remlink(sc_master, sc)) {
+ BLI_assert(false);
+ }
+
+ /* clear the collection items */
+ collection_free(sc, true);
+
+ /* check all layers that use this collection and clear them */
+ for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
+ layer_collection_remove(sl, &sl->layer_collections, sc);
+ sl->active_collection = 0;
+ }
+
+ MEM_freeN(sc);
+ return true;
+}
+
+/**
+ * Returns the master collection
+ */
+SceneCollection *BKE_collection_master(const Scene *scene)
+{
+ return scene->collection;
+}
+
+struct UniqueNameCheckData {
+ ListBase *lb;
+ SceneCollection *lookup_sc;
+};
+
+static bool collection_unique_name_check(void *arg, const char *name)
+{
+ struct UniqueNameCheckData *data = arg;
+
+ for (SceneCollection *sc = data->lb->first; sc; sc = sc->next) {
+ struct UniqueNameCheckData child_data = {.lb = &sc->scene_collections, .lookup_sc = data->lookup_sc};
+
+ if (sc != data->lookup_sc) {
+ if (STREQ(sc->name, name)) {
+ return true;
+ }
+ }
+ if (collection_unique_name_check(&child_data, name)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void BKE_collection_rename(const Scene *scene, SceneCollection *sc, const char *name)
+{
+ SceneCollection *sc_master = BKE_collection_master(scene);
+ struct UniqueNameCheckData data = {.lb = &sc_master->scene_collections, .lookup_sc = sc};
+
+ BLI_strncpy(sc->name, name, sizeof(sc->name));
+ BLI_uniquename_cb(collection_unique_name_check, &data, DATA_("Collection"), '.', sc->name, sizeof(sc->name));
+}
+
+/**
+ * Free (or release) any data used by the master collection (does not free the master collection itself).
+ * Used only to clear the entire scene data since it's not doing re-syncing of the LayerCollection tree
+ */
+void BKE_collection_master_free(Scene *scene, const bool do_id_user)
+{
+ collection_free(BKE_collection_master(scene), do_id_user);
+}
+
+static void collection_object_add(const Scene *scene, SceneCollection *sc, Object *ob)
+{
+ BLI_addtail(&sc->objects, BLI_genericNodeN(ob));
+ id_us_plus((ID *)ob);
+ BKE_layer_sync_object_link(scene, sc, ob);
+}
+
+/**
+ * Add object to collection
+ */
+void BKE_collection_object_add(const Scene *scene, SceneCollection *sc, Object *ob)
+{
+ if (BLI_findptr(&sc->objects, ob, offsetof(LinkData, data))) {
+ /* don't add the same object twice */
+ return;
+ }
+ collection_object_add(scene, sc, ob);
+}
+
+/**
+ * Add object to all collections that reference objects is in
+ * (used to copy objects)
+ */
+void BKE_collection_object_add_from(Scene *scene, Object *ob_src, Object *ob_dst)
+{
+ FOREACH_SCENE_COLLECTION(scene, sc)
+ {
+ if (BLI_findptr(&sc->objects, ob_src, offsetof(LinkData, data))) {
+ collection_object_add(scene, sc, ob_dst);
+ }
+ }
+ FOREACH_SCENE_COLLECTION_END
+
+ for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
+ Base *base_src = BKE_scene_layer_base_find(sl, ob_src);
+ if (base_src != NULL) {
+ Base *base_dst = BKE_scene_layer_base_find(sl, ob_dst);
+ IDP_MergeGroup(base_dst->collection_properties, base_src->collection_properties, true);
+ }
+ }
+}
+
+/**
+ * Remove object from collection.
+ * \param bmain: Can be NULL if free_us is false.
+ */
+void BKE_collection_object_remove(Main *bmain, const Scene *scene, SceneCollection *sc, Object *ob, const bool free_us)
+{
+
+ LinkData *link = BLI_findptr(&sc->objects, ob, offsetof(LinkData, data));
+
+ if (link == NULL) {
+ return;
+ }
+
+ BLI_remlink(&sc->objects, link);
+ MEM_freeN(link);
+
+ TODO_LAYER_SYNC_FILTER; /* need to remove all instances of ob in scene collections -> filter_objects */
+ BKE_layer_sync_object_unlink(scene, sc, ob);
+
+ if (free_us) {
+ BKE_libblock_free_us(bmain, ob);
+ }
+ else {
+ id_us_min(&ob->id);
+ }
+}
+
+/**
+ * Move object from a collection into another
+ */
+void BKE_collection_object_move(const Scene *scene, SceneCollection *sc_dst, SceneCollection *sc_src, Object *ob)
+{
+ BKE_collection_object_add(scene, sc_dst, ob);
+ BKE_collection_object_remove(NULL, scene, sc_src, ob, false);
+}
+
+/**
+ * Remove object from all collections of scene
+ */
+void BKE_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us)
+{
+ BKE_scene_remove_rigidbody_object(scene, ob);
+
+ FOREACH_SCENE_COLLECTION(scene, sc)
+ {
+ BKE_collection_object_remove(bmain, scene, sc, ob, free_us);
+ }
+ FOREACH_SCENE_COLLECTION_END
+}
+
+/* ---------------------------------------------------------------------- */
+/* Outliner drag and drop */
+
+/**
+ * Find and return the SceneCollection that has \a sc_child as one of its directly
+ * nested SceneCollection.
+ *
+ * \param sc_parent Initial SceneCollection to look into recursively, usually the master collection
+ */
+static SceneCollection *find_collection_parent(const SceneCollection *sc_child, SceneCollection *sc_parent)
+{
+ for (SceneCollection *sc_nested = sc_parent->scene_collections.first; sc_nested; sc_nested = sc_nested->next) {
+ if (sc_nested == sc_child) {
+ return sc_parent;
+ }
+
+ SceneCollection *found = find_collection_parent(sc_child, sc_nested);
+ if (found) {
+ return found;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Check if \a sc_reference is nested to \a sc_parent SceneCollection
+ */
+static bool is_collection_in_tree(const SceneCollection *sc_reference, SceneCollection *sc_parent)
+{
+ return find_collection_parent(sc_reference, sc_parent) != NULL;
+}
+
+bool BKE_collection_move_above(const Scene *scene, SceneCollection *sc_dst, SceneCollection *sc_src)
+{
+ /* Find the SceneCollection the sc_src belongs to */
+ SceneCollection *sc_master = BKE_collection_master(scene);
+
+ /* Master Layer can't be moved around*/
+ if (ELEM(sc_master, sc_src, sc_dst)) {
+ return false;
+ }
+
+ /* collection is already where we wanted it to be */
+ if (sc_dst->prev == sc_src) {
+ return false;
+ }
+
+ /* We can't move a collection fs the destiny collection
+ * is nested to the source collection */
+ if (is_collection_in_tree(sc_dst, sc_src)) {
+ return false;
+ }
+
+ SceneCollection *sc_src_parent = find_collection_parent(sc_src, sc_master);
+ SceneCollection *sc_dst_parent = find_collection_parent(sc_dst, sc_master);
+ BLI_assert(sc_src_parent);
+ BLI_assert(sc_dst_parent);
+
+ /* Remove sc_src from its parent */
+ BLI_remlink(&sc_src_parent->scene_collections, sc_src);
+
+ /* Re-insert it where it belongs */
+ BLI_insertlinkbefore(&sc_dst_parent->scene_collections, sc_dst, sc_src);
+
+ /* Update the tree */
+ BKE_layer_collection_resync(scene, sc_src_parent);
+ BKE_layer_collection_resync(scene, sc_dst_parent);
+
+ return true;
+}
+
+bool BKE_collection_move_below(const Scene *scene, SceneCollection *sc_dst, SceneCollection *sc_src)
+{
+ /* Find the SceneCollection the sc_src belongs to */
+ SceneCollection *sc_master = BKE_collection_master(scene);
+
+ /* Master Layer can't be moved around*/
+ if (ELEM(sc_master, sc_src, sc_dst)) {
+ return false;
+ }
+
+ /* Collection is already where we wanted it to be */
+ if (sc_dst->next == sc_src) {
+ return false;
+ }
+
+ /* We can't move a collection if the destiny collection
+ * is nested to the source collection */
+ if (is_collection_in_tree(sc_dst, sc_src)) {
+ return false;
+ }
+
+ SceneCollection *sc_src_parent = find_collection_parent(sc_src, sc_master);
+ SceneCollection *sc_dst_parent = find_collection_parent(sc_dst, sc_master);
+ BLI_assert(sc_src_parent);
+ BLI_assert(sc_dst_parent);
+
+ /* Remove sc_src from its parent */
+ BLI_remlink(&sc_src_parent->scene_collections, sc_src);
+
+ /* Re-insert it where it belongs */
+ BLI_insertlinkafter(&sc_dst_parent->scene_collections, sc_dst, sc_src);
+
+ /* Update the tree */
+ BKE_layer_collection_resync(scene, sc_src_parent);
+ BKE_layer_collection_resync(scene, sc_dst_parent);
+
+ return true;
+}
+
+bool BKE_collection_move_into(const Scene *scene, SceneCollection *sc_dst, SceneCollection *sc_src)
+{
+ /* Find the SceneCollection the sc_src belongs to */
+ SceneCollection *sc_master = BKE_collection_master(scene);
+ if (sc_src == sc_master) {
+ return false;
+ }
+
+ /* We can't move a collection if the destiny collection
+ * is nested to the source collection */
+ if (is_collection_in_tree(sc_dst, sc_src)) {
+ return false;
+ }
+
+ SceneCollection *sc_src_parent = find_collection_parent(sc_src, sc_master);
+ BLI_assert(sc_src_parent);
+
+ /* collection is already where we wanted it to be */
+ if (sc_dst->scene_collections.last == sc_src) {
+ return false;
+ }
+
+ /* Remove sc_src from it */
+ BLI_remlink(&sc_src_parent->scene_collections, sc_src);
+
+ /* Insert sc_src into sc_dst */
+ BLI_addtail(&sc_dst->scene_collections, sc_src);
+
+ /* Update the tree */
+ BKE_layer_collection_resync(scene, sc_src_parent);
+ BKE_layer_collection_resync(scene, sc_dst);
+
+ return true;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Iteractors */
+/* scene collection iteractor */
+
+typedef struct SceneCollectionsIteratorData {
+ Scene *scene;
+ void **array;
+ int tot, cur;
+} SceneCollectionsIteratorData;
+
+static void scene_collection_callback(SceneCollection *sc, BKE_scene_collections_Cb callback, void *data)
+{
+ callback(sc, data);
+
+ for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
+ scene_collection_callback(nsc, callback, data);
+ }
+}
+
+static void scene_collections_count(SceneCollection *UNUSED(sc), void *data)
+{
+ int *tot = data;
+ (*tot)++;
+}
+
+static void scene_collections_build_array(SceneCollection *sc, void *data)
+{
+ SceneCollection ***array = data;
+ **array = sc;
+ (*array)++;
+}
+
+static void scene_collections_array(Scene *scene, SceneCollection ***collections_array, int *tot)
+{
+ SceneCollection *sc = BKE_collection_master(scene);
+ SceneCollection **array;
+
+ *collections_array = NULL;
+ *tot = 0;
+
+ if (scene == NULL)
+ return;
+
+ scene_collection_callback(sc, scene_collections_count, tot);
+
+ if (*tot == 0)
+ return;
+
+ *collections_array = array = MEM_mallocN(sizeof(SceneCollection *) * (*tot), "SceneCollectionArray");
+ scene_collection_callback(sc, 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;
+ SceneCollectionsIteratorData *data = MEM_callocN(sizeof(SceneCollectionsIteratorData), __func__);
+
+ data->scene = scene;
+ iter->data = data;
+
+ scene_collections_array(scene, (SceneCollection ***)&data->array, &data->tot);
+ BLI_assert(data->tot != 0);
+
+ data->cur = 0;
+ iter->current = data->array[data->cur];
+ iter->valid = true;
+}
+
+void BKE_scene_collections_iterator_next(struct BLI_Iterator *iter)
+{
+ SceneCollectionsIteratorData *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)
+{
+ SceneCollectionsIteratorData *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;
+ LinkData *link_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);
+
+ SceneCollection *sc = data->scene_collection_iter.current;
+ iter->current = sc->objects.first ? ((LinkData *)sc->objects.first)->data : NULL;
+ iter->valid = true;
+
+ if (iter->current == NULL) {
+ BKE_scene_objects_iterator_next(iter);
+ }
+}
+
+/**
+ * Gets the first unique object in the sequence
+ */
+static LinkData *object_base_unique(GSet *gs, LinkData *link)
+{
+ for (; link != NULL; link = link->next) {
+ Object *ob = link->data;
+ void **ob_key_p;
+ if (!BLI_gset_ensure_p_ex(gs, ob, &ob_key_p)) {
+ *ob_key_p = ob;
+ return link;
+ }
+ }
+ return NULL;
+}
+
+void BKE_scene_objects_iterator_next(BLI_Iterator *iter)
+{
+ SceneObjectsIteratorData *data = iter->data;
+ LinkData *link = data->link_next ? object_base_unique(data->visited, data->link_next) : NULL;
+
+ if (link) {
+ data->link_next = link->next;
+ iter->current = link->data;
+ }
+ else {
+ /* if this is the last object of this ListBase look at the next SceneCollection */
+ SceneCollection *sc;
+ BKE_scene_collections_iterator_next(&data->scene_collection_iter);
+ do {
+ sc = data->scene_collection_iter.current;
+ /* get the first unique object of this collection */
+ LinkData *new_link = object_base_unique(data->visited, sc->objects.first);
+ if (new_link) {
+ data->link_next = new_link->next;
+ iter->current = new_link->data;
+ 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 8cac856b560..acb48a9646f 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -71,6 +71,15 @@ void collision_move_object(CollisionModifierData *collmd, float step, float prev
float tv[3] = {0, 0, 0};
unsigned int i = 0;
+ /* the collider doesn't move this frame */
+ if (collmd->is_static) {
+ for (i = 0; i < collmd->mvert_num; i++) {
+ zero_v3(collmd->current_v[i].co);
+ }
+
+ return;
+ }
+
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);
@@ -503,12 +512,13 @@ static void add_collision_object(Object ***objs, unsigned int *numobj, unsigned
// return all collision objects in scene
// collision object will exclude self
-Object **get_collisionobjects(Scene *scene, Object *self, Group *group, unsigned int *numcollobj, unsigned int modifier_type)
+Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, unsigned int *numcollobj, unsigned int modifier_type, bool dupli)
{
Base *base;
Object **objs;
GroupObject *go;
unsigned int numobj= 0, maxobj= 100;
+ int level = dupli ? 0 : 1;
objs= MEM_callocN(sizeof(Object *)*maxobj, "CollisionObjectsArray");
@@ -516,17 +526,15 @@ Object **get_collisionobjects(Scene *scene, Object *self, Group *group, unsigned
if (group) {
/* use specified group */
for (go= group->gobject.first; go; go= go->next)
- add_collision_object(&objs, &numobj, &maxobj, go->ob, self, 0, modifier_type);
+ 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)) {
- /* Need to check for active layers, too.
- Otherwise this check fails if the objects are not on the same layer - DG */
- if ((base->lay & self->lay) || (base->lay & scene->lay))
- add_collision_object(&objs, &numobj, &maxobj, base->object, self, 0, modifier_type);
-
+ if ((base->flag & BASE_VISIBLED) != 0) {
+ add_collision_object(&objs, &numobj, &maxobj, base->object, self, level, modifier_type);
+ }
}
}
@@ -535,6 +543,13 @@ Object **get_collisionobjects(Scene *scene, Object *self, Group *group, unsigned
return objs;
}
+Object **get_collisionobjects(Scene *scene, Object *self, Group *group, unsigned int *numcollobj, unsigned int modifier_type)
+{
+ /* 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, numcollobj, modifier_type, true);
+}
+
static void add_collider_cache_object(ListBase **objs, Object *ob, Object *self, int level)
{
CollisionModifierData *cmd= NULL;
@@ -585,7 +600,7 @@ ListBase *get_collider_cache(Scene *scene, Object *self, Group *group)
/* add objects in same layer in scene */
for (SETLOOPER(scene, sce_iter, base)) {
- if (!self || (base->lay & self->lay))
+ if (!self || ((base->flag & BASE_VISIBLED) != 0))
add_collider_cache_object(&objs, base->object, self, 0);
}
@@ -999,7 +1014,7 @@ static bool cloth_points_collision_response_static(ClothModifierData *clmd, Coll
}
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[4])
+ float r_nor[3], float *r_lambda, float r_w[3])
{
float edge1[3], edge2[3], p2face[3], p1p2[3], v0p2[3];
float nor_v0p2, nor_p1p2;
@@ -1011,7 +1026,7 @@ BLI_INLINE bool cloth_point_face_collision_params(const float p1[3], const float
nor_v0p2 = dot_v3v3(v0p2, r_nor);
madd_v3_v3v3fl(p2face, p2, r_nor, -nor_v0p2);
- interp_weights_face_v3(r_w, v0, v1, v2, NULL, p2face);
+ interp_weights_tri_v3(r_w, v0, v1, v2, p2face);
sub_v3_v3v3(p1p2, p2, p1);
sub_v3_v3v3(v0p2, p2, v0);
@@ -1070,7 +1085,7 @@ static CollPair *cloth_point_collpair(
const float *co1 = mverts[bp1].co, *co2 = mverts[bp2].co, *co3 = mverts[bp3].co;
float lambda /*, distance1 */, distance2;
float facenor[3], v1p1[3], v1p2[3];
- float w[4];
+ float w[3];
if (!cloth_point_face_collision_params(p1, p2, co1, co2, co3, facenor, &lambda, w))
return collpair;
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index 4f3ffed41bc..ee0f904c3a6 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -130,7 +130,7 @@ void curvemapping_free(CurveMapping *cumap)
}
}
-void curvemapping_copy_data(CurveMapping *target, CurveMapping *cumap)
+void curvemapping_copy_data(CurveMapping *target, const CurveMapping *cumap)
{
int a;
@@ -146,7 +146,7 @@ void curvemapping_copy_data(CurveMapping *target, CurveMapping *cumap)
}
}
-CurveMapping *curvemapping_copy(CurveMapping *cumap)
+CurveMapping *curvemapping_copy(const CurveMapping *cumap)
{
if (cumap) {
CurveMapping *cumapn = MEM_dupallocN(cumap);
@@ -508,7 +508,7 @@ static void calchandle_curvemap(
if ((bezt->h2 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */
const float ydiff1 = prev->vec[1][1] - bezt->vec[1][1];
const float ydiff2 = next->vec[1][1] - bezt->vec[1][1];
- if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f)||
+ if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) ||
(ydiff1 >= 0.0f && ydiff2 >= 0.0f))
{
bezt->vec[2][1] = bezt->vec[1][1];
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 70fdd4aa72e..07a6b304dff 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -42,7 +42,7 @@
#include "BLI_math.h"
#include "BLI_kdopbvh.h"
#include "BLI_utildefines.h"
-
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
#include "DNA_armature_types.h"
@@ -790,7 +790,7 @@ static void default_get_tarmat(bConstraint *con, bConstraintOb *UNUSED(cob), bCo
ct = ctn; \
} \
} (void)0
-
+
/* --------- ChildOf Constraint ------------ */
static void childof_new_data(void *cdata)
@@ -4344,7 +4344,7 @@ static bConstraintTypeInfo CTI_OBJECTSOLVER = {
static void transformcache_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
bTransformCacheConstraint *data = con->data;
- func(con, (ID **)&data->cache_file, false, userdata);
+ func(con, (ID **)&data->cache_file, true, userdata);
}
static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
@@ -4353,15 +4353,25 @@ static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBa
bTransformCacheConstraint *data = con->data;
Scene *scene = cob->scene;
- const float frame = BKE_scene_frame_get(scene);
- const float time = BKE_cachefile_time_offset(data->cache_file, frame, FPS);
-
CacheFile *cache_file = data->cache_file;
+ if (!cache_file) {
+ return;
+ }
+
+ const float frame = BKE_scene_frame_get(scene);
+ const float time = BKE_cachefile_time_offset(cache_file, frame, FPS);
+
BKE_cachefile_ensure_handle(G.main, cache_file);
- ABC_get_transform(cache_file->handle, cob->ob, data->object_path,
- cob->matrix, time, cache_file->scale);
+ if (!data->reader) {
+ data->reader = CacheReader_open_alembic_object(cache_file->handle,
+ data->reader,
+ cob->ob,
+ data->object_path);
+ }
+
+ ABC_get_transform(data->reader, cob->matrix, time, cache_file->scale);
#else
UNUSED_VARS(con, cob);
#endif
@@ -4377,20 +4387,32 @@ static void transformcache_copy(bConstraint *con, bConstraint *srccon)
BLI_strncpy(dst->object_path, src->object_path, sizeof(dst->object_path));
dst->cache_file = src->cache_file;
- if (dst->cache_file) {
- id_us_plus(&dst->cache_file->id);
+#ifdef WITH_ALEMBIC
+ if (dst->reader) {
+ CacheReader_incref(dst->reader);
}
+#endif
}
static void transformcache_free(bConstraint *con)
{
bTransformCacheConstraint *data = con->data;
- if (data->cache_file) {
- id_us_min(&data->cache_file->id);
+ if (data->reader) {
+#ifdef WITH_ALEMBIC
+ CacheReader_free(data->reader);
+#endif
+ data->reader = NULL;
}
}
+static void transformcache_new_data(void *cdata)
+{
+ bTransformCacheConstraint *data = (bTransformCacheConstraint *)cdata;
+
+ data->cache_file = NULL;
+}
+
static bConstraintTypeInfo CTI_TRANSFORM_CACHE = {
CONSTRAINT_TYPE_TRANSFORM_CACHE, /* type */
sizeof(bTransformCacheConstraint), /* size */
@@ -4399,7 +4421,7 @@ static bConstraintTypeInfo CTI_TRANSFORM_CACHE = {
transformcache_free, /* free data */
transformcache_id_looper, /* id looper */
transformcache_copy, /* copy data */
- NULL, /* new data */
+ transformcache_new_data, /* new data */
NULL, /* get constraint targets */
NULL, /* flush constraint targets */
NULL, /* get target matrix */
@@ -4682,27 +4704,6 @@ bConstraint *BKE_constraint_add_for_object(Object *ob, const char *name, short t
/* ......... */
-/* helper for BKE_constraints_relink() - call ID_NEW() on every ID reference the constraint has */
-static void con_relink_id_cb(bConstraint *UNUSED(con), ID **idpoin, bool UNUSED(is_reference), void *UNUSED(userdata))
-{
- /* ID_NEW() expects a struct with inline "id" member as first
- * since we've got the actual ID block, let's just inline this
- * code.
- *
- * See ID_NEW(a) in DNA_ID.h
- */
- if ((*idpoin) && (*idpoin)->newid)
- (*idpoin) = (void *)(*idpoin)->newid;
-}
-
-/* Reassign links that constraints have to other data (called during file loading?) */
-void BKE_constraints_relink(ListBase *conlist)
-{
- /* just a wrapper around ID-loop for just calling ID_NEW() on all ID refs */
- BKE_constraints_id_loop(conlist, con_relink_id_cb, NULL);
-}
-
-
/* Run the given callback on all ID-blocks in list of constraints */
void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *userdata)
{
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index 2dc028f3102..8cb9fb3fad5 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -38,6 +38,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,8 +50,12 @@
#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 "RNA_access.h"
@@ -65,6 +72,7 @@ struct bContext {
struct {
struct wmWindowManager *manager;
struct wmWindow *window;
+ struct WorkSpace *workspace;
struct bScreen *screen;
struct ScrArea *area;
struct ARegion *region;
@@ -626,6 +634,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);
@@ -825,9 +838,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;
}
@@ -835,8 +850,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;
}
@@ -882,6 +895,7 @@ Main *CTX_data_main(const bContext *C)
void CTX_data_main_set(bContext *C, Main *bmain)
{
C->data.main = bmain;
+ BKE_sound_init_main(bmain);
}
Scene *CTX_data_scene(const bContext *C)
@@ -894,10 +908,62 @@ Scene *CTX_data_scene(const bContext *C)
return C->data.scene;
}
-int CTX_data_mode_enum(const bContext *C)
+SceneLayer *CTX_data_scene_layer(const bContext *C)
{
- Object *obedit = CTX_data_edit_object(C);
+ SceneLayer *sl;
+
+ if (ctx_data_pointer_verify(C, "render_layer", (void *)&sl)) {
+ return sl;
+ }
+ else {
+ return BKE_scene_layer_context_active_ex_PLACEHOLDER(CTX_data_main(C), CTX_data_scene(C));
+ }
+}
+
+/**
+ * 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 SceneLayer we use it.
+ * Otherwise we fallback to the active one of the SceneLayer.
+ */
+LayerCollection *CTX_data_layer_collection(const bContext *C)
+{
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ LayerCollection *lc;
+
+ if (ctx_data_pointer_verify(C, "layer_collection", (void *)&lc)) {
+ if (BKE_scene_layer_has_collection(sl, lc->scene_collection)) {
+ return lc;
+ }
+ }
+ /* fallback */
+ return BKE_layer_collection_get_active(sl);
+}
+
+SceneCollection *CTX_data_scene_collection(const bContext *C)
+{
+ SceneCollection *sc;
+ if (ctx_data_pointer_verify(C, "scene_collection", (void *)&sc)) {
+ if (BKE_scene_layer_has_collection(CTX_data_scene_layer(C), sc)) {
+ return sc;
+ }
+ }
+
+ LayerCollection *lc = CTX_data_layer_collection(C);
+ if (lc) {
+ return lc->scene_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)
+{
+ // Object *obedit = CTX_data_edit_object(C);
if (obedit) {
switch (obedit->type) {
case OB_MESH:
@@ -917,8 +983,7 @@ 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;
@@ -933,6 +998,12 @@ int CTX_data_mode_enum(const bContext *C)
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);
+}
/* would prefer if we can use the enum version below over this one - Campbell */
/* must be aligned with above enum */
@@ -1154,3 +1225,9 @@ 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);
+ SceneLayer *scene_layer = CTX_data_scene_layer(C);
+ return BKE_scene_get_depsgraph(scene, scene_layer);
+}
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 90a514781d7..2863a925000 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -52,7 +52,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"
@@ -64,6 +63,8 @@
#include "BKE_object.h"
#include "BKE_material.h"
+#include "DEG_depsgraph.h"
+
/* globals */
/* local */
@@ -89,20 +90,33 @@ void BKE_curve_editfont_free(Curve *cu)
}
}
-void BKE_curve_editNurb_keyIndex_free(EditNurb *editnurb)
+static void curve_editNurb_keyIndex_cv_free_cb(void *val)
+{
+ CVKeyIndex *index = val;
+ MEM_freeN(index->orig_cv);
+ MEM_freeN(val);
+}
+
+void BKE_curve_editNurb_keyIndex_delCV(GHash *keyindex, const void *cv)
{
- if (!editnurb->keyindex) {
+ BLI_assert(keyindex != NULL);
+ BLI_ghash_remove(keyindex, cv, NULL, curve_editNurb_keyIndex_cv_free_cb);
+}
+
+void BKE_curve_editNurb_keyIndex_free(GHash **keyindex)
+{
+ if (!(*keyindex)) {
return;
}
- BLI_ghash_free(editnurb->keyindex, NULL, MEM_freeN);
- editnurb->keyindex = NULL;
+ BLI_ghash_free(*keyindex, NULL, curve_editNurb_keyIndex_cv_free_cb);
+ *keyindex = NULL;
}
void BKE_curve_editNurb_free(Curve *cu)
{
if (cu->editnurb) {
BKE_nurbList_free(&cu->editnurb->nurbs);
- BKE_curve_editNurb_keyIndex_free(cu->editnurb);
+ BKE_curve_editNurb_keyIndex_free(&cu->editnurb->keyindex);
MEM_freeN(cu->editnurb);
cu->editnurb = NULL;
}
@@ -113,6 +127,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);
@@ -174,7 +190,7 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type)
return cu;
}
-Curve *BKE_curve_copy(Main *bmain, Curve *cu)
+Curve *BKE_curve_copy(Main *bmain, const Curve *cu)
{
Curve *cun;
int a;
@@ -193,6 +209,7 @@ Curve *BKE_curve_copy(Main *bmain, Curve *cu)
cun->strinfo = MEM_dupallocN(cu->strinfo);
cun->tb = MEM_dupallocN(cu->tb);
cun->bb = MEM_dupallocN(cu->bb);
+ cun->batch_cache = NULL;
if (cu->key) {
cun->key = BKE_key_copy(bmain, cu->key);
@@ -455,7 +472,7 @@ void BKE_nurbList_free(ListBase *lb)
BLI_listbase_clear(lb);
}
-Nurb *BKE_nurb_duplicate(Nurb *nu)
+Nurb *BKE_nurb_duplicate(const Nurb *nu)
{
Nurb *newnu;
int len;
@@ -519,7 +536,7 @@ Nurb *BKE_nurb_copy(Nurb *src, int pntsu, int pntsv)
return newnu;
}
-void BKE_nurbList_duplicate(ListBase *lb1, ListBase *lb2)
+void BKE_nurbList_duplicate(ListBase *lb1, const ListBase *lb2)
{
Nurb *nu, *nun;
@@ -731,6 +748,7 @@ BezTriple *BKE_nurb_bezt_get_prev(Nurb *nu, BezTriple *bezt)
BezTriple *bezt_prev;
BLI_assert(ARRAY_HAS_ITEM(bezt, nu->bezt, nu->pntsu));
+ BLI_assert(nu->pntsv == 1);
if (bezt == nu->bezt) {
if (nu->flagu & CU_NURB_CYCLIC) {
@@ -752,6 +770,7 @@ BPoint *BKE_nurb_bpoint_get_prev(Nurb *nu, BPoint *bp)
BPoint *bp_prev;
BLI_assert(ARRAY_HAS_ITEM(bp, nu->bp, nu->pntsu));
+ BLI_assert(nu->pntsv == 1);
if (bp == nu->bp) {
if (nu->flagu & CU_NURB_CYCLIC) {
@@ -768,7 +787,7 @@ BPoint *BKE_nurb_bpoint_get_prev(Nurb *nu, BPoint *bp)
return bp_prev;
}
-void BKE_nurb_bezt_calc_normal(struct Nurb *UNUSED(nu), struct BezTriple *bezt, float r_normal[3])
+void BKE_nurb_bezt_calc_normal(struct Nurb *UNUSED(nu), BezTriple *bezt, float r_normal[3])
{
/* calculate the axis matrix from the spline */
float dir_prev[3], dir_next[3];
@@ -783,7 +802,7 @@ void BKE_nurb_bezt_calc_normal(struct Nurb *UNUSED(nu), struct BezTriple *bezt,
normalize_v3(r_normal);
}
-void BKE_nurb_bezt_calc_plane(struct Nurb *nu, struct BezTriple *bezt, float r_plane[3])
+void BKE_nurb_bezt_calc_plane(struct Nurb *nu, BezTriple *bezt, float r_plane[3])
{
float dir_prev[3], dir_next[3];
@@ -820,7 +839,7 @@ void BKE_nurb_bezt_calc_plane(struct Nurb *nu, struct BezTriple *bezt, float r_p
normalize_v3(r_plane);
}
-void BKE_nurb_bpoint_calc_normal(struct Nurb *nu, struct BPoint *bp, float r_normal[3])
+void BKE_nurb_bpoint_calc_normal(struct Nurb *nu, BPoint *bp, float r_normal[3])
{
BPoint *bp_prev = BKE_nurb_bpoint_get_prev(nu, bp);
BPoint *bp_next = BKE_nurb_bpoint_get_next(nu, bp);
@@ -843,6 +862,34 @@ void BKE_nurb_bpoint_calc_normal(struct Nurb *nu, struct BPoint *bp, float r_nor
normalize_v3(r_normal);
}
+void BKE_nurb_bpoint_calc_plane(struct Nurb *nu, BPoint *bp, float r_plane[3])
+{
+ BPoint *bp_prev = BKE_nurb_bpoint_get_prev(nu, bp);
+ BPoint *bp_next = BKE_nurb_bpoint_get_next(nu, bp);
+
+ float dir_prev[3] = {0.0f}, dir_next[3] = {0.0f};
+
+ if (bp_prev) {
+ sub_v3_v3v3(dir_prev, bp_prev->vec, bp->vec);
+ normalize_v3(dir_prev);
+ }
+ if (bp_next) {
+ sub_v3_v3v3(dir_next, bp->vec, bp_next->vec);
+ normalize_v3(dir_next);
+ }
+ cross_v3_v3v3(r_plane, dir_prev, dir_next);
+
+ /* matches with bones more closely */
+ {
+ float dir_mid[3], tvec[3];
+ add_v3_v3v3(dir_mid, dir_prev, dir_next);
+ cross_v3_v3v3(tvec, r_plane, dir_mid);
+ copy_v3_v3(r_plane, tvec);
+ }
+
+ normalize_v3(r_plane);
+}
+
/* ~~~~~~~~~~~~~~~~~~~~Non Uniform Rational B Spline calculations ~~~~~~~~~~~ */
@@ -4555,7 +4602,7 @@ int 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 {
@@ -4643,3 +4690,20 @@ void BKE_curve_eval_path(EvaluationContext *UNUSED(eval_ctx),
printf("%s on %s\n", __func__, curve->id.name);
}
}
+
+/* Draw Engine */
+void (*BKE_curve_batch_cache_dirty_cb)(Curve *cu, int mode) = NULL;
+void (*BKE_curve_batch_cache_free_cb)(Curve *cu) = NULL;
+
+void BKE_curve_batch_cache_dirty(Curve *cu, int mode)
+{
+ if (cu->batch_cache) {
+ BKE_curve_batch_cache_dirty_cb(cu, mode);
+ }
+}
+void BKE_curve_batch_cache_free(Curve *cu)
+{
+ if (cu->batch_cache) {
+ BKE_curve_batch_cache_free_cb(cu);
+ }
+} \ No newline at end of file
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index f6263b955a6..1833a3f2b5a 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -33,20 +33,17 @@
/** \file blender/blenkernel/intern/customdata.c
* \ingroup bke
*/
-
-
-#include <math.h>
-#include <string.h>
-#include <assert.h>
#include "MEM_guardedalloc.h"
+#include "DNA_customdata_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_ID.h"
#include "BLI_utildefines.h"
-#include "BLI_string.h"
#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_math.h"
#include "BLI_math_color_blend.h"
#include "BLI_mempool.h"
@@ -62,20 +59,16 @@
#include "BKE_mesh_remap.h"
#include "BKE_multires.h"
-#include "data_transfer_intern.h"
-
#include "bmesh.h"
-#include <math.h>
-#include <string.h>
+/* only for customdata_data_transfer_interp_normal_normals */
+#include "data_transfer_intern.h"
/* number of layers to add when growing a CustomData object */
#define CUSTOMDATA_GROW 5
/* ensure typemap size is ok */
-BLI_STATIC_ASSERT(sizeof(((CustomData *)NULL)->typemap) /
- sizeof(((CustomData *)NULL)->typemap[0]) == CD_NUMTYPES,
- "size mismatch");
+BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)NULL)->typemap) == CD_NUMTYPES, "size mismatch");
/********************* Layer type information **********************/
@@ -398,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;
@@ -805,18 +780,15 @@ static void layerInterp_mloopcol(
const float *sub_weights, int count, void *dest)
{
MLoopCol *mc = dest;
- int i;
- const float *sub_weight;
struct {
float a;
float r;
float g;
float b;
- } col;
- col.a = col.r = col.g = col.b = 0;
+ } col = {0};
- sub_weight = sub_weights;
- for (i = 0; i < count; ++i) {
+ const float *sub_weight = sub_weights;
+ for (int i = 0; i < count; ++i) {
float weight = weights ? weights[i] : 1;
const MLoopCol *src = sources[i];
if (sub_weights) {
@@ -833,19 +805,16 @@ static void layerInterp_mloopcol(
col.a += src->a * weight;
}
}
-
+
+
/* Subdivide smooth or fractal can cause problems without clamping
* although weights should also not cause this situation */
- CLAMP(col.a, 0.0f, 255.0f);
- CLAMP(col.r, 0.0f, 255.0f);
- CLAMP(col.g, 0.0f, 255.0f);
- CLAMP(col.b, 0.0f, 255.0f);
- /* delay writing to the destination incase dest is in sources */
- mc->r = (int)col.r;
- mc->g = (int)col.g;
- mc->b = (int)col.b;
- mc->a = (int)col.a;
+ /* also delay writing to the destination incase dest is in sources */
+ mc->r = CLAMPIS(iroundf(col.r), 0, 255);
+ mc->g = CLAMPIS(iroundf(col.g), 0, 255);
+ mc->b = CLAMPIS(iroundf(col.b), 0, 255);
+ mc->a = CLAMPIS(iroundf(col.a), 0, 255);
}
static int layerMaxNum_mloopcol(void)
@@ -1068,15 +1037,10 @@ static void layerInterp_mcol(
/* Subdivide smooth or fractal can cause problems without clamping
* although weights should also not cause this situation */
- CLAMP(col[j].a, 0.0f, 255.0f);
- CLAMP(col[j].r, 0.0f, 255.0f);
- CLAMP(col[j].g, 0.0f, 255.0f);
- CLAMP(col[j].b, 0.0f, 255.0f);
-
- mc[j].a = (int)col[j].a;
- mc[j].r = (int)col[j].r;
- mc[j].g = (int)col[j].g;
- mc[j].b = (int)col[j].b;
+ mc[j].a = CLAMPIS(iroundf(col[j].a), 0, 255);
+ mc[j].r = CLAMPIS(iroundf(col[j].r), 0, 255);
+ mc[j].g = CLAMPIS(iroundf(col[j].g), 0, 255);
+ mc[j].b = CLAMPIS(iroundf(col[j].b), 0, 255);
}
}
@@ -1209,6 +1173,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},
@@ -1234,8 +1207,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 */
@@ -1247,10 +1220,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,
@@ -1331,7 +1303,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",
@@ -1346,41 +1318,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 |
@@ -1400,7 +1372,7 @@ const CustomDataMask CD_MASK_STRANDS_BMESH =
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 |
@@ -1408,7 +1380,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)
{
@@ -1976,11 +1948,15 @@ void *CustomData_add_layer_named(CustomData *data, int type, int alloctype,
bool CustomData_free_layer(CustomData *data, int type, int totelem, int index)
{
- const int n = index - CustomData_get_layer_index(data, type);
+ const int index_first = CustomData_get_layer_index(data, type);
+ const int n = index - index_first;
int i;
-
- if (index < 0)
+
+ BLI_assert(index >= index_first);
+ if ((index_first == -1) || (n < 0)) {
return false;
+ }
+ BLI_assert(data->layers[index].type == type);
customData_free_layer__internal(&data->layers[index], totelem);
@@ -2025,8 +2001,10 @@ bool CustomData_free_layer_active(CustomData *data, int type, int totelem)
void CustomData_free_layers(CustomData *data, int type, int totelem)
{
- while (CustomData_has_layer(data, type))
- CustomData_free_layer_active(data, type, totelem);
+ const int index = CustomData_get_layer_index(data, type);
+ while (CustomData_free_layer(data, type, totelem, index)) {
+ /* pass */
+ }
}
bool CustomData_has_layer(const CustomData *data, int type)
@@ -2528,13 +2506,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) {
@@ -2549,19 +2524,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);
}
@@ -2579,7 +2553,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
@@ -2589,13 +2563,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;
@@ -2608,7 +2582,7 @@ bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *pdata, Custom
if (!LAYER_CMP(ldata, CD_TANGENT, fdata, CD_TANGENT))
return false;
-#undef TEST_RET
+#undef LAYER_CMP
/* if no layers are on either CustomData's,
* then there was nothing to do... */
@@ -2617,25 +2591,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);
}
@@ -2659,25 +2629,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);
}
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index 839673c192b..a83ec8f0486 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -79,7 +79,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;
@@ -962,7 +962,7 @@ 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)) {
@@ -1205,6 +1205,18 @@ 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)) {
+ 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)) {
+ BKE_report(reports, RPT_ERROR,
+ "Source mesh doesn't have any faces, "
+ "None of the 'Face' mappings can be used in this case");
+ continue;
+ }
if (ELEM(0, num_verts_dst, num_verts_src)) {
BKE_report(reports, RPT_ERROR,
"Source or destination meshes do not have any vertices, cannot transfer vertex data");
@@ -1253,6 +1265,12 @@ 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)) {
+ BKE_report(reports, RPT_ERROR,
+ "Source mesh doesn't have any faces, "
+ "None of the 'Face' mappings can be used in this case");
+ continue;
+ }
if (ELEM(0, num_edges_dst, num_edges_src)) {
BKE_report(reports, RPT_ERROR,
"Source or destination meshes do not have any edges, cannot transfer edge data");
@@ -1312,9 +1330,15 @@ 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)) {
+ 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 (ELEM(0, num_loops_dst, num_loops_src)) {
BKE_report(reports, RPT_ERROR,
- "Source or destination meshes do not have any polygons, cannot transfer loop data");
+ "Source or destination meshes do not have any faces, cannot transfer corner data");
continue;
}
@@ -1370,9 +1394,15 @@ 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)) {
+ 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 (ELEM(0, num_polys_dst, num_polys_src)) {
BKE_report(reports, RPT_ERROR,
- "Source or destination meshes do not have any polygons, cannot transfer poly data");
+ "Source or destination meshes do not have any faces, cannot transfer face data");
continue;
}
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index 7052e0a7d25..ffe9986d166 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -45,8 +45,8 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
-#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -54,6 +54,7 @@
#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_deform.h"
@@ -73,10 +74,12 @@ bDeformGroup *BKE_defgroup_new(Object *ob, const char *name)
BLI_addtail(&ob->defbase, defgroup);
defgroup_unique_name(defgroup, ob);
+ BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_NOCHECK);
+
return defgroup;
}
-void defgroup_copy_list(ListBase *outbase, ListBase *inbase)
+void defgroup_copy_list(ListBase *outbase, const ListBase *inbase)
{
bDeformGroup *defgroup, *defgroupn;
@@ -88,7 +91,7 @@ void defgroup_copy_list(ListBase *outbase, ListBase *inbase)
}
}
-bDeformGroup *defgroup_duplicate(bDeformGroup *ingroup)
+bDeformGroup *defgroup_duplicate(const bDeformGroup *ingroup)
{
bDeformGroup *outgroup;
@@ -509,7 +512,7 @@ int *defgroup_flip_map(Object *ob, int *flip_map_len, const bool use_default)
if (use_default)
map[i] = i;
- BKE_deform_flip_side_name(name_flip, dg->name, false);
+ BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip));
if (!STREQ(name_flip, dg->name)) {
flip_num = defgroup_name_index(ob, name_flip);
@@ -545,7 +548,7 @@ int *defgroup_flip_map_single(Object *ob, int *flip_map_len, const bool use_defa
dg = BLI_findlink(&ob->defbase, defgroup);
- BKE_deform_flip_side_name(name_flip, dg->name, false);
+ BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip));
if (!STREQ(name_flip, dg->name)) {
flip_num = defgroup_name_index(ob, name_flip);
@@ -566,7 +569,7 @@ int defgroup_flip_index(Object *ob, int index, const bool use_default)
if (dg) {
char name_flip[sizeof(dg->name)];
- BKE_deform_flip_side_name(name_flip, dg->name, false);
+ BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip));
if (!STREQ(name_flip, dg->name)) {
flip_index = defgroup_name_index(ob, name_flip);
@@ -606,185 +609,6 @@ void defgroup_unique_name(bDeformGroup *dg, Object *ob)
BLI_uniquename_cb(defgroup_unique_check, &data, DATA_("Group"), '.', dg->name, sizeof(dg->name));
}
-static bool is_char_sep(const char c)
-{
- return ELEM(c, '.', ' ', '-', '_');
-}
-
-/**
- * based on `BLI_split_dirfile()` / `os.path.splitext()`,
- * `"a.b.c"` -> (`"a.b"`, `".c"`).
- */
-void BKE_deform_split_suffix(const char string[MAX_VGROUP_NAME], char body[MAX_VGROUP_NAME], char suf[MAX_VGROUP_NAME])
-{
- size_t len = BLI_strnlen(string, MAX_VGROUP_NAME);
- size_t i;
-
- body[0] = suf[0] = '\0';
-
- for (i = len; i > 0; i--) {
- if (is_char_sep(string[i])) {
- BLI_strncpy(body, string, i + 1);
- BLI_strncpy(suf, string + i, (len + 1) - i);
- return;
- }
- }
-
- memcpy(body, string, len + 1);
-}
-
-/**
- * `"a.b.c"` -> (`"a."`, `"b.c"`)
- */
-void BKE_deform_split_prefix(const char string[MAX_VGROUP_NAME], char pre[MAX_VGROUP_NAME], char body[MAX_VGROUP_NAME])
-{
- size_t len = BLI_strnlen(string, MAX_VGROUP_NAME);
- size_t i;
-
- body[0] = pre[0] = '\0';
-
- for (i = 1; i < len; i++) {
- if (is_char_sep(string[i])) {
- i++;
- BLI_strncpy(pre, string, i + 1);
- BLI_strncpy(body, string + i, (len + 1) - i);
- return;
- }
- }
-
- BLI_strncpy(body, string, len);
-}
-
-/**
- * Finds the best possible flipped name. For renaming; check for unique names afterwards.
- *
- * if strip_number: removes number extensions
- *
- * \note don't use sizeof() for 'name' or 'from_name'.
- */
-void BKE_deform_flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[MAX_VGROUP_NAME],
- const bool strip_number)
-{
- int len;
- char prefix[MAX_VGROUP_NAME] = ""; /* The part before the facing */
- char suffix[MAX_VGROUP_NAME] = ""; /* The part after the facing */
- char replace[MAX_VGROUP_NAME] = ""; /* The replacement string */
- char number[MAX_VGROUP_NAME] = ""; /* The number extension string */
- char *index = NULL;
- bool is_set = false;
-
- /* always copy the name, since this can be called with an uninitialized string */
- BLI_strncpy(name, from_name, MAX_VGROUP_NAME);
-
- len = BLI_strnlen(from_name, MAX_VGROUP_NAME);
- if (len < 3) {
- /* we don't do names like .R or .L */
- return;
- }
-
- /* We first check the case with a .### extension, let's find the last period */
- if (isdigit(name[len - 1])) {
- index = strrchr(name, '.'); // last occurrence
- if (index && isdigit(index[1])) { // doesnt handle case bone.1abc2 correct..., whatever!
- if (strip_number == false) {
- BLI_strncpy(number, index, sizeof(number));
- }
- *index = 0;
- len = BLI_strnlen(name, MAX_VGROUP_NAME);
- }
- }
-
- BLI_strncpy(prefix, name, sizeof(prefix));
-
- /* first case; separator . - _ with extensions r R l L */
- if ((len > 1) && is_char_sep(name[len - 2])) {
- is_set = true;
- switch (name[len - 1]) {
- case 'l':
- prefix[len - 1] = 0;
- strcpy(replace, "r");
- break;
- case 'r':
- prefix[len - 1] = 0;
- strcpy(replace, "l");
- break;
- case 'L':
- prefix[len - 1] = 0;
- strcpy(replace, "R");
- break;
- case 'R':
- prefix[len - 1] = 0;
- strcpy(replace, "L");
- break;
- default:
- is_set = false;
- }
- }
-
- /* case; beginning with r R l L, with separator after it */
- if (!is_set && is_char_sep(name[1])) {
- is_set = true;
- switch (name[0]) {
- case 'l':
- strcpy(replace, "r");
- BLI_strncpy(suffix, name + 1, sizeof(suffix));
- prefix[0] = 0;
- break;
- case 'r':
- strcpy(replace, "l");
- BLI_strncpy(suffix, name + 1, sizeof(suffix));
- prefix[0] = 0;
- break;
- case 'L':
- strcpy(replace, "R");
- BLI_strncpy(suffix, name + 1, sizeof(suffix));
- prefix[0] = 0;
- break;
- case 'R':
- strcpy(replace, "L");
- BLI_strncpy(suffix, name + 1, sizeof(suffix));
- prefix[0] = 0;
- break;
- default:
- is_set = false;
- }
- }
-
- if (!is_set && len > 5) {
- /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */
- if (((index = BLI_strcasestr(prefix, "right")) == prefix) ||
- (index == prefix + len - 5))
- {
- is_set = true;
- if (index[0] == 'r') {
- strcpy(replace, "left");
- }
- else {
- strcpy(replace, (index[1] == 'I') ? "LEFT" : "Left");
- }
- *index = 0;
- BLI_strncpy(suffix, index + 5, sizeof(suffix));
- }
- else if (((index = BLI_strcasestr(prefix, "left")) == prefix) ||
- (index == prefix + len - 4))
- {
- is_set = true;
- if (index[0] == 'l') {
- strcpy(replace, "right");
- }
- else {
- strcpy(replace, (index[1] == 'E') ? "RIGHT" : "Right");
- }
- *index = 0;
- BLI_strncpy(suffix, index + 4, sizeof(suffix));
- }
- }
-
- (void)is_set; /* quiet warning */
-
- BLI_snprintf(name, MAX_VGROUP_NAME, "%s%s%s%s", prefix, replace, suffix, number);
-}
-
float defvert_find_weight(const struct MDeformVert *dvert, const int defgroup)
{
MDeformWeight *dw = defvert_find_index(dvert, defgroup);
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
deleted file mode 100644
index 45a23c39910..00000000000
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ /dev/null
@@ -1,3695 +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/intern/depsgraph.c
- * \ingroup bke
- */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "MEM_guardedalloc.h"
-
-#ifdef WIN32
-# include "BLI_winstuff.h"
-#endif
-
-#include "BLI_utildefines.h"
-#include "BLI_listbase.h"
-#include "BLI_ghash.h"
-#include "BLI_threads.h"
-
-#include "DNA_anim_types.h"
-#include "DNA_camera_types.h"
-#include "DNA_cachefile_types.h"
-#include "DNA_group_types.h"
-#include "DNA_lamp_types.h"
-#include "DNA_lattice_types.h"
-#include "DNA_key_types.h"
-#include "DNA_material_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_node_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_windowmanager_types.h"
-#include "DNA_movieclip_types.h"
-#include "DNA_mask_types.h"
-
-#include "BKE_anim.h"
-#include "BKE_animsys.h"
-#include "BKE_action.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_effect.h"
-#include "BKE_fcurve.h"
-#include "BKE_global.h"
-#include "BKE_idcode.h"
-#include "BKE_image.h"
-#include "BKE_key.h"
-#include "BKE_library.h"
-#include "BKE_main.h"
-#include "BKE_node.h"
-#include "BKE_material.h"
-#include "BKE_mball.h"
-#include "BKE_modifier.h"
-#include "BKE_object.h"
-#include "BKE_paint.h"
-#include "BKE_particle.h"
-#include "BKE_pointcache.h"
-#include "BKE_scene.h"
-#include "BKE_screen.h"
-#include "BKE_tracking.h"
-
-#include "GPU_buffers.h"
-
-#include "atomic_ops.h"
-
-#include "depsgraph_private.h"
-
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_build.h"
-#include "DEG_depsgraph_debug.h"
-#include "DEG_depsgraph_query.h"
-
-#ifdef WITH_LEGACY_DEPSGRAPH
-
-static SpinLock threaded_update_lock;
-
-void DAG_init(void)
-{
- BLI_spin_init(&threaded_update_lock);
- DEG_register_node_types();
-}
-
-void DAG_exit(void)
-{
- BLI_spin_end(&threaded_update_lock);
- DEG_free_node_types();
-}
-
-/* Queue and stack operations for dag traversal
- *
- * the queue store a list of freenodes to avoid successive alloc/dealloc
- */
-
-DagNodeQueue *queue_create(int slots)
-{
- DagNodeQueue *queue;
- DagNodeQueueElem *elem;
- int i;
-
- queue = MEM_mallocN(sizeof(DagNodeQueue), "DAG queue");
- queue->freenodes = MEM_mallocN(sizeof(DagNodeQueue), "DAG queue");
- queue->count = 0;
- queue->maxlevel = 0;
- queue->first = queue->last = NULL;
- elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem3");
- elem->node = NULL;
- elem->next = NULL;
- queue->freenodes->first = queue->freenodes->last = elem;
-
- for (i = 1; i < slots; i++) {
- elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem4");
- elem->node = NULL;
- elem->next = NULL;
- queue->freenodes->last->next = elem;
- queue->freenodes->last = elem;
- }
- queue->freenodes->count = slots;
- return queue;
-}
-
-void queue_raz(DagNodeQueue *queue)
-{
- DagNodeQueueElem *elem;
-
- elem = queue->first;
- if (queue->freenodes->last)
- queue->freenodes->last->next = elem;
- else
- queue->freenodes->first = queue->freenodes->last = elem;
-
- elem->node = NULL;
- queue->freenodes->count++;
- while (elem->next) {
- elem = elem->next;
- elem->node = NULL;
- queue->freenodes->count++;
- }
- queue->freenodes->last = elem;
- queue->count = 0;
-}
-
-void queue_delete(DagNodeQueue *queue)
-{
- DagNodeQueueElem *elem;
- DagNodeQueueElem *temp;
-
- elem = queue->first;
- while (elem) {
- temp = elem;
- elem = elem->next;
- MEM_freeN(temp);
- }
-
- elem = queue->freenodes->first;
- while (elem) {
- temp = elem;
- elem = elem->next;
- MEM_freeN(temp);
- }
-
- MEM_freeN(queue->freenodes);
- MEM_freeN(queue);
-}
-
-/* insert in queue, remove in front */
-void push_queue(DagNodeQueue *queue, DagNode *node)
-{
- DagNodeQueueElem *elem;
- int i;
-
- if (node == NULL) {
- fprintf(stderr, "pushing null node\n");
- return;
- }
- /*fprintf(stderr, "BFS push : %s %d\n", ((ID *) node->ob)->name, queue->count);*/
-
- elem = queue->freenodes->first;
- if (elem != NULL) {
- queue->freenodes->first = elem->next;
- if (queue->freenodes->last == elem) {
- queue->freenodes->last = NULL;
- queue->freenodes->first = NULL;
- }
- queue->freenodes->count--;
- }
- else { /* alllocating more */
- elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem1");
- elem->node = NULL;
- elem->next = NULL;
- queue->freenodes->first = queue->freenodes->last = elem;
-
- for (i = 1; i < DAGQUEUEALLOC; i++) {
- elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem2");
- elem->node = NULL;
- elem->next = NULL;
- queue->freenodes->last->next = elem;
- queue->freenodes->last = elem;
- }
- queue->freenodes->count = DAGQUEUEALLOC;
-
- elem = queue->freenodes->first;
- queue->freenodes->first = elem->next;
- }
- elem->next = NULL;
- elem->node = node;
- if (queue->last != NULL)
- queue->last->next = elem;
- queue->last = elem;
- if (queue->first == NULL) {
- queue->first = elem;
- }
- queue->count++;
-}
-
-
-/* insert in front, remove in front */
-void push_stack(DagNodeQueue *queue, DagNode *node)
-{
- DagNodeQueueElem *elem;
- int i;
-
- elem = queue->freenodes->first;
- if (elem != NULL) {
- queue->freenodes->first = elem->next;
- if (queue->freenodes->last == elem) {
- queue->freenodes->last = NULL;
- queue->freenodes->first = NULL;
- }
- queue->freenodes->count--;
- }
- else { /* alllocating more */
- elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem1");
- elem->node = NULL;
- elem->next = NULL;
- queue->freenodes->first = queue->freenodes->last = elem;
-
- for (i = 1; i < DAGQUEUEALLOC; i++) {
- elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem2");
- elem->node = NULL;
- elem->next = NULL;
- queue->freenodes->last->next = elem;
- queue->freenodes->last = elem;
- }
- queue->freenodes->count = DAGQUEUEALLOC;
-
- elem = queue->freenodes->first;
- queue->freenodes->first = elem->next;
- }
- elem->next = queue->first;
- elem->node = node;
- queue->first = elem;
- if (queue->last == NULL)
- queue->last = elem;
- queue->count++;
-}
-
-
-DagNode *pop_queue(DagNodeQueue *queue)
-{
- DagNodeQueueElem *elem;
- DagNode *node;
-
- elem = queue->first;
- if (elem) {
- queue->first = elem->next;
- if (queue->last == elem) {
- queue->last = NULL;
- queue->first = NULL;
- }
- queue->count--;
- if (queue->freenodes->last)
- queue->freenodes->last->next = elem;
- queue->freenodes->last = elem;
- if (queue->freenodes->first == NULL)
- queue->freenodes->first = elem;
- node = elem->node;
- elem->node = NULL;
- elem->next = NULL;
- queue->freenodes->count++;
- return node;
- }
- else {
- fprintf(stderr, "return null\n");
- return NULL;
- }
-}
-
-DagNode *get_top_node_queue(DagNodeQueue *queue)
-{
- return queue->first->node;
-}
-
-DagForest *dag_init(void)
-{
- DagForest *forest;
- /* use callocN to init all zero */
- forest = MEM_callocN(sizeof(DagForest), "DAG root");
- forest->ugly_hack_sorry = true;
- return forest;
-}
-
-/* isdata = object data... */
-/* XXX this needs to be extended to be more flexible (so that not only objects are evaluated via depsgraph)... */
-static void dag_add_driver_relation(AnimData *adt, DagForest *dag, DagNode *node, int isdata)
-{
- FCurve *fcu;
- DagNode *node1;
-
- for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
- ChannelDriver *driver = fcu->driver;
- DriverVar *dvar;
- int isdata_fcu = (isdata) || (fcu->rna_path && strstr(fcu->rna_path, "modifiers["));
-
- /* loop over variables to get the target relationships */
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- /* only used targets */
- DRIVER_TARGETS_USED_LOOPER(dvar)
- {
- if (dtar->id) {
- /* FIXME: other data types need to be added here so that they can work! */
- if (GS(dtar->id->name) == ID_OB) {
- Object *ob = (Object *)dtar->id;
-
- /* normal channel-drives-channel */
- node1 = dag_get_node(dag, dtar->id);
-
- /* check if bone... */
- if ((ob->type == OB_ARMATURE) &&
- ( ((dtar->rna_path) && strstr(dtar->rna_path, "pose.bones[")) ||
- ((dtar->flag & DTAR_FLAG_STRUCT_REF) && (dtar->pchan_name[0])) ))
- {
- dag_add_relation(dag, node1, node, isdata_fcu ? DAG_RL_DATA_DATA : DAG_RL_DATA_OB, "Driver");
- }
- /* check if ob data */
- else if (dtar->rna_path && strstr(dtar->rna_path, "data."))
- dag_add_relation(dag, node1, node, isdata_fcu ? DAG_RL_DATA_DATA : DAG_RL_DATA_OB, "Driver");
- /* normal */
- else
- dag_add_relation(dag, node1, node, isdata_fcu ? DAG_RL_OB_DATA : DAG_RL_OB_OB, "Driver");
- }
- }
- }
- DRIVER_TARGETS_LOOPER_END
- }
- }
-}
-
-/* XXX: forward def for material driver handling... */
-static void dag_add_material_driver_relations(DagForest *dag, DagNode *node, Material *ma);
-
-/* recursive handling for shader nodetree drivers */
-static void dag_add_shader_nodetree_driver_relations(DagForest *dag, DagNode *node, bNodeTree *ntree)
-{
- bNode *n;
-
- /* nodetree itself */
- if (ntree->adt) {
- dag_add_driver_relation(ntree->adt, dag, node, 1);
- }
-
- /* nodetree's nodes... */
- for (n = ntree->nodes.first; n; n = n->next) {
- if (n->id) {
- if (GS(n->id->name) == ID_MA) {
- dag_add_material_driver_relations(dag, node, (Material *)n->id);
- }
- else if (n->type == NODE_GROUP) {
- dag_add_shader_nodetree_driver_relations(dag, node, (bNodeTree *)n->id);
- }
- }
- }
-}
-
-/* recursive handling for material drivers */
-static void dag_add_material_driver_relations(DagForest *dag, DagNode *node, Material *ma)
-{
- /* Prevent infinite recursion by checking (and tagging the material) as having been visited
- * already (see build_dag()). 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)
- dag_add_driver_relation(ma->adt, dag, node, 1);
-
- /* textures */
- // TODO...
- //dag_add_texture_driver_relations(DagForest *dag, DagNode *node, ID *id);
-
- /* material's nodetree */
- if (ma->nodetree)
- dag_add_shader_nodetree_driver_relations(dag, node, ma->nodetree);
-
- ma->id.tag &= ~LIB_TAG_DOIT;
-}
-
-/* recursive handling for lamp drivers */
-static void dag_add_lamp_driver_relations(DagForest *dag, DagNode *node, Lamp *la)
-{
- /* Prevent infinite recursion by checking (and tagging the lamp) as having been visited
- * already (see build_dag()). 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)
- dag_add_driver_relation(la->adt, dag, node, 1);
-
- /* textures */
- // TODO...
- //dag_add_texture_driver_relations(DagForest *dag, DagNode *node, ID *id);
-
- /* lamp's nodetree */
- if (la->nodetree)
- dag_add_shader_nodetree_driver_relations(dag, node, la->nodetree);
-
- la->id.tag &= ~LIB_TAG_DOIT;
-}
-
-static void check_and_create_collision_relation(DagForest *dag, Object *ob, DagNode *node, Object *ob1, int skip_forcefield, bool no_collision)
-{
- DagNode *node2;
- if (ob1->pd && (ob1->pd->deflect || ob1->pd->forcefield) && (ob1 != ob)) {
- if ((skip_forcefield && ob1->pd->forcefield == skip_forcefield) || (no_collision && ob1->pd->forcefield == 0))
- return;
- node2 = dag_get_node(dag, ob1);
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Field Collision");
- }
-}
-
-static void dag_add_collision_field_relation(DagForest *dag, Scene *scene, Object *ob, DagNode *node, int skip_forcefield, bool no_collision)
-{
- Base *base;
- ParticleSystem *particle_system;
-
- for (particle_system = ob->particlesystem.first;
- particle_system;
- particle_system = particle_system->next)
- {
- EffectorWeights *effector_weights = particle_system->part->effector_weights;
- if (effector_weights->group) {
- GroupObject *group_object;
-
- for (group_object = effector_weights->group->gobject.first;
- group_object;
- group_object = group_object->next)
- {
- if ((group_object->ob->lay & ob->lay)) {
- check_and_create_collision_relation(dag, ob, node, group_object->ob, skip_forcefield, no_collision);
- }
- }
- }
- }
-
- /* would be nice to have a list of colliders here
- * so for now walk all objects in scene check 'same layer rule' */
- for (base = scene->base.first; base; base = base->next) {
- if ((base->lay & ob->lay)) {
- Object *ob1 = base->object;
- check_and_create_collision_relation(dag, ob, node, ob1, skip_forcefield, no_collision);
- }
- }
-}
-
-static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Scene *scene, Object *ob, int mask)
-{
- bConstraint *con;
- DagNode *node;
- DagNode *node2;
- DagNode *node3;
- Key *key;
- ParticleSystem *psys;
- int addtoroot = 1;
-
- node = dag_get_node(dag, ob);
-
- if ((ob->data) && (mask & DAG_RL_DATA)) {
- node2 = dag_get_node(dag, ob->data);
- dag_add_relation(dag, node, node2, DAG_RL_DATA, "Object-Data Relation");
- node2->first_ancestor = ob;
- node2->ancestor_count += 1;
- }
-
- /* also build a custom data mask for dependencies that need certain layers */
-
- if (ob->type == OB_ARMATURE) {
- if (ob->pose) {
- bPoseChannel *pchan;
-
- for (pchan = 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;
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar && ct->tar != ob) {
- // fprintf(stderr, "armature %s target :%s\n", ob->id.name, target->id.name);
- node3 = dag_get_node(dag, ct->tar);
-
- if (ct->subtarget[0]) {
- dag_add_relation(dag, node3, node, DAG_RL_OB_DATA | DAG_RL_DATA_DATA, cti->name);
- if (ct->tar->type == OB_MESH)
- node3->customdata_mask |= CD_MASK_MDEFORMVERT;
- }
- else if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_SPLINEIK))
- dag_add_relation(dag, node3, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, cti->name);
- else
- dag_add_relation(dag, node3, node, DAG_RL_OB_DATA, cti->name);
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 1);
- }
-
- }
- }
- }
- }
-
- /* driver dependencies, nla modifiers */
-#if 0 // XXX old animation system
- if (ob->nlastrips.first) {
- bActionStrip *strip;
- bActionChannel *chan;
- for (strip = ob->nlastrips.first; strip; strip = strip->next) {
- if (strip->modifiers.first) {
- bActionModifier *amod;
- for (amod = strip->modifiers.first; amod; amod = amod->next) {
- if (amod->ob) {
- node2 = dag_get_node(dag, amod->ob);
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "NLA Strip Modifier");
- }
- }
- }
- }
- }
-#endif // XXX old animation system
- if (ob->adt)
- dag_add_driver_relation(ob->adt, dag, node, (ob->type == OB_ARMATURE)); // XXX isdata arg here doesn't give an accurate picture of situation
-
- key = BKE_key_from_object(ob);
- if (key && key->adt)
- dag_add_driver_relation(key->adt, dag, node, 1);
-
- if (ob->modifiers.first) {
- ModifierData *md;
-
- for (md = ob->modifiers.first; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
- if (mti->updateDepgraph) mti->updateDepgraph(md, dag, bmain, scene, ob, node);
- }
- }
- if (ob->parent) {
- node2 = dag_get_node(dag, ob->parent);
-
- switch (ob->partype) {
- case PARSKEL:
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_OB, "Parent");
- break;
- case PARVERT1: case PARVERT3:
- dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, "Vertex Parent");
- node2->customdata_mask |= CD_MASK_ORIGINDEX;
- break;
- case PARBONE:
- dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, "Bone Parent");
- break;
- default:
- if (ob->parent->type == OB_LATTICE)
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_OB, "Lattice Parent");
- else if (ob->parent->type == OB_CURVE) {
- Curve *cu = ob->parent->data;
- if (cu->flag & CU_PATH)
- dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, "Curve Parent");
- else
- dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Curve Parent");
- }
- else
- dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Parent");
- break;
- }
- /* exception case: parent is duplivert */
- if (ob->type == OB_MBALL && (ob->parent->transflag & OB_DUPLIVERTS)) {
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_OB, "Duplivert");
- }
-
- addtoroot = 0;
- }
- if (ob->proxy) {
- node2 = dag_get_node(dag, ob->proxy);
- dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA | DAG_RL_OB_OB, "Proxy");
- /* inverted relation, so addtoroot shouldn't be set to zero */
- }
-
- if (ob->transflag & OB_DUPLI) {
- if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) {
- GroupObject *go;
- for (go = ob->dup_group->gobject.first; go; go = go->next) {
- if (go->ob) {
- node2 = dag_get_node(dag, go->ob);
- /* node2 changes node1, this keeps animations updated in groups?? not logical? */
- dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Dupligroup");
- }
- }
- }
- }
-
- /* softbody collision */
- if ((ob->type == OB_MESH) || (ob->type == OB_CURVE) || (ob->type == OB_LATTICE)) {
- if (ob->particlesystem.first ||
- modifiers_isModifierEnabled(ob, eModifierType_Softbody) ||
- modifiers_isModifierEnabled(ob, eModifierType_Cloth) ||
- modifiers_isModifierEnabled(ob, eModifierType_DynamicPaint))
- {
- dag_add_collision_field_relation(dag, scene, ob, node, 0, false); /* TODO: use effectorweight->group */
- }
- else if (modifiers_isModifierEnabled(ob, eModifierType_Smoke)) {
- dag_add_collision_field_relation(dag, scene, ob, node, PFIELD_SMOKEFLOW, false);
- }
- else if (ob->rigidbody_object) {
- dag_add_collision_field_relation(dag, scene, ob, node, 0, true);
- }
- }
-
- /* object data drivers */
- if (ob->data) {
- AnimData *adt = BKE_animdata_from_id((ID *)ob->data);
- if (adt)
- dag_add_driver_relation(adt, dag, node, 1);
- }
-
- /* object type/data relationships */
- switch (ob->type) {
- case OB_CAMERA:
- {
- Camera *cam = (Camera *)ob->data;
-
- if (cam->dof_ob) {
- node2 = dag_get_node(dag, cam->dof_ob);
- dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Camera DoF");
- }
- break;
- }
- case OB_MBALL:
- {
- Object *mom = BKE_mball_basis_find(scene, ob);
-
- if (mom != ob) {
- node2 = dag_get_node(dag, mom);
- dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Metaball"); /* mom depends on children! */
- }
- break;
- }
- case OB_CURVE:
- case OB_FONT:
- {
- Curve *cu = ob->data;
-
- if (cu->bevobj) {
- node2 = dag_get_node(dag, cu->bevobj);
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Curve Bevel");
- }
- if (cu->taperobj) {
- node2 = dag_get_node(dag, cu->taperobj);
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Curve Taper");
- }
- if (ob->type == OB_FONT) {
- /* Really rather dirty hack. needs to support font family to work
- * reliably on render export.
- *
- * This totally mimics behavior of regular verts duplication with
- * parenting. The only tricky thing here is to get list of objects
- * used for the custom "font".
- *
- * This shouldn't harm so much because this code only runs on DAG
- * rebuild and this feature is not that commonly used.
- *
- * - sergey -
- */
- if (cu->family[0] != '\n') {
- ListBase *duplilist;
- DupliObject *dob;
- duplilist = object_duplilist(G.main->eval_ctx, scene, ob);
- for (dob = duplilist->first; dob; dob = dob->next) {
- node2 = dag_get_node(dag, dob->ob);
- dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Object Font");
- }
- free_object_duplilist(duplilist);
- }
-
- if (cu->textoncurve) {
- node2 = dag_get_node(dag, cu->textoncurve);
- /* Text on curve requires path to be evaluated for the target curve. */
- node2->eval_flags |= DAG_EVAL_NEED_CURVE_PATH;
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Texture On Curve");
- }
- }
- break;
- }
- }
-
- /* material drivers */
- if (ob->totcol) {
- int a;
-
- for (a = 1; a <= ob->totcol; a++) {
- Material *ma = give_current_material(ob, a);
-
- if (ma) {
- /* recursively figure out if there are drivers, and hook these up to this object */
- dag_add_material_driver_relations(dag, node, ma);
- }
- }
- }
- else if (ob->type == OB_LAMP) {
- dag_add_lamp_driver_relations(dag, node, ob->data);
- }
-
- /* particles */
- psys = ob->particlesystem.first;
- if (psys) {
- GroupObject *go;
-
- for (; psys; psys = psys->next) {
- BoidRule *rule = NULL;
- BoidState *state = NULL;
- ParticleSettings *part = psys->part;
- ListBase *effectors = NULL;
- EffectorCache *eff;
-
- if (part->adt) {
- dag_add_driver_relation(part->adt, dag, node, 1);
- }
-
- dag_add_relation(dag, node, node, DAG_RL_OB_DATA, "Particle-Object Relation");
-
- if (!psys_check_enabled(ob, psys, G.is_rendering))
- continue;
-
- if (ELEM(part->phystype, PART_PHYS_KEYED, PART_PHYS_BOIDS)) {
- ParticleTarget *pt = psys->targets.first;
-
- for (; pt; pt = pt->next) {
- if (pt->ob && BLI_findlink(&pt->ob->particlesystem, pt->psys - 1)) {
- node2 = dag_get_node(dag, pt->ob);
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Particle Targets");
- }
- }
- }
-
- if (part->ren_as == PART_DRAW_OB && part->dup_ob) {
- node2 = dag_get_node(dag, part->dup_ob);
- /* note that this relation actually runs in the wrong direction, the problem
- * is that dupli system all have this (due to parenting), and the render
- * engine instancing assumes particular ordering of objects in list */
- dag_add_relation(dag, node, node2, DAG_RL_OB_OB, "Particle Object Visualization");
- if (part->dup_ob->type == OB_MBALL)
- dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA, "Particle Object Visualization");
- }
-
- if (part->ren_as == PART_DRAW_GR && part->dup_group) {
- for (go = part->dup_group->gobject.first; go; go = go->next) {
- node2 = dag_get_node(dag, go->ob);
- dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Particle Group Visualization");
- }
- }
-
- effectors = pdInitEffectors(scene, ob, psys, part->effector_weights, false);
-
- if (effectors) {
- for (eff = effectors->first; eff; eff = eff->next) {
- if (eff->psys) {
- node2 = dag_get_node(dag, eff->ob);
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Particle Field");
- }
- }
- }
-
- pdEndEffectors(&effectors);
-
- if (part->boids) {
- for (state = part->boids->states.first; state; state = state->next) {
- for (rule = state->rules.first; rule; rule = rule->next) {
- Object *ruleob = NULL;
- if (rule->type == eBoidRuleType_Avoid)
- ruleob = ((BoidRuleGoalAvoid *)rule)->ob;
- else if (rule->type == eBoidRuleType_FollowLeader)
- ruleob = ((BoidRuleFollowLeader *)rule)->ob;
-
- if (ruleob) {
- node2 = dag_get_node(dag, ruleob);
- dag_add_relation(dag, node2, node, DAG_RL_OB_DATA, "Boid Rule");
- }
- }
- }
- }
- }
- }
-
- /* object constraints */
- for (con = ob->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (!cti)
- continue;
-
- /* special case for camera tracking -- it doesn't use targets to define relations */
- if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) {
- int depends_on_camera = 0;
-
- if (cti->type == CONSTRAINT_TYPE_FOLLOWTRACK) {
- bFollowTrackConstraint *data = (bFollowTrackConstraint *)con->data;
-
- if ((data->clip || data->flag & FOLLOWTRACK_ACTIVECLIP) && data->track[0])
- depends_on_camera = 1;
-
- if (data->depth_ob) {
- node2 = dag_get_node(dag, data->depth_ob);
- dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, cti->name);
- }
- }
- else if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER)
- depends_on_camera = 1;
-
- if (depends_on_camera && scene->camera) {
- node2 = dag_get_node(dag, scene->camera);
- dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, cti->name);
- }
-
- dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation");
- addtoroot = 0;
- }
- else if (cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- Object *obt;
-
- if (ct->tar)
- obt = ct->tar;
- else
- continue;
-
- node2 = dag_get_node(dag, obt);
- if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO))
- dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, cti->name);
- else {
- if (ELEM(obt->type, OB_ARMATURE, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) {
- dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, cti->name);
- if (obt->type == OB_MESH)
- node2->customdata_mask |= CD_MASK_MDEFORMVERT;
- }
- else
- dag_add_relation(dag, node2, node, DAG_RL_OB_OB, cti->name);
- }
- addtoroot = 0;
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 1);
- }
- }
-
- if (addtoroot == 1)
- dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation");
-}
-
-static void build_dag_group(DagForest *dag, DagNode *scenenode, Main *bmain, Scene *scene, Group *group, short mask)
-{
- GroupObject *go;
-
- if (group->id.tag & LIB_TAG_DOIT)
- return;
-
- group->id.tag |= LIB_TAG_DOIT;
-
- for (go = group->gobject.first; go; go = go->next) {
- build_dag_object(dag, scenenode, bmain, scene, go->ob, mask);
- if (go->ob->dup_group)
- build_dag_group(dag, scenenode, bmain, scene, go->ob->dup_group, mask);
- }
-}
-
-DagForest *build_dag(Main *bmain, Scene *sce, short mask)
-{
- Base *base;
- Object *ob;
- DagNode *node;
- DagNode *scenenode;
- DagForest *dag;
- DagAdjList *itA;
-
- dag = sce->theDag;
- if (dag)
- free_forest(dag);
- else {
- dag = dag_init();
- sce->theDag = dag;
- }
- dag->need_update = false;
-
- BKE_main_id_tag_idcode(bmain, ID_OB, LIB_TAG_DOIT, false);
-
- /* clear "LIB_TAG_DOIT" flag from all materials, to prevent infinite recursion problems later [#32017] */
- BKE_main_id_tag_idcode(bmain, ID_MA, LIB_TAG_DOIT, false);
- BKE_main_id_tag_idcode(bmain, ID_LA, LIB_TAG_DOIT, false);
- BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false);
-
- /* add base node for scene. scene is always the first node in DAG */
- scenenode = dag_add_node(dag, sce);
-
- /* add current scene objects */
- for (base = sce->base.first; base; base = base->next) {
- ob = base->object;
- ob->id.tag |= LIB_TAG_DOIT;
- build_dag_object(dag, scenenode, bmain, sce, ob, mask);
- if (ob->proxy)
- build_dag_object(dag, scenenode, bmain, sce, ob->proxy, mask);
- if (ob->dup_group)
- build_dag_group(dag, scenenode, bmain, sce, ob->dup_group, mask);
- }
-
- /* There might be situations when object from current scene depends on
- * objects form other scene AND objects from other scene has own
- * dependencies on objects from other scene.
- *
- * This is really important to include such indirect dependencies in order
- * to keep threaded update safe but since we don't really know if object is
- * coming from current scene or another scene we do rather stupid tag-based
- * check here: all the objects for which build_dag_object() was called are
- * getting tagged with LIB_TAG_DOIT. This way if some node has untagged
- * object we know it's an object from other scene.
- *
- * It should be enough to to it once, because if there's longer chain of
- * indirect dependencies, all the new nodes will be added to the end of the
- * list, meaning we'll keep covering them in this for loop.
- */
- for (node = sce->theDag->DagNode.first; node != NULL; node = node->next) {
- if (node->type == ID_OB) {
- ob = node->ob;
- if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
- ob->id.tag |= LIB_TAG_DOIT;
- build_dag_object(dag, scenenode, bmain, sce, ob, mask);
- if (ob->proxy)
- build_dag_object(dag, scenenode, bmain, sce, ob->proxy, mask);
- if (ob->dup_group)
- build_dag_group(dag, scenenode, bmain, sce, ob->dup_group, mask);
- }
- }
- }
-
- BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false);
-
- /* Now all relations were built, but we need to solve 1 exceptional case;
- * When objects have multiple "parents" (for example parent + constraint working on same object)
- * the relation type has to be synced. One of the parents can change, and should give same event to child */
-
- /* nodes were callocced, so we can use node->color for temporal storage */
- for (node = sce->theDag->DagNode.first; node; node = node->next) {
- if (node->type == ID_OB) {
- for (itA = node->child; itA; itA = itA->next) {
- if (itA->node->type == ID_OB) {
- itA->node->color |= itA->type;
- }
- }
-
- /* also flush custom data mask */
- ((Object *)node->ob)->customdata_mask = node->customdata_mask;
-
- if (node->parent == NULL) {
- dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation");
- }
- }
- }
- /* now set relations equal, so that when only one parent changes, the correct recalcs are found */
- for (node = sce->theDag->DagNode.first; node; node = node->next) {
- if (node->type == ID_OB) {
- for (itA = node->child; itA; itA = itA->next) {
- if (itA->node->type == ID_OB) {
- itA->type |= itA->node->color;
- }
- }
- }
- }
-
- /* cycle detection and solving */
- // solve_cycles(dag);
-
- return dag;
-}
-
-
-void free_forest(DagForest *Dag)
-{ /* remove all nodes and deps */
- DagNode *tempN;
- DagAdjList *tempA;
- DagAdjList *itA;
- DagNode *itN = Dag->DagNode.first;
-
- while (itN) {
- itA = itN->child;
- while (itA) {
- tempA = itA;
- itA = itA->next;
- MEM_freeN(tempA);
- }
-
- itA = itN->parent;
- while (itA) {
- tempA = itA;
- itA = itA->next;
- MEM_freeN(tempA);
- }
-
- tempN = itN;
- itN = itN->next;
- MEM_freeN(tempN);
- }
-
- BLI_ghash_free(Dag->nodeHash, NULL, NULL);
- Dag->nodeHash = NULL;
- Dag->DagNode.first = NULL;
- Dag->DagNode.last = NULL;
- Dag->numNodes = 0;
-
-}
-
-DagNode *dag_find_node(DagForest *forest, void *fob)
-{
- if (forest->nodeHash)
- return BLI_ghash_lookup(forest->nodeHash, fob);
-
- return NULL;
-}
-
-static int dag_print_dependencies = 0; /* debugging */
-
-/* no checking of existence, use dag_find_node first or dag_get_node */
-DagNode *dag_add_node(DagForest *forest, void *fob)
-{
- DagNode *node;
-
- node = MEM_callocN(sizeof(DagNode), "DAG node");
- if (node) {
- node->ob = fob;
- node->color = DAG_WHITE;
-
- if (forest->ugly_hack_sorry) node->type = GS(((ID *) fob)->name); /* sorry, done for pose sorting */
- if (forest->numNodes) {
- ((DagNode *) forest->DagNode.last)->next = node;
- forest->DagNode.last = node;
- forest->numNodes++;
- }
- else {
- forest->DagNode.last = node;
- forest->DagNode.first = node;
- forest->numNodes = 1;
- }
-
- if (!forest->nodeHash)
- forest->nodeHash = BLI_ghash_ptr_new("dag_add_node gh");
- BLI_ghash_insert(forest->nodeHash, fob, node);
- }
-
- return node;
-}
-
-DagNode *dag_get_node(DagForest *forest, void *fob)
-{
- DagNode *node;
-
- node = dag_find_node(forest, fob);
- if (!node)
- node = dag_add_node(forest, fob);
- return node;
-}
-
-
-
-DagNode *dag_get_sub_node(DagForest *forest, void *fob)
-{
- DagNode *node;
- DagAdjList *mainchild, *prev = NULL;
-
- mainchild = ((DagNode *) forest->DagNode.first)->child;
- /* remove from first node (scene) adj list if present */
- while (mainchild) {
- if (mainchild->node == fob) {
- if (prev) {
- prev->next = mainchild->next;
- MEM_freeN(mainchild);
- break;
- }
- else {
- ((DagNode *) forest->DagNode.first)->child = mainchild->next;
- MEM_freeN(mainchild);
- break;
- }
- }
- prev = mainchild;
- mainchild = mainchild->next;
- }
- node = dag_find_node(forest, fob);
- if (!node)
- node = dag_add_node(forest, fob);
- return node;
-}
-
-static void dag_add_parent_relation(DagForest *UNUSED(forest), DagNode *fob1, DagNode *fob2, short rel, const char *name)
-{
- DagAdjList *itA = fob2->parent;
-
- while (itA) { /* search if relation exist already */
- if (itA->node == fob1) {
- itA->type |= rel;
- itA->count += 1;
- return;
- }
- itA = itA->next;
- }
- /* create new relation and insert at head. MALLOC alert! */
- itA = MEM_mallocN(sizeof(DagAdjList), "DAG adj list");
- itA->node = fob1;
- itA->type = rel;
- itA->count = 1;
- itA->next = fob2->parent;
- itA->name = name;
- fob2->parent = itA;
-}
-
-void dag_add_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel, const char *name)
-{
- DagAdjList *itA = fob1->child;
-
- /* parent relation is for cycle checking */
- dag_add_parent_relation(forest, fob1, fob2, rel, name);
-
- /* TODO(sergey): Find a better place for this. */
-#ifdef WITH_OPENSUBDIV
- if ((rel & (DAG_RL_DATA_DATA | DAG_RL_DATA_OB)) != 0) {
- if (fob1->type == ID_OB) {
- if ((fob1->eval_flags & DAG_EVAL_NEED_CPU) == 0) {
- Object *ob2 = fob2->ob;
- if (ob2->recalc & OB_RECALC_ALL) {
- /* Make sure object has all the data on CPU. */
- Object *ob1 = fob1->ob;
- ob1->recalc |= OB_RECALC_DATA;
- }
- fob1->eval_flags |= DAG_EVAL_NEED_CPU;
- }
- }
- }
-#endif
-
- while (itA) { /* search if relation exist already */
- if (itA->node == fob2) {
- itA->type |= rel;
- itA->count += 1;
- return;
- }
- itA = itA->next;
- }
- /* create new relation and insert at head. MALLOC alert! */
- itA = MEM_mallocN(sizeof(DagAdjList), "DAG adj list");
- itA->node = fob2;
- itA->type = rel;
- itA->count = 1;
- itA->next = fob1->child;
- itA->name = name;
- fob1->child = itA;
-}
-
-static const char *dag_node_name(DagForest *dag, DagNode *node)
-{
- if (node->ob == NULL)
- return "null";
- else if (dag->ugly_hack_sorry)
- return ((ID *)(node->ob))->name + 2;
- else
- return ((bPoseChannel *)(node->ob))->name;
-}
-
-static void dag_node_print_dependencies(DagForest *dag, DagNode *node)
-{
- DagAdjList *itA;
-
- printf("%s depends on:\n", dag_node_name(dag, node));
-
- for (itA = node->parent; itA; itA = itA->next)
- printf(" %s through %s\n", dag_node_name(dag, itA->node), itA->name);
- printf("\n");
-}
-
-static int dag_node_print_dependency_recurs(DagForest *dag, DagNode *node, DagNode *endnode)
-{
- DagAdjList *itA;
-
- if (node->color == DAG_BLACK)
- return 0;
-
- node->color = DAG_BLACK;
-
- if (node == endnode)
- return 1;
-
- for (itA = node->parent; itA; itA = itA->next) {
- if (dag_node_print_dependency_recurs(dag, itA->node, endnode)) {
- printf(" %s depends on %s through %s.\n", dag_node_name(dag, node), dag_node_name(dag, itA->node), itA->name);
- return 1;
- }
- }
-
- return 0;
-}
-
-static void dag_node_print_dependency_cycle(DagForest *dag, DagNode *startnode, DagNode *endnode, const char *name)
-{
- DagNode *node;
-
- for (node = dag->DagNode.first; node; node = node->next)
- node->color = DAG_WHITE;
-
- printf(" %s depends on %s through %s.\n", dag_node_name(dag, endnode), dag_node_name(dag, startnode), name);
- dag_node_print_dependency_recurs(dag, startnode, endnode);
- printf("\n");
-}
-
-static int dag_node_recurs_level(DagNode *node, int level)
-{
- DagAdjList *itA;
- int newlevel;
-
- node->color = DAG_BLACK; /* done */
- newlevel = ++level;
-
- for (itA = node->parent; itA; itA = itA->next) {
- if (itA->node->color == DAG_WHITE) {
- itA->node->ancestor_count = dag_node_recurs_level(itA->node, level);
- newlevel = MAX2(newlevel, level + itA->node->ancestor_count);
- }
- else
- newlevel = MAX2(newlevel, level + itA->node->ancestor_count);
- }
-
- return newlevel;
-}
-
-static void dag_check_cycle(DagForest *dag)
-{
- DagNode *node;
- DagAdjList *itA;
-
- dag->is_acyclic = true;
-
- /* debugging print */
- if (dag_print_dependencies)
- for (node = dag->DagNode.first; node; node = node->next)
- dag_node_print_dependencies(dag, node);
-
- /* tag nodes unchecked */
- for (node = dag->DagNode.first; node; node = node->next)
- node->color = DAG_WHITE;
-
- for (node = dag->DagNode.first; node; node = node->next) {
- if (node->color == DAG_WHITE) {
- node->ancestor_count = dag_node_recurs_level(node, 0);
- }
- }
-
- /* check relations, and print errors */
- for (node = dag->DagNode.first; node; node = node->next) {
- for (itA = node->parent; itA; itA = itA->next) {
- if (itA->node->ancestor_count > node->ancestor_count) {
- if (node->ob && itA->node->ob) {
- dag->is_acyclic = false;
- printf("Dependency cycle detected:\n");
- dag_node_print_dependency_cycle(dag, itA->node, node, itA->name);
- }
- }
- }
- }
-
- /* parent relations are only needed for cycle checking, so free now */
- for (node = dag->DagNode.first; node; node = node->next) {
- while (node->parent) {
- itA = node->parent->next;
- MEM_freeN(node->parent);
- node->parent = itA;
- }
- }
-}
-
-/* debug test functions */
-
-void graph_print_queue(DagNodeQueue *nqueue)
-{
- DagNodeQueueElem *queueElem;
-
- queueElem = nqueue->first;
- while (queueElem) {
- fprintf(stderr, "** %s %i %i-%i ", ((ID *) queueElem->node->ob)->name, queueElem->node->color, queueElem->node->DFS_dvtm, queueElem->node->DFS_fntm);
- queueElem = queueElem->next;
- }
- fprintf(stderr, "\n");
-}
-
-void graph_print_queue_dist(DagNodeQueue *nqueue)
-{
- DagNodeQueueElem *queueElem;
- int count;
-
- queueElem = nqueue->first;
- count = 0;
- while (queueElem) {
- fprintf(stderr, "** %25s %2.2i-%2.2i ", ((ID *) queueElem->node->ob)->name, queueElem->node->DFS_dvtm, queueElem->node->DFS_fntm);
- while (count < queueElem->node->DFS_dvtm - 1) { fputc(' ', stderr); count++; }
- fputc('|', stderr);
- while (count < queueElem->node->DFS_fntm - 2) { fputc('-', stderr); count++; }
- fputc('|', stderr);
- fputc('\n', stderr);
- count = 0;
- queueElem = queueElem->next;
- }
- fprintf(stderr, "\n");
-}
-
-void graph_print_adj_list(DagForest *dag)
-{
- DagNode *node;
- DagAdjList *itA;
-
- node = dag->DagNode.first;
- while (node) {
- fprintf(stderr, "node : %s col: %i", ((ID *) node->ob)->name, node->color);
- itA = node->child;
- while (itA) {
- fprintf(stderr, "-- %s ", ((ID *) itA->node->ob)->name);
-
- itA = itA->next;
- }
- fprintf(stderr, "\n");
- node = node->next;
- }
-}
-
-/* ************************ API *********************** */
-
-/* mechanism to allow editors to be informed of depsgraph updates,
- * to do their own updates based on changes... */
-static void (*EditorsUpdateIDCb)(Main *bmain, ID *id) = NULL;
-static void (*EditorsUpdateSceneCb)(Main *bmain, Scene *scene, int updated) = NULL;
-static void (*EditorsUpdateScenePreCb)(Main *bmain, Scene *scene, bool time) = NULL;
-
-void DAG_editors_update_cb(void (*id_func)(Main *bmain, ID *id),
- void (*scene_func)(Main *bmain, Scene *scene, int updated),
- void (*scene_pre_func)(Main *bmain, Scene *scene, bool time))
-{
- if (DEG_depsgraph_use_legacy()) {
- EditorsUpdateIDCb = id_func;
- EditorsUpdateSceneCb = scene_func;
- EditorsUpdateScenePreCb = scene_pre_func;
- }
- else {
- /* New dependency graph. */
- DEG_editors_set_update_cb(id_func, scene_func, scene_pre_func);
- }
-}
-
-void DAG_editors_update_pre(Main *bmain, Scene *scene, bool time)
-{
- if (DEG_depsgraph_use_legacy()) {
- if (EditorsUpdateScenePreCb != NULL) {
- EditorsUpdateScenePreCb(bmain, scene, time);
- }
- }
- else {
- DEG_editors_update_pre(bmain, scene, time);
- }
-}
-
-static void dag_editors_id_update(Main *bmain, ID *id)
-{
- if (EditorsUpdateIDCb)
- EditorsUpdateIDCb(bmain, id);
-}
-
-static void dag_editors_scene_update(Main *bmain, Scene *scene, int updated)
-{
- if (EditorsUpdateSceneCb)
- EditorsUpdateSceneCb(bmain, scene, updated);
-}
-
-/* groups with objects in this scene need to be put in the right order as well */
-static void scene_sort_groups(Main *bmain, Scene *sce)
-{
- Base *base;
- Group *group;
- GroupObject *go;
- Object *ob;
-
- /* test; are group objects all in this scene? */
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- ob->id.tag &= ~LIB_TAG_DOIT;
- ob->id.newid = NULL; /* newid abuse for GroupObject */
- }
- for (base = sce->base.first; base; base = base->next)
- base->object->id.tag |= LIB_TAG_DOIT;
-
- for (group = bmain->group.first; group; group = group->id.next) {
- for (go = group->gobject.first; go; go = go->next) {
- if ((go->ob->id.tag & LIB_TAG_DOIT) == 0)
- break;
- }
- /* this group is entirely in this scene */
- if (go == NULL) {
- ListBase listb = {NULL, NULL};
-
- for (go = group->gobject.first; go; go = go->next)
- go->ob->id.newid = (ID *)go;
-
- /* in order of sorted bases we reinsert group objects */
- for (base = sce->base.first; base; base = base->next) {
-
- if (base->object->id.newid) {
- go = (GroupObject *)base->object->id.newid;
- base->object->id.newid = NULL;
- BLI_remlink(&group->gobject, go);
- BLI_addtail(&listb, go);
- }
- }
- /* copy the newly sorted listbase */
- group->gobject = listb;
- }
- }
-}
-
-static void dag_scene_tag_rebuild(Scene *sce)
-{
- if (sce->theDag) {
- sce->theDag->need_update = true;
- }
-}
-
-/* free the depency graph */
-static void dag_scene_free(Scene *sce)
-{
- if (sce->theDag) {
- free_forest(sce->theDag);
- MEM_freeN(sce->theDag);
- sce->theDag = NULL;
- }
-}
-
-/* Check whether object data needs to be evaluated before it
- * might be used by others.
- *
- * Means that mesh object needs to have proper derivedFinal,
- * curves-typed objects are to have proper curve cache.
- *
- * Other objects or objects which are tagged for data update are
- * not considered to be in need of evaluation.
- */
-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;
-}
-
-/* Check whether object data is tagged for update. */
-static bool check_object_tagged_for_update(Object *object)
-{
- if (object->recalc & OB_RECALC_ALL) {
- return true;
- }
-
- if (ELEM(object->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) {
- ID *data_id = object->data;
- return (data_id->tag & (LIB_TAG_ID_RECALC_DATA | LIB_TAG_ID_RECALC)) != 0;
- }
-
- return false;
-}
-
-/* Flush changes from tagged objects in the scene to their
- * dependencies which are not evaluated yet.
- *
- * This is needed to ensure all the dependencies are met
- * before objects gets handled by object_handle_update(),
- *
- * This is needed when visible layers are changed or changing
- * scene graph layout which involved usage of objects which
- * aren't in the scene or weren't visible yet.
- */
-static void dag_invisible_dependencies_flush(Scene *scene)
-{
- DagNode *root_node = scene->theDag->DagNode.first, *node;
- DagNodeQueue *queue;
-
- for (node = root_node; node != NULL; node = node->next) {
- node->color = DAG_WHITE;
- }
-
- queue = queue_create(DAGQUEUEALLOC);
-
- for (node = root_node; node != NULL; node = node->next) {
- if (node->color == DAG_WHITE) {
- push_stack(queue, node);
- node->color = DAG_GRAY;
-
- while (queue->count) {
- DagNode *current_node = get_top_node_queue(queue);
- DagAdjList *itA;
- bool skip = false;
-
- for (itA = current_node->child; itA; itA = itA->next) {
- if (itA->node->color == DAG_WHITE) {
- itA->node->color = DAG_GRAY;
- push_stack(queue, itA->node);
- skip = true;
- break;
- }
- }
-
- if (!skip) {
- current_node = pop_queue(queue);
-
- if (current_node->type == ID_OB) {
- Object *current_object = current_node->ob;
- if (check_object_needs_evaluation(current_object)) {
- for (itA = current_node->child; itA; itA = itA->next) {
- if (itA->node->type == ID_OB) {
- Object *object = itA->node->ob;
- if (check_object_tagged_for_update(object)) {
- current_object->recalc |= OB_RECALC_OB | OB_RECALC_DATA;
- }
- }
- }
- }
- }
- node->color = DAG_BLACK;
- }
- }
- }
- }
-
- queue_delete(queue);
-}
-
-static void dag_invisible_dependencies_check_flush(Main *bmain, Scene *scene)
-{
- if (DAG_id_type_tagged(bmain, ID_OB) ||
- 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_LT)) /* Lattice */
- {
- dag_invisible_dependencies_flush(scene);
- }
-}
-
-/* sort the base list on dependency order */
-static void dag_scene_build(Main *bmain, Scene *sce)
-{
- DagNode *node, *rootnode;
- DagNodeQueue *nqueue;
- DagAdjList *itA;
- int time;
- int skip = 0;
- ListBase tempbase;
- Base *base;
-
- BLI_listbase_clear(&tempbase);
-
- build_dag(bmain, sce, DAG_RL_ALL_BUT_DATA);
-
- dag_check_cycle(sce->theDag);
-
- nqueue = queue_create(DAGQUEUEALLOC);
-
- for (node = sce->theDag->DagNode.first; node; node = node->next) {
- node->color = DAG_WHITE;
- }
-
- time = 1;
-
- rootnode = sce->theDag->DagNode.first;
- rootnode->color = DAG_GRAY;
- time++;
- push_stack(nqueue, rootnode);
-
- while (nqueue->count) {
-
- skip = 0;
- node = get_top_node_queue(nqueue);
-
- itA = node->child;
- while (itA != NULL) {
- if (itA->node->color == DAG_WHITE) {
- itA->node->DFS_dvtm = time;
- itA->node->color = DAG_GRAY;
-
- time++;
- push_stack(nqueue, itA->node);
- skip = 1;
- break;
- }
- itA = itA->next;
- }
-
- if (!skip) {
- if (node) {
- node = pop_queue(nqueue);
- if (node->ob == sce) /* we are done */
- break;
- node->color = DAG_BLACK;
-
- time++;
- base = sce->base.first;
- while (base && base->object != node->ob)
- base = base->next;
- if (base) {
- BLI_remlink(&sce->base, base);
- BLI_addhead(&tempbase, base);
- }
- }
- }
- }
-
- /* temporal correction for circular dependencies */
- base = sce->base.first;
- while (base) {
- BLI_remlink(&sce->base, base);
- BLI_addhead(&tempbase, base);
- //if (G.debug & G_DEBUG)
- printf("cyclic %s\n", base->object->id.name);
- base = sce->base.first;
- }
-
- sce->base = tempbase;
- queue_delete(nqueue);
-
- /* all groups with objects in this scene gets resorted too */
- scene_sort_groups(bmain, sce);
-
- if (G.debug & G_DEBUG) {
- printf("\nordered\n");
- for (base = sce->base.first; base; base = base->next) {
- printf(" %s\n", base->object->id.name);
- }
- }
-
- /* Make sure that new dependencies which came from invisible layers
- * are tagged for update (if they're needed for objects which were
- * tagged for update).
- */
- dag_invisible_dependencies_check_flush(bmain, sce);
-}
-
-/* clear all dependency graphs */
-void DAG_relations_tag_update(Main *bmain)
-{
- if (DEG_depsgraph_use_legacy()) {
- Scene *sce;
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- dag_scene_tag_rebuild(sce);
- }
- }
- else {
- /* New dependency graph. */
- DEG_relations_tag_update(bmain);
- }
-}
-
-/* rebuild dependency graph only for a given scene */
-void DAG_scene_relations_rebuild(Main *bmain, Scene *sce)
-{
- if (DEG_depsgraph_use_legacy()) {
- dag_scene_free(sce);
- DAG_scene_relations_update(bmain, sce);
- }
- else {
- /* New dependency graph. */
- DEG_scene_relations_rebuild(bmain, sce);
- }
-}
-
-/* create dependency graph if it was cleared or didn't exist yet */
-void DAG_scene_relations_update(Main *bmain, Scene *sce)
-{
- if (DEG_depsgraph_use_legacy()) {
- if (!sce->theDag || sce->theDag->need_update)
- dag_scene_build(bmain, sce);
- }
- else {
- /* New dependency graph. */
- DEG_scene_relations_update(bmain, sce);
- }
-}
-
-void DAG_scene_relations_validate(Main *bmain, Scene *sce)
-{
- if (!DEG_depsgraph_use_legacy()) {
- DEG_debug_scene_relations_validate(bmain, sce);
- }
-}
-
-void DAG_scene_free(Scene *sce)
-{
- if (DEG_depsgraph_use_legacy()) {
- if (sce->theDag) {
- free_forest(sce->theDag);
- MEM_freeN(sce->theDag);
- sce->theDag = NULL;
- }
- }
- else {
- if (sce->depsgraph) {
- DEG_graph_free(sce->depsgraph);
- sce->depsgraph = NULL;
- }
- }
-}
-
-static void lib_id_recalc_tag(Main *bmain, ID *id)
-{
- id->tag |= LIB_TAG_ID_RECALC;
- DAG_id_type_tag(bmain, GS(id->name));
-}
-
-static void lib_id_recalc_data_tag(Main *bmain, ID *id)
-{
- id->tag |= LIB_TAG_ID_RECALC_DATA;
- DAG_id_type_tag(bmain, GS(id->name));
-}
-
-/* node was checked to have lasttime != curtime and is if type ID_OB */
-static void flush_update_node(Main *bmain, DagNode *node, unsigned int layer, int curtime)
-{
- DagAdjList *itA;
- Object *ob, *obc;
- int oldflag;
- bool changed = false;
- unsigned int all_layer;
-
- node->lasttime = curtime;
-
- ob = node->ob;
- if (ob && (ob->recalc & OB_RECALC_ALL)) {
- all_layer = node->scelay;
-
- /* got an object node that changes, now check relations */
- for (itA = node->child; itA; itA = itA->next) {
- all_layer |= itA->lay;
- /* the relationship is visible */
- if ((itA->lay & layer)) { // XXX || (itA->node->ob == obedit)
- if (itA->node->type == ID_OB) {
- obc = itA->node->ob;
- oldflag = obc->recalc;
-
- /* got a ob->obc relation, now check if flag needs flush */
- if (ob->recalc & OB_RECALC_OB) {
- if (itA->type & DAG_RL_OB_OB) {
- //printf("ob %s changes ob %s\n", ob->id.name, obc->id.name);
- obc->recalc |= OB_RECALC_OB;
- lib_id_recalc_tag(bmain, &obc->id);
- }
- if (itA->type & DAG_RL_OB_DATA) {
- //printf("ob %s changes obdata %s\n", ob->id.name, obc->id.name);
- obc->recalc |= OB_RECALC_DATA;
- lib_id_recalc_data_tag(bmain, &obc->id);
- }
- }
- if (ob->recalc & OB_RECALC_DATA) {
- if (itA->type & DAG_RL_DATA_OB) {
- //printf("obdata %s changes ob %s\n", ob->id.name, obc->id.name);
- obc->recalc |= OB_RECALC_OB;
- lib_id_recalc_tag(bmain, &obc->id);
- }
- if (itA->type & DAG_RL_DATA_DATA) {
- //printf("obdata %s changes obdata %s\n", ob->id.name, obc->id.name);
- obc->recalc |= OB_RECALC_DATA;
- lib_id_recalc_data_tag(bmain, &obc->id);
- }
- }
- if (oldflag != obc->recalc) changed = 1;
- }
- }
- }
- /* even nicer, we can clear recalc flags... */
- if ((all_layer & layer) == 0) { // XXX && (ob != obedit)) {
- /* but existing displaylists or derivedmesh should be freed */
- if (ob->recalc & OB_RECALC_DATA)
- BKE_object_free_derived_caches(ob);
-
- ob->recalc &= ~OB_RECALC_ALL;
- }
- }
-
- /* check case where child changes and parent forcing obdata to change */
- /* should be done regardless if this ob has recalc set */
- /* could merge this in with loop above...? (ton) */
- for (itA = node->child; itA; itA = itA->next) {
- /* the relationship is visible */
- if ((itA->lay & layer)) { // XXX || (itA->node->ob == obedit)
- if (itA->node->type == ID_OB) {
- obc = itA->node->ob;
- /* child moves */
- if ((obc->recalc & OB_RECALC_ALL) == OB_RECALC_OB) {
- /* parent has deforming info */
- if (itA->type & (DAG_RL_OB_DATA | DAG_RL_DATA_DATA)) {
- // printf("parent %s changes ob %s\n", ob->id.name, obc->id.name);
- obc->recalc |= OB_RECALC_DATA;
- lib_id_recalc_data_tag(bmain, &obc->id);
- }
- }
- }
- }
- }
-
- /* we only go deeper if node not checked or something changed */
- for (itA = node->child; itA; itA = itA->next) {
- if (changed || itA->node->lasttime != curtime)
- flush_update_node(bmain, itA->node, layer, curtime);
- }
-
-}
-
-/* node was checked to have lasttime != curtime, and is of type ID_OB */
-static unsigned int flush_layer_node(Scene *sce, DagNode *node, int curtime)
-{
- DagAdjList *itA;
-
- node->lasttime = curtime;
- node->lay = node->scelay;
-
- for (itA = node->child; itA; itA = itA->next) {
- if (itA->node->type == ID_OB) {
- if (itA->node->lasttime != curtime) {
- itA->lay = flush_layer_node(sce, itA->node, curtime); /* lay is only set once for each relation */
- }
- else {
- itA->lay = itA->node->lay;
- }
-
- node->lay |= itA->lay;
- }
- }
-
- return node->lay;
-}
-
-/* node was checked to have lasttime != curtime, and is of type ID_OB */
-static void flush_pointcache_reset(Main *bmain, Scene *scene, DagNode *node,
- int curtime, unsigned int lay, bool reset)
-{
- DagAdjList *itA;
- Object *ob;
-
- node->lasttime = curtime;
-
- for (itA = node->child; itA; itA = itA->next) {
- if (itA->node->type == ID_OB) {
- if (itA->node->lasttime != curtime) {
- ob = (Object *)(itA->node->ob);
-
- if (reset || (ob->recalc & OB_RECALC_ALL)) {
- if (BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH)) {
- /* Don't tag nodes which are on invisible layer. */
- if (itA->node->lay & lay) {
- ob->recalc |= OB_RECALC_DATA;
- lib_id_recalc_data_tag(bmain, &ob->id);
- }
- }
-
- flush_pointcache_reset(bmain, scene, itA->node, curtime, lay, true);
- }
- else
- flush_pointcache_reset(bmain, scene, itA->node, curtime, lay, false);
- }
- }
- }
-}
-
-/* flush layer flags to dependencies */
-static void dag_scene_flush_layers(Scene *sce, int lay)
-{
- DagNode *node, *firstnode;
- DagAdjList *itA;
- Base *base;
- int lasttime;
-
- firstnode = sce->theDag->DagNode.first; /* always scene node */
-
- for (itA = firstnode->child; itA; itA = itA->next)
- itA->lay = 0;
-
- sce->theDag->time++; /* so we know which nodes were accessed */
- lasttime = sce->theDag->time;
-
- /* update layer flags in nodes */
- for (base = sce->base.first; base; base = base->next) {
- node = dag_get_node(sce->theDag, base->object);
- node->scelay = base->object->lay;
- }
-
- /* ensure cameras are set as if they are on a visible layer, because
- * they ared still used for rendering or setting the camera view
- *
- * XXX, this wont work for local view / unlocked camera's */
- if (sce->camera) {
- node = dag_get_node(sce->theDag, sce->camera);
- node->scelay |= lay;
- }
-
-#ifdef DURIAN_CAMERA_SWITCH
- {
- TimeMarker *m;
-
- for (m = sce->markers.first; m; m = m->next) {
- if (m->camera) {
- node = dag_get_node(sce->theDag, m->camera);
- node->scelay |= lay;
- }
- }
- }
-#endif
-
- /* flush layer nodes to dependencies */
- for (itA = firstnode->child; itA; itA = itA->next)
- if (itA->node->lasttime != lasttime && itA->node->type == ID_OB)
- flush_layer_node(sce, itA->node, lasttime);
-}
-
-static void dag_tag_renderlayers(Scene *sce, unsigned int lay)
-{
- if (sce->nodetree) {
- bNode *node;
- Base *base;
- unsigned int lay_changed = 0;
-
- for (base = sce->base.first; base; base = base->next)
- if (base->lay & lay)
- if (base->object->recalc)
- lay_changed |= base->lay;
-
- for (node = sce->nodetree->nodes.first; node; node = node->next) {
- if (node->id == (ID *)sce) {
- SceneRenderLayer *srl = BLI_findlink(&sce->r.layers, node->custom1);
- if (srl && (srl->lay & lay_changed))
- nodeUpdate(sce->nodetree, node);
- }
- }
- }
-}
-
-/* flushes all recalc flags in objects down the dependency tree */
-void DAG_scene_flush_update(Main *bmain, Scene *sce, unsigned int lay, const short time)
-{
- DagNode *firstnode;
- DagAdjList *itA;
- Object *ob;
- int lasttime;
-
- if (!DEG_depsgraph_use_legacy()) {
- return;
- }
-
- if (sce->theDag == NULL || sce->theDag->need_update) {
- printf("DAG zero... not allowed to happen!\n");
- DAG_scene_relations_update(bmain, sce);
- }
-
- firstnode = sce->theDag->DagNode.first; /* always scene node */
-
- /* first we flush the layer flags */
- dag_scene_flush_layers(sce, lay);
-
- /* then we use the relationships + layer info to flush update events */
- sce->theDag->time++; /* so we know which nodes were accessed */
- lasttime = sce->theDag->time;
- for (itA = firstnode->child; itA; itA = itA->next)
- if (itA->node->lasttime != lasttime && itA->node->type == ID_OB)
- flush_update_node(bmain, itA->node, lay, lasttime);
-
- /* if update is not due to time change, do pointcache clears */
- if (!time) {
- sce->theDag->time++; /* so we know which nodes were accessed */
- lasttime = sce->theDag->time;
- for (itA = firstnode->child; itA; itA = itA->next) {
- if (itA->node->lasttime != lasttime && itA->node->type == ID_OB) {
- ob = (Object *)(itA->node->ob);
-
- if (ob->recalc & OB_RECALC_ALL) {
- if (BKE_ptcache_object_reset(sce, ob, PTCACHE_RESET_DEPSGRAPH)) {
- ob->recalc |= OB_RECALC_DATA;
- lib_id_recalc_data_tag(bmain, &ob->id);
- }
-
- flush_pointcache_reset(bmain, sce, itA->node, lasttime,
- lay, true);
- }
- else
- flush_pointcache_reset(bmain, sce, itA->node, lasttime,
- lay, false);
- }
- }
- }
-
- dag_tag_renderlayers(sce, lay);
-}
-
-static bool modifier_nlastrips_use_time(ListBase *strips)
-{
- NlaStrip *strip;
-
- if (strips) {
- for (strip = strips->first; strip; strip = strip->next) {
- if (modifier_nlastrips_use_time(&strip->strips)) {
- return true;
- }
- else if (strip->act) {
- FCurve *fcu;
-
- for (fcu = strip->act->curves.first; fcu; fcu = fcu->next) {
- if (fcu->rna_path && strstr(fcu->rna_path, "modifiers["))
- return true;
- }
- }
- }
- }
-
- return false;
-}
-
-static bool object_modifiers_use_time(Object *ob)
-{
- ModifierData *md;
-
- /* check if a modifier in modifier stack needs time input */
- for (md = ob->modifiers.first; md; md = md->next) {
- if (modifier_dependsOnTime(md))
- return true;
- }
-
- /* check whether any modifiers are animated */
- if (ob->adt) {
- AnimData *adt = ob->adt;
- NlaTrack *nlt;
- FCurve *fcu;
-
- /* action - check for F-Curves with paths containing 'modifiers[' */
- if (adt->action) {
- for (fcu = adt->action->curves.first; fcu; fcu = fcu->next) {
- if (fcu->rna_path && strstr(fcu->rna_path, "modifiers["))
- return true;
- }
- }
-
- /* This here allows modifier properties to get driven and still update properly
- *
- * Workaround to get [#26764] (e.g. subsurf levels not updating when animated/driven)
- * working, without the updating problems ([#28525] [#28690] [#28774] [#28777]) caused
- * by the RNA updates cache introduced in r.38649
- */
- for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
- if (fcu->rna_path && strstr(fcu->rna_path, "modifiers["))
- return true;
- }
-
- /* Also check NLA Strips... [#T45938] */
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
- if (modifier_nlastrips_use_time(&nlt->strips))
- return true;
- }
- }
-
- return false;
-}
-
-static short animdata_use_time(AnimData *adt)
-{
- NlaTrack *nlt;
-
- if (adt == NULL) return 0;
-
- /* check action - only if assigned, and it has anim curves */
- if (adt->action && adt->action->curves.first)
- return 1;
-
- /* check NLA tracks + strips */
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
- if (nlt->strips.first)
- return 1;
- }
-
- /* If we have drivers, more likely than not, on a frame change
- * they'll need updating because their owner changed
- *
- * This is kindof a hack to get around a whole host of problems
- * involving drivers using non-object datablock data (which the
- * depsgraph currently has no way of representing let alone correctly
- * dependency sort+tagging). By doing this, at least we ensure that
- * some commonly attempted drivers (such as scene -> current frame;
- * see "Driver updates fail" thread on Bf-committers dated July 2)
- * will work correctly, and that other non-object datablocks will have
- * their drivers update at least on frame change.
- *
- * -- Aligorith, July 4 2011
- */
- if (adt->drivers.first)
- return 1;
-
- return 0;
-}
-
-static void dag_object_time_update_flags(Main *bmain, Scene *scene, Object *ob)
-{
- if (ob->constraints.first) {
- bConstraint *con;
- for (con = ob->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (cti) {
- /* special case for camera tracking -- it doesn't use targets to define relations */
- if (ELEM(cti->type,
- CONSTRAINT_TYPE_FOLLOWTRACK,
- CONSTRAINT_TYPE_CAMERASOLVER,
- CONSTRAINT_TYPE_OBJECTSOLVER,
- CONSTRAINT_TYPE_TRANSFORM_CACHE))
- {
- ob->recalc |= OB_RECALC_OB;
- }
- else if (cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar) {
- ob->recalc |= OB_RECALC_OB;
- break;
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 1);
- }
-
- }
- }
- }
-
- if (ob->parent) {
- /* motion path or bone child */
- if (ob->parent->type == OB_CURVE || ob->parent->type == OB_ARMATURE) ob->recalc |= OB_RECALC_OB;
- }
-
-#if 0 // XXX old animation system
- if (ob->nlastrips.first) {
- if (ob->dup_group) {
- bActionStrip *strip;
- /* this case is for groups with nla, whilst nla target has no action or nla */
- for (strip = ob->nlastrips.first; strip; strip = strip->next) {
- if (strip->object)
- strip->object->recalc |= OB_RECALC_ALL;
- }
- }
- }
-#endif // XXX old animation system
-
- if (animdata_use_time(ob->adt)) {
- ob->recalc |= OB_RECALC_OB;
- ob->adt->recalc |= ADT_RECALC_ANIM;
- }
-
- if ((ob->adt) && (ob->type == OB_ARMATURE)) ob->recalc |= OB_RECALC_DATA;
-
- if (object_modifiers_use_time(ob)) ob->recalc |= OB_RECALC_DATA;
- if ((ob->pose) && (ob->pose->flag & POSE_CONSTRAINTS_TIMEDEPEND)) ob->recalc |= OB_RECALC_DATA;
-
- // XXX: scene here may not be the scene that contains the rigidbody world affecting this!
- if (ob->rigidbody_object && BKE_scene_check_rigidbody_active(scene))
- ob->recalc |= OB_RECALC_OB;
-
- {
- AnimData *adt = BKE_animdata_from_id((ID *)ob->data);
- Mesh *me;
- Curve *cu;
- Lattice *lt;
-
- switch (ob->type) {
- case OB_MESH:
- me = ob->data;
- if (me->key) {
- if (!(ob->shapeflag & OB_SHAPE_LOCK)) {
- ob->recalc |= OB_RECALC_DATA;
- }
- }
- if (ob->particlesystem.first)
- ob->recalc |= OB_RECALC_DATA;
- break;
- case OB_CURVE:
- case OB_SURF:
- cu = ob->data;
- if (cu->key) {
- if (!(ob->shapeflag & OB_SHAPE_LOCK)) {
- ob->recalc |= OB_RECALC_DATA;
- }
- }
- break;
- case OB_FONT:
- cu = ob->data;
- if (BLI_listbase_is_empty(&cu->nurb) && cu->str && cu->vfont)
- ob->recalc |= OB_RECALC_DATA;
- break;
- case OB_LATTICE:
- lt = ob->data;
- if (lt->key) {
- if (!(ob->shapeflag & OB_SHAPE_LOCK)) {
- ob->recalc |= OB_RECALC_DATA;
- }
- }
- break;
- case OB_MBALL:
- if (ob->transflag & OB_DUPLI) ob->recalc |= OB_RECALC_DATA;
- break;
- case OB_EMPTY:
- /* update animated images */
- if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data)
- if (BKE_image_is_animated(ob->data))
- ob->recalc |= OB_RECALC_DATA;
- break;
- }
-
- if (animdata_use_time(adt)) {
- ob->recalc |= OB_RECALC_DATA;
- adt->recalc |= ADT_RECALC_ANIM;
- }
-
- if (ob->particlesystem.first) {
- ParticleSystem *psys = ob->particlesystem.first;
-
- for (; psys; psys = psys->next) {
- if (psys_check_enabled(ob, psys, G.is_rendering)) {
- ob->recalc |= OB_RECALC_DATA;
- break;
- }
- }
- }
- }
-
- if (ob->recalc & OB_RECALC_OB)
- lib_id_recalc_tag(bmain, &ob->id);
- if (ob->recalc & OB_RECALC_DATA)
- lib_id_recalc_data_tag(bmain, &ob->id);
-
-}
-
-/* recursively update objects in groups, each group is done at most once */
-static void dag_group_update_flags(Main *bmain, Scene *scene, Group *group, const bool do_time)
-{
- GroupObject *go;
-
- if (group->id.tag & LIB_TAG_DOIT)
- return;
-
- group->id.tag |= LIB_TAG_DOIT;
-
- for (go = group->gobject.first; go; go = go->next) {
- if (do_time)
- dag_object_time_update_flags(bmain, scene, go->ob);
- if (go->ob->dup_group)
- dag_group_update_flags(bmain, scene, go->ob->dup_group, do_time);
- }
-}
-
-/* flag all objects that need recalc, for changes in time for example */
-/* do_time: make this optional because undo resets objects to their animated locations without this */
-void DAG_scene_update_flags(Main *bmain, Scene *scene, unsigned int lay, const bool do_time, const bool do_invisible_flush)
-{
- Base *base;
- Object *ob;
- Group *group;
- GroupObject *go;
- Scene *sce_iter;
-
- BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false);
-
- /* set ob flags where animated systems are */
- for (SETLOOPER(scene, sce_iter, base)) {
- ob = base->object;
-
- if (do_time) {
- /* now if DagNode were part of base, the node->lay could be checked... */
- /* we do all now, since the scene_flush checks layers and clears recalc flags even */
-
- /* NOTE: "sce_iter" not "scene" so that rigidbodies in background scenes work
- * (i.e. muting + rbw availability can be checked and tagged properly) [#33970]
- */
- dag_object_time_update_flags(bmain, sce_iter, ob);
- }
-
- /* recursively tag groups with LIB_TAG_DOIT, and update flags for objects */
- if (ob->dup_group)
- dag_group_update_flags(bmain, scene, ob->dup_group, do_time);
- }
-
- for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set)
- DAG_scene_flush_update(bmain, sce_iter, lay, 1);
-
- if (do_time) {
- /* test: set time flag, to disable baked systems to update */
- for (SETLOOPER(scene, sce_iter, base)) {
- ob = base->object;
- if (ob->recalc & OB_RECALC_ALL)
- ob->recalc |= OB_RECALC_TIME;
- }
-
- /* hrmf... an exception to look at once, for invisible camera object we do it over */
- if (scene->camera)
- dag_object_time_update_flags(bmain, scene, scene->camera);
- }
-
- /* and store the info in groupobject */
- for (group = bmain->group.first; group; group = group->id.next) {
- if (group->id.tag & LIB_TAG_DOIT) {
- for (go = group->gobject.first; go; go = go->next) {
- go->recalc = go->ob->recalc;
- // printf("ob %s recalc %d\n", go->ob->id.name, go->recalc);
- }
- group->id.tag &= ~LIB_TAG_DOIT;
- }
- }
-
- if (do_invisible_flush) {
- dag_invisible_dependencies_check_flush(bmain, scene);
- }
-}
-
-/* struct returned by DagSceneLayer */
-typedef struct DagSceneLayer {
- struct DagSceneLayer *next, *prev;
- Scene *scene;
- unsigned int layer;
-} DagSceneLayer;
-
-/* returns visible scenes with valid DAG */
-static void dag_current_scene_layers(Main *bmain, ListBase *lb)
-{
- wmWindowManager *wm;
- wmWindow *win;
-
- BLI_listbase_clear(lb);
-
- /* if we have a windowmanager, look into windows */
- if ((wm = bmain->wm.first)) {
-
- BKE_main_id_flag_listbase(&bmain->scene, LIB_TAG_DOIT, 1);
-
- for (win = wm->windows.first; win; win = win->next) {
- if (win->screen && win->screen->scene->theDag) {
- Scene *scene = win->screen->scene;
- DagSceneLayer *dsl;
-
- if (scene->id.tag & LIB_TAG_DOIT) {
- dsl = MEM_mallocN(sizeof(DagSceneLayer), "dag scene layer");
-
- BLI_addtail(lb, dsl);
-
- dsl->scene = scene;
- dsl->layer = BKE_screen_visible_layers(win->screen, scene);
-
- scene->id.tag &= ~LIB_TAG_DOIT;
- }
- else {
- /* It is possible that multiple windows shares the same scene
- * and have different layers visible.
- *
- * Here we deal with such cases by squashing layers bits from
- * multiple windoew to the DagSceneLayer.
- *
- * TODO(sergey): Such a lookup could be optimized perhaps,
- * however should be fine for now since we usually have only
- * few open windows.
- */
- for (dsl = lb->first; dsl; dsl = dsl->next) {
- if (dsl->scene == scene) {
- dsl->layer |= BKE_screen_visible_layers(win->screen, scene);
- break;
- }
- }
- }
- }
- }
- }
- else {
- /* if not, use the first sce */
- DagSceneLayer *dsl = MEM_mallocN(sizeof(DagSceneLayer), "dag scene layer");
-
- BLI_addtail(lb, dsl);
-
- dsl->scene = bmain->scene.first;
- dsl->layer = dsl->scene->lay;
-
- /* XXX for background mode, we should get the scene
- * from somewhere, for the -S option, but it's in
- * the context, how to get it here? */
- }
-}
-
-static void dag_group_on_visible_update(Scene *scene, Group *group)
-{
- GroupObject *go;
-
- if (group->id.tag & LIB_TAG_DOIT)
- return;
-
- group->id.tag |= LIB_TAG_DOIT;
-
- for (go = group->gobject.first; go; go = go->next) {
- if (ELEM(go->ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) {
- go->ob->recalc |= OB_RECALC_DATA;
- go->ob->id.tag |= LIB_TAG_DOIT;
- lib_id_recalc_tag(G.main, &go->ob->id);
- }
- if (go->ob->proxy_from) {
- go->ob->recalc |= OB_RECALC_OB;
- go->ob->id.tag |= LIB_TAG_DOIT;
- lib_id_recalc_tag(G.main, &go->ob->id);
- }
-
- if (go->ob->dup_group)
- dag_group_on_visible_update(scene, go->ob->dup_group);
- }
-}
-
-void DAG_on_visible_update(Main *bmain, const bool do_time)
-{
- ListBase listbase;
- DagSceneLayer *dsl;
-
- if (!DEG_depsgraph_use_legacy()) {
- /* Inform new dependnecy graphs about visibility changes. */
- DEG_on_visible_update(bmain, do_time);
- return;
- }
-
- /* get list of visible scenes and layers */
- dag_current_scene_layers(bmain, &listbase);
-
- for (dsl = listbase.first; dsl; dsl = dsl->next) {
- Scene *scene = dsl->scene;
- Scene *sce_iter;
- Base *base;
- Object *ob;
- DagNode *node;
- unsigned int lay = dsl->layer, oblay;
-
- /* derivedmeshes and displists are not saved to file so need to be
- * remade, tag them so they get remade in the scene update loop,
- * note armature poses or object matrices are preserved and do not
- * require updates, so we skip those */
- for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set)
- dag_scene_flush_layers(sce_iter, lay);
-
- BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false);
-
- for (SETLOOPER(scene, sce_iter, base)) {
- ob = base->object;
- node = (sce_iter->theDag) ? dag_get_node(sce_iter->theDag, ob) : NULL;
- oblay = (node) ? node->lay : ob->lay;
-
- if ((oblay & lay) & ~scene->lay_updated) {
- /* TODO(sergey): Why do we need armature here now but didn't need before? */
- if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE, OB_ARMATURE)) {
- ob->recalc |= OB_RECALC_DATA;
- lib_id_recalc_tag(bmain, &ob->id);
- }
- /* This should not be needed here, but in some cases, like after a redo, we can end up with
- * a wrong final matrix (see T42472).
- * Quoting Sergey, this comes from BKE_object_handle_update_ex, which is calling
- * BKE_object_where_is_calc_ex when it shouldn't, but that issue is not easily fixable.
- */
- else {
- ob->recalc |= OB_RECALC_OB;
- lib_id_recalc_tag(bmain, &ob->id);
- }
- if (ob->proxy && (ob->proxy_group == NULL)) {
- ob->proxy->recalc |= OB_RECALC_DATA;
- lib_id_recalc_tag(bmain, &ob->id);
- }
- if (ob->dup_group)
- dag_group_on_visible_update(scene, ob->dup_group);
- }
- }
-
- BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false);
-
- /* now tag update flags, to ensure deformers get calculated on redraw */
- DAG_scene_update_flags(bmain, scene, lay, do_time, true);
- scene->lay_updated |= lay;
- }
-
- BLI_freelistN(&listbase);
-
- /* hack to get objects updating on layer changes */
- DAG_id_type_tag(bmain, ID_OB);
-
- /* so masks update on load */
- if (bmain->mask.first) {
- Mask *mask;
-
- for (mask = bmain->mask.first; mask; mask = mask->id.next) {
- DAG_id_tag_update(&mask->id, 0);
- }
- }
-}
-
-static void dag_id_flush_update__isDependentTexture(
- void *userData, Object *UNUSED(ob), ID **idpoin, int UNUSED(cd_flag))
-{
- struct { ID *id; bool is_dependent; } *data = userData;
-
- if (*idpoin && GS((*idpoin)->name) == ID_TE) {
- if (data->id == (*idpoin))
- data->is_dependent = 1;
- }
-}
-
-static void dag_id_flush_update(Main *bmain, Scene *sce, ID *id)
-{
- Object *obt, *ob = NULL;
- short idtype;
-
- /* here we flush a few things before actual scene wide flush, mostly
- * due to only objects and not other datablocks being in the depsgraph */
-
- /* set flags & pointcache for object */
- if (GS(id->name) == ID_OB) {
- ob = (Object *)id;
- BKE_ptcache_object_reset(sce, ob, PTCACHE_RESET_DEPSGRAPH);
-
- /* So if someone tagged object recalc directly,
- * id_tag_update bit-field stays relevant
- */
- if (ob->recalc & OB_RECALC_ALL) {
- DAG_id_type_tag(bmain, GS(id->name));
- }
-
- if (ob->recalc & OB_RECALC_DATA) {
- /* all users of this ob->data should be checked */
- id = ob->data;
-
- /* no point in trying in this cases */
- if (id && id->us <= 1) {
- dag_editors_id_update(bmain, id);
- id = NULL;
- }
- }
- }
-
- /* set flags & pointcache for object data */
- if (id) {
- idtype = GS(id->name);
-
-
- if (OB_DATA_SUPPORT_ID(idtype)) {
- for (obt = bmain->object.first; obt; obt = obt->id.next) {
- if (!(ob && obt == ob) && obt->data == id) {
- obt->recalc |= OB_RECALC_DATA;
- lib_id_recalc_data_tag(bmain, &obt->id);
- BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH);
- }
- }
- }
- else if (idtype == ID_VF) {
- for (obt = bmain->object.first; obt; obt = obt->id.next) {
- if (obt->type == OB_FONT) {
- Curve *cu = obt->data;
- if (ELEM((struct VFont *)id, CURVE_VFONT_ANY(cu))) {
- obt->recalc |= OB_RECALC_DATA;
- lib_id_recalc_data_tag(bmain, &obt->id);
- }
- }
- }
- }
-
- /* set flags based on textures - can influence depgraph via modifiers */
- if (idtype == ID_TE) {
- for (obt = bmain->object.first; obt; obt = obt->id.next) {
- struct { ID *id; bool is_dependent; } data;
- data.id = id;
- data.is_dependent = 0;
-
- modifiers_foreachIDLink(obt, dag_id_flush_update__isDependentTexture, &data);
- if (data.is_dependent) {
- obt->recalc |= OB_RECALC_DATA;
- lib_id_recalc_data_tag(bmain, &obt->id);
- }
-
- /* particle settings can use the texture as well */
- if (obt->particlesystem.first) {
- ParticleSystem *psys = obt->particlesystem.first;
- MTex **mtexp, *mtex;
- int a;
- for (; psys; psys = psys->next) {
- mtexp = psys->part->mtex;
- for (a = 0; a < MAX_MTEX; a++, mtexp++) {
- mtex = *mtexp;
- if (mtex && mtex->tex == (Tex *)id) {
- obt->recalc |= OB_RECALC_DATA;
- lib_id_recalc_data_tag(bmain, &obt->id);
-
- if (mtex->mapto & PAMAP_INIT)
- psys->recalc |= PSYS_RECALC_RESET;
- if (mtex->mapto & PAMAP_CHILD)
- psys->recalc |= PSYS_RECALC_CHILD;
-
- BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH);
- }
- }
- }
- }
- }
- }
-
- /* set flags based on ShapeKey */
- if (idtype == ID_KE) {
- for (obt = bmain->object.first; obt; obt = obt->id.next) {
- Key *key = BKE_key_from_object(obt);
- if (!(ob && obt == ob) && ((ID *)key == id)) {
- obt->flag |= (OB_RECALC_OB | OB_RECALC_DATA);
- lib_id_recalc_tag(bmain, &obt->id);
- lib_id_recalc_data_tag(bmain, &obt->id);
- BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH);
- }
- }
- }
-
- /* set flags based on particle settings */
- if (idtype == ID_PA) {
- ParticleSystem *psys;
- for (obt = bmain->object.first; obt; obt = obt->id.next)
- for (psys = obt->particlesystem.first; psys; psys = psys->next)
- if (&psys->part->id == id)
- BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH);
- }
-
- if (ELEM(idtype, ID_MA, ID_TE)) {
- obt = sce->basact ? sce->basact->object : NULL;
- if (obt && obt->mode & OB_MODE_TEXTURE_PAINT) {
- BKE_texpaint_slots_refresh_object(sce, obt);
- BKE_paint_proj_mesh_data_check(sce, obt, NULL, NULL, NULL, NULL);
- GPU_drawobject_free(obt->derivedFinal);
- }
- }
-
- if (idtype == ID_MC) {
- MovieClip *clip = (MovieClip *) id;
-
- BKE_tracking_dopesheet_tag_update(&clip->tracking);
-
- for (obt = bmain->object.first; obt; obt = obt->id.next) {
- bConstraint *con;
- for (con = obt->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER,
- CONSTRAINT_TYPE_OBJECTSOLVER))
- {
- obt->recalc |= OB_RECALC_OB;
- lib_id_recalc_tag(bmain, &obt->id);
- break;
- }
- }
- }
-
- if (sce->nodetree) {
- bNode *node;
-
- for (node = sce->nodetree->nodes.first; node; node = node->next) {
- if (node->id == id) {
- nodeUpdate(sce->nodetree, node);
- }
- }
- }
- }
-
- /* Not pretty to iterate all the nodes here, but it's as good as it
- * could be with the current depsgraph design/
- */
- if (idtype == ID_IM) {
- FOREACH_NODETREE(bmain, ntree, parent_id) {
- if (ntree->type == NTREE_SHADER) {
- bNode *node;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->id == id) {
- lib_id_recalc_tag(bmain, &ntree->id);
- break;
- }
- }
- }
- } FOREACH_NODETREE_END
- }
-
- if (idtype == ID_MSK) {
- if (sce->nodetree) {
- bNode *node;
-
- for (node = sce->nodetree->nodes.first; node; node = node->next) {
- if (node->id == id) {
- nodeUpdate(sce->nodetree, node);
- }
- }
- }
- }
-
- /* camera's matrix is used to orient reconstructed stuff,
- * so it should happen tracking-related constraints recalculation
- * when camera is changing (sergey) */
- if (sce->camera && &sce->camera->id == id) {
- MovieClip *clip = BKE_object_movieclip_get(sce, sce->camera, true);
-
- if (clip)
- dag_id_flush_update(bmain, sce, &clip->id);
- }
-
- /* update editors */
- dag_editors_id_update(bmain, id);
- }
-}
-
-void DAG_ids_flush_tagged(Main *bmain)
-{
- ListBase listbase;
- DagSceneLayer *dsl;
- ListBase *lbarray[MAX_LIBARRAY];
- int a;
- bool do_flush = false;
-
- if (!DEG_depsgraph_use_legacy()) {
- DEG_ids_flush_tagged(bmain);
- return;
- }
-
- /* get list of visible scenes and layers */
- dag_current_scene_layers(bmain, &listbase);
-
- if (BLI_listbase_is_empty(&listbase))
- return;
-
- /* loop over all ID types */
- a = set_listbasepointers(bmain, lbarray);
-
- while (a--) {
- ListBase *lb = lbarray[a];
- ID *id = lb->first;
-
- if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) {
- for (; id; id = id->next) {
- if (id->tag & (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA)) {
-
- for (dsl = listbase.first; dsl; dsl = dsl->next)
- dag_id_flush_update(bmain, dsl->scene, id);
-
- do_flush = true;
- }
- }
- }
- }
-
- /* flush changes to other objects */
- if (do_flush) {
- for (dsl = listbase.first; dsl; dsl = dsl->next)
- DAG_scene_flush_update(bmain, dsl->scene, dsl->layer, 0);
- }
-
- BLI_freelistN(&listbase);
-}
-
-void DAG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
-{
- ListBase *lbarray[MAX_LIBARRAY];
- int a;
- bool updated = false;
-
- if (!DEG_depsgraph_use_legacy()) {
- DEG_ids_check_recalc(bmain, scene, time);
- return;
- }
-
- /* loop over all ID types */
- a = set_listbasepointers(bmain, lbarray);
-
- while (a--) {
- ListBase *lb = lbarray[a];
- ID *id = lb->first;
-
- if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) {
- updated = true;
- break;
- }
- }
-
- dag_editors_scene_update(bmain, scene, (updated || time));
-}
-
-/* It is possible that scene_update_post and frame_update_post handlers
- * will modify objects. The issue is that DAG_ids_clear_recalc is called
- * just after callbacks, which leaves objects with recalc flags but no
- * corresponding bit in ID recalc bitfield. This leads to some kind of
- * regression when using ID type tag fields to check whether there objects
- * to be updated internally comparing threaded DAG with legacy one.
- *
- * For now let's have a workaround which will preserve tag for ID_OB
- * if there're objects with OB_RECALC_ALL bits. This keeps behavior
- * unchanged comparing with 2.69 release.
- *
- * TODO(sergey): Need to get rid of such a workaround.
- *
- * - sergey -
- */
-
-#define POST_UPDATE_HANDLER_WORKAROUND
-
-void DAG_ids_clear_recalc(Main *bmain)
-{
- ListBase *lbarray[MAX_LIBARRAY];
- bNodeTree *ntree;
- int a;
-
-#ifdef POST_UPDATE_HANDLER_WORKAROUND
- bool have_updated_objects = false;
-
- if (DAG_id_type_tagged(bmain, ID_OB)) {
- ListBase listbase;
- DagSceneLayer *dsl;
-
- /* We need to check all visible scenes, otherwise resetting
- * OB_ID changed flag will only work fine for first scene of
- * multiple visible and all the rest will skip update.
- *
- * This could also lead to wrong behavior scene update handlers
- * because of missing ID datablock changed flags.
- *
- * This is a bit of a bummer to allocate list here, but likely
- * it wouldn't become too much bad because it only happens when
- * objects were actually changed.
- */
- dag_current_scene_layers(bmain, &listbase);
-
- for (dsl = listbase.first; dsl; dsl = dsl->next) {
- Scene *scene = dsl->scene;
- DagNode *node;
- for (node = scene->theDag->DagNode.first;
- node != NULL && have_updated_objects == false;
- node = node->next)
- {
- if (node->type == ID_OB) {
- Object *object = (Object *) node->ob;
- if (object->recalc & OB_RECALC_ALL) {
- have_updated_objects = true;
- break;
- }
- }
- }
- }
-
- BLI_freelistN(&listbase);
- }
-#endif
-
- /* loop over all ID types */
- a = set_listbasepointers(bmain, lbarray);
-
- while (a--) {
- ListBase *lb = lbarray[a];
- ID *id = lb->first;
-
- if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) {
- for (; id; id = id->next) {
- if (id->tag & (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA))
- id->tag &= ~(LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA);
-
- /* some ID's contain semi-datablock nodetree */
- ntree = ntreeFromID(id);
- if (ntree && (ntree->id.tag & (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA)))
- ntree->id.tag &= ~(LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA);
- }
- }
- }
-
- memset(bmain->id_tag_update, 0, sizeof(bmain->id_tag_update));
-
-#ifdef POST_UPDATE_HANDLER_WORKAROUND
- if (have_updated_objects) {
- DAG_id_type_tag(bmain, ID_OB);
- }
-#endif
-}
-
-void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag)
-{
- if (!DEG_depsgraph_use_legacy()) {
- DEG_id_tag_update_ex(bmain, id, flag);
- return;
- }
-
- if (id == NULL) return;
-
- if (G.debug & G_DEBUG_DEPSGRAPH) {
- printf("%s: id=%s flag=%d\n", __func__, id->name, flag);
- }
-
- /* tag ID for update */
- if (flag) {
- 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);
- }
- else
- lib_id_recalc_tag(bmain, id);
-
- /* flag is for objects and particle systems */
- if (flag) {
- Object *ob;
- short idtype = GS(id->name);
-
- if (idtype == ID_OB) {
- /* only quick tag */
- ob = (Object *)id;
- ob->recalc |= (flag & OB_RECALC_ALL);
- }
- else if (idtype == ID_PA) {
- ParticleSystem *psys;
- /* this is weak still, should be done delayed as well */
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- if (&psys->part->id == id) {
- ob->recalc |= (flag & OB_RECALC_ALL);
- psys->recalc |= (flag & PSYS_RECALC);
- lib_id_recalc_tag(bmain, &ob->id);
- lib_id_recalc_data_tag(bmain, &ob->id);
- }
- }
- }
- }
- else {
- /* disable because this is called on various ID types automatically.
- * where printing warning is not useful. for now just ignore */
- /* BLI_assert(!"invalid flag for this 'idtype'"); */
- }
- }
- else if (GS(id->name) == ID_CF) {
- for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
- ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);
-
- if (md) {
- MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
-
- if (mcmd->cache_file && (&mcmd->cache_file->id == id)) {
- ob->recalc |= OB_RECALC_DATA;
- continue;
- }
- }
-
- for (bConstraint *con = ob->constraints.first; con; con = con->next) {
- if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) {
- continue;
- }
-
- bTransformCacheConstraint *data = con->data;
-
- if (data->cache_file && (&data->cache_file->id == id)) {
- ob->recalc |= OB_RECALC_DATA;
- break;
- }
- }
- }
- }
-}
-
-void DAG_id_tag_update(ID *id, short flag)
-{
- DAG_id_tag_update_ex(G.main, id, flag);
-}
-
-void DAG_id_type_tag(Main *bmain, short idtype)
-{
- if (idtype == ID_NT) {
- /* stupid workaround so parent datablocks of nested nodetree get looped
- * over when we loop over tagged datablock types */
- DAG_id_type_tag(bmain, ID_MA);
- DAG_id_type_tag(bmain, ID_TE);
- DAG_id_type_tag(bmain, ID_LA);
- DAG_id_type_tag(bmain, ID_WO);
- DAG_id_type_tag(bmain, ID_SCE);
- }
-
- bmain->id_tag_update[BKE_idcode_to_index(idtype)] = 1;
-}
-
-int DAG_id_type_tagged(Main *bmain, short idtype)
-{
- return bmain->id_tag_update[BKE_idcode_to_index(idtype)];
-}
-
-#if 0 // UNUSED
-/* recursively descends tree, each node only checked once */
-/* node is checked to be of type object */
-static int parent_check_node(DagNode *node, int curtime)
-{
- DagAdjList *itA;
-
- node->lasttime = curtime;
-
- if (node->color == DAG_GRAY)
- return DAG_GRAY;
-
- for (itA = node->child; itA; itA = itA->next) {
- if (itA->node->type == ID_OB) {
-
- if (itA->node->color == DAG_GRAY)
- return DAG_GRAY;
-
- /* descend if not done */
- if (itA->node->lasttime != curtime) {
- itA->node->color = parent_check_node(itA->node, curtime);
-
- if (itA->node->color == DAG_GRAY)
- return DAG_GRAY;
- }
- }
- }
-
- return DAG_WHITE;
-}
-#endif
-
-/* ******************* DAG FOR ARMATURE POSE ***************** */
-
-/* we assume its an armature with pose */
-void DAG_pose_sort(Object *ob)
-{
- bPose *pose = ob->pose;
- bPoseChannel *pchan;
- bConstraint *con;
- DagNode *node;
- DagNode *node2, *node3;
- DagNode *rootnode;
- DagForest *dag;
- DagNodeQueue *nqueue;
- DagAdjList *itA;
- ListBase tempbase;
- int skip = 0;
-
- dag = dag_init();
- dag->ugly_hack_sorry = false; /* no ID structs */
-
- rootnode = dag_add_node(dag, NULL); /* node->ob becomes NULL */
-
- /* we add the hierarchy and the constraints */
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- int addtoroot = 1;
-
- node = dag_get_node(dag, pchan);
-
- if (pchan->parent) {
- node2 = dag_get_node(dag, pchan->parent);
- dag_add_relation(dag, node2, node, 0, "Parent Relation");
- addtoroot = 0;
- }
- for (con = pchan->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar == ob && ct->subtarget[0]) {
- bPoseChannel *target = BKE_pose_channel_find_name(ob->pose, ct->subtarget);
- if (target) {
- node2 = dag_get_node(dag, target);
- dag_add_relation(dag, node2, node, 0, "Pose Constraint");
-
- if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
- bKinematicConstraint *data = (bKinematicConstraint *)con->data;
- bPoseChannel *parchan;
- int segcount = 0;
-
- /* exclude tip from chain? */
- if (!(data->flag & CONSTRAINT_IK_TIP))
- parchan = pchan->parent;
- else
- parchan = pchan;
-
- /* Walk to the chain's root */
- while (parchan) {
- node3 = dag_get_node(dag, parchan);
- dag_add_relation(dag, node2, node3, 0, "IK Constraint");
-
- segcount++;
- if (segcount == data->rootbone || segcount > 255) break; /* 255 is weak */
- parchan = parchan->parent;
- }
- }
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 1);
- }
- }
- if (addtoroot == 1) {
- dag_add_relation(dag, rootnode, node, 0, "Root Bone Relation");
- }
- }
-
- dag_check_cycle(dag);
-
- /* now we try to sort... */
- BLI_listbase_clear(&tempbase);
-
- nqueue = queue_create(DAGQUEUEALLOC);
-
- /* tag nodes unchecked */
- for (node = dag->DagNode.first; node; node = node->next)
- node->color = DAG_WHITE;
-
- rootnode->color = DAG_GRAY;
- push_stack(nqueue, rootnode);
-
- while (nqueue->count) {
-
- skip = 0;
- node = get_top_node_queue(nqueue);
-
- itA = node->child;
- while (itA != NULL) {
- if (itA->node->color == DAG_WHITE) {
- itA->node->color = DAG_GRAY;
- push_stack(nqueue, itA->node);
- skip = 1;
- break;
- }
- itA = itA->next;
- }
-
- if (!skip) {
- if (node) {
- node = pop_queue(nqueue);
- if (node->ob == NULL) /* we are done */
- break;
- node->color = DAG_BLACK;
-
- /* put node in new list */
- BLI_remlink(&pose->chanbase, node->ob);
- BLI_addhead(&tempbase, node->ob);
- }
- }
- }
-
- /* temporal correction for circular dependencies */
- while (pose->chanbase.first) {
- pchan = pose->chanbase.first;
- BLI_remlink(&pose->chanbase, pchan);
- BLI_addhead(&tempbase, pchan);
-
- printf("cyclic %s\n", pchan->name);
- }
-
- pose->chanbase = tempbase;
- queue_delete(nqueue);
-
-// printf("\nordered\n");
-// for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
-// printf(" %s\n", pchan->name);
-// }
-
- free_forest(dag);
- MEM_freeN(dag);
-}
-
-/* ************************ DAG FOR THREADED UPDATE ********************* */
-
-/* Initialize run-time data in the graph needed for traversing it
- * from multiple threads and start threaded tree traversal by adding
- * the root node to the queue.
- *
- * This will mark DAG nodes as object/non-object and will calculate
- * num_pending_parents of nodes (which is how many non-updated parents node
- * have, which helps a lot checking whether node could be scheduled
- * already or not).
- */
-void DAG_threaded_update_begin(Scene *scene,
- void (*func)(void *node, void *user_data),
- void *user_data)
-{
- DagNode *node;
-
- /* We reset num_pending_parents to zero first and tag node as not scheduled yet... */
- for (node = scene->theDag->DagNode.first; node; node = node->next) {
- node->num_pending_parents = 0;
- node->scheduled = false;
- }
-
- /* ... and then iterate over all the nodes and
- * increase num_pending_parents for node childs.
- */
- for (node = scene->theDag->DagNode.first; node; node = node->next) {
- DagAdjList *itA;
-
- for (itA = node->child; itA; itA = itA->next) {
- if (itA->node != node) {
- itA->node->num_pending_parents++;
- }
- }
- }
-
- /* Add root nodes to the queue. */
- BLI_spin_lock(&threaded_update_lock);
- for (node = scene->theDag->DagNode.first; node; node = node->next) {
- if (node->num_pending_parents == 0) {
- node->scheduled = true;
- func(node, user_data);
- }
- }
- BLI_spin_unlock(&threaded_update_lock);
-}
-
-/* This function is called when handling node is done.
- *
- * This function updates num_pending_parents for all childs and
- * schedules them if they're ready.
- */
-void DAG_threaded_update_handle_node_updated(void *node_v,
- void (*func)(void *node, void *user_data),
- void *user_data)
-{
- DagNode *node = node_v;
- DagAdjList *itA;
-
- for (itA = node->child; itA; itA = itA->next) {
- DagNode *child_node = itA->node;
- if (child_node != node) {
- atomic_sub_uint32(&child_node->num_pending_parents, 1);
-
- if (child_node->num_pending_parents == 0) {
- bool need_schedule;
-
- BLI_spin_lock(&threaded_update_lock);
- need_schedule = child_node->scheduled == false;
- child_node->scheduled = true;
- BLI_spin_unlock(&threaded_update_lock);
-
- if (need_schedule) {
- func(child_node, user_data);
- }
- }
- }
- }
-}
-
-/* ************************ DAG DEBUGGING ********************* */
-
-void DAG_print_dependencies(Main *bmain, Scene *scene, Object *ob)
-{
- /* utility for debugging dependencies */
- dag_print_dependencies = 1;
-
- if (ob && (ob->mode & OB_MODE_POSE)) {
- printf("\nDEPENDENCY RELATIONS for %s\n\n", ob->id.name + 2);
- DAG_pose_sort(ob);
- }
- else {
- printf("\nDEPENDENCY RELATIONS for %s\n\n", scene->id.name + 2);
- DAG_scene_relations_rebuild(bmain, scene);
- }
-
- dag_print_dependencies = 0;
-}
-
-/* ************************ DAG querying ********************* */
-
-/* Will return Object ID if node represents Object,
- * and will return NULL otherwise.
- */
-Object *DAG_get_node_object(void *node_v)
-{
- DagNode *node = node_v;
-
- if (node->type == ID_OB) {
- return node->ob;
- }
-
- return NULL;
-}
-
-/* Returns node name, used for debug output only, atm. */
-const char *DAG_get_node_name(Scene *scene, void *node_v)
-{
- DagNode *node = node_v;
-
- return dag_node_name(scene->theDag, node);
-}
-
-short DAG_get_eval_flags_for_object(Scene *scene, void *object)
-{
- DagNode *node;
-
- if (!DEG_depsgraph_use_legacy()) {
- return DEG_get_eval_flags_for_id(scene->depsgraph, (ID *)object);
- }
-
- if (scene->theDag == NULL) {
- /* Happens when converting objects to mesh from a python script
- * after modifying scene graph.
- *
- * Currently harmless because it's only called for temporary
- * objects which are out of the DAG anyway.
- */
- return 0;
- }
-
- node = dag_find_node(scene->theDag, object);
-
- if (node) {
- return node->eval_flags;
- }
- else {
- /* Happens when external render engine exports temporary objects
- * which are not in the DAG.
- */
-
- /* TODO(sergey): Doublecheck objects with Curve Deform exports all fine. */
-
- /* TODO(sergey): Weak but currently we can't really access proper DAG from
- * the modifiers stack. This is because in most cases modifier is to use
- * the foreground scene, but to access evaluation flags we need to know
- * active background scene, which we don't know.
- */
- if (scene->set) {
- return DAG_get_eval_flags_for_object(scene->set, object);
- }
- return 0;
- }
-}
-
-bool DAG_is_acyclic(Scene *scene)
-{
- return scene->theDag->is_acyclic;
-}
-
-#else
-
-/* *********************************************************************
- * Stubs to avoid linking issues and make sure legacy crap is not used *
- * *********************************************************************
- */
-
-DagNodeQueue *queue_create(int UNUSED(slots))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
- return NULL;
-}
-
-void queue_raz(DagNodeQueue *UNUSED(queue))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
-}
-
-void queue_delete(DagNodeQueue *UNUSED(queue))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
-}
-
-void push_queue(DagNodeQueue *UNUSED(queue), DagNode *UNUSED(node))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
-}
-
-void push_stack(DagNodeQueue *UNUSED(queue), DagNode *UNUSED(node))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
-}
-
-DagNode *pop_queue(DagNodeQueue *UNUSED(queue))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
- return NULL;
-}
-
-DagNode *get_top_node_queue(DagNodeQueue *UNUSED(queue))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
- return NULL;
-}
-
-DagForest *dag_init(void)
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
- return NULL;
-}
-
-DagForest *build_dag(Main *UNUSED(bmain),
- Scene *UNUSED(sce),
- short UNUSED(mask))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
- return NULL;
-}
-
-void free_forest(DagForest *UNUSED(Dag))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
-}
-
-DagNode *dag_find_node(DagForest *UNUSED(forest), void *UNUSED(fob))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
- return NULL;
-}
-
-DagNode *dag_add_node(DagForest *UNUSED(forest), void *UNUSED(fob))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
- return NULL;
-}
-
-DagNode *dag_get_node(DagForest *UNUSED(forest), void *UNUSED(fob))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
- return NULL;
-}
-
-DagNode *dag_get_sub_node(DagForest *UNUSED(forest), void *UNUSED(fob))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
- return NULL;
-}
-
-void dag_add_relation(DagForest *UNUSED(forest),
- DagNode *UNUSED(fob1),
- DagNode *UNUSED(fob2),
- short UNUSED(rel),
- const char *UNUSED(name))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
-}
-
-/* debug test functions */
-
-void graph_print_queue(DagNodeQueue *UNUSED(nqueue))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
-}
-
-void graph_print_queue_dist(DagNodeQueue *UNUSED(nqueue))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
-}
-
-void graph_print_adj_list(DagForest *UNUSED(dag))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
-}
-
-void DAG_scene_flush_update(Main *UNUSED(bmain),
- Scene *UNUSED(sce),
- unsigned int UNUSED(lay),
- const short UNUSED(time))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
-}
-
-void DAG_scene_update_flags(Main *UNUSED(bmain),
- Scene *UNUSED(scene),
- unsigned int UNUSED(lay),
- const bool UNUSED(do_time),
- const bool UNUSED(do_invisible_flush))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
-}
-
-/* ******************* DAG FOR ARMATURE POSE ***************** */
-
-void DAG_pose_sort(Object *UNUSED(ob))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
-}
-
-/* ************************ DAG FOR THREADED UPDATE ********************* */
-
-void DAG_threaded_update_begin(Scene *UNUSED(scene),
- void (*func)(void *node, void *user_data),
- void *UNUSED(user_data))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
- (void)func;
-}
-
-void DAG_threaded_update_handle_node_updated(void *UNUSED(node_v),
- void (*func)(void *node, void *user_data),
- void *UNUSED(user_data))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
- (void)func;
-}
-
-/* ************************ DAG querying ********************* */
-
-Object *DAG_get_node_object(void *UNUSED(node_v))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
- return NULL;
-}
-
-const char *DAG_get_node_name(Scene *UNUSED(scene), void *UNUSED(node_v))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
- return "INVALID";
-}
-
-bool DAG_is_acyclic(Scene *UNUSED(scene))
-{
- BLI_assert(!"Should not be used with new dependnecy graph");
- return false;
-}
-
-/* ************************************
- * This functions are to be supported *
- * ************************************
- */
-
-void DAG_init(void)
-{
- DEG_register_node_types();
-}
-
-void DAG_exit(void)
-{
- DEG_free_node_types();
-}
-
-/* ************************ API *********************** */
-
-void DAG_editors_update_cb(DEG_EditorUpdateIDCb id_func,
- DEG_EditorUpdateSceneCb scene_func,
- DEG_EditorUpdateScenePreCb scene_func_pre)
-{
- DEG_editors_set_update_cb(id_func, scene_func, scene_func_pre);
-}
-
-void DAG_editors_update_pre(Main *bmain, Scene *scene, bool time)
-{
- DEG_editors_update_pre(bmain, scene, time);
-}
-
-/* Tag all relations for update. */
-void DAG_relations_tag_update(Main *bmain)
-{
- DEG_relations_tag_update(bmain);
-}
-
-/* Rebuild dependency graph only for a given scene. */
-void DAG_scene_relations_rebuild(Main *bmain, Scene *scene)
-{
- DEG_scene_relations_rebuild(bmain, scene);
-}
-
-/* Create dependency graph if it was cleared or didn't exist yet. */
-void DAG_scene_relations_update(Main *bmain, Scene *scene)
-{
- DEG_scene_relations_update(bmain, scene);
-}
-
-void DAG_scene_relations_validate(Main *bmain, Scene *scene)
-{
- DEG_debug_scene_relations_validate(bmain, scene);
-}
-
-void DAG_scene_free(Scene *scene)
-{
- DEG_scene_graph_free(scene);
-}
-
-void DAG_on_visible_update(Main *bmain, const bool do_time)
-{
- DEG_on_visible_update(bmain, do_time);
-}
-
-void DAG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
-{
- DEG_ids_check_recalc(bmain, scene, time);
-}
-
-void DAG_id_tag_update(ID *id, short flag)
-{
- DEG_id_tag_update_ex(G.main, id, flag);
-}
-
-void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag)
-{
- DEG_id_tag_update_ex(bmain, id, flag);
-}
-
-void DAG_id_type_tag(Main *bmain, short idtype)
-{
- DEG_id_type_tag(bmain, idtype);
-}
-
-int DAG_id_type_tagged(Main *bmain, short idtype)
-{
- return DEG_id_type_tagged(bmain, idtype);
-}
-
-void DAG_ids_clear_recalc(Main *bmain)
-{
- DEG_ids_clear_recalc(bmain);
-}
-
-short DAG_get_eval_flags_for_object(Scene *scene, void *object)
-{
- return DEG_get_eval_flags_for_id(scene->depsgraph, (ID *)object);
-}
-
-void DAG_ids_flush_tagged(Main *bmain)
-{
- DEG_ids_flush_tagged(bmain);
-}
-
-/* ************************ DAG DEBUGGING ********************* */
-
-void DAG_print_dependencies(Main *UNUSED(bmain),
- Scene *scene,
- Object *UNUSED(ob))
-{
- DEG_debug_graphviz(scene->depsgraph, stdout, "Depsgraph", false);
-}
-
-#endif
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index 49db75a0474..25f50056c42 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -48,7 +48,6 @@
#include "BLI_utildefines.h"
#include "BKE_global.h"
-#include "BKE_depsgraph.h"
#include "BKE_displist.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_object.h"
@@ -63,6 +62,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)
@@ -167,10 +169,12 @@ void BKE_displist_normals_add(ListBase *lb)
if (dl->nors == NULL) {
dl->nors = MEM_callocN(sizeof(float) * 3, "dlnors");
- if (dl->verts[2] < 0.0f)
+ if (dl->flag & DL_BACK_CURVE) {
dl->nors[2] = -1.0f;
- else
+ }
+ else {
dl->nors[2] = 1.0f;
+ }
}
}
else if (dl->type == DL_SURF) {
@@ -469,6 +473,7 @@ void BKE_displist_fill(ListBase *dispbase, ListBase *to, const float normal_proj
sf_arena = BLI_memarena_new(BLI_SCANFILL_ARENA_SIZE, __func__);
while (cont) {
+ int dl_flag_accum = 0;
cont = 0;
totvert = 0;
nextcol = 0;
@@ -514,6 +519,7 @@ void BKE_displist_fill(ListBase *dispbase, ListBase *to, const float normal_proj
nextcol = 1;
}
}
+ dl_flag_accum |= dl->flag;
}
dl = dl->next;
}
@@ -526,6 +532,7 @@ void BKE_displist_fill(ListBase *dispbase, ListBase *to, const float normal_proj
if (tot) {
dlnew = MEM_callocN(sizeof(DispList), "filldisplist");
dlnew->type = DL_INDEX3;
+ dlnew->flag = (dl_flag_accum & (DL_BACK_CURVE | DL_FRONT_CURVE));
dlnew->col = colnr;
dlnew->nr = totvert;
dlnew->parts = tot;
@@ -603,6 +610,7 @@ static void bevels_to_filledpoly(Curve *cu, ListBase *dispbase)
dlnew->nr = dl->parts;
dlnew->parts = 1;
dlnew->type = DL_POLY;
+ dlnew->flag = DL_BACK_CURVE;
dlnew->col = dl->col;
dlnew->charidx = dl->charidx;
@@ -623,6 +631,7 @@ static void bevels_to_filledpoly(Curve *cu, ListBase *dispbase)
dlnew->nr = dl->parts;
dlnew->parts = 1;
dlnew->type = DL_POLY;
+ dlnew->flag = DL_FRONT_CURVE;
dlnew->col = dl->col;
dlnew->charidx = dl->charidx;
@@ -819,7 +828,7 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb,
if (editmode)
required_mode |= eModifierMode_Editmode;
- if (cu->editnurb == NULL) {
+ if (!editmode) {
keyVerts = BKE_key_evaluate_object(ob, &numVerts);
if (keyVerts) {
@@ -1731,8 +1740,9 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
}
if (!for_orco) {
+ /* TODO(sergey): How do we get depsgraph here? */
if ((cu->flag & CU_PATH) ||
- DAG_get_eval_flags_for_object(scene, ob) & DAG_EVAL_NEED_CURVE_PATH)
+ DEG_get_eval_flags_for_id(scene->depsgraph_legacy, &ob->id) & DAG_EVAL_NEED_CURVE_PATH)
{
calc_curvepath(ob, &nubase);
}
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index d35de6fc5d3..fb5ef403218 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -32,6 +32,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_kdtree.h"
+#include "BLI_string_utils.h"
#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@@ -101,6 +102,10 @@ static const float gaussianTotal = 3.309425f;
static int neighX[8] = {1, 1, 0, -1, -1, -1, 0, 1};
static int neighY[8] = {0, 1, 1, 1, 0, -1, -1, -1};
+/* Neighbor x/y list that prioritizes grid directions over diagonals */
+static int neighStraightX[8] = {1, 0, -1, 0, 1, -1, -1, 1};
+static int neighStraightY[8] = {0, 1, 0, -1, 1, 1, -1, -1};
+
/* subframe_updateObject() flags */
#define SUBFRAME_RECURSION 5
/* surface_getBrushFlags() return vals */
@@ -211,6 +216,7 @@ typedef struct ImgSeqFormatData {
/* adjacency data flags */
#define ADJ_ON_MESH_EDGE (1 << 0)
+#define ADJ_BORDER_PIXEL (1 << 1)
typedef struct PaintAdjData {
int *n_target; /* array of neighboring point indexes, for single sample use (n_index + neigh_num) */
@@ -218,6 +224,8 @@ typedef struct PaintAdjData {
int *n_num; /* num of neighs for each point */
int *flags; /* vertex adjacency flags */
int total_targets; /* size of n_target */
+ int *border; /* indices of border pixels (only for texture paint) */
+ int total_border; /* size of border */
} PaintAdjData;
/***************************** General Utils ******************************/
@@ -478,7 +486,7 @@ 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, const SceneLayer *sl)
{
Base *base = NULL;
GroupObject *go = NULL;
@@ -490,7 +498,7 @@ static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scen
if (surface->brush_group)
go = surface->brush_group->gobject.first;
else
- base = scene->base.first;
+ base = FIRSTBASE_NEW;
while (base || go) {
brushObj = NULL;
@@ -818,6 +826,8 @@ static void dynamicPaint_freeAdjData(PaintSurfaceData *data)
MEM_freeN(data->adj_data->n_target);
if (data->adj_data->flags)
MEM_freeN(data->adj_data->flags);
+ if (data->adj_data->border)
+ MEM_freeN(data->adj_data->border);
MEM_freeN(data->adj_data);
data->adj_data = NULL;
}
@@ -1294,6 +1304,8 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const b
ad->n_target = MEM_callocN(sizeof(int) * neigh_points, "Surface Adj Targets");
ad->flags = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Flags");
ad->total_targets = neigh_points;
+ ad->border = NULL;
+ ad->total_border = 0;
/* in case of allocation error, free memory */
if (!ad->n_index || !ad->n_num || !ad->n_target || !temp_data) {
@@ -1885,8 +1897,8 @@ static DerivedMesh *dynamicPaint_Modifier_apply(
/* apply weights into a vertex group, if doesnt exists add a new layer */
if (defgrp_index != -1 && !dvert && (surface->output_name[0] != '\0')) {
- dvert = CustomData_add_layer_named(&result->vertData, CD_MDEFORMVERT, CD_CALLOC,
- NULL, sData->total_points, surface->output_name);
+ dvert = CustomData_add_layer(&result->vertData, CD_MDEFORMVERT, CD_CALLOC,
+ NULL, sData->total_points);
}
if (defgrp_index != -1 && dvert) {
int i;
@@ -1961,7 +1973,7 @@ static void canvas_copyDerivedMesh(DynamicPaintCanvasSettings *canvas, DerivedMe
/*
* Updates derived mesh copy and processes dynamic paint step / caches.
*/
-static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm)
+static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene, SceneLayer *sl, Object *ob, DerivedMesh *dm)
{
if (pmd->canvas) {
DynamicPaintCanvasSettings *canvas = pmd->canvas;
@@ -2015,14 +2027,16 @@ static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene
}
/* try to read from cache */
- if (BKE_ptcache_read(&pid, (float)scene->r.cfra)) {
+ bool can_simulate = ((int)scene->r.cfra == current_frame) && !(cache->flag & PTCACHE_BAKED);
+
+ if (BKE_ptcache_read(&pid, (float)scene->r.cfra, can_simulate)) {
BKE_ptcache_validate(cache, (int)scene->r.cfra);
}
/* if read failed and we're on surface range do recalculate */
- else if ((int)scene->r.cfra == current_frame && !(cache->flag & PTCACHE_BAKED)) {
+ else if (can_simulate) {
/* calculate surface frame */
canvas->flags |= MOD_DPAINT_BAKING;
- dynamicPaint_calculateFrame(surface, scene, ob, current_frame);
+ dynamicPaint_calculateFrame(surface, scene, sl, ob, current_frame);
canvas->flags &= ~MOD_DPAINT_BAKING;
/* restore canvas derivedmesh if required */
@@ -2041,7 +2055,7 @@ static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene
}
/* Modifier call. Processes dynamic paint modifier step. */
-DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm)
+DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scene, SceneLayer *sl, Object *ob, DerivedMesh *dm)
{
if (pmd->canvas) {
DerivedMesh *ret;
@@ -2050,7 +2064,7 @@ DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scen
DM_ensure_looptri(dm);
/* Update canvas data for a new frame */
- dynamicPaint_frameUpdate(pmd, scene, ob, dm);
+ dynamicPaint_frameUpdate(pmd, scene, sl, ob, dm);
/* Return output mesh */
ret = dynamicPaint_Modifier_apply(pmd, ob, dm);
@@ -2062,7 +2076,7 @@ DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scen
DM_ensure_looptri(dm);
/* Update canvas data for a new frame */
- dynamicPaint_frameUpdate(pmd, scene, ob, dm);
+ dynamicPaint_frameUpdate(pmd, scene, sl, ob, dm);
/* Return output mesh */
return dynamicPaint_Modifier_apply(pmd, ob, dm);
@@ -2231,9 +2245,12 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const in
point[0] = ((float)tx + 0.5f) / w;
point[1] = ((float)ty + 0.5f) / h;
- /* search through defined area for neighbor */
- for (int u = u_min; u <= u_max; u++) {
- for (int v = v_min; v <= v_max; v++) {
+ /* search through defined area for neighbor, checking grid directions first */
+ for (int ni = 0; ni < 8; ni++) {
+ int u = neighStraightX[ni];
+ int v = neighStraightY[ni];
+
+ if (u >= u_min && u <= u_max && v >= v_min && v <= v_max) {
/* if not this pixel itself */
if (u != 0 || v != 0) {
const int ind = (tx + u) + w * (ty + v);
@@ -2255,7 +2272,7 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const in
* to non--1 *before* its tri_index is set (i.e. that it cannot be used a neighbour).
*/
tPoint->neighbour_pixel = ind - 1;
- atomic_add_uint32(&tPoint->neighbour_pixel, 1);
+ atomic_add_and_fetch_uint32(&tPoint->neighbour_pixel, 1);
tPoint->tri_index = i;
/* Now calculate pixel data for this pixel as it was on polygon surface */
@@ -2271,7 +2288,6 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const in
tPoint->v2 = mloop[mlooptri[i].tri[1]].v;
tPoint->v3 = mloop[mlooptri[i].tri[2]].v;
- u = u_max + 1; /* make sure we exit outer loop as well */
break;
}
}
@@ -2281,12 +2297,42 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const in
/* Increase the final number of active surface points if relevant. */
if (tPoint->tri_index != -1)
- atomic_add_uint32(active_points, 1);
+ atomic_add_and_fetch_uint32(active_points, 1);
}
}
#undef JITTER_SAMPLES
+static float dist_squared_to_looptri_uv_edges(const MLoopTri *mlooptri, const MLoopUV *mloopuv, int tri_index, const float point[2])
+{
+ float min_distance = FLT_MAX;
+
+ for (int i = 0; i < 3; i++) {
+ const float dist_squared = dist_squared_to_line_segment_v2(
+ point,
+ mloopuv[mlooptri[tri_index].tri[(i + 0)]].uv,
+ mloopuv[mlooptri[tri_index].tri[(i + 1) % 3]].uv
+ );
+
+ if (dist_squared < min_distance)
+ min_distance = dist_squared;
+ }
+
+ return min_distance;
+}
+
+typedef struct DynamicPaintFindIslandBorderData {
+ const MeshElemMap *vert_to_looptri_map;
+ int w, h, px, py;
+
+ int best_index;
+ float best_weight;
+} DynamicPaintFindIslandBorderData;
+
+static void dynamic_paint_find_island_border(
+ const DynamicPaintCreateUVSurfaceData *data, DynamicPaintFindIslandBorderData *bdata,
+ int tri_index, const float pixel[2], int in_edge, int depth);
+
/* Tries to find the neighboring pixel in given (uv space) direction.
* Result is used by effect system to move paint on the surface.
*
@@ -2337,159 +2383,286 @@ static int dynamic_paint_find_neighbour_pixel(
* TODO: Implement something more accurate / optimized?
*/
{
- const MLoop *mloop = data->mloop;
- const MLoopTri *mlooptri = data->mlooptri;
- const MLoopUV *mloopuv = data->mloopuv;
-
- /* Get closest edge to that subpixel on UV map */
+ DynamicPaintFindIslandBorderData bdata = {
+ .vert_to_looptri_map = vert_to_looptri_map,
+ .w = w, .h = h, .px = px, .py = py,
+ .best_index = NOT_FOUND, .best_weight = 1.0f
+ };
float pixel[2];
- /* distances only used for comparison */
- float dist_squared, t_dist_squared;
-
- int edge1_index, edge2_index;
- int e1_index, e2_index, target_tri;
- float closest_point[2], lambda, dir_vec[2];
- int target_uv1 = 0, target_uv2 = 0, final_pixel[2], final_index;
-
- const float *s_uv1, *s_uv2, *t_uv1, *t_uv2;
pixel[0] = ((float)(px + neighX[n_index]) + 0.5f) / (float)w;
pixel[1] = ((float)(py + neighY[n_index]) + 0.5f) / (float)h;
- /*
- * Find closest edge to that pixel
- */
+ /* Do a small recursive search for the best island edge. */
+ dynamic_paint_find_island_border(data, &bdata, cPoint->tri_index, pixel, -1, 5);
- /* Dist to first edge */
- e1_index = cPoint->v1;
- e2_index = cPoint->v2;
- edge1_index = 0;
- edge2_index = 1;
- dist_squared = dist_squared_to_line_segment_v2(
- pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv);
-
- /* Dist to second edge */
- t_dist_squared = dist_squared_to_line_segment_v2(
- pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv);
- if (t_dist_squared < dist_squared) {
- e1_index = cPoint->v2;
- e2_index = cPoint->v3;
- edge1_index = 1;
- edge2_index = 2;
- dist_squared = t_dist_squared;
- }
-
- /* Dist to third edge */
- t_dist_squared = dist_squared_to_line_segment_v2(
- pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv);
- if (t_dist_squared < dist_squared) {
- e1_index = cPoint->v3;
- e2_index = cPoint->v1;
- edge1_index = 2;
- edge2_index = 0;
- dist_squared = t_dist_squared;
- }
+ return bdata.best_index;
+ }
+}
- /*
- * Now find another face that is linked to that edge
- */
- target_tri = -1;
+static void dynamic_paint_find_island_border(
+ const DynamicPaintCreateUVSurfaceData *data, DynamicPaintFindIslandBorderData *bdata,
+ int tri_index, const float pixel[2], int in_edge, int depth)
+{
+ const MLoop *mloop = data->mloop;
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
+
+ const unsigned int *loop_idx = mlooptri[tri_index].tri;
+
+ /* Enumerate all edges of the triangle, rotating the vertex list accordingly. */
+ for (int edge_idx = 0; edge_idx < 3; edge_idx++) {
+ /* but not the edge we have just recursed through */
+ if (edge_idx == in_edge)
+ continue;
+
+ float uv0[2], uv1[2], uv2[2];
+
+ copy_v2_v2(uv0, mloopuv[loop_idx[(edge_idx + 0)]].uv);
+ copy_v2_v2(uv1, mloopuv[loop_idx[(edge_idx + 1) % 3]].uv);
+ copy_v2_v2(uv2, mloopuv[loop_idx[(edge_idx + 2) % 3]].uv);
+
+ /* Verify the target point is on the opposite side of the edge from the third triangle
+ * vertex, to ensure that we always move closer to the goal point. */
+ const float sidep = line_point_side_v2(uv0, uv1, pixel);
+ const float side2 = line_point_side_v2(uv0, uv1, uv2);
+
+ if (side2 == 0.0f)
+ continue;
+
+ /* Hack: allow all edges of the original triangle */
+ const bool correct_side = (in_edge == -1) || (sidep < 0 && side2 > 0) || (sidep > 0 && side2 < 0);
+
+ /* Allow exactly on edge for the non-recursive case */
+ if (!correct_side && sidep != 0.0f)
+ continue;
+
+ /* Now find another face that is linked to that edge. */
+ const int vert0 = mloop[loop_idx[(edge_idx + 0)]].v;
+ const int vert1 = mloop[loop_idx[(edge_idx + 1) % 3]].v;
/* Use a pre-computed vert-to-looptri mapping, speeds up things a lot compared to looping over all loopti. */
- for (int i = 0; i < vert_to_looptri_map[e1_index].count; i++) {
- const int lt_index = vert_to_looptri_map[e1_index].indices[i];
- const int v0 = mloop[mlooptri[lt_index].tri[0]].v;
- const int v1 = mloop[mlooptri[lt_index].tri[1]].v;
- const int v2 = mloop[mlooptri[lt_index].tri[2]].v;
+ const MeshElemMap *map = &bdata->vert_to_looptri_map[vert0];
- BLI_assert(ELEM(e1_index, v0, v1, v2));
+ bool found_other = false;
+ int target_tri = -1;
+ int target_edge = -1;
- if (ELEM(e2_index, v0, v1, v2)) {
- if (lt_index == cPoint->tri_index)
- continue;
+ float ouv0[2], ouv1[2];
- target_tri = lt_index;
+ for (int i = 0; i < map->count && !found_other; i++) {
+ const int lt_index = map->indices[i];
- /* Get edge UV index */
- target_uv1 = (e1_index == v0) ? 0 : ((e1_index == v1) ? 1 : 2);
- target_uv2 = (e2_index == v0) ? 0 : ((e2_index == v1) ? 1 : 2);
- break;
+ if (lt_index == tri_index)
+ continue;
+
+ const unsigned int *other_loop_idx = mlooptri[lt_index].tri;
+
+ /* Check edges for match, looping in the same order as the outer loop. */
+ for (int j = 0; j < 3; j++) {
+ const int overt0 = mloop[other_loop_idx[(j + 0)]].v;
+ const int overt1 = mloop[other_loop_idx[(j + 1) % 3]].v;
+
+ /* Allow for swapped vertex order */
+ if (overt0 == vert0 && overt1 == vert1) {
+ found_other = true;
+ copy_v2_v2(ouv0, mloopuv[other_loop_idx[(j + 0)]].uv);
+ copy_v2_v2(ouv1, mloopuv[other_loop_idx[(j + 1) % 3]].uv);
+ }
+ else if (overt0 == vert1 && overt1 == vert0) {
+ found_other = true;
+ copy_v2_v2(ouv1, mloopuv[other_loop_idx[(j + 0)]].uv);
+ copy_v2_v2(ouv0, mloopuv[other_loop_idx[(j + 1) % 3]].uv);
+ }
+
+ if (found_other) {
+ target_tri = lt_index;
+ target_edge = j;
+ break;
+ }
}
}
- /* If none found pixel is on mesh edge */
- if (target_tri == -1)
- return ON_MESH_EDGE;
+ if (!found_other) {
+ if (bdata->best_index < 0)
+ bdata->best_index = ON_MESH_EDGE;
- /*
- * If target face is connected in UV space as well, just use original index
- */
- s_uv1 = mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv;
- s_uv2 = mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv;
- t_uv1 = mloopuv[mlooptri[target_tri].tri[target_uv1]].uv;
- t_uv2 = mloopuv[mlooptri[target_tri].tri[target_uv2]].uv;
+ continue;
+ }
- //printf("connected UV : %f,%f & %f,%f - %f,%f & %f,%f\n", s_uv1[0], s_uv1[1], s_uv2[0], s_uv2[1], t_uv1[0], t_uv1[1], t_uv2[0], t_uv2[1]);
+ /* If this edge is connected in UV space too, recurse */
+ if (equals_v2v2(uv0, ouv0) && equals_v2v2(uv1, ouv1)) {
+ if (depth > 0 && correct_side) {
+ dynamic_paint_find_island_border(data, bdata, target_tri, pixel, target_edge, depth - 1);
+ }
- if (((s_uv1[0] == t_uv1[0] && s_uv1[1] == t_uv1[1]) &&
- (s_uv2[0] == t_uv2[0] && s_uv2[1] == t_uv2[1])) ||
- ((s_uv2[0] == t_uv1[0] && s_uv2[1] == t_uv1[1]) &&
- (s_uv1[0] == t_uv2[0] && s_uv1[1] == t_uv2[1])))
- {
- return ((px + neighX[n_index]) + w * (py + neighY[n_index]));
+ continue;
}
+ /* Otherwise try to map to the other side of the edge.
+ * First check if there already is a better solution. */
+ const float dist_squared = dist_squared_to_line_segment_v2(pixel, uv0, uv1);
+
+ if (bdata->best_index >= 0 && dist_squared >= bdata->best_weight)
+ continue;
+
/*
* Find a point that is relatively at same edge position
* on this other face UV
*/
- lambda = closest_to_line_v2(
- closest_point, pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv);
- CLAMP(lambda, 0.0f, 1.0f);
+ float closest_point[2], dir_vec[2], tgt_pixel[2];
- sub_v2_v2v2(
- dir_vec,
- mloopuv[mlooptri[target_tri].tri[target_uv2]].uv,
- mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
+ float lambda = closest_to_line_v2(closest_point, pixel, uv0, uv1);
+ CLAMP(lambda, 0.0f, 1.0f);
- mul_v2_fl(dir_vec, lambda);
+ sub_v2_v2v2(dir_vec, ouv1, ouv0);
+ madd_v2_v2v2fl(tgt_pixel, ouv0, dir_vec, lambda);
- copy_v2_v2(pixel, mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
- add_v2_v2(pixel, dir_vec);
- pixel[0] = (pixel[0] * (float)w) - 0.5f;
- pixel[1] = (pixel[1] * (float)h) - 0.5f;
+ int w = bdata->w, h = bdata->h, px = bdata->px, py = bdata->py;
- final_pixel[0] = (int)floorf(pixel[0]);
- final_pixel[1] = (int)floorf(pixel[1]);
+ int final_pixel[2] = { (int)floorf(tgt_pixel[0] * w), (int)floorf(tgt_pixel[1] * h) };
/* If current pixel uv is outside of texture */
- if (final_pixel[0] < 0 || final_pixel[0] >= w || final_pixel[1] < 0 || final_pixel[1] >= h)
- return OUT_OF_TEXTURE;
+ if (final_pixel[0] < 0 || final_pixel[0] >= w || final_pixel[1] < 0 || final_pixel[1] >= h) {
+ if (bdata->best_index == NOT_FOUND)
+ bdata->best_index = OUT_OF_TEXTURE;
- final_index = final_pixel[0] + w * final_pixel[1];
+ continue;
+ }
+
+ const PaintUVPoint *tempPoints = data->tempPoints;
+ int final_index = final_pixel[0] + w * final_pixel[1];
/* If we ended up to our origin point ( mesh has smaller than pixel sized faces) */
if (final_index == (px + w * py))
- return NOT_FOUND;
- /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
- if (tempPoints[final_index].tri_index != target_tri)
- return NOT_FOUND;
+ continue;
/* If final point is an "edge pixel", use it's "real" neighbor instead */
- if (tempPoints[final_index].neighbour_pixel != -1)
- final_index = cPoint->neighbour_pixel;
+ if (tempPoints[final_index].neighbour_pixel != -1) {
+ final_index = tempPoints[final_index].neighbour_pixel;
+
+ /* If we ended up to our origin point */
+ if (final_index == (px + w * py))
+ continue;
+ }
+
+ /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
+ if (tempPoints[final_index].tri_index != target_tri) {
+ /* Check if it's close enough to likely touch the intended triangle. Any triangle
+ * becomes thinner than a pixel at its vertices, so robustness requires some margin. */
+ const float final_pt[2] = { ((final_index % w) + 0.5f) / w, ((final_index / w) + 0.5f) / h };
+ const float threshold = SQUARE(0.7f) / (w * h);
+
+ if (dist_squared_to_looptri_uv_edges(mlooptri, mloopuv, tempPoints[final_index].tri_index, final_pt) > threshold)
+ continue;
+ }
+
+ bdata->best_index = final_index;
+ bdata->best_weight = dist_squared;
+ }
+}
+
+static bool dynamicPaint_pointHasNeighbor(PaintAdjData *ed, int index, int neighbor)
+{
+ const int idx = ed->n_index[index];
+
+ for (int i = 0; i < ed->n_num[index]; i++) {
+ if (ed->n_target[idx + i] == neighbor) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Makes the adjacency data symmetric, except for border pixels. I.e. if A is neighbor of B, B is neighbor of A. */
+static bool dynamicPaint_symmetrizeAdjData(PaintAdjData *ed, int active_points)
+{
+ int *new_n_index = MEM_callocN(sizeof(int) * active_points, "Surface Adj Index");
+ int *new_n_num = MEM_callocN(sizeof(int) * active_points, "Surface Adj Counts");
+
+ if (new_n_num && new_n_index) {
+ /* Count symmetrized neigbors */
+ int total_targets = 0;
+
+ for (int index = 0; index < active_points; index++) {
+ total_targets += ed->n_num[index];
+ new_n_num[index] = ed->n_num[index];
+ }
+
+ for (int index = 0; index < active_points; index++) {
+ if (ed->flags[index] & ADJ_BORDER_PIXEL) {
+ continue;
+ }
+
+ for (int i = 0, idx = ed->n_index[index]; i < ed->n_num[index]; i++) {
+ const int target = ed->n_target[idx + i];
+
+ assert(!(ed->flags[target] & ADJ_BORDER_PIXEL));
+
+ if (!dynamicPaint_pointHasNeighbor(ed, target, index)) {
+ new_n_num[target]++;
+ total_targets++;
+ }
+ }
+ }
+
+ /* Allocate a new target map */
+ int *new_n_target = MEM_callocN(sizeof(int) * total_targets, "Surface Adj Targets");
+
+ if (new_n_target) {
+ /* Copy existing neighbors to the new map */
+ int n_pos = 0;
+
+ for (int index = 0; index < active_points; index++) {
+ new_n_index[index] = n_pos;
+ memcpy(&new_n_target[n_pos], &ed->n_target[ed->n_index[index]], sizeof(int) * ed->n_num[index]);
+
+ /* Reset count to old, but advance position by new, leaving a gap to fill below. */
+ n_pos += new_n_num[index];
+ new_n_num[index] = ed->n_num[index];
+ }
+
+ assert(n_pos == total_targets);
+
+ /* Add symmetrized - this loop behavior must exactly match the count pass above */
+ for (int index = 0; index < active_points; index++) {
+ if (ed->flags[index] & ADJ_BORDER_PIXEL) {
+ continue;
+ }
+
+ for (int i = 0, idx = ed->n_index[index]; i < ed->n_num[index]; i++) {
+ const int target = ed->n_target[idx + i];
- return final_index;
+ if (!dynamicPaint_pointHasNeighbor(ed, target, index)) {
+ const int num = new_n_num[target]++;
+ new_n_target[new_n_index[target] + num] = index;
+ }
+ }
+ }
+
+ /* Swap maps */
+ MEM_freeN(ed->n_target);
+ ed->n_target = new_n_target;
+
+ MEM_freeN(ed->n_index);
+ ed->n_index = new_n_index;
+
+ MEM_freeN(ed->n_num);
+ ed->n_num = new_n_num;
+
+ ed->total_targets = total_targets;
+ return true;
+ }
}
+
+ if (new_n_index)
+ MEM_freeN(new_n_index);
+ if (new_n_num)
+ MEM_freeN(new_n_num);
+
+ return false;
}
int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, float *progress, short *do_update)
@@ -2640,6 +2813,8 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo
&vert_to_looptri_map, &vert_to_looptri_map_mem,
dm->getVertArray(dm), dm->getNumVerts(dm), mlooptri, tottri, mloop, dm->getNumLoops(dm));
+ int total_border = 0;
+
for (int ty = 0; ty < h; ty++) {
for (int tx = 0; tx < w; tx++) {
const int index = tx + w * ty;
@@ -2648,15 +2823,22 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo
ed->n_index[final_index[index]] = n_pos;
ed->n_num[final_index[index]] = 0;
+ if (tempPoints[index].neighbour_pixel != -1) {
+ ed->flags[final_index[index]] |= ADJ_BORDER_PIXEL;
+ total_border++;
+ }
+
for (int i = 0; i < 8; i++) {
/* Try to find a neighboring pixel in defined direction. If not found, -1 is returned */
const int n_target = dynamic_paint_find_neighbour_pixel(
&data, vert_to_looptri_map, w, h, tx, ty, i);
- if (n_target >= 0) {
- ed->n_target[n_pos] = final_index[n_target];
- ed->n_num[final_index[index]]++;
- n_pos++;
+ if (n_target >= 0 && n_target != index) {
+ if (!dynamicPaint_pointHasNeighbor(ed, final_index[index], final_index[n_target])) {
+ ed->n_target[n_pos] = final_index[n_target];
+ ed->n_num[final_index[index]]++;
+ n_pos++;
+ }
}
else if (n_target == ON_MESH_EDGE || n_target == OUT_OF_TEXTURE) {
ed->flags[final_index[index]] |= ADJ_ON_MESH_EDGE;
@@ -2668,6 +2850,57 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo
MEM_freeN(vert_to_looptri_map);
MEM_freeN(vert_to_looptri_map_mem);
+
+ /* Make neighbors symmetric */
+ if (!dynamicPaint_symmetrizeAdjData(ed, active_points)) {
+ error = true;
+ }
+
+ /* Create a list of border pixels */
+ ed->border = MEM_callocN(sizeof(int) * total_border, "Border Pixel Index");
+
+ if (ed->border) {
+ ed->total_border = total_border;
+
+ for (int i = 0, next = 0; i < active_points; i++) {
+ if (ed->flags[i] & ADJ_BORDER_PIXEL) {
+ ed->border[next++] = i;
+ }
+ }
+ }
+
+#if 0
+ /* -----------------------------------------------------------------
+ * For debug, write a dump of adjacency data to a file.
+ * -----------------------------------------------------------------*/
+ FILE *dump_file = fopen("dynpaint-adj-data.txt", "w");
+ int *tmp = MEM_callocN(sizeof(int) * active_points, "tmp");
+ for (int ty = 0; ty < h; ty++) {
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
+ if (tempPoints[index].tri_index != -1)
+ tmp[final_index[index]] = index;
+ }
+ }
+ for (int ty = 0; ty < h; ty++) {
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
+ const int fidx = final_index[index];
+
+ if (tempPoints[index].tri_index != -1) {
+ int nidx = tempPoints[index].neighbour_pixel;
+ fprintf(dump_file, "%d\t%d,%d\t%u\t%d,%d\t%d\t", fidx, tx, h-1-ty, tempPoints[index].tri_index, nidx<0?-1:(nidx%w), nidx<0?-1:h-1-(nidx/w), ed->flags[fidx]);
+ for (int i = 0; i < ed->n_num[fidx]; i++) {
+ int tgt = tmp[ed->n_target[ed->n_index[fidx]+i]];
+ fprintf(dump_file, "%s%d,%d", i?" ":"", tgt%w, h-1-tgt/w);
+ }
+ fprintf(dump_file, "\n");
+ }
+ }
+ }
+ MEM_freeN(tmp);
+ fclose(dump_file);
+#endif
}
}
@@ -3700,7 +3933,7 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(
/* velocity brush, only do on main sample */
if (brush->flags & MOD_DPAINT_USES_VELOCITY && ss == 0 && brushVelocity) {
- float weights[4];
+ float weights[3];
float brushPointVelocity[3];
float velocity[3];
@@ -3709,7 +3942,7 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(
const int v3 = mloop[mlooptri[hitTri].tri[2]].v;
/* calculate barycentric weights for hit point */
- interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, hitCoord);
+ interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, hitCoord);
/* simple check based on brush surface velocity,
* todo: perhaps implement something that handles volume movement as well */
@@ -4490,6 +4723,10 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus
for (step = 0; step < steps; step++) {
for (index = 0; index < sData->total_points; index++) {
int i;
+
+ if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
+ continue;
+
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
float smudge_str = bData->brush_velocity[index * 4 + 3];
@@ -4669,6 +4906,9 @@ static void dynamic_paint_effect_spread_cb(void *userdata, const int index)
const DynamicPaintSurface *surface = data->surface;
const PaintSurfaceData *sData = surface->data;
+ if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
+ return;
+
const int numOfNeighs = sData->adj_data->n_num[index];
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
@@ -4698,7 +4938,7 @@ static void dynamic_paint_effect_spread_cb(void *userdata, const int index)
CLAMP(w_factor, 0.0f, 1.0f);
/* mix new wetness and color */
- pPoint->wetness = (1.0f - w_factor) * pPoint->wetness + w_factor * pPoint_prev->wetness;
+ pPoint->wetness = pPoint->wetness + w_factor * (pPoint_prev->wetness - pPoint->wetness);
pPoint->e_color[3] = mixColors(pPoint->e_color, pPoint->e_color[3],
pPoint_prev->e_color, pPoint_prev->e_color[3], w_factor);
}
@@ -4711,6 +4951,9 @@ static void dynamic_paint_effect_shrink_cb(void *userdata, const int index)
const DynamicPaintSurface *surface = data->surface;
const PaintSurfaceData *sData = surface->data;
+ if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
+ return;
+
const int numOfNeighs = sData->adj_data->n_num[index];
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
@@ -4757,6 +5000,10 @@ static void dynamic_paint_effect_drip_cb(void *userdata, const int index)
const DynamicPaintSurface *surface = data->surface;
const PaintSurfaceData *sData = surface->data;
+
+ if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
+ return;
+
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
const PaintPoint *prevPoint = data->prevPoint;
@@ -4777,6 +5024,8 @@ static void dynamic_paint_effect_drip_cb(void *userdata, const int index)
return;
CLAMP(w_factor, 0.0f, 1.0f);
+ float ppoint_wetness_diff = 0.0f;
+
/* get force affect points */
surface_determineForceTargetPoints(sData, index, &force[index * 4], closest_d, closest_id);
@@ -4798,9 +5047,9 @@ static void dynamic_paint_effect_drip_cb(void *userdata, const int index)
/* Sort of spinlock, but only for given ePoint.
* Since the odds a same ePoint is modified at the same time by several threads is very low, this is
* much more efficient than a global spin lock. */
- const unsigned int pointlock_idx = n_trgt / 8;
- const uint8_t pointlock_bitmask = 1 << (n_trgt & 7); /* 7 == 0b111 */
- while (atomic_fetch_and_or_uint8(&point_locks[pointlock_idx], pointlock_bitmask) & pointlock_bitmask);
+ const unsigned int epointlock_idx = n_trgt / 8;
+ const uint8_t epointlock_bitmask = 1 << (n_trgt & 7); /* 7 == 0b111 */
+ while (atomic_fetch_and_or_uint8(&point_locks[epointlock_idx], epointlock_bitmask) & epointlock_bitmask);
PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[n_trgt];
const float e_wet = ePoint->wetness;
@@ -4821,18 +5070,38 @@ static void dynamic_paint_effect_drip_cb(void *userdata, const int index)
CLAMP_MAX(ePoint->e_color[3], pPoint_prev->e_color[3]);
}
- /* decrease paint wetness on current point */
- pPoint->wetness -= (ePoint->wetness - e_wet);
- CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS);
+ /* Decrease paint wetness on current point
+ * (just store diff here, that way we can only lock current point once at the end to apply it). */
+ ppoint_wetness_diff += (ePoint->wetness - e_wet);
#ifndef NDEBUG
- uint8_t ret = atomic_fetch_and_and_uint8(&point_locks[pointlock_idx], ~pointlock_bitmask);
- BLI_assert(ret & pointlock_bitmask);
+ {
+ uint8_t ret = atomic_fetch_and_and_uint8(&point_locks[epointlock_idx], ~epointlock_bitmask);
+ BLI_assert(ret & epointlock_bitmask);
+ }
#else
- atomic_fetch_and_and_uint8(&point_locks[pointlock_idx], ~pointlock_bitmask);
+ atomic_fetch_and_and_uint8(&point_locks[epointlock_idx], ~epointlock_bitmask);
#endif
}
}
+
+ {
+ const unsigned int ppointlock_idx = index / 8;
+ const uint8_t ppointlock_bitmask = 1 << (index & 7); /* 7 == 0b111 */
+ while (atomic_fetch_and_or_uint8(&point_locks[ppointlock_idx], ppointlock_bitmask) & ppointlock_bitmask);
+
+ pPoint->wetness -= ppoint_wetness_diff;
+ CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS);
+
+#ifndef NDEBUG
+ {
+ uint8_t ret = atomic_fetch_and_and_uint8(&point_locks[ppointlock_idx], ~ppointlock_bitmask);
+ BLI_assert(ret & ppointlock_bitmask);
+ }
+#else
+ atomic_fetch_and_and_uint8(&point_locks[ppointlock_idx], ~ppointlock_bitmask);
+#endif
+ }
}
static void dynamicPaint_doEffectStep(
@@ -4903,6 +5172,80 @@ static void dynamicPaint_doEffectStep(
}
}
+static void dynamic_paint_border_cb(void *userdata, const int b_index)
+{
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+
+ const int index = sData->adj_data->border[b_index];
+
+ const int numOfNeighs = sData->adj_data->n_num[index];
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+
+ const int *n_index = sData->adj_data->n_index;
+ const int *n_target = sData->adj_data->n_target;
+
+ /* Average neighboring points. Intermediaries use premultiplied alpha. */
+ float mix_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ float mix_e_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ float mix_wetness = 0.0f;
+
+ for (int i = 0; i < numOfNeighs; i++) {
+ const int n_idx = n_index[index] + i;
+ const int target = n_target[n_idx];
+
+ PaintPoint *pPoint2 = &((PaintPoint *)sData->type_data)[target];
+
+ assert(!(sData->adj_data->flags[target] & ADJ_BORDER_PIXEL));
+
+ madd_v3_v3fl(mix_color, pPoint2->color, pPoint2->color[3]);
+ mix_color[3] += pPoint2->color[3];
+
+ madd_v3_v3fl(mix_e_color, pPoint2->e_color, pPoint2->e_color[3]);
+ mix_e_color[3] += pPoint2->e_color[3];
+
+ mix_wetness += pPoint2->wetness;
+ }
+
+ const float divisor = 1.0f / numOfNeighs;
+
+ if (mix_color[3]) {
+ pPoint->color[3] = mix_color[3] * divisor;
+ mul_v3_v3fl(pPoint->color, mix_color, divisor / pPoint->color[3]);
+ }
+ else {
+ pPoint->color[3] = 0.0f;
+ }
+
+ if (mix_e_color[3]) {
+ pPoint->e_color[3] = mix_e_color[3] * divisor;
+ mul_v3_v3fl(pPoint->e_color, mix_e_color, divisor / pPoint->e_color[3]);
+ }
+ else {
+ pPoint->e_color[3] = 0.0f;
+ }
+
+ pPoint->wetness = mix_wetness / numOfNeighs;
+}
+
+static void dynamicPaint_doBorderStep(DynamicPaintSurface *surface)
+{
+ PaintSurfaceData *sData = surface->data;
+
+ if (!sData->adj_data || !sData->adj_data->border)
+ return;
+
+ /* Don't use prevPoint, relying on the condition that neighbors are never border pixels. */
+ DynamicPaintEffectData data = {
+ .surface = surface
+ };
+
+ BLI_task_parallel_range(
+ 0, sData->adj_data->total_border, &data, dynamic_paint_border_cb, sData->adj_data->total_border > 1000);
+}
+
static void dynamic_paint_wave_step_cb(void *userdata, const int index)
{
const DynamicPaintEffectData *data = userdata;
@@ -5295,7 +5638,7 @@ static void dynamic_paint_generate_bake_data_cb(void *userdata, const int index)
}
}
-static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Scene *scene, Object *ob)
+static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const SceneLayer *sl, Object *ob)
{
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
@@ -5303,7 +5646,7 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
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, sl) & BRUSH_USES_VELOCITY));
const bool do_accel_data = (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) != 0;
int canvasNumOfVerts = dm->getNumVerts(dm);
@@ -5415,7 +5758,7 @@ 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(Scene *scene, Object *ob, DynamicPaintSurface *surface, float timescale, float subframe)
+static int dynamicPaint_doStep(Scene *scene, SceneLayer *sl, Object *ob, DynamicPaintSurface *surface, float timescale, float subframe)
{
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
@@ -5448,7 +5791,7 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
if (surface->brush_group)
go = surface->brush_group->gobject.first;
else
- base = scene->base.first;
+ base = FIRSTBASE_NEW;
while (base || go) {
brushObj = NULL;
@@ -5501,8 +5844,6 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
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))
@@ -5512,9 +5853,8 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
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) {
+ if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) {
dynamicPaint_paintSinglePoint(surface, brushObj->loc, brush, brushObj, &bMats, scene, timescale);
}
/* Mesh volume/proximity: */
@@ -5575,6 +5915,11 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
if (force)
MEM_freeN(force);
}
+
+ /* paint island border pixels */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ dynamicPaint_doBorderStep(surface);
+ }
}
return ret;
@@ -5583,7 +5928,7 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
/*
* Calculate a single frame and included subframes for surface
*/
-int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, Scene *scene, Object *cObject, int frame)
+int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, Scene *scene, SceneLayer *sl, Object *cObject, int frame)
{
float timescale = 1.0f;
@@ -5592,7 +5937,7 @@ int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, Scene *scene, Obje
dynamicPaint_applySurfaceDisplace(surface, surface->canvas->dm);
/* update bake data */
- dynamicPaint_generateBakeData(surface, scene, cObject);
+ dynamicPaint_generateBakeData(surface, sl, cObject);
/* don't do substeps for first frame */
if (surface->substeps && (frame != surface->start_frame)) {
@@ -5601,10 +5946,10 @@ int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, Scene *scene, Obje
for (st = 1; st <= surface->substeps; st++) {
float subframe = ((float) st) / (surface->substeps + 1);
- if (!dynamicPaint_doStep(scene, cObject, surface, timescale, subframe))
+ if (!dynamicPaint_doStep(scene, sl, cObject, surface, timescale, subframe))
return 0;
}
}
- return dynamicPaint_doStep(scene, cObject, surface, timescale, 0.0f);
+ return dynamicPaint_doStep(scene, sl, cObject, surface, timescale, 0.0f);
}
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
index 1aba76baa2c..baf91b638b9 100644
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -50,6 +50,7 @@
#include "BKE_mesh.h"
#include "BKE_editmesh.h"
#include "BKE_editmesh_bvh.h"
+#include "BKE_editmesh_tangent.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -149,6 +150,8 @@ static void emDM_ensurePolyCenters(EditDerivedBMesh *bmdm)
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);
}
@@ -238,393 +241,62 @@ static void emDM_calcLoopNormalsSpaceArray(
#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 *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)
+ const char (*tangent_names)[MAX_NAME], int tangent_names_len)
{
EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
BMEditMesh *em = bmdm->em;
- BMesh *bm = bmdm->em->bm;
- if (CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV) == 0)
- return;
-
- 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];
- char 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 (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;
- }
- 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;
-
- /* 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);
- 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
+ if (CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPUV) == 0) {
+ return;
}
- /* Update active layer index */
- int uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, act_uv_n);
- int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[uv_index].name);
- CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index);
- /* Update render layer index */
- uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, ren_uv_n);
- tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[uv_index].name);
- CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index);
+ const float (*poly_normals)[3] = bmdm->polyNos;
+ const float (*loop_normals)[3] = CustomData_get_layer(&dm->loopData, CD_NORMAL);
+ const float (*vert_orco)[3] = dm->getVertDataArray(dm, CD_ORCO); /* can be NULL */
+ BKE_editmesh_loop_tangent_calc(
+ em, calc_active_tangent,
+ tangent_names, tangent_names_len,
+ poly_normals, loop_normals,
+ vert_orco,
+ &dm->loopData, dm->numLoopData,
+ &dm->tangent_mask);
}
-/** \} */
-
static void emDM_recalcTessellation(DerivedMesh *UNUSED(dm))
{
/* do nothing */
}
-static void emDM_recalcLoopTri(DerivedMesh *UNUSED(dm))
+static void emDM_recalcLoopTri(DerivedMesh *dm)
{
- /* Nothing to do: emDM tessellation is known,
- * allocate and fill in with emDM_getLoopTriArray */
+ 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;
+
+ 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);
+ }
}
static const MLoopTri *emDM_getLoopTriArray(DerivedMesh *dm)
@@ -633,32 +305,9 @@ static const MLoopTri *emDM_getLoopTriArray(DerivedMesh *dm)
BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num);
}
else {
- 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;
-
- 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);
- }
+ dm->recalcLoopTri(dm);
}
+
return dm->looptris.array;
}
@@ -810,39 +459,6 @@ static void emDM_drawMappedEdgesInterp(
}
}
-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]),
@@ -1191,20 +807,6 @@ static void emDM_drawMappedFaces(
}
}
-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)];
@@ -1212,222 +814,6 @@ static void bmdm_get_tri_colpreview(BMLoop *ls[3], MLoopCol *lcol[3], unsigned c
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) glColor3ubv((const GLubyte *)&(lcol[0]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
-
- glTexCoord2fv(luv[1]->uv);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[1]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
-
- glTexCoord2fv(luv[2]->uv);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[2]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
- }
- else {
- glTexCoord2fv(luv[0]->uv);
- if (has_vcol_any) glColor3ubv((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) glColor3ubv((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) glColor3ubv((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) glColor3ubv((const GLubyte *)&(lcol[0]->r));
- glVertex3fv(ltri[0]->v->co);
-
- glTexCoord2fv(luv[1]->uv);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[1]->r));
- glVertex3fv(ltri[1]->v->co);
-
- glTexCoord2fv(luv[2]->uv);
- if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[2]->r));
- glVertex3fv(ltri[2]->v->co);
- }
- else {
- glTexCoord2fv(luv[0]->uv);
- if (has_vcol_any) glColor3ubv((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) glColor3ubv((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) glColor3ubv((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);
-}
-
-static void emdm_pass_attrib_update_uniforms(const DMVertexAttribs *attribs)
-{
- int i;
- if (attribs->totorco) {
- glUniform1i(attribs->orco.gl_info_index, 0);
- }
- for (i = 0; i < attribs->tottface; i++) {
- glUniform1i(attribs->tface[i].gl_info_index, 0);
- }
- for (i = 0; i < attribs->totmcol; i++) {
- glUniform1i(attribs->mcol[i].gl_info_index, GPU_ATTR_INFO_SRGB);
- }
-
- for (i = 0; i < attribs->tottang; i++) {
- glUniform1i(attribs->tang[i].gl_info_index, 0);
- }
-}
-
/**
* \note
*
@@ -1548,7 +934,7 @@ static void emDM_drawMappedFacesGLSL(
do_draw = setMaterial(matnr = new_matnr, &gattribs);
if (do_draw) {
DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
- emdm_pass_attrib_update_uniforms(&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);
}
@@ -2071,35 +1457,27 @@ static void *emDM_getTessFaceDataArray(DerivedMesh *dm, int type)
/* 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 int type_from = (type == CD_MTFACE) ? CD_MTEXPOLY : CD_MLOOPCOL;
- int index;
const char *bmdata;
char *data;
- index = CustomData_get_layer_index(&bm->pdata, type_from);
- if (index != -1) {
+ bool has_type_source = CustomData_has_layer(&bm->ldata, (type == CD_MTFACE) ? CD_MLOOPUV : 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);
- index = CustomData_get_layer_index(&dm->faceData, type);
+ 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);
@@ -2293,12 +1671,9 @@ DerivedMesh *getEditDerivedBMesh(
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;
@@ -2643,7 +2018,7 @@ static void statvis_calc_distort(
vertexCos[BM_elem_index_get(l_iter->next->v)]);
}
else {
- BM_loop_calc_face_normal(l_iter, no_corner);
+ BM_loop_calc_face_normal_safe(l_iter, no_corner);
}
/* simple way to detect (what is most likely) concave */
if (dot_v3v3(f_no, no_corner) < 0.0f) {
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index fea3c24d322..c95da3b2569 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -165,26 +165,6 @@ void BKE_editmesh_tessface_calc(BMEditMesh *em)
#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) {
diff --git a/source/blender/blenkernel/intern/editmesh_tangent.c b/source/blender/blenkernel/intern/editmesh_tangent.c
new file mode 100644
index 00000000000..589c346b248
--- /dev/null
+++ b/source/blender/blenkernel/intern/editmesh_tangent.c
@@ -0,0 +1,428 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "BKE_DerivedMesh.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; /* 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 = 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 */
+}
+
+/** \} */ \ No newline at end of file
diff --git a/source/blender/blenkernel/intern/editstrands.c b/source/blender/blenkernel/intern/editstrands.c
index 23b17c77935..799c55b8b35 100644
--- a/source/blender/blenkernel/intern/editstrands.c
+++ b/source/blender/blenkernel/intern/editstrands.c
@@ -98,12 +98,8 @@ BMEditStrands *BKE_editstrands_from_object(Object *ob)
return NULL;
}
-void BKE_editstrands_update_linked_customdata(BMEditStrands *es)
+void BKE_editstrands_update_linked_customdata(BMEditStrands *UNUSED(es))
{
- BMesh *bm = es->base.bm;
-
- /* this is done for BMEditMesh, but should never exist for strands */
- BLI_assert(!CustomData_has_layer(&bm->pdata, CD_MTEXPOLY));
}
/*does not free the BMEditStrands struct itself*/
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index 5090e46f1fc..8380588776b 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -64,6 +64,7 @@
#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"
@@ -155,15 +156,20 @@ static EffectorCache *new_effector_cache(Scene *scene, Object *ob, ParticleSyste
eff->frame = -1;
return eff;
}
-static void add_object_to_effectors(ListBase **effectors, Scene *scene, EffectorWeights *weights, Object *ob, Object *ob_src)
+static void add_object_to_effectors(ListBase **effectors, Scene *scene, EffectorWeights *weights, Object *ob, Object *ob_src, bool for_simulation)
{
EffectorCache *eff = NULL;
- if ( ob == ob_src || weights->weight[ob->pd->forcefield] == 0.0f )
+ if ( ob == ob_src )
return;
- if (ob->pd->shape == PFIELD_SHAPE_POINTS && !ob->derivedFinal )
- return;
+ if (for_simulation) {
+ if (weights->weight[ob->pd->forcefield] == 0.0f )
+ return;
+
+ if (ob->pd->shape == PFIELD_SHAPE_POINTS && !ob->derivedFinal )
+ return;
+ }
if (*effectors == NULL)
*effectors = MEM_callocN(sizeof(ListBase), "effectors list");
@@ -175,7 +181,7 @@ static void add_object_to_effectors(ListBase **effectors, Scene *scene, Effector
BLI_addtail(*effectors, eff);
}
-static void add_particles_to_effectors(ListBase **effectors, Scene *scene, EffectorWeights *weights, Object *ob, ParticleSystem *psys, ParticleSystem *psys_src)
+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;
@@ -185,14 +191,14 @@ static void add_particles_to_effectors(ListBase **effectors, Scene *scene, Effec
if ( psys == psys_src && (part->flag & PART_SELF_EFFECT) == 0)
return;
- if ( part->pd && part->pd->forcefield && weights->weight[part->pd->forcefield] != 0.0f) {
+ 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));
}
- if (part->pd2 && part->pd2->forcefield && weights->weight[part->pd2->forcefield] != 0.0f) {
+ 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");
@@ -202,8 +208,9 @@ static void add_particles_to_effectors(ListBase **effectors, Scene *scene, Effec
/* returns ListBase handle with objects taking part in the effecting */
ListBase *pdInitEffectors(Scene *scene, Object *ob_src, ParticleSystem *psys_src,
- EffectorWeights *weights, bool precalc)
+ EffectorWeights *weights, bool for_simulation)
{
+ SceneLayer *sl = BKE_scene_layer_context_active_PLACEHOLDER(scene); /* Can't get sl from the calling modifiers yet */
Base *base;
unsigned int layer= ob_src->lay;
ListBase *effectors = NULL;
@@ -214,34 +221,32 @@ ListBase *pdInitEffectors(Scene *scene, Object *ob_src, ParticleSystem *psys_src
for (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);
+ add_object_to_effectors(&effectors, scene, weights, go->ob, ob_src, for_simulation);
if ( go->ob->particlesystem.first ) {
ParticleSystem *psys= go->ob->particlesystem.first;
for ( ; psys; psys=psys->next )
- add_particles_to_effectors(&effectors, scene, weights, go->ob, psys, psys_src);
+ add_particles_to_effectors(&effectors, scene, weights, go->ob, psys, psys_src, for_simulation);
}
}
}
}
else {
- for (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 (base = FIRSTBASE_NEW; base; base = base->next) {
+ if ( base->object->pd && base->object->pd->forcefield )
+ add_object_to_effectors(&effectors, scene, weights, base->object, ob_src, for_simulation);
- if ( base->object->particlesystem.first ) {
- ParticleSystem *psys= base->object->particlesystem.first;
+ if ( base->object->particlesystem.first ) {
+ ParticleSystem *psys= base->object->particlesystem.first;
- for ( ; psys; psys=psys->next )
- add_particles_to_effectors(&effectors, scene, weights, base->object, psys, psys_src);
- }
+ for ( ; psys; psys=psys->next )
+ add_particles_to_effectors(&effectors, scene, weights, base->object, psys, psys_src, for_simulation);
}
}
}
- if (precalc)
+ if (for_simulation)
pdPrecalculateEffectors(effectors);
return effectors;
@@ -765,7 +770,7 @@ static void do_texture_effector(EffectorCache *eff, EffectorData *efd, EffectedP
force[1] = (0.5f - result->tg) * strength;
force[2] = (0.5f - result->tb) * strength;
}
- else {
+ else if (nabla != 0) {
strength/=nabla;
tex_co[0] += nabla;
@@ -805,6 +810,9 @@ static void do_texture_effector(EffectorCache *eff, EffectorData *efd, EffectedP
force[2] = (dgdx - drdy) * strength;
}
}
+ else {
+ zero_v3(force);
+ }
if (eff->pd->flag & PFIELD_TEX_2D) {
float fac = -dot_v3v3(force, efd->nor);
@@ -840,6 +848,14 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected
break;
case PFIELD_FORCE:
normalize_v3(force);
+ if (pd->flag & PFIELD_GRAVITATION){ /* Option: Multiply by 1/distance^2 */
+ if (efd->distance < FLT_EPSILON){
+ strength = 0.0f;
+ }
+ else {
+ strength *= powf(efd->distance, -2.0f);
+ }
+ }
mul_v3_fl(force, strength * efd->falloff);
break;
case PFIELD_VORTEX:
@@ -970,19 +986,19 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected
*/
void pdDoEffectors(ListBase *effectors, ListBase *colliders, EffectorWeights *weights, EffectedPoint *point, float *force, float *impulse)
{
-/*
- * Modifies the force on a particle according to its
- * relation with the effector object
- * Different kind of effectors include:
- * Forcefields: Gravity-like attractor
- * (force power is related to the inverse of distance to the power of a falloff value)
- * Vortex fields: swirling effectors
- * (particles rotate around Z-axis of the object. otherwise, same relation as)
- * (Forcefields, but this is not done through a force/acceleration)
- * Guide: particles on a path
- * (particles are guided along a curve bezier or old nurbs)
- * (is independent of other effectors)
- */
+ /*
+ * Modifies the force on a particle according to its
+ * relation with the effector object
+ * Different kind of effectors include:
+ * Forcefields: Gravity-like attractor
+ * (force power is related to the inverse of distance to the power of a falloff value)
+ * Vortex fields: swirling effectors
+ * (particles rotate around Z-axis of the object. otherwise, same relation as)
+ * (Forcefields, but this is not done through a force/acceleration)
+ * Guide: particles on a path
+ * (particles are guided along a curve bezier or old nurbs)
+ * (is independent of other effectors)
+ */
EffectorCache *eff;
EffectorData efd;
int p=0, tot = 1, step = 1;
@@ -1122,7 +1138,7 @@ static void debug_data_insert(SimDebugData *debug_data, SimDebugElement *elem)
BLI_ghash_insert(debug_data->gh, elem, elem);
}
-void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[3], float r, float g, float b, const char *category, unsigned int hash)
+void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[3], const char *str, float r, float g, float b, const char *category, unsigned int hash)
{
unsigned int category_hash = BLI_ghashutil_strhash_p(category);
SimDebugElement *elem;
@@ -1141,8 +1157,18 @@ void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[
elem->color[0] = r;
elem->color[1] = g;
elem->color[2] = b;
- copy_v3_v3(elem->v1, v1);
- copy_v3_v3(elem->v2, v2);
+ if (v1)
+ copy_v3_v3(elem->v1, v1);
+ else
+ zero_v3(elem->v1);
+ if (v2)
+ copy_v3_v3(elem->v2, v2);
+ else
+ zero_v3(elem->v2);
+ if (str)
+ BLI_strncpy(elem->str, str, sizeof(elem->str));
+ else
+ elem->str[0] = '\0';
debug_data_insert(_sim_debug_data, elem);
}
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index a89d423e7a6..db6c533ab57 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -47,6 +47,7 @@
#include "BLI_math.h"
#include "BLI_easing.h"
#include "BLI_threads.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -125,7 +126,7 @@ void free_fcurves(ListBase *list)
/* ---------------------- Copy --------------------------- */
/* duplicate an F-Curve */
-FCurve *copy_fcurve(FCurve *fcu)
+FCurve *copy_fcurve(const FCurve *fcu)
{
FCurve *fcu_d;
@@ -1216,6 +1217,7 @@ 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)
{
@@ -1238,6 +1240,32 @@ static bPoseChannel *dtar_get_pchan_ptr(ChannelDriver *driver, DriverTarget *dta
return NULL;
}
}
+#endif
+
+static short driver_check_valid_targets(ChannelDriver *driver, DriverVar *dvar)
+{
+ short valid_targets = 0;
+
+ DRIVER_TARGETS_USED_LOOPER(dvar)
+ {
+ Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
+
+ /* check if this target has valid data */
+ if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
+ /* invalid target, so will not have enough targets */
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ }
+ else {
+ /* target seems to be OK now... */
+ dtar->flag &= ~DTAR_FLAG_INVALID;
+ valid_targets++;
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END
+
+ return valid_targets;
+}
/* ......... */
@@ -1251,62 +1279,54 @@ static float dvar_eval_singleProp(ChannelDriver *driver, DriverVar *dvar)
/* evaluate 'rotation difference' driver variable */
static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
{
- DriverTarget *dtar1 = &dvar->targets[0];
- DriverTarget *dtar2 = &dvar->targets[1];
- bPoseChannel *pchan, *pchan2;
- float q1[4], q2[4], quat[4], angle;
-
- /* get pose channels, and check if we've got two */
- pchan = dtar_get_pchan_ptr(driver, dtar1);
- pchan2 = dtar_get_pchan_ptr(driver, dtar2);
-
- if (ELEM(NULL, pchan, pchan2)) {
- /* disable this driver, since it doesn't work correctly... */
- driver->flag |= DRIVER_FLAG_INVALID;
-
- /* check what the error was */
- if ((pchan == NULL) && (pchan2 == NULL)) {
- if (G.debug & G_DEBUG) {
- printf("Driver Evaluation Error: Rotational difference failed - first 2 targets invalid\n");
- }
-
- dtar1->flag |= DTAR_FLAG_INVALID;
- dtar2->flag |= DTAR_FLAG_INVALID;
- }
- else if (pchan == NULL) {
- if (G.debug & G_DEBUG) {
- printf("Driver Evaluation Error: Rotational difference failed - first target not valid PoseChannel\n");
- }
-
- dtar1->flag |= DTAR_FLAG_INVALID;
- dtar2->flag &= ~DTAR_FLAG_INVALID;
- }
- else if (pchan2 == NULL) {
- if (G.debug & G_DEBUG) {
- printf("Driver Evaluation Error: Rotational difference failed - second target not valid PoseChannel\n");
- }
-
- dtar1->flag &= ~DTAR_FLAG_INVALID;
- dtar2->flag |= DTAR_FLAG_INVALID;
+ short valid_targets = driver_check_valid_targets(driver, dvar);
+
+ /* make sure we have enough valid targets to use - all or nothing for now... */
+ if (driver_check_valid_targets(driver, dvar) != 2) {
+ if (G.debug & G_DEBUG) {
+ printf("RotDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)\n",
+ valid_targets, dvar->targets[0].id, dvar->targets[1].id);
}
-
- /* stop here... */
return 0.0f;
}
- else {
- dtar1->flag &= ~DTAR_FLAG_INVALID;
- dtar2->flag &= ~DTAR_FLAG_INVALID;
+
+ float (*mat[2])[4];
+
+ /* NOTE: for now, these are all just worldspace */
+ for (int i = 0; i < 2; i++) {
+ /* get pointer to loc values to store in */
+ DriverTarget *dtar = &dvar->targets[i];
+ Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
+ bPoseChannel *pchan;
+
+ /* after the checks above, the targets should be valid here... */
+ BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB));
+
+ /* try to get posechannel */
+ pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
+
+ /* check if object or bone */
+ if (pchan) {
+ /* bone */
+ mat[i] = pchan->pose_mat;
+ }
+ else {
+ /* object */
+ mat[i] = ob->obmat;
+ }
}
-
+
+ float q1[4], q2[4], quat[4], angle;
+
/* use the final posed locations */
- mat4_to_quat(q1, pchan->pose_mat);
- mat4_to_quat(q2, pchan2->pose_mat);
-
+ mat4_to_quat(q1, mat[0]);
+ mat4_to_quat(q2, mat[1]);
+
invert_qt_normalized(q1);
mul_qt_qtqt(quat, q1, q2);
angle = 2.0f * (saacos(quat[0]));
angle = ABS(angle);
-
+
return (angle > (float)M_PI) ? (float)((2.0f * (float)M_PI) - angle) : (float)(angle);
}
@@ -1316,32 +1336,8 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
{
float loc1[3] = {0.0f, 0.0f, 0.0f};
float loc2[3] = {0.0f, 0.0f, 0.0f};
- short valid_targets = 0;
-
- /* Perform two passes
- *
- * FIRST PASS - to just check that everything works...
- * NOTE: we use loops here to reduce code duplication, though in practice,
- * there can only be 2 items or else we run into some problems later
- */
- DRIVER_TARGETS_USED_LOOPER(dvar)
- {
- Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
-
- /* check if this target has valid data */
- if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
- /* invalid target, so will not have enough targets */
- driver->flag |= DRIVER_FLAG_INVALID;
- dtar->flag |= DTAR_FLAG_INVALID;
- }
- else {
- /* target seems to be OK now... */
- dtar->flag &= ~DTAR_FLAG_INVALID;
- valid_targets++;
- }
- }
- DRIVER_TARGETS_LOOPER_END
-
+ short valid_targets = driver_check_valid_targets(driver, dvar);
+
/* make sure we have enough valid targets to use - all or nothing for now... */
if (valid_targets < dvar->num_targets) {
if (G.debug & G_DEBUG) {
@@ -1350,8 +1346,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
}
return 0.0f;
}
-
-
+
/* SECOND PASS: get two location values */
/* NOTE: for now, these are all just worldspace */
DRIVER_TARGETS_USED_LOOPER(dvar)
@@ -1569,7 +1564,7 @@ static DriverVarTypeInfo dvar_types[MAX_DVAR_TYPES] = {
BEGIN_DVAR_TYPEDEF(DVAR_TYPE_ROT_DIFF)
dvar_eval_rotDiff, /* eval callback */
2, /* number of targets used */
- {"Bone 1", "Bone 2"}, /* UI names for targets */
+ {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */
{DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY, DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
END_DVAR_TYPEDEF,
@@ -1810,7 +1805,7 @@ void fcurve_free_driver(FCurve *fcu)
}
/* This makes a copy of the given driver */
-ChannelDriver *fcurve_copy_driver(ChannelDriver *driver)
+ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver)
{
ChannelDriver *ndriver;
@@ -1950,7 +1945,7 @@ float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, const fl
BLI_mutex_unlock(&python_driver_lock);
}
#else /* WITH_PYTHON*/
- (void)evaltime;
+ UNUSED_VARS(anim_rna, evaltime);
#endif /* WITH_PYTHON*/
break;
}
diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c
index 2c301c04100..f1732ee7a9a 100644
--- a/source/blender/blenkernel/intern/fmodifier.c
+++ b/source/blender/blenkernel/intern/fmodifier.c
@@ -116,7 +116,7 @@ static void fcm_generator_free(FModifier *fcm)
MEM_freeN(data->coefficients);
}
-static void fcm_generator_copy(FModifier *fcm, FModifier *src)
+static void fcm_generator_copy(FModifier *fcm, const FModifier *src)
{
FMod_Generator *gen = (FMod_Generator *)fcm->data;
FMod_Generator *ogen = (FMod_Generator *)src->data;
@@ -386,7 +386,7 @@ static void fcm_envelope_free(FModifier *fcm)
MEM_freeN(env->data);
}
-static void fcm_envelope_copy(FModifier *fcm, FModifier *src)
+static void fcm_envelope_copy(FModifier *fcm, const FModifier *src)
{
FMod_Envelope *env = (FMod_Envelope *)fcm->data;
FMod_Envelope *oenv = (FMod_Envelope *)src->data;
@@ -877,7 +877,7 @@ static void fcm_python_new_data(void *mdata)
data->prop->type = IDP_GROUP;
}
-static void fcm_python_copy(FModifier *fcm, FModifier *src)
+static void fcm_python_copy(FModifier *fcm, const FModifier *src)
{
FMod_Python *pymod = (FMod_Python *)fcm->data;
FMod_Python *opymod = (FMod_Python *)src->data;
@@ -1040,7 +1040,7 @@ static void fmods_init_typeinfo(void)
/* This function should be used for getting the appropriate type-info when only
* a F-Curve modifier type is known
*/
-const FModifierTypeInfo *get_fmodifier_typeinfo(int type)
+const FModifierTypeInfo *get_fmodifier_typeinfo(const int type)
{
/* initialize the type-info list? */
if (FMI_INIT) {
@@ -1065,7 +1065,7 @@ const FModifierTypeInfo *get_fmodifier_typeinfo(int type)
/* This function should always be used to get the appropriate type-info, as it
* has checks which prevent segfaults in some weird cases.
*/
-const FModifierTypeInfo *fmodifier_get_typeinfo(FModifier *fcm)
+const FModifierTypeInfo *fmodifier_get_typeinfo(const FModifier *fcm)
{
/* only return typeinfo for valid modifiers */
if (fcm)
@@ -1117,7 +1117,7 @@ FModifier *add_fmodifier(ListBase *modifiers, int type)
}
/* Make a copy of the specified F-Modifier */
-FModifier *copy_fmodifier(FModifier *src)
+FModifier *copy_fmodifier(const FModifier *src)
{
const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(src);
FModifier *dst;
@@ -1142,7 +1142,7 @@ FModifier *copy_fmodifier(FModifier *src)
}
/* Duplicate all of the F-Modifiers in the Modifier stacks */
-void copy_fmodifiers(ListBase *dst, ListBase *src)
+void copy_fmodifiers(ListBase *dst, const ListBase *src)
{
FModifier *fcm, *srcfcm;
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index 580842fe176..401fed74c52 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -695,10 +695,14 @@ bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase
if (ef->selboxes)
MEM_freeN(ef->selboxes);
- if (BKE_vfont_select_get(ob, &selstart, &selend))
- ef->selboxes = MEM_callocN((selend - selstart + 1) * sizeof(EditFontSelBox), "font selboxes");
- else
+ if (BKE_vfont_select_get(ob, &selstart, &selend)) {
+ ef->selboxes_len = (selend - selstart) + 1;
+ ef->selboxes = MEM_callocN(ef->selboxes_len * sizeof(EditFontSelBox), "font selboxes");
+ }
+ else {
+ ef->selboxes_len = 0;
ef->selboxes = NULL;
+ }
selboxes = ef->selboxes;
}
diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c
index 3a15be5a09d..0a0b023df82 100644
--- a/source/blender/blenkernel/intern/freestyle.c
+++ b/source/blender/blenkernel/intern/freestyle.c
@@ -40,6 +40,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
// function declarations
static FreestyleLineSet *alloc_lineset(void);
@@ -151,22 +152,14 @@ bool BKE_freestyle_module_delete(FreestyleConfig *config, FreestyleModuleConfig
return true;
}
-bool BKE_freestyle_module_move_up(FreestyleConfig *config, FreestyleModuleConfig *module_conf)
-{
- if (BLI_findindex(&config->modules, module_conf) == -1)
- return false;
- BLI_remlink(&config->modules, module_conf);
- BLI_insertlinkbefore(&config->modules, module_conf->prev, module_conf);
- return true;
-}
-
-bool BKE_freestyle_module_move_down(FreestyleConfig *config, FreestyleModuleConfig *module_conf)
+/**
+ * Reinsert \a module_conf offset by \a direction from current position.
+ * \return if position of \a module_conf changed.
+ */
+bool BKE_freestyle_module_move(FreestyleConfig *config, FreestyleModuleConfig *module_conf, int direction)
{
- if (BLI_findindex(&config->modules, module_conf) == -1)
- return false;
- BLI_remlink(&config->modules, module_conf);
- BLI_insertlinkafter(&config->modules, module_conf->next, module_conf);
- return true;
+ return ((BLI_findindex(&config->modules, module_conf) > -1) &&
+ (BLI_listbase_link_move(&config->modules, module_conf, direction) == true));
}
void BKE_freestyle_lineset_unique_name(FreestyleConfig *config, FreestyleLineSet *lineset)
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index e4bac0a947a..758438bb051 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -39,6 +39,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math_vector.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -382,7 +383,8 @@ bGPDpalette *BKE_gpencil_palette_addnew(bGPdata *gpd, const char *name, bool set
sizeof(palette->info));
/* make this one the active one */
- if (setactive) {
+ /* 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);
}
@@ -752,7 +754,7 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
}
/* make a copy of a given gpencil datablock */
-bGPdata *BKE_gpencil_data_duplicate(Main *bmain, bGPdata *gpd_src, bool internal_copy)
+bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy)
{
const bGPDlayer *gpl_src;
bGPDlayer *gpl_dst;
@@ -1263,12 +1265,16 @@ void BKE_gpencil_palettecolor_changename(bGPdata *gpd, char *oldname, const char
bGPDlayer *gpl;
bGPDframe *gpf;
bGPDstroke *gps;
-
+
+ /* Sanity checks (gpd may not be set in the RNA pointers sometimes) */
+ if (ELEM(NULL, gpd, oldname, newname))
+ return;
+
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
for (gps = gpf->strokes.first; gps; gps = gps->next) {
if (STREQ(gps->colorname, oldname)) {
- strcpy(gps->colorname, newname);
+ BLI_strncpy(gps->colorname, newname, sizeof(gps->colorname));
}
}
}
@@ -1282,7 +1288,11 @@ void BKE_gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name)
bGPDlayer *gpl;
bGPDframe *gpf;
bGPDstroke *gps, *gpsn;
-
+
+ /* Sanity checks (gpd may not be set in the RNA pointers sometimes) */
+ if (ELEM(NULL, gpd, name))
+ return;
+
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
for (gps = gpf->strokes.first; gps; gps = gpsn) {
diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c
index 9b011dbb003..94a341de366 100644
--- a/source/blender/blenkernel/intern/group.c
+++ b/source/blender/blenkernel/intern/group.c
@@ -45,8 +45,6 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_group.h"
#include "BKE_icons.h"
@@ -80,6 +78,8 @@ Group *BKE_group_add(Main *bmain, const char *name)
Group *group;
group = BKE_libblock_alloc(bmain, ID_GR, name);
+ id_us_min(&group->id);
+ id_us_ensure_real(&group->id);
group->layer = (1 << 20) - 1;
group->preview = NULL;
@@ -87,7 +87,7 @@ Group *BKE_group_add(Main *bmain, const char *name)
return group;
}
-Group *BKE_group_copy(Main *bmain, Group *group)
+Group *BKE_group_copy(Main *bmain, const Group *group)
{
Group *groupn;
@@ -130,18 +130,11 @@ static bool group_object_add_internal(Group *group, Object *ob)
return true;
}
-bool BKE_group_object_add(Group *group, Object *object, Scene *scene, Base *base)
+bool BKE_group_object_add(Group *group, Object *object)
{
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;
}
@@ -208,18 +201,12 @@ bool BKE_group_object_cyclic_check(Main *bmain, Object *object, Group *group)
return group_object_cyclic_check_internal(object, group);
}
-bool BKE_group_object_unlink(Group *group, Object *object, Scene *scene, Base *base)
+bool BKE_group_object_unlink(Group *group, Object *object)
{
if (group_object_unlink_internal(group, object)) {
/* object can be NULL */
if (object && BKE_group_object_find(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;
}
@@ -327,7 +314,7 @@ static void group_replaces_nla(Object *parent, Object *target, char mode)
* 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(EvaluationContext *eval_ctx, Scene *scene, Object *UNUSED(parent), Group *group)
+void BKE_group_handle_recalc_and_update(struct EvaluationContext *eval_ctx, Scene *scene, Object *UNUSED(parent), Group *group)
{
GroupObject *go;
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c
index 2d5b15c8f9d..db50a04348b 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.c
@@ -42,6 +42,7 @@
#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"
@@ -143,7 +144,7 @@ static PreviewImage *previewimg_create_ex(size_t deferred_data_size)
memset(prv_img, 0, sizeof(*prv_img)); /* leave deferred data dirty */
if (deferred_data_size) {
- prv_img->use_deferred = true;
+ prv_img->tag |= PRV_TAG_DEFFERED;
}
for (i = 0; i < NUM_ICON_SIZES; ++i) {
@@ -204,7 +205,7 @@ void BKE_previewimg_clear(struct PreviewImage *prv)
}
}
-PreviewImage *BKE_previewimg_copy(PreviewImage *prv)
+PreviewImage *BKE_previewimg_copy(const PreviewImage *prv)
{
PreviewImage *prv_img = NULL;
int i;
@@ -222,7 +223,7 @@ PreviewImage *BKE_previewimg_copy(PreviewImage *prv)
}
/** Duplicate preview image from \a id and clear icon_id, to be used by datablock copy functions. */
-void BKE_previewimg_id_copy(ID *new_id, ID *old_id)
+void BKE_previewimg_id_copy(ID *new_id, const ID *old_id)
{
PreviewImage **old_prv_p = BKE_previewimg_id_get_p(old_id);
PreviewImage **new_prv_p = BKE_previewimg_id_get_p(new_id);
@@ -239,7 +240,7 @@ void BKE_previewimg_id_copy(ID *new_id, ID *old_id)
}
}
-PreviewImage **BKE_previewimg_id_get_p(ID *id)
+PreviewImage **BKE_previewimg_id_get_p(const ID *id)
{
switch (GS(id->name)) {
#define ID_PRV_CASE(id_code, id_struct) case id_code: { return &((id_struct *)id)->preview; } ((void)0)
@@ -252,6 +253,7 @@ PreviewImage **BKE_previewimg_id_get_p(ID *id)
ID_PRV_CASE(ID_OB, Object);
ID_PRV_CASE(ID_GR, Group);
ID_PRV_CASE(ID_SCE, Scene);
+ ID_PRV_CASE(ID_SCR, bScreen);
#undef ID_PRV_CASE
}
@@ -355,11 +357,14 @@ PreviewImage *BKE_previewimg_cached_thumbnail_read(
return prv;
}
-void BKE_previewimg_cached_release(const char *name)
+void BKE_previewimg_cached_release_pointer(PreviewImage *prv)
{
- PreviewImage *prv = BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN);
-
if (prv) {
+ if (prv->tag & PRV_TAG_DEFFERED_RENDERING) {
+ /* We cannot delete the preview while it is being loaded in another thread... */
+ prv->tag |= PRV_TAG_DEFFERED_DELETE;
+ return;
+ }
if (prv->icon_id) {
BKE_icon_delete(prv->icon_id);
}
@@ -367,11 +372,18 @@ void BKE_previewimg_cached_release(const char *name)
}
}
+void BKE_previewimg_cached_release(const char *name)
+{
+ PreviewImage *prv = BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN);
+
+ BKE_previewimg_cached_release_pointer(prv);
+}
+
/** Handle deferred (lazy) loading/generation of preview image, if needed.
* For now, only used with file thumbnails. */
void BKE_previewimg_ensure(PreviewImage *prv, const int size)
{
- if (prv->use_deferred) {
+ if ((prv->tag & PRV_TAG_DEFFERED) != 0) {
const bool do_icon = ((size == ICON_SIZE_ICON) && !prv->rect[ICON_SIZE_ICON]);
const bool do_preview = ((size == ICON_SIZE_PREVIEW) && !prv->rect[ICON_SIZE_PREVIEW]);
diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c
index 70d037d85f3..487635f06ad 100644
--- a/source/blender/blenkernel/intern/idcode.c
+++ b/source/blender/blenkernel/intern/idcode.c
@@ -81,8 +81,9 @@ static IDType idtypes[] = {
{ 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, 0 },
+ { 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 },
@@ -91,6 +92,7 @@ static IDType idtypes[] = {
{ 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 */
@@ -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 b2641b110f8..a3bd15252cb 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -117,31 +117,35 @@ IDProperty *IDP_CopyIDPArray(const IDProperty *array)
return narray;
}
-void IDP_FreeIDPArray(IDProperty *prop)
+static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user)
{
int i;
BLI_assert(prop->type == IDP_IDPARRAY);
for (i = 0; i < prop->len; i++)
- IDP_FreeProperty(GETPROP(prop, i));
+ IDP_FreeProperty_ex(GETPROP(prop, i), do_id_user);
if (prop->data.pointer)
MEM_freeN(prop->data.pointer);
}
-/*shallow copies item*/
+/* shallow copies item */
void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item)
{
IDProperty *old;
BLI_assert(prop->type == IDP_IDPARRAY);
+ if (index >= prop->len || index < 0)
+ return;
+
old = GETPROP(prop, index);
- if (index >= prop->len || index < 0) return;
- if (item != old) IDP_FreeProperty(old);
-
- memcpy(GETPROP(prop, index), item, sizeof(IDProperty));
+ if (item != old) {
+ IDP_FreeProperty(old);
+
+ memcpy(old, item, sizeof(IDProperty));
+ }
}
IDProperty *IDP_GetIndexArray(IDProperty *prop, int index)
@@ -433,22 +437,24 @@ void IDP_FreeString(IDProperty *prop)
/* -------------------------------------------------------------------- */
-/* ID Type (not in use yet) */
+/* ID Type */
-/** \name IDProperty ID API (unused)
+/** \name IDProperty ID API
* \{ */
-void IDP_LinkID(IDProperty *prop, ID *id)
-{
- if (prop->data.pointer)
- id_us_min(((ID *)prop->data.pointer));
- prop->data.pointer = id;
- id_us_plus(id);
-}
-void IDP_UnlinkID(IDProperty *prop)
+static IDProperty *IDP_CopyID(const IDProperty *prop)
{
- id_us_min(((ID *)prop->data.pointer));
+ IDProperty *newp;
+
+ BLI_assert(prop->type == IDP_ID);
+ newp = idp_generic_copy(prop);
+
+ newp->data.pointer = prop->data.pointer;
+ id_us_plus(IDP_Id(newp));
+
+ return newp;
}
+
/** \} */
@@ -468,6 +474,7 @@ static IDProperty *IDP_CopyGroup(const IDProperty *prop)
BLI_assert(prop->type == IDP_GROUP);
newp = idp_generic_copy(prop);
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(link));
@@ -499,14 +506,9 @@ void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src)
break;
default:
{
- IDProperty *tmp = other;
- IDProperty *copy = IDP_CopyProperty(prop);
-
- BLI_insertlinkafter(&dest->data.group, other, copy);
- BLI_remlink(&dest->data.group, tmp);
-
- IDP_FreeProperty(tmp);
- MEM_freeN(tmp);
+ BLI_insertlinkreplace(&dest->data.group, other, IDP_CopyProperty(prop));
+ IDP_FreeProperty(other);
+ MEM_freeN(other);
break;
}
}
@@ -526,11 +528,9 @@ void IDP_SyncGroupTypes(IDProperty *dst, const IDProperty *src, const bool do_ar
if ((prop_dst->type != prop_src->type || prop_dst->subtype != prop_src->subtype) ||
(do_arraylen && ELEM(prop_dst->type, IDP_ARRAY, IDP_IDPARRAY) && (prop_src->len != prop_dst->len)))
{
- IDP_FreeFromGroup(dst, prop_dst);
- prop_dst = IDP_CopyProperty(prop_src);
-
- dst->len++;
- BLI_insertlinkbefore(&dst->data.group, prop_dst_next, prop_dst);
+ BLI_insertlinkreplace(&dst->data.group, prop_dst, IDP_CopyProperty(prop_src));
+ IDP_FreeProperty(prop_dst);
+ MEM_freeN(prop_dst);
}
else if (prop_dst->type == IDP_GROUP) {
IDP_SyncGroupTypes(prop_dst, prop_src, do_arraylen);
@@ -555,11 +555,7 @@ void IDP_ReplaceGroupInGroup(IDProperty *dest, const IDProperty *src)
for (prop = src->data.group.first; prop; prop = prop->next) {
for (loop = dest->data.group.first; loop; loop = loop->next) {
if (STREQ(loop->name, prop->name)) {
- IDProperty *copy = IDP_CopyProperty(prop);
-
- BLI_insertlinkafter(&dest->data.group, loop, copy);
-
- BLI_remlink(&dest->data.group, loop);
+ BLI_insertlinkreplace(&dest->data.group, loop, IDP_CopyProperty(prop));
IDP_FreeProperty(loop);
MEM_freeN(loop);
break;
@@ -586,9 +582,7 @@ void IDP_ReplaceInGroup_ex(IDProperty *group, IDProperty *prop, IDProperty *prop
BLI_assert(prop_exist == IDP_GetPropertyFromGroup(group, prop->name));
if ((prop_exist = IDP_GetPropertyFromGroup(group, prop->name))) {
- BLI_insertlinkafter(&group->data.group, prop_exist, prop);
-
- BLI_remlink(&group->data.group, prop_exist);
+ BLI_insertlinkreplace(&group->data.group, prop_exist, prop);
IDP_FreeProperty(prop_exist);
MEM_freeN(prop_exist);
}
@@ -607,6 +601,7 @@ 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)
{
@@ -617,13 +612,29 @@ 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) {
+ if (prop->type == IDP_GROUP) {
+ IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name);
+
+ if (prop_exist != NULL) {
+ IDP_MergeGroup(prop_exist, prop, do_overwrite);
+ continue;
+ }
+ }
+
IDProperty *copy = IDP_CopyProperty(prop);
IDP_ReplaceInGroup(dest, copy);
}
}
else {
for (prop = src->data.group.first; prop; prop = prop->next) {
- if (IDP_GetPropertyFromGroup(dest, prop->name) == NULL) {
+ IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name);
+ if (prop_exist != NULL) {
+ if (prop->type == IDP_GROUP) {
+ IDP_MergeGroup(prop_exist, prop, do_overwrite);
+ continue;
+ }
+ }
+ else {
IDProperty *copy = IDP_CopyProperty(prop);
dest->len++;
BLI_addtail(&dest->data.group, copy);
@@ -719,13 +730,13 @@ IDProperty *IDP_GetPropertyTypeFromGroup(IDProperty *prop, const char *name, con
* This is because all ID Property freeing functions free only direct data (not the ID Property
* struct itself), but for Groups the child properties *are* considered
* direct data. */
-static void IDP_FreeGroup(IDProperty *prop)
+static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user)
{
IDProperty *loop;
BLI_assert(prop->type == IDP_GROUP);
for (loop = prop->data.group.first; loop; loop = loop->next) {
- IDP_FreeProperty(loop);
+ IDP_FreeProperty_ex(loop, do_id_user);
}
BLI_freelistN(&prop->data.group);
}
@@ -742,12 +753,51 @@ IDProperty *IDP_CopyProperty(const IDProperty *prop)
switch (prop->type) {
case IDP_GROUP: return IDP_CopyGroup(prop);
case IDP_STRING: return IDP_CopyString(prop);
+ case IDP_ID: return IDP_CopyID(prop);
case IDP_ARRAY: return IDP_CopyArray(prop);
case IDP_IDPARRAY: return IDP_CopyIDPArray(prop);
default: return idp_generic_copy(prop);
}
}
+/* Updates ID pointers after an object has been copied */
+/* TODO Nuke this once its only user has been correctly converted to use generic ID management from BKE_library! */
+void IDP_RelinkProperty(struct IDProperty *prop)
+{
+ if (!prop)
+ return;
+
+ switch (prop->type) {
+ case IDP_GROUP:
+ {
+ for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) {
+ IDP_RelinkProperty(loop);
+ }
+ break;
+ }
+ case IDP_IDPARRAY:
+ {
+ IDProperty *idp_array = IDP_Array(prop);
+ for (int i = 0; i < prop->len; i++) {
+ IDP_RelinkProperty(&idp_array[i]);
+ }
+ break;
+ }
+ case IDP_ID:
+ {
+ ID *id = IDP_Id(prop);
+ if (id && id->newid) {
+ id_us_min(IDP_Id(prop));
+ prop->data.pointer = id->newid;
+ id_us_plus(IDP_Id(prop));
+ }
+ break;
+ }
+ default:
+ break; /* Nothing to do for other IDProp types. */
+ }
+}
+
/**
* Get the Group property that contains the id properties for ID id. Set create_if_needed
* to create the Group property and attach it to id if it doesn't exist; otherwise
@@ -844,6 +894,8 @@ bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is
return false;
return true;
}
+ case IDP_ID:
+ return (IDP_Id(prop1) == IDP_Id(prop2));
default:
/* should never get here */
BLI_assert(0);
@@ -867,17 +919,19 @@ bool IDP_EqualsProperties(IDProperty *prop1, IDProperty *prop2)
* The union is simple to use; see the top of this header file for its definition.
* An example of using this function:
*
- * IDPropertyTemplate val;
- * IDProperty *group, *idgroup, *color;
- * group = IDP_New(IDP_GROUP, val, "group1"); //groups don't need a template.
+ * \code{.c}
+ * IDPropertyTemplate val;
+ * IDProperty *group, *idgroup, *color;
+ * group = IDP_New(IDP_GROUP, val, "group1"); //groups don't need a template.
*
- * val.array.len = 4
- * val.array.type = IDP_FLOAT;
- * color = IDP_New(IDP_ARRAY, val, "color1");
+ * val.array.len = 4
+ * val.array.type = IDP_FLOAT;
+ * color = IDP_New(IDP_ARRAY, val, "color1");
*
- * idgroup = IDP_GetProperties(some_id, 1);
- * IDP_AddToGroup(idgroup, color);
- * IDP_AddToGroup(idgroup, group);
+ * idgroup = IDP_GetProperties(some_id, 1);
+ * IDP_AddToGroup(idgroup, color);
+ * IDP_AddToGroup(idgroup, group);
+ * \endcode
*
* Note that you MUST either attach the id property to an id property group with
* IDP_AddToGroup or MEM_freeN the property, doing anything else might result in
@@ -897,7 +951,7 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *
*(float *)&prop->data.val = val->f;
break;
case IDP_DOUBLE:
- prop = MEM_callocN(sizeof(IDProperty), "IDProperty float");
+ prop = MEM_callocN(sizeof(IDProperty), "IDProperty double");
*(double *)&prop->data.val = val->d;
break;
case IDP_ARRAY:
@@ -917,6 +971,7 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *
prop->len = prop->totallen = val->array.len;
break;
}
+ printf("%s: bad array type.\n", __func__);
return NULL;
}
case IDP_STRING:
@@ -963,6 +1018,14 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *
/* heh I think all needed values are set properly by calloc anyway :) */
break;
}
+ case IDP_ID:
+ {
+ prop = MEM_callocN(sizeof(IDProperty), "IDProperty datablock");
+ prop->data.pointer = (void *)val->id;
+ prop->type = IDP_ID;
+ id_us_plus(IDP_Id(prop));
+ break;
+ }
default:
{
prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
@@ -977,11 +1040,10 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *
}
/**
- * \note this will free all child properties of list arrays and groups!
- * Also, note that this does NOT unlink anything! Plus it doesn't free
- * the actual struct IDProperty struct either.
+ * \note This will free allocated data, all child properties of arrays and groups, and unlink IDs!
+ * But it does not free the actual IDProperty struct itself.
*/
-void IDP_FreeProperty(IDProperty *prop)
+void IDP_FreeProperty_ex(IDProperty *prop, const bool do_id_user)
{
switch (prop->type) {
case IDP_ARRAY:
@@ -991,14 +1053,24 @@ void IDP_FreeProperty(IDProperty *prop)
IDP_FreeString(prop);
break;
case IDP_GROUP:
- IDP_FreeGroup(prop);
+ IDP_FreeGroup(prop, do_id_user);
break;
case IDP_IDPARRAY:
- IDP_FreeIDPArray(prop);
+ IDP_FreeIDPArray(prop, do_id_user);
+ break;
+ case IDP_ID:
+ if (do_id_user) {
+ id_us_min(IDP_Id(prop));
+ }
break;
}
}
+void IDP_FreeProperty(IDProperty *prop)
+{
+ IDP_FreeProperty_ex(prop, true);
+}
+
void IDP_ClearProperty(IDProperty *prop)
{
IDP_FreeProperty(prop);
@@ -1006,18 +1078,4 @@ void IDP_ClearProperty(IDProperty *prop)
prop->len = prop->totallen = 0;
}
-/**
- * Unlinks any struct IDProperty<->ID linkage that might be going on.
- *
- * \note currently unused
- */
-void IDP_UnlinkProperty(IDProperty *prop)
-{
- switch (prop->type) {
- case IDP_ID:
- IDP_UnlinkID(prop);
- break;
- }
-}
-
/** \} */
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 626d389ac2d..2915e9d715d 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -62,6 +62,7 @@
#include "BLI_blenlib.h"
#include "BLI_math_vector.h"
+#include "BLI_mempool.h"
#include "BLI_threads.h"
#include "BLI_timecode.h" /* for stamp timecode format */
#include "BLI_utildefines.h"
@@ -80,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"
@@ -433,10 +435,9 @@ static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src)
}
/* empty image block, of similar type and filename */
-Image *BKE_image_copy(Main *bmain, Image *ima)
+Image *BKE_image_copy(Main *bmain, const Image *ima)
{
Image *nima = image_alloc(bmain, ima->id.name + 2, ima->source, ima->type);
- ima->id.newid = &nima->id;
BLI_strncpy(nima->name, ima->name, sizeof(ima->name));
@@ -1239,12 +1240,11 @@ char BKE_imtype_valid_channels(const char imtype, bool write_file)
switch (imtype) {
case R_IMF_IMTYPE_BMP:
if (write_file) break;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case R_IMF_IMTYPE_TARGA:
case R_IMF_IMTYPE_RAWTGA:
case R_IMF_IMTYPE_IRIS:
case R_IMF_IMTYPE_PNG:
- case R_IMF_IMTYPE_RADHDR:
case R_IMF_IMTYPE_TIFF:
case R_IMF_IMTYPE_OPENEXR:
case R_IMF_IMTYPE_MULTILAYER:
@@ -1325,7 +1325,7 @@ char BKE_imtype_from_arg(const char *imtype_arg)
else if (STREQ(imtype_arg, "EXR")) return R_IMF_IMTYPE_OPENEXR;
else if (STREQ(imtype_arg, "MULTILAYER")) return R_IMF_IMTYPE_MULTILAYER;
#endif
- else if (STREQ(imtype_arg, "MPEG")) return R_IMF_IMTYPE_FFMPEG;
+ 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;
@@ -1580,24 +1580,7 @@ void BKE_imbuf_to_image_format(struct ImageFormatData *im_format, const ImBuf *i
}
/* planes */
- /* TODO(sergey): Channels doesn't correspond actual planes used for image buffer
- * For example byte buffer will have 4 channels but it might easily
- * be BW or RGB image.
- *
- * Need to use im_format->planes = imbuf->planes instead?
- */
- switch (imbuf->channels) {
- case 0:
- case 4: im_format->planes = R_IMF_PLANES_RGBA;
- break;
- case 3: im_format->planes = R_IMF_PLANES_RGB;
- break;
- case 1: im_format->planes = R_IMF_PLANES_BW;
- break;
- default: im_format->planes = R_IMF_PLANES_RGB;
- break;
- }
-
+ im_format->planes = imbuf->planes;
}
@@ -1866,7 +1849,7 @@ void BKE_image_stamp_buf(
display = IMB_colormanagement_display_get_named(display_device);
if (stamp_data_template == NULL) {
- stampdata(scene, camera, &stamp_data, 1);
+ stampdata(scene, camera, &stamp_data, (scene->r.stamp & R_STAMP_HIDE_LABELS) == 0);
}
else {
stampdata_from_template(&stamp_data, scene, stamp_data_template);
@@ -2235,8 +2218,10 @@ void BKE_imbuf_write_prepare(ImBuf *ibuf, const ImageFormatData *imf)
ibuf->foptions.flag |= OPENEXR_HALF;
ibuf->foptions.flag |= (imf->exr_codec & OPENEXR_COMPRESS);
- if (!(imf->flag & R_IMF_FLAG_ZBUF))
- ibuf->zbuf_float = NULL; /* signal for exr saving */
+ if (!(imf->flag & R_IMF_FLAG_ZBUF)) {
+ /* Signal for exr saving. */
+ IMB_freezbuffloatImBuf(ibuf);
+ }
}
#endif
@@ -2560,8 +2545,9 @@ void BKE_image_walk_all_users(const Main *mainp, void *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) {
+ 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_VIEW3D) {
View3D *v3d = sa->spacedata.first;
BGpic *bgpic;
@@ -2756,7 +2742,6 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal)
}
}
-#define PASSTYPE_UNSET -1
/* return renderpass for a given pass index and active view */
/* fallback to available if there are missing passes for active view */
static RenderPass *image_render_pass_get(RenderLayer *rl, const int pass, const int view, int *r_passindex)
@@ -2765,7 +2750,7 @@ static RenderPass *image_render_pass_get(RenderLayer *rl, const int pass, const
RenderPass *rpass;
int rp_index = 0;
- int rp_passtype = PASSTYPE_UNSET;
+ const char *rp_name = "";
for (rpass = rl->passes.first; rpass; rpass = rpass->next, rp_index++) {
if (rp_index == pass) {
@@ -2775,12 +2760,12 @@ static RenderPass *image_render_pass_get(RenderLayer *rl, const int pass, const
break;
}
else {
- rp_passtype = rpass->passtype;
+ rp_name = rpass->name;
}
}
/* multiview */
- else if ((rp_passtype != PASSTYPE_UNSET) &&
- (rpass->passtype == rp_passtype) &&
+ else if (rp_name[0] &&
+ STREQ(rpass->name, rp_name) &&
(rpass->view_id == view))
{
rpass_ret = rpass;
@@ -2800,7 +2785,6 @@ static RenderPass *image_render_pass_get(RenderLayer *rl, const int pass, const
return rpass_ret;
}
-#undef PASSTYPE_UNSET
/* if layer or pass changes, we need an index for the imbufs list */
/* note it is called for rendered results, but it doesnt use the index! */
@@ -2881,7 +2865,7 @@ bool BKE_image_is_stereo(Image *ima)
{
return BKE_image_is_multiview(ima) &&
(BLI_findstring(&ima->views, STEREO_LEFT_NAME, offsetof(ImageView, name)) &&
- BLI_findstring(&ima->views, STEREO_RIGHT_NAME, offsetof(ImageView, name)));
+ BLI_findstring(&ima->views, STEREO_RIGHT_NAME, offsetof(ImageView, name)));
}
static void image_init_multilayer_multiview(Image *ima, RenderResult *rr)
@@ -3178,7 +3162,7 @@ static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, cons
struct ImBuf *ibuf;
char name[FILE_MAX];
int flag;
- ImageUser iuser_t;
+ ImageUser iuser_t = {0};
/* XXX temp stuff? */
if (ima->lastframe != frame)
@@ -3186,8 +3170,12 @@ static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, cons
ima->lastframe = frame;
- if (iuser)
+ if (iuser) {
iuser_t = *iuser;
+ }
+ else {
+ /* TODO(sergey): Do we need to initialize something here? */
+ }
iuser_t.view = view_id;
BKE_image_user_file_path(&iuser_t, ima, name);
@@ -3766,7 +3754,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
}
for (rpass = rl->passes.first; rpass; rpass = rpass->next)
- if (rpass->passtype == SCE_PASS_Z)
+ if (STREQ(rpass->name, RE_PASSNAME_Z) && rpass->view_id == actview)
rectz = rpass->rect;
}
}
@@ -4147,33 +4135,32 @@ typedef struct ImagePoolEntry {
typedef struct ImagePool {
ListBase image_buffers;
+ BLI_mempool *memory_pool;
} ImagePool;
ImagePool *BKE_image_pool_new(void)
{
ImagePool *pool = MEM_callocN(sizeof(ImagePool), "Image Pool");
+ pool->memory_pool = BLI_mempool_create(sizeof(ImagePoolEntry), 0, 128, BLI_MEMPOOL_NOP);
return pool;
}
void BKE_image_pool_free(ImagePool *pool)
{
- ImagePoolEntry *entry, *next_entry;
-
- /* use single lock to dereference all the image buffers */
+ /* Use single lock to dereference all the image buffers. */
BLI_spin_lock(&image_spin);
-
- for (entry = pool->image_buffers.first; entry; entry = next_entry) {
- next_entry = entry->next;
-
- if (entry->ibuf)
+ for (ImagePoolEntry *entry = pool->image_buffers.first;
+ entry != NULL;
+ entry = entry->next)
+ {
+ if (entry->ibuf) {
IMB_freeImBuf(entry->ibuf);
-
- MEM_freeN(entry);
+ }
}
-
BLI_spin_unlock(&image_spin);
+ BLI_mempool_destroy(pool->memory_pool);
MEM_freeN(pool);
}
@@ -4225,7 +4212,7 @@ ImBuf *BKE_image_pool_acquire_ibuf(Image *ima, ImageUser *iuser, ImagePool *pool
ibuf = image_acquire_ibuf(ima, iuser, NULL);
- entry = MEM_callocN(sizeof(ImagePoolEntry), "Image Pool Entry");
+ entry = BLI_mempool_alloc(pool->memory_pool);
entry->image = ima;
entry->frame = frame;
entry->index = index;
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 730d5a93758..f3a85dcee2b 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -62,6 +62,7 @@
#include "BLI_blenlib.h"
#include "BLI_dynstr.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 6cdeaf5e59b..98b251294ae 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -38,6 +38,7 @@
#include "BLI_blenlib.h"
#include "BLI_math_vector.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -150,7 +151,7 @@ Key *BKE_key_add(ID *id) /* common function */
return key;
}
-Key *BKE_key_copy(Main *bmain, Key *key)
+Key *BKE_key_copy(Main *bmain, const Key *key)
{
Key *keyn;
KeyBlock *kbn, *kb;
diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c
index e9d039ad480..4a3a1c50195 100644
--- a/source/blender/blenkernel/intern/lamp.c
+++ b/source/blender/blenkernel/intern/lamp.c
@@ -69,6 +69,7 @@ void BKE_lamp_init(Lamp *la)
la->bufsize = 512;
la->clipsta = 0.5f;
la->clipend = 40.0f;
+ la->bleedexp = 120.0f;
la->samp = 3;
la->bias = 1.0f;
la->soft = 3.0f;
@@ -116,7 +117,7 @@ Lamp *BKE_lamp_add(Main *bmain, const char *name)
return la;
}
-Lamp *BKE_lamp_copy(Main *bmain, Lamp *la)
+Lamp *BKE_lamp_copy(Main *bmain, const Lamp *la)
{
Lamp *lan;
int a;
@@ -154,8 +155,6 @@ Lamp *localize_lamp(Lamp *la)
if (lan->mtex[a]) {
lan->mtex[a] = MEM_mallocN(sizeof(MTex), "localize_lamp");
memcpy(lan->mtex[a], la->mtex[a], sizeof(MTex));
- /* free lamp decrements */
- id_us_plus((ID *)lan->mtex[a]->tex);
}
}
@@ -176,15 +175,10 @@ void BKE_lamp_make_local(Main *bmain, Lamp *la, const bool lib_local)
void BKE_lamp_free(Lamp *la)
{
- MTex *mtex;
int a;
for (a = 0; a < MAX_MTEX; a++) {
- mtex = la->mtex[a];
- if (mtex && mtex->tex)
- id_us_min(&mtex->tex->id);
- if (mtex)
- MEM_freeN(mtex);
+ MEM_SAFE_FREE(la->mtex[a]);
}
BKE_animdata_free((ID *)la, false);
@@ -195,6 +189,7 @@ void BKE_lamp_free(Lamp *la)
if (la->nodetree) {
ntreeFreeTree(la->nodetree);
MEM_freeN(la->nodetree);
+ la->nodetree = NULL;
}
BKE_previewimg_free(&la->preview);
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index b0671f33094..c6773d98adf 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_global.h"
#include "BKE_key.h"
@@ -67,7 +66,7 @@
#include "BKE_deform.h"
-/* Workaround for cyclic depenndnecy with curves.
+/* Workaround for cyclic dependency with curves.
* In such case curve_cache might not be ready yet,
*/
#define CYCLIC_DEPENDENCY_WORKAROUND
@@ -277,7 +276,7 @@ Lattice *BKE_lattice_add(Main *bmain, const char *name)
return lt;
}
-Lattice *BKE_lattice_copy(Main *bmain, Lattice *lt)
+Lattice *BKE_lattice_copy(Main *bmain, const Lattice *lt)
{
Lattice *ltn;
@@ -307,6 +306,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);
@@ -1227,8 +1228,24 @@ void BKE_lattice_translate(Lattice *lt, float offset[3], bool do_keys)
/* **** Depsgraph evaluation **** */
-void BKE_lattice_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
+void BKE_lattice_eval_geometry(struct EvaluationContext *UNUSED(eval_ctx),
Lattice *UNUSED(latt))
{
}
+/* Draw Engine */
+void (*BKE_lattice_batch_cache_dirty_cb)(Lattice *lt, int mode) = NULL;
+void (*BKE_lattice_batch_cache_free_cb)(Lattice *lt) = NULL;
+
+void BKE_lattice_batch_cache_dirty(Lattice *lt, int mode)
+{
+ if (lt->batch_cache) {
+ BKE_lattice_batch_cache_dirty_cb(lt, mode);
+ }
+}
+void BKE_lattice_batch_cache_free(Lattice *lt)
+{
+ if (lt->batch_cache) {
+ BKE_lattice_batch_cache_free_cb(lt);
+ }
+} \ No newline at end of file
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
new file mode 100644
index 00000000000..3342c198ee1
--- /dev/null
+++ b/source/blender/blenkernel/intern/layer.c
@@ -0,0 +1,1828 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_listbase.h"
+#include "BLI_string.h"
+#include "BLI_string_utf8.h"
+#include "BLI_string_utils.h"
+#include "BLT_translation.h"
+
+#include "BKE_collection.h"
+#include "BKE_global.h"
+#include "BKE_idprop.h"
+#include "BKE_layer.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_workspace.h"
+
+#include "DNA_ID.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 "DRW_engine.h"
+
+#include "MEM_guardedalloc.h"
+
+#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
+
+/* prototype */
+struct EngineSettingsCB_Type;
+static void layer_collection_free(SceneLayer *sl, LayerCollection *lc);
+static LayerCollection *layer_collection_add(SceneLayer *sl, LayerCollection *parent, SceneCollection *sc);
+static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc, const SceneCollection *sc);
+static IDProperty *collection_engine_settings_create(struct EngineSettingsCB_Type *ces_type, const bool populate);
+static IDProperty *collection_engine_get(IDProperty *root, const int type, const char *engine_name);
+static void collection_engine_settings_init(IDProperty *root, const bool populate);
+static void layer_engine_settings_init(IDProperty *root, const bool populate);
+static void object_bases_iterator_next(BLI_Iterator *iter, const int flag);
+
+/* RenderLayer */
+
+/**
+ * Returns the SceneLayer to be used for rendering
+ * Most of the time BKE_scene_layer_from_workspace_get should be used instead
+ */
+SceneLayer *BKE_scene_layer_from_scene_get(const Scene *scene)
+{
+ SceneLayer *sl = BLI_findlink(&scene->render_layers, scene->active_layer);
+ BLI_assert(sl);
+ return sl;
+}
+
+/**
+ * Returns the SceneLayer to be used for drawing, outliner, and other context related areas.
+ */
+SceneLayer *BKE_scene_layer_from_workspace_get(const struct WorkSpace *workspace)
+{
+ return BKE_workspace_render_layer_get(workspace);
+}
+
+/**
+ * This is a placeholder to know which areas of the code need to be addressed for the Workspace changes.
+ * Never use this, you should either use BKE_scene_layer_workspace_active or get SceneLayer explicitly.
+ */
+SceneLayer *BKE_scene_layer_context_active_ex_PLACEHOLDER(const Main *UNUSED(bmain), const Scene *scene)
+{
+ return BKE_scene_layer_from_scene_get(scene);
+}
+
+/**
+ * This is a placeholder to know which areas of the code need to be addressed for the Workspace changes.
+ * Never use this, you should either use BKE_scene_layer_workspace_active or get SceneLayer explicitly.
+ */
+SceneLayer *BKE_scene_layer_context_active_PLACEHOLDER(const Scene *scene)
+{
+ return BKE_scene_layer_from_scene_get(scene);
+}
+
+/**
+ * Add a new renderlayer
+ * by default, a renderlayer has the master collection
+ */
+SceneLayer *BKE_scene_layer_add(Scene *scene, const char *name)
+{
+ if (!name) {
+ name = DATA_("Render Layer");
+ }
+
+ IDPropertyTemplate val = {0};
+ SceneLayer *sl = MEM_callocN(sizeof(SceneLayer), "Scene Layer");
+ sl->flag |= SCENE_LAYER_RENDER;
+
+ sl->properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
+ layer_engine_settings_init(sl->properties, false);
+
+ BLI_addtail(&scene->render_layers, sl);
+
+ /* unique name */
+ BLI_strncpy_utf8(sl->name, name, sizeof(sl->name));
+ BLI_uniquename(&scene->render_layers, sl, DATA_("SceneLayer"), '.', offsetof(SceneLayer, name), sizeof(sl->name));
+
+ SceneCollection *sc = BKE_collection_master(scene);
+ layer_collection_add(sl, NULL, sc);
+
+ return sl;
+}
+
+/**
+ * Free (or release) any data used by this SceneLayer.
+ */
+void BKE_scene_layer_free(SceneLayer *sl)
+{
+ sl->basact = NULL;
+
+ for (Base *base = sl->object_bases.first; base; base = base->next) {
+ if (base->collection_properties) {
+ IDP_FreeProperty(base->collection_properties);
+ MEM_freeN(base->collection_properties);
+ }
+ }
+ BLI_freelistN(&sl->object_bases);
+
+ for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) {
+ layer_collection_free(NULL, lc);
+ }
+ BLI_freelistN(&sl->layer_collections);
+
+ if (sl->properties) {
+ IDP_FreeProperty(sl->properties);
+ MEM_freeN(sl->properties);
+ }
+
+ if (sl->properties_evaluated) {
+ IDP_FreeProperty(sl->properties_evaluated);
+ MEM_freeN(sl->properties_evaluated);
+ }
+
+ for (SceneLayerEngineData *sled = sl->drawdata.first; sled; sled = sled->next) {
+ if (sled->storage) {
+ if (sled->free) {
+ sled->free(sled->storage);
+ }
+ MEM_freeN(sled->storage);
+ }
+ }
+ BLI_freelistN(&sl->drawdata);
+
+ MEM_SAFE_FREE(sl->stats);
+
+ MEM_freeN(sl);
+}
+
+/**
+ * Set the render engine of a renderlayer
+ */
+void BKE_scene_layer_engine_set(SceneLayer *sl, const char *engine)
+{
+ BLI_strncpy_utf8(sl->engine, engine, sizeof(sl->engine));
+}
+
+/**
+ * Tag all the selected objects of a renderlayer
+ */
+void BKE_scene_layer_selected_objects_tag(SceneLayer *sl, const int tag)
+{
+ for (Base *base = sl->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;
+}
+
+/**
+ * Find the SceneLayer a LayerCollection belongs to
+ */
+SceneLayer *BKE_scene_layer_find_from_collection(const Scene *scene, LayerCollection *lc)
+{
+ for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
+ if (find_scene_collection_in_scene_collections(&sl->layer_collections, lc)) {
+ return sl;
+ }
+ }
+ return NULL;
+}
+
+/* Base */
+
+Base *BKE_scene_layer_base_find(SceneLayer *sl, Object *ob)
+{
+ return BLI_findptr(&sl->object_bases, ob, offsetof(Base, object));
+}
+
+void BKE_scene_layer_base_deselect_all(SceneLayer *sl)
+{
+ Base *base;
+
+ for (base = sl->object_bases.first; base; base = base->next) {
+ base->flag &= ~BASE_SELECTED;
+ }
+}
+
+void BKE_scene_layer_base_select(struct SceneLayer *sl, Base *selbase)
+{
+ sl->basact = selbase;
+ if ((selbase->flag & BASE_SELECTABLED) != 0) {
+ selbase->flag |= BASE_SELECTED;
+ }
+}
+
+static void scene_layer_object_base_unref(SceneLayer *sl, Base *base)
+{
+ base->refcount--;
+
+ /* It only exists in the RenderLayer */
+ if (base->refcount == 0) {
+ if (sl->basact == base) {
+ sl->basact = NULL;
+ }
+
+ if (base->collection_properties) {
+ IDP_FreeProperty(base->collection_properties);
+ MEM_freeN(base->collection_properties);
+ }
+
+ BLI_remlink(&sl->object_bases, base);
+ MEM_freeN(base);
+ }
+}
+
+/**
+ * Return the base if existent, or create it if necessary
+ * Always bump the refcount
+ */
+static Base *object_base_add(SceneLayer *sl, Object *ob)
+{
+ Base *base;
+ base = BKE_scene_layer_base_find(sl, ob);
+
+ if (base == NULL) {
+ base = MEM_callocN(sizeof(Base), "Object Base");
+
+ /* Do not bump user count, leave it for SceneCollections. */
+ base->object = ob;
+ BLI_addtail(&sl->object_bases, base);
+
+ IDPropertyTemplate val = {0};
+ base->collection_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
+ }
+
+ base->refcount++;
+ return base;
+}
+
+/* LayerCollection */
+
+/**
+ * When freeing the entire SceneLayer at once we don't bother with unref
+ * otherwise SceneLayer is passed to keep the syncing of the LayerCollection tree
+ */
+static void layer_collection_free(SceneLayer *sl, LayerCollection *lc)
+{
+ if (sl) {
+ for (LinkData *link = lc->object_bases.first; link; link = link->next) {
+ scene_layer_object_base_unref(sl, link->data);
+ }
+ }
+
+ BLI_freelistN(&lc->object_bases);
+ BLI_freelistN(&lc->overrides);
+
+ if (lc->properties) {
+ IDP_FreeProperty(lc->properties);
+ MEM_freeN(lc->properties);
+ }
+
+ if (lc->properties_evaluated) {
+ IDP_FreeProperty(lc->properties_evaluated);
+ MEM_freeN(lc->properties_evaluated);
+ }
+
+ for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
+ layer_collection_free(sl, nlc);
+ }
+
+ BLI_freelistN(&lc->layer_collections);
+}
+
+/**
+ * Free (or release) LayerCollection from SceneLayer
+ * (does not free the LayerCollection itself).
+ */
+void BKE_layer_collection_free(SceneLayer *sl, LayerCollection *lc)
+{
+ layer_collection_free(sl, lc);
+}
+
+/* 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)++;
+
+ LayerCollection *lc_nested = collection_from_index(&lc->layer_collections, number, i);
+ if (lc_nested) {
+ return lc_nested;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Get the active collection
+ */
+LayerCollection *BKE_layer_collection_get_active(SceneLayer *sl)
+{
+ int i = 0;
+ return collection_from_index(&sl->layer_collections, sl->active_collection, &i);
+}
+
+
+/**
+ * Return layer collection to add new object(s).
+ * Create one if none exists.
+ */
+LayerCollection *BKE_layer_collection_get_active_ensure(Scene *scene, SceneLayer *sl)
+{
+ LayerCollection *lc = BKE_layer_collection_get_active(sl);
+
+ if (lc == NULL) {
+ BLI_assert(BLI_listbase_is_empty(&sl->layer_collections));
+ /* When there is no collection linked to this SceneLayer, create one. */
+ SceneCollection *sc = BKE_collection_add(scene, NULL, NULL);
+ lc = BKE_collection_link(sl, sc);
+ }
+
+ 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(SceneLayer *sl)
+{
+ return collection_count(&sl->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)++;
+
+ 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(SceneLayer *sl, const LayerCollection *lc)
+{
+ int i = 0;
+ return index_from_collection(&sl->layer_collections, lc, &i);
+}
+
+/**
+ * Lookup the listbase that contains \a lc.
+ */
+static ListBase *layer_collection_listbase_find(ListBase *lb, LayerCollection *lc)
+{
+ for (LayerCollection *lc_iter = lb->first; lc_iter; lc_iter = lc_iter->next) {
+ if (lc_iter == lc) {
+ return lb;
+ }
+
+ ListBase *lb_child_result;
+ if ((lb_child_result = layer_collection_listbase_find(&lc_iter->layer_collections, lc))) {
+ return lb_child_result;
+ }
+ }
+
+ return NULL;
+}
+
+#if 0
+/**
+ * Lookup the listbase that contains \a sc.
+ */
+static ListBase *scene_collection_listbase_find(ListBase *lb, SceneCollection *sc)
+{
+ for (SceneCollection *sc_iter = lb->first; sc_iter; sc_iter = sc_iter->next) {
+ if (sc_iter == sc) {
+ return lb;
+ }
+
+ ListBase *lb_child_result;
+ if ((lb_child_result = scene_collection_listbase_find(&sc_iter->scene_collections, sc))) {
+ return lb_child_result;
+ }
+ }
+
+ return NULL;
+}
+#endif
+
+/* ---------------------------------------------------------------------- */
+/* Outliner drag and drop */
+
+/**
+ * Nest a LayerCollection into another one
+ * Both collections must be from the same SceneLayer, return true if succeded.
+ *
+ * The LayerCollection will effectively be moved into the
+ * new (nested) position. So all the settings, overrides, ... go with it, and
+ * if the collection was directly linked to the SceneLayer it's then unlinked.
+ *
+ * For the other SceneLayers we simply resync the tree, without changing directly
+ * linked collections (even if they link to the same SceneCollection)
+ *
+ * \param lc_src LayerCollection to nest into \a lc_dst
+ * \param lc_dst LayerCollection to have \a lc_src inserted into
+ */
+
+static void layer_collection_swap(
+ SceneLayer *sl, ListBase *lb_a, ListBase *lb_b,
+ LayerCollection *lc_a, LayerCollection *lc_b)
+{
+ if (lb_a == NULL) {
+ lb_a = layer_collection_listbase_find(&sl->layer_collections, lc_a);
+ }
+
+ if (lb_b == NULL) {
+ lb_b = layer_collection_listbase_find(&sl->layer_collections, lc_b);
+ }
+
+ BLI_assert(lb_a);
+ BLI_assert(lb_b);
+
+ BLI_listbases_swaplinks(lb_a, lb_b, lc_a, lc_b);
+}
+
+/**
+ * Move \a lc_src into \a lc_dst. Both have to be stored in \a sl.
+ * If \a lc_src is directly linked to the SceneLayer it's unlinked
+ */
+bool BKE_layer_collection_move_into(const Scene *scene, LayerCollection *lc_dst, LayerCollection *lc_src)
+{
+ SceneLayer *sl = BKE_scene_layer_find_from_collection(scene, lc_src);
+ bool is_directly_linked = false;
+
+ if ((!sl) || (sl != BKE_scene_layer_find_from_collection(scene, lc_dst))) {
+ return false;
+ }
+
+ /* We can't nest the collection into itself */
+ if (lc_src->scene_collection == lc_dst->scene_collection) {
+ return false;
+ }
+
+ /* Collection is already where we wanted it to be */
+ if (lc_dst->layer_collections.last == lc_src) {
+ return false;
+ }
+
+ /* Collection is already where we want it to be in the scene tree
+ * but we want to swap it in the layer tree still */
+ if (lc_dst->scene_collection->scene_collections.last == lc_src->scene_collection) {
+ LayerCollection *lc_swap = lc_dst->layer_collections.last;
+ layer_collection_swap(sl, &lc_dst->layer_collections, NULL, lc_dst->layer_collections.last, lc_src);
+
+ if (BLI_findindex(&sl->layer_collections, lc_swap) != -1) {
+ BKE_collection_unlink(sl, lc_swap);
+ }
+ return true;
+ }
+ else {
+ LayerCollection *lc_temp;
+ is_directly_linked = BLI_findindex(&sl->layer_collections, lc_src) != -1;
+
+ if (!is_directly_linked) {
+ /* lc_src will be invalid after BKE_collection_move_into!
+ * so we swap it with lc_temp to preserve its settings */
+ lc_temp = BKE_collection_link(sl, lc_src->scene_collection);
+ layer_collection_swap(sl, &sl->layer_collections, NULL, lc_temp, lc_src);
+ }
+
+ if (!BKE_collection_move_into(scene, lc_dst->scene_collection, lc_src->scene_collection)) {
+ if (!is_directly_linked) {
+ /* Swap back and remove */
+ layer_collection_swap(sl, NULL, NULL, lc_temp, lc_src);
+ BKE_collection_unlink(sl, lc_temp);
+ }
+ return false;
+ }
+ }
+
+ LayerCollection *lc_new = BLI_findptr(&lc_dst->layer_collections, lc_src->scene_collection, offsetof(LayerCollection, scene_collection));
+ BLI_assert(lc_new);
+ layer_collection_swap(sl, &lc_dst->layer_collections, NULL, lc_new, lc_src);
+
+ /* If it's directly linked, unlink it after the swap */
+ if (BLI_findindex(&sl->layer_collections, lc_new) != -1) {
+ BKE_collection_unlink(sl, lc_new);
+ }
+
+ return true;
+}
+
+/**
+ * Move \a lc_src above \a lc_dst. Both have to be stored in \a sl.
+ * If \a lc_src is directly linked to the SceneLayer it's unlinked
+ */
+bool BKE_layer_collection_move_above(const Scene *scene, LayerCollection *lc_dst, LayerCollection *lc_src)
+{
+ SceneLayer *sl = BKE_scene_layer_find_from_collection(scene, lc_src);
+ const bool is_directly_linked_src = BLI_findindex(&sl->layer_collections, lc_src) != -1;
+ const bool is_directly_linked_dst = BLI_findindex(&sl->layer_collections, lc_dst) != -1;
+
+ if ((!sl) || (sl != BKE_scene_layer_find_from_collection(scene, lc_dst))) {
+ return false;
+ }
+
+ /* Collection is already where we wanted it to be */
+ if (lc_dst->prev == lc_src) {
+ return false;
+ }
+
+ /* Collection is already where we want it to be in the scene tree
+ * but we want to swap it in the layer tree still */
+ if (lc_dst->prev && lc_dst->prev->scene_collection == lc_src->scene_collection) {
+ LayerCollection *lc_swap = lc_dst->prev;
+ layer_collection_swap(sl, NULL, NULL, lc_dst->prev, lc_src);
+
+ if (BLI_findindex(&sl->layer_collections, lc_swap) != -1) {
+ BKE_collection_unlink(sl, lc_swap);
+ }
+ return true;
+ }
+ /* We don't allow to move above/below a directly linked collection
+ * unless the source collection is also directly linked */
+ else if (is_directly_linked_dst) {
+ /* Both directly linked to the SceneLayer, just need to swap */
+ if (is_directly_linked_src) {
+ BLI_remlink(&sl->layer_collections, lc_src);
+ BLI_insertlinkbefore(&sl->layer_collections, lc_dst, lc_src);
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ else {
+ LayerCollection *lc_temp;
+
+ if (!is_directly_linked_src) {
+ /* lc_src will be invalid after BKE_collection_move_into!
+ * so we swap it with lc_temp to preserve its settings */
+ lc_temp = BKE_collection_link(sl, lc_src->scene_collection);
+ layer_collection_swap(sl, &sl->layer_collections, NULL, lc_temp, lc_src);
+ }
+
+ if (!BKE_collection_move_above(scene, lc_dst->scene_collection, lc_src->scene_collection)) {
+ if (!is_directly_linked_src) {
+ /* Swap back and remove */
+ layer_collection_swap(sl, NULL, NULL, lc_temp, lc_src);
+ BKE_collection_unlink(sl, lc_temp);
+ }
+ return false;
+ }
+ }
+
+ LayerCollection *lc_new = lc_dst->prev;
+ BLI_assert(lc_new);
+ layer_collection_swap(sl, NULL, NULL, lc_new, lc_src);
+
+ /* If it's directly linked, unlink it after the swap */
+ if (BLI_findindex(&sl->layer_collections, lc_new) != -1) {
+ BKE_collection_unlink(sl, lc_new);
+ }
+
+ return true;
+}
+
+/**
+ * Move \a lc_src below \a lc_dst. Both have to be stored in \a sl.
+ * If \a lc_src is directly linked to the SceneLayer it's unlinked
+ */
+bool BKE_layer_collection_move_below(const Scene *scene, LayerCollection *lc_dst, LayerCollection *lc_src)
+{
+ SceneLayer *sl = BKE_scene_layer_find_from_collection(scene, lc_src);
+ const bool is_directly_linked_src = BLI_findindex(&sl->layer_collections, lc_src) != -1;
+ const bool is_directly_linked_dst = BLI_findindex(&sl->layer_collections, lc_dst) != -1;
+
+ if ((!sl) || (sl != BKE_scene_layer_find_from_collection(scene, lc_dst))) {
+ return false;
+ }
+
+ /* Collection is already where we wanted it to be */
+ if (lc_dst->next == lc_src) {
+ return false;
+ }
+
+ /* Collection is already where we want it to be in the scene tree
+ * but we want to swap it in the layer tree still */
+ if (lc_dst->next && lc_dst->next->scene_collection == lc_src->scene_collection) {
+ LayerCollection *lc_swap = lc_dst->next;
+ layer_collection_swap(sl, NULL, NULL, lc_dst->next, lc_src);
+
+ if (BLI_findindex(&sl->layer_collections, lc_swap) != -1) {
+ BKE_collection_unlink(sl, lc_swap);
+ }
+ return true;
+ }
+ /* We don't allow to move above/below a directly linked collection
+ * unless the source collection is also directly linked */
+ else if (is_directly_linked_dst) {
+ /* Both directly linked to the SceneLayer, just need to swap */
+ if (is_directly_linked_src) {
+ BLI_remlink(&sl->layer_collections, lc_src);
+ BLI_insertlinkafter(&sl->layer_collections, lc_dst, lc_src);
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ else {
+ LayerCollection *lc_temp;
+
+ if (!is_directly_linked_src) {
+ /* lc_src will be invalid after BKE_collection_move_into!
+ * so we swap it with lc_temp to preserve its settings */
+ lc_temp = BKE_collection_link(sl, lc_src->scene_collection);
+ layer_collection_swap(sl, &sl->layer_collections, NULL, lc_temp, lc_src);
+ }
+
+ if (!BKE_collection_move_below(scene, lc_dst->scene_collection, lc_src->scene_collection)) {
+ if (!is_directly_linked_src) {
+ /* Swap back and remove */
+ layer_collection_swap(sl, NULL, NULL, lc_temp, lc_src);
+ BKE_collection_unlink(sl, lc_temp);
+ }
+ return false;
+ }
+ }
+
+ LayerCollection *lc_new = lc_dst->next;
+ BLI_assert(lc_new);
+ layer_collection_swap(sl, NULL, NULL, lc_new, lc_src);
+
+ /* If it's directly linked, unlink it after the swap */
+ if (BLI_findindex(&sl->layer_collections, lc_new) != -1) {
+ BKE_collection_unlink(sl, lc_new);
+ }
+
+ return true;
+}
+
+static bool layer_collection_resync(SceneLayer *sl, LayerCollection *lc, const SceneCollection *sc)
+{
+ if (lc->scene_collection == sc) {
+ ListBase collections = {NULL};
+ BLI_movelisttolist(&collections, &lc->layer_collections);
+
+ for (SceneCollection *sc_nested = sc->scene_collections.first; sc_nested; sc_nested = sc_nested->next) {
+ LayerCollection *lc_nested = BLI_findptr(&collections, sc_nested, offsetof(LayerCollection, scene_collection));
+ if (lc_nested) {
+ BLI_remlink(&collections, lc_nested);
+ BLI_addtail(&lc->layer_collections, lc_nested);
+ }
+ else {
+ layer_collection_add(sl, lc, sc_nested);
+ }
+ }
+
+ for (LayerCollection *lc_nested = collections.first; lc_nested; lc_nested = lc_nested->next) {
+ layer_collection_free(sl, lc_nested);
+ }
+ BLI_freelistN(&collections);
+
+ BLI_assert(BLI_listbase_count(&lc->layer_collections) ==
+ BLI_listbase_count(&sc->scene_collections));
+
+ return true;
+ }
+
+ for (LayerCollection *lc_nested = lc->layer_collections.first; lc_nested; lc_nested = lc_nested->next) {
+ if (layer_collection_resync(sl, lc_nested, sc)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Update the scene layers so that any LayerCollection that points
+ * to \a sc is re-synced again
+ */
+void BKE_layer_collection_resync(const Scene *scene, const SceneCollection *sc)
+{
+ for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
+ for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) {
+ layer_collection_resync(sl, lc, sc);
+ }
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+
+/**
+ * Link a collection to a renderlayer
+ * The collection needs to be created separately
+ */
+LayerCollection *BKE_collection_link(SceneLayer *sl, SceneCollection *sc)
+{
+ LayerCollection *lc = layer_collection_add(sl, NULL, sc);
+ sl->active_collection = BKE_layer_collection_findindex(sl, lc);
+ return lc;
+}
+
+/**
+ * Unlink a collection base from a renderlayer
+ * The corresponding collection is not removed from the master collection
+ */
+void BKE_collection_unlink(SceneLayer *sl, LayerCollection *lc)
+{
+ BKE_layer_collection_free(sl, lc);
+ BLI_remlink(&sl->layer_collections, lc);
+ MEM_freeN(lc);
+ sl->active_collection = 0;
+}
+
+static void layer_collection_object_add(SceneLayer *sl, LayerCollection *lc, Object *ob)
+{
+ Base *base = object_base_add(sl, ob);
+
+ /* Only add an object once - prevent SceneCollection->objects and
+ * SceneCollection->filter_objects to add the same object. */
+
+ if (BLI_findptr(&lc->object_bases, base, offsetof(LinkData, data))) {
+ return;
+ }
+
+ bool is_visible = (lc->flag & COLLECTION_VISIBLE) != 0;
+ bool is_selectable = is_visible && ((lc->flag & COLLECTION_SELECTABLE) != 0);
+
+ if (is_visible) {
+ base->flag |= BASE_VISIBLED;
+ }
+
+ if (is_selectable) {
+ base->flag |= BASE_SELECTABLED;
+ }
+
+ BLI_addtail(&lc->object_bases, BLI_genericNodeN(base));
+}
+
+static void layer_collection_object_remove(SceneLayer *sl, LayerCollection *lc, Object *ob)
+{
+ Base *base;
+ base = BKE_scene_layer_base_find(sl, ob);
+
+ LinkData *link = BLI_findptr(&lc->object_bases, base, offsetof(LinkData, data));
+ BLI_remlink(&lc->object_bases, link);
+ MEM_freeN(link);
+
+ scene_layer_object_base_unref(sl, base);
+}
+
+static void layer_collection_objects_populate(SceneLayer *sl, LayerCollection *lc, ListBase *objects)
+{
+ for (LinkData *link = objects->first; link; link = link->next) {
+ layer_collection_object_add(sl, lc, link->data);
+ }
+}
+
+static void layer_collection_populate(SceneLayer *sl, LayerCollection *lc, SceneCollection *sc)
+{
+ layer_collection_objects_populate(sl, lc, &sc->objects);
+ layer_collection_objects_populate(sl, lc, &sc->filter_objects);
+
+ for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
+ layer_collection_add(sl, lc, nsc);
+ }
+}
+
+static LayerCollection *layer_collection_add(SceneLayer *sl, LayerCollection *parent, SceneCollection *sc)
+{
+ IDPropertyTemplate val = {0};
+ LayerCollection *lc = MEM_callocN(sizeof(LayerCollection), "Collection Base");
+
+ lc->scene_collection = sc;
+ lc->flag = COLLECTION_VISIBLE | COLLECTION_SELECTABLE;
+
+ lc->properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
+ collection_engine_settings_init(lc->properties, false);
+
+ if (parent != NULL) {
+ BLI_addtail(&parent->layer_collections, lc);
+ }
+ else {
+ BLI_addtail(&sl->layer_collections, lc);
+ }
+
+ layer_collection_populate(sl, lc, sc);
+
+ return lc;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/**
+ * See if render layer has the scene collection linked directly, or indirectly (nested)
+ */
+bool BKE_scene_layer_has_collection(SceneLayer *sl, const SceneCollection *sc)
+{
+ for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) {
+ if (find_layer_collection_by_scene_collection(lc, sc) != NULL) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * See if the object is in any of the scene layers of the scene
+ */
+bool BKE_scene_has_object(Scene *scene, Object *ob)
+{
+ for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
+ Base *base = BKE_scene_layer_base_find(sl, ob);
+ if (base) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+/* ---------------------------------------------------------------------- */
+/* Syncing */
+
+static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc, const SceneCollection *sc)
+{
+ if (lc->scene_collection == sc) {
+ return lc;
+ }
+
+ for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
+ LayerCollection *found = find_layer_collection_by_scene_collection(nlc, sc);
+ if (found) {
+ return found;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Add a new LayerCollection for all the SceneLayers that have sc_parent
+ */
+void BKE_layer_sync_new_scene_collection(Scene *scene, const SceneCollection *sc_parent, SceneCollection *sc)
+{
+ for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
+ for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) {
+ LayerCollection *lc_parent = find_layer_collection_by_scene_collection(lc, sc_parent);
+ if (lc_parent) {
+ layer_collection_add(sl, lc_parent, sc);
+ }
+ }
+ }
+}
+
+/**
+ * Add a corresponding ObjectBase to all the equivalent LayerCollection
+ */
+void BKE_layer_sync_object_link(const Scene *scene, SceneCollection *sc, Object *ob)
+{
+ for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
+ for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) {
+ LayerCollection *found = find_layer_collection_by_scene_collection(lc, sc);
+ if (found) {
+ layer_collection_object_add(sl, found, ob);
+ }
+ }
+ }
+}
+
+/**
+ * Remove the equivalent object base to all layers that have this collection
+ * also remove all reference to ob in the filter_objects
+ */
+void BKE_layer_sync_object_unlink(const Scene *scene, SceneCollection *sc, Object *ob)
+{
+ for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
+ for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) {
+ LayerCollection *found = find_layer_collection_by_scene_collection(lc, sc);
+ if (found) {
+ layer_collection_object_remove(sl, found, ob);
+ }
+ }
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+/* Override */
+
+/**
+ * Add a new datablock override
+ */
+void BKE_collection_override_datablock_add(LayerCollection *UNUSED(lc), const char *UNUSED(data_path), ID *UNUSED(id))
+{
+ TODO_LAYER_OVERRIDE;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Engine Settings */
+
+ListBase R_layer_collection_engines_settings_callbacks = {NULL, NULL};
+ListBase R_scene_layer_engines_settings_callbacks = {NULL, NULL};
+
+typedef struct EngineSettingsCB_Type {
+ struct EngineSettingsCB_Type *next, *prev;
+
+ char name[MAX_NAME]; /* engine name */
+
+ EngineSettingsCB callback;
+
+} EngineSettingsCB_Type;
+
+static void create_engine_settings_scene(IDProperty *root, EngineSettingsCB_Type *es_type)
+{
+ if (collection_engine_get(root, COLLECTION_MODE_NONE, es_type->name)) {
+ return;
+ }
+
+ IDProperty *props = collection_engine_settings_create(es_type, true);
+ IDP_AddToGroup(root, props);
+}
+
+static void create_layer_collection_engine_settings_scene(Scene *scene, EngineSettingsCB_Type *es_type)
+{
+ create_engine_settings_scene(scene->collection_properties, es_type);
+}
+
+static void create_scene_layer_engine_settings_scene(Scene *scene, EngineSettingsCB_Type *es_type)
+{
+ create_engine_settings_scene(scene->layer_properties, es_type);
+}
+
+static void create_layer_collection_engine_settings_collection(LayerCollection *lc, EngineSettingsCB_Type *es_type)
+{
+ if (BKE_layer_collection_engine_collection_get(lc, COLLECTION_MODE_NONE, es_type->name)) {
+ return;
+ }
+
+ IDProperty *props = collection_engine_settings_create(es_type, false);
+ IDP_AddToGroup(lc->properties, props);
+
+ for (LayerCollection *lcn = lc->layer_collections.first; lcn; lcn = lcn->next) {
+ create_layer_collection_engine_settings_collection(lcn, es_type);
+ }
+}
+
+static void create_layer_collection_engines_settings_scene(Scene *scene, EngineSettingsCB_Type *es_type)
+{
+ /* Populate the scene with the new settings. */
+ create_layer_collection_engine_settings_scene(scene, es_type);
+
+ for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
+ for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) {
+ create_layer_collection_engine_settings_collection(lc, es_type);
+ }
+ }
+}
+
+static void create_scene_layer_engines_settings_scene(Scene *scene, EngineSettingsCB_Type *es_type)
+{
+ /* Populate the scene with the new settings. */
+ create_scene_layer_engine_settings_scene(scene, es_type);
+}
+
+static void create_scene_layer_engines_settings_layer(SceneLayer *sl, EngineSettingsCB_Type *es_type)
+{
+ if (BKE_scene_layer_engine_layer_get(sl, COLLECTION_MODE_NONE, es_type->name)) {
+ return;
+ }
+
+ IDProperty *props = collection_engine_settings_create(es_type, false);
+ IDP_AddToGroup(sl->properties, props);
+}
+
+static EngineSettingsCB_Type *engine_settings_callback_register(const char *engine_name, EngineSettingsCB func, ListBase *lb)
+{
+ EngineSettingsCB_Type *es_type;
+
+ /* Cleanup in case it existed. */
+ es_type = BLI_findstring(lb, engine_name, offsetof(EngineSettingsCB_Type, name));
+
+ if (es_type) {
+ BLI_remlink(lb, es_type);
+ MEM_freeN(es_type);
+ }
+
+ es_type = MEM_callocN(sizeof(EngineSettingsCB_Type), __func__);
+ BLI_strncpy_utf8(es_type->name, engine_name, sizeof(es_type->name));
+ es_type->callback = func;
+ BLI_addtail(lb, es_type);
+
+ return es_type;
+}
+
+void BKE_layer_collection_engine_settings_callback_register(
+ Main *bmain, const char *engine_name, EngineSettingsCB func)
+{
+ EngineSettingsCB_Type *es_type =
+ engine_settings_callback_register(engine_name, func, &R_layer_collection_engines_settings_callbacks);
+
+ if (bmain) {
+ /* Populate all of the collections of the scene with those settings. */
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ create_layer_collection_engines_settings_scene(scene, es_type);
+ }
+ }
+}
+
+void BKE_scene_layer_engine_settings_callback_register(
+ Main *bmain, const char *engine_name, EngineSettingsCB func)
+{
+ EngineSettingsCB_Type *es_type =
+ engine_settings_callback_register(engine_name, func, &R_scene_layer_engines_settings_callbacks);
+
+ if (bmain) {
+ /* Populate all of the collections of the scene with those settings. */
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ create_scene_layer_engines_settings_scene(scene, es_type);
+
+ for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
+ create_scene_layer_engines_settings_layer(sl, es_type);
+ }
+ }
+ }
+}
+
+void BKE_layer_collection_engine_settings_callback_free(void)
+{
+ BLI_freelistN(&R_layer_collection_engines_settings_callbacks);
+}
+
+void BKE_scene_layer_engine_settings_callback_free(void)
+{
+ BLI_freelistN(&R_scene_layer_engines_settings_callbacks);
+}
+
+/**
+ * Create a root IDProperty for this engine
+ *
+ * \param populate whether we want to pre-fill the collection with the default properties
+ */
+static IDProperty *collection_engine_settings_create(EngineSettingsCB_Type *es_type, const bool populate)
+{
+ IDProperty *props;
+ IDPropertyTemplate val = {0};
+
+ props = IDP_New(IDP_GROUP, &val, es_type->name);
+ props->subtype = IDP_GROUP_SUB_ENGINE_RENDER;
+
+ /* properties */
+ if (populate) {
+ es_type->callback(NULL, props);
+ }
+
+ return props;
+}
+
+static void layer_collection_create_mode_settings_object(IDProperty *root, const bool populate)
+{
+ IDProperty *props;
+ IDPropertyTemplate val = {0};
+
+ props = IDP_New(IDP_GROUP, &val, "ObjectMode");
+ props->subtype = IDP_GROUP_SUB_MODE_OBJECT;
+
+ /* properties */
+ if (populate) {
+ OBJECT_collection_settings_create(props);
+ }
+
+ IDP_AddToGroup(root, props);
+}
+
+static void layer_collection_create_mode_settings_edit(IDProperty *root, const bool populate)
+{
+ IDProperty *props;
+ IDPropertyTemplate val = {0};
+
+ props = IDP_New(IDP_GROUP, &val, "EditMode");
+ props->subtype = IDP_GROUP_SUB_MODE_EDIT;
+
+ /* properties */
+ if (populate) {
+ EDIT_MESH_collection_settings_create(props);
+ }
+
+ IDP_AddToGroup(root, props);
+}
+
+static void layer_collection_create_mode_settings_paint_weight(IDProperty *root, const bool populate)
+{
+ IDProperty *props;
+ IDPropertyTemplate val = {0};
+
+ props = IDP_New(IDP_GROUP, &val, "WeightPaintMode");
+ props->subtype = IDP_GROUP_SUB_MODE_PAINT_WEIGHT;
+
+ /* properties */
+ if (populate) {
+ PAINT_WEIGHT_collection_settings_create(props);
+ }
+
+ IDP_AddToGroup(root, props);
+}
+
+static void layer_collection_create_mode_settings_paint_vertex(IDProperty *root, const bool populate)
+{
+ IDProperty *props;
+ IDPropertyTemplate val = {0};
+
+ props = IDP_New(IDP_GROUP, &val, "VertexPaintMode");
+ props->subtype = IDP_GROUP_SUB_MODE_PAINT_VERTEX;
+
+ /* properties */
+ if (populate) {
+ PAINT_VERTEX_collection_settings_create(props);
+ }
+
+ IDP_AddToGroup(root, props);
+}
+
+static void layer_collection_create_render_settings(IDProperty *root, const bool populate)
+{
+ EngineSettingsCB_Type *es_type;
+ for (es_type = R_layer_collection_engines_settings_callbacks.first; es_type; es_type = es_type->next) {
+ IDProperty *props = collection_engine_settings_create(es_type, populate);
+ IDP_AddToGroup(root, props);
+ }
+}
+
+static void scene_layer_create_render_settings(IDProperty *root, const bool populate)
+{
+ EngineSettingsCB_Type *es_type;
+ for (es_type = R_scene_layer_engines_settings_callbacks.first; es_type; es_type = es_type->next) {
+ IDProperty *props = collection_engine_settings_create(es_type, populate);
+ IDP_AddToGroup(root, props);
+ }
+}
+
+static void collection_create_mode_settings(IDProperty *root, const bool populate)
+{
+ /* XXX TODO: put all those engines in the R_engines_settings_callbacks
+ * and have IDP_AddToGroup outside the callbacks */
+ layer_collection_create_mode_settings_object(root, populate);
+ layer_collection_create_mode_settings_edit(root, populate);
+ layer_collection_create_mode_settings_paint_weight(root, populate);
+ layer_collection_create_mode_settings_paint_vertex(root, populate);
+}
+
+static void layer_create_mode_settings(IDProperty *root, const bool populate)
+{
+ TODO_LAYER; /* XXX like collection_create_mode_settings */
+ UNUSED_VARS(root, populate);
+}
+
+static int idproperty_group_subtype(const int mode_type)
+{
+ int idgroup_type;
+
+ switch (mode_type) {
+ case COLLECTION_MODE_OBJECT:
+ idgroup_type = IDP_GROUP_SUB_MODE_OBJECT;
+ break;
+ case COLLECTION_MODE_EDIT:
+ idgroup_type = IDP_GROUP_SUB_MODE_EDIT;
+ break;
+ case COLLECTION_MODE_PAINT_WEIGHT:
+ idgroup_type = IDP_GROUP_SUB_MODE_PAINT_WEIGHT;
+ break;
+ case COLLECTION_MODE_PAINT_VERTEX:
+ idgroup_type = IDP_GROUP_SUB_MODE_PAINT_VERTEX;
+ break;
+ default:
+ case COLLECTION_MODE_NONE:
+ return IDP_GROUP_SUB_ENGINE_RENDER;
+ break;
+ }
+
+ return idgroup_type;
+}
+
+/**
+ * Return collection enginne settings for either Object s of LayerCollection s
+ */
+static IDProperty *collection_engine_get(
+ IDProperty *root, const int type, const char *engine_name)
+{
+ const int subtype = idproperty_group_subtype(type);
+
+ if (subtype == IDP_GROUP_SUB_ENGINE_RENDER) {
+ return IDP_GetPropertyFromGroup(root, engine_name);
+ }
+ else {
+ IDProperty *prop;
+ for (prop = root->data.group.first; prop; prop = prop->next) {
+ if (prop->subtype == subtype) {
+ return prop;
+ }
+ }
+ }
+
+ BLI_assert(false);
+ return NULL;
+}
+
+/**
+ * Return collection engine settings from Object for specified engine of mode
+ */
+IDProperty *BKE_layer_collection_engine_evaluated_get(Object *ob, const int type, const char *engine_name)
+{
+ return collection_engine_get(ob->base_collection_properties, type, engine_name);
+}
+/**
+ * Return layer collection engine settings for specified engine
+ */
+IDProperty *BKE_layer_collection_engine_collection_get(LayerCollection *lc, const int type, const char *engine_name)
+{
+ return collection_engine_get(lc->properties, type, engine_name);
+}
+
+/**
+ * Return layer collection engine settings for specified engine in the scene
+ */
+IDProperty *BKE_layer_collection_engine_scene_get(Scene *scene, const int type, const char *engine_name)
+{
+ return collection_engine_get(scene->collection_properties, type, engine_name);
+}
+
+/**
+ * Return scene layer engine settings for specified engine in the scene
+ */
+IDProperty *BKE_scene_layer_engine_scene_get(Scene *scene, const int type, const char *engine_name)
+{
+ return collection_engine_get(scene->layer_properties, type, engine_name);
+}
+
+/**
+ * Return scene layer engine settings for specified engine
+ */
+IDProperty *BKE_scene_layer_engine_layer_get(SceneLayer *sl, const int type, const char *engine_name)
+{
+ return collection_engine_get(sl->properties, type, engine_name);
+}
+
+/**
+ * Return scene layer evaluated engine settings for specified engine
+ */
+IDProperty *BKE_scene_layer_engine_evaluated_get(SceneLayer *sl, const int type, const char *engine_name)
+{
+ return collection_engine_get(sl->properties_evaluated, type, engine_name);
+}
+
+/* ---------------------------------------------------------------------- */
+/* Engine Settings Properties */
+
+void BKE_collection_engine_property_add_float(IDProperty *props, const char *name, float value)
+{
+ IDPropertyTemplate val = {0};
+ val.f = value;
+ IDP_AddToGroup(props, IDP_New(IDP_FLOAT, &val, name));
+}
+
+void BKE_collection_engine_property_add_float_array(
+ IDProperty *props, const char *name, const float *values, const int array_length)
+{
+ IDPropertyTemplate val = {0};
+ val.array.len = array_length;
+ val.array.type = IDP_FLOAT;
+
+ IDProperty *idprop= IDP_New(IDP_ARRAY, &val, name);
+ memcpy(IDP_Array(idprop), values, sizeof(float) * idprop->len);
+ IDP_AddToGroup(props, idprop);
+}
+
+void BKE_collection_engine_property_add_int(IDProperty *props, const char *name, int value)
+{
+ IDPropertyTemplate val = {0};
+ val.i = value;
+ IDP_AddToGroup(props, IDP_New(IDP_INT, &val, name));
+}
+
+void BKE_collection_engine_property_add_bool(IDProperty *props, const char *name, bool value)
+{
+ IDPropertyTemplate val = {0};
+ val.i = value;
+ IDP_AddToGroup(props, IDP_New(IDP_INT, &val, name));
+}
+
+int BKE_collection_engine_property_value_get_int(IDProperty *props, const char *name)
+{
+ IDProperty *idprop = IDP_GetPropertyFromGroup(props, name);
+ return idprop ? IDP_Int(idprop) : 0;
+}
+
+float BKE_collection_engine_property_value_get_float(IDProperty *props, const char *name)
+{
+ IDProperty *idprop = IDP_GetPropertyFromGroup(props, name);
+ return idprop ? IDP_Float(idprop) : 0.0f;
+}
+
+const float *BKE_collection_engine_property_value_get_float_array(IDProperty *props, const char *name)
+{
+ IDProperty *idprop = IDP_GetPropertyFromGroup(props, name);
+ return idprop ? IDP_Array(idprop) : NULL;
+}
+
+bool BKE_collection_engine_property_value_get_bool(IDProperty *props, const char *name)
+{
+ IDProperty *idprop = IDP_GetPropertyFromGroup(props, name);
+ return idprop ? IDP_Int(idprop) : 0;
+}
+
+void BKE_collection_engine_property_value_set_int(IDProperty *props, const char *name, int value)
+{
+ IDProperty *idprop = IDP_GetPropertyFromGroup(props, name);
+ IDP_Int(idprop) = value;
+}
+
+void BKE_collection_engine_property_value_set_float(IDProperty *props, const char *name, float value)
+{
+ IDProperty *idprop = IDP_GetPropertyFromGroup(props, name);
+ IDP_Float(idprop) = value;
+}
+
+void BKE_collection_engine_property_value_set_float_array(IDProperty *props, const char *name, const float *values)
+{
+ IDProperty *idprop = IDP_GetPropertyFromGroup(props, name);
+ memcpy(IDP_Array(idprop), values, sizeof(float) * idprop->len);
+}
+
+void BKE_collection_engine_property_value_set_bool(IDProperty *props, const char *name, bool value)
+{
+ IDProperty *idprop = IDP_GetPropertyFromGroup(props, name);
+ IDP_Int(idprop) = value;
+}
+
+/* Engine Settings recalculate */
+
+/* get all the default settings defined in scene and merge them here */
+static void collection_engine_settings_init(IDProperty *root, const bool populate)
+{
+ /* render engines */
+ layer_collection_create_render_settings(root, populate);
+
+ /* mode engines */
+ collection_create_mode_settings(root, populate);
+}
+
+/* get all the default settings defined in scene and merge them here */
+static void layer_engine_settings_init(IDProperty *root, const bool populate)
+{
+ /* render engines */
+ scene_layer_create_render_settings(root, populate);
+
+ /* mode engines */
+ layer_create_mode_settings(root, populate);
+}
+
+/**
+ * Initialize the layer collection render setings
+ * It's used mainly for scenes
+ */
+void BKE_layer_collection_engine_settings_create(IDProperty *root)
+{
+ collection_engine_settings_init(root, true);
+}
+
+/**
+ * Initialize the render setings
+ * It's used mainly for scenes
+ */
+void BKE_scene_layer_engine_settings_create(IDProperty *root)
+{
+ layer_engine_settings_init(root, true);
+}
+
+/**
+ * Reference of IDProperty group scene collection settings
+ * Used when reading blendfiles, to see if there is any missing settings.
+ */
+static struct {
+ struct {
+ IDProperty *collection_properties;
+ IDProperty *render_settings;
+ } scene;
+ IDProperty *scene_layer;
+ IDProperty *layer_collection;
+} root_reference = {
+ .scene = {NULL, NULL},
+ .scene_layer = NULL,
+ .layer_collection = NULL,
+};
+
+/**
+ * Free the reference scene collection settings IDProperty group.
+ */
+static void engine_settings_validate_init(void)
+{
+ IDPropertyTemplate val = {0};
+
+ /* LayerCollection engine settings. */
+ if (root_reference.scene.collection_properties == NULL) {
+ root_reference.scene.collection_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
+ collection_engine_settings_init(root_reference.scene.collection_properties, true);
+ }
+
+ if (root_reference.layer_collection == NULL) {
+ root_reference.layer_collection = IDP_New(IDP_GROUP, &val, ROOT_PROP);
+ collection_engine_settings_init(root_reference.layer_collection, false);
+ }
+
+ /* Render engine setting. */
+ if (root_reference.scene.render_settings == NULL) {
+ root_reference.scene.render_settings = IDP_New(IDP_GROUP, &val, ROOT_PROP);
+ layer_engine_settings_init(root_reference.scene.render_settings, true);
+ }
+
+ if (root_reference.scene_layer == NULL) {
+ root_reference.scene_layer = IDP_New(IDP_GROUP, &val, ROOT_PROP);
+ layer_engine_settings_init(root_reference.scene_layer, false);
+ }
+}
+
+/**
+ * Free the reference scene collection settings IDProperty group.
+ */
+static void layer_collection_engine_settings_validate_free(void)
+{
+ IDProperty *idprops[] = {
+ root_reference.scene.render_settings,
+ root_reference.scene.collection_properties,
+ root_reference.scene_layer,
+ root_reference.layer_collection,
+ NULL,
+ };
+
+ IDProperty **idprop = &idprops[0];
+ while (*idprop) {
+ if (*idprop) {
+ IDP_FreeProperty(*idprop);
+ MEM_freeN(*idprop);
+ *idprop = NULL;
+ idprop++;
+ }
+ }
+}
+
+/**
+ * Make sure Scene has all required collection settings.
+ */
+void BKE_layer_collection_engine_settings_validate_scene(Scene *scene)
+{
+ if (root_reference.scene.collection_properties == NULL) {
+ engine_settings_validate_init();
+ }
+
+ if (scene->collection_properties == NULL) {
+ IDPropertyTemplate val = {0};
+ scene->collection_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
+ BKE_layer_collection_engine_settings_create(scene->collection_properties);
+ }
+ else {
+ IDP_MergeGroup(scene->collection_properties, root_reference.scene.collection_properties, false);
+ }
+}
+
+/**
+ * Maker sure LayerCollection has all required collection settings.
+ */
+void BKE_layer_collection_engine_settings_validate_collection(LayerCollection *lc)
+{
+ if (root_reference.layer_collection == NULL) {
+ engine_settings_validate_init();
+ }
+
+ BLI_assert(lc->properties != NULL);
+ IDP_MergeGroup(lc->properties, root_reference.layer_collection, false);
+}
+
+/**
+ * Make sure Scene has all required collection settings.
+ */
+void BKE_scene_layer_engine_settings_validate_scene(Scene *scene)
+{
+ if (root_reference.scene.render_settings == NULL) {
+ engine_settings_validate_init();
+ }
+
+ if (scene->layer_properties == NULL) {
+ IDPropertyTemplate val = {0};
+ scene->layer_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
+ BKE_scene_layer_engine_settings_create(scene->layer_properties);
+ }
+ else {
+ IDP_MergeGroup(scene->layer_properties, root_reference.scene.render_settings, false);
+ }
+}
+
+/**
+ * Make sure Scene has all required collection settings.
+ */
+void BKE_scene_layer_engine_settings_validate_layer(SceneLayer *sl)
+{
+ if (root_reference.scene_layer == NULL) {
+ engine_settings_validate_init();
+ }
+
+ IDP_MergeGroup(sl->properties, root_reference.scene_layer, false);
+}
+
+/* ---------------------------------------------------------------------- */
+/* Iterators */
+
+static void object_bases_iterator_begin(BLI_Iterator *iter, void *data_in, const int flag)
+{
+ SceneLayer *sl = data_in;
+ Base *base = sl->object_bases.first;
+
+ /* when there are no objects */
+ if (base == NULL) {
+ iter->valid = false;
+ return;
+ }
+
+ iter->valid = true;
+ iter->data = base;
+
+ if ((base->flag & flag) == 0) {
+ object_bases_iterator_next(iter, flag);
+ }
+ else {
+ iter->current = base;
+ }
+}
+
+static void object_bases_iterator_next(BLI_Iterator *iter, const int flag)
+{
+ Base *base = ((Base *)iter->data)->next;
+
+ while (base) {
+ if ((base->flag & flag) != 0) {
+ iter->current = base;
+ iter->data = base;
+ return;
+ }
+ base = base->next;
+ }
+
+ iter->current = NULL;
+ iter->valid = false;
+}
+
+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;
+ }
+}
+
+void BKE_selected_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ objects_iterator_begin(iter, data_in, BASE_SELECTED);
+}
+
+void BKE_selected_objects_iterator_next(BLI_Iterator *iter)
+{
+ objects_iterator_next(iter, BASE_SELECTED);
+}
+
+void BKE_selected_objects_iterator_end(BLI_Iterator *UNUSED(iter))
+{
+ /* do nothing */
+}
+
+void BKE_visible_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ objects_iterator_begin(iter, data_in, BASE_VISIBLED);
+}
+
+void BKE_visible_objects_iterator_next(BLI_Iterator *iter)
+{
+ objects_iterator_next(iter, BASE_VISIBLED);
+}
+
+void BKE_visible_objects_iterator_end(BLI_Iterator *UNUSED(iter))
+{
+ /* do nothing */
+}
+
+void BKE_selected_bases_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ object_bases_iterator_begin(iter, data_in, BASE_SELECTED);
+}
+
+void BKE_selected_bases_iterator_next(BLI_Iterator *iter)
+{
+ object_bases_iterator_next(iter, BASE_SELECTED);
+}
+
+void BKE_selected_bases_iterator_end(BLI_Iterator *UNUSED(iter))
+{
+ /* do nothing */
+}
+
+void BKE_visible_bases_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ object_bases_iterator_begin(iter, data_in, BASE_VISIBLED);
+}
+
+void BKE_visible_bases_iterator_next(BLI_Iterator *iter)
+{
+ object_bases_iterator_next(iter, BASE_VISIBLED);
+}
+
+void BKE_visible_bases_iterator_end(BLI_Iterator *UNUSED(iter))
+{
+ /* do nothing */
+}
+
+/* Evaluation */
+
+/**
+ * Reset props
+ *
+ * If props_ref is pasted, copy props from it
+ */
+static void idproperty_reset(IDProperty **props, IDProperty *props_ref)
+{
+ IDPropertyTemplate val = {0};
+
+ if (*props) {
+ IDP_FreeProperty(*props);
+ MEM_freeN(*props);
+ }
+ *props = IDP_New(IDP_GROUP, &val, ROOT_PROP);
+
+ if (props_ref) {
+ IDP_MergeGroup(*props, props_ref, true);
+ }
+}
+
+void BKE_layer_eval_layer_collection_pre(struct EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene, SceneLayer *scene_layer)
+{
+ DEBUG_PRINT("%s on %s (%p)\n", __func__, scene_layer->name, scene_layer);
+ for (Base *base = scene_layer->object_bases.first; base != NULL; base = base->next) {
+ base->flag &= ~(BASE_VISIBLED | BASE_SELECTABLED);
+ idproperty_reset(&base->collection_properties, scene->collection_properties);
+ }
+
+ /* Sync properties from scene to scene layer. */
+ idproperty_reset(&scene_layer->properties_evaluated, scene->layer_properties);
+ IDP_MergeGroup(scene_layer->properties_evaluated, scene_layer->properties, true);
+
+ /* TODO(sergey): Is it always required? */
+ scene_layer->flag |= SCENE_LAYER_ENGINE_DIRTY;
+}
+
+void BKE_layer_eval_layer_collection(struct EvaluationContext *UNUSED(eval_ctx),
+ LayerCollection *layer_collection,
+ LayerCollection *parent_layer_collection)
+{
+ DEBUG_PRINT("%s on %s (%p), parent %s (%p)\n",
+ __func__,
+ layer_collection->scene_collection->name,
+ layer_collection->scene_collection,
+ (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection->name : "NONE",
+ (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection : NULL);
+
+ /* visibility */
+ layer_collection->flag_evaluated = layer_collection->flag;
+ bool is_visible = (layer_collection->flag & COLLECTION_VISIBLE) != 0;
+ bool is_selectable = is_visible && ((layer_collection->flag & COLLECTION_SELECTABLE) != 0);
+
+ if (parent_layer_collection != NULL) {
+ is_visible &= (parent_layer_collection->flag_evaluated & COLLECTION_VISIBLE) != 0;
+ is_selectable &= (parent_layer_collection->flag_evaluated & COLLECTION_SELECTABLE) != 0;
+ layer_collection->flag_evaluated &= parent_layer_collection->flag_evaluated;
+ }
+
+ /* overrides */
+ if (is_visible) {
+ if (parent_layer_collection == NULL) {
+ idproperty_reset(&layer_collection->properties_evaluated, layer_collection->properties);
+ }
+ else {
+ idproperty_reset(&layer_collection->properties_evaluated, parent_layer_collection->properties_evaluated);
+ IDP_MergeGroup(layer_collection->properties_evaluated, layer_collection->properties, true);
+ }
+ }
+
+ for (LinkData *link = layer_collection->object_bases.first; link != NULL; link = link->next) {
+ Base *base = link->data;
+
+ if (is_visible) {
+ IDP_MergeGroup(base->collection_properties, layer_collection->properties_evaluated, true);
+ base->flag |= BASE_VISIBLED;
+ }
+
+ if (is_selectable) {
+ base->flag |= BASE_SELECTABLED;
+ }
+ }
+}
+
+void BKE_layer_eval_layer_collection_post(struct EvaluationContext *UNUSED(eval_ctx),
+ SceneLayer *scene_layer)
+{
+ DEBUG_PRINT("%s on %s (%p)\n", __func__, scene_layer->name, scene_layer);
+ /* if base is not selectabled, clear select */
+ for (Base *base = scene_layer->object_bases.first; base; base = base->next) {
+ if ((base->flag & BASE_SELECTABLED) == 0) {
+ base->flag &= ~BASE_SELECTED;
+ }
+ }
+}
+
+/**
+ * Free any static allocated memory.
+ */
+void BKE_layer_exit(void)
+{
+ layer_collection_engine_settings_validate_free();
+}
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 6d94cd28b31..ed64de9b1aa 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -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,9 +71,15 @@
#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"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_memarena.h"
+#include "BLI_mempool.h"
+#include "BLI_string_utils.h"
#include "BLI_threads.h"
#include "BLT_translation.h"
@@ -86,7 +93,6 @@
#include "BKE_cachefile.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"
@@ -112,6 +118,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"
@@ -126,6 +133,14 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "atomic_ops.h"
+
+//#define DEBUG_TIME
+
+#ifdef DEBUG_TIME
+# include "PIL_time_utildefines.h"
+#endif
+
/* GS reads the memory pointed at in a specific ordering.
* only use this definition, makes little and big endian systems
* work fine, in conjunction with MAKE_ID */
@@ -258,10 +273,25 @@ void id_fake_user_clear(ID *id)
}
}
+void BKE_id_clear_newpoin(ID *id)
+{
+ if (id->newid) {
+ id->newid->tag &= ~LIB_TAG_NEW;
+ }
+ id->newid = NULL;
+}
+
static int id_expand_local_callback(
- void *UNUSED(user_data), struct ID *UNUSED(id_self), struct ID **id_pointer, int UNUSED(cd_flag))
+ void *UNUSED(user_data), struct ID *id_self, struct ID **id_pointer, int cb_flag)
{
- if (*id_pointer) {
+ if (cb_flag & IDWALK_CB_PRIVATE) {
+ return IDWALK_RET_NOP;
+ }
+
+ /* Can hapen that we get unlinkable ID here, e.g. with shapekey referring to itself (through drivers)...
+ * Just skip it, shape key can only be either indirectly linked, or fully local, period.
+ * And let's curse one more time that stupid useless shapekey ID type! */
+ if (*id_pointer && *id_pointer != id_self && BKE_idcode_is_linkable(GS((*id_pointer)->name))) {
id_lib_extern(*id_pointer);
}
@@ -271,18 +301,18 @@ static int id_expand_local_callback(
/**
* Expand ID usages of given id as 'extern' (and no more indirect) linked data. Used by ID copy/make_local functions.
*/
-void BKE_id_expand_local(ID *id)
+void BKE_id_expand_local(Main *bmain, ID *id)
{
- BKE_library_foreach_ID_link(id, id_expand_local_callback, NULL, 0);
+ BKE_library_foreach_ID_link(bmain, id, id_expand_local_callback, NULL, IDWALK_READONLY);
}
/**
* Ensure new (copied) ID is fully made local.
*/
-void BKE_id_copy_ensure_local(Main *bmain, ID *old_id, ID *new_id)
+void BKE_id_copy_ensure_local(Main *bmain, const ID *old_id, ID *new_id)
{
if (ID_IS_LINKED_DATABLOCK(old_id)) {
- BKE_id_expand_local(new_id);
+ BKE_id_expand_local(bmain, new_id);
BKE_id_lib_local_paths(bmain, old_id->lib, new_id);
}
}
@@ -309,7 +339,7 @@ void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, c
if (lib_local || is_local) {
if (!is_lib) {
id_clear_lib_data_ex(bmain, id, id_in_mainlist);
- BKE_id_expand_local(id);
+ BKE_id_expand_local(bmain, id);
}
else {
ID *id_new;
@@ -318,6 +348,17 @@ void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, c
if (id_copy(bmain, id, &id_new, false)) {
id_new->us = 0;
+ /* setting newid is mandatory for complex make_lib_local logic... */
+ ID_NEW_SET(id, id_new);
+ Key *key = BKE_key_from_id(id), *key_new = BKE_key_from_id(id);
+ if (key && key_new) {
+ ID_NEW_SET(key, key_new);
+ }
+ bNodeTree *ntree = ntreeFromID(id), *ntree_new = ntreeFromID(id_new);
+ if (ntree && ntree_new) {
+ ID_NEW_SET(ntree, ntree_new);
+ }
+
if (!lib_local) {
BKE_libblock_remap(bmain, id, id_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
@@ -329,6 +370,8 @@ void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, c
/**
* Calls the appropriate make_local method for the block, unless test is set.
*
+ * \note Always set ID->newid pointer in case it gets duplicated...
+ *
* \param lib_local Special flag used when making a whole library's content local, it needs specific handling.
*
* \return true if the block can be made local.
@@ -378,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 +477,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:
@@ -447,7 +497,7 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local)
* Invokes the appropriate copy method for the block and returns the result in
* newid, unless test. Returns true if the block can be copied.
*/
-bool id_copy(Main *bmain, ID *id, ID **newid, bool test)
+bool id_copy(Main *bmain, const ID *id, ID **newid, bool test)
{
if (!test) {
*newid = NULL;
@@ -487,6 +537,9 @@ bool id_copy(Main *bmain, ID *id, ID **newid, bool test)
case ID_SPK:
if (!test) *newid = (ID *)BKE_speaker_copy(bmain, (Speaker *)id);
return true;
+ case ID_LP:
+ if (!test) *newid = (ID *)BKE_lightprobe_copy(bmain, (LightProbe *)id);
+ return true;
case ID_CA:
if (!test) *newid = (ID *)BKE_camera_copy(bmain, (Camera *)id);
return true;
@@ -538,6 +591,7 @@ bool id_copy(Main *bmain, ID *id, ID **newid, bool test)
case ID_CF:
if (!test) *newid = (ID *)BKE_cachefile_copy(bmain, (CacheFile *)id);
return true;
+ case ID_WS:
case ID_SCE:
case ID_LI:
case ID_SCR:
@@ -553,6 +607,7 @@ bool id_copy(Main *bmain, ID *id, ID **newid, bool test)
return false;
}
+/** Does *not* set ID->newid pointer. */
bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
{
ID *newid = NULL;
@@ -563,11 +618,11 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
if (RNA_property_editable(ptr, prop)) {
if (id_copy(CTX_data_main(C), id, &newid, false) && newid) {
/* copy animation actions too */
- BKE_animdata_copy_id_action(id);
+ BKE_animdata_copy_id_action(id, false);
/* us is 1 by convention, but RNA_property_pointer_set
* will also increment it, so set it to zero */
newid->us = 0;
-
+
/* assign copy */
RNA_id_pointer_create(newid, &idptr);
RNA_property_pointer_set(ptr, prop, idptr);
@@ -622,6 +677,8 @@ ListBase *which_libbase(Main *mainlib, short type)
return &(mainlib->text);
case ID_SPK:
return &(mainlib->speaker);
+ case ID_LP:
+ return &(mainlib->lightprobe);
case ID_SO:
return &(mainlib->sound);
case ID_GR:
@@ -652,6 +709,8 @@ ListBase *which_libbase(Main *mainlib, short type)
return &(mainlib->paintcurves);
case ID_CF:
return &(mainlib->cachefiles);
+ case ID_WS:
+ return &(mainlib->workspaces);
}
return NULL;
}
@@ -737,11 +796,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_DATABLOCK(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);
+ DEG_id_type_tag(bmain, ID_OB);
}
/**
@@ -790,6 +849,7 @@ int set_listbasepointers(Main *main, ListBase **lb)
lb[INDEX_ID_BR] = &(main->brush);
lb[INDEX_ID_PA] = &(main->particle);
lb[INDEX_ID_SPK] = &(main->speaker);
+ lb[INDEX_ID_LP] = &(main->lightprobe);
lb[INDEX_ID_WO] = &(main->world);
lb[INDEX_ID_MC] = &(main->movieclip);
@@ -797,6 +857,7 @@ int set_listbasepointers(Main *main, ListBase **lb)
lb[INDEX_ID_OB] = &(main->object);
lb[INDEX_ID_LS] = &(main->linestyle); /* referenced by scenes */
lb[INDEX_ID_SCE] = &(main->scene);
+ lb[INDEX_ID_WS] = &(main->workspaces); /* before wm, so it's freed after it! */
lb[INDEX_ID_WM] = &(main->wm);
lb[INDEX_ID_MSK] = &(main->mask);
@@ -816,118 +877,74 @@ int set_listbasepointers(Main *main, ListBase **lb)
* **************************** */
/**
+ * Get allocation size fo a given datablock type and optionally allocation name.
+ */
+size_t BKE_libblock_get_alloc_info(short type, const char **name)
+{
+#define CASE_RETURN(id_code, type) \
+ case id_code: \
+ do { \
+ if (name != NULL) { \
+ *name = #type; \
+ } \
+ return sizeof(type); \
+ } while(0)
+
+ switch ((ID_Type)type) {
+ CASE_RETURN(ID_SCE, Scene);
+ CASE_RETURN(ID_LI, Library);
+ CASE_RETURN(ID_OB, Object);
+ CASE_RETURN(ID_ME, Mesh);
+ CASE_RETURN(ID_CU, Curve);
+ CASE_RETURN(ID_MB, MetaBall);
+ CASE_RETURN(ID_MA, Material);
+ CASE_RETURN(ID_TE, Tex);
+ CASE_RETURN(ID_IM, Image);
+ CASE_RETURN(ID_LT, Lattice);
+ CASE_RETURN(ID_LA, Lamp);
+ CASE_RETURN(ID_CA, Camera);
+ CASE_RETURN(ID_IP, Ipo);
+ CASE_RETURN(ID_KE, Key);
+ CASE_RETURN(ID_WO, World);
+ CASE_RETURN(ID_SCR, bScreen);
+ 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_AR, bArmature);
+ CASE_RETURN(ID_AC, bAction);
+ CASE_RETURN(ID_NT, bNodeTree);
+ CASE_RETURN(ID_BR, Brush);
+ CASE_RETURN(ID_PA, ParticleSettings);
+ CASE_RETURN(ID_WM, wmWindowManager);
+ CASE_RETURN(ID_GD, bGPdata);
+ CASE_RETURN(ID_MC, MovieClip);
+ CASE_RETURN(ID_MSK, Mask);
+ CASE_RETURN(ID_LS, FreestyleLineStyle);
+ 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
+}
+
+/**
* Allocates and returns memory of the right size for the specified block type,
* initialized to zero.
*/
void *BKE_libblock_alloc_notest(short type)
{
- ID *id = NULL;
-
- switch ((ID_Type)type) {
- case ID_SCE:
- id = MEM_callocN(sizeof(Scene), "scene");
- break;
- case ID_LI:
- id = MEM_callocN(sizeof(Library), "library");
- break;
- case ID_OB:
- id = MEM_callocN(sizeof(Object), "object");
- break;
- case ID_ME:
- id = MEM_callocN(sizeof(Mesh), "mesh");
- break;
- case ID_CU:
- id = MEM_callocN(sizeof(Curve), "curve");
- break;
- case ID_MB:
- id = MEM_callocN(sizeof(MetaBall), "mball");
- break;
- case ID_MA:
- id = MEM_callocN(sizeof(Material), "mat");
- break;
- case ID_TE:
- id = MEM_callocN(sizeof(Tex), "tex");
- break;
- case ID_IM:
- id = MEM_callocN(sizeof(Image), "image");
- break;
- case ID_LT:
- id = MEM_callocN(sizeof(Lattice), "latt");
- break;
- case ID_LA:
- id = MEM_callocN(sizeof(Lamp), "lamp");
- break;
- case ID_CA:
- id = MEM_callocN(sizeof(Camera), "camera");
- break;
- case ID_IP:
- id = MEM_callocN(sizeof(Ipo), "ipo");
- break;
- case ID_KE:
- id = MEM_callocN(sizeof(Key), "key");
- break;
- case ID_WO:
- id = MEM_callocN(sizeof(World), "world");
- break;
- case ID_SCR:
- id = MEM_callocN(sizeof(bScreen), "screen");
- break;
- case ID_VF:
- id = MEM_callocN(sizeof(VFont), "vfont");
- break;
- case ID_TXT:
- id = MEM_callocN(sizeof(Text), "text");
- break;
- case ID_SPK:
- id = MEM_callocN(sizeof(Speaker), "speaker");
- break;
- case ID_SO:
- id = MEM_callocN(sizeof(bSound), "sound");
- break;
- case ID_GR:
- id = MEM_callocN(sizeof(Group), "group");
- break;
- case ID_AR:
- id = MEM_callocN(sizeof(bArmature), "armature");
- break;
- case ID_AC:
- id = MEM_callocN(sizeof(bAction), "action");
- break;
- case ID_NT:
- id = MEM_callocN(sizeof(bNodeTree), "nodetree");
- break;
- case ID_BR:
- id = MEM_callocN(sizeof(Brush), "brush");
- break;
- case ID_PA:
- id = MEM_callocN(sizeof(ParticleSettings), "ParticleSettings");
- break;
- case ID_WM:
- id = MEM_callocN(sizeof(wmWindowManager), "Window manager");
- break;
- case ID_GD:
- id = MEM_callocN(sizeof(bGPdata), "Grease Pencil");
- break;
- case ID_MC:
- id = MEM_callocN(sizeof(MovieClip), "Movie Clip");
- break;
- case ID_MSK:
- id = MEM_callocN(sizeof(Mask), "Mask");
- break;
- case ID_LS:
- id = MEM_callocN(sizeof(FreestyleLineStyle), "Freestyle Line Style");
- break;
- case ID_PAL:
- id = MEM_callocN(sizeof(Palette), "Palette");
- break;
- case ID_PC:
- id = MEM_callocN(sizeof(PaintCurve), "Paint Curve");
- break;
- case ID_CF:
- id = MEM_callocN(sizeof(CacheFile), "Cache File");
- break;
+ const char *name;
+ size_t size = BKE_libblock_get_alloc_info(type, &name);
+ if (size != 0) {
+ return MEM_callocN(size, name);
}
- return id;
+ BLI_assert(!"Request to allocate unknown data type");
+ return NULL;
}
/**
@@ -952,7 +969,7 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name)
/* alphabetic insertion: is in new_id */
BKE_main_unlock(bmain);
}
- DAG_id_type_tag(bmain, type);
+ DEG_id_type_tag(bmain, type);
return id;
}
@@ -1004,6 +1021,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;
@@ -1096,7 +1116,7 @@ void BKE_libblock_copy_data(ID *id, const ID *id_from, const bool do_action)
}
/* used everywhere in blenkernel */
-void *BKE_libblock_copy(Main *bmain, ID *id)
+void *BKE_libblock_copy(Main *bmain, const ID *id)
{
ID *idn;
size_t idn_len;
@@ -1112,16 +1132,13 @@ void *BKE_libblock_copy(Main *bmain, ID *id)
memcpy(cpn + sizeof(ID), cp + sizeof(ID), idn_len - sizeof(ID));
}
-
- id->newid = idn;
- idn->tag |= LIB_TAG_NEW;
BKE_libblock_copy_data(idn, id, false);
return idn;
}
-void *BKE_libblock_copy_nolib(ID *id, const bool do_action)
+void *BKE_libblock_copy_nolib(const ID *id, const bool do_action)
{
ID *idn;
size_t idn_len;
@@ -1139,8 +1156,6 @@ void *BKE_libblock_copy_nolib(ID *id, const bool do_action)
memcpy(cpn + sizeof(ID), cp + sizeof(ID), idn_len - sizeof(ID));
}
- id->newid = idn;
- idn->tag |= LIB_TAG_NEW;
idn->us = 1;
BKE_libblock_copy_data(idn, id, do_action);
@@ -1148,31 +1163,6 @@ void *BKE_libblock_copy_nolib(ID *id, const bool do_action)
return idn;
}
-static int id_relink_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int cd_flag)
-{
- ID *id = *id_pointer;
- if (id) {
- /* See: NEW_ID macro */
- if (id->newid) {
- BKE_library_update_ID_link_user(id->newid, id, cd_flag);
- *id_pointer = id->newid;
- }
- else if (id->tag & LIB_TAG_NEW) {
- id->tag &= ~LIB_TAG_NEW;
- BKE_libblock_relink(id);
- }
- }
- return IDWALK_RET_NOP;
-}
-
-void BKE_libblock_relink(ID *id)
-{
- if (ID_IS_LINKED_DATABLOCK(id))
- return;
-
- BKE_library_foreach_ID_link(id, id_relink_looper, NULL, 0);
-}
-
void BKE_library_free(Library *lib)
{
if (lib->packedfile)
@@ -1203,7 +1193,7 @@ void BKE_main_free(Main *mainvar)
while ( (id = lb->first) ) {
#if 1
- BKE_libblock_free_ex(mainvar, id, false);
+ 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 */
@@ -1251,6 +1241,10 @@ void BKE_main_free(Main *mainvar)
}
}
+ 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);
@@ -1267,6 +1261,78 @@ 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.
*
@@ -1407,7 +1473,8 @@ static ID *is_dupid(ListBase *lb, ID *id, const char *name)
static bool check_for_dupid(ListBase *lb, ID *id, char *name)
{
ID *idtest;
- int nr = 0, a, left_len;
+ int nr = 0, a;
+ size_t left_len;
#define MAX_IN_USE 64
bool in_use[MAX_IN_USE];
/* to speed up finding unused numbers within [1 .. MAX_IN_USE - 1] */
@@ -1431,14 +1498,18 @@ static bool check_for_dupid(ListBase *lb, ID *id, char *name)
/* if new name will be too long, truncate it */
if (nr > 999 && left_len > (MAX_ID_NAME - 8)) { /* assumption: won't go beyond 9999 */
- left[MAX_ID_NAME - 8] = 0;
+ left[MAX_ID_NAME - 8] = '\0';
left_len = MAX_ID_NAME - 8;
}
else if (left_len > (MAX_ID_NAME - 7)) {
- left[MAX_ID_NAME - 7] = 0;
+ left[MAX_ID_NAME - 7] = '\0';
left_len = MAX_ID_NAME - 7;
}
+ /* Code above may have generated invalid utf-8 string, due to raw truncation.
+ * Ensure we get a valid one now! */
+ left_len -= (size_t)BLI_utf8_invalid_strip(left, left_len);
+
for (idtest = lb->first; idtest; idtest = idtest->next) {
int nrtest;
if ( (id != idtest) &&
@@ -1479,7 +1550,7 @@ static bool check_for_dupid(ListBase *lb, ID *id, char *name)
* shave off the end chars until we have a unique name.
* Check the null terminators match as well so we don't get Cube.000 -> Cube.00 */
if (nr == 0 && name[left_len] == '\0') {
- int len;
+ size_t len;
/* FIXME: this code will never be executed, because either nr will be
* at least 1, or name will not end at left_len! */
BLI_assert(0);
@@ -1592,15 +1663,6 @@ void id_clear_lib_data_ex(Main *bmain, ID *id, const bool id_in_mainlist)
if ((key = BKE_key_from_id(id))) {
id_clear_lib_data_ex(bmain, &key->id, id_in_mainlist); /* sigh, why are keys in Main? */
}
-
- if (GS(id->name) == ID_OB) {
- Object *object = (Object *)id;
- if (object->proxy_from != NULL) {
- object->proxy_from->proxy = NULL;
- object->proxy_from->proxy_group = NULL;
- }
- object->proxy = object->proxy_from = object->proxy_group = NULL;
- }
}
void id_clear_lib_data(Main *bmain, ID *id)
@@ -1626,6 +1688,62 @@ void BKE_main_id_clear_newpoins(Main *bmain)
}
}
+
+static void library_make_local_copying_check(ID *id, GSet *loop_tags, MainIDRelations *id_relations, GSet *done_ids)
+{
+ if (BLI_gset_haskey(done_ids, id)) {
+ return; /* Already checked, nothing else to do. */
+ }
+
+ MainIDRelationsEntry *entry = BLI_ghash_lookup(id_relations->id_used_to_user, id);
+ BLI_gset_insert(loop_tags, id);
+ for (; entry != NULL; entry = entry->next) {
+ ID *par_id = (ID *)entry->id_pointer; /* used_to_user stores ID pointer, not pointer to ID pointer... */
+
+ /* Our oh-so-beloved 'from' pointers... */
+ if (entry->usage_flag & IDWALK_CB_LOOPBACK) {
+ /* We totally disregard Object->proxy_from 'usage' here, this one would only generate fake positives. */
+ if (GS(par_id->name) == ID_OB) {
+ BLI_assert(((Object *)par_id)->proxy_from == (Object *)id);
+ continue;
+ }
+
+ /* Shapekeys are considered 'private' to their owner ID here, and never tagged (since they cannot be linked),
+ * so we have to switch effective parent to their owner. */
+ if (GS(par_id->name) == ID_KE) {
+ par_id = ((Key *)par_id)->from;
+ }
+ }
+
+ if (par_id->lib == NULL) {
+ /* Local user, early out to avoid some gset querying... */
+ continue;
+ }
+ if (!BLI_gset_haskey(done_ids, par_id)) {
+ if (BLI_gset_haskey(loop_tags, par_id)) {
+ /* We are in a 'dependency loop' of IDs, this does not say us anything, skip it.
+ * Note that this is the situation that can lead to archipelagoes of linked data-blocks
+ * (since all of them have non-local users, they would all be duplicated, leading to a loop of unused
+ * linked data-blocks that cannot be freed since they all use each other...). */
+ continue;
+ }
+ /* Else, recursively check that user ID. */
+ library_make_local_copying_check(par_id, loop_tags, id_relations, done_ids);
+ }
+
+ if (par_id->tag & LIB_TAG_DOIT) {
+ /* This user will be fully local in future, so far so good, nothing to do here but check next user. */
+ }
+ else {
+ /* This user won't be fully local in future, so current ID won't be either. And we are done checking it. */
+ id->tag &= ~LIB_TAG_DOIT;
+ break;
+ }
+ }
+ BLI_gset_add(done_ids, id);
+ BLI_gset_remove(loop_tags, id, NULL);
+}
+
/** Make linked datablocks local.
*
* \param bmain Almost certainly G.main.
@@ -1633,26 +1751,39 @@ void BKE_main_id_clear_newpoins(Main *bmain)
* \param untagged_only If true, only make local datablocks not tagged with LIB_TAG_PRE_EXISTING.
* \param set_fake If true, set fake user on all localized datablocks (except group and objects ones).
*/
-/* XXX TODO This function should probably be reworked.
- *
- * Old (2.77) version was simply making (tagging) datablocks as local, without actually making any check whether
+/* Note: Old (2.77) version was simply making (tagging) datablocks as local, without actually making any check whether
* they were also indirectly used or not...
*
- * Current version uses regular id_make_local callback, but this is not super-efficient since this ends up
- * duplicating some IDs and then removing original ones (due to missing knowledge of which ID uses some other ID).
- *
- * We could first check all IDs and detect those to be made local that are only used by other local or future-local
- * datablocks, and directly tag those as local (instead of going through id_make_local) maybe...
- *
- * We'll probably need at some point a true dependency graph between datablocks, but for now this should work
- * good enough (performances is not a critical point here anyway).
+ * Current version uses regular id_make_local callback, with advanced pre-processing step to detect all cases of
+ * IDs currently indirectly used, but which will be used by local data only once this function is finished.
+ * This allows to avoid any uneeded duplication of IDs, and hence all time lost afterwards to remove
+ * orphaned linked data-blocks...
*/
-void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged_only, const bool set_fake)
+void BKE_library_make_local(
+ Main *bmain, const Library *lib, GHash *old_to_new_ids, const bool untagged_only, const bool set_fake)
{
ListBase *lbarray[MAX_LIBARRAY];
- ID *id, *id_next;
+ ID *id;
int a;
+ LinkNode *todo_ids = NULL;
+ LinkNode *copied_ids = NULL;
+ MemArena *linklist_mem = BLI_memarena_new(512 * sizeof(*todo_ids), __func__);
+
+ GSet *done_ids = BLI_gset_ptr_new(__func__);
+
+#ifdef DEBUG_TIME
+ TIMEIT_START(make_local);
+#endif
+
+ BKE_main_relations_create(bmain);
+
+#ifdef DEBUG_TIME
+ printf("Pre-compute current ID relations: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
+#endif
+
+ /* Step 1: Detect datablocks to make local. */
for (a = set_listbasepointers(bmain, lbarray); a--; ) {
id = lbarray[a]->first;
@@ -1660,69 +1791,349 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged
* by real datablocks responsible of them. */
const bool do_skip = (id && !BKE_idcode_is_linkable(GS(id->name)));
- for (; id; id = id_next) {
- id->newid = NULL;
- id_next = id->next; /* id is possibly being inserted again */
-
- /* The check on the second line (LIB_TAG_PRE_EXISTING) is done so its
- * possible to tag data you don't want to be made local, used for
- * appending data, so any libdata already linked wont become local
- * (very nasty to discover all your links are lost after appending)
- * */
- if (!do_skip && id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) &&
- ((untagged_only == false) || !(id->tag & LIB_TAG_PRE_EXISTING)))
+ for (; id; id = id->next) {
+ ID *ntree = (ID *)ntreeFromID(id);
+
+ id->tag &= ~LIB_TAG_DOIT;
+ if (ntree != NULL) {
+ ntree->tag &= ~LIB_TAG_DOIT;
+ }
+
+ if (id->lib == NULL) {
+ id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW);
+ }
+ /* The check on the fourth line (LIB_TAG_PRE_EXISTING) is done so its possible to tag data you don't want to
+ * be made local, used for appending data, so any libdata already linked wont become local (very nasty
+ * to discover all your links are lost after appending).
+ * Also, never ever make proxified objects local, would not make any sense. */
+ /* Some more notes:
+ * - Shapekeys are never tagged here (since they are not linkable).
+ * - Nodetrees used in materials etc. have to be tagged manually, since they do not exist in Main (!).
+ * This is ok-ish on 'make local' side of things (since those are handled by their 'owner' IDs),
+ * but complicates slightly the pre-processing of relations between IDs at step 2... */
+ else if (!do_skip && id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) &&
+ ELEM(lib, NULL, id->lib) &&
+ !(GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) &&
+ ((untagged_only == false) || !(id->tag & LIB_TAG_PRE_EXISTING)))
{
- if (lib == NULL || id->lib == lib) {
- if (id->lib) {
- /* In this specific case, we do want to make ID local even if it has no local usage yet... */
- id_make_local(bmain, id, false, true);
- }
- else {
- id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW);
- }
- }
+ BLI_linklist_prepend_arena(&todo_ids, id, linklist_mem);
+ id->tag |= LIB_TAG_DOIT;
- if (set_fake) {
- if (!ELEM(GS(id->name), ID_OB, ID_GR)) {
- /* do not set fake user on objects, groups (instancing) */
- id_fake_user_set(id);
- }
+ /* Tag those nasty non-ID nodetrees, but do not add them to todo list, making them local is handled
+ * by 'owner' ID. This is needed for library_make_local_copying_check() to work OK at step 2. */
+ if (ntree != NULL) {
+ ntree->tag |= LIB_TAG_DOIT;
}
}
+ else {
+ /* Linked ID that we won't be making local (needed info for step 2, see below). */
+ BLI_gset_add(done_ids, id);
+ }
}
}
- /* We have to remap local usages of old (linked) ID to new (local) id in a second loop, as lbarray ordering is not
- * enough to ensure us we did catch all dependencies (e.g. if making local a parent object before its child...).
- * See T48907. */
- for (a = set_listbasepointers(bmain, lbarray); a--; ) {
- for (id = lbarray[a]->first; id; id = id->next) {
+#ifdef DEBUG_TIME
+ printf("Step 1: Detect datablocks to make local: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
+#endif
+
+ /* Step 2: Check which datablocks we can directly make local (because they are only used by already, or future,
+ * local data), others will need to be duplicated. */
+ GSet *loop_tags = BLI_gset_ptr_new(__func__);
+ for (LinkNode *it = todo_ids; it; it = it->next) {
+ library_make_local_copying_check(it->link, loop_tags, bmain->relations, done_ids);
+ BLI_assert(BLI_gset_size(loop_tags) == 0);
+ }
+ BLI_gset_free(loop_tags, NULL);
+ BLI_gset_free(done_ids, NULL);
+
+ /* Next step will most likely add new IDs, better to get rid of this mapping now. */
+ BKE_main_relations_free(bmain);
+
+#ifdef DEBUG_TIME
+ printf("Step 2: Check which datablocks we can directly make local: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
+#endif
+
+ /* Step 3: Make IDs local, either directly (quick and simple), or using generic process,
+ * which involves more complex checks and might instead create a local copy of original linked ID. */
+ for (LinkNode *it = todo_ids, *it_next; it; it = it_next) {
+ it_next = it->next;
+ id = it->link;
+
+ if (id->tag & LIB_TAG_DOIT) {
+ /* We know all users of this object are local or will be made fully local, even if currently there are
+ * some indirect usages. So instead of making a copy that we'll likely get rid of later, directly make
+ * that data block local. Saves a tremendous amount of time with complex scenes... */
+ id_clear_lib_data_ex(bmain, id, true);
+ BKE_id_expand_local(bmain, id);
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+ else {
+ /* In this specific case, we do want to make ID local even if it has no local usage yet... */
+ if (GS(id->name) == ID_OB) {
+ /* Special case for objects because we don't want proxy pointers to be
+ * cleared yet. This will happen down the road in this function.
+ */
+ BKE_object_make_local_ex(bmain, (Object *)id, true, false);
+ }
+ else {
+ id_make_local(bmain, id, false, true);
+ }
+
if (id->newid) {
- BKE_libblock_remap(bmain, id, id->newid, ID_REMAP_SKIP_INDIRECT_USAGE);
+ /* Reuse already allocated LinkNode (transferring it from todo_ids to copied_ids). */
+ BLI_linklist_prepend_nlink(&copied_ids, id, it);
+ }
+ }
+
+ if (set_fake) {
+ if (!ELEM(GS(id->name), ID_OB, ID_GR)) {
+ /* do not set fake user on objects, groups (instancing) */
+ id_fake_user_set(id);
+ }
+ }
+ }
+
+#ifdef DEBUG_TIME
+ printf("Step 3: Make IDs local: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
+#endif
+
+ /* At this point, we are done with directly made local IDs. Now we have to handle duplicated ones, since their
+ * remaining linked original counterpart may not be needed anymore... */
+ todo_ids = NULL;
+
+ /* Step 4: We have to remap local usages of old (linked) ID to new (local) ID in a separated loop,
+ * as lbarray ordering is not enough to ensure us we did catch all dependencies
+ * (e.g. if making local a parent object before its child...). See T48907. */
+ /* TODO This is now the biggest step by far (in term of processing time). We may be able to gain here by
+ * using again main->relations mapping, but... this implies BKE_libblock_remap & co to be able to update
+ * main->relations on the fly. Have to think about it a bit more, and see whether new code is OK first, anyway. */
+ for (LinkNode *it = copied_ids; it; it = it->next) {
+ id = it->link;
+
+ BLI_assert(id->newid != NULL);
+ BLI_assert(id->lib != NULL);
+
+ BKE_libblock_remap(bmain, id, id->newid, ID_REMAP_SKIP_INDIRECT_USAGE);
+ if (old_to_new_ids) {
+ BLI_ghash_insert(old_to_new_ids, id, id->newid);
+ }
+
+ /* Special hack for groups... Thing is, since we can't instantiate them here, we need to ensure
+ * they remain 'alive' (only instantiation is a real group 'user'... *sigh* See T49722. */
+ if (GS(id->name) == ID_GR && (id->tag & LIB_TAG_INDIRECT) != 0) {
+ id_us_ensure_real(id->newid);
+ }
+ }
+
+#ifdef DEBUG_TIME
+ printf("Step 4: Remap local usages of old (linked) ID to new (local) ID: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
+#endif
+
+ /* Note: Keeping both version of the code (old one being safer, since it still has checks against unused IDs)
+ * for now, we can remove old one once it has been tested for some time in master... */
+#if 1
+ /* Step 5: proxy 'remapping' hack. */
+ for (LinkNode *it = copied_ids; it; it = it->next) {
+ /* Attempt to re-link copied proxy objects. This allows appending of an entire scene
+ * from another blend file into this one, even when that blend file contains proxified
+ * armatures that have local references. Since the proxified object needs to be linked
+ * (not local), this will only work when the "Localize all" checkbox is disabled.
+ * TL;DR: this is a dirty hack on top of an already weak feature (proxies). */
+ if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) {
+ Object *ob = (Object *)id;
+ Object *ob_new = (Object *)id->newid;
+ bool is_local = false, is_lib = false;
+
+ /* Proxies only work when the proxified object is linked-in from a library. */
+ if (ob->proxy->id.lib == NULL) {
+ printf("Warning, proxy object %s will loose its link to %s, because the "
+ "proxified object is local.\n", id->newid->name, ob->proxy->id.name);
+ continue;
+ }
+
+ BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
+
+ /* We can only switch the proxy'ing to a made-local proxy if it is no longer
+ * referred to from a library. Not checking for local use; if new local proxy
+ * was not used locally would be a nasty bug! */
+ if (is_local || is_lib) {
+ printf("Warning, made-local proxy object %s will loose its link to %s, "
+ "because the linked-in proxy is referenced (is_local=%i, is_lib=%i).\n",
+ id->newid->name, ob->proxy->id.name, is_local, is_lib);
+ }
+ else {
+ /* we can switch the proxy'ing from the linked-in to the made-local proxy.
+ * BKE_object_make_proxy() shouldn't be used here, as it allocates memory that
+ * was already allocated by BKE_object_make_local_ex() (which called BKE_object_copy_ex). */
+ ob_new->proxy = ob->proxy;
+ ob_new->proxy_group = ob->proxy_group;
+ ob_new->proxy_from = ob->proxy_from;
+ ob_new->proxy->proxy_from = ob_new;
+ ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
}
}
}
- /* Third step: remove datablocks that have been copied to be localized and are no more used in the end...
+#ifdef DEBUG_TIME
+ printf("Step 5: Proxy 'remapping' hack: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
+#endif
+
+#else
+ LinkNode *linked_loop_candidates = NULL;
+
+ /* Step 5: remove datablocks that have been copied to be localized and are no more used in the end...
* Note that we may have to loop more than once here, to tackle dependencies between linked objects... */
bool do_loop = true;
while (do_loop) {
do_loop = false;
- for (a = set_listbasepointers(bmain, lbarray); a--; ) {
- for (id = lbarray[a]->first; id; id = id_next) {
- id_next = id->next;
- if (id->newid) {
- bool is_local = false, is_lib = false;
-
- BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
- if (!is_local && !is_lib) {
- BKE_libblock_free(bmain, id);
- do_loop = true;
+ for (LinkNode *it = copied_ids; it; it = it->next) {
+ if ((id = it->link) == NULL) {
+ continue;
+ }
+
+ bool is_local = false, is_lib = false;
+
+ BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
+
+ /* Attempt to re-link copied proxy objects. This allows appending of an entire scene
+ * from another blend file into this one, even when that blend file contains proxified
+ * armatures that have local references. Since the proxified object needs to be linked
+ * (not local), this will only work when the "Localize all" checkbox is disabled.
+ * TL;DR: this is a dirty hack on top of an already weak feature (proxies). */
+ if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) {
+ Object *ob = (Object *)id;
+ Object *ob_new = (Object *)id->newid;
+
+ /* Proxies only work when the proxified object is linked-in from a library. */
+ if (ob->proxy->id.lib == NULL) {
+ printf("Warning, proxy object %s will loose its link to %s, because the "
+ "proxified object is local.\n", id->newid->name, ob->proxy->id.name);
+ }
+ /* We can only switch the proxy'ing to a made-local proxy if it is no longer
+ * referred to from a library. Not checking for local use; if new local proxy
+ * was not used locally would be a nasty bug! */
+ else if (is_local || is_lib) {
+ printf("Warning, made-local proxy object %s will loose its link to %s, "
+ "because the linked-in proxy is referenced (is_local=%i, is_lib=%i).\n",
+ id->newid->name, ob->proxy->id.name, is_local, is_lib);
+ }
+ else {
+ /* we can switch the proxy'ing from the linked-in to the made-local proxy.
+ * BKE_object_make_proxy() shouldn't be used here, as it allocates memory that
+ * was already allocated by BKE_object_make_local_ex() (which called BKE_object_copy_ex). */
+ ob_new->proxy = ob->proxy;
+ ob_new->proxy_group = ob->proxy_group;
+ ob_new->proxy_from = ob->proxy_from;
+ ob_new->proxy->proxy_from = ob_new;
+ ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
+ }
+ }
+
+ if (!is_local) {
+ if (!is_lib) { /* Not used at all, we can free it! */
+ BLI_assert(!"Unused linked data copy remaining from MakeLibLocal process, should not happen anymore");
+ printf("\t%s (from %s)\n", id->name, id->lib->id.name);
+ BKE_libblock_free(bmain, id);
+ it->link = NULL;
+ do_loop = true;
+ }
+ /* Only used by linked data, potential candidate to ugly lib-only dependency cycles... */
+ else if ((id->tag & LIB_TAG_DOIT) == 0) { /* Check TAG_DOIT to avoid adding same ID several times... */
+ /* Note that we store the node, not directly ID pointer, that way if it->link is set to NULL
+ * later we can skip it in lib-dependency cycles search later. */
+ BLI_linklist_prepend_arena(&linked_loop_candidates, it, linklist_mem);
+ id->tag |= LIB_TAG_DOIT;
+
+ /* Grrrrrrr... those half-datablocks-stuff... grrrrrrrrrrr...
+ * Here we have to also tag them as potential candidates, otherwise they would falsy report
+ * ID they used as 'directly used' in sixth step. */
+ ID *ntree = (ID *)ntreeFromID(id);
+ if (ntree != NULL) {
+ ntree->tag |= LIB_TAG_DOIT;
}
}
}
}
}
+
+#ifdef DEBUG_TIME
+ printf("Step 5: Remove linked datablocks that have been copied and ended fully localized: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
+#endif
+
+ /* Step 6: Try to find circle dependencies between indirectly-linked-only datablocks.
+ * Those are fake 'usages' that prevent their deletion. See T49775 for nice ugly case. */
+ BKE_library_unused_linked_data_set_tag(bmain, false);
+ for (LinkNode *it = linked_loop_candidates; it; it = it->next) {
+ if (it->link == NULL) {
+ continue;
+ }
+ if ((id = ((LinkNode *)it->link)->link) == NULL) {
+ it->link = NULL;
+ continue;
+ }
+
+ /* Note: in theory here we are only handling datablocks forming exclusive linked dependency-cycles-based
+ * archipelagos, so no need to check again after we have deleted one, as done in previous step. */
+ if (id->tag & LIB_TAG_DOIT) {
+ BLI_assert(!"Unused linked data copy remaining from MakeLibLocal process (archipelago case), should not happen anymore");
+ /* Object's deletion rely on valid ob->data, but ob->data may have already been freed here...
+ * Setting it to NULL may not be 100% correct, but should be safe and do the work. */
+ if (GS(id->name) == ID_OB) {
+ ((Object *)id)->data = NULL;
+ }
+
+ /* Note: *in theory* IDs tagged here are fully *outside* of file scope, totally unused, so we can
+ * directly wipe them out without caring about clearing their usages.
+ * However, this is a highly-risky presumption, and nice crasher in case something goes wrong here.
+ * So for 2.78a will keep the safe option, and switch to more efficient one in master later. */
+#if 1
+ BKE_libblock_free_ex(bmain, id, false, true);
+#else
+ BKE_libblock_unlink(bmain, id, false, false);
+ BKE_libblock_free(bmain, id);
+#endif
+ ((LinkNode *)it->link)->link = NULL; /* Not strictly necessary, but safer (see T49903)... */
+ it->link = NULL;
+ }
+ }
+
+#ifdef DEBUG_TIME
+ printf("Step 6: Try to find circle dependencies between indirectly-linked-only datablocks: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
+#endif
+
+#endif
+
+ /* This is probably more of a hack than something we should do here, but...
+ * Issue is, the whole copying + remapping done in complex cases above may leave pose channels of armatures
+ * in complete invalid state (more precisely, the bone pointers of the pchans - very crappy cross-datablocks
+ * relationship), se we tag it to be fully recomputed, but this does not seems to be enough in some cases,
+ * and evaluation code ends up trying to evaluate a not-yet-updated armature object's deformations.
+ * 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);
+ }
+ }
+
+#ifdef DEBUG_TIME
+ printf("Hack: Forcefully rebuild armature object poses: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
+#endif
+
+ BKE_main_id_clear_newpoins(bmain);
+ BLI_memarena_free(linklist_mem);
+
+#ifdef DEBUG_TIME
+ printf("Cleanup and finish: Done.\n");
+ TIMEIT_END(make_local);
+#endif
}
/**
@@ -1790,3 +2201,13 @@ void BKE_library_filepath_set(Library *lib, const char *filepath)
BLI_path_abs(lib->filepath, basepath);
}
}
+
+void BKE_id_tag_set_atomic(ID *id, int tag)
+{
+ atomic_fetch_and_or_uint32((uint32_t *)&id->tag, tag);
+}
+
+void BKE_id_tag_clear_atomic(ID *id, int tag)
+{
+ atomic_fetch_and_and_uint32((uint32_t *)&id->tag, ~tag);
+}
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index cb864334208..e397dcf7667 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -33,6 +33,7 @@
#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_constraint_types.h"
@@ -51,6 +52,7 @@
#include "DNA_mask_types.h"
#include "DNA_node_types.h"
#include "DNA_object_force.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
#include "DNA_sensor_types.h"
@@ -60,6 +62,8 @@
#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"
@@ -68,27 +72,34 @@
#include "BLI_linklist_stack.h"
#include "BKE_animsys.h"
+#include "BKE_collection.h"
#include "BKE_constraint.h"
#include "BKE_fcurve.h"
+#include "BKE_idprop.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
+#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
-#define FOREACH_FINALIZE_VOID FOREACH_FINALIZE: (void)0
+#define FOREACH_FINALIZE_VOID \
+ if (0) { goto FOREACH_FINALIZE; } \
+ FOREACH_FINALIZE: ((void)0)
-#define FOREACH_CALLBACK_INVOKE_ID_PP(_data, id_pp, cb_flag) \
+#define FOREACH_CALLBACK_INVOKE_ID_PP(_data, id_pp, _cb_flag) \
+ CHECK_TYPE(id_pp, ID **); \
if (!((_data)->status & IDWALK_STOP)) { \
const int _flag = (_data)->flag; \
ID *old_id = *(id_pp); \
- const int callback_return = (_data)->callback((_data)->user_data, (_data)->self_id, id_pp, cb_flag | (_data)->cd_flag); \
+ const int callback_return = (_data)->callback((_data)->user_data, (_data)->self_id, id_pp, _cb_flag | (_data)->cb_flag); \
if (_flag & IDWALK_READONLY) { \
BLI_assert(*(id_pp) == old_id); \
} \
@@ -129,7 +140,7 @@ enum {
typedef struct LibraryForeachIDData {
ID *self_id;
int flag;
- int cd_flag;
+ int cb_flag;
LibraryIDLinkCallback callback;
void *user_data;
int status;
@@ -139,20 +150,51 @@ typedef struct LibraryForeachIDData {
BLI_LINKSTACK_DECLARE(ids_todo, ID *);
} LibraryForeachIDData;
+static void library_foreach_idproperty_ID_link(LibraryForeachIDData *data, IDProperty *prop, int flag)
+{
+ if (!prop)
+ return;
+
+ switch (prop->type) {
+ case IDP_GROUP:
+ {
+ for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) {
+ library_foreach_idproperty_ID_link(data, loop, flag);
+ }
+ break;
+ }
+ case IDP_IDPARRAY:
+ {
+ IDProperty *loop = IDP_Array(prop);
+ for (int i = 0; i < prop->len; i++) {
+ library_foreach_idproperty_ID_link(data, &loop[i], flag);
+ }
+ break;
+ }
+ case IDP_ID:
+ FOREACH_CALLBACK_INVOKE_ID(data, prop->data.pointer, flag);
+ break;
+ default:
+ break; /* Nothing to do here with other types of IDProperties... */
+ }
+
+ FOREACH_FINALIZE_VOID;
+}
+
static void library_foreach_rigidbodyworldSceneLooper(
- struct RigidBodyWorld *UNUSED(rbw), ID **id_pointer, void *user_data, int cd_flag)
+ struct RigidBodyWorld *UNUSED(rbw), ID **id_pointer, void *user_data, int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
FOREACH_FINALIZE_VOID;
}
static void library_foreach_modifiersForeachIDLink(
- void *user_data, Object *UNUSED(object), ID **id_pointer, int cd_flag)
+ 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, cd_flag);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
FOREACH_FINALIZE_VOID;
}
@@ -161,44 +203,44 @@ static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), ID
bool is_reference, void *user_data)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- const int cd_flag = is_reference ? IDWALK_USER : IDWALK_NOP;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+ 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 cd_flag)
+ 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, cd_flag);
+ 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 cd_flag)
+ bSensor *UNUSED(sensor), ID **id_pointer, void *user_data, int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
FOREACH_FINALIZE_VOID;
}
static void library_foreach_controllersObjectLooper(
- bController *UNUSED(controller), ID **id_pointer, void *user_data, int cd_flag)
+ bController *UNUSED(controller), ID **id_pointer, void *user_data, int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+ 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 cd_flag)
+ bActuator *UNUSED(actuator), ID **id_pointer, void *user_data, int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
FOREACH_FINALIZE_VOID;
}
@@ -207,7 +249,7 @@ static void library_foreach_nla_strip(LibraryForeachIDData *data, NlaStrip *stri
{
NlaStrip *substrip;
- FOREACH_CALLBACK_INVOKE(data, strip->act, IDWALK_USER);
+ FOREACH_CALLBACK_INVOKE(data, strip->act, IDWALK_CB_USER);
for (substrip = strip->strips.first; substrip; substrip = substrip->next) {
library_foreach_nla_strip(data, substrip);
@@ -230,14 +272,14 @@ static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *
/* only used targets */
DRIVER_TARGETS_USED_LOOPER(dvar)
{
- FOREACH_CALLBACK_INVOKE_ID(data, dtar->id, IDWALK_NOP);
+ FOREACH_CALLBACK_INVOKE_ID(data, dtar->id, IDWALK_CB_NOP);
}
DRIVER_TARGETS_LOOPER_END
}
}
- FOREACH_CALLBACK_INVOKE(data, adt->action, IDWALK_USER);
- FOREACH_CALLBACK_INVOKE(data, adt->tmpact, IDWALK_USER);
+ FOREACH_CALLBACK_INVOKE(data, adt->action, IDWALK_CB_USER);
+ FOREACH_CALLBACK_INVOKE(data, adt->tmpact, IDWALK_CB_USER);
for (nla_track = adt->nla_tracks.first; nla_track; nla_track = nla_track->next) {
for (nla_strip = nla_track->strips.first; nla_strip; nla_strip = nla_strip->next) {
@@ -250,27 +292,60 @@ static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *
static void library_foreach_mtex(LibraryForeachIDData *data, MTex *mtex)
{
- FOREACH_CALLBACK_INVOKE(data, mtex->object, IDWALK_NOP);
- FOREACH_CALLBACK_INVOKE(data, mtex->tex, IDWALK_USER);
+ FOREACH_CALLBACK_INVOKE(data, mtex->object, IDWALK_CB_NOP);
+ FOREACH_CALLBACK_INVOKE(data, mtex->tex, IDWALK_CB_USER);
FOREACH_FINALIZE_VOID;
}
static void library_foreach_paint(LibraryForeachIDData *data, Paint *paint)
{
- FOREACH_CALLBACK_INVOKE(data, paint->brush, IDWALK_USER);
- FOREACH_CALLBACK_INVOKE(data, paint->palette, IDWALK_USER);
+ FOREACH_CALLBACK_INVOKE(data, paint->brush, IDWALK_CB_USER);
+ FOREACH_CALLBACK_INVOKE(data, paint->palette, IDWALK_CB_USER);
FOREACH_FINALIZE_VOID;
}
+static void library_foreach_bone(LibraryForeachIDData *data, Bone *bone)
+{
+ library_foreach_idproperty_ID_link(data, bone->prop, IDWALK_CB_USER);
+
+ for (Bone *curbone = bone->childbase.first; curbone; curbone = curbone->next) {
+ library_foreach_bone(data, curbone);
+ }
+
+ FOREACH_FINALIZE_VOID;
+}
+
+static void library_foreach_ID_as_subdata_link(
+ ID **id_pp, LibraryIDLinkCallback callback, void *user_data, int flag, LibraryForeachIDData *data)
+{
+ /* Needed e.g. for callbacks handling relationships... This call shall be absolutely readonly. */
+ ID *id = *id_pp;
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pp, IDWALK_CB_PRIVATE);
+ BLI_assert(id == *id_pp);
+
+ if (flag & IDWALK_RECURSE) {
+ /* Defer handling into main loop, recursively calling BKE_library_foreach_ID_link in IDWALK_RECURSE case is
+ * troublesome, see T49553. */
+ if (!BLI_gset_haskey(data->ids_handled, id)) {
+ BLI_gset_add(data->ids_handled, id);
+ BLI_LINKSTACK_PUSH(data->ids_todo, id);
+ }
+ }
+ else {
+ BKE_library_foreach_ID_link(NULL, id, callback, user_data, flag);
+ }
+
+ FOREACH_FINALIZE_VOID;
+}
/**
* Loop over all of the ID's this datablock links to.
*
* \note: May be extended to be recursive in the future.
*/
-void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *user_data, int flag)
+void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback callback, void *user_data, int flag)
{
LibraryForeachIDData data;
int i;
@@ -281,6 +356,8 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
data.ids_handled = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
BLI_LINKSTACK_INIT(data.ids_todo);
+
+ BLI_gset_add(data.ids_handled, id);
}
else {
data.ids_handled = NULL;
@@ -296,9 +373,23 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
#define CALLBACK_INVOKE(check_id_super, cb_flag) \
FOREACH_CALLBACK_INVOKE(&data, check_id_super, cb_flag)
- do {
+ for (; id != NULL; id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL) {
data.self_id = id;
- data.cd_flag = ID_IS_LINKED_DATABLOCK(id) ? IDWALK_INDIRECT_USAGE : 0;
+ data.cb_flag = ID_IS_LINKED_DATABLOCK(id) ? IDWALK_CB_INDIRECT_USAGE : 0;
+
+ if (bmain != NULL && bmain->relations != NULL && (flag & IDWALK_READONLY)) {
+ /* Note that this is minor optimization, even in worst cases (like id being an object with lots of
+ * drivers and constraints and modifiers, or material etc. with huge node tree),
+ * but we might as well use it (Main->relations is always assumed valid, it's responsability of code
+ * creating it to free it, especially if/when it starts modifying Main database). */
+ MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->id_user_to_used, id);
+ for (; entry != NULL; entry = entry->next) {
+ FOREACH_CALLBACK_INVOKE_ID_PP(&data, entry->id_pointer, entry->usage_flag);
+ }
+ continue;
+ }
+
+ library_foreach_idproperty_ID_link(&data, id->properties, IDWALK_CB_USER);
AnimData *adt = BKE_animdata_from_id(id);
if (adt) {
@@ -309,7 +400,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_LI:
{
Library *lib = (Library *) id;
- CALLBACK_INVOKE(lib->parent, IDWALK_NOP);
+ CALLBACK_INVOKE(lib->parent, IDWALK_CB_NOP);
break;
}
case ID_SCE:
@@ -317,41 +408,41 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
Scene *scene = (Scene *) id;
ToolSettings *toolsett = scene->toolsettings;
SceneRenderLayer *srl;
- Base *base;
+ BaseLegacy *legacy_base;
- CALLBACK_INVOKE(scene->camera, IDWALK_NOP);
- CALLBACK_INVOKE(scene->world, IDWALK_USER);
- CALLBACK_INVOKE(scene->set, IDWALK_NOP);
- CALLBACK_INVOKE(scene->clip, IDWALK_USER);
+ CALLBACK_INVOKE(scene->camera, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(scene->world, IDWALK_CB_USER);
+ CALLBACK_INVOKE(scene->set, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(scene->clip, IDWALK_CB_USER);
if (scene->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- BKE_library_foreach_ID_link((ID *)scene->nodetree, callback, user_data, flag);
+ 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_NOP);
+ 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_USER);
+ CALLBACK_INVOKE(srl->mat_override, IDWALK_CB_USER);
}
if (srl->light_override) {
- CALLBACK_INVOKE(srl->light_override, IDWALK_USER);
+ 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_NOP);
+ 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_USER);
+ CALLBACK_INVOKE(fls->group, IDWALK_CB_USER);
}
if (fls->linestyle) {
- CALLBACK_INVOKE(fls->linestyle, IDWALK_USER);
+ CALLBACK_INVOKE(fls->linestyle, IDWALK_CB_USER);
}
}
}
@@ -360,35 +451,59 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
Sequence *seq;
SEQP_BEGIN(scene->ed, seq)
{
- CALLBACK_INVOKE(seq->scene, IDWALK_NOP);
- CALLBACK_INVOKE(seq->scene_camera, IDWALK_NOP);
- CALLBACK_INVOKE(seq->clip, IDWALK_USER);
- CALLBACK_INVOKE(seq->mask, IDWALK_USER);
- CALLBACK_INVOKE(seq->sound, IDWALK_USER);
+ CALLBACK_INVOKE(seq->scene, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(seq->scene_camera, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(seq->clip, IDWALK_CB_USER);
+ CALLBACK_INVOKE(seq->mask, IDWALK_CB_USER);
+ CALLBACK_INVOKE(seq->sound, IDWALK_CB_USER);
+ library_foreach_idproperty_ID_link(&data, seq->prop, IDWALK_CB_USER);
for (SequenceModifierData *smd = seq->modifiers.first; smd; smd = smd->next) {
- CALLBACK_INVOKE(smd->mask_id, IDWALK_USER);
+ CALLBACK_INVOKE(smd->mask_id, IDWALK_CB_USER);
}
}
SEQ_END
}
- CALLBACK_INVOKE(scene->gpd, IDWALK_USER);
+ CALLBACK_INVOKE(scene->gpd, IDWALK_CB_USER);
+
+ for (legacy_base = scene->base.first; legacy_base; legacy_base = legacy_base->next) {
+ CALLBACK_INVOKE(legacy_base->object, IDWALK_CB_USER);
+ }
+
+ FOREACH_SCENE_COLLECTION(scene, sc)
+ {
+ for (LinkData *link = sc->objects.first; link; link = link->next) {
+ CALLBACK_INVOKE_ID(link->data, IDWALK_CB_USER);
+ }
+
+ for (LinkData *link = sc->filter_objects.first; link; link = link->next) {
+ CALLBACK_INVOKE_ID(link->data, IDWALK_CB_USER);
+ }
+ }
+ FOREACH_SCENE_COLLECTION_END
+
+ SceneLayer *sl;
+ for (sl = scene->render_layers.first; sl; sl = sl->next) {
+ for (Base *base = sl->object_bases.first; base; base = base->next) {
+ CALLBACK_INVOKE(base->object, IDWALK_NOP);
+ }
+ }
- for (base = scene->base.first; base; base = base->next) {
- CALLBACK_INVOKE(base->object, IDWALK_USER);
+ for (TimeMarker *marker = scene->markers.first; marker; marker = marker->next) {
+ CALLBACK_INVOKE(marker->camera, IDWALK_CB_NOP);
}
if (toolsett) {
- CALLBACK_INVOKE(toolsett->skgen_template, IDWALK_NOP);
+ CALLBACK_INVOKE(toolsett->skgen_template, IDWALK_CB_NOP);
- CALLBACK_INVOKE(toolsett->particle.scene, IDWALK_NOP);
- CALLBACK_INVOKE(toolsett->particle.object, IDWALK_NOP);
- CALLBACK_INVOKE(toolsett->particle.shape_object, IDWALK_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);
library_foreach_paint(&data, &toolsett->imapaint.paint);
- CALLBACK_INVOKE(toolsett->imapaint.stencil, IDWALK_USER);
- CALLBACK_INVOKE(toolsett->imapaint.clone, IDWALK_USER);
- CALLBACK_INVOKE(toolsett->imapaint.canvas, IDWALK_USER);
+ CALLBACK_INVOKE(toolsett->imapaint.stencil, IDWALK_CB_USER);
+ CALLBACK_INVOKE(toolsett->imapaint.clone, IDWALK_CB_USER);
+ CALLBACK_INVOKE(toolsett->imapaint.canvas, IDWALK_CB_USER);
if (toolsett->vpaint) {
library_foreach_paint(&data, &toolsett->vpaint->paint);
@@ -398,7 +513,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
if (toolsett->sculpt) {
library_foreach_paint(&data, &toolsett->sculpt->paint);
- CALLBACK_INVOKE(toolsett->sculpt->gravity_object, IDWALK_NOP);
+ CALLBACK_INVOKE(toolsett->sculpt->gravity_object, IDWALK_CB_NOP);
}
if (toolsett->uvsculpt) {
library_foreach_paint(&data, &toolsett->uvsculpt->paint);
@@ -409,7 +524,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
BKE_rigidbody_world_id_loop(scene->rigidbody_world, library_foreach_rigidbodyworldSceneLooper, &data);
}
- CALLBACK_INVOKE(scene->gm.dome.warptext, IDWALK_NOP);
+ CALLBACK_INVOKE(scene->gm.dome.warptext, IDWALK_CB_NOP);
break;
}
@@ -420,75 +535,77 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
ParticleSystem *psys;
/* Object is special, proxies make things hard... */
- const int data_cd_flag = data.cd_flag;
- const int proxy_cd_flag = (object->proxy || object->proxy_group) ? IDWALK_INDIRECT_USAGE : 0;
+ const int data_cb_flag = data.cb_flag;
+ const int proxy_cb_flag = ((data.flag & IDWALK_NO_INDIRECT_PROXY_DATA_USAGE) == 0 && (object->proxy || object->proxy_group)) ?
+ IDWALK_CB_INDIRECT_USAGE : 0;
/* object data special case */
- data.cd_flag |= proxy_cd_flag;
+ data.cb_flag |= proxy_cb_flag;
if (object->type == OB_EMPTY) {
/* empty can have NULL or Image */
- CALLBACK_INVOKE_ID(object->data, IDWALK_USER);
+ CALLBACK_INVOKE_ID(object->data, IDWALK_CB_USER);
}
else {
/* when set, this can't be NULL */
if (object->data) {
- CALLBACK_INVOKE_ID(object->data, IDWALK_USER | IDWALK_NEVER_NULL);
+ CALLBACK_INVOKE_ID(object->data, IDWALK_CB_USER | IDWALK_CB_NEVER_NULL);
}
}
- data.cd_flag = data_cd_flag;
+ data.cb_flag = data_cb_flag;
- CALLBACK_INVOKE(object->parent, IDWALK_NOP);
- CALLBACK_INVOKE(object->track, IDWALK_NOP);
+ CALLBACK_INVOKE(object->parent, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(object->track, IDWALK_CB_NOP);
/* object->proxy is refcounted, but not object->proxy_group... *sigh* */
- CALLBACK_INVOKE(object->proxy, IDWALK_USER);
- CALLBACK_INVOKE(object->proxy_group, IDWALK_NOP);
+ CALLBACK_INVOKE(object->proxy, IDWALK_CB_USER);
+ CALLBACK_INVOKE(object->proxy_group, IDWALK_CB_NOP);
/* Special case!
* Since this field is set/owned by 'user' of this ID (and not ID itself), it is only indirect usage
* if proxy object is linked... Twisted. */
if (object->proxy_from) {
- data.cd_flag = ID_IS_LINKED_DATABLOCK(object->proxy_from) ? IDWALK_INDIRECT_USAGE : 0;
+ data.cb_flag = ID_IS_LINKED_DATABLOCK(object->proxy_from) ? IDWALK_CB_INDIRECT_USAGE : 0;
}
- CALLBACK_INVOKE(object->proxy_from, IDWALK_NOP);
- data.cd_flag = data_cd_flag;
+ CALLBACK_INVOKE(object->proxy_from, IDWALK_CB_LOOPBACK);
+ data.cb_flag = data_cb_flag;
- CALLBACK_INVOKE(object->poselib, IDWALK_USER);
+ CALLBACK_INVOKE(object->poselib, IDWALK_CB_USER);
- data.cd_flag |= proxy_cd_flag;
+ data.cb_flag |= proxy_cb_flag;
for (i = 0; i < object->totcol; i++) {
- CALLBACK_INVOKE(object->mat[i], IDWALK_USER);
+ CALLBACK_INVOKE(object->mat[i], IDWALK_CB_USER);
}
- data.cd_flag = data_cd_flag;
+ data.cb_flag = data_cb_flag;
- CALLBACK_INVOKE(object->gpd, IDWALK_USER);
- CALLBACK_INVOKE(object->dup_group, IDWALK_USER);
+ CALLBACK_INVOKE(object->gpd, IDWALK_CB_USER);
+ CALLBACK_INVOKE(object->dup_group, IDWALK_CB_USER);
if (object->pd) {
- CALLBACK_INVOKE(object->pd->tex, IDWALK_USER);
- CALLBACK_INVOKE(object->pd->f_source, IDWALK_NOP);
+ CALLBACK_INVOKE(object->pd->tex, IDWALK_CB_USER);
+ CALLBACK_INVOKE(object->pd->f_source, IDWALK_CB_NOP);
}
/* Note that ob->effect is deprecated, so no need to handle it here. */
if (object->pose) {
bPoseChannel *pchan;
- data.cd_flag |= proxy_cd_flag;
+ data.cb_flag |= proxy_cb_flag;
for (pchan = object->pose->chanbase.first; pchan; pchan = pchan->next) {
- CALLBACK_INVOKE(pchan->custom, IDWALK_USER);
+ library_foreach_idproperty_ID_link(&data, pchan->prop, IDWALK_CB_USER);
+ CALLBACK_INVOKE(pchan->custom, IDWALK_CB_USER);
BKE_constraints_id_loop(&pchan->constraints, library_foreach_constraintObjectLooper, &data);
}
- data.cd_flag = data_cd_flag;
+ data.cb_flag = data_cb_flag;
}
if (object->rigidbody_constraint) {
- CALLBACK_INVOKE(object->rigidbody_constraint->ob1, IDWALK_NOP);
- CALLBACK_INVOKE(object->rigidbody_constraint->ob2, IDWALK_NOP);
+ CALLBACK_INVOKE(object->rigidbody_constraint->ob1, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(object->rigidbody_constraint->ob2, IDWALK_CB_NOP);
}
if (object->lodlevels.first) {
LodLevel *level;
for (level = object->lodlevels.first; level; level = level->next) {
- CALLBACK_INVOKE(level->source, IDWALK_NOP);
+ CALLBACK_INVOKE(level->source, IDWALK_CB_NOP);
}
}
@@ -500,10 +617,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
if (object->soft) {
- CALLBACK_INVOKE(object->soft->collision_group, IDWALK_NOP);
+ CALLBACK_INVOKE(object->soft->collision_group, IDWALK_CB_NOP);
if (object->soft->effector_weights) {
- CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_NOP);
+ CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_CB_NOP);
}
}
@@ -513,38 +630,23 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
break;
}
+ case ID_AR:
+ {
+ bArmature *arm = (bArmature *)id;
+
+ for (Bone *bone = arm->bonebase.first; bone; bone = bone->next) {
+ library_foreach_bone(&data, bone);
+ }
+ break;
+ }
+
case ID_ME:
{
Mesh *mesh = (Mesh *) id;
- CALLBACK_INVOKE(mesh->texcomesh, IDWALK_USER);
- CALLBACK_INVOKE(mesh->key, IDWALK_USER);
+ CALLBACK_INVOKE(mesh->texcomesh, IDWALK_CB_USER);
+ CALLBACK_INVOKE(mesh->key, IDWALK_CB_USER);
for (i = 0; i < mesh->totcol; i++) {
- CALLBACK_INVOKE(mesh->mat[i], IDWALK_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_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_USER_ONE);
- }
- }
- }
+ CALLBACK_INVOKE(mesh->mat[i], IDWALK_CB_USER);
}
break;
}
@@ -552,17 +654,17 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_CU:
{
Curve *curve = (Curve *) id;
- CALLBACK_INVOKE(curve->bevobj, IDWALK_NOP);
- CALLBACK_INVOKE(curve->taperobj, IDWALK_NOP);
- CALLBACK_INVOKE(curve->textoncurve, IDWALK_NOP);
- CALLBACK_INVOKE(curve->key, IDWALK_USER);
+ CALLBACK_INVOKE(curve->bevobj, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(curve->taperobj, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(curve->textoncurve, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(curve->key, IDWALK_CB_USER);
for (i = 0; i < curve->totcol; i++) {
- CALLBACK_INVOKE(curve->mat[i], IDWALK_USER);
+ CALLBACK_INVOKE(curve->mat[i], IDWALK_CB_USER);
}
- CALLBACK_INVOKE(curve->vfont, IDWALK_USER);
- CALLBACK_INVOKE(curve->vfontb, IDWALK_USER);
- CALLBACK_INVOKE(curve->vfonti, IDWALK_USER);
- CALLBACK_INVOKE(curve->vfontbi, IDWALK_USER);
+ CALLBACK_INVOKE(curve->vfont, IDWALK_CB_USER);
+ CALLBACK_INVOKE(curve->vfontb, IDWALK_CB_USER);
+ CALLBACK_INVOKE(curve->vfonti, IDWALK_CB_USER);
+ CALLBACK_INVOKE(curve->vfontbi, IDWALK_CB_USER);
break;
}
@@ -570,7 +672,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
{
MetaBall *metaball = (MetaBall *) id;
for (i = 0; i < metaball->totcol; i++) {
- CALLBACK_INVOKE(metaball->mat[i], IDWALK_USER);
+ CALLBACK_INVOKE(metaball->mat[i], IDWALK_CB_USER);
}
break;
}
@@ -585,9 +687,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
if (material->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- BKE_library_foreach_ID_link((ID *)material->nodetree, callback, user_data, flag);
+ library_foreach_ID_as_subdata_link((ID **)&material->nodetree, callback, user_data, flag, &data);
}
- CALLBACK_INVOKE(material->group, IDWALK_USER);
+ CALLBACK_INVOKE(material->group, IDWALK_CB_USER);
+ CALLBACK_INVOKE(material->edit_image, IDWALK_CB_USER);
break;
}
@@ -596,26 +699,26 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
Tex *texture = (Tex *) id;
if (texture->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- BKE_library_foreach_ID_link((ID *)texture->nodetree, callback, user_data, flag);
+ library_foreach_ID_as_subdata_link((ID **)&texture->nodetree, callback, user_data, flag, &data);
}
- CALLBACK_INVOKE(texture->ima, IDWALK_USER);
+ CALLBACK_INVOKE(texture->ima, IDWALK_CB_USER);
if (texture->env) {
- CALLBACK_INVOKE(texture->env->object, IDWALK_NOP);
- CALLBACK_INVOKE(texture->env->ima, IDWALK_USER);
+ 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_NOP);
+ CALLBACK_INVOKE(texture->pd->object, IDWALK_CB_NOP);
if (texture->vd)
- CALLBACK_INVOKE(texture->vd->object, IDWALK_NOP);
+ CALLBACK_INVOKE(texture->vd->object, IDWALK_CB_NOP);
if (texture->ot)
- CALLBACK_INVOKE(texture->ot->object, IDWALK_NOP);
+ CALLBACK_INVOKE(texture->ot->object, IDWALK_CB_NOP);
break;
}
case ID_LT:
{
Lattice *lattice = (Lattice *) id;
- CALLBACK_INVOKE(lattice->key, IDWALK_USER);
+ CALLBACK_INVOKE(lattice->key, IDWALK_CB_USER);
break;
}
@@ -629,7 +732,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
if (lamp->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- BKE_library_foreach_ID_link((ID *)lamp->nodetree, callback, user_data, flag);
+ library_foreach_ID_as_subdata_link((ID **)&lamp->nodetree, callback, user_data, flag, &data);
}
break;
}
@@ -637,25 +740,14 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_CA:
{
Camera *camera = (Camera *) id;
- CALLBACK_INVOKE(camera->dof_ob, IDWALK_NOP);
+ CALLBACK_INVOKE(camera->dof_ob, IDWALK_CB_NOP);
break;
}
case ID_KE:
{
- /* XXX Only ID pointer from shapekeys is the 'from' one, which is not actually ID usage.
- * Maybe we should even nuke it from here, not 100% sure yet...
- * (see also foreach_libblock_id_users_callback).
- */
Key *key = (Key *) id;
- CALLBACK_INVOKE_ID(key->from, IDWALK_NOP);
- break;
- }
-
- case ID_SCR:
- {
- bScreen *screen = (bScreen *) id;
- CALLBACK_INVOKE(screen->scene, IDWALK_USER_ONE);
+ CALLBACK_INVOKE_ID(key->from, IDWALK_CB_LOOPBACK);
break;
}
@@ -669,7 +761,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
if (world->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- BKE_library_foreach_ID_link((ID *)world->nodetree, callback, user_data, flag);
+ library_foreach_ID_as_subdata_link((ID **)&world->nodetree, callback, user_data, flag, &data);
}
break;
}
@@ -677,7 +769,14 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_SPK:
{
Speaker *speaker = (Speaker *) id;
- CALLBACK_INVOKE(speaker->sound, IDWALK_USER);
+ CALLBACK_INVOKE(speaker->sound, IDWALK_CB_USER);
+ break;
+ }
+
+ case ID_LP:
+ {
+ LightProbe *probe = (LightProbe *) id;
+ CALLBACK_INVOKE(probe->image, IDWALK_CB_USER);
break;
}
@@ -686,7 +785,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
Group *group = (Group *) id;
GroupObject *gob;
for (gob = group->gobject.first; gob; gob = gob->next) {
- CALLBACK_INVOKE(gob->ob, IDWALK_USER_ONE);
+ CALLBACK_INVOKE(gob->ob, IDWALK_CB_USER_ONE);
}
break;
}
@@ -695,9 +794,27 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
{
bNodeTree *ntree = (bNodeTree *) id;
bNode *node;
- CALLBACK_INVOKE(ntree->gpd, IDWALK_USER);
+ bNodeSocket *sock;
+
+ CALLBACK_INVOKE(ntree->gpd, IDWALK_CB_USER);
+
for (node = ntree->nodes.first; node; node = node->next) {
- CALLBACK_INVOKE_ID(node->id, IDWALK_USER);
+ CALLBACK_INVOKE_ID(node->id, IDWALK_CB_USER);
+
+ library_foreach_idproperty_ID_link(&data, node->prop, IDWALK_CB_USER);
+ for (sock = node->inputs.first; sock; sock = sock->next) {
+ library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
+ }
+ for (sock = node->outputs.first; sock; sock = sock->next) {
+ library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
+ }
+ }
+
+ for (sock = ntree->inputs.first; sock; sock = sock->next) {
+ library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
+ }
+ for (sock = ntree->outputs.first; sock; sock = sock->next) {
+ library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
}
break;
}
@@ -705,9 +822,9 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_BR:
{
Brush *brush = (Brush *) id;
- CALLBACK_INVOKE(brush->toggle_brush, IDWALK_NOP);
- CALLBACK_INVOKE(brush->clone.image, IDWALK_NOP);
- CALLBACK_INVOKE(brush->paint_curve, IDWALK_USER);
+ CALLBACK_INVOKE(brush->toggle_brush, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(brush->clone.image, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(brush->paint_curve, IDWALK_CB_USER);
library_foreach_mtex(&data, &brush->mtex);
library_foreach_mtex(&data, &brush->mask_mtex);
break;
@@ -716,10 +833,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_PA:
{
ParticleSettings *psett = (ParticleSettings *) id;
- CALLBACK_INVOKE(psett->dup_group, IDWALK_NOP);
- CALLBACK_INVOKE(psett->dup_ob, IDWALK_NOP);
- CALLBACK_INVOKE(psett->bb_ob, IDWALK_NOP);
- CALLBACK_INVOKE(psett->collision_group, IDWALK_NOP);
+ CALLBACK_INVOKE(psett->dup_group, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(psett->dup_ob, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(psett->bb_ob, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(psett->collision_group, IDWALK_CB_NOP);
for (i = 0; i < MAX_MTEX; i++) {
if (psett->mtex[i]) {
@@ -728,16 +845,16 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
if (psett->effector_weights) {
- CALLBACK_INVOKE(psett->effector_weights->group, IDWALK_NOP);
+ CALLBACK_INVOKE(psett->effector_weights->group, IDWALK_CB_NOP);
}
if (psett->pd) {
- CALLBACK_INVOKE(psett->pd->tex, IDWALK_USER);
- CALLBACK_INVOKE(psett->pd->f_source, IDWALK_NOP);
+ CALLBACK_INVOKE(psett->pd->tex, IDWALK_CB_USER);
+ CALLBACK_INVOKE(psett->pd->f_source, IDWALK_CB_NOP);
}
if (psett->pd2) {
- CALLBACK_INVOKE(psett->pd2->tex, IDWALK_USER);
- CALLBACK_INVOKE(psett->pd2->f_source, IDWALK_NOP);
+ CALLBACK_INVOKE(psett->pd2->tex, IDWALK_CB_USER);
+ CALLBACK_INVOKE(psett->pd2->f_source, IDWALK_CB_NOP);
}
if (psett->boids) {
@@ -748,11 +865,11 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
for (rule = state->rules.first; rule; rule = rule->next) {
if (rule->type == eBoidRuleType_Avoid) {
BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule;
- CALLBACK_INVOKE(gabr->ob, IDWALK_NOP);
+ CALLBACK_INVOKE(gabr->ob, IDWALK_CB_NOP);
}
else if (rule->type == eBoidRuleType_FollowLeader) {
BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule;
- CALLBACK_INVOKE(flbr->ob, IDWALK_NOP);
+ CALLBACK_INVOKE(flbr->ob, IDWALK_CB_NOP);
}
}
}
@@ -768,19 +885,19 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
MovieTrackingTrack *track;
MovieTrackingPlaneTrack *plane_track;
- CALLBACK_INVOKE(clip->gpd, IDWALK_USER);
+ CALLBACK_INVOKE(clip->gpd, IDWALK_CB_USER);
for (track = tracking->tracks.first; track; track = track->next) {
- CALLBACK_INVOKE(track->gpd, IDWALK_USER);
+ CALLBACK_INVOKE(track->gpd, IDWALK_CB_USER);
}
for (object = tracking->objects.first; object; object = object->next) {
for (track = object->tracks.first; track; track = track->next) {
- CALLBACK_INVOKE(track->gpd, IDWALK_USER);
+ CALLBACK_INVOKE(track->gpd, IDWALK_CB_USER);
}
}
for (plane_track = tracking->plane_tracks.first; plane_track; plane_track = plane_track->next) {
- CALLBACK_INVOKE(plane_track->image, IDWALK_USER);
+ CALLBACK_INVOKE(plane_track->image, IDWALK_CB_USER);
}
break;
}
@@ -795,7 +912,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
for (mask_spline = mask_layer->splines.first; mask_spline; mask_spline = mask_spline->next) {
for (i = 0; i < mask_spline->tot_point; i++) {
MaskSplinePoint *point = &mask_spline->points[i];
- CALLBACK_INVOKE_ID(point->parent.id, IDWALK_USER);
+ CALLBACK_INVOKE_ID(point->parent.id, IDWALK_CB_USER);
}
}
}
@@ -813,14 +930,14 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
if (linestyle->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- BKE_library_foreach_ID_link((ID *)linestyle->nodetree, callback, user_data, flag);
+ library_foreach_ID_as_subdata_link((ID **)&linestyle->nodetree, callback, user_data, flag, &data);
}
for (lsm = linestyle->color_modifiers.first; lsm; lsm = lsm->next) {
if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
LineStyleColorModifier_DistanceFromObject *p = (LineStyleColorModifier_DistanceFromObject *)lsm;
if (p->target) {
- CALLBACK_INVOKE(p->target, IDWALK_NOP);
+ CALLBACK_INVOKE(p->target, IDWALK_CB_NOP);
}
}
}
@@ -828,7 +945,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
LineStyleAlphaModifier_DistanceFromObject *p = (LineStyleAlphaModifier_DistanceFromObject *)lsm;
if (p->target) {
- CALLBACK_INVOKE(p->target, IDWALK_NOP);
+ CALLBACK_INVOKE(p->target, IDWALK_CB_NOP);
}
}
}
@@ -836,22 +953,69 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
LineStyleThicknessModifier_DistanceFromObject *p = (LineStyleThicknessModifier_DistanceFromObject *)lsm;
if (p->target) {
- CALLBACK_INVOKE(p->target, IDWALK_NOP);
+ CALLBACK_INVOKE(p->target, IDWALK_CB_NOP);
}
}
}
break;
}
+ case ID_AC:
+ {
+ bAction *act = (bAction *) id;
+
+ for (TimeMarker *marker = act->markers.first; marker; marker = marker->next) {
+ CALLBACK_INVOKE(marker->camera, IDWALK_CB_NOP);
+ }
+ 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(screen, IDWALK_CB_NOP);
+ /* allow callback to set a different screen */
+ BKE_workspace_layout_screen_set(layout, screen);
+ }
+
+ break;
+ }
+ case ID_GD:
+ {
+ bGPdata *gpencil = (bGPdata *) id;
+
+ for (bGPDlayer *gp_layer = gpencil->layers.first; gp_layer; gp_layer = gp_layer->next) {
+ CALLBACK_INVOKE(gp_layer->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_AR:
- case ID_AC:
- case ID_GD:
- case ID_WM:
case ID_PAL:
case ID_PC:
case ID_CF:
@@ -862,7 +1026,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
break;
}
- } while ((id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL));
+ }
FOREACH_FINALIZE:
if (data.ids_handled) {
@@ -880,13 +1044,13 @@ FOREACH_FINALIZE:
/**
* re-usable function, use when replacing ID's
*/
-void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cd_flag)
+void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cb_flag)
{
- if (cd_flag & IDWALK_USER) {
+ if (cb_flag & IDWALK_CB_USER) {
id_us_min(id_src);
id_us_plus(id_dst);
}
- else if (cd_flag & IDWALK_USER_ONE) {
+ else if (cb_flag & IDWALK_CB_USER_ONE) {
id_us_ensure_real(id_dst);
}
}
@@ -897,10 +1061,28 @@ void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cd_flag)
* This is a 'simplified' abstract version of #BKE_library_foreach_ID_link() above, quite useful to reduce
* useless iterations in some cases.
*/
-bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id_type_used)
+/* XXX This has to be fully rethink, basing check on ID type is not really working anymore (and even worth once
+ * IDProps will support ID pointers), we'll have to do some quick checks on IDs themselves... */
+bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
{
- if (id_type_used == ID_AC) {
- return id_type_can_have_animdata(id_type_owner);
+ /* any type of ID can be used in custom props. */
+ if (id_owner->properties) {
+ return true;
+ }
+
+ const short id_type_owner = GS(id_owner->name);
+
+ /* IDProps of armature bones and nodes, and bNode->id can use virtually any type of ID. */
+ if (ELEM(id_type_owner, ID_NT, ID_AR)) {
+ return true;
+ }
+
+ if (ntreeFromID(id_owner)) {
+ return true;
+ }
+
+ if (BKE_animdata_from_id(id_owner)) {
+ return true; /* AnimationData can use virtually any kind of datablocks, through drivers especially. */
}
switch ((ID_Type)id_type_owner) {
@@ -908,8 +1090,7 @@ bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id
return ELEM(id_type_used, ID_LI);
case ID_SCE:
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) ||
- BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ 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
@@ -926,13 +1107,13 @@ bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id
case ID_MB:
return ELEM(id_type_used, ID_MA);
case ID_MA:
- return (ELEM(id_type_used, ID_TE, ID_GR) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ return (ELEM(id_type_used, ID_TE, ID_GR));
case ID_TE:
- return (ELEM(id_type_used, ID_IM, ID_OB) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ return (ELEM(id_type_used, ID_IM, ID_OB));
case ID_LT:
return ELEM(id_type_used, ID_KE);
case ID_LA:
- return (ELEM(id_type_used, ID_TE) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ return (ELEM(id_type_used, ID_TE));
case ID_CA:
return ELEM(id_type_used, ID_OB);
case ID_KE:
@@ -940,7 +1121,7 @@ bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id
case ID_SCR:
return ELEM(id_type_used, ID_SCE);
case ID_WO:
- return (ELEM(id_type_used, ID_TE) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ return (ELEM(id_type_used, ID_TE));
case ID_SPK:
return ELEM(id_type_used, ID_SO);
case ID_GR:
@@ -961,7 +1142,10 @@ bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id
case ID_MSK:
return ELEM(id_type_used, ID_MC); /* WARNING! mask->parent.id, not typed. */
case ID_LS:
- return (ELEM(id_type_used, ID_TE, ID_OB) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+ return (ELEM(id_type_used, ID_TE, ID_OB));
+ case ID_LP:
+ return ELEM(id_type_used, ID_IM);
+ case ID_WS:
case ID_IM:
case ID_VF:
case ID_TXT:
@@ -994,30 +1178,31 @@ typedef struct IDUsersIter {
int count_direct, count_indirect; /* Set by callback. */
} IDUsersIter;
-static int foreach_libblock_id_users_callback(void *user_data, ID *self_id, ID **id_p, int cb_flag)
+static int foreach_libblock_id_users_callback(void *user_data, ID *UNUSED(self_id), ID **id_p, int cb_flag)
{
IDUsersIter *iter = user_data;
- /* XXX This is actually some kind of hack...
- * Issue is, only ID pointer from shapekeys is the 'from' one, which is not actually ID usage.
- * Maybe we should even nuke it from BKE_library_foreach_ID_link, not 100% sure yet...
- */
- if (GS(self_id->name) == ID_KE) {
- return IDWALK_RET_NOP;
- }
+ if (*id_p) {
+ /* 'Loopback' ID pointers (the ugly 'from' ones, Object->proxy_from and Key->from).
+ * Those are not actually ID usage, we can ignore them here.
+ */
+ if (cb_flag & IDWALK_CB_LOOPBACK) {
+ return IDWALK_RET_NOP;
+ }
- if (*id_p && (*id_p == iter->id)) {
+ if (*id_p == iter->id) {
#if 0
- printf("%s uses %s (refcounted: %d, userone: %d, used_one: %d, used_one_active: %d, indirect_usage: %d)\n",
- iter->curr_id->name, iter->id->name, (cb_flag & IDWALK_USER) ? 1 : 0, (cb_flag & IDWALK_USER_ONE) ? 1 : 0,
- (iter->id->tag & LIB_TAG_EXTRAUSER) ? 1 : 0, (iter->id->tag & LIB_TAG_EXTRAUSER_SET) ? 1 : 0,
- (cb_flag & IDWALK_INDIRECT_USAGE) ? 1 : 0);
+ printf("%s uses %s (refcounted: %d, userone: %d, used_one: %d, used_one_active: %d, indirect_usage: %d)\n",
+ iter->curr_id->name, iter->id->name, (cb_flag & IDWALK_USER) ? 1 : 0, (cb_flag & IDWALK_USER_ONE) ? 1 : 0,
+ (iter->id->tag & LIB_TAG_EXTRAUSER) ? 1 : 0, (iter->id->tag & LIB_TAG_EXTRAUSER_SET) ? 1 : 0,
+ (cb_flag & IDWALK_INDIRECT_USAGE) ? 1 : 0);
#endif
- if (cb_flag & IDWALK_INDIRECT_USAGE) {
- iter->count_indirect++;
- }
- else {
- iter->count_direct++;
+ if (cb_flag & IDWALK_CB_INDIRECT_USAGE) {
+ iter->count_indirect++;
+ }
+ else {
+ iter->count_direct++;
+ }
}
}
@@ -1043,7 +1228,7 @@ int BKE_library_ID_use_ID(ID *id_user, ID *id_used)
iter.curr_id = id_user;
iter.count_direct = iter.count_indirect = 0;
- BKE_library_foreach_ID_link(iter.curr_id, foreach_libblock_id_users_callback, (void *)&iter, IDWALK_NOP);
+ BKE_library_foreach_ID_link(NULL, iter.curr_id, foreach_libblock_id_users_callback, (void *)&iter, IDWALK_READONLY);
return iter.count_direct + iter.count_indirect;
}
@@ -1061,7 +1246,7 @@ static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked)
while (i-- && !is_defined) {
ID *id_curr = lb_array[i]->first;
- if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(id->name))) {
+ if (!id_curr || !BKE_library_id_can_use_idtype(id_curr, GS(id->name))) {
continue;
}
@@ -1072,7 +1257,7 @@ static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked)
}
iter.curr_id = id_curr;
BKE_library_foreach_ID_link(
- id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_NOP);
+ bmain, id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_READONLY);
is_defined = ((check_linked ? iter.count_indirect : iter.count_direct) != 0);
}
@@ -1113,7 +1298,7 @@ void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, boo
while (i-- && !is_defined) {
ID *id_curr = lb_array[i]->first;
- if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(id->name))) {
+ if (!id_curr || !BKE_library_id_can_use_idtype(id_curr, GS(id->name))) {
continue;
}
@@ -1123,7 +1308,7 @@ void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, boo
continue;
}
iter.curr_id = id_curr;
- BKE_library_foreach_ID_link(id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_NOP);
+ BKE_library_foreach_ID_link(bmain, id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_READONLY);
is_defined = (iter.count_direct != 0 && iter.count_indirect != 0);
}
@@ -1132,3 +1317,105 @@ void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, boo
*is_used_local = (iter.count_direct != 0);
*is_used_linked = (iter.count_indirect != 0);
}
+
+/* ***** IDs usages.checking/tagging. ***** */
+static int foreach_libblock_used_linked_data_tag_clear_cb(
+ void *user_data, ID *self_id, ID **id_p, int UNUSED(cb_flag))
+{
+ bool *is_changed = user_data;
+
+ if (*id_p) {
+ /* XXX This is actually some kind of hack...
+ * Issue is, shapekeys' 'from' ID pointer is not actually ID usage.
+ * Maybe we should even nuke it from BKE_library_foreach_ID_link, not 100% sure yet...
+ */
+ if ((GS(self_id->name) == ID_KE) && (((Key *)self_id)->from == *id_p)) {
+ return IDWALK_RET_NOP;
+ }
+ /* XXX another hack, for similar reasons as above one. */
+ if ((GS(self_id->name) == ID_OB) && (((Object *)self_id)->proxy_from == (Object *)*id_p)) {
+ return IDWALK_RET_NOP;
+ }
+
+ /* If checked id is used by an assumed used ID, then it is also used and not part of any linked archipelago. */
+ if (!(self_id->tag & LIB_TAG_DOIT) && ((*id_p)->tag & LIB_TAG_DOIT)) {
+ (*id_p)->tag &= ~LIB_TAG_DOIT;
+ *is_changed = true;
+ }
+ }
+
+ return IDWALK_RET_NOP;
+}
+
+/**
+ * Detect orphaned linked data blocks (i.e. linked data not used (directly or indirectly) in any way by any local data),
+ * including complex cases like 'linked archipelagoes', i.e. linked datablocks that use each other in loops,
+ * which prevents their deletion by 'basic' usage checks...
+ *
+ * \param do_init_tag if \a true, all linked data are checked, if \a false, only linked datablocks already tagged with
+ * LIB_TAG_DOIT are checked.
+ */
+void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag)
+{
+ ListBase *lb_array[MAX_LIBARRAY];
+
+ if (do_init_tag) {
+ int i = set_listbasepointers(bmain, lb_array);
+
+ while (i--) {
+ for (ID *id = lb_array[i]->first; id; id = id->next) {
+ if (id->lib && (id->tag & LIB_TAG_INDIRECT) != 0) {
+ id->tag |= LIB_TAG_DOIT;
+ }
+ else {
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+ }
+ }
+ }
+
+ bool do_loop = true;
+ while (do_loop) {
+ int i = set_listbasepointers(bmain, lb_array);
+ do_loop = false;
+
+ while (i--) {
+ for (ID *id = lb_array[i]->first; id; id = id->next) {
+ if (id->tag & LIB_TAG_DOIT) {
+ /* Unused ID (so far), no need to check it further. */
+ continue;
+ }
+ BKE_library_foreach_ID_link(
+ bmain, id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_READONLY);
+ }
+ }
+ }
+}
+
+/**
+ * Untag linked data blocks used by other untagged linked datablocks.
+ * Used to detect datablocks that we can forcefully make local (instead of copying them to later get rid of original):
+ * All datablocks we want to make local are tagged by caller, after this function has ran caller knows datablocks still
+ * tagged can directly be made local, since they are only used by other datablocks that will also be made fully local.
+ */
+void BKE_library_indirectly_used_data_tag_clear(Main *bmain)
+{
+ ListBase *lb_array[MAX_LIBARRAY];
+
+ bool do_loop = true;
+ while (do_loop) {
+ int i = set_listbasepointers(bmain, lb_array);
+ do_loop = false;
+
+ while (i--) {
+ for (ID *id = lb_array[i]->first; id; id = id->next) {
+ if (id->lib == NULL || id->tag & LIB_TAG_DOIT) {
+ /* Local or non-indirectly-used ID (so far), no need to check it further. */
+ continue;
+ }
+ BKE_library_foreach_ID_link(
+ bmain, id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_READONLY);
+ }
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index 1830ca0bd90..a260dffea2f 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -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,8 +73,8 @@
#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"
@@ -99,14 +101,20 @@
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
+#include "BKE_lightprobe.h"
+#include "BKE_sca.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
@@ -133,6 +141,7 @@ void BKE_library_callback_remap_editor_id_reference_set(BKE_library_remap_editor
}
typedef struct IDRemap {
+ Main *bmain; /* Only used to trigger depsgraph updates in the right bmain. */
ID *old_id;
ID *new_id;
ID *id; /* The ID in which we are replacing old_id by new_id usages. */
@@ -154,8 +163,12 @@ enum {
ID_REMAP_IS_USER_ONE_SKIPPED = 1 << 1, /* There was some skipped 'user_one' usages of old_id. */
};
-static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self), ID **id_p, int cb_flag)
+static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id_p, int cb_flag)
{
+ if (cb_flag & IDWALK_CB_PRIVATE) {
+ return IDWALK_RET_NOP;
+ }
+
IDRemap *id_remap_data = user_data;
ID *old_id = id_remap_data->old_id;
ID *new_id = id_remap_data->new_id;
@@ -167,14 +180,15 @@ static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self),
}
if (*id_p && (*id_p == old_id)) {
- const bool is_indirect = (cb_flag & IDWALK_INDIRECT_USAGE) != 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,
* on the other hand since they get reset to lib data on file open/reload it is indirect too...
* Edit Mode is also a 'skip direct' case. */
const bool is_obj = (GS(id->name) == ID_OB);
+ const bool is_obj_proxy = (is_obj && (((Object *)id)->proxy || ((Object *)id)->proxy_group));
const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id));
- const bool is_never_null = ((cb_flag & IDWALK_NEVER_NULL) && (new_id == NULL) &&
+ 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_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0;
@@ -183,7 +197,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self),
id->name, old_id->name, old_id, new_id ? new_id->name : "<NONE>", new_id, skip_indirect);
#endif
- if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_NEVER_NULL)) {
+ if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_CB_NEVER_NULL)) {
id->tag |= LIB_TAG_DOIT;
}
@@ -201,10 +215,10 @@ static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self),
else {
BLI_assert(0);
}
- if (cb_flag & IDWALK_USER) {
+ if (cb_flag & IDWALK_CB_USER) {
id_remap_data->skipped_refcounted++;
}
- else if (cb_flag & IDWALK_USER_ONE) {
+ else if (cb_flag & IDWALK_CB_USER_ONE) {
/* No need to count number of times this happens, just a flag is enough. */
id_remap_data->status |= ID_REMAP_IS_USER_ONE_SKIPPED;
}
@@ -212,19 +226,20 @@ static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self),
else {
if (!is_never_null) {
*id_p = new_id;
+ DEG_id_tag_update_ex(id_remap_data->bmain, id_self, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
}
- if (cb_flag & IDWALK_USER) {
+ if (cb_flag & IDWALK_CB_USER) {
id_us_min(old_id);
/* We do not want to handle LIB_TAG_INDIRECT/LIB_TAG_EXTERN here. */
if (new_id)
new_id->us++;
}
- else if (cb_flag & IDWALK_USER_ONE) {
+ else if (cb_flag & IDWALK_CB_USER_ONE) {
id_us_ensure_real(new_id);
/* We cannot affect old_id->us directly, LIB_TAG_EXTRAUSER(_SET) are assumed to be set as needed,
* that extra user is processed in final handling... */
}
- if (!is_indirect) {
+ if (!is_indirect || is_obj_proxy) {
id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
}
}
@@ -235,7 +250,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self),
/* Some reamapping 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)
+ IDRemap *r_id_remap_data, Scene *sce, BaseLegacy *base, const bool skip_indirect, const bool is_indirect)
{
if (skip_indirect && is_indirect) {
r_id_remap_data->skipped_indirect++;
@@ -251,6 +266,22 @@ static void libblock_remap_data_preprocess_scene_base_unlink(
}
}
+/* Some remapping unfortunately require extra and/or specific handling, tackle those here. */
+static void libblock_remap_data_preprocess_scene_object_unlink(
+ IDRemap *r_id_remap_data, Scene *sce, Object *ob, 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 {
+ BKE_collections_object_remove(r_id_remap_data->bmain, sce, ob, false);
+ 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)) {
@@ -265,7 +296,15 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data)
/* In case we are unlinking... */
if (!r_id_remap_data->old_id) {
/* ... everything from scene. */
- Base *base, *base_next;
+ FOREACH_SCENE_OBJECT(sce, ob_iter)
+ {
+ libblock_remap_data_preprocess_scene_object_unlink(
+ r_id_remap_data, sce, ob_iter, skip_indirect, is_indirect);
+ }
+ FOREACH_SCENE_OBJECT_END
+
+
+ BaseLegacy *base, *base_next;
for (base = sce->base.first; base; base = base_next) {
base_next = base->next;
libblock_remap_data_preprocess_scene_base_unlink(
@@ -275,8 +314,11 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data)
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);
+ libblock_remap_data_preprocess_scene_object_unlink(
+ r_id_remap_data, sce, old_ob, skip_indirect, is_indirect);
+
+ BaseLegacy *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);
@@ -322,7 +364,7 @@ static void libblock_remap_data_postprocess_object_fromgroup_update(Main *bmain,
}
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(group, NULL, NULL, NULL);
+ BKE_group_object_unlink(group, NULL);
}
}
else {
@@ -335,23 +377,17 @@ static void libblock_remap_data_postprocess_group_scene_unlink(Main *UNUSED(bmai
{
/* 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(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(grp, ob);
- }
- if (!grp) {
- ob->flag &= ~OB_FROMGROUP;
- }
+ for (BaseLegacy *base = sce->base.first; base; base = base->next) {
+ Object *ob = base->object;
+ if (ob->flag & OB_FROMGROUP) {
+ Group *grp = BKE_group_object_find(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(grp, ob);
}
- if (!(ob->flag & OB_FROMGROUP)) {
- base->flag &= ~OB_FROMGROUP;
+ if (!grp) {
+ ob->flag &= ~OB_FROMGROUP;
}
}
}
@@ -375,6 +411,18 @@ static void libblock_remap_data_postprocess_obdata_relink(Main *UNUSED(bmain), O
}
}
+static void libblock_remap_data_postprocess_nodetree_update(Main *bmain, ID *new_id)
+{
+ /* Verify all nodetree user nodes. */
+ ntreeVerifyNodes(bmain, new_id);
+
+ /* Update node trees as necessary. */
+ FOREACH_NODETREE(bmain, ntree, id) {
+ /* make an update call for the tree */
+ ntreeUpdateTree(bmain, ntree);
+ } FOREACH_NODETREE_END
+}
+
/**
* Execute the 'data' part of the remapping (that is, all ID pointers from other ID datablocks).
*
@@ -385,24 +433,26 @@ static void libblock_remap_data_postprocess_obdata_relink(Main *UNUSED(bmain), O
* - \a id is non-NULL:
* + If \a old_id is NULL, \a new_id must also be NULL, and all ID pointers from \a id are cleared (i.e. \a id
* does not references any other datablock anymore).
- * + If \a old_id is non-NULL, behavior is as with a NULL \a id, but only for given \a id.
+ * + If \a old_id is non-NULL, behavior is as with a NULL \a id, but only within given \a id.
*
- * \param bmain: the Main data storage to operate on (can be NULL if \a id is non-NULL).
- * \param id: the datablock to operate on (can be NULL if \a bmain is non-NULL).
+ * \param bmain: the Main data storage to operate on (must never be NULL).
+ * \param id: the datablock to operate on (can be NULL, in which case we operate over all IDs from given bmain).
* \param old_id: the datablock to dereference (may be NULL if \a id is non-NULL).
* \param new_id: the new datablock to replace \a old_id references with (may be NULL).
* \param r_id_remap_data: if non-NULL, the IDRemap struct to use (uselful to retrieve info about remapping process).
*/
-static void libblock_remap_data(
+ATTR_NONNULL(1) static void libblock_remap_data(
Main *bmain, ID *id, ID *old_id, ID *new_id, const short remap_flags, IDRemap *r_id_remap_data)
{
IDRemap id_remap_data;
ListBase *lb_array[MAX_LIBARRAY];
int i;
+ const int foreach_id_flags = (remap_flags & ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE) != 0 ? IDWALK_NO_INDIRECT_PROXY_DATA_USAGE : IDWALK_NOP;
if (r_id_remap_data == NULL) {
r_id_remap_data = &id_remap_data;
}
+ r_id_remap_data->bmain = bmain;
r_id_remap_data->old_id = old_id;
r_id_remap_data->new_id = new_id;
r_id_remap_data->id = NULL;
@@ -418,7 +468,7 @@ static void libblock_remap_data(
#endif
r_id_remap_data->id = id;
libblock_remap_data_preprocess(r_id_remap_data);
- BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
+ BKE_library_foreach_ID_link(NULL, id, foreach_libblock_remap_callback, (void *)r_id_remap_data, foreach_id_flags);
}
else {
i = set_listbasepointers(bmain, lb_array);
@@ -427,24 +477,24 @@ static void libblock_remap_data(
* objects actually using given old_id... sounds rather unlikely currently, though, so this will do for now. */
while (i--) {
- ID *id_curr = lb_array[i]->first;
-
- if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(old_id->name))) {
- continue;
- }
-
- for (; id_curr; id_curr = id_curr->next) {
- /* Note that we cannot skip indirect usages of old_id here (if requested), we still need to check it for
- * the user count handling...
- * XXX No more true (except for debug usage of those skipping counters). */
- r_id_remap_data->id = id_curr;
- libblock_remap_data_preprocess(r_id_remap_data);
- BKE_library_foreach_ID_link(
- id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
+ for (ID *id_curr = lb_array[i]->first; id_curr; id_curr = id_curr->next) {
+ if (BKE_library_id_can_use_idtype(id_curr, GS(old_id->name))) {
+ /* Note that we cannot skip indirect usages of old_id here (if requested), we still need to check it for
+ * the user count handling...
+ * XXX No more true (except for debug usage of those skipping counters). */
+ r_id_remap_data->id = id_curr;
+ libblock_remap_data_preprocess(r_id_remap_data);
+ BKE_library_foreach_ID_link(
+ NULL, id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, foreach_id_flags);
+ }
}
}
}
+ 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)) {
@@ -502,12 +552,15 @@ void BKE_libblock_remap_locked(
* been incremented for that, we have to decrease once more its user count... unless we had to skip
* some 'user_one' cases. */
if ((old_id->tag & LIB_TAG_EXTRAUSER_SET) && !(id_remap_data.status & ID_REMAP_IS_USER_ONE_SKIPPED)) {
- id_us_min(old_id);
- old_id->tag &= ~LIB_TAG_EXTRAUSER_SET;
+ id_us_clear_real(old_id);
}
- BLI_assert(old_id->us - skipped_refcounted >= 0);
- UNUSED_VARS_NDEBUG(skipped_refcounted);
+ if (old_id->us - skipped_refcounted < 0) {
+ printf("Error in remapping process from '%s' (%p) to '%s' (%p): "
+ "wrong user count in old ID after process (summing up to %d)\n",
+ old_id->name, old_id, new_id ? new_id->name : "<NULL>", new_id, old_id->us - skipped_refcounted);
+ BLI_assert(0);
+ }
if (skipped_direct == 0) {
/* old_id is assumed to not be used directly anymore... */
@@ -544,8 +597,16 @@ void BKE_libblock_remap_locked(
break;
}
+ /* Node trees may virtually use any kind of data-block... */
+ /* XXX Yuck!!!! nodetree update can do pretty much any thing when talking about py nodes,
+ * including creating new data-blocks (see T50385), so we need to unlock main here. :(
+ * Why can't we have re-entrent locks? */
+ BKE_main_unlock(bmain);
+ libblock_remap_data_postprocess_nodetree_update(bmain, new_id);
+ BKE_main_lock(bmain);
+
/* Full rebuild of DAG! */
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
}
void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
@@ -610,7 +671,7 @@ void BKE_libblock_relink_ex(
BLI_assert(new_id == NULL);
}
- libblock_remap_data(NULL, id, old_id, new_id, remap_flags, NULL);
+ libblock_remap_data(bmain, id, old_id, new_id, remap_flags, NULL);
/* Some after-process updates.
* This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead?
@@ -658,61 +719,50 @@ void BKE_libblock_relink_ex(
}
}
-static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata)
+static int id_relink_to_newid_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int cb_flag)
{
- ChannelDriver *driver;
- FCurve *fcu;
-
- /* find the driver this belongs to and update it */
- for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
- driver = fcu->driver;
-
- if (driver) {
- DriverVar *dvar;
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- DRIVER_TARGETS_USED_LOOPER(dvar)
- {
- if (dtar->id == userdata)
- dtar->id = NULL;
- }
- DRIVER_TARGETS_LOOPER_END
- }
- }
+ if (cb_flag & IDWALK_CB_PRIVATE) {
+ return IDWALK_RET_NOP;
}
-}
-void BKE_libblock_free_data(Main *bmain, ID *id)
-{
- if (id->properties) {
- IDP_FreeProperty(id->properties);
- MEM_freeN(id->properties);
+ ID *id = *id_pointer;
+ if (id) {
+ /* See: NEW_ID macro */
+ if (id->newid) {
+ BKE_library_update_ID_link_user(id->newid, id, cb_flag);
+ *id_pointer = id->newid;
+ }
+ else if (id->tag & LIB_TAG_NEW) {
+ id->tag &= ~LIB_TAG_NEW;
+ BKE_libblock_relink_to_newid(id);
+ }
}
-
- /* this ID may be a driver target! */
- BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id);
+ return IDWALK_RET_NOP;
}
-/**
- * used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c
+/** Similar to libblock_relink_ex, but is remapping IDs to their newid value if non-NULL, in given \a id.
*
- * \param do_id_user: if \a true, try to release other ID's 'references' hold by \a idv.
+ * Very specific usage, not sure we'll keep it on the long run, currently only used in Object duplication code...
*/
-void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user)
+void BKE_libblock_relink_to_newid(ID *id)
{
- ID *id = idv;
- short type = GS(id->name);
- ListBase *lb = which_libbase(bmain, type);
-
- DAG_id_type_tag(bmain, type);
+ if (ID_IS_LINKED_DATABLOCK(id))
+ return;
-#ifdef WITH_PYTHON
- BPY_id_release(id);
-#endif
+ BKE_library_foreach_ID_link(NULL, id, id_relink_to_newid_looper, NULL, 0);
+}
- if (do_id_user) {
- BKE_libblock_relink_ex(bmain, id, NULL, NULL, true);
+void BKE_libblock_free_data(ID *id, const bool do_id_user)
+{
+ if (id->properties) {
+ IDP_FreeProperty_ex(id->properties, do_id_user);
+ MEM_freeN(id->properties);
}
+}
+void BKE_libblock_free_datablock(ID *id)
+{
+ const short type = GS(id->name);
switch (type) {
case ID_SCE:
BKE_scene_free((Scene *)id);
@@ -771,6 +821,9 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user)
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;
@@ -817,22 +870,54 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user)
case ID_CF:
BKE_cachefile_free((CacheFile *)id);
break;
+ case ID_WS:
+ BKE_workspace_free((WorkSpace *)id);
+ break;
+ }
+}
+
+/**
+ * used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c
+ *
+ * \param do_id_user: if \a true, try to release other ID's 'references' hold by \a idv.
+ * (only applies to main database)
+ * \param do_ui_user: similar to do_id_user but makes sure UI does not hold references to
+ * \a id.
+ */
+void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const bool do_ui_user)
+{
+ ID *id = idv;
+ short type = GS(id->name);
+ ListBase *lb = which_libbase(bmain, type);
+
+ DEG_id_type_tag(bmain, type);
+
+#ifdef WITH_PYTHON
+ BPY_id_release(id);
+#endif
+
+ if (do_id_user) {
+ BKE_libblock_relink_ex(bmain, id, NULL, NULL, true);
}
+ BKE_libblock_free_datablock(id);
+
/* avoid notifying on removed data */
BKE_main_lock(bmain);
- if (free_notifier_reference_cb) {
- free_notifier_reference_cb(id);
- }
+ if (do_ui_user) {
+ if (free_notifier_reference_cb) {
+ free_notifier_reference_cb(id);
+ }
- if (remap_editor_id_reference_cb) {
- remap_editor_id_reference_cb(id, NULL);
+ if (remap_editor_id_reference_cb) {
+ remap_editor_id_reference_cb(id, NULL);
+ }
}
BLI_remlink(lb, id);
- BKE_libblock_free_data(bmain, id);
+ BKE_libblock_free_data(id, do_id_user);
BKE_main_unlock(bmain);
MEM_freeN(id);
@@ -840,7 +925,7 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user)
void BKE_libblock_free(Main *bmain, void *idv)
{
- BKE_libblock_free_ex(bmain, idv, true);
+ BKE_libblock_free_ex(bmain, idv, true, true);
}
void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */
@@ -853,9 +938,10 @@ void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */
* Since only 'user_one' usage of objects is groups, 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!
* Otherwise, there is no real way to get rid of an object anymore - better handling of this is TODO.
*/
- if ((GS(id->name) == ID_OB) && (id->us == 1)) {
+ if ((GS(id->name) == ID_OB) && (id->us == 1) && (id->lib == NULL)) {
id_us_clear_real(id);
}
@@ -875,8 +961,8 @@ void BKE_libblock_delete(Main *bmain, void *idv)
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
/* First tag all datablocks directly from target lib.
- * Note that we go forward here, since we want to check dependencies before users (e.g. meshes before objects).
- * Avoids to have to loop twice. */
+ * Note that we go forward here, since we want to check dependencies before users (e.g. meshes before objects).
+ * Avoids to have to loop twice. */
for (i = 0; i < base_count; i++) {
ListBase *lb = lbarray[i];
ID *id;
diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c
new file mode 100644
index 00000000000..a1fa266512b
--- /dev/null
+++ b/source/blender/blenkernel/intern/lightprobe.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) 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/probe.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_main.h"
+#include "BKE_lightprobe.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->data_draw_size = 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);
+
+ BKE_lightprobe_init(probe);
+
+ return probe;
+}
+
+LightProbe *BKE_lightprobe_copy(Main *bmain, LightProbe *probe)
+{
+ LightProbe *probe_new;
+
+ probe_new = BKE_libblock_copy(bmain, &probe->id);
+
+ BKE_id_copy_ensure_local(bmain, &probe->id, &probe_new->id);
+
+ return probe_new;
+}
+
+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 430935a5fad..771e81ddc4f 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -41,6 +41,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
@@ -154,7 +155,7 @@ void BKE_linestyle_free(FreestyleLineStyle *linestyle)
BKE_linestyle_geometry_modifier_remove(linestyle, m);
}
-FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *linestyle)
+FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, const FreestyleLineStyle *linestyle)
{
FreestyleLineStyle *new_linestyle;
LineStyleModifier *m;
@@ -354,7 +355,7 @@ LineStyleModifier *BKE_linestyle_color_modifier_add(FreestyleLineStyle *linestyl
return m;
}
-LineStyleModifier *BKE_linestyle_color_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m)
+LineStyleModifier *BKE_linestyle_color_modifier_copy(FreestyleLineStyle *linestyle, const LineStyleModifier *m)
{
LineStyleModifier *new_m;
@@ -593,7 +594,7 @@ LineStyleModifier *BKE_linestyle_alpha_modifier_add(FreestyleLineStyle *linestyl
return m;
}
-LineStyleModifier *BKE_linestyle_alpha_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m)
+LineStyleModifier *BKE_linestyle_alpha_modifier_copy(FreestyleLineStyle *linestyle, const LineStyleModifier *m)
{
LineStyleModifier *new_m;
@@ -862,7 +863,7 @@ LineStyleModifier *BKE_linestyle_thickness_modifier_add(FreestyleLineStyle *line
return m;
}
-LineStyleModifier *BKE_linestyle_thickness_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m)
+LineStyleModifier *BKE_linestyle_thickness_modifier_copy(FreestyleLineStyle *linestyle, const LineStyleModifier *m)
{
LineStyleModifier *new_m;
@@ -1194,7 +1195,7 @@ LineStyleModifier *BKE_linestyle_geometry_modifier_add(FreestyleLineStyle *lines
return m;
}
-LineStyleModifier *BKE_linestyle_geometry_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m)
+LineStyleModifier *BKE_linestyle_geometry_modifier_copy(FreestyleLineStyle *linestyle, const LineStyleModifier *m)
{
LineStyleModifier *new_m;
@@ -1343,33 +1344,25 @@ int BKE_linestyle_geometry_modifier_remove(FreestyleLineStyle *linestyle, LineSt
return 0;
}
-static void move_modifier(ListBase *lb, LineStyleModifier *modifier, int direction)
+/**
+ * Reinsert \a modifier in modifier list with an offset of \a direction.
+ * \return if position of \a modifier has changed.
+ */
+bool BKE_linestyle_color_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
{
- BLI_remlink(lb, modifier);
- if (direction > 0)
- BLI_insertlinkbefore(lb, modifier->prev, modifier);
- else
- BLI_insertlinkafter(lb, modifier->next, modifier);
+ return BLI_listbase_link_move(&linestyle->color_modifiers, modifier, direction);
}
-
-void BKE_linestyle_color_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
+bool BKE_linestyle_alpha_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
{
- move_modifier(&linestyle->color_modifiers, modifier, direction);
+ return BLI_listbase_link_move(&linestyle->alpha_modifiers, modifier, direction);
}
-
-void BKE_linestyle_alpha_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
+bool BKE_linestyle_thickness_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
{
- move_modifier(&linestyle->alpha_modifiers, modifier, direction);
+ return BLI_listbase_link_move(&linestyle->thickness_modifiers, modifier, direction);
}
-
-void BKE_linestyle_thickness_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
-{
- move_modifier(&linestyle->thickness_modifiers, modifier, direction);
-}
-
-void BKE_linestyle_geometry_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
+bool BKE_linestyle_geometry_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
{
- move_modifier(&linestyle->geometry_modifiers, modifier, direction);
+ return BLI_listbase_link_move(&linestyle->geometry_modifiers, modifier, direction);
}
void BKE_linestyle_modifier_list_color_ramps(FreestyleLineStyle *linestyle, ListBase *listbase)
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index 21023d9f53c..ae27e9bcd34 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -36,8 +36,8 @@
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
-#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
@@ -192,7 +192,7 @@ void BKE_mask_layer_rename(Mask *mask, MaskLayer *masklay, char *oldname, char *
BKE_animdata_fix_paths_rename_all(&mask->id, "layers", oldname, masklay->name);
}
-MaskLayer *BKE_mask_layer_copy(MaskLayer *masklay)
+MaskLayer *BKE_mask_layer_copy(const MaskLayer *masklay)
{
MaskLayer *masklay_new;
MaskSpline *spline;
@@ -236,7 +236,7 @@ MaskLayer *BKE_mask_layer_copy(MaskLayer *masklay)
return masklay_new;
}
-void BKE_mask_layer_copy_list(ListBase *masklayers_new, ListBase *masklayers)
+void BKE_mask_layer_copy_list(ListBase *masklayers_new, const ListBase *masklayers)
{
MaskLayer *layer;
@@ -840,7 +840,7 @@ Mask *BKE_mask_copy_nolib(Mask *mask)
return mask_new;
}
-Mask *BKE_mask_copy(Main *bmain, Mask *mask)
+Mask *BKE_mask_copy(Main *bmain, const Mask *mask)
{
Mask *mask_new;
@@ -851,7 +851,7 @@ Mask *BKE_mask_copy(Main *bmain, Mask *mask)
BKE_mask_layer_copy_list(&mask_new->masklayers, &mask->masklayers);
/* enable fake user by default */
- id_fake_user_set(&mask->id);
+ id_fake_user_set(&mask_new->id);
BKE_id_copy_ensure_local(bmain, &mask->id, &mask_new->id);
@@ -906,7 +906,7 @@ void BKE_mask_spline_free_list(ListBase *splines)
}
}
-static MaskSplinePoint *mask_spline_points_copy(MaskSplinePoint *points, int tot_point)
+static MaskSplinePoint *mask_spline_points_copy(const MaskSplinePoint *points, int tot_point)
{
MaskSplinePoint *npoints;
int i;
@@ -923,7 +923,7 @@ static MaskSplinePoint *mask_spline_points_copy(MaskSplinePoint *points, int tot
return npoints;
}
-MaskSpline *BKE_mask_spline_copy(MaskSpline *spline)
+MaskSpline *BKE_mask_spline_copy(const MaskSpline *spline)
{
MaskSpline *nspline = MEM_callocN(sizeof(MaskSpline), "new spline");
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 470108545b8..e7232322a36 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -72,6 +72,8 @@
#include "BKE_editmesh.h"
#include "BKE_font.h"
+#include "DEG_depsgraph_build.h"
+
#include "GPU_material.h"
/* used in UI and render */
@@ -205,6 +207,8 @@ void BKE_material_init(Material *ma)
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,7 +223,7 @@ Material *BKE_material_add(Main *bmain, const char *name)
}
/* XXX keep synced with next function */
-Material *BKE_material_copy(Main *bmain, Material *ma)
+Material *BKE_material_copy(Main *bmain, const Material *ma)
{
Material *man;
int a;
@@ -227,6 +231,7 @@ Material *BKE_material_copy(Main *bmain, Material *ma)
man = BKE_libblock_copy(bmain, &ma->id);
id_lib_extern((ID *)man->group);
+ id_lib_extern((ID *)man->edit_image);
for (a = 0; a < MAX_MTEX; a++) {
if (ma->mtex[a]) {
@@ -247,6 +252,8 @@ Material *BKE_material_copy(Main *bmain, Material *ma)
BLI_listbase_clear(&man->gpumaterial);
+ /* TODO Duplicate Engine Settings and set runtime to NULL */
+
BKE_id_copy_ensure_local(bmain, &ma->id, &man->id);
return man;
@@ -278,6 +285,8 @@ Material *localize_material(Material *ma)
man->nodetree = ntreeLocalize(ma->nodetree);
BLI_listbase_clear(&man->gpumaterial);
+
+ /* TODO Duplicate Engine Settings and set runtime to NULL */
return man;
}
@@ -398,7 +407,7 @@ static void material_data_index_clear_id(ID *id)
}
}
-void BKE_material_resize_id(struct ID *id, short totcol, bool do_id_user)
+void BKE_material_resize_id(Main *bmain, ID *id, short totcol, bool do_id_user)
{
Material ***matar = give_matarar_id(id);
short *totcolp = give_totcolp_id(id);
@@ -424,9 +433,11 @@ void BKE_material_resize_id(struct ID *id, short totcol, bool do_id_user)
*matar = MEM_recallocN(*matar, sizeof(void *) * totcol);
}
*totcolp = totcol;
+
+ DEG_relations_tag_update(bmain);
}
-void BKE_material_append_id(ID *id, Material *ma)
+void BKE_material_append_id(Main *bmain, ID *id, Material *ma)
{
Material ***matar;
if ((matar = give_matarar_id(id))) {
@@ -439,11 +450,12 @@ void BKE_material_append_id(ID *id, Material *ma)
(*matar)[(*totcol)++] = ma;
id_us_plus((ID *)ma);
- test_all_objects_materials(G.main, id);
+ test_all_objects_materials(bmain, id);
+ DEG_relations_tag_update(bmain);
}
}
-Material *BKE_material_pop_id(ID *id, int index_i, bool update_data)
+Material *BKE_material_pop_id(Main *bmain, ID *id, int index_i, bool update_data)
{
short index = (short)index_i;
Material *ret = NULL;
@@ -472,13 +484,15 @@ Material *BKE_material_pop_id(ID *id, int index_i, bool update_data)
/* decrease mat_nr index */
material_data_index_remove_id(id, index);
}
+
+ DEG_relations_tag_update(bmain);
}
}
return ret;
}
-void BKE_material_clear_id(struct ID *id, bool update_data)
+void BKE_material_clear_id(Main *bmain, ID *id, bool update_data)
{
Material ***matar;
if ((matar = give_matarar_id(id))) {
@@ -497,6 +511,8 @@ void BKE_material_clear_id(struct ID *id, bool update_data)
/* decrease mat_nr index */
material_data_index_clear_id(id);
}
+
+ DEG_relations_tag_update(bmain);
}
}
@@ -553,7 +569,7 @@ Material *give_node_material(Material *ma)
return NULL;
}
-void BKE_material_resize_object(Object *ob, const short totcol, bool do_id_user)
+void BKE_material_resize_object(Main *bmain, Object *ob, const short totcol, bool do_id_user)
{
Material **newmatar;
char *newmatbits;
@@ -590,6 +606,8 @@ void BKE_material_resize_object(Object *ob, const short totcol, bool do_id_user)
ob->totcol = totcol;
if (ob->totcol && ob->actcol == 0) ob->actcol = 1;
if (ob->actcol > ob->totcol) ob->actcol = ob->totcol;
+
+ DEG_relations_tag_update(bmain);
}
void test_object_materials(Object *ob, ID *id)
@@ -601,7 +619,7 @@ void test_object_materials(Object *ob, ID *id)
return;
}
- BKE_material_resize_object(ob, *totcol, false);
+ BKE_material_resize_object(G.main, ob, *totcol, false);
}
void test_all_objects_materials(Main *bmain, ID *id)
@@ -617,7 +635,7 @@ void test_all_objects_materials(Main *bmain, ID *id)
BKE_main_lock(bmain);
for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->data == id) {
- BKE_material_resize_object(ob, *totcol, false);
+ BKE_material_resize_object(bmain, ob, *totcol, false);
}
}
BKE_main_unlock(bmain);
@@ -929,7 +947,7 @@ static void do_init_render_material(Material *ma, int r_mode, float *amb)
if (needtang) ma->mode |= MA_NORMAP_TANG;
else ma->mode &= ~MA_NORMAP_TANG;
- if (ma->mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE)) {
+ if (ma->mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) {
needuv = 1;
if (r_mode & R_OSA) ma->texco |= TEXCO_OSA; /* for texfaces */
}
@@ -1290,6 +1308,14 @@ void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma)
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);
+
+ /* XXX, for 2.8 testing & development its useful to have non Cycles/BI engines use material nodes
+ * In the future we may have some way to check this which each engine can define.
+ * For now use material slots for Clay/Eevee.
+ * - Campbell */
+ if (!(use_nodes || is_bi)) {
+ is_bi = true;
+ }
if (!ma)
return;
@@ -1688,6 +1714,7 @@ void copy_matcopybuf(Material *ma)
matcopybuf.nodetree = ntreeCopyTree_ex(ma->nodetree, G.main, false);
matcopybuf.preview = NULL;
BLI_listbase_clear(&matcopybuf.gpumaterial);
+ /* TODO Duplicate Engine Settings and set runtime to NULL */
matcopied = 1;
}
@@ -1743,501 +1770,30 @@ void paste_matcopybuf(Material *ma)
ma->nodetree = ntreeCopyTree_ex(matcopybuf.nodetree, G.main, 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)
+struct Image *BKE_object_material_edit_image_get(Object *ob, short mat_nr)
{
- 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(Mesh *me, Material *ma)
-{
- BKE_material_append_id(&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;
- }
+ Material *ma = give_current_material(ob, mat_nr + 1);
+ return ma ? ma->edit_image : NULL;
}
-/* returns material number */
-static short convert_tfacenomaterial(Main *main, Mesh *me, MTFace *tf, int flag)
+struct Image **BKE_object_material_edit_image_get_array(Object *ob)
{
- 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(&main->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(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(main, idname + 2);
-
- if (ma) {
- printf("TexFace Convert: Material \"%s\" created.\n", idname + 2);
- mat_nr = mesh_addmaterial(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 *main, 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 = 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) 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(&main->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(me, mat_new);
- }
- /* create a new material */
- else {
- mat_new = BKE_material_copy(main, 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(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(&me->id, a, true);
- }
- else {
- a++;
- }
- }
+ Image **image_array = MEM_mallocN(sizeof(Material *) * ob->totcol, __func__);
+ for (int i = 0; i < ob->totcol; i++) {
+ image_array[i] = BKE_object_material_edit_image_get(ob, i);
}
+ return image_array;
}
-
-#define MAT_BGE_DISPUTED -99999
-
-int do_version_tface(Main *main)
+bool BKE_object_material_edit_image_set(Object *ob, short mat_nr, Image *image)
{
- 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_DATABLOCK(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_DATABLOCK(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_DATABLOCK(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;
- }
- }
+ Material *ma = give_current_material(ob, mat_nr + 1);
+ if (ma) {
+ /* both may be NULL */
+ id_us_min((ID *)ma->edit_image);
+ ma->edit_image = image;
+ id_us_plus((ID *)ma->edit_image);
+ return true;
}
-
- return nowarning;
+ return false;
}
-
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index 8d024ea9aa5..27e2b17b4e2 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -49,6 +49,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BKE_global.h"
@@ -56,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"
@@ -66,6 +66,8 @@
#include "BKE_object.h"
#include "BKE_material.h"
+//#include "DEG_depsgraph.h"
+
/* Functions */
/** Free (or release) any data used by this mball (does not free the mball itself). */
@@ -102,7 +104,7 @@ MetaBall *BKE_mball_add(Main *bmain, const char *name)
return mb;
}
-MetaBall *BKE_mball_copy(Main *bmain, MetaBall *mb)
+MetaBall *BKE_mball_copy(Main *bmain, const MetaBall *mb)
{
MetaBall *mbn;
int a;
@@ -315,13 +317,13 @@ bool BKE_mball_is_basis_for(Object *ob1, Object *ob2)
void BKE_mball_properties_copy(Scene *scene, Object *active_object)
{
Scene *sce_iter = scene;
- Base *base;
+ BaseLegacy *base;
Object *ob;
MetaBall *active_mball = (MetaBall *)active_object->data;
int basisnr, obnr;
char basisname[MAX_ID_NAME], obname[MAX_ID_NAME];
SceneBaseIter iter;
- EvaluationContext *eval_ctx = G.main->eval_ctx;
+ struct EvaluationContext *eval_ctx = G.main->eval_ctx;
BLI_split_name_num(basisname, &basisnr, active_object->id.name + 2, '.');
@@ -358,27 +360,25 @@ void BKE_mball_properties_copy(Scene *scene, Object *active_object)
*/
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;
- EvaluationContext *eval_ctx = G.main->eval_ctx;
BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.');
- BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL);
- while (BKE_scene_base_iter_next(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 (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
+ for (Base *base = sl->object_bases.first; base; base = base->next) {
+ Object *ob = base->object;
+ 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;
+ }
}
}
}
@@ -532,7 +532,7 @@ void BKE_mball_select_swap(struct MetaBall *mb)
/* **** Depsgraph evaluation **** */
-void BKE_mball_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
+void BKE_mball_eval_geometry(struct EvaluationContext *UNUSED(eval_ctx),
MetaBall *UNUSED(mball))
{
}
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c
index 2068854421f..d897213d362 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.c
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -41,18 +41,19 @@
#include "DNA_scene_types.h"
#include "BLI_listbase.h"
-#include "BLI_path_util.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLI_memarena.h"
#include "BKE_global.h"
-#include "BKE_depsgraph.h"
#include "BKE_scene.h"
#include "BKE_displist.h"
#include "BKE_mball_tessellate.h" /* own include */
+#include "DEG_depsgraph.h"
+
#include "BLI_strict_flags.h"
/* experimental (faster) normal calculation */
@@ -316,12 +317,12 @@ static float densfunc(const MetaElem *ball, float x, float y, float z)
if (dvec[2] > ball->expz) dvec[2] -= ball->expz;
else if (dvec[2] < -ball->expz) dvec[2] += ball->expz;
else dvec[2] = 0.0;
- /* fall through */
+ ATTR_FALLTHROUGH;
case MB_PLANE:
if (dvec[1] > ball->expy) dvec[1] -= ball->expy;
else if (dvec[1] < -ball->expy) dvec[1] += ball->expy;
else dvec[1] = 0.0;
- /* fall through */
+ ATTR_FALLTHROUGH;
case MB_TUBE:
if (dvec[0] > ball->expx) dvec[0] -= ball->expx;
else if (dvec[0] < -ball->expx) dvec[0] += ball->expx;
@@ -660,7 +661,7 @@ static void makecubetable(void)
for (i = 0; i < 256; i++) {
for (e = 0; e < 12; e++) done[e] = 0;
for (c = 0; c < 8; c++) pos[c] = MB_BIT(i, c);
- for (e = 0; e < 12; e++)
+ for (e = 0; e < 12; e++) {
if (!done[e] && (pos[corner1[e]] != pos[corner2[e]])) {
INTLIST *ints = NULL;
INTLISTS *lists = MEM_callocN(sizeof(INTLISTS), "mball_intlist");
@@ -687,6 +688,7 @@ static void makecubetable(void)
lists->next = cubetable[i];
cubetable[i] = lists;
}
+ }
}
for (i = 0; i < 256; i++) {
@@ -1080,7 +1082,7 @@ static void polygonize(PROCESS *process)
static void init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scene, Object *ob)
{
Scene *sce_iter = scene;
- Base *base;
+ BaseLegacy *base;
Object *bob;
MetaBall *mb;
const MetaElem *ml;
@@ -1102,7 +1104,7 @@ static void init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scen
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;
@@ -1193,10 +1195,10 @@ static void init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scen
break;
case MB_CUBE: /* cube is "expanded" by expz, expy and expx */
expz += ml->expz;
- /* fall through */
+ ATTR_FALLTHROUGH;
case MB_PLANE: /* plane is "expanded" by expy and expx */
expy += ml->expy;
- /* fall through */
+ ATTR_FALLTHROUGH;
case MB_TUBE: /* tube is "expanded" by expx */
expx += ml->expx;
break;
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 733e9030056..8c9690b01df 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -39,7 +39,9 @@
#include "BLI_utildefines.h"
#include "BLI_math.h"
+#include "BLI_linklist.h"
#include "BLI_listbase.h"
+#include "BLI_memarena.h"
#include "BLI_edgehash.h"
#include "BLI_string.h"
@@ -57,7 +59,6 @@
#include "BKE_multires.h"
#include "BKE_key.h"
#include "BKE_mball.h"
-#include "BKE_depsgraph.h"
/* these 2 are only used by conversion functions */
#include "BKE_curve.h"
/* -- */
@@ -66,6 +67,11 @@
#include "DEG_depsgraph.h"
+/* Define for cases when you want extra validation of mesh
+ * after certain modifications.
+ */
+// #undef VALIDATE_MESH
+
enum {
MESHCMP_DVERT_WEIGHTMISMATCH = 1,
MESHCMP_DVERT_GROUPMISMATCH,
@@ -120,7 +126,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++;
}
@@ -128,7 +134,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++;
}
@@ -142,14 +148,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++;
@@ -317,7 +323,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);
@@ -328,7 +334,7 @@ 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) {
@@ -337,7 +343,7 @@ static void mesh_ensure_tessellation_customdata(Mesh *me)
* 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 */
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);
}
}
@@ -389,14 +395,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)
@@ -415,7 +418,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);
}
@@ -435,6 +437,8 @@ void BKE_mesh_free(Mesh *me)
{
BKE_animdata_free(&me->id, false);
+ BKE_mesh_batch_cache_free(me);
+
CustomData_free(&me->vdata, me->totvert);
CustomData_free(&me->edata, me->totedge);
CustomData_free(&me->fdata, me->totface);
@@ -494,7 +498,7 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name)
return me;
}
-Mesh *BKE_mesh_copy(Main *bmain, Mesh *me)
+Mesh *BKE_mesh_copy(Main *bmain, const Mesh *me)
{
Mesh *men;
int a;
@@ -522,6 +526,7 @@ Mesh *BKE_mesh_copy(Main *bmain, Mesh *me)
BKE_mesh_update_customdata_pointers(men, do_tessface);
men->edit_btmesh = NULL;
+ men->batch_cache = NULL;
men->mselect = MEM_dupallocN(men->mselect);
men->bb = MEM_dupallocN(men->bb);
@@ -576,33 +581,44 @@ bool BKE_mesh_uv_cdlayer_rename_index(Mesh *me, const int poly_index, const int
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;
+ cdlp = (poly_index != -1) ? &pdata->layers[poly_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);
+ }
+
+ if (cdlp == NULL && cdlf == NULL) {
+ return false;
}
/* 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++) {
+ for (i = 1;
+ (cdlp && !STREQ(cdlu->name, cdlp->name)) ||
+ (cdlf && !STREQ(cdlu->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);
+ if (cdlp) {
+ BLI_strncpy(cdlp->name, cdlu->name, sizeof(cdlp->name));
+ CustomData_set_layer_unique_name(pdata, poly_index);
+ }
break;
case 1:
BLI_strncpy(cdlu->name, cdlp->name, sizeof(cdlu->name));
- CustomData_set_layer_unique_name(ldata, cdlu - ldata->layers);
+ CustomData_set_layer_unique_name(ldata, loop_index);
break;
case 2:
if (cdlf) {
- BLI_strncpy(cdlf->name, cdlp->name, sizeof(cdlf->name));
- CustomData_set_layer_unique_name(fdata, cdlf - fdata->layers);
+ BLI_strncpy(cdlf->name, cdlu->name, sizeof(cdlf->name));
+ CustomData_set_layer_unique_name(fdata, face_index);
}
break;
}
@@ -613,66 +629,44 @@ bool BKE_mesh_uv_cdlayer_rename_index(Mesh *me, const int poly_index, const int
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;
- }
+ if (lidx == -1) {
+ if (fidx == -1) {
+ /* No layer found with this name! */
+ return false;
}
- pidx = lidx;
- }
- else {
- if (lidx == -1) {
- lidx = pidx;
- }
- 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, -1, lidx, fidx, new_name, do_tessface);
}
}
@@ -750,6 +744,18 @@ void BKE_mesh_texspace_get(Mesh *me, float r_loc[3], float r_rot[3], float r_siz
if (r_size) copy_v3_v3(r_size, me->size);
}
+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)
{
float *texloc, *texrot, *texsize;
@@ -1332,7 +1338,7 @@ int BKE_mesh_nurbs_displist_to_mdata(
/* this may fail replacing ob->data, be sure to check ob->type */
-void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use_orco_uv)
+void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use_orco_uv, const char *obdata_name)
{
Main *bmain = G.main;
Object *ob1;
@@ -1359,7 +1365,7 @@ void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use
}
/* make mesh */
- me = BKE_mesh_add(G.main, "Mesh");
+ me = BKE_mesh_add(bmain, obdata_name);
me->totvert = totvert;
me->totedge = totedge;
me->totloop = totloop;
@@ -1372,14 +1378,13 @@ void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use
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);
}
BKE_mesh_calc_normals(me);
}
else {
- me = BKE_mesh_add(G.main, "Mesh");
+ me = BKE_mesh_add(bmain, obdata_name);
DM_to_mesh(dm, me, ob, CD_MASK_MESH, false);
}
@@ -1391,9 +1396,7 @@ void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use
cu->mat = NULL;
cu->totcol = 0;
- if (ob->data) {
- BKE_libblock_free(bmain, ob->data);
- }
+ /* Do not decrement ob->data usercount here, it's done at end of func with BKE_libblock_free_us() call. */
ob->data = me;
ob->type = OB_MESH;
@@ -1403,11 +1406,14 @@ void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use
if (ob1->data == cu) {
ob1->type = OB_MESH;
+ id_us_min((ID *)ob1->data);
ob1->data = ob->data;
- id_us_plus((ID *)ob->data);
+ id_us_plus((ID *)ob1->data);
}
ob1 = ob1->id.next;
}
+
+ BKE_libblock_free_us(bmain, cu);
}
void BKE_mesh_from_nurbs(Object *ob)
@@ -1420,7 +1426,7 @@ void BKE_mesh_from_nurbs(Object *ob)
disp = ob->curve_cache->disp;
}
- BKE_mesh_from_nurbs_displist(ob, &disp, use_orco_uv);
+ BKE_mesh_from_nurbs_displist(ob, &disp, use_orco_uv, cu->id.name);
}
typedef struct EdgeLink {
@@ -2048,7 +2054,7 @@ void BKE_mesh_mselect_active_set(Mesh *me, int index, int type)
(me->mselect[me->totselect - 1].type == type));
}
-void BKE_mesh_calc_normals_split(Mesh *mesh)
+void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spacearr)
{
float (*r_loopnors)[3];
float (*polynors)[3];
@@ -2083,111 +2089,337 @@ void BKE_mesh_calc_normals_split(Mesh *mesh)
BKE_mesh_normals_loop_split(
mesh->mvert, mesh->totvert, mesh->medge, mesh->totedge,
mesh->mloop, r_loopnors, mesh->totloop, mesh->mpoly, (const float (*)[3])polynors, mesh->totpoly,
- (mesh->flag & ME_AUTOSMOOTH) != 0, mesh->smoothresh, NULL, clnors, NULL);
+ (mesh->flag & ME_AUTOSMOOTH) != 0, mesh->smoothresh, r_lnors_spacearr, clnors, NULL);
if (free_polynors) {
MEM_freeN(polynors);
}
}
-/* Spli faces based on the edge angle.
- * Matches behavior of face splitting in render engines.
- */
-void BKE_mesh_split_faces(Mesh *mesh)
+void BKE_mesh_calc_normals_split(Mesh *mesh)
{
- const int num_verts = mesh->totvert;
- const int num_edges = mesh->totedge;
- const int num_polys = mesh->totpoly;
+ BKE_mesh_calc_normals_split_ex(mesh, NULL);
+}
+
+/* Split faces helper functions. */
+
+typedef struct SplitFaceNewVert {
+ struct SplitFaceNewVert *next;
+ int new_index;
+ int orig_index;
+ float *vnor;
+} SplitFaceNewVert;
+
+typedef struct SplitFaceNewEdge {
+ struct SplitFaceNewEdge *next;
+ int new_index;
+ int orig_index;
+ int v1;
+ int v2;
+} SplitFaceNewEdge;
+
+/* Detect needed new vertices, and update accordingly loops' vertex indices.
+ * WARNING! Leaves mesh in invalid state. */
+static int split_faces_prepare_new_verts(
+ const Mesh *mesh, MLoopNorSpaceArray *lnors_spacearr, SplitFaceNewVert **new_verts, MemArena *memarena,
+ bool *r_need_vnors_recalc)
+{
+ /* Note: if lnors_spacearr is NULL, ther is no autosmooth handling, and we only split out flat polys. */
+ const int num_loops = mesh->totloop;
+ int num_verts = mesh->totvert;
MVert *mvert = mesh->mvert;
- MEdge *medge = mesh->medge;
MLoop *mloop = mesh->mloop;
- MPoly *mpoly = mesh->mpoly;
- float (*lnors)[3];
- int poly, num_new_verts = 0;
- if ((mesh->flag & ME_AUTOSMOOTH) == 0) {
- return;
- }
- BKE_mesh_tessface_clear(mesh);
- /* Compute loop normals if needed. */
- if (!CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
- BKE_mesh_calc_normals_split(mesh);
- }
- lnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
- /* Count number of vertices to be split. */
- for (poly = 0; poly < num_polys; poly++) {
- MPoly *mp = &mpoly[poly];
- int loop;
- for (loop = 0; loop < mp->totloop; loop++) {
- MLoop *ml = &mloop[mp->loopstart + loop];
- MVert *mv = &mvert[ml->v];
- float vn[3];
- normal_short_to_float_v3(vn, mv->no);
- if (!equals_v3v3(vn, lnors[mp->loopstart + loop])) {
- num_new_verts++;
+
+ BLI_bitmap *verts_used = BLI_BITMAP_NEW(num_verts, __func__);
+
+ if (lnors_spacearr) {
+ BLI_bitmap *done_loops = BLI_BITMAP_NEW(num_loops, __func__);
+
+ MLoop *ml = mloop;
+ MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr;
+ for (int loop_idx = 0; loop_idx < num_loops; 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;
+
+ BLI_assert(*lnor_space);
+
+ if ((*lnor_space)->loops) {
+ for (LinkNode *lnode = (*lnor_space)->loops; lnode; lnode = lnode->next) {
+ const int ml_fan_idx = GET_INT_FROM_POINTER(lnode->link);
+ BLI_BITMAP_ENABLE(done_loops, ml_fan_idx);
+ if (vert_used) {
+ mloop[ml_fan_idx].v = new_vert_idx;
+ }
+ }
+ }
+ else {
+ /* Single loop in this fan... */
+ BLI_BITMAP_ENABLE(done_loops, loop_idx);
+ if (vert_used) {
+ ml->v = new_vert_idx;
+ }
+ }
+
+ if (!vert_used) {
+ BLI_BITMAP_ENABLE(verts_used, vert_idx);
+ /* We need to update that vertex's normal here, we won't go over it again. */
+ /* This is important! *DO NOT* set vnor to final computed lnor, vnor should always be defined to
+ * 'automatic normal' value computed from its polys, not some custom normal.
+ * Fortunately, that's the loop normal space's 'lnor' reference vector. ;) */
+ normal_float_to_short_v3(mvert[vert_idx].no, (*lnor_space)->vec_lnor);
+ }
+ else {
+ /* Add new vert to list. */
+ SplitFaceNewVert *new_vert = BLI_memarena_alloc(memarena, sizeof(*new_vert));
+ new_vert->orig_index = vert_idx;
+ new_vert->new_index = new_vert_idx;
+ new_vert->vnor = (*lnor_space)->vec_lnor; /* See note above. */
+ new_vert->next = *new_verts;
+ *new_verts = new_vert;
+ }
}
}
+
+ MEM_freeN(done_loops);
}
- if (num_new_verts == 0) {
- /* No new vertices are to be added, can do early exit. */
- return;
- }
- /* Reallocate all vert and edge related data. */
- mesh->totvert += num_new_verts;
- mesh->totedge += 2 * num_new_verts;
- CustomData_realloc(&mesh->vdata, mesh->totvert);
- CustomData_realloc(&mesh->edata, mesh->totedge);
- /* Update pointers to a newly allocated memory. */
- BKE_mesh_update_customdata_pointers(mesh, false);
- mvert = mesh->mvert;
- medge = mesh->medge;
- /* Perform actual vertex split. */
- num_new_verts = 0;
- for (poly = 0; poly < num_polys; poly++) {
- MPoly *mp = &mpoly[poly];
- int loop;
- for (loop = 0; loop < mp->totloop; loop++) {
- int poly_loop = mp->loopstart + loop;
- MLoop *ml = &mloop[poly_loop];
- MVert *mv = &mvert[ml->v];
- float vn[3];
- normal_short_to_float_v3(vn, mv->no);
- if (!equals_v3v3(vn, lnors[mp->loopstart + loop])) {
- int poly_loop_prev = mp->loopstart + (loop + mp->totloop - 1) % mp->totloop;
- MLoop *ml_prev = &mloop[poly_loop_prev];
- int new_edge_prev, new_edge;
- /* Cretae new vertex. */
- int new_vert = num_verts + num_new_verts;
- CustomData_copy_data(&mesh->vdata, &mesh->vdata,
- ml->v, new_vert, 1);
- normal_float_to_short_v3(mvert[new_vert].no,
- lnors[poly_loop]);
- /* Create new edges. */
- new_edge_prev = num_edges + 2 * num_new_verts;
- new_edge = num_edges + 2 * num_new_verts + 1;
- CustomData_copy_data(&mesh->edata, &mesh->edata,
- ml_prev->e, new_edge_prev, 1);
- CustomData_copy_data(&mesh->edata, &mesh->edata,
- ml->e, new_edge, 1);
- if (medge[new_edge_prev].v1 == ml->v) {
- medge[new_edge_prev].v1 = new_vert;
+ else {
+ /* No loop normal spaces available, we only split out flat polys. */
+ const int num_polys = mesh->totpoly;
+ const MPoly *mpoly = mesh->mpoly;
+
+ /* We do that in two loops, to keep original edges/verts to smooth polys preferencially. */
+ const MPoly *mp = mpoly;
+ for (int i = 0; i < num_polys; i++, mp++) {
+ if (mp->flag & ME_SMOOTH) {
+ const MLoop *ml = &mloop[mp->loopstart];
+ for (int j = 0; j < mp->totloop; j++, ml++) {
+ /* Just mark the vertex as used/reserved, that way neighbor flat polys, if any,
+ * will have to create their own. */
+ BLI_BITMAP_ENABLE(verts_used, ml->v);
}
- else {
- medge[new_edge_prev].v2 = new_vert;
+ }
+ }
+
+ mp = mpoly;
+ for (int i = 0; i < num_polys; i++, mp++) {
+ if (!(mp->flag & ME_SMOOTH)) {
+ MLoop *ml = &mloop[mp->loopstart];
+ for (int j = 0; j < mp->totloop; j++, ml++) {
+ const int vert_idx = ml->v;
+
+ if (BLI_BITMAP_TEST(verts_used, vert_idx)) {
+ /* Add new vert to list. */
+ const int new_vert_idx = num_verts++;
+ ml->v = new_vert_idx;
+
+ SplitFaceNewVert *new_vert = BLI_memarena_alloc(memarena, sizeof(*new_vert));
+ new_vert->orig_index = vert_idx;
+ new_vert->new_index = new_vert_idx;
+ new_vert->vnor = NULL; /* See note below about normals. */
+ new_vert->next = *new_verts;
+ *new_verts = new_vert;
+ }
+ else {
+ BLI_BITMAP_ENABLE(verts_used, vert_idx);
+ }
}
- if (medge[new_edge].v1 == ml->v) {
- medge[new_edge].v1 = new_vert;
+ /* Note: there is no way to get new normals for smooth vertices here (and we don't have direct access
+ * to poly normals either for flat ones), so we'll have to recompute all vnors at the end... */
+ *r_need_vnors_recalc = true;
+ }
+ }
+ }
+
+ MEM_freeN(verts_used);
+
+ return num_verts - mesh->totvert;
+}
+
+/* Detect needed new edges, and update accordingly loops' edge indices.
+ * WARNING! Leaves mesh in invalid state. */
+static int split_faces_prepare_new_edges(
+ const Mesh *mesh, SplitFaceNewEdge **new_edges, MemArena *memarena)
+{
+ const int num_polys = mesh->totpoly;
+ int num_edges = mesh->totedge;
+ MEdge *medge = mesh->medge;
+ MLoop *mloop = mesh->mloop;
+ const MPoly *mpoly = mesh->mpoly;
+
+ BLI_bitmap *edges_used = BLI_BITMAP_NEW(num_edges, __func__);
+ EdgeHash *edges_hash = BLI_edgehash_new_ex(__func__, num_edges);
+
+ const MPoly *mp = mpoly;
+ for (int poly_idx = 0; poly_idx < num_polys; poly_idx++, mp++) {
+ MLoop *ml_prev = &mloop[mp->loopstart + mp->totloop - 1];
+ MLoop *ml = &mloop[mp->loopstart];
+ for (int loop_idx = 0; loop_idx < mp->totloop; loop_idx++, ml++) {
+ void **eval;
+ if (!BLI_edgehash_ensure_p(edges_hash, ml_prev->v, ml->v, &eval)) {
+ const int edge_idx = ml_prev->e;
+
+ /* That edge has not been encountered yet, define it. */
+ if (BLI_BITMAP_TEST(edges_used, edge_idx)) {
+ /* Original edge has already been used, we need to define a new one. */
+ const int new_edge_idx = num_edges++;
+ *eval = SET_INT_IN_POINTER(new_edge_idx);
+ ml_prev->e = new_edge_idx;
+
+ SplitFaceNewEdge *new_edge = BLI_memarena_alloc(memarena, sizeof(*new_edge));
+ new_edge->orig_index = edge_idx;
+ new_edge->new_index = new_edge_idx;
+ new_edge->v1 = ml_prev->v;
+ new_edge->v2 = ml->v;
+ new_edge->next = *new_edges;
+ *new_edges = new_edge;
}
else {
- medge[new_edge].v2 = new_vert;
+ /* We can re-use original edge. */
+ medge[edge_idx].v1 = ml_prev->v;
+ medge[edge_idx].v2 = ml->v;
+ *eval = SET_INT_IN_POINTER(edge_idx);
+ BLI_BITMAP_ENABLE(edges_used, edge_idx);
}
-
- ml->v = new_vert;
- ml_prev->e = new_edge_prev;
- ml->e = new_edge;
- num_new_verts++;
}
+ else {
+ /* Edge already known, just update loop's edge index. */
+ ml_prev->e = GET_INT_FROM_POINTER(*eval);
+ }
+
+ ml_prev = ml;
+ }
+ }
+
+ MEM_freeN(edges_used);
+ BLI_edgehash_free(edges_hash, NULL);
+
+ return num_edges - mesh->totedge;
+}
+
+/* Perform actual split of vertices. */
+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;
+ 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) {
+ 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);
+ if (new_verts->vnor) {
+ normal_float_to_short_v3(new_mv->no, new_verts->vnor);
+ }
+ }
+}
+
+/* Perform actual split of edges. */
+static void split_faces_split_new_edges(
+ Mesh *mesh, SplitFaceNewEdge *new_edges, const int num_new_edges)
+{
+ const int num_edges = mesh->totedge - num_new_edges;
+ MEdge *medge = mesh->medge;
+
+ /* Remember new_edges is a single linklist, so its items are in reversed order... */
+ MEdge *new_med = &medge[mesh->totedge - 1];
+ for (int i = mesh->totedge - 1; i >= num_edges ; i--, new_med--, new_edges = new_edges->next) {
+ BLI_assert(new_edges->new_index == i);
+ BLI_assert(new_edges->new_index != new_edges->orig_index);
+ CustomData_copy_data(&mesh->edata, &mesh->edata, new_edges->orig_index, i, 1);
+ new_med->v1 = new_edges->v1;
+ new_med->v2 = new_edges->v2;
+ }
+}
+
+/* Split faces based on the edge angle and loop normals.
+ * Matches behavior of face splitting in render engines.
+ *
+ * NOTE: Will leave CD_NORMAL loop data layer which is
+ * used by render engines to set shading up.
+ */
+void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
+{
+ const int num_polys = mesh->totpoly;
+
+ if (num_polys == 0) {
+ return;
+ }
+ BKE_mesh_tessface_clear(mesh);
+
+ MLoopNorSpaceArray *lnors_spacearr = NULL;
+ MemArena *memarena;
+ bool need_vnors_recalc = false;
+
+ if (mesh->flag & ME_AUTOSMOOTH) {
+ lnors_spacearr = MEM_callocN(sizeof(*lnors_spacearr), __func__);
+ /* Compute loop normals and loop normal spaces (a.k.a. smooth fans of faces around vertices). */
+ BKE_mesh_calc_normals_split_ex(mesh, lnors_spacearr);
+ /* Stealing memarena from loop normals space array. */
+ memarena = lnors_spacearr->mem;
+ }
+ else {
+ /* We still have to split out flat faces... */
+ memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ }
+
+ SplitFaceNewVert *new_verts = NULL;
+ SplitFaceNewEdge *new_edges = NULL;
+
+ /* Detect loop normal spaces (a.k.a. smooth fans) that will need a new vert. */
+ const int num_new_verts = split_faces_prepare_new_verts(mesh, lnors_spacearr, &new_verts, memarena, &need_vnors_recalc);
+
+ if (num_new_verts > 0) {
+ /* Reminder: beyond this point, there is no way out, mesh is in invalid state (due to early-reassignment of
+ * loops' vertex and edge indices to new, to-be-created split ones). */
+
+ const int num_new_edges = split_faces_prepare_new_edges(mesh, &new_edges, memarena);
+ /* We can have to split a vertex without having to add a single new edge... */
+ const bool do_edges = (num_new_edges > 0);
+
+ /* Reallocate all vert and edge related data. */
+ mesh->totvert += num_new_verts;
+ mesh->totedge += num_new_edges;
+ CustomData_realloc(&mesh->vdata, mesh->totvert);
+ if (do_edges) {
+ CustomData_realloc(&mesh->edata, mesh->totedge);
}
+ /* Update pointers to a newly allocated memory. */
+ BKE_mesh_update_customdata_pointers(mesh, false);
+
+ /* Perform actual split of vertices and edges. */
+ split_faces_split_new_verts(mesh, new_verts, num_new_verts);
+ if (do_edges) {
+ split_faces_split_new_edges(mesh, new_edges, num_new_edges);
+ }
+ }
+
+ /* Note: after this point mesh is expected to be valid again. */
+
+ /* CD_NORMAL is expected to be temporary only. */
+ if (free_loop_normals) {
+ CustomData_free_layers(&mesh->ldata, CD_NORMAL, mesh->totloop);
+ }
+
+ if (lnors_spacearr) {
+ /* Also frees new_verts/edges temp data, since we used its memarena to allocate them. */
+ BKE_lnor_spacearr_free(lnors_spacearr);
+ MEM_freeN(lnors_spacearr);
}
+ else {
+ BLI_memarena_free(memarena);
+ }
+
+ if (need_vnors_recalc) {
+ BKE_mesh_calc_normals(mesh);
+ }
+#ifdef VALIDATE_MESH
+ BKE_mesh_validate(mesh, true, true);
+#endif
}
/* settings: 1 - preview, 2 - render */
@@ -2197,8 +2429,10 @@ Mesh *BKE_mesh_new_from_object(
{
Mesh *tmpmesh;
Curve *tmpcu = NULL, *copycu;
- int render = settings == eModifierMode_Render, i;
- int cage = !apply_modifiers;
+ int i;
+ const bool render = (settings == eModifierMode_Render);
+ const bool cage = !apply_modifiers;
+ bool do_mat_id_data_us = true;
/* perform the mesh extraction based on type */
switch (ob->type) {
@@ -2251,7 +2485,7 @@ Mesh *BKE_mesh_new_from_object(
/* convert object type to mesh */
uv_from_orco = (tmpcu->flag & CU_UV_ORCO) != 0;
- BKE_mesh_from_nurbs_displist(tmpobj, &dispbase, uv_from_orco);
+ BKE_mesh_from_nurbs_displist(tmpobj, &dispbase, uv_from_orco, tmpcu->id.name + 2);
tmpmesh = tmpobj->data;
@@ -2268,6 +2502,12 @@ Mesh *BKE_mesh_new_from_object(
BKE_mesh_texspace_copy_from_object(tmpmesh, ob);
BKE_libblock_free_us(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
+ * Mesh ID, so we do not want to increase materials' usercount later. */
+ do_mat_id_data_us = false;
+
break;
}
@@ -2281,7 +2521,7 @@ Mesh *BKE_mesh_new_from_object(
if (ob != basis_ob)
return NULL; /* only do basis metaball */
- tmpmesh = BKE_mesh_add(bmain, "Mesh");
+ tmpmesh = BKE_mesh_add(bmain, ((ID *)ob->data)->name + 2);
/* BKE_mesh_add gives us a user count we don't need */
id_us_min(&tmpmesh->id);
@@ -2315,14 +2555,17 @@ Mesh *BKE_mesh_new_from_object(
if (cage) {
/* copies the data */
tmpmesh = BKE_mesh_copy(bmain, ob->data);
- /* if not getting the original caged mesh, get final derived mesh */
+
+ /* XXX BKE_mesh_copy() already handles materials usercount. */
+ do_mat_id_data_us = false;
}
+ /* if not getting the original caged mesh, get final derived mesh */
else {
/* Make a dummy mesh, saves copying */
DerivedMesh *dm;
/* 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 */
+ * for example, needs CD_MASK_MDEFORMVERT */
if (calc_undeformed)
mask |= CD_MASK_ORCO;
@@ -2333,8 +2576,13 @@ Mesh *BKE_mesh_new_from_object(
else
dm = mesh_create_derived_view(sce, ob, mask);
- tmpmesh = BKE_mesh_add(bmain, "Mesh");
+ tmpmesh = BKE_mesh_add(bmain, ((ID *)ob->data)->name + 2);
DM_to_mesh(dm, tmpmesh, ob, mask, true);
+
+ /* Copy autosmooth settings from original mesh. */
+ Mesh *me = (Mesh *)ob->data;
+ tmpmesh->flag |= (me->flag & ME_AUTOSMOOTH);
+ tmpmesh->smoothresh = me->smoothresh;
}
/* BKE_mesh_add/copy gives us a user count we don't need */
@@ -2357,10 +2605,9 @@ Mesh *BKE_mesh_new_from_object(
if (tmpcu->mat) {
for (i = tmpcu->totcol; i-- > 0; ) {
/* are we an object material or data based? */
+ tmpmesh->mat[i] = give_current_material(ob, i + 1);
- tmpmesh->mat[i] = ob->matbits[i] ? ob->mat[i] : tmpcu->mat[i];
-
- if (tmpmesh->mat[i]) {
+ if (((ob->matbits && ob->matbits[i]) || do_mat_id_data_us) && tmpmesh->mat[i]) {
id_us_plus(&tmpmesh->mat[i]->id);
}
}
@@ -2377,9 +2624,9 @@ Mesh *BKE_mesh_new_from_object(
if (tmpmb->mat) {
for (i = tmpmb->totcol; i-- > 0; ) {
/* are we an object material or data based? */
- tmpmesh->mat[i] = ob->matbits[i] ? ob->mat[i] : tmpmb->mat[i];
+ tmpmesh->mat[i] = give_current_material(ob, i + 1);
- if (tmpmesh->mat[i]) {
+ if (((ob->matbits && ob->matbits[i]) || do_mat_id_data_us) && tmpmesh->mat[i]) {
id_us_plus(&tmpmesh->mat[i]->id);
}
}
@@ -2397,9 +2644,9 @@ Mesh *BKE_mesh_new_from_object(
if (origmesh->mat) {
for (i = origmesh->totcol; i-- > 0; ) {
/* are we an object material or data based? */
- tmpmesh->mat[i] = ob->matbits[i] ? ob->mat[i] : origmesh->mat[i];
+ tmpmesh->mat[i] = give_current_material(ob, i + 1);
- if (tmpmesh->mat[i]) {
+ if (((ob->matbits && ob->matbits[i]) || do_mat_id_data_us) && tmpmesh->mat[i]) {
id_us_plus(&tmpmesh->mat[i]->id);
}
}
@@ -2428,3 +2675,20 @@ void BKE_mesh_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
BKE_mesh_texspace_calc(mesh);
}
}
+
+/* Draw Engine */
+void (*BKE_mesh_batch_cache_dirty_cb)(Mesh *me, int mode) = NULL;
+void (*BKE_mesh_batch_cache_free_cb)(Mesh *me) = NULL;
+
+void BKE_mesh_batch_cache_dirty(Mesh *me, int mode)
+{
+ if (me->batch_cache) {
+ BKE_mesh_batch_cache_dirty_cb(me, mode);
+ }
+}
+void BKE_mesh_batch_cache_free(Mesh *me)
+{
+ if (me->batch_cache) {
+ BKE_mesh_batch_cache_free_cb(me);
+ }
+} \ No newline at end of file
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index fa113ef5eef..ca8b58ffae3 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -58,6 +58,7 @@
#include "BLI_strict_flags.h"
+#include "atomic_ops.h"
#include "mikktspace.h"
// #define DEBUG_TIME
@@ -236,7 +237,9 @@ static void mesh_calc_normals_poly_accum_task_cb(void *userdata, const int pidx)
const float fac = saacos(-dot_v3v3(cur_edge, prev_edge));
/* accumulate */
- madd_v3_v3fl(vnors[ml[i].v], pnor, fac);
+ for (int k = 3; k--; ) {
+ atomic_add_and_fetch_fl(&vnors[ml[i].v][k], pnor[k] * fac);
+ }
prev_edge = cur_edge;
}
}
@@ -301,13 +304,13 @@ void BKE_mesh_calc_normals_poly(
void BKE_mesh_calc_normals(Mesh *mesh)
{
#ifdef DEBUG_TIME
- TIMEIT_START(BKE_mesh_calc_normals);
+ TIMEIT_START_AVERAGED(BKE_mesh_calc_normals);
#endif
BKE_mesh_calc_normals_poly(mesh->mvert, NULL, mesh->totvert,
mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly,
NULL, false);
#ifdef DEBUG_TIME
- TIMEIT_END(BKE_mesh_calc_normals);
+ TIMEIT_END_AVERAGED(BKE_mesh_calc_normals);
#endif
}
@@ -627,7 +630,6 @@ typedef struct LoopSplitTaskDataCommon {
* Note we do not need to protect it, though, since two different tasks will *always* affect different
* elements in the arrays. */
MLoopNorSpaceArray *lnors_spacearr;
- BLI_bitmap *sharp_verts;
float (*loopnors)[3];
short (*clnors_data)[2];
@@ -640,11 +642,8 @@ typedef struct LoopSplitTaskDataCommon {
const int *loop_to_poly;
const float (*polynors)[3];
+ int numLoops;
int numPolys;
-
- /* ***** Workers communication. ***** */
- ThreadQueue *task_queue;
-
} LoopSplitTaskDataCommon;
#define INDEX_UNSET INT_MIN
@@ -652,6 +651,50 @@ typedef struct LoopSplitTaskDataCommon {
/* See comment about edge_to_loops below. */
#define IS_EDGE_SHARP(_e2l) (ELEM((_e2l)[1], INDEX_UNSET, INDEX_INVALID))
+static void loop_manifold_fan_around_vert_next(
+ const MLoop *mloops, const MPoly *mpolys,
+ const int *loop_to_poly, const int *e2lfan_curr, const uint mv_pivot_index,
+ const MLoop **r_mlfan_curr, int *r_mlfan_curr_index, int *r_mlfan_vert_index, int *r_mpfan_curr_index)
+{
+ const MLoop *mlfan_next;
+ const MPoly *mpfan_next;
+
+ /* Warning! This is rather complex!
+ * We have to find our next edge around the vertex (fan mode).
+ * First we find the next loop, which is either previous or next to mlfan_curr_index, depending
+ * whether both loops using current edge are in the same direction or not, and whether
+ * mlfan_curr_index actually uses the vertex we are fanning around!
+ * mlfan_curr_index is the index of mlfan_next here, and mlfan_next is not the real next one
+ * (i.e. not the future mlfan_curr)...
+ */
+ *r_mlfan_curr_index = (e2lfan_curr[0] == *r_mlfan_curr_index) ? e2lfan_curr[1] : e2lfan_curr[0];
+ *r_mpfan_curr_index = loop_to_poly[*r_mlfan_curr_index];
+
+ BLI_assert(*r_mlfan_curr_index >= 0);
+ BLI_assert(*r_mpfan_curr_index >= 0);
+
+ mlfan_next = &mloops[*r_mlfan_curr_index];
+ mpfan_next = &mpolys[*r_mpfan_curr_index];
+ if (((*r_mlfan_curr)->v == mlfan_next->v && (*r_mlfan_curr)->v == mv_pivot_index) ||
+ ((*r_mlfan_curr)->v != mlfan_next->v && (*r_mlfan_curr)->v != mv_pivot_index))
+ {
+ /* We need the previous loop, but current one is our vertex's loop. */
+ *r_mlfan_vert_index = *r_mlfan_curr_index;
+ if (--(*r_mlfan_curr_index) < mpfan_next->loopstart) {
+ *r_mlfan_curr_index = mpfan_next->loopstart + mpfan_next->totloop - 1;
+ }
+ }
+ else {
+ /* We need the next loop, which is also our vertex's loop. */
+ if (++(*r_mlfan_curr_index) >= mpfan_next->loopstart + mpfan_next->totloop) {
+ *r_mlfan_curr_index = mpfan_next->loopstart;
+ }
+ *r_mlfan_vert_index = *r_mlfan_curr_index;
+ }
+ *r_mlfan_curr = &mloops[*r_mlfan_curr_index];
+ /* And now we are back in sync, mlfan_curr_index is the index of mlfan_curr! Pff! */
+}
+
static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopSplitTaskData *data)
{
MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
@@ -677,7 +720,7 @@ static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopS
*/
copy_v3_v3(*lnor, polynors[mp_index]);
- /* printf("BASIC: handling loop %d / edge %d / vert %d / poly %d\n", ml_curr_index, ml_curr->e, ml_curr->v, mp_index); */
+// printf("BASIC: handling loop %d / edge %d / vert %d / poly %d\n", ml_curr_index, ml_curr->e, ml_curr->v, mp_index);
/* If needed, generate this (simple!) lnor space. */
if (lnors_spacearr) {
@@ -744,8 +787,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
const MEdge *me_org = &medges[ml_curr->e]; /* ml_curr would be mlfan_prev if we needed that one */
const int *e2lfan_curr;
float vec_curr[3], vec_prev[3], vec_org[3];
- const MLoop *mlfan_curr, *mlfan_next;
- const MPoly *mpfan_next;
+ const MLoop *mlfan_curr;
float lnor[3] = {0.0f, 0.0f, 0.0f};
/* mlfan_vert_index: the loop of our current edge might not be the loop of our current vertex! */
int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index;
@@ -784,7 +826,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
}
}
- /* printf("FAN: vert %d, start edge %d\n", mv_pivot_index, ml_curr->e); */
+// printf("FAN: vert %d, start edge %d\n", mv_pivot_index, ml_curr->e);
while (true) {
const MEdge *me_curr = &medges[mlfan_curr->e];
@@ -800,7 +842,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
normalize_v3(vec_curr);
}
- /* printf("\thandling edge %d / loop %d\n", mlfan_curr->e, mlfan_curr_index); */
+// printf("\thandling edge %d / loop %d\n", mlfan_curr->e, mlfan_curr_index);
{
/* Code similar to accumulate_vertex_normals_poly. */
@@ -842,46 +884,16 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
/* Current edge is sharp and we have finished with this fan of faces around this vert,
* or this vert is smooth, and we have completed a full turn around it.
*/
- /* printf("FAN: Finished!\n"); */
+// printf("FAN: Finished!\n");
break;
}
copy_v3_v3(vec_prev, vec_curr);
- /* Warning! This is rather complex!
- * We have to find our next edge around the vertex (fan mode).
- * First we find the next loop, which is either previous or next to mlfan_curr_index, depending
- * whether both loops using current edge are in the same direction or not, and whether
- * mlfan_curr_index actually uses the vertex we are fanning around!
- * mlfan_curr_index is the index of mlfan_next here, and mlfan_next is not the real next one
- * (i.e. not the future mlfan_curr)...
- */
- mlfan_curr_index = (e2lfan_curr[0] == mlfan_curr_index) ? e2lfan_curr[1] : e2lfan_curr[0];
- mpfan_curr_index = loop_to_poly[mlfan_curr_index];
-
- BLI_assert(mlfan_curr_index >= 0);
- BLI_assert(mpfan_curr_index >= 0);
-
- mlfan_next = &mloops[mlfan_curr_index];
- mpfan_next = &mpolys[mpfan_curr_index];
- if ((mlfan_curr->v == mlfan_next->v && mlfan_curr->v == mv_pivot_index) ||
- (mlfan_curr->v != mlfan_next->v && mlfan_curr->v != mv_pivot_index))
- {
- /* We need the previous loop, but current one is our vertex's loop. */
- mlfan_vert_index = mlfan_curr_index;
- if (--mlfan_curr_index < mpfan_next->loopstart) {
- mlfan_curr_index = mpfan_next->loopstart + mpfan_next->totloop - 1;
- }
- }
- else {
- /* We need the next loop, which is also our vertex's loop. */
- if (++mlfan_curr_index >= mpfan_next->loopstart + mpfan_next->totloop) {
- mlfan_curr_index = mpfan_next->loopstart;
- }
- mlfan_vert_index = mlfan_curr_index;
- }
- mlfan_curr = &mloops[mlfan_curr_index];
- /* And now we are back in sync, mlfan_curr_index is the index of mlfan_curr! Pff! */
+ /* Find next loop of the smooth fan. */
+ loop_manifold_fan_around_vert_next(
+ mloops, mpolys, loop_to_poly, e2lfan_curr, mv_pivot_index,
+ &mlfan_curr, &mlfan_curr_index, &mlfan_vert_index, &mpfan_curr_index);
e2lfan_curr = edge_to_loops[mlfan_curr->e];
}
@@ -952,31 +964,25 @@ static void loop_split_worker_do(
}
}
-static void loop_split_worker(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
+static void loop_split_worker(TaskPool * __restrict pool, void *taskdata, int UNUSED(threadid))
{
- LoopSplitTaskDataCommon *common_data = taskdata;
- LoopSplitTaskData *data_buff;
+ LoopSplitTaskDataCommon *common_data = BLI_task_pool_userdata(pool);
+ LoopSplitTaskData *data = taskdata;
/* Temp edge vectors stack, only used when computing lnor spacearr. */
BLI_Stack *edge_vectors = common_data->lnors_spacearr ? BLI_stack_new(sizeof(float[3]), __func__) : NULL;
#ifdef DEBUG_TIME
- TIMEIT_START(loop_split_worker);
+ TIMEIT_START_AVERAGED(loop_split_worker);
#endif
- while ((data_buff = BLI_thread_queue_pop(common_data->task_queue))) {
- LoopSplitTaskData *data = data_buff;
- int i;
-
- for (i = 0; i < LOOP_SPLIT_TASK_BLOCK_SIZE; i++, data++) {
- /* A NULL ml_curr is used to tag ended data! */
- if (data->ml_curr == NULL) {
- break;
- }
- loop_split_worker_do(common_data, data, edge_vectors);
+ for (int i = 0; i < LOOP_SPLIT_TASK_BLOCK_SIZE; i++, data++) {
+ /* A NULL ml_curr is used to tag ended data! */
+ if (data->ml_curr == NULL) {
+ break;
}
- MEM_freeN(data_buff);
+ loop_split_worker_do(common_data, data, edge_vectors);
}
if (edge_vectors) {
@@ -984,49 +990,117 @@ static void loop_split_worker(TaskPool * __restrict UNUSED(pool), void *taskdata
}
#ifdef DEBUG_TIME
- TIMEIT_END(loop_split_worker);
+ TIMEIT_END_AVERAGED(loop_split_worker);
#endif
}
-/* Note we use data_buff to detect whether we are in threaded context or not, in later case it is NULL. */
-static void loop_split_generator_do(LoopSplitTaskDataCommon *common_data, const bool threaded)
+/* Check whether gievn loop is part of an unknown-so-far cyclic smooth fan, or not.
+ * Needed because cyclic smooth fans have no obvious 'entry point', and yet we need to walk them once, and only once. */
+static bool loop_split_generator_check_cyclic_smooth_fan(
+ const MLoop *mloops, const MPoly *mpolys,
+ const int (*edge_to_loops)[2], const int *loop_to_poly, const int *e2l_prev, BLI_bitmap *skip_loops,
+ const MLoop *ml_curr, const MLoop *ml_prev, const int ml_curr_index, const int ml_prev_index,
+ const int mp_curr_index)
+{
+ const unsigned int mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
+ const int *e2lfan_curr;
+ const MLoop *mlfan_curr;
+ /* mlfan_vert_index: the loop of our current edge might not be the loop of our current vertex! */
+ int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index;
+
+ e2lfan_curr = e2l_prev;
+ if (IS_EDGE_SHARP(e2lfan_curr)) {
+ /* Sharp loop, so not a cyclic smooth fan... */
+ return false;
+ }
+
+ mlfan_curr = ml_prev;
+ mlfan_curr_index = ml_prev_index;
+ mlfan_vert_index = ml_curr_index;
+ mpfan_curr_index = mp_curr_index;
+
+ BLI_assert(mlfan_curr_index >= 0);
+ BLI_assert(mlfan_vert_index >= 0);
+ BLI_assert(mpfan_curr_index >= 0);
+
+ BLI_assert(!BLI_BITMAP_TEST(skip_loops, mlfan_vert_index));
+ BLI_BITMAP_ENABLE(skip_loops, mlfan_vert_index);
+
+ while (true) {
+ /* Find next loop of the smooth fan. */
+ loop_manifold_fan_around_vert_next(
+ mloops, mpolys, loop_to_poly, e2lfan_curr, mv_pivot_index,
+ &mlfan_curr, &mlfan_curr_index, &mlfan_vert_index, &mpfan_curr_index);
+
+ e2lfan_curr = edge_to_loops[mlfan_curr->e];
+
+ if (IS_EDGE_SHARP(e2lfan_curr)) {
+ /* Sharp loop/edge, so not a cyclic smooth fan... */
+ return false;
+ }
+ /* Smooth loop/edge... */
+ else if (BLI_BITMAP_TEST(skip_loops, mlfan_vert_index)) {
+ if (mlfan_vert_index == ml_curr_index) {
+ /* We walked around a whole cyclic smooth fan without finding any already-processed loop, means we can
+ * use initial ml_curr/ml_prev edge as start for this smooth fan. */
+ return true;
+ }
+ /* ... already checked in some previous looping, we can abort. */
+ return false;
+ }
+ else {
+ /* ... we can skip it in future, and keep checking the smooth fan. */
+ BLI_BITMAP_ENABLE(skip_loops, mlfan_vert_index);
+ }
+ }
+}
+
+static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common_data)
{
MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
- BLI_bitmap *sharp_verts = common_data->sharp_verts;
float (*loopnors)[3] = common_data->loopnors;
const MLoop *mloops = common_data->mloops;
const MPoly *mpolys = common_data->mpolys;
+ const int *loop_to_poly = common_data->loop_to_poly;
const int (*edge_to_loops)[2] = common_data->edge_to_loops;
+ const int numLoops = common_data->numLoops;
const int numPolys = common_data->numPolys;
const MPoly *mp;
int mp_index;
- LoopSplitTaskData *data, *data_buff = NULL, data_mem;
+ const MLoop *ml_curr;
+ const MLoop *ml_prev;
+ int ml_curr_index;
+ int ml_prev_index;
+
+ BLI_bitmap *skip_loops = BLI_BITMAP_NEW(numLoops, __func__);
+
+ LoopSplitTaskData *data_buff = NULL;
int data_idx = 0;
/* Temp edge vectors stack, only used when computing lnor spacearr (and we are not multi-threading). */
- BLI_Stack *edge_vectors = (lnors_spacearr && !data_buff) ? BLI_stack_new(sizeof(float[3]), __func__) : NULL;
+ BLI_Stack *edge_vectors = NULL;
#ifdef DEBUG_TIME
- TIMEIT_START(loop_split_generator);
+ TIMEIT_START_AVERAGED(loop_split_generator);
#endif
- if (!threaded) {
- memset(&data_mem, 0, sizeof(data_mem));
- data = &data_mem;
+ if (!pool) {
+ if (lnors_spacearr) {
+ edge_vectors = BLI_stack_new(sizeof(float[3]), __func__);
+ }
}
/* We now know edges that can be smoothed (with their vector, and their two loops), and edges that will be hard!
* Now, time to generate the normals.
*/
for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) {
- const MLoop *ml_curr, *ml_prev;
float (*lnors)[3];
const int ml_last_index = (mp->loopstart + mp->totloop) - 1;
- int ml_curr_index = mp->loopstart;
- int ml_prev_index = ml_last_index;
+ ml_curr_index = mp->loopstart;
+ ml_prev_index = ml_last_index;
ml_curr = &mloops[ml_curr_index];
ml_prev = &mloops[ml_prev_index];
@@ -1036,23 +1110,40 @@ static void loop_split_generator_do(LoopSplitTaskDataCommon *common_data, const
const int *e2l_curr = edge_to_loops[ml_curr->e];
const int *e2l_prev = edge_to_loops[ml_prev->e];
- if (!IS_EDGE_SHARP(e2l_curr) && (!lnors_spacearr || BLI_BITMAP_TEST_BOOL(sharp_verts, ml_curr->v))) {
- /* A smooth edge, and we are not generating lnor_spacearr, or the related vertex is sharp.
- * We skip it because it is either:
- * - in the middle of a 'smooth fan' already computed (or that will be as soon as we hit
- * one of its ends, i.e. one of its two sharp edges), or...
- * - the related vertex is a "full smooth" one, in which case pre-populated normals from vertex
- * are just fine (or it has already be handled in a previous loop in case of needed lnors spacearr)!
- */
- /* printf("Skipping loop %d / edge %d / vert %d(%d)\n", ml_curr_index, ml_curr->e, ml_curr->v, sharp_verts[ml_curr->v]); */
+// printf("Checking loop %d / edge %u / vert %u (sharp edge: %d, skiploop: %d)...",
+// ml_curr_index, ml_curr->e, ml_curr->v, IS_EDGE_SHARP(e2l_curr), BLI_BITMAP_TEST_BOOL(skip_loops, ml_curr_index));
+
+ /* 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. */
+ /* Note: In theory, we could make loop_split_generator_check_cyclic_smooth_fan() store
+ * mlfan_vert_index'es and edge indexes in two stacks, to avoid having to fan again around the vert during
+ * actual computation of clnor & clnorspace. However, this would complicate the code, add more memory usage,
+ * and despite its logical complexity, loop_manifold_fan_around_vert_next() is quite cheap in term of
+ * CPU cycles, so really think it's not worth it. */
+ if (!IS_EDGE_SHARP(e2l_curr) &&
+ (BLI_BITMAP_TEST(skip_loops, ml_curr_index) ||
+ !loop_split_generator_check_cyclic_smooth_fan(
+ mloops, mpolys, edge_to_loops, loop_to_poly, e2l_prev, skip_loops,
+ ml_curr, ml_prev, ml_curr_index, ml_prev_index, mp_index)))
+ {
+// printf("SKIPPING!\n");
}
else {
- if (threaded) {
+ LoopSplitTaskData *data, data_local;
+
+// printf("PROCESSING!\n");
+
+ if (pool) {
if (data_idx == 0) {
data_buff = MEM_callocN(sizeof(*data_buff) * LOOP_SPLIT_TASK_BLOCK_SIZE, __func__);
}
data = &data_buff[data_idx];
}
+ else {
+ data = &data_local;
+ memset(data, 0, sizeof(*data));
+ }
if (IS_EDGE_SHARP(e2l_curr) && IS_EDGE_SHARP(e2l_prev)) {
data->lnor = lnors;
@@ -1088,22 +1179,18 @@ static void loop_split_generator_do(LoopSplitTaskDataCommon *common_data, const
data->mp_index = mp_index;
if (lnors_spacearr) {
data->lnor_space = BKE_lnor_space_create(lnors_spacearr);
- /* Tag related vertex as sharp, to avoid fanning around it again (in case it was a smooth one).
- * This *has* to be done outside of workers tasks! */
- BLI_BITMAP_ENABLE(sharp_verts, ml_curr->v);
}
}
- if (threaded) {
+ if (pool) {
data_idx++;
if (data_idx == LOOP_SPLIT_TASK_BLOCK_SIZE) {
- BLI_thread_queue_push(common_data->task_queue, data_buff);
+ BLI_task_pool_push(pool, loop_split_worker, data_buff, true, TASK_PRIORITY_LOW);
data_idx = 0;
}
}
else {
loop_split_worker_do(common_data, data, edge_vectors);
- memset(data, 0, sizeof(data_mem));
}
}
@@ -1112,44 +1199,32 @@ static void loop_split_generator_do(LoopSplitTaskDataCommon *common_data, const
}
}
- if (threaded) {
- /* Last block of data... Since it is calloc'ed and we use first NULL item as stopper, everything is fine. */
- if (LIKELY(data_idx)) {
- BLI_thread_queue_push(common_data->task_queue, data_buff);
- }
-
- /* This will signal all other worker threads to wake up and finish! */
- BLI_thread_queue_nowait(common_data->task_queue);
+ /* Last block of data... Since it is calloc'ed and we use first NULL item as stopper, everything is fine. */
+ if (pool && data_idx) {
+ BLI_task_pool_push(pool, loop_split_worker, data_buff, true, TASK_PRIORITY_LOW);
}
if (edge_vectors) {
BLI_stack_free(edge_vectors);
}
+ MEM_freeN(skip_loops);
#ifdef DEBUG_TIME
- TIMEIT_END(loop_split_generator);
+ TIMEIT_END_AVERAGED(loop_split_generator);
#endif
}
-static void loop_split_generator(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
-{
- LoopSplitTaskDataCommon *common_data = taskdata;
-
- loop_split_generator_do(common_data, true);
-}
-
/**
* Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
* Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry (splitting edges).
*/
void BKE_mesh_normals_loop_split(
- const MVert *mverts, const int numVerts, MEdge *medges, const int numEdges,
+ const MVert *mverts, const int UNUSED(numVerts), MEdge *medges, const int numEdges,
MLoop *mloops, float (*r_loopnors)[3], const int numLoops,
MPoly *mpolys, const float (*polynors)[3], const int numPolys,
const bool use_split_normals, float split_angle,
MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], int *r_loop_to_poly)
{
-
/* For now this is not supported. If we do not use split normals, we do not generate anything fancy! */
BLI_assert(use_split_normals || !(r_lnors_spacearr));
@@ -1182,8 +1257,6 @@ void BKE_mesh_normals_loop_split(
return;
}
- {
-
/* Mapping edge -> loops.
* If that edge is used by more than two loops (polys), it is always sharp (and tagged as such, see below).
* We also use the second loop index as a kind of flag: smooth edge: > 0,
@@ -1193,33 +1266,25 @@ void BKE_mesh_normals_loop_split(
* store the negated value of loop index instead of INDEX_INVALID to retrieve the real value later in code).
* Note also that lose edges always have both values set to 0!
*/
- int (*edge_to_loops)[2] = MEM_callocN(sizeof(int[2]) * (size_t)numEdges, __func__);
+ int (*edge_to_loops)[2] = MEM_callocN(sizeof(*edge_to_loops) * (size_t)numEdges, __func__);
/* Simple mapping from a loop to its polygon index. */
- int *loop_to_poly = r_loop_to_poly ? r_loop_to_poly : MEM_mallocN(sizeof(int) * (size_t)numLoops, __func__);
+ int *loop_to_poly = r_loop_to_poly ? r_loop_to_poly : MEM_mallocN(sizeof(*loop_to_poly) * (size_t)numLoops, __func__);
MPoly *mp;
- int mp_index, me_index;
- bool check_angle = (split_angle < (float)M_PI);
- int i;
+ int mp_index;
- BLI_bitmap *sharp_verts = NULL;
- MLoopNorSpaceArray _lnors_spacearr = {NULL};
+ /* When using custom loop normals, disable the angle feature! */
+ const bool check_angle = (split_angle < (float)M_PI) && (clnors_data == NULL);
- LoopSplitTaskDataCommon common_data = {NULL};
+ MLoopNorSpaceArray _lnors_spacearr = {NULL};
#ifdef DEBUG_TIME
- TIMEIT_START(BKE_mesh_normals_loop_split);
+ TIMEIT_START_AVERAGED(BKE_mesh_normals_loop_split);
#endif
if (check_angle) {
- /* When using custom loop normals, disable the angle feature! */
- if (clnors_data) {
- check_angle = false;
- }
- else {
- split_angle = cosf(split_angle);
- }
+ split_angle = cosf(split_angle);
}
if (!r_lnors_spacearr && clnors_data) {
@@ -1228,7 +1293,6 @@ void BKE_mesh_normals_loop_split(
}
if (r_lnors_spacearr) {
BKE_lnor_spacearr_init(r_lnors_spacearr, numLoops);
- sharp_verts = BLI_BITMAP_NEW((size_t)numVerts, __func__);
}
/* This first loop check which edges are actually smooth, and compute edge vectors. */
@@ -1282,60 +1346,38 @@ void BKE_mesh_normals_loop_split(
}
}
- if (r_lnors_spacearr) {
- /* Tag vertices that have at least one sharp edge as 'sharp' (used for the lnor spacearr computation).
- * XXX This third loop over edges is a bit disappointing, could not find any other way yet.
- * Not really performance-critical anyway.
- */
- for (me_index = 0; me_index < numEdges; me_index++) {
- const int *e2l = edge_to_loops[me_index];
- const MEdge *me = &medges[me_index];
- if (IS_EDGE_SHARP(e2l)) {
- BLI_BITMAP_ENABLE(sharp_verts, me->v1);
- BLI_BITMAP_ENABLE(sharp_verts, me->v2);
- }
- }
- }
-
/* Init data common to all tasks. */
- common_data.lnors_spacearr = r_lnors_spacearr;
- common_data.loopnors = r_loopnors;
- common_data.clnors_data = clnors_data;
-
- common_data.mverts = mverts;
- common_data.medges = medges;
- common_data.mloops = mloops;
- common_data.mpolys = mpolys;
- common_data.sharp_verts = sharp_verts;
- common_data.edge_to_loops = (const int(*)[2])edge_to_loops;
- common_data.loop_to_poly = loop_to_poly;
- common_data.polynors = polynors;
- common_data.numPolys = numPolys;
+ LoopSplitTaskDataCommon common_data = {
+ .lnors_spacearr = r_lnors_spacearr,
+ .loopnors = r_loopnors,
+ .clnors_data = clnors_data,
+ .mverts = mverts,
+ .medges = medges,
+ .mloops = mloops,
+ .mpolys = mpolys,
+ .edge_to_loops = (const int(*)[2])edge_to_loops,
+ .loop_to_poly = loop_to_poly,
+ .polynors = polynors,
+ .numLoops = numLoops,
+ .numPolys = numPolys,
+ };
if (numLoops < LOOP_SPLIT_TASK_BLOCK_SIZE * 8) {
/* Not enough loops to be worth the whole threading overhead... */
- loop_split_generator_do(&common_data, false);
+ loop_split_generator(NULL, &common_data);
}
else {
TaskScheduler *task_scheduler;
TaskPool *task_pool;
- int nbr_workers;
-
- common_data.task_queue = BLI_thread_queue_init();
task_scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create(task_scheduler, NULL);
+ task_pool = BLI_task_pool_create(task_scheduler, &common_data);
+
+ loop_split_generator(task_pool, &common_data);
- nbr_workers = max_ii(2, BLI_task_scheduler_num_threads(task_scheduler));
- for (i = 1; i < nbr_workers; i++) {
- BLI_task_pool_push(task_pool, loop_split_worker, &common_data, false, TASK_PRIORITY_HIGH);
- }
- BLI_task_pool_push(task_pool, loop_split_generator, &common_data, false, TASK_PRIORITY_HIGH);
BLI_task_pool_work_and_wait(task_pool);
BLI_task_pool_free(task_pool);
-
- BLI_thread_queue_free(common_data.task_queue);
}
MEM_freeN(edge_to_loops);
@@ -1344,17 +1386,14 @@ void BKE_mesh_normals_loop_split(
}
if (r_lnors_spacearr) {
- MEM_freeN(sharp_verts);
if (r_lnors_spacearr == &_lnors_spacearr) {
BKE_lnor_spacearr_free(r_lnors_spacearr);
}
}
#ifdef DEBUG_TIME
- TIMEIT_END(BKE_mesh_normals_loop_split);
+ TIMEIT_END_AVERAGED(BKE_mesh_normals_loop_split);
#endif
-
- }
}
#undef INDEX_UNSET
@@ -1590,8 +1629,8 @@ void BKE_mesh_normals_loop_custom_from_vertices_set(
/**
* Computes average per-vertex normals from given custom loop normals.
*
- * @param clnors The computed custom loop normals.
- * @param r_vert_clnors The (already allocated) array where to store averaged per-vertex normals.
+ * \param clnors: The computed custom loop normals.
+ * \param r_vert_clnors: The (already allocated) array where to store averaged per-vertex normals.
*/
void BKE_mesh_normals_loop_to_vertex(
const int numVerts, const MLoop *mloops, const int numLoops,
@@ -1626,152 +1665,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
* \{ */
@@ -1906,19 +1799,19 @@ void BKE_mesh_calc_poly_center(
const MVert *mvarray, float r_cent[3])
{
if (mpoly->totloop == 3) {
- cent_tri_v3(r_cent,
- mvarray[loopstart[0].v].co,
- mvarray[loopstart[1].v].co,
- mvarray[loopstart[2].v].co
- );
+ mid_v3_v3v3v3(r_cent,
+ mvarray[loopstart[0].v].co,
+ mvarray[loopstart[1].v].co,
+ mvarray[loopstart[2].v].co
+ );
}
else if (mpoly->totloop == 4) {
- cent_quad_v3(r_cent,
- mvarray[loopstart[0].v].co,
- mvarray[loopstart[1].v].co,
- mvarray[loopstart[2].v].co,
- mvarray[loopstart[3].v].co
- );
+ mid_v3_v3v3v3v3(r_cent,
+ mvarray[loopstart[0].v].co,
+ mvarray[loopstart[1].v].co,
+ mvarray[loopstart[2].v].co,
+ mvarray[loopstart[3].v].co
+ );
}
else {
mesh_calc_ngon_center(mpoly, loopstart, mvarray, r_cent);
@@ -1954,36 +1847,54 @@ float BKE_mesh_calc_poly_area(
}
}
-/* note, results won't be correct if polygon is non-planar */
-static float mesh_calc_poly_planar_area_centroid(
+/**
+ * Calculate the volume and volume-weighted centroid of the volume formed by the polygon and the origin.
+ * Results will be negative if the origin is "outside" the polygon
+ * (+ve normal side), but the polygon may be non-planar with no effect.
+ *
+ * Method from:
+ * - http://forums.cgsociety.org/archive/index.php?t-756235.html
+ * - http://www.globalspec.com/reference/52702/203279/4-8-the-centroid-of-a-tetrahedron
+ *
+ * \note volume is 6x actual volume, and centroid is 4x actual volume-weighted centroid
+ * (so division can be done once at the end)
+ * \note results will have bias if polygon is non-planar.
+ */
+static float mesh_calc_poly_volume_and_weighted_centroid(
const MPoly *mpoly, const MLoop *loopstart, const MVert *mvarray,
float r_cent[3])
{
- int i;
- float tri_area;
- float total_area = 0.0f;
- float v1[3], v2[3], v3[3], normal[3], tri_cent[3];
+ const float *v_pivot, *v_step1;
+ float total_volume = 0.0f;
- BKE_mesh_calc_poly_normal(mpoly, loopstart, mvarray, normal);
- copy_v3_v3(v1, mvarray[loopstart[0].v].co);
- copy_v3_v3(v2, mvarray[loopstart[1].v].co);
zero_v3(r_cent);
- for (i = 2; i < mpoly->totloop; i++) {
- copy_v3_v3(v3, mvarray[loopstart[i].v].co);
+ v_pivot = mvarray[loopstart[0].v].co;
+ v_step1 = mvarray[loopstart[1].v].co;
- tri_area = area_tri_signed_v3(v1, v2, v3, normal);
- total_area += tri_area;
+ for (int i = 2; i < mpoly->totloop; i++) {
+ const float *v_step2 = mvarray[loopstart[i].v].co;
- cent_tri_v3(tri_cent, v1, v2, v3);
- madd_v3_v3fl(r_cent, tri_cent, tri_area);
+ /* Calculate the 6x volume of the tetrahedron formed by the 3 vertices
+ * of the triangle and the origin as the fourth vertex */
+ float v_cross[3];
+ cross_v3_v3v3(v_cross, v_pivot, v_step1);
+ const float tetra_volume = dot_v3v3 (v_cross, v_step2);
+ total_volume += tetra_volume;
- copy_v3_v3(v2, v3);
- }
+ /* Calculate the centroid of the tetrahedron formed by the 3 vertices
+ * of the triangle and the origin as the fourth vertex.
+ * The centroid is simply the average of the 4 vertices.
+ *
+ * Note that the vector is 4x the actual centroid so the division can be done once at the end. */
+ for (uint j = 0; j < 3; j++) {
+ r_cent[j] += tetra_volume * (v_pivot[j] + v_step1[j] + v_step2[j]);
+ }
- mul_v3_fl(r_cent, 1.0f / total_area);
+ v_step1 = v_step2;
+ }
- return total_area;
+ return total_volume;
}
#if 0 /* slow version of the function below */
@@ -2104,25 +2015,28 @@ bool BKE_mesh_center_centroid(const Mesh *me, float r_cent[3])
{
int i = me->totpoly;
MPoly *mpoly;
- float poly_area;
- float total_area = 0.0f;
+ float poly_volume;
+ float total_volume = 0.0f;
float poly_cent[3];
zero_v3(r_cent);
- /* calculate a weighted average of polygon centroids */
+ /* calculate a weighted average of polyhedron centroids */
for (mpoly = me->mpoly; i--; mpoly++) {
- poly_area = mesh_calc_poly_planar_area_centroid(mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent);
+ poly_volume = mesh_calc_poly_volume_and_weighted_centroid(mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent);
- madd_v3_v3fl(r_cent, poly_cent, poly_area);
- total_area += poly_area;
+ /* poly_cent is already volume-weighted, so no need to multiply by the volume */
+ add_v3_v3(r_cent, poly_cent);
+ total_volume += poly_volume;
}
/* otherwise we get NAN for 0 polys */
- if (me->totpoly) {
- mul_v3_fl(r_cent, 1.0f / total_area);
+ if (total_volume != 0.0f) {
+ /* multipy by 0.25 to get the correct centroid */
+ /* no need to divide volume by 6 as the centroid is weighted by 6x the volume, so it all cancels out */
+ mul_v3_fl(r_cent, 0.25f / total_volume);
}
- /* zero area faces cause this, fallback to median */
+ /* this can happen for non-manifold objects, fallback to median */
if (UNLIKELY(!is_finite_v3(r_cent))) {
return BKE_mesh_center_median(me, r_cent);
}
@@ -2247,12 +2161,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) */
@@ -2260,17 +2174,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);
@@ -2322,14 +2232,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,
+void BKE_mesh_loops_to_tessdata(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);
@@ -2339,17 +2249,14 @@ void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData
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);
}
@@ -2672,7 +2579,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
@@ -2693,7 +2600,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.
@@ -2872,7 +2779,7 @@ int BKE_mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata,
MPoly *mp, *mpoly;
MFace *mface, *mf;
- 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);
@@ -2912,7 +2819,7 @@ int BKE_mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata,
CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mface, totface);
- CustomData_from_bmeshpoly(fdata, pdata, ldata, totface);
+ CustomData_from_bmeshpoly(fdata, ldata, totface);
mp = mpoly;
k = 0;
@@ -2934,9 +2841,10 @@ int BKE_mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata,
mf->v2 = mloop[mf->v2].v;
mf->v3 = mloop[mf->v3].v;
- BKE_mesh_loops_to_mface_corners(fdata, ldata, pdata,
- lindex, k, i, 3,
- numTex, numCol, hasPCol, hasOrigSpace, hasLNor);
+ BKE_mesh_loops_to_mface_corners(
+ fdata, ldata, pdata,
+ lindex, k, i, 3,
+ numUV, numCol, hasPCol, hasOrigSpace, hasLNor);
test_index_face(mf, fdata, k, 3);
}
else {
@@ -2954,9 +2862,10 @@ int BKE_mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata,
mf->v3 = mloop[mf->v3].v;
mf->v4 = mloop[mf->v4].v;
- BKE_mesh_loops_to_mface_corners(fdata, ldata, pdata,
- lindex, k, i, 4,
- numTex, numCol, hasPCol, hasOrigSpace, hasLNor);
+ BKE_mesh_loops_to_mface_corners(
+ fdata, ldata, pdata,
+ lindex, k, i, 4,
+ numUV, numCol, hasPCol, hasOrigSpace, hasLNor);
test_index_face(mf, fdata, k, 4);
}
@@ -2971,11 +2880,11 @@ int BKE_mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata,
#endif /* USE_BMESH_SAVE_AS_COMPAT */
-static void bm_corners_to_loops_ex(ID *id, CustomData *fdata, CustomData *ldata, CustomData *pdata,
- MFace *mface, int totloop, int findex, int loopstart, int numTex, int numCol)
+static void bm_corners_to_loops_ex(
+ 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;
@@ -2986,9 +2895,6 @@ static void bm_corners_to_loops_ex(ID *id, CustomData *fdata, CustomData *ldata,
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++;
@@ -3096,7 +3002,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);
}
@@ -3139,7 +3045,7 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id, CustomData *fdata, CustomData
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 */
@@ -3189,7 +3095,7 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id, CustomData *fdata, CustomData
# 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_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c
index 8562988b5e1..525c0c9728e 100644
--- a/source/blender/blenkernel/intern/mesh_mapping.c
+++ b/source/blender/blenkernel/intern/mesh_mapping.c
@@ -165,7 +165,7 @@ UvVertMap *BKE_mesh_uv_vert_map_create(
vmap->vert[a] = newvlist;
}
- if (use_winding) {
+ if (use_winding) {
MEM_freeN(winding);
}
diff --git a/source/blender/blenkernel/intern/mesh_sample.c b/source/blender/blenkernel/intern/mesh_sample.c
index ca4cb6dbbd3..82efd568c21 100644
--- a/source/blender/blenkernel/intern/mesh_sample.c
+++ b/source/blender/blenkernel/intern/mesh_sample.c
@@ -156,7 +156,7 @@ BLI_INLINE void mesh_sample_weights_from_loc(MeshSample *sample, DerivedMesh *dm
float w[4];
int tri[3];
- interp_weights_face_v3_index(tri, w, v1, v2, v3, v4, loc);
+ interp_weights_quad_v3_index(tri, w, v1, v2, v3, v4, loc);
sample->orig_verts[0] = index[tri[0]];
sample->orig_verts[1] = index[tri[1]];
@@ -700,7 +700,7 @@ bool BKE_mesh_sample_from_particle(MeshSample *sample, ParticleSystem *psys, Der
}
/* test both triangles of the face */
- interp_weights_face_v3(w, co1, co2, co3, NULL, vec);
+ interp_weights_quad_v3(w, co1, co2, co3, NULL, vec);
if (w[0] <= 1.0f && w[1] <= 1.0f && w[2] <= 1.0f) {
sample->orig_verts[0] = mface->v1;
sample->orig_verts[1] = mface->v2;
@@ -710,7 +710,7 @@ bool BKE_mesh_sample_from_particle(MeshSample *sample, ParticleSystem *psys, Der
return true;
}
else if (mface->v4) {
- interp_weights_face_v3(w, co3, co4, co1, NULL, vec);
+ interp_weights_quad_v3(w, co3, co4, co1, NULL, vec);
sample->orig_verts[0] = mface->v3;
sample->orig_verts[1] = mface->v4;
sample->orig_verts[2] = mface->v1;
@@ -744,7 +744,7 @@ bool BKE_mesh_sample_to_particle(MeshSample *sample, ParticleSystem *UNUSED(psys
pa->num = nearest.index;
pa->num_dmcache = DMCACHE_NOTFOUND;
- interp_weights_face_v3(pa->fuv, co1, co2, co3, co4, vec);
+ interp_weights_quad_v3(pa->fuv, co1, co2, co3, co4, vec);
pa->foffset = 0.0f; /* XXX any sensible way to reconstruct this? */
return true;
diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c
new file mode 100644
index 00000000000..c1b74b3eb6f
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_tangent.c
@@ -0,0 +1,692 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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 */
+#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;
+ 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 */
+ }
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index ba890b005d8..54de843bc64 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -43,10 +43,11 @@
#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... */
@@ -584,8 +585,8 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
int prev_e = ml->e;
ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, v1, v2));
fix_flag.loops_edge = true;
- PRINT_ERR("\tPoly %u has invalid edge reference (%d), fixed using edge %u\n",
- sp->index, prev_e, ml->e);
+ PRINT_ERR("\tPoly %u has invalid edge reference (%d, is_removed: %d), fixed using edge %u\n",
+ sp->index, prev_e, IS_REMOVED_EDGE(me), ml->e);
}
else {
PRINT_ERR("\tPoly %u has invalid edge reference (%u)\n", sp->index, ml->e);
@@ -936,7 +937,7 @@ bool BKE_mesh_validate_all_customdata(CustomData *vdata, CustomData *edata,
{
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);
@@ -944,17 +945,8 @@ bool BKE_mesh_validate_all_customdata(CustomData *vdata, CustomData *edata,
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);
@@ -965,18 +957,10 @@ bool BKE_mesh_validate_all_customdata(CustomData *vdata, CustomData *edata,
}
/* 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;
@@ -1019,7 +1003,7 @@ int BKE_mesh_validate(Mesh *me, const int do_verbose, const int cddata_check_mas
&changed);
if (changed) {
- DAG_id_tag_update(&me->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&me->id, OB_RECALC_DATA);
return true;
}
else {
@@ -1028,64 +1012,6 @@ int BKE_mesh_validate(Mesh *me, const int do_verbose, const int cddata_check_mas
}
/**
- * Duplicate of BM_mesh_cd_validate() for Mesh data.
- */
-void BKE_mesh_cd_validate(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;
-
- /* 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);
- }
-
- 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);
- }
-
- BLI_assert(totlayer_mtex == totlayer_uv);
-
- /* 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);
- }
- }
-}
-
-/**
* Check all material indices of polygons are valid, invalid ones are set to 0.
* \returns is_valid.
*/
@@ -1105,7 +1031,7 @@ int 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 {
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 41e4c21d814..2276d56b9c6 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -49,10 +49,11 @@
#include "DNA_object_types.h"
#include "BLI_utildefines.h"
-#include "BLI_path_util.h"
#include "BLI_listbase.h"
#include "BLI_linklist.h"
+#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index 0d362086134..dfa8742a295 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -1033,7 +1033,7 @@ static ImBuf *get_stable_cached_frame(MovieClip *clip, MovieClipUser *user, ImBu
stableibuf = cache->stabilized.ibuf;
- BKE_tracking_stabilization_data_get(&clip->tracking, clip_framenr, stableibuf->x, stableibuf->y, tloc, &tscale, &tangle);
+ BKE_tracking_stabilization_data_get(clip, clip_framenr, stableibuf->x, stableibuf->y, tloc, &tscale, &tangle);
/* check for stabilization parameters */
if (tscale != cache->stabilized.scale ||
@@ -1057,7 +1057,7 @@ static ImBuf *put_stabilized_frame_to_cache(MovieClip *clip, MovieClipUser *user
float tloc[2], tscale, tangle;
int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, framenr);
- stableibuf = BKE_tracking_stabilize_frame(&clip->tracking, clip_framenr, ibuf, tloc, &tscale, &tangle);
+ stableibuf = BKE_tracking_stabilize_frame(clip, clip_framenr, ibuf, tloc, &tscale, &tangle);
copy_v2_v2(cache->stabilized.loc, tloc);
@@ -1247,8 +1247,6 @@ static void free_buffers(MovieClip *clip)
IMB_free_anim(clip->anim);
clip->anim = NULL;
}
-
- BKE_animdata_free((ID *) clip, false);
}
void BKE_movieclip_clear_cache(MovieClip *clip)
@@ -1270,8 +1268,6 @@ void BKE_movieclip_reload(MovieClip *clip)
/* clear cache */
free_buffers(clip);
- clip->tracking.stabilization.ok = false;
-
/* update clip source */
detect_clip_source(clip);
@@ -1489,9 +1485,10 @@ void BKE_movieclip_free(MovieClip *clip)
free_buffers(clip);
BKE_tracking_free(&clip->tracking);
+ BKE_animdata_free((ID *) clip, false);
}
-MovieClip *BKE_movieclip_copy(Main *bmain, MovieClip *clip)
+MovieClip *BKE_movieclip_copy(Main *bmain, const MovieClip *clip)
{
MovieClip *clip_new;
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index c321bc92a71..148fc3827e0 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -40,9 +40,9 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
-#include "BLI_path_util.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_ghash.h"
#include "BLT_translation.h"
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 2b88ae4823c..05d6b981dc1 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -46,10 +46,11 @@
#include "DNA_world_types.h"
#include "DNA_linestyle_types.h"
-#include "BLI_string.h"
-#include "BLI_math.h"
#include "BLI_listbase.h"
+#include "BLI_math.h"
#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -736,11 +737,14 @@ void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node)
node_socket_free(ntree, sock, node);
MEM_freeN(sock);
}
+ BLI_listbase_clear(&node->inputs);
+
for (sock = node->outputs.first; sock; sock = sock_next) {
sock_next = sock->next;
node_socket_free(ntree, sock, node);
MEM_freeN(sock);
}
+ BLI_listbase_clear(&node->outputs);
node->update |= NODE_UPDATE;
}
@@ -917,7 +921,7 @@ static void node_socket_copy(bNodeSocket *dst, bNodeSocket *src)
/* keep socket listorder identical, for copying links */
/* ntree is the target tree */
-bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node)
+bNode *nodeCopyNode(bNodeTree *ntree, bNode *node)
{
bNode *nnode = MEM_callocN(sizeof(bNode), "dupli node");
bNodeSocket *sock, *oldsock;
@@ -1196,7 +1200,9 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname)
* copying for internal use (threads for eg), where you wont want it to modify the
* scene data.
*/
-static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool skip_database, bool do_id_user, bool do_make_extern, bool copy_previews)
+static bNodeTree *ntreeCopyTree_internal(
+ const bNodeTree *ntree, Main *bmain,
+ bool skip_database, bool do_id_user, bool do_make_extern, bool copy_previews)
{
bNodeTree *newtree;
bNode *node /*, *nnode */ /* UNUSED */, *last;
@@ -1295,42 +1301,15 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool ski
return newtree;
}
-bNodeTree *ntreeCopyTree_ex(bNodeTree *ntree, Main *bmain, const bool do_id_user)
+bNodeTree *ntreeCopyTree_ex(const bNodeTree *ntree, Main *bmain, const bool do_id_user)
{
return ntreeCopyTree_internal(ntree, bmain, false, do_id_user, true, true);
}
-bNodeTree *ntreeCopyTree(Main *bmain, bNodeTree *ntree)
+bNodeTree *ntreeCopyTree(Main *bmain, const bNodeTree *ntree)
{
return ntreeCopyTree_ex(ntree, bmain, true);
}
-/* use when duplicating scenes */
-void ntreeSwitchID_ex(bNodeTree *ntree, ID *id_from, ID *id_to, const bool do_id_user)
-{
- bNode *node;
-
- if (id_from == id_to) {
- /* should never happen but may as well skip if it does */
- return;
- }
-
- /* for scene duplication only */
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->id == id_from) {
- if (do_id_user) {
- id_us_min(id_from);
- id_us_plus(id_to);
- }
-
- node->id = id_to;
- }
- }
-}
-void ntreeSwitchID(bNodeTree *ntree, ID *id_from, ID *id_to)
-{
- ntreeSwitchID_ex(ntree, id_from, id_to, true);
-}
-
void ntreeUserIncrefID(bNodeTree *ntree)
{
bNode *node;
@@ -1721,11 +1700,12 @@ static void node_free_node_ex(bNodeTree *ntree, bNode *node, bool remove_animdat
ntreeTexEndExecTree(ntree->execdata);
ntree->execdata = NULL;
}
-
- if (node->typeinfo->freefunc)
- node->typeinfo->freefunc(node);
}
-
+
+ if (node->typeinfo->freefunc) {
+ node->typeinfo->freefunc(node);
+ }
+
for (sock = node->inputs.first; sock; sock = nextsock) {
nextsock = sock->next;
node_socket_free(ntree, sock, node);
@@ -1851,7 +1831,7 @@ void ntreeFreeTree(bNodeTree *ntree)
if (tntree == ntree)
break;
if (tntree == NULL) {
- BKE_libblock_free_data(G.main, &ntree->id);
+ BKE_libblock_free_data(&ntree->id, true);
}
}
@@ -2045,7 +2025,7 @@ bNodeTree *ntreeLocalize(bNodeTree *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)
@@ -3195,12 +3175,20 @@ void nodeSynchronizeID(bNode *node, bool copy_to_id)
void nodeLabel(bNodeTree *ntree, bNode *node, char *label, int maxlen)
{
- if (node->label[0] != '\0')
+ if (node->label[0] != '\0') {
BLI_strncpy(label, node->label, maxlen);
- else if (node->typeinfo->labelfunc)
+ }
+ else if (node->typeinfo->labelfunc) {
node->typeinfo->labelfunc(ntree, node, label, maxlen);
- else
- BLI_strncpy(label, IFACE_(node->typeinfo->ui_name), maxlen);
+ }
+ else {
+ /* Kind of hacky and weak... Ideally would be better to use RNA here. :| */
+ const char *tmp = CTX_IFACE_(BLT_I18NCONTEXT_ID_NODETREE, node->typeinfo->ui_name);
+ if (tmp == node->typeinfo->ui_name) {
+ tmp = IFACE_(node->typeinfo->ui_name);
+ }
+ BLI_strncpy(label, tmp, maxlen);
+ }
}
static void node_type_base_defaults(bNodeType *ntype)
@@ -3591,6 +3579,7 @@ static void registerShaderNodes(void)
register_node_type_sh_background();
register_node_type_sh_bsdf_anisotropic();
register_node_type_sh_bsdf_diffuse();
+ register_node_type_sh_bsdf_principled();
register_node_type_sh_bsdf_glossy();
register_node_type_sh_bsdf_glass();
register_node_type_sh_bsdf_translucent();
@@ -3607,9 +3596,12 @@ 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_metallic();
+ register_node_type_sh_eevee_specular();
register_node_type_sh_output_lamp();
register_node_type_sh_output_material();
+ register_node_type_sh_output_eevee_material();
register_node_type_sh_output_world();
register_node_type_sh_output_linestyle();
@@ -3799,3 +3791,20 @@ 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)
+{
+ 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--;
+ }
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index fd19c16faf8..5f99421ccb3 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -58,6 +58,7 @@
#include "DNA_view3d_types.h"
#include "DNA_world_types.h"
#include "DNA_object_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_property_types.h"
#include "DNA_rigidbody_types.h"
@@ -78,7 +79,6 @@
#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"
@@ -91,6 +91,7 @@
#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,9 +104,11 @@
#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_lightprobe.h"
#include "BKE_property.h"
#include "BKE_rigidbody.h"
#include "BKE_sca.h"
@@ -118,6 +121,10 @@
#include "BKE_camera.h"
#include "BKE_image.h"
+#include "DEG_depsgraph.h"
+
+#include "DRW_engine.h"
+
#ifdef WITH_MOD_FLUID
#include "LBM_fluidsim.h"
#endif
@@ -127,8 +134,9 @@
#endif
#include "CCGSubSurf.h"
+#include "atomic_ops.h"
-#include "GPU_material.h"
+#include "GPU_lamp.h"
/* Vertex parent modifies original BMesh which is not safe for threading.
* Ideally such a modification should be handled as a separate DAG update
@@ -153,7 +161,7 @@ void BKE_object_workob_clear(Object *workob)
void BKE_object_update_base_layer(struct Scene *scene, Object *ob)
{
- Base *base = scene->base.first;
+ BaseLegacy *base = scene->base.first;
while (base) {
if (base->object == ob) base->lay = ob->lay;
@@ -246,6 +254,10 @@ bool BKE_object_support_modifier_type_check(Object *ob, int modifier_type)
mti = modifierType_getInfo(modifier_type);
+ /* only geometry objects should be able to get modifiers [#25291] */
+ if (!ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
+ return false;
+ }
if (ob->type == OB_LATTICE && (mti->flags & eModifierTypeFlag_AcceptsLattice) == 0) {
return false;
@@ -315,19 +327,24 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr
/* free data derived from mesh, called when mesh changes or is freed */
void BKE_object_free_derived_caches(Object *ob)
{
- /* also serves as signal to remake texspace */
+ /* Also serves as signal to remake texspace.
+ *
+ * NOTE: This function can be called from threads on different objects
+ * sharing same data datablock. So we need to ensure atomic nature of
+ * data modification here.
+ */
if (ob->type == OB_MESH) {
Mesh *me = ob->data;
if (me && me->bb) {
- me->bb->flag |= BOUNDBOX_DIRTY;
+ atomic_fetch_and_or_uint32((uint*)&me->bb->flag, BOUNDBOX_DIRTY);
}
}
else if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) {
Curve *cu = ob->data;
if (cu && cu->bb) {
- cu->bb->flag |= BOUNDBOX_DIRTY;
+ atomic_fetch_and_or_uint32((uint*)&cu->bb->flag, BOUNDBOX_DIRTY);
}
}
@@ -346,7 +363,16 @@ void BKE_object_free_derived_caches(Object *ob)
ob->derivedDeform->release(ob->derivedDeform);
ob->derivedDeform = NULL;
}
-
+
+ if (ob->mesh_evaluated != NULL) {
+ /* Evaluated mesh points to edit mesh, but does not own it. */
+ ob->mesh_evaluated->edit_btmesh = NULL;
+ BKE_mesh_free(ob->mesh_evaluated);
+ BKE_libblock_free_data(&ob->mesh_evaluated->id, false);
+ MEM_freeN(ob->mesh_evaluated);
+ ob->mesh_evaluated = NULL;
+ }
+
BKE_object_free_curve_cache(ob);
}
@@ -391,7 +417,7 @@ void BKE_object_free_caches(Object *object)
* 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);
}
}
@@ -408,6 +434,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;
@@ -438,6 +465,18 @@ void BKE_object_free(Object *ob)
}
GPU_lamp_free(ob);
+ for (ObjectEngineData *oed = ob->drawdata.first; oed; oed = oed->next) {
+ if (oed->storage) {
+ if (oed->free) {
+ oed->free(oed->storage);
+ }
+ MEM_freeN(oed->storage);
+ }
+ }
+ BLI_freelistN(&ob->drawdata);
+
+ ob->deg_update_flag = 0;
+
BKE_sculptsession_free(ob);
BLI_freelistN(&ob->pc_ids);
@@ -454,6 +493,9 @@ void BKE_object_free(Object *ob)
}
BKE_previewimg_free(&ob->preview);
+
+ /* don't free, let the base free it */
+ ob->base_collection_properties = NULL;
}
/* actual check for internal data, not context or flags */
@@ -571,6 +613,7 @@ 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_EMPTY: return NULL;
default:
printf("%s: Internal error, bad type: %d\n", __func__, type);
@@ -673,23 +716,26 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
/* 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,
+ Main *bmain, Scene *scene, SceneLayer *sl,
int type, const char *name)
{
Object *ob;
Base *base;
+ LayerCollection *lc;
ob = BKE_object_add_only_object(bmain, type, name);
ob->data = BKE_object_obdata_add_from_type(bmain, type, name);
- 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);
+ lc = BKE_layer_collection_get_active_ensure(scene, sl);
+
+ BKE_collection_object_add(scene, lc->scene_collection, ob);
+ base = BKE_scene_layer_base_find(sl, ob);
+ BKE_scene_layer_base_deselect_all(sl);
+ BKE_scene_layer_base_select(sl, base);
+
+ DEG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
return ob;
}
@@ -784,9 +830,9 @@ static LodLevel *lod_level_select(Object *ob, const float camera_position[3])
return current;
}
-bool BKE_object_lod_is_usable(Object *ob, Scene *scene)
+bool BKE_object_lod_is_usable(Object *ob, SceneLayer *sl)
{
- bool active = (scene) ? ob == OBACT : false;
+ bool active = (sl) ? ob == OBACT_NEW : false;
return (ob->mode == OB_MODE_OBJECT || !active);
}
@@ -800,11 +846,11 @@ void BKE_object_lod_update(Object *ob, const float camera_position[3])
}
}
-static Object *lod_ob_get(Object *ob, Scene *scene, int flag)
+static Object *lod_ob_get(Object *ob, SceneLayer *sl, int flag)
{
LodLevel *current = ob->currentlod;
- if (!current || !BKE_object_lod_is_usable(ob, scene))
+ if (!current || !BKE_object_lod_is_usable(ob, sl))
return ob;
while (current->prev && (!(current->flags & flag) || !current->source || current->source->type != OB_MESH)) {
@@ -814,14 +860,14 @@ static Object *lod_ob_get(Object *ob, Scene *scene, int flag)
return current->source;
}
-struct Object *BKE_object_lod_meshob_get(Object *ob, Scene *scene)
+struct Object *BKE_object_lod_meshob_get(Object *ob, SceneLayer *sl)
{
- return lod_ob_get(ob, scene, OB_LOD_USE_MESH);
+ return lod_ob_get(ob, sl, OB_LOD_USE_MESH);
}
-struct Object *BKE_object_lod_matob_get(Object *ob, Scene *scene)
+struct Object *BKE_object_lod_matob_get(Object *ob, SceneLayer *sl)
{
- return lod_ob_get(ob, scene, OB_LOD_USE_MAT);
+ return lod_ob_get(ob, sl, OB_LOD_USE_MAT);
}
#endif /* WITH_GAMEENGINE */
@@ -872,7 +918,7 @@ SoftBody *copy_softbody(const SoftBody *sb, bool copy_caches)
return sbn;
}
-BulletSoftBody *copy_bulletsoftbody(BulletSoftBody *bsb)
+BulletSoftBody *copy_bulletsoftbody(const BulletSoftBody *bsb)
{
BulletSoftBody *bsbn;
@@ -934,6 +980,7 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys)
psysn->effectors = NULL;
psysn->tree = NULL;
psysn->bvhtree = NULL;
+ psysn->batch_cache = NULL;
BLI_listbase_clear(&psysn->pathcachebufs);
BLI_listbase_clear(&psysn->childcachebufs);
@@ -1005,7 +1052,7 @@ void BKE_object_copy_softbody(Object *ob_dst, const Object *ob_src)
}
}
-static void copy_object_pose(Object *obn, Object *ob)
+static void copy_object_pose(Object *obn, const Object *ob)
{
bPoseChannel *chan;
@@ -1038,7 +1085,7 @@ static void copy_object_pose(Object *obn, Object *ob)
}
}
-static void copy_object_lod(Object *obn, Object *ob)
+static void copy_object_lod(Object *obn, const Object *ob)
{
BLI_duplicatelist(&obn->lodlevels, &ob->lodlevels);
@@ -1089,7 +1136,7 @@ void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src)
copy_v3_v3(ob_tar->size, ob_src->size);
}
-Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches)
+Object *BKE_object_copy_ex(Main *bmain, const Object *ob, bool copy_caches)
{
Object *obn;
ModifierData *md;
@@ -1119,11 +1166,9 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches)
BLI_listbase_clear(&obn->prop);
BKE_bproperty_copy_list(&obn->prop, &ob->prop);
-
- copy_sensors(&obn->sensors, &ob->sensors);
- copy_controllers(&obn->controllers, &ob->controllers);
- copy_actuators(&obn->actuators, &ob->actuators);
-
+
+ BKE_sca_logic_copy(obn, ob);
+
if (ob->pose) {
copy_object_pose(obn, ob);
/* backwards compat... non-armatures can get poses in older files? */
@@ -1131,6 +1176,7 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches)
BKE_pose_rebuild(obn, obn->data);
}
defgroup_copy_list(&obn->defbase, &ob->defbase);
+ BKE_object_facemap_copy_list(&obn->fmaps, &ob->fmaps);
BKE_constraints_copy(&obn->constraints, &ob->constraints, true);
obn->mode = OB_MODE_OBJECT;
@@ -1138,8 +1184,9 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches)
/* increase user numbers */
id_us_plus((ID *)obn->data);
+ id_us_plus((ID *)obn->poselib);
id_us_plus((ID *)obn->gpd);
- id_lib_extern((ID *)obn->dup_group);
+ id_us_plus((ID *)obn->dup_group);
for (a = 0; a < obn->totcol; a++) id_us_plus((ID *)obn->mat[a]);
@@ -1162,6 +1209,7 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches)
BLI_listbase_clear(&obn->gpulamp);
BLI_listbase_clear(&obn->pc_ids);
+ BLI_listbase_clear(&obn->drawdata);
obn->mpath = NULL;
@@ -1179,12 +1227,12 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches)
}
/* copy objects, will re-initialize cached simulation data */
-Object *BKE_object_copy(Main *bmain, Object *ob)
+Object *BKE_object_copy(Main *bmain, const Object *ob)
{
return BKE_object_copy_ex(bmain, ob, false);
}
-void BKE_object_make_local(Main *bmain, Object *ob, const bool lib_local)
+void BKE_object_make_local_ex(Main *bmain, Object *ob, const bool lib_local, const bool clear_proxy)
{
bool is_local = false, is_lib = false;
@@ -1203,7 +1251,14 @@ void BKE_object_make_local(Main *bmain, Object *ob, const bool lib_local)
if (lib_local || is_local) {
if (!is_lib) {
id_clear_lib_data(bmain, &ob->id);
- BKE_id_expand_local(&ob->id);
+ BKE_id_expand_local(bmain, &ob->id);
+ if (clear_proxy) {
+ if (ob->proxy_from != NULL) {
+ ob->proxy_from->proxy = NULL;
+ ob->proxy_from->proxy_group = NULL;
+ }
+ ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
+ }
}
else {
Object *ob_new = BKE_object_copy(bmain, ob);
@@ -1211,6 +1266,9 @@ void BKE_object_make_local(Main *bmain, Object *ob, const bool lib_local)
ob_new->id.us = 0;
ob_new->proxy = ob_new->proxy_from = ob_new->proxy_group = NULL;
+ /* setting newid is mandatory for complex make_lib_local logic... */
+ ID_NEW_SET(ob, ob_new);
+
if (!lib_local) {
BKE_libblock_remap(bmain, ob, ob_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
@@ -1218,6 +1276,11 @@ void BKE_object_make_local(Main *bmain, Object *ob, const bool lib_local)
}
}
+void BKE_object_make_local(Main *bmain, Object *ob, const bool lib_local)
+{
+ BKE_object_make_local_ex(bmain, ob, lib_local, true);
+}
+
/* Returns true if the Object is from an external blend file (libdata) */
bool BKE_object_is_libdata(Object *ob)
{
@@ -1242,10 +1305,10 @@ static void armature_set_id_extern(Object *ob)
unsigned int lay = arm->layer_protected;
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (!(pchan->bone->layer & lay))
+ if (!(pchan->bone->layer & lay)) {
id_lib_extern((ID *)pchan->custom);
+ }
}
-
}
void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
@@ -1303,8 +1366,8 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
ob->proxy_group = gob;
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
@@ -1338,7 +1401,10 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
ob->type = target->type;
ob->data = target->data;
id_us_plus((ID *)ob->data); /* ensures lib data becomes LIB_TAG_EXTERN */
-
+
+ /* copy vertex groups */
+ defgroup_copy_list(&ob->defbase, &target->defbase);
+
/* copy material and index information */
ob->actcol = ob->totcol = 0;
if (ob->mat) MEM_freeN(ob->mat);
@@ -2217,78 +2283,6 @@ void BKE_boundbox_minmax(const BoundBox *bb, float obmat[4][4], float r_min[3],
}
}
-void BKE_boundbox_scale(struct BoundBox *bb_dst, const struct BoundBox *bb_src, float scale)
-{
- float cent[3];
- BKE_boundbox_calc_center_aabb(bb_src, cent);
-
- for (int i = 0; i < ARRAY_SIZE(bb_dst->vec); i++) {
- bb_dst->vec[i][0] = ((bb_src->vec[i][0] - cent[0]) * scale) + cent[0];
- bb_dst->vec[i][1] = ((bb_src->vec[i][1] - cent[1]) * scale) + cent[1];
- bb_dst->vec[i][2] = ((bb_src->vec[i][2] - cent[2]) * scale) + cent[2];
- }
-}
-
-/**
- * Returns a BBox which each dimensions are at least epsilon.
- * \note In case a given dimension needs to be enlarged, its final value will be in [epsilon, 3 * epsilon] range.
- *
- * \param bb the input bbox to check.
- * \param bb_temp the temp bbox to modify (\a bb content is never changed).
- * \param epsilon the minimum dimension to ensure.
- * \return either bb (if nothing needed to be changed) or bb_temp.
- */
-BoundBox *BKE_boundbox_ensure_minimum_dimensions(BoundBox *bb, BoundBox *bb_temp, const float epsilon)
-{
- if (fabsf(bb->vec[0][0] - bb->vec[4][0]) < epsilon) {
- /* Flat along X axis... */
- *bb_temp = *bb;
- bb = bb_temp;
- bb->vec[0][0] -= epsilon;
- bb->vec[1][0] -= epsilon;
- bb->vec[2][0] -= epsilon;
- bb->vec[3][0] -= epsilon;
- bb->vec[4][0] += epsilon;
- bb->vec[5][0] += epsilon;
- bb->vec[6][0] += epsilon;
- bb->vec[7][0] += epsilon;
- }
-
- if (fabsf(bb->vec[0][1] - bb->vec[3][1]) < epsilon) {
- /* Flat along Y axis... */
- if (bb != bb_temp) {
- *bb_temp = *bb;
- bb = bb_temp;
- }
- bb->vec[0][1] -= epsilon;
- bb->vec[1][1] -= epsilon;
- bb->vec[4][1] -= epsilon;
- bb->vec[5][1] -= epsilon;
- bb->vec[2][1] += epsilon;
- bb->vec[3][1] += epsilon;
- bb->vec[6][1] += epsilon;
- bb->vec[7][1] += epsilon;
- }
-
- if (fabsf(bb->vec[0][2] - bb->vec[1][2]) < epsilon) {
- /* Flat along Z axis... */
- if (bb != bb_temp) {
- *bb_temp = *bb;
- bb = bb_temp;
- }
- bb->vec[0][2] -= epsilon;
- bb->vec[3][2] -= epsilon;
- bb->vec[4][2] -= epsilon;
- bb->vec[7][2] -= epsilon;
- bb->vec[1][2] += epsilon;
- bb->vec[2][2] += epsilon;
- bb->vec[5][2] += epsilon;
- bb->vec[6][2] += epsilon;
- }
-
- return bb;
-}
-
BoundBox *BKE_object_boundbox_get(Object *ob)
{
BoundBox *bb = NULL;
@@ -2532,14 +2526,14 @@ void BKE_object_foreach_display_point(
}
void BKE_scene_foreach_display_point(
- Scene *scene, View3D *v3d, const short flag,
+ Scene *scene, SceneLayer *sl,
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) {
+ for (base = FIRSTBASE_NEW; base; base = base->next) {
+ if (((base->flag & BASE_VISIBLED) != 0) && ((base->flag & BASE_SELECTED) != 0)) {
ob = base->object;
if ((ob->transflag & OB_DUPLI) == 0) {
@@ -2760,14 +2754,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:
@@ -2797,45 +2784,6 @@ int BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc,
return 1;
}
-/*
- * Test a bounding box for ray intersection
- * assumes the ray is already local to the boundbox space
- */
-bool BKE_boundbox_ray_hit_check(
- const struct BoundBox *bb,
- const float ray_start[3], const float ray_normal[3],
- float *r_lambda)
-{
- const int triangle_indexes[12][3] = {
- {0, 1, 2}, {0, 2, 3},
- {3, 2, 6}, {3, 6, 7},
- {1, 2, 6}, {1, 6, 5},
- {5, 6, 7}, {4, 5, 7},
- {0, 3, 7}, {0, 4, 7},
- {0, 1, 5}, {0, 4, 5}};
-
- bool result = false;
- int i;
-
- for (i = 0; i < 12 && (!result || r_lambda); i++) {
- float lambda;
- int v1, v2, v3;
- v1 = triangle_indexes[i][0];
- v2 = triangle_indexes[i][1];
- v3 = triangle_indexes[i][2];
- if (isect_ray_tri_v3(ray_start, ray_normal, bb->vec[v1], bb->vec[v2], bb->vec[v3], &lambda, NULL) &&
- (!r_lambda || *r_lambda > lambda))
- {
- result = true;
- if (r_lambda) {
- *r_lambda = lambda;
- }
- }
- }
-
- return result;
-}
-
static int pc_cmp(const void *a, const void *b)
{
const LinkData *ad = a, *bd = b;
@@ -3215,6 +3163,14 @@ static bool constructive_modifier_is_deform_modified(ModifierData *md)
ScrewModifierData *smd = (ScrewModifierData *)md;
return smd->ob_axis != NULL && object_moves_in_time(smd->ob_axis);
}
+ else if (md->type == eModifierType_MeshSequenceCache) {
+ /* NOTE: Not ideal because it's unknown whether topology changes or not.
+ * This will be detected later, so by assuming it's only deformation
+ * going on here we allow to bake deform-only mesh to Alembic and have
+ * proper motion blur after that.
+ */
+ return true;
+ }
return false;
}
@@ -3365,33 +3321,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 SceneLayer *scene_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 = scene_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 = scene_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_NEW(base)) ||
+ (objectSet == OB_SET_VISIBLE && BASE_EDITABLE_BGMODE_NEW(base)))
{
Object *ob = base->object;
@@ -3420,8 +3376,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 = scene_layer->object_bases.first; local_base; local_base = local_base->next) {
+ if (BASE_EDITABLE_BGMODE_NEW(local_base)) {
Object *child = local_base->object;
if (obrel_list_test(child)) {
@@ -3465,18 +3421,11 @@ struct LinkNode *BKE_object_groups(Object *ob)
return group_linknode;
}
-void BKE_object_groups_clear(Scene *scene, Base *base, Object *object)
+void BKE_object_groups_clear(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(group, base->object))) {
- BKE_group_object_unlink(group, object, scene, base);
+ while ((group = BKE_group_object_find(group, ob))) {
+ BKE_group_object_unlink(group, ob);
}
}
diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c
index b5f63588423..887618415be 100644
--- a/source/blender/blenkernel/intern/object_deform.c
+++ b/source/blender/blenkernel/intern/object_deform.c
@@ -32,6 +32,7 @@
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
+#include "BLI_string_utils.h"
#include "DNA_armature_types.h"
#include "DNA_cloth_types.h"
@@ -50,6 +51,7 @@
#include "BKE_editmesh.h"
#include "BKE_object_deform.h" /* own include */
#include "BKE_object.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
/** \name Misc helpers
@@ -404,12 +406,15 @@ void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup)
object_defgroup_remove_edit_mode(ob, defgroup);
else
object_defgroup_remove_object_mode(ob, defgroup);
+
+ BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_NOCHECK);
}
/**
* Remove all vgroups from object. Work in Object and Edit modes.
+ * When only_unlocked=true, locked vertex groups are not removed.
*/
-void BKE_object_defgroup_remove_all(Object *ob)
+void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked)
{
bDeformGroup *dg = (bDeformGroup *)ob->defbase.first;
const bool edit_mode = BKE_object_is_in_editmode_vgroup(ob);
@@ -418,10 +423,12 @@ void BKE_object_defgroup_remove_all(Object *ob)
while (dg) {
bDeformGroup *next_dg = dg->next;
- if (edit_mode)
- object_defgroup_remove_edit_mode(ob, dg);
- else
- object_defgroup_remove_object_mode(ob, dg);
+ if (!only_unlocked || (dg->flag & DG_LOCK_WEIGHT) == 0) {
+ if (edit_mode)
+ object_defgroup_remove_edit_mode(ob, dg);
+ else
+ object_defgroup_remove_object_mode(ob, dg);
+ }
dg = next_dg;
}
@@ -446,6 +453,15 @@ void BKE_object_defgroup_remove_all(Object *ob)
}
/**
+ * Remove all vgroups from object. Work in Object and Edit modes.
+ */
+void BKE_object_defgroup_remove_all(struct Object *ob)
+{
+ BKE_object_defgroup_remove_all_ex(ob, false);
+}
+
+
+/**
* Get MDeformVert vgroup data from given object. Should only be used in Object mode.
*
* \return True if the id type supports weights.
@@ -611,7 +627,7 @@ void BKE_object_defgroup_mirror_selection(
if (dg_selection[i]) {
char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, defgroup->name, false);
+ BLI_string_flip_side_name(name_flip, defgroup->name, false, sizeof(name_flip));
i_mirr = STREQ(name_flip, defgroup->name) ? i : defgroup_name_index(ob, name_flip);
if ((i_mirr >= 0 && i_mirr < defbase_tot) && (dg_flags_sel[i_mirr] == false)) {
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index 21a0246353e..1f10ed25249 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -49,7 +49,6 @@
#include "BKE_animsys.h"
#include "BKE_DerivedMesh.h"
-#include "BKE_depsgraph.h"
#include "BKE_font.h"
#include "BKE_group.h"
#include "BKE_global.h"
@@ -62,8 +61,10 @@
#include "BKE_editmesh.h"
#include "BKE_anim.h"
+#include "DEG_depsgraph.h"
#include "BLI_strict_flags.h"
+#include "BLI_hash.h"
/* Dupli-Geometry */
@@ -76,7 +77,6 @@ typedef struct DupliContext {
Scene *scene;
Object *object;
float space_mat[4][4];
- unsigned int lay;
int persistent_id[MAX_DUPLI_RECUR];
int level;
@@ -109,7 +109,6 @@ static void init_context(DupliContext *r_ctx, EvaluationContext *eval_ctx, Scene
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);
@@ -180,6 +179,23 @@ static DupliObject *make_dupli(const DupliContext *ctx,
if (ob->type == OB_MBALL)
dob->no_draw = true;
+ /* random number */
+ /* the logic here is designed to match Cycles */
+ dob->random_id = BLI_hash_string(dob->ob->id.name + 2);
+
+ if (dob->persistent_id[0] != INT_MAX) {
+ for (i = 0; i < MAX_DUPLI_RECUR * 2; i++) {
+ dob->random_id = BLI_hash_int_2d(dob->random_id, (unsigned int)dob->persistent_id[i]);
+ }
+ }
+ else {
+ dob->random_id = BLI_hash_int_2d(dob->random_id, 0);
+ }
+
+ if (ctx->object != ob) {
+ dob->random_id ^= BLI_hash_int(BLI_hash_string(ctx->object->id.name + 2));
+ }
+
return dob;
}
@@ -221,31 +237,39 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild
if (ctx->group) {
unsigned int lay = ctx->group->layer;
+ int groupid = 0;
GroupObject *go;
- for (go = ctx->group->gobject.first; go; go = go->next) {
+ 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)) {
+ DupliContext pctx;
+ copy_dupli_context(&pctx, ctx, ctx->object, NULL, groupid, false);
+
/* mballs have a different dupli handling */
if (ob->type != OB_MBALL)
ob->flag |= OB_DONE; /* doesnt render */
- make_child_duplis_cb(ctx, userdata, ob);
+ make_child_duplis_cb(&pctx, userdata, ob);
}
}
}
else {
unsigned int lay = ctx->scene->lay;
- Base *base;
- for (base = ctx->scene->base.first; base; base = base->next) {
+ int baseid = 0;
+ BaseLegacy *base;
+ for (base = ctx->scene->base.first; base; base = base->next, baseid++) {
Object *ob = base->object;
if ((base->lay & lay) && ob != obedit && is_child(ob, parent)) {
+ DupliContext pctx;
+ copy_dupli_context(&pctx, ctx, ctx->object, NULL, baseid, false);
+
/* mballs have a different dupli handling */
if (ob->type != OB_MBALL)
ob->flag |= OB_DONE; /* doesnt render */
- make_child_duplis_cb(ctx, userdata, ob);
+ make_child_duplis_cb(&pctx, userdata, ob);
}
}
}
@@ -521,10 +545,15 @@ static void make_duplis_verts(const DupliContext *ctx)
BMEditMesh *em = BKE_editmesh_from_object(parent);
CustomDataMask dm_mask = (use_texcoords ? CD_MASK_BAREMESH | CD_MASK_ORCO : CD_MASK_BAREMESH);
- if (em)
+ 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);
- else
+ }
+ else {
vdd.dm = mesh_get_derived_final(scene, parent, dm_mask);
+ }
vdd.edit_btmesh = me->edit_btmesh;
if (use_texcoords)
@@ -634,8 +663,7 @@ static void make_duplis_font(const DupliContext *ctx)
float rmat[4][4];
zero_v3(obmat[3]);
- unit_m4(rmat);
- rotate_m4(rmat, 'Z', -ct->rot);
+ axis_angle_to_mat4_single(rmat, 'Z', -ct->rot);
mul_m4_m4m4(obmat, obmat, rmat);
}
@@ -785,10 +813,15 @@ 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 (em)
+ 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);
- else
+ }
+ else {
fdd.dm = mesh_get_derived_final(scene, parent, dm_mask);
+ }
if (use_texcoords) {
CustomData *ml_data = fdd.dm->getLoopDataLayout(fdd.dm);
diff --git a/source/blender/blenkernel/intern/object_facemap.c b/source/blender/blenkernel/intern/object_facemap.c
new file mode 100644
index 00000000000..700935de0e8
--- /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 "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 "BLI_utildefines.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+#include "BLI_listbase.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 5cb704e4737..50502115edc 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -32,6 +32,7 @@
#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"
@@ -43,7 +44,7 @@
#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_animsys.h"
#include "BKE_displist.h"
@@ -51,20 +52,20 @@
#include "BKE_key.h"
#include "BKE_lamp.h"
#include "BKE_lattice.h"
+#include "BKE_library.h"
#include "BKE_editmesh.h"
#include "BKE_object.h"
#include "BKE_particle.h"
+#include "BKE_pointcache.h"
#include "BKE_scene.h"
#include "BKE_material.h"
+#include "BKE_mesh.h"
#include "BKE_image.h"
+#include "MEM_guardedalloc.h"
#include "DEG_depsgraph.h"
-#ifdef WITH_LEGACY_DEPSGRAPH
-# define DEBUG_PRINT if (!DEG_depsgraph_use_legacy() && G.debug & G_DEBUG_DEPSGRAPH) printf
-#else
-# define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
-#endif
+#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
static ThreadMutex material_lock = BLI_MUTEX_INITIALIZER;
@@ -144,18 +145,6 @@ void BKE_object_eval_done(EvaluationContext *UNUSED(eval_ctx), Object *ob)
else ob->transflag &= ~OB_NEG_SCALE;
}
-void BKE_object_eval_modifier(struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob,
- struct ModifierData *md)
-{
- DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
- (void) eval_ctx; /* Ignored. */
- (void) scene; /* Ignored. */
- (void) ob; /* Ignored. */
- (void) md; /* Ignored. */
-}
-
void BKE_object_handle_data_update(EvaluationContext *eval_ctx,
Scene *scene,
Object *ob)
@@ -345,5 +334,78 @@ void BKE_object_eval_uber_data(EvaluationContext *eval_ctx,
BLI_assert(ob->type != OB_ARMATURE);
BKE_object_handle_data_update(eval_ctx, scene, ob);
+ switch (ob->type) {
+ case OB_MESH:
+ BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ break;
+ case OB_LATTICE:
+ BKE_lattice_batch_cache_dirty(ob->data, BKE_LATTICE_BATCH_DIRTY_ALL);
+ break;
+ case OB_CURVE:
+ case OB_FONT:
+ case OB_SURF:
+ BKE_curve_batch_cache_dirty(ob->data, BKE_CURVE_BATCH_DIRTY_ALL);
+ break;
+ }
+
+#ifdef WITH_COPY_ON_WRITE
+ if (ob->type == OB_MESH) {
+ /* Quick hack to convert evaluated derivedMesh to Mesh. */
+ DerivedMesh *dm = ob->derivedFinal;
+ if (dm != NULL) {
+ Mesh *mesh = (Mesh *)ob->data;
+ Mesh *new_mesh = BKE_libblock_alloc_notest(ID_ME);
+ BKE_mesh_init(new_mesh);
+ /* Copy ID name so GS(new_mesh->id) works correct later on. */
+ BLI_strncpy(new_mesh->id.name, mesh->id.name, sizeof(new_mesh->id.name));
+ /* Copy materials so render engines can access them. */
+ new_mesh->mat = MEM_dupallocN(mesh->mat);
+ new_mesh->totcol = mesh->totcol;
+ DM_to_mesh(dm, new_mesh, ob, ob->lastDataMask, true);
+ new_mesh->edit_btmesh = mesh->edit_btmesh;
+ /* Store result mesh as derived_mesh of object. This way we have
+ * explicit way to query final object evaluated data and know for sure
+ * who owns the newly created mesh datablock.
+ */
+ ob->mesh_evaluated = new_mesh;
+ /* TODO(sergey): This is kind of compatibility thing, so all render
+ * engines can use object->data for mesh data for display. This is
+ * something what we might want to change in the future.
+ */
+ ob->data = new_mesh;
+ /* Save some memory by throwing DerivedMesh away. */
+ /* NOTE: Watch out, some tools might need it!
+ * So keep around for now..
+ */
+ }
+#if 0
+ if (ob->derivedFinal != NULL) {
+ ob->derivedFinal->needsFree = 1;
+ ob->derivedFinal->release(ob->derivedFinal);
+ ob->derivedFinal = NULL;
+ }
+ if (ob->derivedDeform != NULL) {
+ ob->derivedDeform->needsFree = 1;
+ ob->derivedDeform->release(ob->derivedDeform);
+ ob->derivedDeform = NULL;
+ }
+#endif
+ }
+#endif
+
ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME);
}
+
+void BKE_object_eval_cloth(EvaluationContext *UNUSED(eval_ctx), Scene *scene, Object *object)
+{
+ DEBUG_PRINT("%s on %s\n", __func__, object->id.name);
+ BKE_ptcache_object_reset(scene, object, PTCACHE_RESET_DEPSGRAPH);
+}
+
+void BKE_object_eval_update_shading(EvaluationContext *UNUSED(eval_ctx), Object *object)
+{
+ DEBUG_PRINT("%s on %s\n", __func__, object->id.name);
+ if (object->type == OB_MESH) {
+ BKE_mesh_batch_cache_dirty(object->data, BKE_MESH_BATCH_DIRTY_SHADING);
+ }
+}
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index c5179e5a428..537c8926a5b 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -334,10 +334,10 @@ void BKE_ocean_eval_uv(struct Ocean *oc, struct OceanResult *ocr, float u, float
i1 = i1 % oc->_M;
j1 = j1 % oc->_N;
-
#define BILERP(m) (interpf(interpf(m[i1 * oc->_N + j1], m[i0 * oc->_N + j1], frac_x), \
interpf(m[i1 * oc->_N + j0], m[i0 * oc->_N + j0], frac_x), \
frac_z))
+
{
if (oc->_do_disp_y) {
ocr->disp[1] = BILERP(oc->_disp_y);
@@ -531,7 +531,7 @@ static void ocean_compute_htilda(void *userdata, const int i)
}
}
-static void ocean_compute_displacement_y(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
+static void ocean_compute_displacement_y(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
{
OceanSimulateData *osd = BLI_task_pool_userdata(pool);
const Ocean *o = osd->o;
@@ -539,7 +539,7 @@ static void ocean_compute_displacement_y(TaskPool *pool, void *UNUSED(taskdata),
fftw_execute(o->_disp_y_plan);
}
-static void ocean_compute_displacement_x(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
+static void ocean_compute_displacement_x(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
{
OceanSimulateData *osd = BLI_task_pool_userdata(pool);
const Ocean *o = osd->o;
@@ -567,7 +567,7 @@ static void ocean_compute_displacement_x(TaskPool *pool, void *UNUSED(taskdata),
fftw_execute(o->_disp_x_plan);
}
-static void ocean_compute_displacement_z(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
+static void ocean_compute_displacement_z(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
{
OceanSimulateData *osd = BLI_task_pool_userdata(pool);
const Ocean *o = osd->o;
@@ -595,7 +595,7 @@ static void ocean_compute_displacement_z(TaskPool *pool, void *UNUSED(taskdata),
fftw_execute(o->_disp_z_plan);
}
-static void ocean_compute_jacobian_jxx(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
+static void ocean_compute_jacobian_jxx(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
{
OceanSimulateData *osd = BLI_task_pool_userdata(pool);
const Ocean *o = osd->o;
@@ -627,7 +627,7 @@ static void ocean_compute_jacobian_jxx(TaskPool *pool, void *UNUSED(taskdata), i
}
}
-static void ocean_compute_jacobian_jzz(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
+static void ocean_compute_jacobian_jzz(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
{
OceanSimulateData *osd = BLI_task_pool_userdata(pool);
const Ocean *o = osd->o;
@@ -659,7 +659,7 @@ static void ocean_compute_jacobian_jzz(TaskPool *pool, void *UNUSED(taskdata), i
}
}
-static void ocean_compute_jacobian_jxz(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
+static void ocean_compute_jacobian_jxz(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
{
OceanSimulateData *osd = BLI_task_pool_userdata(pool);
const Ocean *o = osd->o;
@@ -685,7 +685,7 @@ static void ocean_compute_jacobian_jxz(TaskPool *pool, void *UNUSED(taskdata), i
fftw_execute(o->_Jxz_plan);
}
-static void ocean_compute_normal_x(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
+static void ocean_compute_normal_x(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
{
OceanSimulateData *osd = BLI_task_pool_userdata(pool);
const Ocean *o = osd->o;
@@ -704,7 +704,7 @@ static void ocean_compute_normal_x(TaskPool *pool, void *UNUSED(taskdata), int U
fftw_execute(o->_N_x_plan);
}
-static void ocean_compute_normal_z(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
+static void ocean_compute_normal_z(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
{
OceanSimulateData *osd = BLI_task_pool_userdata(pool);
const Ocean *o = osd->o;
diff --git a/source/blender/blenkernel/intern/outliner_treehash.c b/source/blender/blenkernel/intern/outliner_treehash.c
index f31ba34a984..3e99dbe37ca 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 "BKE_outliner_treehash.h"
@@ -56,7 +57,7 @@ static TseGroup *tse_group_create(void)
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 +67,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);
@@ -140,7 +161,21 @@ void BKE_outliner_treehash_add_element(void *treehash, TreeStoreElem *elem)
*val_p = tse_group_create();
}
group = *val_p;
- tse_group_add(group, elem);
+ 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)
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index 489fc2f3710..64f90ef5c52 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -450,7 +450,7 @@ char *unpackFile(ReportList *reports, const char *abs_name, const char *local_na
break;
}
/* else create it */
- /* fall-through */
+ ATTR_FALLTHROUGH;
}
case PF_WRITE_LOCAL:
if (writePackedFile(reports, local_name, pf, 1) == RET_OK) {
@@ -471,7 +471,7 @@ char *unpackFile(ReportList *reports, const char *abs_name, const char *local_na
break;
}
/* else create it */
- /* fall-through */
+ ATTR_FALLTHROUGH;
}
case PF_WRITE_ORIGINAL:
if (writePackedFile(reports, abs_name, pf, 1) == RET_OK) {
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 53675f33a69..c798a1587ee 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -52,7 +52,6 @@
#include "BKE_main.h"
#include "BKE_context.h"
#include "BKE_crazyspace.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_key.h"
@@ -64,6 +63,8 @@
#include "BKE_pbvh.h"
#include "BKE_subsurf.h"
+#include "DEG_depsgraph.h"
+
#include "bmesh.h"
const char PAINT_CURSOR_SCULPT[3] = {255, 100, 100};
@@ -73,9 +74,9 @@ const char PAINT_CURSOR_TEXTURE_PAINT[3] = {255, 255, 255};
static OverlayControlFlags overlay_flags = 0;
-void BKE_paint_invalidate_overlay_tex(Scene *scene, const Tex *tex)
+void BKE_paint_invalidate_overlay_tex(Scene *scene, SceneLayer *sl, const Tex *tex)
{
- Paint *p = BKE_paint_get_active(scene);
+ Paint *p = BKE_paint_get_active(scene, sl);
Brush *br = p->brush;
if (!br)
@@ -87,9 +88,9 @@ void BKE_paint_invalidate_overlay_tex(Scene *scene, const Tex *tex)
overlay_flags |= PAINT_INVALID_OVERLAY_TEXTURE_SECONDARY;
}
-void BKE_paint_invalidate_cursor_overlay(Scene *scene, CurveMapping *curve)
+void BKE_paint_invalidate_cursor_overlay(Scene *scene, SceneLayer *sl, CurveMapping *curve)
{
- Paint *p = BKE_paint_get_active(scene);
+ Paint *p = BKE_paint_get_active(scene, sl);
Brush *br = p->brush;
if (br && br->curve == curve)
@@ -155,13 +156,13 @@ Paint *BKE_paint_get_active_from_paintmode(Scene *sce, PaintMode mode)
return NULL;
}
-Paint *BKE_paint_get_active(Scene *sce)
+Paint *BKE_paint_get_active(Scene *sce, SceneLayer *sl)
{
- if (sce) {
+ if (sce && sl) {
ToolSettings *ts = sce->toolsettings;
- if (sce->basact && sce->basact->object) {
- switch (sce->basact->object->mode) {
+ if (sl->basact && sl->basact->object) {
+ switch (sl->basact->object->mode) {
case OB_MODE_SCULPT:
return &ts->sculpt->paint;
case OB_MODE_VERTEX_PAINT:
@@ -187,14 +188,15 @@ Paint *BKE_paint_get_active(Scene *sce)
Paint *BKE_paint_get_active_from_context(const bContext *C)
{
Scene *sce = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
SpaceImage *sima;
- if (sce) {
+ if (sce && sl) {
ToolSettings *ts = sce->toolsettings;
Object *obact = NULL;
- if (sce->basact && sce->basact->object)
- obact = sce->basact->object;
+ if (sl->basact && sl->basact->object)
+ obact = sl->basact->object;
if ((sima = CTX_wm_space_image(C)) != NULL) {
if (obact && obact->mode == OB_MODE_EDIT) {
@@ -237,14 +239,15 @@ Paint *BKE_paint_get_active_from_context(const bContext *C)
PaintMode BKE_paintmode_get_active_from_context(const bContext *C)
{
Scene *sce = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
SpaceImage *sima;
- if (sce) {
+ if (sce && sl) {
ToolSettings *ts = sce->toolsettings;
Object *obact = NULL;
- if (sce->basact && sce->basact->object)
- obact = sce->basact->object;
+ if (sl->basact && sl->basact->object)
+ obact = sl->basact->object;
if ((sima = CTX_wm_space_image(C)) != NULL) {
if (obact && obact->mode == OB_MODE_EDIT) {
@@ -314,7 +317,7 @@ PaintCurve *BKE_paint_curve_add(Main *bmain, const char *name)
return pc;
}
-PaintCurve *BKE_paint_curve_copy(Main *bmain, PaintCurve *pc)
+PaintCurve *BKE_paint_curve_copy(Main *bmain, const PaintCurve *pc)
{
PaintCurve *pc_new;
@@ -396,7 +399,7 @@ Palette *BKE_palette_add(Main *bmain, const char *name)
return palette;
}
-Palette *BKE_palette_copy(Main *bmain, Palette *palette)
+Palette *BKE_palette_copy(Main *bmain, const Palette *palette)
{
Palette *palette_new;
@@ -409,7 +412,7 @@ Palette *BKE_palette_copy(Main *bmain, Palette *palette)
return palette_new;
}
-void BKE_palette_make_local(Main *bmain, Palette *palette, bool lib_local)
+void BKE_palette_make_local(Main *bmain, Palette *palette, const bool lib_local)
{
BKE_id_make_local_generic(bmain, &palette->id, true, lib_local);
}
@@ -681,7 +684,7 @@ void BKE_sculptsession_bm_to_me(Object *ob, bool reorder)
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);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
}
@@ -926,6 +929,9 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
}
}
}
+
+ /* 2.8x - avoid full mesh update! */
+ BKE_mesh_batch_cache_dirty(me, BKE_MESH_BATCH_DIRTY_SCULPT_COORDS);
}
int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd)
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 2e8afc846e7..9a3da64e7d8 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -79,7 +79,6 @@
#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"
@@ -87,6 +86,9 @@
#include "BKE_scene.h"
#include "BKE_deform.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "RE_render_ext.h"
unsigned int PSYS_FRAND_SEED_OFFSET[PSYS_FRAND_COUNT];
@@ -254,11 +256,16 @@ struct LatticeDeformData *psys_create_lattice_deform_data(ParticleSimulationData
if (psys_in_edit_mode(sim->scene, 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;
for (; md; md = md->next) {
if (md->type == eModifierType_Lattice) {
- LatticeModifierData *lmd = (LatticeModifierData *)md;
- lattice = lmd->object;
+ if (md->mode & mode) {
+ LatticeModifierData *lmd = (LatticeModifierData *)md;
+ lattice = lmd->object;
+ sim->psys->lattice_strength = lmd->strength;
+ }
+
break;
}
}
@@ -319,16 +326,24 @@ void psys_check_group_weights(ParticleSettings *part)
int current = 0;
if (part->ren_as == PART_DRAW_GR && part->dup_group && part->dup_group->gobject.first) {
- /* first remove all weights that don't have an object in the group */
+ /* 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 (!BKE_group_object_exists(part->dup_group, dw->ob)) {
- tdw = dw->next;
- BLI_freelinkN(&part->dupliweights, dw);
- dw = tdw;
+ 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
+ else {
dw = dw->next;
+ }
}
/* then add objects in the group to new list */
@@ -496,7 +511,9 @@ void psys_free_particles(ParticleSystem *psys)
PARTICLE_P;
if (psys->particles) {
- if (psys->part->type == PART_HAIR) {
+ /* Even though psys->part should never be NULL, this can happen as an exception during deletion.
+ * See ID_REMAP_SKIP/FORCE/FLAG_NEVER_NULL_USAGE in BKE_library_remap. */
+ if (psys->part && psys->part->type == PART_HAIR) {
LOOP_PARTICLES {
if (pa->hair)
MEM_freeN(pa->hair);
@@ -586,7 +603,7 @@ void psys_free(Object *ob, ParticleSystem *psys)
BLI_bvhtree_free(psys->bvhtree);
BLI_kdtree_free(psys->tree);
-
+
if (psys->fluid_springs)
MEM_freeN(psys->fluid_springs);
@@ -597,6 +614,8 @@ void psys_free(Object *ob, ParticleSystem *psys)
MEM_freeN(psys->pdd);
}
+ BKE_particle_batch_cache_free(psys);
+
MEM_freeN(psys);
}
}
@@ -629,8 +648,9 @@ void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[4][4], floa
data->childcachebufs.last = psys->childcachebufs.last;
data->totchildcache = psys->totchildcache;
- if (psmd->dm_final)
- data->dm = CDDM_copy(psmd->dm_final);
+ 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;
@@ -883,6 +903,9 @@ static void get_pointcache_keys_for_time(Object *UNUSED(ob), PointCache *cache,
index2 = BKE_ptcache_mem_index_find(pm, index);
index1 = BKE_ptcache_mem_index_find(pm->prev, index);
+ if (index2 < 0) {
+ return;
+ }
BKE_ptcache_make_particle_key(key2, index2, pm->data, (float)pm->frame);
if (index1 < 0)
@@ -893,6 +916,9 @@ static void get_pointcache_keys_for_time(Object *UNUSED(ob), PointCache *cache,
else if (cache->mem_cache.first) {
pm = cache->mem_cache.first;
index2 = BKE_ptcache_mem_index_find(pm, index);
+ if (index2 < 0) {
+ return;
+ }
BKE_ptcache_make_particle_key(key2, index2, pm->data, (float)pm->frame);
copy_particle_key(key1, key2, 1);
}
@@ -2700,7 +2726,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
/* lattices have to be calculated separately to avoid mixups between effector calculations */
if (psys->lattice_deform_data) {
for (k = 0, ca = cache[p]; k <= segments; k++, ca++)
- calc_latt_deform(psys->lattice_deform_data, ca->co, 1.0f);
+ calc_latt_deform(psys->lattice_deform_data, ca->co, psys->lattice_strength);
}
}
@@ -3147,8 +3173,8 @@ ModifierData *object_add_particle_system(Scene *scene, Object *ob, const char *n
psys->flag = PSYS_CURRENT;
psys->cfra = BKE_scene_frame_get_from_ctime(scene, CFRA + 1);
- DAG_relations_tag_update(G.main);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(G.main);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
return md;
}
@@ -3183,6 +3209,9 @@ void object_remove_particle_system(Scene *UNUSED(scene), Object *ob)
/* clear particle system */
BLI_remlink(&ob->particlesystem, psys);
+ if (psys->part) {
+ id_us_min(&psys->part->id);
+ }
psys_free(ob, psys);
if (ob->particlesystem.first)
@@ -3190,8 +3219,8 @@ void object_remove_particle_system(Scene *UNUSED(scene), Object *ob)
else
ob->mode &= ~(OB_MODE_PARTICLE_EDIT | OB_MODE_HAIR_EDIT);
- DAG_relations_tag_update(G.main);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(G.main);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
static void default_particle_settings(ParticleSettings *part)
@@ -3276,6 +3305,7 @@ static void default_particle_settings(ParticleSettings *part)
part->omat = 1;
part->use_modifier_stack = false;
+ part->draw_size = 0.1f;
}
@@ -3317,7 +3347,7 @@ void BKE_particlesettings_rough_curve_init(ParticleSettings *part)
part->roughcurve = cumap;
}
-ParticleSettings *BKE_particlesettings_copy(Main *bmain, ParticleSettings *part)
+ParticleSettings *BKE_particlesettings_copy(Main *bmain, const ParticleSettings *part)
{
ParticleSettings *partn;
int a;
@@ -3360,7 +3390,8 @@ void BKE_particlesettings_make_local(Main *bmain, ParticleSettings *part, const
/* Textures */
/************************************************/
-static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int face_index, const float fuv[4], char *name, float *texco)
+static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int index, const float fuv[4],
+ char *name, float *texco, bool from_vert)
{
MFace *mf;
MTFace *tf;
@@ -3376,11 +3407,15 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int face_index, co
if (pa) {
i = ELEM(pa->num_dmcache, DMCACHE_NOTFOUND, DMCACHE_ISCHILD) ? pa->num : pa->num_dmcache;
- if (i >= dm->getNumTessFaces(dm))
+ if ((!from_vert && i >= dm->getNumTessFaces(dm)) ||
+ (from_vert && i >= dm->getNumVerts(dm)))
+ {
i = -1;
+ }
+ }
+ else {
+ i = index;
}
- else
- i = face_index;
if (i == -1) {
texco[0] = 0.0f;
@@ -3388,7 +3423,22 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int face_index, co
texco[2] = 0.0f;
}
else {
- mf = dm->getTessFaceData(dm, i, CD_MFACE);
+ if (from_vert) {
+ mf = dm->getTessFaceDataArray(dm, CD_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++) {
+ if (ELEM(i, mf->v1, mf->v2, mf->v3, mf->v4)) {
+ i = j;
+ break;
+ }
+ }
+ }
+ else {
+ mf = dm->getTessFaceData(dm, i, CD_MFACE);
+ }
psys_interpolate_uvs(&tf[i], mf->v4, fuv, texco);
@@ -3455,9 +3505,13 @@ 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, texvec))
+ if (fw && get_particle_uv(dm, NULL, face_index, fw, mtex->uvname,
+ texvec, (part->from == PART_FROM_VERT)))
+ {
break;
- /* no break, failed to get uv's, so let's try orco's */
+ }
+ /* no break, failed to get uv's, so let's try orco's */
+ ATTR_FALLTHROUGH;
case TEXCO_ORCO:
copy_v3_v3(texvec, orco);
break;
@@ -3527,9 +3581,13 @@ 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, texvec))
+ if (get_particle_uv(sim->psmd->dm_final, pa, 0, pa->fuv, mtex->uvname,
+ texvec, (part->from == PART_FROM_VERT)))
+ {
break;
- /* no break, failed to get uv's, so let's try orco's */
+ }
+ /* 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);
@@ -3737,7 +3795,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
}
if (psys->lattice_deform_data && edit == 0)
- calc_latt_deform(psys->lattice_deform_data, state->co, 1.0f);
+ calc_latt_deform(psys->lattice_deform_data, state->co, psys->lattice_strength);
}
}
}
@@ -3976,7 +4034,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
do_child_modifiers(NULL, sim, NULL, key1->co, key1->vel, key1->rot, par_orco, cpa, cpa->fuv, mat, state, t);
if (psys->lattice_deform_data)
- calc_latt_deform(psys->lattice_deform_data, state->co, 1.0f);
+ calc_latt_deform(psys->lattice_deform_data, state->co, psys->lattice_strength);
}
else {
if (pa->state.time == cfra || ELEM(part->phystype, PART_PHYS_NO, PART_PHYS_KEYED))
@@ -4035,7 +4093,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
}
if (sim->psys->lattice_deform_data)
- calc_latt_deform(sim->psys->lattice_deform_data, state->co, 1.0f);
+ calc_latt_deform(sim->psys->lattice_deform_data, state->co, psys->lattice_strength);
}
return 1;
@@ -4282,7 +4340,7 @@ void psys_apply_hair_lattice(Scene *scene, Object *ob, ParticleSystem *psys)
hkey = pa->hair;
for (h = 0; h < pa->totkey; h++, hkey++) {
mul_m4_v3(hairmat, hkey->co);
- calc_latt_deform(psys->lattice_deform_data, hkey->co, 1.0f);
+ calc_latt_deform(psys->lattice_deform_data, hkey->co, psys->lattice_strength);
mul_m4_v3(imat, hkey->co);
}
}
@@ -4294,3 +4352,22 @@ void psys_apply_hair_lattice(Scene *scene, Object *ob, ParticleSystem *psys)
psys->flag |= PSYS_EDITED;
}
}
+
+
+
+/* Draw Engine */
+void (*BKE_particle_batch_cache_dirty_cb)(ParticleSystem *psys, int mode) = NULL;
+void (*BKE_particle_batch_cache_free_cb)(ParticleSystem *psys) = NULL;
+
+void BKE_particle_batch_cache_dirty(ParticleSystem *psys, int mode)
+{
+ if (psys->batch_cache) {
+ BKE_particle_batch_cache_dirty_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 ec5f73f87ce..bfcda89a635 100644
--- a/source/blender/blenkernel/intern/particle_child.c
+++ b/source/blender/blenkernel/intern/particle_child.c
@@ -136,7 +136,7 @@ static void do_kink_spiral_deform(ParticleKey *state, const float dir[3], const
*
* The "density" parameter b is defined by the shape parameter
* and goes up to the Golden Spiral for 1.0
- * http://en.wikipedia.org/wiki/Golden_spiral
+ * https://en.wikipedia.org/wiki/Golden_spiral
*/
const float b = shape * (1.0f + sqrtf(5.0f)) / (float)M_PI * 0.25f;
/* angle of the spiral against the curve (rotated opposite to make a smooth transition) */
@@ -355,9 +355,13 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod
{
const float step_length = 1.0f / (float)(totkeys - 1);
-
float cur_length = 0.0f;
-
+
+ if (max_length <= 0.0f) {
+ keys->segments = -1;
+ totkeys = 0;
+ }
+
/* we have to correct velocity because of kink & clump */
for (k = 0, key = keys; k < totkeys; ++k, ++key) {
if (k >= 2) {
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 44cf5b119c1..4f758bde7f9 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -427,12 +427,38 @@ static int distribute_binary_search(float *sum, int n, float value)
static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, int p)
{
ParticleThreadContext *ctx= thread->ctx;
- int rng_skip_tot= PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
+ MFace *mface;
+
+ DM_ensure_tessface(ctx->dm);
+ mface = ctx->dm->getTessFaceDataArray(ctx->dm, CD_MFACE);
+
+ int rng_skip_tot = PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
/* TODO_PARTICLE - use original index */
- pa->num= ctx->index[p];
- pa->fuv[0] = 1.0f;
- pa->fuv[1] = pa->fuv[2] = pa->fuv[3] = 0.0;
+ pa->num = ctx->index[p];
+
+ zero_v4(pa->fuv);
+
+ if (pa->num != DMCACHE_NOTFOUND && pa->num < ctx->dm->getNumVerts(ctx->dm)) {
+
+ /* 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++) {
+ if (ELEM(pa->num, mface->v1, mface->v2, mface->v3, mface->v4)) {
+ unsigned int *vert = &mface->v1;
+
+ for (int j = 0; j < 4; j++, vert++) {
+ if (*vert == pa->num) {
+ pa->fuv[j] = 1.0f;
+ break;
+ }
+ }
+
+ break;
+ }
+ }
+ }
#if ONLY_WORKING_WITH_PA_VERTS
if (ctx->tree) {
@@ -1092,7 +1118,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
/* For hair, sort by origindex (allows optimization's in rendering), */
/* however with virtual parents the children need to be in random order. */
- if (part->type == PART_HAIR && !(part->childtype==PART_CHILD_FACES && part->parents!=0.0f)) {
+ if (part->type == PART_HAIR && !(part->childtype==PART_CHILD_FACES && part->parents != 0.0f)) {
int *orig_index = NULL;
if (from == PART_FROM_VERT) {
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 0728fef2a32..a6ed50fd0e9 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -78,6 +78,7 @@
#include "BKE_particle.h"
#include "BKE_global.h"
+#include "BKE_collection.h"
#include "BKE_DerivedMesh.h"
#include "BKE_object.h"
#include "BKE_material.h"
@@ -88,7 +89,6 @@
#include "BKE_modifier.h"
#include "BKE_scene.h"
#include "BKE_bvhutils.h"
-#include "BKE_depsgraph.h"
#include "PIL_time.h"
@@ -1000,7 +1000,7 @@ void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime,
part=psys->part;
/* get precise emitter matrix if particle is born */
- if (part->type!=PART_HAIR && dtime > 0.f && pa->time < cfra && pa->time >= sim->psys->cfra) {
+ 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);
psys->flag |= PSYS_OB_ANIM_RESTORE;
@@ -1183,7 +1183,7 @@ static void set_keyed_keys(ParticleSimulationData *sim)
key->time = pa->time;
}
- if (psys->flag & PSYS_KEYED_TIMING && pt->duration!=0.0f)
+ if (psys->flag & PSYS_KEYED_TIMING && pt->duration != 0.0f)
k++;
ksim.psys->flag |= keyed_flag;
@@ -2180,7 +2180,7 @@ static void basic_rotate(ParticleSettings *part, ParticleData *pa, float dfra, f
* The algorithm is roughly:
* 1. Use a BVH tree to search for faces that a particle may collide with.
* 2. Use Newton's method to find the exact time at which the collision occurs.
- * http://en.wikipedia.org/wiki/Newton's_method
+ * https://en.wikipedia.org/wiki/Newton's_method
*
************************************************/
#define COLLISION_MIN_RADIUS 0.001f
@@ -2896,7 +2896,6 @@ 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)
@@ -2941,8 +2940,9 @@ 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);
+ FOREACH_SCENE_OBJECT(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)) {
@@ -2951,6 +2951,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons
}
}
}
+ FOREACH_SCENE_OBJECT_END
if (!skip) {
psys_cache_paths(sim, cfra, use_render_params);
@@ -3925,7 +3926,7 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_
/* 2. try to read from the cache */
if (pid) {
- int cache_result = BKE_ptcache_read(pid, cache_cfra);
+ int cache_result = BKE_ptcache_read(pid, cache_cfra, true);
if (ELEM(cache_result, PTCACHE_READ_EXACT, PTCACHE_READ_INTERPOLATED)) {
cached_step(sim, cfra);
@@ -4320,6 +4321,8 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys, cons
/* 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);
+
+ BKE_particle_batch_cache_dirty(psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
}
/* ID looper */
@@ -4328,27 +4331,29 @@ void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func,
{
ParticleTarget *pt;
- func(psys, (ID **)&psys->part, userdata, IDWALK_USER | IDWALK_NEVER_NULL);
- func(psys, (ID **)&psys->target_ob, userdata, IDWALK_NOP);
- func(psys, (ID **)&psys->parent, userdata, IDWALK_NOP);
+ func(psys, (ID **)&psys->part, userdata, IDWALK_CB_USER | IDWALK_CB_NEVER_NULL);
+ func(psys, (ID **)&psys->target_ob, userdata, IDWALK_CB_NOP);
+ func(psys, (ID **)&psys->parent, userdata, IDWALK_CB_NOP);
for (pt = psys->targets.first; pt; pt = pt->next) {
- func(psys, (ID **)&pt->ob, userdata, IDWALK_NOP);
+ func(psys, (ID **)&pt->ob, userdata, IDWALK_CB_NOP);
}
- if (psys->part->phystype == PART_PHYS_BOIDS) {
+ /* Even though psys->part should never be NULL, this can happen as an exception during deletion.
+ * See ID_REMAP_SKIP/FORCE/FLAG_NEVER_NULL_USAGE in BKE_library_remap. */
+ if (psys->part && psys->part->phystype == PART_PHYS_BOIDS) {
ParticleData *pa;
int p;
for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++) {
- func(psys, (ID **)&pa->boid->ground, userdata, IDWALK_NOP);
+ func(psys, (ID **)&pa->boid->ground, userdata, IDWALK_CB_NOP);
}
}
}
/* **** Depsgraph evaluation **** */
-void BKE_particle_system_eval(EvaluationContext *UNUSED(eval_ctx),
+void BKE_particle_system_eval(struct EvaluationContext *UNUSED(eval_ctx),
Scene *scene,
Object *ob,
ParticleSystem *psys)
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index ff69f381b06..ef2eaf8405b 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -40,6 +40,7 @@
#include "BKE_paint.h"
#include "GPU_buffers.h"
+#include "GPU_immediate.h"
#include "bmesh.h"
@@ -620,7 +621,7 @@ void BKE_pbvh_free(PBVH *bvh)
if (node->flag & PBVH_Leaf) {
if (node->draw_buffers)
- GPU_free_pbvh_buffers(node->draw_buffers);
+ GPU_pbvh_buffers_free(node->draw_buffers);
if (node->vert_indices)
MEM_freeN((void *)node->vert_indices);
if (node->face_vert_indices)
@@ -635,7 +636,7 @@ void BKE_pbvh_free(PBVH *bvh)
BLI_gset_free(node->bm_other_verts, NULL);
}
}
- GPU_free_pbvh_buffer_multires(&bvh->grid_common_gpu_buffer);
+ GPU_pbvh_multires_buffers_free(&bvh->grid_common_gpu_buffer);
if (bvh->deformed) {
if (bvh->verts) {
@@ -977,7 +978,7 @@ static void pbvh_update_normals_accum_task_cb(void *userdata, const int n)
* Not exact equivalent though, since atomicity is only ensured for one component
* of the vector at a time, but here it shall not make any sensible difference. */
for (int k = 3; k--; ) {
- atomic_add_fl(&vnors[v][k], fn[k]);
+ atomic_add_and_fetch_fl(&vnors[v][k], fn[k]);
}
}
}
@@ -1090,11 +1091,11 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
PBVHNode *node = nodes[n];
if (node->flag & PBVH_RebuildDrawBuffers) {
- GPU_free_pbvh_buffers(node->draw_buffers);
+ GPU_pbvh_buffers_free(node->draw_buffers);
switch (bvh->type) {
case PBVH_GRIDS:
node->draw_buffers =
- GPU_build_grid_pbvh_buffers(node->prim_indices,
+ GPU_pbvh_grid_buffers_build(node->prim_indices,
node->totprim,
bvh->grid_hidden,
bvh->gridkey.grid_size,
@@ -1102,7 +1103,7 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
break;
case PBVH_FACES:
node->draw_buffers =
- GPU_build_mesh_pbvh_buffers(node->face_vert_indices,
+ GPU_pbvh_mesh_buffers_build(node->face_vert_indices,
bvh->mpoly, bvh->mloop, bvh->looptri,
bvh->verts,
node->prim_indices,
@@ -1110,42 +1111,44 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
break;
case PBVH_BMESH:
node->draw_buffers =
- GPU_build_bmesh_pbvh_buffers(bvh->flags & PBVH_DYNTOPO_SMOOTH_SHADING);
+ GPU_pbvh_bmesh_buffers_build(bvh->flags & PBVH_DYNTOPO_SMOOTH_SHADING);
break;
}
-
+
node->flag &= ~PBVH_RebuildDrawBuffers;
}
if (node->flag & PBVH_UpdateDrawBuffers) {
switch (bvh->type) {
case PBVH_GRIDS:
- GPU_update_grid_pbvh_buffers(node->draw_buffers,
- bvh->grids,
- bvh->grid_flag_mats,
- node->prim_indices,
- node->totprim,
- &bvh->gridkey,
- bvh->show_diffuse_color);
+ GPU_pbvh_grid_buffers_update(
+ node->draw_buffers,
+ bvh->grids,
+ bvh->grid_flag_mats,
+ node->prim_indices,
+ node->totprim,
+ &bvh->gridkey,
+ bvh->show_diffuse_color);
break;
case PBVH_FACES:
- GPU_update_mesh_pbvh_buffers(node->draw_buffers,
- bvh->verts,
- node->vert_indices,
- node->uniq_verts +
- node->face_verts,
- CustomData_get_layer(bvh->vdata,
- CD_PAINT_MASK),
- node->face_vert_indices,
- bvh->show_diffuse_color);
+ GPU_pbvh_mesh_buffers_update(
+ node->draw_buffers,
+ bvh->verts,
+ node->vert_indices,
+ node->uniq_verts +
+ node->face_verts,
+ CustomData_get_layer(bvh->vdata, CD_PAINT_MASK),
+ node->face_vert_indices,
+ bvh->show_diffuse_color);
break;
case PBVH_BMESH:
- GPU_update_bmesh_pbvh_buffers(node->draw_buffers,
- bvh->bm,
- node->bm_faces,
- node->bm_unique_verts,
- node->bm_other_verts,
- bvh->show_diffuse_color);
+ GPU_pbvh_bmesh_buffers_update(
+ node->draw_buffers,
+ bvh->bm,
+ node->bm_faces,
+ node->bm_unique_verts,
+ node->bm_other_verts,
+ bvh->show_diffuse_color);
break;
}
@@ -1156,15 +1159,16 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
static void pbvh_draw_BB(PBVH *bvh)
{
- GPU_init_draw_pbvh_BB();
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
for (int a = 0; a < bvh->totnode; a++) {
PBVHNode *node = &bvh->nodes[a];
- GPU_draw_pbvh_BB(node->vb.bmin, node->vb.bmax, ((node->flag & PBVH_Leaf) != 0));
+ GPU_pbvh_BB_draw(node->vb.bmin, node->vb.bmax, ((node->flag & PBVH_Leaf) != 0), pos);
}
- GPU_end_draw_pbvh_BB();
+ immUnbindProgram();
}
static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag)
@@ -1737,26 +1741,8 @@ 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_draw_pbvh_buffers(node->draw_buffers,
+ GPU_pbvh_buffers_draw(node->draw_buffers,
data->setMaterial,
data->wireframe,
data->fast);
@@ -1861,6 +1847,67 @@ void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*fnors)[3],
pbvh_draw_BB(bvh);
}
+struct PBVHNodeDrawCallbackData {
+
+ void (*draw_fn)(void *user_data, Gwn_Batch *batch);
+ void *user_data;
+ bool fast;
+};
+
+static void pbvh_node_draw_cb(PBVHNode *node, void *data_v)
+{
+ struct PBVHNodeDrawCallbackData *data = data_v;
+
+ if (!(node->flag & PBVH_FullyHidden)) {
+ Gwn_Batch *triangles = GPU_pbvh_buffers_batch_get(node->draw_buffers, data->fast);
+ if (triangles != NULL) {
+ data->draw_fn(data->user_data, triangles);
+ }
+ }
+}
+
+/**
+ * Version of #BKE_pbvh_draw that runs a callback.
+ */
+void BKE_pbvh_draw_cb(
+ PBVH *bvh, float (*planes)[4], float (*fnors)[3], bool fast,
+ void (*draw_fn)(void *user_data, Gwn_Batch *batch), void *user_data)
+{
+ struct PBVHNodeDrawCallbackData draw_data = {
+ .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]);
+
+ BKE_pbvh_search_gather(bvh, update_search_cb, SET_INT_IN_POINTER(PBVH_UpdateNormals | PBVH_UpdateDrawBuffers),
+ &nodes, &totnode);
+
+ pbvh_update_normals(bvh, nodes, totnode, fnors);
+ pbvh_update_draw_buffers(bvh, nodes, totnode);
+
+ if (nodes) MEM_freeN(nodes);
+
+ if (planes) {
+ 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, pbvh_node_draw_cb, &draw_data);
+ }
+#if 0
+ if (G.debug_value == 14)
+ pbvh_draw_BB(bvh);
+#endif
+}
+
void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, void **gridfaces,
DMFlagMat *flagmats, BLI_bitmap **grid_hidden)
{
@@ -2070,22 +2117,22 @@ 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;
}
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 55f9f384081..c5e49883dc6 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -148,8 +148,7 @@ BLI_INLINE void bm_face_as_array_index_tri(BMFace *f, int r_index[3])
*
* Its assumed that \a l_radial_first is never forming the target face.
*/
-static bool bm_face_exists_tri_from_loop_vert(
- BMLoop *l_radial_first, BMVert *v_opposite, BMFace **r_face_existing)
+static BMFace *bm_face_exists_tri_from_loop_vert(BMLoop *l_radial_first, BMVert *v_opposite)
{
BLI_assert(!ELEM(v_opposite, l_radial_first->v, l_radial_first->next->v, l_radial_first->prev->v));
if (l_radial_first->radial_next != l_radial_first) {
@@ -157,12 +156,11 @@ static bool bm_face_exists_tri_from_loop_vert(
do {
BLI_assert(l_radial_iter->f->len == 3);
if (l_radial_iter->prev->v == v_opposite) {
- *r_face_existing = l_radial_iter->f;
- return true;
+ return l_radial_iter->f;
}
} while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
}
- return false;
+ return NULL;
}
/**
@@ -354,7 +352,7 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde
n->layer_disp = NULL;
if (n->draw_buffers) {
- GPU_free_pbvh_buffers(n->draw_buffers);
+ GPU_pbvh_buffers_free(n->draw_buffers);
n->draw_buffers = NULL;
}
n->flag &= ~PBVH_Leaf;
@@ -519,7 +517,7 @@ static BMFace *pbvh_bmesh_face_create(
PBVHNode *node = &bvh->nodes[node_index];
/* ensure we never add existing face */
- BLI_assert(BM_face_exists(v_tri, 3, NULL) == false);
+ BLI_assert(!BM_face_exists(v_tri, 3));
BMFace *f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP);
f->head.hflag = f_example->head.hflag;
@@ -1313,18 +1311,17 @@ static void pbvh_bmesh_collapse_edge(
* deletion as well. Prevents extraneous "flaps" from being
* created. */
#if 0
- if (UNLIKELY(BM_face_exists(v_tri, 3, &existing_face)))
+ if (UNLIKELY(existing_face = BM_face_exists(v_tri, 3)))
#else
- if (UNLIKELY(bm_face_exists_tri_from_loop_vert(l->next, v_conn, &existing_face)))
+ if (UNLIKELY(existing_face = bm_face_exists_tri_from_loop_vert(l->next, v_conn)))
#endif
{
- BLI_assert(existing_face);
BLI_buffer_append(deleted_faces, BMFace *, existing_face);
}
else {
BMVert *v_tri[3] = {v_conn, l->next->v, l->prev->v};
- BLI_assert(BM_face_exists(v_tri, 3, NULL) == false);
+ BLI_assert(!BM_face_exists(v_tri, 3));
BMEdge *e_tri[3];
PBVHNode *n = pbvh_bmesh_node_from_face(bvh, f);
int ni = n - bvh->nodes;
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 69a98c06000..0b152534dcb 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -1137,13 +1137,13 @@ static int ptcache_smoke_openvdb_read(struct OpenVDBReader *reader, void *smoke_
OpenVDB_import_grid_fl(reader, "density", &dens, sds->res_wt);
- if (fluid_fields & SM_ACTIVE_FIRE) {
+ if (cache_fields & SM_ACTIVE_FIRE) {
OpenVDB_import_grid_fl(reader, "flame", &flame, sds->res_wt);
OpenVDB_import_grid_fl(reader, "fuel", &fuel, sds->res_wt);
OpenVDB_import_grid_fl(reader, "react", &react, sds->res_wt);
}
- if (fluid_fields & SM_ACTIVE_COLORS) {
+ if (cache_fields & SM_ACTIVE_COLORS) {
OpenVDB_import_grid_vec(reader, "color", &r, &g, &b, sds->res_wt);
}
@@ -2632,7 +2632,7 @@ static int ptcache_interpolate(PTCacheID *pid, float cfra, int cfra1, int cfra2)
}
/* reads cache from disk or memory */
/* possible to get old or interpolated result */
-int BKE_ptcache_read(PTCacheID *pid, float cfra)
+int BKE_ptcache_read(PTCacheID *pid, float cfra, bool no_extrapolate_old)
{
int cfrai = (int)floor(cfra), cfra1=0, cfra2=0;
int ret = 0;
@@ -2658,10 +2658,17 @@ int BKE_ptcache_read(PTCacheID *pid, float cfra)
return 0;
/* don't read old cache if already simulated past cached frame */
- if (cfra1 == 0 && cfra2 && cfra2 <= pid->cache->simframe)
- return 0;
- if (cfra1 && cfra1 == cfra2)
- return 0;
+ if (no_extrapolate_old) {
+ if (cfra1 == 0 && cfra2 && cfra2 <= pid->cache->simframe)
+ return 0;
+ if (cfra1 && cfra1 == cfra2)
+ return 0;
+ }
+ else {
+ /* avoid calling interpolate between the same frame values */
+ if (cfra1 && cfra1 == cfra2)
+ cfra1 = 0;
+ }
if (cfra1) {
if (pid->file_type == PTCACHE_FILE_OPENVDB && pid->read_openvdb_stream) {
@@ -3611,9 +3618,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
psys_get_pointcache_start_end(scene, pid->calldata, &cache->startframe, &cache->endframe);
}
- if ((cache->flag & PTCACHE_REDO_NEEDED || (cache->flag & PTCACHE_SIMULATION_VALID)==0) &&
- (render || bake))
- {
+ if (((cache->flag & PTCACHE_BAKED) == 0) && (render || bake)) {
BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
}
@@ -3647,7 +3652,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(G.main->eval_ctx, bmain, scene, scene->lay);
+ BKE_scene_update_for_newframe(G.main->eval_ctx, bmain, scene);
if (baker->update_progress) {
float progress = ((float)(CFRA - startframe)/(float)(endframe - startframe));
@@ -3733,7 +3738,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_update_for_newframe(bmain->eval_ctx, bmain, scene);
}
/* TODO: call redraw all windows somehow */
diff --git a/source/blender/blenkernel/intern/property.c b/source/blender/blenkernel/intern/property.c
index dc4063b42ed..b163f623d21 100644
--- a/source/blender/blenkernel/intern/property.c
+++ b/source/blender/blenkernel/intern/property.c
@@ -65,7 +65,7 @@ void BKE_bproperty_free_list(ListBase *lb)
}
}
-bProperty *BKE_bproperty_copy(bProperty *prop)
+bProperty *BKE_bproperty_copy(const bProperty *prop)
{
bProperty *propn;
@@ -80,7 +80,7 @@ bProperty *BKE_bproperty_copy(bProperty *prop)
return propn;
}
-void BKE_bproperty_copy_list(ListBase *lbn, ListBase *lbo)
+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 */
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 0f1f9b4bdf7..a2b5ac4359d 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -46,6 +46,7 @@
# include "RBI_api.h"
#endif
+#include "DNA_ID.h"
#include "DNA_group_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@@ -54,7 +55,6 @@
#include "DNA_scene_types.h"
#include "BKE_cdderivedmesh.h"
-#include "BKE_depsgraph.h"
#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_library.h"
@@ -65,13 +65,22 @@
#include "BKE_rigidbody.h"
#include "BKE_scene.h"
-#ifdef WITH_BULLET
-
/* ************************************** */
/* Memory Management */
/* Freeing Methods --------------------- */
+#ifndef WITH_BULLET
+
+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)) {}
+static void RB_body_delete(void *UNUSED(body)) {}
+static void RB_shape_delete(void *UNUSED(shape)) {}
+static void RB_constraint_delete(void *UNUSED(con)) {}
+
+#endif
+
/* Free rigidbody world */
void BKE_rigidbody_free_world(RigidBodyWorld *rbw)
{
@@ -165,6 +174,8 @@ void BKE_rigidbody_free_constraint(Object *ob)
ob->rigidbody_constraint = NULL;
}
+#ifdef WITH_BULLET
+
/* Copying Methods --------------------- */
/* These just copy the data, clearing out references to physics objects.
@@ -172,7 +183,7 @@ void BKE_rigidbody_free_constraint(Object *ob)
* be added to relevant groups later...
*/
-RigidBodyOb *BKE_rigidbody_copy_object(Object *ob)
+RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob)
{
RigidBodyOb *rboN = NULL;
@@ -192,7 +203,7 @@ RigidBodyOb *BKE_rigidbody_copy_object(Object *ob)
return rboN;
}
-RigidBodyCon *BKE_rigidbody_copy_constraint(Object *ob)
+RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob)
{
RigidBodyCon *rbcN = NULL;
@@ -211,13 +222,6 @@ RigidBodyCon *BKE_rigidbody_copy_constraint(Object *ob)
return rbcN;
}
-/* preserve relationships between constraints and rigid bodies after duplication */
-void BKE_rigidbody_relink_constraint(RigidBodyCon *rbc)
-{
- ID_NEW(rbc->ob1);
- ID_NEW(rbc->ob2);
-}
-
/* ************************************** */
/* Setup Utilities - Validate Sim Instances */
@@ -804,8 +808,20 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b
RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_stiffness_z);
RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_damping_z);
+ RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->flag & RBC_FLAG_USE_SPRING_ANG_X);
+ RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_stiffness_ang_x);
+ RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_damping_ang_x);
+
+ RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Y);
+ RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_stiffness_ang_y);
+ RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_damping_ang_y);
+
+ RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Z);
+ RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_stiffness_ang_z);
+ RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_damping_ang_z);
+
RB_constraint_set_equilibrium_6dof_spring(rbc->physics_constraint);
- /* fall-through */
+ ATTR_FALLTHROUGH;
case RBC_TYPE_6DOF:
if (rbc->type == RBC_TYPE_6DOF) /* a litte awkward but avoids duplicate code for limits */
rbc->physics_constraint = RB_constraint_new_6dof(loc, rot, rb1, rb2);
@@ -950,24 +966,21 @@ RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw)
void BKE_rigidbody_world_groups_relink(RigidBodyWorld *rbw)
{
- if (rbw->group && rbw->group->id.newid)
- rbw->group = (Group *)rbw->group->id.newid;
- if (rbw->constraints && rbw->constraints->id.newid)
- rbw->constraints = (Group *)rbw->constraints->id.newid;
- if (rbw->effector_weights->group && rbw->effector_weights->group->id.newid)
- rbw->effector_weights->group = (Group *)rbw->effector_weights->group->id.newid;
+ ID_NEW_REMAP(rbw->group);
+ ID_NEW_REMAP(rbw->constraints);
+ ID_NEW_REMAP(rbw->effector_weights->group);
}
void BKE_rigidbody_world_id_loop(RigidBodyWorld *rbw, RigidbodyWorldIDFunc func, void *userdata)
{
- func(rbw, (ID **)&rbw->group, userdata, IDWALK_NOP);
- func(rbw, (ID **)&rbw->constraints, userdata, IDWALK_NOP);
- func(rbw, (ID **)&rbw->effector_weights->group, userdata, IDWALK_NOP);
+ func(rbw, (ID **)&rbw->group, userdata, IDWALK_CB_NOP);
+ func(rbw, (ID **)&rbw->constraints, userdata, IDWALK_CB_NOP);
+ func(rbw, (ID **)&rbw->effector_weights->group, userdata, IDWALK_CB_NOP);
if (rbw->objects) {
int i;
for (i = 0; i < rbw->numbodies; i++) {
- func(rbw, (ID **)&rbw->objects[i], userdata, IDWALK_NOP);
+ func(rbw, (ID **)&rbw->objects[i], userdata, IDWALK_CB_NOP);
}
}
}
@@ -1072,9 +1085,15 @@ RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short ty
rbc->spring_damping_x = 0.5f;
rbc->spring_damping_y = 0.5f;
rbc->spring_damping_z = 0.5f;
+ rbc->spring_damping_ang_x = 0.5f;
+ rbc->spring_damping_ang_y = 0.5f;
+ rbc->spring_damping_ang_z = 0.5f;
rbc->spring_stiffness_x = 10.0f;
rbc->spring_stiffness_y = 10.0f;
rbc->spring_stiffness_z = 10.0f;
+ rbc->spring_stiffness_ang_x = 10.0f;
+ rbc->spring_stiffness_ang_y = 10.0f;
+ rbc->spring_stiffness_ang_z = 10.0f;
rbc->motor_lin_max_impulse = 1.0f;
rbc->motor_lin_target_velocity = 1.0f;
@@ -1466,24 +1485,60 @@ 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)
{
RigidBodyOb *rbo = ob->rigidbody_object;
+ bool correct_delta = !(rbo->flag & RBO_FLAG_KINEMATIC || rbo->type == RBO_TYPE_PASSIVE);
/* return rigid body and object to their initial states */
copy_v3_v3(rbo->pos, ob->loc);
copy_v3_v3(ob->loc, loc);
+ if (correct_delta) {
+ add_v3_v3(rbo->pos, ob->dloc);
+ }
+
if (ob->rotmode > 0) {
- eulO_to_quat(rbo->orn, ob->rot, ob->rotmode);
+ float qt[4];
+ eulO_to_quat(qt, ob->rot, ob->rotmode);
+
+ if (correct_delta) {
+ float dquat[4];
+ eulO_to_quat(dquat, ob->drot, ob->rotmode);
+
+ mul_qt_qtqt(rbo->orn, dquat, qt);
+ }
+ else {
+ copy_qt_qt(rbo->orn, qt);
+ }
+
copy_v3_v3(ob->rot, rot);
}
else if (ob->rotmode == ROT_MODE_AXISANGLE) {
- axis_angle_to_quat(rbo->orn, ob->rotAxis, ob->rotAngle);
+ float qt[4];
+ axis_angle_to_quat(qt, ob->rotAxis, ob->rotAngle);
+
+ if (correct_delta) {
+ float dquat[4];
+ axis_angle_to_quat(dquat, ob->drotAxis, ob->drotAngle);
+
+ mul_qt_qtqt(rbo->orn, dquat, qt);
+ }
+ else {
+ copy_qt_qt(rbo->orn, qt);
+ }
+
copy_v3_v3(ob->rotAxis, rotAxis);
ob->rotAngle = rotAngle;
}
else {
- copy_qt_qt(rbo->orn, ob->quat);
+ if (correct_delta) {
+ mul_qt_qtqt(rbo->orn, ob->dquat, ob->quat);
+ }
+ else {
+ copy_qt_qt(rbo->orn, ob->quat);
+ }
+
copy_qt_qt(ob->quat, quat);
}
+
if (rbo->physics_object) {
/* allow passive objects to return to original transform */
if (rbo->type == RBO_TYPE_PASSIVE)
@@ -1495,8 +1550,9 @@ void BKE_rigidbody_aftertrans_update(Object *ob, float loc[3], float rot[3], flo
void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw)
{
- if (rbw)
+ if (rbw) {
rbw->pointcache->flag |= PTCACHE_OUTDATED;
+ }
}
/* ------------------ */
@@ -1543,12 +1599,8 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
BKE_ptcache_id_time(&pid, scene, ctime, &startframe, &endframe, NULL);
cache = rbw->pointcache;
- if (ctime <= startframe) {
- rbw->ltime = startframe;
- return;
- }
/* make sure we don't go out of cache frame range */
- else if (ctime > endframe) {
+ if (ctime > endframe) {
ctime = endframe;
}
@@ -1560,14 +1612,19 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
/* try to read from cache */
// RB_TODO deal with interpolated, old and baked results
- if (BKE_ptcache_read(&pid, ctime)) {
+ bool can_simulate = (ctime == rbw->ltime + 1) && !(cache->flag & PTCACHE_BAKED);
+
+ if (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0) {
+ rbw->ltime = cache->startframe;
+ }
+
+ if (BKE_ptcache_read(&pid, ctime, can_simulate)) {
BKE_ptcache_validate(cache, (int)ctime);
- rbw->ltime = ctime;
return;
}
/* advance simulation, we can only step one frame forward */
- if (ctime == rbw->ltime + 1 && !(cache->flag & PTCACHE_BAKED)) {
+ if (ctime == rbw->ltime + 1) {
/* 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);
@@ -1600,12 +1657,8 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
# pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
-void BKE_rigidbody_free_world(RigidBodyWorld *rbw) {}
-void BKE_rigidbody_free_object(Object *ob) {}
-void BKE_rigidbody_free_constraint(Object *ob) {}
-struct RigidBodyOb *BKE_rigidbody_copy_object(Object *ob) { return NULL; }
-struct RigidBodyCon *BKE_rigidbody_copy_constraint(Object *ob) { return NULL; }
-void BKE_rigidbody_relink_constraint(RigidBodyCon *rbc) {}
+struct RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob) { return NULL; }
+struct RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob) { return NULL; }
void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool rebuild) {}
void BKE_rigidbody_calc_volume(Object *ob, float *r_vol) { if (r_vol) *r_vol = 0.0f; }
void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3]) { zero_v3(r_center); }
@@ -1634,7 +1687,7 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) {}
/* -------------------- */
/* Depsgraph evaluation */
-void BKE_rigidbody_rebuild_sim(EvaluationContext *UNUSED(eval_ctx),
+void BKE_rigidbody_rebuild_sim(struct EvaluationContext *UNUSED(eval_ctx),
Scene *scene)
{
float ctime = BKE_scene_frame_get(scene);
@@ -1649,7 +1702,7 @@ void BKE_rigidbody_rebuild_sim(EvaluationContext *UNUSED(eval_ctx),
}
}
-void BKE_rigidbody_eval_simulation(EvaluationContext *UNUSED(eval_ctx),
+void BKE_rigidbody_eval_simulation(struct EvaluationContext *UNUSED(eval_ctx),
Scene *scene)
{
float ctime = BKE_scene_frame_get(scene);
@@ -1664,7 +1717,7 @@ void BKE_rigidbody_eval_simulation(EvaluationContext *UNUSED(eval_ctx),
}
}
-void BKE_rigidbody_object_sync_transforms(EvaluationContext *UNUSED(eval_ctx),
+void BKE_rigidbody_object_sync_transforms(struct EvaluationContext *UNUSED(eval_ctx),
Scene *scene,
Object *ob)
{
diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c
index a468420f87d..19d646daf9f 100644
--- a/source/blender/blenkernel/intern/sca.c
+++ b/source/blender/blenkernel/intern/sca.c
@@ -44,7 +44,9 @@
#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"
@@ -85,7 +87,7 @@ bSensor *copy_sensor(bSensor *sens)
return sensn;
}
-void copy_sensors(ListBase *lbn, ListBase *lbo)
+void copy_sensors(ListBase *lbn, const ListBase *lbo)
{
bSensor *sens, *sensn;
@@ -249,7 +251,7 @@ bController *copy_controller(bController *cont)
return contn;
}
-void copy_controllers(ListBase *lbn, ListBase *lbo)
+void copy_controllers(ListBase *lbn, const ListBase *lbo)
{
bController *cont, *contn;
@@ -387,7 +389,7 @@ bActuator *copy_actuator(bActuator *act)
return actn;
}
-void copy_actuators(ListBase *lbn, ListBase *lbo)
+void copy_actuators(ListBase *lbn, const ListBase *lbo)
{
bActuator *act, *actn;
@@ -600,41 +602,41 @@ void set_sca_new_poins_ob(Object *ob)
if (act->flag & ACT_NEW) {
if (act->type==ACT_EDIT_OBJECT) {
bEditObjectActuator *eoa= act->data;
- ID_NEW(eoa->ob);
+ ID_NEW_REMAP(eoa->ob);
}
else if (act->type==ACT_SCENE) {
bSceneActuator *sca= act->data;
- ID_NEW(sca->camera);
+ ID_NEW_REMAP(sca->camera);
}
else if (act->type==ACT_CAMERA) {
bCameraActuator *ca= act->data;
- ID_NEW(ca->ob);
+ ID_NEW_REMAP(ca->ob);
}
else if (act->type==ACT_OBJECT) {
bObjectActuator *oa= act->data;
- ID_NEW(oa->reference);
+ ID_NEW_REMAP(oa->reference);
}
else if (act->type==ACT_MESSAGE) {
bMessageActuator *ma= act->data;
- ID_NEW(ma->toObject);
+ ID_NEW_REMAP(ma->toObject);
}
else if (act->type==ACT_PARENT) {
bParentActuator *para = act->data;
- ID_NEW(para->ob);
+ ID_NEW_REMAP(para->ob);
}
else if (act->type==ACT_ARMATURE) {
bArmatureActuator *aa = act->data;
- ID_NEW(aa->target);
- ID_NEW(aa->subtarget);
+ ID_NEW_REMAP(aa->target);
+ ID_NEW_REMAP(aa->subtarget);
}
else if (act->type==ACT_PROPERTY) {
bPropertyActuator *pa= act->data;
- ID_NEW(pa->ob);
+ ID_NEW_REMAP(pa->ob);
}
else if (act->type==ACT_STEERING) {
bSteeringActuator *sta = act->data;
- ID_NEW(sta->navmesh);
- ID_NEW(sta->target);
+ ID_NEW_REMAP(sta->navmesh);
+ ID_NEW_REMAP(sta->target);
}
}
act= act->next;
@@ -653,6 +655,161 @@ void set_sca_new_poins(void)
}
}
+/**
+ * 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)
+{
+ copy_sensors(&ob_new->sensors, &ob->sensors);
+ copy_controllers(&ob_new->controllers, &ob->controllers);
+ copy_actuators(&ob_new->actuators, &ob->actuators);
+
+ 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)
{
@@ -835,19 +992,19 @@ void BKE_sca_sensors_id_loop(ListBase *senslist, SCASensorIDFunc func, void *use
bSensor *sensor;
for (sensor = senslist->first; sensor; sensor = sensor->next) {
- func(sensor, (ID **)&sensor->ob, userdata, IDWALK_NOP);
+ 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_NOP);
+ func(sensor, (ID **)&ts->ma, userdata, IDWALK_CB_NOP);
break;
}
case SENS_MESSAGE:
{
bMessageSensor *ms = sensor->data;
- func(sensor, (ID **)&ms->fromObject, userdata, IDWALK_NOP);
+ func(sensor, (ID **)&ms->fromObject, userdata, IDWALK_CB_NOP);
break;
}
case SENS_ALWAYS:
@@ -878,7 +1035,7 @@ void BKE_sca_controllers_id_loop(ListBase *contlist, SCAControllerIDFunc func, v
case CONT_PYTHON:
{
bPythonCont *pc = controller->data;
- func(controller, (ID **)&pc->text, userdata, IDWALK_NOP);
+ func(controller, (ID **)&pc->text, userdata, IDWALK_CB_NOP);
break;
}
case CONT_LOGIC_AND:
@@ -899,89 +1056,89 @@ void BKE_sca_actuators_id_loop(ListBase *actlist, SCAActuatorIDFunc func, void *
bActuator *actuator;
for (actuator = actlist->first; actuator; actuator = actuator->next) {
- func(actuator, (ID **)&actuator->ob, userdata, IDWALK_NOP);
+ 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_NOP);
+ func(actuator, (ID **)&aoa->ob, userdata, IDWALK_CB_NOP);
break;
}
case ACT_ACTION:
{
bActionActuator *aa = actuator->data;
- func(actuator, (ID **)&aa->act, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&aa->act, userdata, IDWALK_CB_NOP);
break;
}
case ACT_SOUND:
{
bSoundActuator *sa = actuator->data;
- func(actuator, (ID **)&sa->sound, userdata, IDWALK_NOP);
+ 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_NOP);
- func(actuator, (ID **)&eoa->me, userdata, IDWALK_NOP);
+ 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_NOP);
- func(actuator, (ID **)&sa->camera, userdata, IDWALK_NOP);
+ 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_NOP);
+ func(actuator, (ID **)&pa->ob, userdata, IDWALK_CB_NOP);
break;
}
case ACT_OBJECT:
{
bObjectActuator *oa = actuator->data;
- func(actuator, (ID **)&oa->reference, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&oa->reference, userdata, IDWALK_CB_NOP);
break;
}
case ACT_CAMERA:
{
bCameraActuator *ca = actuator->data;
- func(actuator, (ID **)&ca->ob, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&ca->ob, userdata, IDWALK_CB_NOP);
break;
}
case ACT_MESSAGE:
{
bMessageActuator *ma = actuator->data;
- func(actuator, (ID **)&ma->toObject, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&ma->toObject, userdata, IDWALK_CB_NOP);
break;
}
case ACT_2DFILTER:
{
bTwoDFilterActuator *tdfa = actuator->data;
- func(actuator, (ID **)&tdfa->text, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&tdfa->text, userdata, IDWALK_CB_NOP);
break;
}
case ACT_PARENT:
{
bParentActuator *pa = actuator->data;
- func(actuator, (ID **)&pa->ob, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&pa->ob, userdata, IDWALK_CB_NOP);
break;
}
case ACT_ARMATURE:
{
bArmatureActuator *aa = actuator->data;
- func(actuator, (ID **)&aa->target, userdata, IDWALK_NOP);
- func(actuator, (ID **)&aa->subtarget, userdata, IDWALK_NOP);
+ 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_NOP);
- func(actuator, (ID **)&sa->navmesh, userdata, IDWALK_NOP);
+ 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... */
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index c3c23756b70..4ebc47244fb 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -56,6 +56,7 @@
#include "BLI_utildefines.h"
#include "BLI_callbacks.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_threads.h"
#include "BLI_task.h"
@@ -66,8 +67,8 @@
#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"
@@ -77,7 +78,9 @@
#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"
#include "BKE_main.h"
#include "BKE_mask.h"
@@ -90,9 +93,12 @@
#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_query.h"
#include "RE_engine.h"
@@ -105,6 +111,8 @@
const char *RE_engine_id_BLENDER_RENDER = "BLENDER_RENDER";
const char *RE_engine_id_BLENDER_GAME = "BLENDER_GAME";
+const char *RE_engine_id_BLENDER_CLAY = "BLENDER_CLAY";
+const char *RE_engine_id_BLENDER_EEVEE = "BLENDER_EEVEE";
const char *RE_engine_id_CYCLES = "CYCLES";
void free_avicodecdata(AviCodecData *acd)
@@ -152,17 +160,69 @@ static void remove_sequencer_fcurves(Scene *sce)
}
}
+/* copy SceneCollection tree but keep pointing to the same objects */
+static void scene_collection_copy(SceneCollection *scn, SceneCollection *sc)
+{
+ BLI_duplicatelist(&scn->objects, &sc->objects);
+ for (LinkData *link = scn->objects.first; link; link = link->next) {
+ id_us_plus(link->data);
+ }
+
+ BLI_duplicatelist(&scn->filter_objects, &sc->filter_objects);
+ for (LinkData *link = scn->filter_objects.first; link; link = link->next) {
+ id_us_plus(link->data);
+ }
+
+ BLI_duplicatelist(&scn->scene_collections, &sc->scene_collections);
+ SceneCollection *nscn = scn->scene_collections.first; /* nested SceneCollection new */
+ for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
+ scene_collection_copy(nscn, nsc);
+ nscn = nscn->next;
+ }
+}
+
+/* Find the equivalent SceneCollection in the new tree */
+static SceneCollection *scene_collection_from_new_tree(SceneCollection *sc_reference, SceneCollection *scn, SceneCollection *sc)
+{
+ if (sc == sc_reference) {
+ return scn;
+ }
+
+ SceneCollection *nscn = scn->scene_collections.first; /* nested master collection new */
+ for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
+
+ SceneCollection *found = scene_collection_from_new_tree(sc_reference, nscn, nsc);
+ if (found) {
+ return found;
+ }
+ nscn = nscn->next;
+ }
+ return NULL;
+}
+
+/* recreate the LayerCollection tree */
+static void layer_collections_recreate(SceneLayer *sl, ListBase *lb, SceneCollection *mcn, SceneCollection *mc)
+{
+ for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+
+ SceneCollection *sc = scene_collection_from_new_tree(lc->scene_collection, mcn, mc);
+ BLI_assert(sc);
+
+ /* instead of syncronizing both trees we simply re-create it */
+ BKE_collection_link(sl, sc);
+ }
+}
+
Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
{
Scene *scen;
SceneRenderLayer *srl, *new_srl;
FreestyleLineSet *lineset;
ToolSettings *ts;
- Base *base, *obase;
+ BaseLegacy *legacy_base, *olegacy_base;
if (type == SCE_COPY_EMPTY) {
ListBase rl, rv;
- /* XXX. main should become an arg */
scen = BKE_scene_add(bmain, sce->id.name + 2);
rl = scen->r.layers;
@@ -187,24 +247,22 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
scen = BKE_libblock_copy(bmain, &sce->id);
BLI_duplicatelist(&(scen->base), &(sce->base));
- BKE_main_id_clear_newpoins(bmain);
-
- id_us_plus((ID *)scen->world);
+ if (type != SCE_COPY_FULL) {
+ id_us_plus((ID *)scen->world);
+ }
id_us_plus((ID *)scen->set);
/* id_us_plus((ID *)scen->gm.dome.warptext); */ /* XXX Not refcounted? see readfile.c */
scen->ed = NULL;
scen->theDag = NULL;
- scen->depsgraph = NULL;
+ scen->depsgraph_legacy = NULL;
scen->obedit = NULL;
- scen->stats = NULL;
scen->fps_info = NULL;
if (sce->rigidbody_world)
scen->rigidbody_world = BKE_rigidbody_world_copy(sce->rigidbody_world);
BLI_duplicatelist(&(scen->markers), &(sce->markers));
- BLI_duplicatelist(&(scen->transform_spaces), &(sce->transform_spaces));
BLI_duplicatelist(&(scen->r.layers), &(sce->r.layers));
BLI_duplicatelist(&(scen->r.views), &(sce->r.views));
BKE_keyingsets_copy(&(scen->keyingsets), &(sce->keyingsets));
@@ -212,21 +270,21 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
if (sce->nodetree) {
/* ID's are managed on both copy and switch */
scen->nodetree = ntreeCopyTree(bmain, sce->nodetree);
- ntreeSwitchID(scen->nodetree, &sce->id, &scen->id);
+ BKE_libblock_relink_ex(bmain, scen->nodetree, &sce->id, &scen->id, false);
}
- obase = sce->base.first;
- base = scen->base.first;
- while (base) {
- id_us_plus(&base->object->id);
- if (obase == sce->basact) scen->basact = base;
+ olegacy_base = sce->base.first;
+ legacy_base = scen->base.first;
+ while (legacy_base) {
+ id_us_plus(&legacy_base->object->id);
+ if (olegacy_base == sce->basact) scen->basact = legacy_base;
- obase = obase->next;
- base = base->next;
+ olegacy_base = olegacy_base->next;
+ legacy_base = legacy_base->next;
}
/* copy action and remove animation used by sequencer */
- BKE_animdata_copy_id_action(&scen->id);
+ BKE_animdata_copy_id_action(&scen->id, false);
if (type != SCE_COPY_FULL)
remove_sequencer_fcurves(scen);
@@ -234,17 +292,63 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
/* copy Freestyle settings */
new_srl = scen->r.layers.first;
for (srl = sce->r.layers.first; srl; srl = srl->next) {
+ if (new_srl->prop != NULL) {
+ new_srl->prop = IDP_CopyProperty(new_srl->prop);
+ }
BKE_freestyle_config_copy(&new_srl->freestyleConfig, &srl->freestyleConfig);
if (type == SCE_COPY_FULL) {
for (lineset = new_srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
if (lineset->linestyle) {
- id_us_plus((ID *)lineset->linestyle);
+ /* Has been incremented by BKE_freestyle_config_copy(). */
+ id_us_min(&lineset->linestyle->id);
lineset->linestyle = BKE_linestyle_copy(bmain, lineset->linestyle);
}
}
}
new_srl = new_srl->next;
}
+
+ /* layers and collections */
+ scen->collection = MEM_dupallocN(sce->collection);
+ SceneCollection *mcn = BKE_collection_master(scen);
+ SceneCollection *mc = BKE_collection_master(sce);
+
+ /* recursively creates a new SceneCollection tree */
+ scene_collection_copy(mcn, mc);
+
+ IDPropertyTemplate val = {0};
+ BLI_duplicatelist(&scen->render_layers, &sce->render_layers);
+ SceneLayer *new_sl = scen->render_layers.first;
+ for (SceneLayer *sl = sce->render_layers.first; sl; sl = sl->next) {
+ new_sl->stats = NULL;
+ new_sl->properties_evaluated = NULL;
+ new_sl->properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
+ IDP_MergeGroup(new_sl->properties, sl->properties, true);
+
+ /* we start fresh with no overrides and no visibility flags set
+ * instead of syncing both trees we simply unlink and relink the scene collection */
+ BLI_listbase_clear(&new_sl->layer_collections);
+ BLI_listbase_clear(&new_sl->object_bases);
+ BLI_listbase_clear(&new_sl->drawdata);
+ layer_collections_recreate(new_sl, &sl->layer_collections, mcn, mc);
+
+ Object *active_ob = OBACT_NEW;
+ Base *new_base = new_sl->object_bases.first;
+ for (Base *base = sl->object_bases.first; base; base = base->next) {
+ new_base->flag = base->flag;
+ new_base->flag_legacy = base->flag_legacy;
+
+ if (new_base->object == active_ob) {
+ new_sl->basact = new_base;
+ }
+
+ new_base = new_base->next;
+ }
+ new_sl = new_sl->next;
+ }
+
+ scen->collection_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
+ scen->layer_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
}
/* copy color management settings */
@@ -283,18 +387,29 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
ts->sculpt = MEM_dupallocN(ts->sculpt);
BKE_paint_copy(&ts->sculpt->paint, &ts->sculpt->paint);
}
+ if (ts->uvsculpt) {
+ ts->uvsculpt = MEM_dupallocN(ts->uvsculpt);
+ BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint);
+ }
BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint);
ts->imapaint.paintcursor = NULL;
id_us_plus((ID *)ts->imapaint.stencil);
+ id_us_plus((ID *)ts->imapaint.clone);
+ id_us_plus((ID *)ts->imapaint.canvas);
ts->particle.paintcursor = NULL;
+ ts->particle.scene = NULL;
+ ts->particle.object = NULL;
+
/* duplicate Grease Pencil Drawing Brushes */
BLI_listbase_clear(&ts->gp_brushes);
for (bGPDbrush *brush = sce->toolsettings->gp_brushes.first; brush; brush = brush->next) {
bGPDbrush *newbrush = BKE_gpencil_brush_duplicate(brush);
BLI_addtail(&ts->gp_brushes, newbrush);
}
-
+
+ /* duplicate Grease Pencil interpolation curve */
+ ts->gp_interpolate.custom_ipo = curvemapping_copy(ts->gp_interpolate.custom_ipo);
}
/* make a private copy of the avicodecdata */
@@ -319,7 +434,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
/* camera */
if (type == SCE_COPY_LINK_DATA || type == SCE_COPY_FULL) {
- ID_NEW(scen->camera);
+ ID_NEW_REMAP(scen->camera);
}
/* before scene copy */
@@ -328,9 +443,8 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
/* world */
if (type == SCE_COPY_FULL) {
if (scen->world) {
- id_us_plus((ID *)scen->world);
scen->world = BKE_world_copy(bmain, scen->world);
- BKE_animdata_copy_id_action((ID *)scen->world);
+ BKE_animdata_copy_id_action((ID *)scen->world, false);
}
if (sce->ed) {
@@ -355,6 +469,15 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
BKE_previewimg_id_copy(&scen->id, &sce->id);
+ if (type != SCE_COPY_NEW) {
+ if (sce->collection_properties) {
+ IDP_MergeGroup(scen->collection_properties, sce->collection_properties, true);
+ }
+ if (sce->layer_properties) {
+ IDP_MergeGroup(scen->layer_properties, sce->layer_properties, true);
+ }
+ }
+
return scen;
}
@@ -372,7 +495,7 @@ 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;
@@ -414,16 +537,19 @@ void BKE_scene_free(Scene *sce)
MEM_freeN(sce->r.ffcodecdata.properties);
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);
-
+
if (sce->toolsettings) {
if (sce->toolsettings->vpaint) {
BKE_paint_free(&sce->toolsettings->vpaint->paint);
@@ -441,21 +567,25 @@ void BKE_scene_free(Scene *sce)
BKE_paint_free(&sce->toolsettings->uvsculpt->paint);
MEM_freeN(sce->toolsettings->uvsculpt);
}
+ BKE_paint_free(&sce->toolsettings->imapaint.paint);
+
/* free Grease Pencil Drawing Brushes */
BKE_gpencil_free_brushes(&sce->toolsettings->gp_brushes);
BLI_freelistN(&sce->toolsettings->gp_brushes);
-
- BKE_paint_free(&sce->toolsettings->imapaint.paint);
-
+
+ /* free Grease Pencil interpolation curve */
+ if (sce->toolsettings->gp_interpolate.custom_ipo) {
+ curvemapping_free(sce->toolsettings->gp_interpolate.custom_ipo);
+ }
+
MEM_freeN(sce->toolsettings);
sce->toolsettings = NULL;
}
- DAG_scene_free(sce);
- if (sce->depsgraph)
- DEG_graph_free(sce->depsgraph);
-
- MEM_SAFE_FREE(sce->stats);
+ DEG_scene_graph_free(sce);
+ if (sce->depsgraph_legacy)
+ DEG_graph_free(sce->depsgraph_legacy);
+
MEM_SAFE_FREE(sce->fps_info);
BKE_sound_destroy_scene(sce);
@@ -464,6 +594,37 @@ void BKE_scene_free(Scene *sce)
BKE_previewimg_free(&sce->preview);
curvemapping_free_data(&sce->r.mblur_shutter_curve);
+
+ for (SceneLayer *sl = sce->render_layers.first, *sl_next; sl; sl = sl_next) {
+ sl_next = sl->next;
+
+ BLI_remlink(&sce->render_layers, sl);
+ BKE_scene_layer_free(sl);
+ }
+
+ /* Master Collection */
+ BKE_collection_master_free(sce, do_id_user);
+ MEM_freeN(sce->collection);
+ sce->collection = NULL;
+
+ /* LayerCollection engine settings. */
+ if (sce->collection_properties) {
+ IDP_FreeProperty(sce->collection_properties);
+ MEM_freeN(sce->collection_properties);
+ sce->collection_properties = NULL;
+ }
+
+ /* Render engine setting. */
+ if (sce->layer_properties) {
+ IDP_FreeProperty(sce->layer_properties);
+ MEM_freeN(sce->layer_properties);
+ sce->layer_properties = NULL;
+ }
+}
+
+void BKE_scene_free(Scene *sce)
+{
+ BKE_scene_free_ex(sce, true);
}
void BKE_scene_init(Scene *sce)
@@ -667,7 +828,7 @@ 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;
@@ -719,7 +880,7 @@ void BKE_scene_init(Scene *sce)
sce->gm.angulardeactthreshold = 1.0f;
sce->gm.deactivationtime = 0.0f;
- sce->gm.flag = GAME_DISPLAY_LISTS;
+ sce->gm.flag = 0;
sce->gm.matmode = GAME_MAT_MULTITEX;
sce->gm.obstacleSimulation = OBSTSIMULATION_NONE;
@@ -813,6 +974,20 @@ 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;
+
+ /* Master Collection */
+ sce->collection = MEM_callocN(sizeof(SceneCollection), "Master Collection");
+ BLI_strncpy(sce->collection->name, "Master Collection", sizeof(sce->collection->name));
+
+ /* Engine settings */
+ IDPropertyTemplate val = {0};
+ sce->collection_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
+ BKE_layer_collection_engine_settings_create(sce->collection_properties);
+
+ sce->layer_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
+ BKE_scene_layer_engine_settings_create(sce->layer_properties);
+
+ BKE_scene_layer_add(sce, "Render Layer");
}
Scene *BKE_scene_add(Main *bmain, const char *name)
@@ -820,15 +995,17 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
Scene *sce;
sce = BKE_libblock_alloc(bmain, ID_SCE, name);
+ id_us_min(&sce->id);
+ id_us_ensure_real(&sce->id);
BKE_scene_init(sce);
return sce;
}
-Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name)
+BaseLegacy *BKE_scene_base_find_by_name(struct Scene *scene, const char *name)
{
- Base *base;
+ BaseLegacy *base;
for (base = scene->base.first; base; base = base->next) {
if (STREQ(base->object->id.name + 2, name)) {
@@ -839,24 +1016,23 @@ Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name)
return base;
}
-Base *BKE_scene_base_find(Scene *scene, Object *ob)
+BaseLegacy *BKE_scene_base_find(Scene *scene, Object *ob)
{
- return BLI_findptr(&scene->base, ob, offsetof(Base, object));
+ return BLI_findptr(&scene->base, ob, offsetof(BaseLegacy, object));
}
/**
* 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_change_active_scene is used when changing scenes by the user.
*/
void BKE_scene_set_background(Main *bmain, Scene *scene)
{
Scene *sce;
- Base *base;
+ BaseLegacy *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);
@@ -880,7 +1056,7 @@ void BKE_scene_set_background(Main *bmain, Scene *scene)
/* sort baselist for scene and sets */
for (sce = scene; sce; sce = sce->set)
- DAG_scene_relations_rebuild(bmain, sce);
+ DEG_scene_relations_rebuild(bmain, sce);
/* copy layers and flags from bases to objects */
for (base = scene->base.first; base; base = base->next) {
@@ -888,13 +1064,7 @@ void BKE_scene_set_background(Main *bmain, Scene *scene)
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;
+ BKE_scene_base_flag_sync_from_base(base);
}
/* no full animation update, this to enable render code to work (render code calls own animation updates) */
}
@@ -905,7 +1075,7 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name)
Scene *sce = (Scene *)BKE_libblock_find_name_ex(bmain, ID_SCE, name);
if (sce) {
BKE_scene_set_background(bmain, sce);
- printf("Scene switch: '%s' in file: '%s'\n", name, bmain->name);
+ printf("Scene switch for render: '%s' in file: '%s'\n", name, bmain->name);
return sce;
}
@@ -915,7 +1085,7 @@ 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(EvaluationContext *eval_ctx, SceneBaseIter *iter,
- Scene **scene, int val, Base **base, Object **ob)
+ Scene **scene, int val, BaseLegacy **base, Object **ob)
{
bool run_again = true;
@@ -997,7 +1167,7 @@ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter,
}
/* handle dupli's */
if (iter->dupob) {
- (*base)->flag |= OB_FROMDUPLI;
+ (*base)->flag_legacy |= OB_FROMDUPLI;
*ob = iter->dupob->ob;
iter->phase = F_DUPLI;
@@ -1016,7 +1186,7 @@ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter,
}
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. */
@@ -1041,9 +1211,22 @@ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter,
return iter->phase;
}
+Scene *BKE_scene_find_from_collection(const Main *bmain, const SceneCollection *scene_collection)
+{
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ for (SceneLayer *layer = scene->render_layers.first; layer; layer = layer->next) {
+ if (BKE_scene_layer_has_collection(layer, scene_collection)) {
+ return scene;
+ }
+ }
+ }
+
+ return NULL;
+}
+
Object *BKE_scene_camera_find(Scene *sc)
{
- Base *base;
+ BaseLegacy *base;
for (base = sc->base.first; base; base = base->next)
if (base->object->type == OB_CAMERA)
@@ -1145,47 +1328,54 @@ char *BKE_scene_find_last_marker_name(Scene *scene, int frame)
return best_marker ? best_marker->name : NULL;
}
+void BKE_scene_remove_rigidbody_object(Scene *scene, Object *ob)
+{
+ /* remove rigid body constraint from world before removing object */
+ if (ob->rigidbody_constraint)
+ BKE_rigidbody_remove_constraint(scene, ob);
+ /* remove rigid body object from world before removing object */
+ if (ob->rigidbody_object)
+ BKE_rigidbody_remove_object(scene, ob);
+}
-Base *BKE_scene_base_add(Scene *sce, Object *ob)
+BaseLegacy *BKE_scene_base_add(Scene *sce, Object *ob)
{
- Base *b = MEM_callocN(sizeof(*b), __func__);
+ BaseLegacy *b = MEM_callocN(sizeof(*b), __func__);
BLI_addhead(&sce->base, b);
b->object = ob;
- b->flag = ob->flag;
+ b->flag_legacy = ob->flag;
b->lay = ob->lay;
return b;
}
-void BKE_scene_base_unlink(Scene *sce, Base *base)
+void BKE_scene_base_unlink(Scene *sce, BaseLegacy *base)
{
- /* remove rigid body constraint from world before removing object */
- if (base->object->rigidbody_constraint)
- BKE_rigidbody_remove_constraint(sce, base->object);
- /* remove rigid body object from world before removing object */
- if (base->object->rigidbody_object)
- BKE_rigidbody_remove_object(sce, base->object);
-
+ BKE_scene_remove_rigidbody_object(sce, base->object);
+
BLI_remlink(&sce->base, base);
if (sce->basact == base)
sce->basact = NULL;
}
+/* deprecated, use BKE_scene_layer_base_deselect_all */
void BKE_scene_base_deselect_all(Scene *sce)
{
- Base *b;
+ BaseLegacy *b;
for (b = sce->base.first; b; b = b->next) {
- b->flag &= ~SELECT;
- b->object->flag = b->flag;
+ b->flag_legacy &= ~SELECT;
+ int flag = b->object->flag & (OB_FROMGROUP);
+ b->object->flag = b->flag_legacy;
+ b->object->flag |= flag;
}
}
-void BKE_scene_base_select(Scene *sce, Base *selbase)
+void BKE_scene_base_select(Scene *sce, BaseLegacy *selbase)
{
- selbase->flag |= SELECT;
- selbase->object->flag = selbase->flag;
+ selbase->flag_legacy |= SELECT;
+ selbase->object->flag = selbase->flag_legacy;
sce->basact = selbase;
}
@@ -1239,109 +1429,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(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(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(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(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
@@ -1357,7 +1444,7 @@ static void scene_depsgraph_hack(EvaluationContext *eval_ctx, Scene *scene, Scen
static void scene_armature_depsgraph_workaround(Main *bmain)
{
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_tagged(bmain, ID_OB)) {
return;
}
for (ob = bmain->object.first; ob; ob = ob->id.next) {
@@ -1370,355 +1457,25 @@ static void scene_armature_depsgraph_workaround(Main *bmain)
}
#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;
- Scene *scene;
- Scene *scene_parent;
- double base_time;
-
-#ifdef MBALL_SINGLETHREAD_HACK
- bool has_mballs;
-#endif
-
- /* 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(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(eval_ctx, scene_parent, object, scene->rigidbody_world, true);
-
- if (object->dup_group && (object->transflag & OB_DUPLIGROUP))
- BKE_group_handle_recalc_and_update(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;
- 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) {
- 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(eval_ctx, scene_parent, object, scene->rigidbody_world, false);
-
- /* Calculate statistics. */
- if (add_to_stats) {
- StatisicsEntry *entry;
-
- BLI_assert(threadid < BLI_pool_get_num_threads(pool));
-
- 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)
-{
- int i, tot_thread;
- double finish_time;
-
- if ((G.debug & G_DEBUG_DEPSGRAPH) == 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();
- tot_thread = BLI_system_thread_count();
-
- for (i = 0; i < tot_thread; i++) {
- int total_objects = 0;
- double 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)
- {
- total_objects++;
- total_time += entry->duration;
- }
-
- printf("Thread %d: total %d objects in %f sec.\n", i, total_objects, 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);
- }
- }
-
- BLI_freelistN(&state->statistics[i]);
- }
- if (state->has_updated_objects) {
- printf("Scene update in %f sec\n", 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 = BLI_task_scheduler_get();
- TaskPool *task_pool;
- ThreadedObjectUpdateState state;
- bool need_singlethread_pass;
-
- /* 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.scene = scene;
- state.scene_parent = scene_parent;
-
- /* Those are only needed when blender is run with --debug argument. */
- if (G.debug & G_DEBUG_DEPSGRAPH) {
- 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();
- }
-
-#ifdef MBALL_SINGLETHREAD_HACK
- state.has_mballs = false;
-#endif
-
- task_pool = BLI_task_pool_create(task_scheduler, &state);
- if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
- BLI_pool_set_num_threads(task_pool, 1);
- }
-
- 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) {
- 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(eval_ctx, scene, scene_parent);
- }
-}
-
-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;
+ const bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
+ Scene *scene = window->scene;
ScrArea *area;
+ RenderEngineType *type = RE_engines_find(scene->r.engine);
+ if ((type->draw_engine != NULL) || (type->render_to_view == NULL)) {
+ continue;
+ }
+ const bool use_legacy = (type->flag & RE_USE_LEGACY_PIPELINE) != 0;
for (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->drawtype == OB_RENDER || !use_legacy) {
return true;
}
}
@@ -1747,7 +1504,7 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene)
if (check_rendered_viewport_visible(bmain)) {
BMesh *bm = mesh->edit_btmesh->bm;
BM_mesh_bm_to_me(bm, mesh, (&(struct BMeshToMeshParams){0}));
- DAG_id_tag_update(&mesh->id, 0);
+ DEG_id_tag_update(&mesh->id, 0);
}
}
}
@@ -1756,24 +1513,13 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene)
void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *scene)
{
Scene *sce_iter;
-#ifdef WITH_LEGACY_DEPSGRAPH
- bool use_new_eval = !DEG_depsgraph_use_legacy();
-#endif
-
- /* 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);
+ DEG_scene_relations_update(bmain, sce_iter);
/* Uncomment this to check if graph was properly tagged for update. */
#if 0
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (use_new_eval)
-#endif
- {
- DAG_scene_relations_validate(bmain, sce_iter);
- }
+ DEG_scene_relations_validate(bmain, sce_iter);
#endif
}
@@ -1781,7 +1527,7 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
prepare_mesh_for_viewport_render(bmain, scene);
/* flush recalc flags to dependencies */
- DAG_ids_flush_tagged(bmain);
+ DEG_ids_flush_tagged(bmain, scene);
/* removed calls to quick_cache, see pointcache.c */
@@ -1796,17 +1542,9 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
*
* 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);
- /* TODO(sergey): This is to beocme a node in new depsgraph. */
- BKE_mask_update_scene(bmain, scene);
- }
+ DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph_legacy, scene);
+ /* TODO(sergey): This is to beocme a node in new depsgraph. */
+ BKE_mask_update_scene(bmain, scene);
/* update sound system animation (TODO, move to depsgraph) */
BKE_sound_update_scene(bmain, scene);
@@ -1820,110 +1558,35 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
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.
- */
-#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);
-
- FOREACH_NODETREE(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
- }
-#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);
+ DEG_ids_check_recalc(bmain, scene, false);
/* clear recalc flags */
- DAG_ids_clear_recalc(bmain);
+ DEG_ids_clear_recalc(bmain);
}
/* 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_update_for_newframe(EvaluationContext *eval_ctx, Main *bmain, Scene *sce)
{
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 graph? */
- (void) do_invisible_flush;
-#endif
- DAG_editors_update_pre(bmain, sce, true);
+ DEG_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
- */
- 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
- }
-#endif
+ DEG_scene_relations_update(bmain, sce_iter);
BKE_mask_evaluate_all_masks(bmain, ctime, true);
@@ -1934,67 +1597,26 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
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.
- */
-#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_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
+ DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph_legacy, ctime);
/* 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(eval_ctx, sce, sce);
- }
-#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);
/* Inform editors about possible changes. */
- DAG_ids_check_recalc(bmain, sce, true);
+ DEG_ids_check_recalc(bmain, sce, 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);
}
/* return default layer, also used to patch old files */
@@ -2035,6 +1657,13 @@ bool BKE_scene_remove_render_layer(Main *bmain, Scene *scene, SceneRenderLayer *
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);
@@ -2042,15 +1671,7 @@ bool BKE_scene_remove_render_layer(Main *bmain, Scene *scene, SceneRenderLayer *
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--;
- }
- }
+ BKE_nodetree_remove_layer_n(sce->nodetree, scene, act);
}
}
@@ -2097,7 +1718,7 @@ bool BKE_scene_remove_render_view(Scene *scene, SceneRenderView *srv)
int get_render_subsurf_level(const RenderData *r, int lvl, bool for_render)
{
- if (r->mode & R_SIMPLIFY) {
+ if (r->mode & R_SIMPLIFY) {
if (for_render)
return min_ii(r->simplify_subsurf_render, lvl);
else
@@ -2137,21 +1758,40 @@ float get_render_aosss_error(const RenderData *r, float error)
return error;
}
-/* helper function for the SETLOOPER macro */
+/**
+ * Helper function for the SETLOOPER macro
+ *
+ * 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, Base *base)
{
if (base && base->next) {
/* common case, step to the next */
return base->next;
}
- else if (base == NULL && (*sce_iter)->base.first) {
+ else if (base == NULL) {
/* first time looping, return the scenes first base */
- return (Base *)(*sce_iter)->base.first;
+
+ /* for the first loop we should get the layer from context */
+ SceneLayer *sl = BKE_scene_layer_context_active_PLACEHOLDER((*sce_iter));
+ /* TODO For first scene (non-background set), we should pass the render layer as argument.
+ * In some cases we want it to be the workspace one, in other the scene one. */
+ TODO_LAYER;
+
+ if (sl->object_bases.first) {
+ return (Base *)sl->object_bases.first;
+ }
+ /* no base on this scene layer */
+ goto next_set;
}
else {
+next_set:
/* reached the end, get the next base in the set */
while ((*sce_iter = (*sce_iter)->set)) {
- base = (Base *)(*sce_iter)->base.first;
+ SceneLayer *sl = BKE_scene_layer_from_scene_get((*sce_iter));
+ base = (Base *)sl->object_bases.first;
+
if (base) {
return base;
}
@@ -2196,23 +1836,60 @@ bool BKE_scene_uses_blender_game(const Scene *scene)
return STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME);
}
-void BKE_scene_base_flag_to_objects(struct Scene *scene)
+bool BKE_scene_uses_blender_eevee(const Scene *scene)
+{
+ return STREQ(scene->r.engine, RE_engine_id_BLENDER_EEVEE);
+}
+
+void BKE_scene_base_flag_to_objects(SceneLayer *sl)
{
- Base *base = scene->base.first;
+ Base *base = sl->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_base_flag_sync_from_base(BaseLegacy *base)
{
- Base *base = scene->base.first;
+ BKE_scene_object_base_flag_sync_from_base(base);
+}
- while (base) {
- base->flag = base->object->flag;
- base = base->next;
+void BKE_scene_base_flag_sync_from_object(BaseLegacy *base)
+{
+ BKE_scene_object_base_flag_sync_from_object(base);
+}
+
+void BKE_scene_object_base_flag_sync_from_base(Base *base)
+{
+ Object *ob = base->object;
+
+ /* keep the object only flags untouched */
+ int flag = ob->flag & OB_FROMGROUP;
+
+ ob->flag = base->flag;
+ ob->flag |= 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_SELECTABLED) != 0);
+ }
+ else {
+ base->flag &= ~BASE_SELECTED;
}
}
@@ -2573,3 +2250,9 @@ int BKE_scene_multiview_num_videos_get(const RenderData *rd)
return BKE_scene_multiview_num_views_get(rd);
}
}
+
+Depsgraph* BKE_scene_get_depsgraph(Scene *scene, SceneLayer *scene_layer)
+{
+ (void) scene_layer;
+ return scene->depsgraph_legacy;
+}
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 857bd5447c8..f3a93a0a42c 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -45,13 +45,16 @@
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
+#include "DNA_workspace_types.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BLI_rect.h"
+#include "BKE_icons.h"
#include "BKE_idprop.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
/* ************ Spacetype/regiontype handling ************** */
@@ -180,6 +183,7 @@ ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar)
BLI_listbase_clear(&newar->panels_category_active);
BLI_listbase_clear(&newar->ui_lists);
newar->swinid = 0;
+ newar->manipulator_map = NULL;
newar->regiontimer = NULL;
/* use optional regiondata callback */
@@ -288,6 +292,17 @@ void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID
}
}
+
+/**
+ * Avoid bad-level calls to #WM_manipulatormap_delete.
+ */
+static void (*region_free_manipulatormap_callback)(struct wmManipulatorMap *) = NULL;
+
+void BKE_region_callback_free_manipulatormap_set(void (*callback)(struct wmManipulatorMap *))
+{
+ region_free_manipulatormap_callback = callback;
+}
+
/* not region itself */
void BKE_area_region_free(SpaceType *st, ARegion *ar)
{
@@ -337,6 +352,8 @@ void BKE_area_region_free(SpaceType *st, ARegion *ar)
MEM_freeN(uilst->properties);
}
}
+
+ region_free_manipulatormap_callback(ar->manipulator_map);
BLI_freelistN(&ar->ui_lists);
BLI_freelistN(&ar->ui_previews);
BLI_freelistN(&ar->panels_category);
@@ -380,6 +397,8 @@ void BKE_screen_free(bScreen *sc)
BLI_freelistN(&sc->vertbase);
BLI_freelistN(&sc->edgebase);
BLI_freelistN(&sc->areabase);
+
+ BKE_previewimg_free(&sc->preview);
}
/* for depsgraph */
@@ -579,7 +598,7 @@ void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
}
}
-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;
@@ -588,55 +607,26 @@ 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)
+void BKE_screen_transform_orientation_remove(
+ const bScreen *screen, const WorkSpace *workspace, const TransformOrientation *orientation)
{
- 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--;
- }
-}
+ const int orientation_index = BKE_workspace_transform_orientation_get_index(workspace, orientation);
-void BKE_screen_view3d_main_twmode_remove(ListBase *screen_lb, Scene *scene, const int i)
-{
- bScreen *sc;
+ 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;
- 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);
- }
+ if (v3d->custom_orientation_index == orientation_index) {
+ /* could also use orientation_index-- */
+ v3d->twmode = V3D_MANIP_GLOBAL;
+ v3d->custom_orientation_index = -1;
}
}
}
@@ -683,3 +673,13 @@ void BKE_screen_gpu_fx_validate(GPUFXSettings *fx_settings)
GPU_fx_compositor_init_ssao_settings(fx_ssao);
}
}
+
+bool BKE_screen_is_fullscreen_area(const bScreen *screen)
+{
+ return ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL);
+}
+
+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 ce7c520438a..e435d87024e 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -684,7 +684,7 @@ static float invGammaCorrect(float c)
else if (i >= RE_GAMMA_TABLE_SIZE) res = powf(c, valid_inv_gamma);
else res = inv_gamma_range_table[i] +
((c - color_domain_table[i]) * inv_gamfactor_table[i]);
-
+
return res;
}
@@ -1074,29 +1074,31 @@ static void do_sub_effect(const SeqRenderData *context, Sequence *UNUSED(seq), f
static void do_drop_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect2i, unsigned char *rect1i, unsigned char *outi)
{
- int height, width, temp, fac, fac1, fac2;
+ int temp, fac, fac1, fac2;
unsigned char *rt1, *rt2, *out;
int field = 1;
- width = x;
- height = y;
+ const int width = x;
+ const int height = y;
+ const int xoff = min_ii(XOFF, width);
+ const int yoff = min_ii(YOFF, height);
fac1 = (int) (70.0f * facf0);
fac2 = (int) (70.0f * facf1);
- rt2 = (unsigned char *) (rect2i + YOFF * width);
- rt1 = (unsigned char *) rect1i;
- out = (unsigned char *) outi;
- for (y = 0; y < height - YOFF; y++) {
+ rt2 = rect2i + yoff * 4 * width;
+ rt1 = rect1i;
+ out = outi;
+ for (y = 0; y < height - yoff; y++) {
if (field) fac = fac1;
else fac = fac2;
field = !field;
- memcpy(out, rt1, sizeof(int) * XOFF);
- rt1 += XOFF * 4;
- out += XOFF * 4;
+ memcpy(out, rt1, sizeof(*out) * xoff * 4);
+ rt1 += xoff * 4;
+ out += xoff * 4;
- for (x = XOFF; x < width; x++) {
+ for (x = xoff; x < width; x++) {
temp = ((fac * rt2[3]) >> 8);
*(out++) = MAX2(0, *rt1 - temp); rt1++;
@@ -1105,37 +1107,38 @@ static void do_drop_effect_byte(float facf0, float facf1, int x, int y, unsigned
*(out++) = MAX2(0, *rt1 - temp); rt1++;
rt2 += 4;
}
- rt2 += XOFF * 4;
+ rt2 += xoff * 4;
}
- memcpy(out, rt1, sizeof(int) * YOFF * width);
+ memcpy(out, rt1, sizeof(*out) * yoff * 4 * width);
}
static void do_drop_effect_float(float facf0, float facf1, int x, int y, float *rect2i, float *rect1i, float *outi)
{
- int height, width;
float temp, fac, fac1, fac2;
float *rt1, *rt2, *out;
int field = 1;
- width = x;
- height = y;
+ const int width = x;
+ const int height = y;
+ const int xoff = min_ii(XOFF, width);
+ const int yoff = min_ii(YOFF, height);
fac1 = 70.0f * facf0;
fac2 = 70.0f * facf1;
- rt2 = (rect2i + YOFF * width);
+ rt2 = rect2i + yoff * 4 * width;
rt1 = rect1i;
out = outi;
- for (y = 0; y < height - YOFF; y++) {
+ for (y = 0; y < height - yoff; y++) {
if (field) fac = fac1;
else fac = fac2;
field = !field;
- memcpy(out, rt1, 4 * sizeof(float) * XOFF);
- rt1 += XOFF * 4;
- out += XOFF * 4;
+ memcpy(out, rt1, sizeof(*out) * xoff * 4);
+ rt1 += xoff * 4;
+ out += xoff * 4;
- for (x = XOFF; x < width; x++) {
+ for (x = xoff; x < width; x++) {
temp = fac * rt2[3];
*(out++) = MAX2(0.0f, *rt1 - temp); rt1++;
@@ -1144,9 +1147,9 @@ static void do_drop_effect_float(float facf0, float facf1, int x, int y, float *
*(out++) = MAX2(0.0f, *rt1 - temp); rt1++;
rt2 += 4;
}
- rt2 += XOFF * 4;
+ rt2 += xoff * 4;
}
- memcpy(out, rt1, 4 * sizeof(float) * YOFF * width);
+ memcpy(out, rt1, sizeof(*out) * yoff * 4 * width);
}
/*********************** Mul *************************/
diff --git a/source/blender/blenkernel/intern/seqmodifier.c b/source/blender/blenkernel/intern/seqmodifier.c
index 95c6b7736e1..e2f74dbab3c 100644
--- a/source/blender/blenkernel/intern/seqmodifier.c
+++ b/source/blender/blenkernel/intern/seqmodifier.c
@@ -34,8 +34,8 @@
#include "MEM_guardedalloc.h"
#include "BLI_listbase.h"
-#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
@@ -202,21 +202,22 @@ static void whiteBalance_apply_threaded(int width, int height, unsigned char *re
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
int pixel_index = (y * width + x) * 4;
- float result[4], mask[3] = {1.0f, 1.0f, 1.0f};
+ float rgba[4], result[4], mask[3] = {1.0f, 1.0f, 1.0f};
if (rect_float) {
- copy_v3_v3(result, rect_float + pixel_index);
+ copy_v3_v3(rgba, rect_float + pixel_index);
}
else {
- straight_uchar_to_premul_float(result, rect + pixel_index);
+ straight_uchar_to_premul_float(rgba, rect + pixel_index);
}
+ copy_v4_v4(result, rgba);
#if 0
mul_v3_v3(result, multiplier);
#else
/* similar to division without the clipping */
for (int i = 0; i < 3; i++) {
- result[i] = 1.0f - powf(1.0f - result[i], multiplier[i]);
+ result[i] = 1.0f - powf(1.0f - rgba[i], multiplier[i]);
}
#endif
@@ -227,9 +228,9 @@ static void whiteBalance_apply_threaded(int width, int height, unsigned char *re
rgb_uchar_to_float(mask, mask_rect + pixel_index);
}
- result[0] = result[0] * (1.0f - mask[0]) + result[0] * mask[0];
- result[1] = result[1] * (1.0f - mask[1]) + result[1] * mask[1];
- result[2] = result[2] * (1.0f - mask[2]) + result[2] * mask[2];
+ result[0] = rgba[0] * (1.0f - mask[0]) + result[0] * mask[0];
+ result[1] = rgba[1] * (1.0f - mask[1]) + result[1] * mask[1];
+ result[2] = rgba[2] * (1.0f - mask[2]) + result[2] * mask[2];
if (rect_float) {
copy_v3_v3(rect_float + pixel_index, result);
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index c240aa27343..6ddce874449 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,8 @@
#include "BKE_library.h"
#include "BKE_idprop.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "RE_pipeline.h"
@@ -320,7 +322,8 @@ void BKE_sequencer_free_clipboard(void)
/* Manage pointers in the clipboard.
* note that these pointers should _never_ be access in the sequencer,
* they are only for storage while in the clipboard
- * notice 'newid' is used for temp pointer storage here, validate on access.
+ * notice 'newid' is used for temp pointer storage here, validate on access (this is safe usage,
+ * since those datablocks are fully out of Main lists).
*/
#define ID_PT (*id_pt)
static void seqclipboard_ptr_free(ID **id_pt)
@@ -479,55 +482,74 @@ void BKE_sequencer_editing_free(Scene *scene)
static void sequencer_imbuf_assign_spaces(Scene *scene, ImBuf *ibuf)
{
- if (ibuf->rect_float) {
+ if (ibuf->rect != NULL) {
+ IMB_colormanagement_assign_rect_colorspace(ibuf, scene->sequencer_colorspace_settings.name);
+ }
+ if (ibuf->rect_float != NULL) {
IMB_colormanagement_assign_float_colorspace(ibuf, scene->sequencer_colorspace_settings.name);
}
}
void BKE_sequencer_imbuf_to_sequencer_space(Scene *scene, ImBuf *ibuf, bool make_float)
{
- const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR);
+ /* Early output check: if both buffers are NULL we have nothing to convert. */
+ if (ibuf->rect_float == NULL && ibuf->rect == NULL) {
+ return;
+ }
+ /* Get common conversion settings. */
const char *to_colorspace = scene->sequencer_colorspace_settings.name;
- const char *float_colorspace = IMB_colormanagement_get_float_colorspace(ibuf);
-
- if (!ibuf->rect_float) {
- if (ibuf->rect) {
- const char *byte_colorspace = IMB_colormanagement_get_rect_colorspace(ibuf);
- if (make_float || !STREQ(to_colorspace, byte_colorspace)) {
- /* If byte space is not in sequencer's working space, we deliver float color space,
- * this is to to prevent data loss.
- */
-
- /* when converting byte buffer to float in sequencer we need to make float
- * buffer be in sequencer's working space, which is currently only doable
- * from linear space.
- */
-
- /*
- * OCIO_TODO: would be nice to support direct single transform from byte to sequencer's
- */
-
- IMB_float_from_rect(ibuf);
- }
- else {
- return;
- }
+ /* Perform actual conversion logic. */
+ if (ibuf->rect_float == NULL) {
+ /* We are not requested to give float buffer and byte buffer is already
+ * in thee required colorspace. Can skip doing anything here.
+ */
+ const char *from_colorspace = IMB_colormanagement_get_rect_colorspace(ibuf);
+ if (!make_float && STREQ(from_colorspace, to_colorspace)) {
+ return;
+ }
+ if (false) {
+ /* The idea here is to provide as fast playback as possible and
+ * enforcing float buffer here (a) uses more cache memory (b) might
+ * make some other effects slower to apply.
+ *
+ * However, this might also have negative effect by adding weird
+ * artifacts which will then not happen in final render.
+ */
+ IMB_colormanagement_transform_byte_threaded(
+ (unsigned char *)ibuf->rect, ibuf->x, ibuf->y, ibuf->channels,
+ from_colorspace, to_colorspace);
}
else {
- return;
+ /* We perform conversion to a float buffer so we don't worry about
+ * precision loss.
+ */
+ imb_addrectfloatImBuf(ibuf);
+ IMB_colormanagement_transform_from_byte_threaded(
+ ibuf->rect_float, (unsigned char *)ibuf->rect,
+ ibuf->x, ibuf->y, ibuf->channels,
+ from_colorspace, to_colorspace);
+ /* We don't need byte buffer anymore. */
+ imb_freerectImBuf(ibuf);
}
}
-
- if (from_colorspace && from_colorspace[0] != '\0') {
- if (ibuf->rect)
+ else {
+ const char *from_colorspace = IMB_colormanagement_get_float_colorspace(ibuf);
+ /* Unknown input color space, can't perform conversion. */
+ if (from_colorspace == NULL || from_colorspace[0] == '\0') {
+ return;
+ }
+ /* We don't want both byte and float buffers around: they'll either run
+ * out of sync or conversion of byte buffer will loose precision in there.
+ */
+ if (ibuf->rect != NULL) {
imb_freerectImBuf(ibuf);
-
- if (!STREQ(float_colorspace, to_colorspace)) {
- IMB_colormanagement_transform_threaded(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels,
- from_colorspace, to_colorspace, true);
- sequencer_imbuf_assign_spaces(scene, ibuf);
}
+ IMB_colormanagement_transform_threaded(ibuf->rect_float,
+ ibuf->x, ibuf->y, ibuf->channels,
+ from_colorspace, to_colorspace,
+ true);
}
+ sequencer_imbuf_assign_spaces(scene, ibuf);
}
void BKE_sequencer_imbuf_from_sequencer_space(Scene *scene, ImBuf *ibuf)
@@ -1755,7 +1777,7 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c
if (proxy->anim == NULL) {
return NULL;
}
-
+
seq_open_anim_file(context->scene, seq, true);
sanim = seq->anims.first;
@@ -1763,7 +1785,7 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c
return IMB_anim_absolute(proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE);
}
-
+
if (seq_proxy_get_fname(ed, seq, cfra, render_size, name, context->view_id) == 0) {
return NULL;
}
@@ -2062,7 +2084,7 @@ void BKE_sequencer_proxy_set(struct Sequence *seq, bool value)
}
}
else {
- seq->flag ^= SEQ_USE_PROXY;
+ seq->flag &= ~SEQ_USE_PROXY;
}
}
@@ -3281,10 +3303,10 @@ 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);
+ BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene);
ibuf = sequencer_view3d_cb(
/* set for OpenGL render (NULL when scrubbing) */
- scene, camera, width, height, IB_rect,
+ scene, BKE_scene_layer_from_scene_get(scene), camera, width, height, IB_rect,
context->scene->r.seq_prev_type,
(context->scene->r.seq_flag & R_SEQ_SOLID_TEX) != 0,
use_gpencil, use_background, scene->r.alphamode,
@@ -3314,7 +3336,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
if (re == NULL)
re = RE_NewRender(scene->id.name);
- BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay);
+ BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene);
RE_BlenderFrame(re, context->bmain, scene, NULL, camera, scene->lay, frame, false);
/* restore previous state after it was toggled on & off by RE_BlenderFrame */
@@ -3374,7 +3396,7 @@ finally:
scene->r.subframe = orig_data.subframe;
if (is_frame_update) {
- BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay);
+ BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene);
}
#ifdef DURIAN_CAMERA_SWITCH
@@ -3447,7 +3469,13 @@ static ImBuf *do_render_strip_uncached(
state->scene_parents = &scene_parent;
/* end check */
- ibuf = do_render_strip_seqbase(context, state, seq, nr, use_preprocess);
+ /* Use the Scene Seq's scene for the context when rendering the scene's sequences
+ * (necessary for Multicam Selector among others).
+ */
+ SeqRenderData local_context = *context;
+ local_context.scene = seq->scene;
+
+ ibuf = do_render_strip_seqbase(&local_context, state, seq, nr, use_preprocess);
/* step back in the list */
state->scene_parents = state->scene_parents->next;
@@ -4164,9 +4192,10 @@ static bool update_changed_seq_recurs(Scene *scene, Sequence *seq, Sequence *cha
if (free_imbuf) {
if (ibuf_change) {
- if (seq->type == SEQ_TYPE_MOVIE)
+ if (seq->type == SEQ_TYPE_MOVIE) {
BKE_sequence_free_anim(seq);
- if (seq->type == SEQ_TYPE_SPEED) {
+ }
+ else if (seq->type == SEQ_TYPE_SPEED) {
BKE_sequence_effect_speed_rebuild_map(scene, seq, true);
}
}
@@ -5156,6 +5185,7 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
sound = BKE_sound_new_file(bmain, seq_load->path); /* handles relative paths */
if (sound->playback_handle == NULL) {
+ BKE_libblock_free(bmain, sound);
#if 0
if (op)
BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index 43569f9ded2..667f8d1e8c7 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -126,7 +126,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 DerivedMesh *smokeModifier_do(SmokeModifierData *UNUSED(smd), Scene *UNUSED(scene), SceneLayer *UNUSED(sl), Object *UNUSED(ob), DerivedMesh *UNUSED(dm)) { 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 */
@@ -360,6 +360,10 @@ static void smokeModifier_freeDomain(SmokeModifierData *smd)
BKE_ptcache_free_list(&(smd->domain->ptcaches[0]));
smd->domain->point_cache[0] = NULL;
+ if (smd->domain->coba) {
+ MEM_freeN(smd->domain->coba);
+ }
+
MEM_freeN(smd->domain);
smd->domain = NULL;
}
@@ -536,6 +540,17 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
#endif
smd->domain->data_depth = 0;
smd->domain->cache_file_format = PTCACHE_FILE_PTCACHE;
+
+ smd->domain->display_thickness = 1.0f;
+ smd->domain->slice_method = MOD_SMOKE_SLICE_VIEW_ALIGNED;
+ smd->domain->axis_slice_method = AXIS_SLICE_FULL;
+ smd->domain->slice_per_voxel = 5.0f;
+ smd->domain->slice_depth = 0.5f;
+ smd->domain->slice_axis = 0;
+ smd->domain->vector_scale = 1.0f;
+
+ smd->domain->coba = NULL;
+ smd->domain->coba_field = FLUID_FIELD_DENSITY;
}
else if (smd->type & MOD_SMOKE_TYPE_FLOW)
{
@@ -629,6 +644,19 @@ void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData
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;
+
+ if (smd->domain->coba) {
+ tsmd->domain->coba = MEM_dupallocN(smd->domain->coba);
+ }
}
else if (tsmd->flow) {
tsmd->flow->psys = smd->flow->psys;
@@ -665,16 +693,16 @@ void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData
#ifdef WITH_SMOKE
// forward decleration
-static void smoke_calc_transparency(SmokeDomainSettings *sds, Scene *scene);
+static void smoke_calc_transparency(SmokeDomainSettings *sds, SceneLayer *sl);
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(SceneLayer *sl, 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_NEW; base_tmp; base_tmp = base_tmp->next) {
if (base_tmp->object->type == OB_LAMP) {
Lamp *la = base_tmp->object->data;
@@ -730,15 +758,14 @@ static void obstacles_from_derivedmesh_task_cb(void *userdata, const int z)
/* find the nearest point on the mesh */
if (BLI_bvhtree_find_nearest(data->tree->tree, ray_start, &nearest, data->tree->nearest_callback, data->tree) != -1) {
const MLoopTri *lt = &data->looptri[nearest.index];
- float weights[4];
+ float weights[3];
int v1, v2, v3;
/* calculate barycentric weights for nearest point */
v1 = data->mloop[lt->tri[0]].v;
v2 = data->mloop[lt->tri[1]].v;
v3 = data->mloop[lt->tri[2]].v;
- interp_weights_face_v3(
- weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, NULL, nearest.co);
+ interp_weights_tri_v3(weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, nearest.co);
// DG TODO
if (data->has_velocity)
@@ -1426,7 +1453,7 @@ static void sample_derivedmesh(
/* find the nearest point on the mesh */
if (BLI_bvhtree_find_nearest(treeData->tree, ray_start, &nearest, treeData->nearest_callback, treeData) != -1) {
- float weights[4];
+ float weights[3];
int v1, v2, v3, f_index = nearest.index;
float n1[3], n2[3], n3[3], hit_normal[3];
@@ -1443,7 +1470,7 @@ static void sample_derivedmesh(
v1 = mloop[mlooptri[f_index].tri[0]].v;
v2 = mloop[mlooptri[f_index].tri[1]].v;
v3 = mloop[mlooptri[f_index].tri[2]].v;
- interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, nearest.co);
+ interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, nearest.co);
if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && velocity_map) {
/* apply normal directional velocity */
@@ -2656,7 +2683,7 @@ static DerivedMesh *createDomainGeometry(SmokeDomainSettings *sds, Object *ob)
return result;
}
-static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm)
+static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, SceneLayer *sl, Object *ob, DerivedMesh *dm)
{
if ((smd->type & MOD_SMOKE_TYPE_FLOW))
{
@@ -2737,19 +2764,18 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *
return;
}
+ /* 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);
+
/* try to read from cache */
- if (BKE_ptcache_read(&pid, (float)framenr) == PTCACHE_READ_EXACT) {
+ if (BKE_ptcache_read(&pid, (float)framenr, can_simulate) == PTCACHE_READ_EXACT) {
BKE_ptcache_validate(cache, framenr);
smd->time = framenr;
return;
}
- /* only calculate something when we advanced a single frame */
- if (framenr != (int)smd->time + 1)
- return;
-
- /* don't simulate if viewing start frame, but scene frame is not real start frame */
- if (framenr != scene->r.cfra)
+ if (!can_simulate)
return;
#ifdef DEBUG_TIME
@@ -2784,7 +2810,7 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *
}
// create shadows before writing cache so they get stored
- smoke_calc_transparency(sds, scene);
+ smoke_calc_transparency(sds, sl);
if (sds->wt && sds->total_cells > 1) {
smoke_turbulence_step(sds->wt, sds->fluid);
@@ -2801,13 +2827,13 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *
}
}
-struct DerivedMesh *smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm)
+struct DerivedMesh *smokeModifier_do(SmokeModifierData *smd, Scene *scene, SceneLayer *sl, Object *ob, DerivedMesh *dm)
{
/* 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);
- smokeModifier_process(smd, scene, ob, dm);
+ smokeModifier_process(smd, scene, sl, ob, dm);
if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain)
BLI_rw_mutex_unlock(smd->domain->fluid_mutex);
@@ -2922,7 +2948,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, SceneLayer *sl)
{
float bv[6] = {0};
float light[3];
@@ -2930,7 +2956,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(sl, light)) return;
/* convert light pos to sim cell space */
mul_m4_v3(sds->imat, light);
@@ -3052,9 +3078,15 @@ float smoke_get_velocity_at(struct Object *ob, float position[3], float velocity
int smoke_get_data_flags(SmokeDomainSettings *sds)
{
int flags = 0;
- if (smoke_has_heat(sds->fluid)) flags |= SM_ACTIVE_HEAT;
- if (smoke_has_fuel(sds->fluid)) flags |= SM_ACTIVE_FIRE;
- if (smoke_has_colors(sds->fluid)) flags |= SM_ACTIVE_COLORS;
+
+ if (sds->fluid) {
+ if (smoke_has_heat(sds->fluid))
+ flags |= SM_ACTIVE_HEAT;
+ if (smoke_has_fuel(sds->fluid))
+ flags |= SM_ACTIVE_FIRE;
+ if (smoke_has_colors(sds->fluid))
+ flags |= SM_ACTIVE_COLORS;
+ }
return flags;
}
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index 901926dd8d4..0b8c11f6dc8 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -512,7 +512,7 @@ static void ccd_build_deflector_hash_single(GHash *hash, Object *ob)
/**
* \note group 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(SceneLayer *sl, Group *group, Object *vertexowner, GHash *hash)
{
Object *ob;
@@ -530,10 +530,10 @@ static void ccd_build_deflector_hash(Scene *scene, Group *group, Object *vertexo
}
}
else {
- for (Base *base = scene->base.first; base; base = base->next) {
+ for (Base *base = FIRSTBASE_NEW; 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 (base->object->type == OB_MESH) {
+ ob = base->object;
if ((vertexowner) && (ob == vertexowner)) {
/* if vertexowner is given we don't want to check collision with owner object */
continue;
@@ -558,7 +558,7 @@ static void ccd_update_deflector_hash_single(GHash *hash, Object *ob)
/**
* \note group 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(SceneLayer *sl, Group *group, Object *vertexowner, GHash *hash)
{
Object *ob;
@@ -576,10 +576,10 @@ static void ccd_update_deflector_hash(Scene *scene, Group *group, Object *vertex
}
}
else {
- for (Base *base = scene->base.first; base; base = base->next) {
+ for (Base *base = FIRSTBASE_NEW; 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 (base->object->type == OB_MESH) {
+ ob = base->object;
if (ob == vertexowner) {
/* if vertexowner is given we don't want to check collision with owner object */
continue;
@@ -977,7 +977,7 @@ static void free_softbody_intern(SoftBody *sb)
/**
* \note group overrides scene when not NULL.
*/
-static bool are_there_deflectors(Scene *scene, Group *group, unsigned int layer)
+static bool are_there_deflectors(SceneLayer *sl, Group *group)
{
if (group) {
for (GroupObject *go = group->gobject.first; go; go = go->next) {
@@ -986,8 +986,8 @@ static bool are_there_deflectors(Scene *scene, Group *group, unsigned int layer)
}
}
else {
- for (Base *base = scene->base.first; base; base= base->next) {
- if ( (base->lay & layer) && base->object->pd) {
+ for (Base *base = FIRSTBASE_NEW; base; base = base->next) {
+ if (base->object->pd) {
if (base->object->pd->deflect)
return 1;
}
@@ -997,9 +997,9 @@ static bool are_there_deflectors(Scene *scene, Group *group, unsigned int layer)
return 0;
}
-static int query_external_colliders(Scene *scene, Group *group, Object *me)
+static int query_external_colliders(SceneLayer *sl, Group *group)
{
- return(are_there_deflectors(scene, group, me->lay));
+ return(are_there_deflectors(sl, group));
}
/* --- dependency information functions*/
@@ -1856,19 +1856,21 @@ static void dfdx_spring(int ia, int ic, int op, float dir[3], float L, float len
float m, delta_ij;
int i, j;
if (L < len) {
- for (i=0;i<3;i++)
+ for (i=0;i<3;i++) {
for (j=0;j<3;j++) {
delta_ij = (i==j ? (1.0f): (0.0f));
m=factor*(dir[i]*dir[j] + (1-L/len)*(delta_ij - dir[i]*dir[j]));
EIG_linear_solver_matrix_add(ia+i, op+ic+j, m);
}
+ }
}
else {
- for (i=0;i<3;i++)
+ for (i=0;i<3;i++) {
for (j=0;j<3;j++) {
m=factor*dir[i]*dir[j];
EIG_linear_solver_matrix_add(ia+i, op+ic+j, m);
}
+ }
}
}
@@ -2231,11 +2233,11 @@ 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(Scene *scene, SceneLayer *sl, 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)
- */
+ /* 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;
@@ -2247,7 +2249,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(sl, 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));
@@ -2276,11 +2278,11 @@ static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, fl
}
-static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, float timenow)
+static void softbody_calc_forces(Scene *scene, SceneLayer *sl, 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(scene, sl, ob, forcetime, timenow);
return;
}
else {
@@ -2311,7 +2313,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(sl, 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));
@@ -3508,7 +3510,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(Scene *scene, SceneLayer *sl, Object *ob, SoftBody *sb, float dtime)
{
/* the simulator */
float forcetime;
@@ -3522,11 +3524,11 @@ static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime)
*/
if (dtime < 0 || dtime > 10.5f) return;
- ccd_update_deflector_hash(scene, sb->collision_group, ob, sb->scratch->colliderhash);
+ ccd_update_deflector_hash(sl, 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);
+ if (query_external_colliders(sl, sb->collision_group)) {
+ ccd_build_deflector_hash(sl, sb->collision_group, ob, sb->scratch->colliderhash);
}
sb->scratch->needstobuildcollider=0;
}
@@ -3556,12 +3558,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(scene, sl, 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(scene, sl, ob, forcetime, timedone/dtime);
softbody_apply_forces(ob, forcetime, 2, &err, mid_flags);
softbody_apply_goalsnap(ob);
@@ -3642,7 +3644,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(Scene *scene, SceneLayer *sl, Object *ob, float cfra, float (*vertexCos)[3], int numVerts)
{
SoftBody *sb= ob->soft;
PointCache *cache;
@@ -3650,7 +3652,6 @@ 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;
framenr= (int)cfra;
@@ -3719,9 +3720,12 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i
}
/* try to read from cache */
- cache_result = BKE_ptcache_read(&pid, (float)framenr+scene->r.subframe);
+ bool can_simulate = (framenr == sb->last_frame + 1) && !(cache->flag & PTCACHE_BAKED);
+
+ cache_result = BKE_ptcache_read(&pid, (float)framenr+scene->r.subframe, can_simulate);
- if (cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED) {
+ if (cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED ||
+ (!can_simulate && cache_result == PTCACHE_READ_OLD)) {
softbody_to_object(ob, vertexCos, numVerts, sb->local);
BKE_ptcache_validate(cache, framenr);
@@ -3742,7 +3746,7 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i
return;
}
- if (framenr!=sb->last_frame+1)
+ if (!can_simulate)
return;
/* if on second frame, write cache for first frame */
@@ -3755,7 +3759,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(scene, sl, 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 2f47966ec55..8469351c54a 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -147,12 +147,12 @@ void BKE_sound_free(bSound *sound)
BKE_sound_free_waveform(sound);
+#endif /* WITH_AUDASPACE */
if (sound->spinlock) {
BLI_spin_end(sound->spinlock);
MEM_freeN(sound->spinlock);
sound->spinlock = NULL;
- }
-#endif /* WITH_AUDASPACE */
+ }
}
void BKE_sound_make_local(Main *bmain, bSound *sound, const bool lib_local)
@@ -167,6 +167,10 @@ static const char *force_device = NULL;
#ifdef WITH_JACK
static void sound_sync_callback(void *data, int mode, float time)
{
+ // Ugly: Blender doesn't like it when the animation is played back during rendering
+ if (G.is_rendering)
+ return;
+
struct Main *bmain = (struct Main *)data;
struct Scene *scene;
@@ -251,7 +255,8 @@ void BKE_sound_init(struct Main *bmain)
void BKE_sound_init_main(struct Main *bmain)
{
#ifdef WITH_JACK
- AUD_setSynchronizerCallback(sound_sync_callback, bmain);
+ if (sound_device)
+ AUD_setSynchronizerCallback(sound_sync_callback, bmain);
#else
(void)bmain; /* unused */
#endif
@@ -449,6 +454,16 @@ void BKE_sound_destroy_scene(struct Scene *scene)
AUD_destroySet(scene->speaker_handles);
}
+void BKE_sound_reset_scene_specs(struct Scene *scene)
+{
+ AUD_Specs specs;
+
+ specs.channels = AUD_Device_getChannels(sound_device);
+ specs.rate = AUD_Device_getRate(sound_device);
+
+ AUD_Sequence_setSpecs(scene->sound_scene, specs);
+}
+
void BKE_sound_mute_scene(struct Scene *scene, int muted)
{
if (scene->sound_scene)
@@ -575,15 +590,10 @@ void BKE_sound_update_sequencer(struct Main *main, bSound *sound)
static void sound_start_play_scene(struct Scene *scene)
{
- AUD_Specs specs;
-
if (scene->playback_handle)
AUD_Handle_stop(scene->playback_handle);
- specs.channels = AUD_Device_getChannels(sound_device);
- specs.rate = AUD_Device_getRate(sound_device);
-
- AUD_Sequence_setSpecs(scene->sound_scene, specs);
+ BKE_sound_reset_scene_specs(scene);
if ((scene->playback_handle = AUD_Device_play(sound_device, scene->sound_scene, 1)))
AUD_Handle_setLoopCount(scene->playback_handle, -1);
@@ -692,6 +702,10 @@ void BKE_sound_seek_scene(struct Main *bmain, struct Scene *scene)
float BKE_sound_sync_scene(struct Scene *scene)
{
+ // Ugly: Blender doesn't like it when the animation is played back during rendering
+ if (G.is_rendering)
+ return NAN_FLT;
+
if (scene->playback_handle) {
if (scene->audio.flag & AUDIO_SYNC)
return AUD_getSynchronizerPosition(scene->playback_handle);
@@ -703,6 +717,10 @@ float BKE_sound_sync_scene(struct Scene *scene)
int BKE_sound_scene_playing(struct Scene *scene)
{
+ // Ugly: Blender doesn't like it when the animation is played back during rendering
+ if (G.is_rendering)
+ return -1;
+
if (scene->audio.flag & AUDIO_SYNC)
return AUD_isSynchronizerPlaying();
else
@@ -865,7 +883,7 @@ char **BKE_sound_get_device_names(void)
audio_device_names = AUD_getDeviceNames();
#else
static const char *names[] = {
- "Null", "SDL", "OpenAL", "Jack", NULL
+ "Null", "SDL", "OpenAL", "JACK", NULL
};
audio_device_names = (char **)names;
#endif
@@ -897,6 +915,7 @@ void BKE_sound_delete_cache(struct bSound *UNUSED(sound)) {}
void BKE_sound_load(struct Main *UNUSED(bmain), struct bSound *UNUSED(sound)) {}
void BKE_sound_create_scene(struct Scene *UNUSED(scene)) {}
void BKE_sound_destroy_scene(struct Scene *UNUSED(scene)) {}
+void BKE_sound_reset_scene_specs(struct Scene *UNUSED(scene)) {}
void BKE_sound_mute_scene(struct Scene *UNUSED(scene), int UNUSED(muted)) {}
void *BKE_sound_scene_add_scene_sound(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence),
int UNUSED(startframe), int UNUSED(endframe), int UNUSED(frameskip)) { return NULL; }
diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c
index ee6886e3fb2..d00e4b1a0d2 100644
--- a/source/blender/blenkernel/intern/speaker.c
+++ b/source/blender/blenkernel/intern/speaker.c
@@ -68,7 +68,7 @@ void *BKE_speaker_add(Main *bmain, const char *name)
return spk;
}
-Speaker *BKE_speaker_copy(Main *bmain, Speaker *spk)
+Speaker *BKE_speaker_copy(Main *bmain, const Speaker *spk)
{
Speaker *spkn;
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index e876bf43809..1f72744bdee 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -1901,7 +1901,8 @@ static void ccgDM_glNormalFast(float *a, float *b, float *c, float *d)
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 */
+ normalize_v3(no); /* we no longer rely on GL_NORMALIZE */
+
glNormal3fv(no);
}
@@ -2707,7 +2708,6 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
GPU_vertex_setup(dm);
GPU_normal_setup(dm);
GPU_triangle_setup(dm);
- glShadeModel(GL_SMOOTH);
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,
@@ -2811,8 +2811,6 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
}
#endif
- glShadeModel(GL_SMOOTH);
-
CCG_key_top_level(&key, ss);
ccgdm_pbvh_update(ccgdm);
@@ -2823,12 +2821,13 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
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); \
+#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);
@@ -2965,6 +2964,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
}
}
+ glShadeModel(GL_SMOOTH);
#undef PASSATTRIB
}
else {
@@ -3170,8 +3170,6 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
MEM_freeN(mat_orig_to_new);
MEM_freeN(matconv);
}
-
- glShadeModel(GL_SMOOTH);
}
static void ccgDM_drawFacesGLSL(DerivedMesh *dm, DMSetMaterial setMaterial)
@@ -3198,24 +3196,62 @@ static void ccgDM_drawMappedFacesMat(DerivedMesh *dm,
#ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) {
- int new_matnr;
- bool draw_smooth;
+ 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;
}
- /* TODO(sergey): Single matierial currently. */
- if (faceFlags) {
- draw_smooth = (faceFlags[0].flag & ME_SMOOTH);
- new_matnr = (faceFlags[0].mat_nr + 1);
+ 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;
}
- else {
- draw_smooth = true;
- new_matnr = 1;
+ 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(draw_smooth ? GL_SMOOTH : GL_FLAT);
- setMaterial(userData, new_matnr, &gattribs);
- ccgSubSurf_drawGLMesh(ss, true, -1, -1);
glShadeModel(GL_SMOOTH);
return;
}
@@ -3226,12 +3262,13 @@ static void ccgDM_drawMappedFacesMat(DerivedMesh *dm,
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); \
+#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);
@@ -3369,263 +3406,8 @@ static void ccgDM_drawMappedFacesMat(DerivedMesh *dm,
}
}
-#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;
-
glShadeModel(GL_SMOOTH);
- /* 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 = GET_INT_FROM_POINTER(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();
+#undef PASSATTRIB
}
static void ccgDM_drawMappedFaces(DerivedMesh *dm,
@@ -3681,8 +3463,8 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm,
if (do_draw) {
glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
ccgSubSurf_drawGLMesh(ss, true, -1, -1);
+ glShadeModel(GL_SMOOTH);
}
- glShadeModel(GL_SMOOTH);
return;
}
#endif
@@ -3744,10 +3526,6 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm,
GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE);
}
- /* no need to set shading mode to flat because
- * normals are already used to change shading */
- glShadeModel(GL_SMOOTH);
-
for (S = 0; S < numVerts; S++) {
CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
if (ln) {
@@ -4442,46 +4220,46 @@ static void ccgDM_recalcTessellation(DerivedMesh *UNUSED(dm))
/* Nothing to do: CCG handles creating its own tessfaces */
}
-static void ccgDM_recalcLoopTri(DerivedMesh *UNUSED(dm))
+static void ccgDM_recalcLoopTri(DerivedMesh *dm)
{
- /* Nothing to do: CCG tessellation is known,
- * allocate and fill in with ccgDM_getLoopTriArray */
+ BLI_rw_mutex_lock(&loops_cache_rwlock, THREAD_LOCK_WRITE);
+ MLoopTri *mlooptri;
+ const int tottri = dm->numPolyData * 2;
+ int i, poly_index;
+
+ DM_ensure_looptri_data(dm);
+ mlooptri = dm->looptris.array;
+
+ BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num);
+ BLI_assert(tottri == dm->looptris.num);
+
+ for (i = 0, poly_index = 0; i < tottri; i += 2, poly_index += 1) {
+ MLoopTri *lt;
+ lt = &mlooptri[i];
+ /* quad is (0, 3, 2, 1) */
+ lt->tri[0] = (poly_index * 4) + 0;
+ lt->tri[1] = (poly_index * 4) + 2;
+ lt->tri[2] = (poly_index * 4) + 3;
+ lt->poly = poly_index;
+
+ lt = &mlooptri[i + 1];
+ lt->tri[0] = (poly_index * 4) + 0;
+ lt->tri[1] = (poly_index * 4) + 1;
+ lt->tri[2] = (poly_index * 4) + 2;
+ lt->poly = poly_index;
+ }
+ BLI_rw_mutex_unlock(&loops_cache_rwlock);
}
static const MLoopTri *ccgDM_getLoopTriArray(DerivedMesh *dm)
{
- BLI_rw_mutex_lock(&loops_cache_rwlock, THREAD_LOCK_WRITE);
if (dm->looptris.array) {
BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num);
}
else {
- MLoopTri *mlooptri;
- const int tottri = dm->numPolyData * 2;
- int i, poly_index;
-
- DM_ensure_looptri_data(dm);
- mlooptri = dm->looptris.array;
-
- BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num);
- BLI_assert(tottri == dm->looptris.num);
-
- for (i = 0, poly_index = 0; i < tottri; i += 2, poly_index += 1) {
- MLoopTri *lt;
- lt = &mlooptri[i];
- /* quad is (0, 3, 2, 1) */
- lt->tri[0] = (poly_index * 4) + 0;
- lt->tri[1] = (poly_index * 4) + 2;
- lt->tri[2] = (poly_index * 4) + 3;
- lt->poly = poly_index;
-
- lt = &mlooptri[i + 1];
- lt->tri[0] = (poly_index * 4) + 0;
- lt->tri[1] = (poly_index * 4) + 1;
- lt->tri[2] = (poly_index * 4) + 2;
- lt->poly = poly_index;
- }
+ dm->recalcLoopTri(dm);
}
- BLI_rw_mutex_unlock(&loops_cache_rwlock);
+
return dm->looptris.array;
}
@@ -4551,13 +4329,10 @@ static void set_default_ccgdm_callbacks(CCGDerivedMesh *ccgdm)
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;
@@ -5012,8 +4787,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;
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 1636042f479..9444e605e6d 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -58,7 +58,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"
@@ -235,8 +234,9 @@ Text *BKE_text_add(Main *bmain, const char *name)
/* to a valid utf-8 sequences */
int txt_extended_ascii_as_utf8(char **str)
{
- int bad_char, added = 0, i = 0;
- int length = strlen(*str);
+ ptrdiff_t bad_char, i = 0;
+ const ptrdiff_t length = (ptrdiff_t)strlen(*str);
+ int added = 0;
while ((*str)[i]) {
if ((bad_char = BLI_utf8_invalid_byte(*str + i, length - i)) == -1)
@@ -248,7 +248,7 @@ int txt_extended_ascii_as_utf8(char **str)
if (added != 0) {
char *newstr = MEM_mallocN(length + added + 1, "text_line");
- int mi = 0;
+ ptrdiff_t mi = 0;
i = 0;
while ((*str)[i]) {
@@ -410,6 +410,7 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const
}
ta = BKE_libblock_alloc(bmain, ID_TXT, BLI_path_basename(filepath_abs));
+ ta->id.us = 0;
BLI_listbase_clear(&ta->lines);
ta->curl = ta->sell = NULL;
@@ -447,7 +448,7 @@ Text *BKE_text_load(Main *bmain, const char *file, const char *relpath)
return BKE_text_load_ex(bmain, file, relpath, false);
}
-Text *BKE_text_copy(Main *bmain, Text *ta)
+Text *BKE_text_copy(Main *bmain, const Text *ta)
{
Text *tan;
TextLine *line, *tmp;
@@ -1933,7 +1934,7 @@ void txt_do_undo(Text *text)
int op = text->undo_buf[text->undo_pos];
int prev_flags;
unsigned int linep;
- unsigned int uchar;
+ unsigned int uni_char;
unsigned int curln, selln;
unsigned short curc, selc;
unsigned short charp;
@@ -1969,14 +1970,14 @@ void txt_do_undo(Text *text)
case UNDO_BS_3:
case UNDO_BS_4:
charp = op - UNDO_BS_1 + 1;
- uchar = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp);
+ uni_char = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp);
/* get and restore the cursors */
txt_undo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc);
txt_move_to(text, curln, curc, 0);
txt_move_to(text, curln, curc, 1);
- txt_add_char(text, uchar);
+ txt_add_char(text, uni_char);
text->undo_pos--;
break;
@@ -1986,14 +1987,14 @@ void txt_do_undo(Text *text)
case UNDO_DEL_3:
case UNDO_DEL_4:
charp = op - UNDO_DEL_1 + 1;
- uchar = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp);
+ uni_char = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp);
/* get and restore the cursors */
txt_undo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc);
txt_move_to(text, curln, curc, 0);
txt_move_to(text, curln, curc, 1);
- txt_add_char(text, uchar);
+ txt_add_char(text, uni_char);
txt_move_left(text, 0);
@@ -2161,7 +2162,7 @@ void txt_do_redo(Text *text)
char *buf;
unsigned int linep;
unsigned short charp;
- unsigned int uchar;
+ unsigned int uni_uchar;
unsigned int curln, selln;
unsigned short curc, selc;
@@ -2188,9 +2189,9 @@ void txt_do_redo(Text *text)
txt_move_to(text, curln, curc, 1);
charp = op - UNDO_INSERT_1 + 1;
- uchar = txt_redo_read_unicode(text->undo_buf, &text->undo_pos, charp);
+ uni_uchar = txt_redo_read_unicode(text->undo_buf, &text->undo_pos, charp);
- txt_add_char(text, uchar);
+ txt_add_char(text, uni_uchar);
break;
case UNDO_BS_1:
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index 2d3ecad19ad..1e0659d3d67 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -549,11 +549,11 @@ int colorband_element_remove(struct ColorBand *coba, int index)
if (index < 0 || index >= coba->tot)
return 0;
+ coba->tot--;
for (a = index; a < coba->tot; a++) {
coba->data[a] = coba->data[a + 1];
}
if (coba->cur) coba->cur--;
- coba->tot--;
return 1;
}
@@ -846,7 +846,7 @@ MTex *BKE_texture_mtex_add_id(ID *id, int slot)
/* ------------------------------------------------------------------------- */
-Tex *BKE_texture_copy(Main *bmain, Tex *tex)
+Tex *BKE_texture_copy(Main *bmain, const Tex *tex)
{
Tex *texn;
@@ -1263,7 +1263,7 @@ EnvMap *BKE_texture_envmap_add(void)
/* ------------------------------------------------------------------------- */
-EnvMap *BKE_texture_envmap_copy(EnvMap *env)
+EnvMap *BKE_texture_envmap_copy(const EnvMap *env)
{
EnvMap *envn;
int a;
@@ -1336,7 +1336,7 @@ PointDensity *BKE_texture_pointdensity_add(void)
return pd;
}
-PointDensity *BKE_texture_pointdensity_copy(PointDensity *pd)
+PointDensity *BKE_texture_pointdensity_copy(const PointDensity *pd)
{
PointDensity *pdn;
@@ -1430,7 +1430,7 @@ OceanTex *BKE_texture_ocean_add(void)
return ot;
}
-OceanTex *BKE_texture_ocean_copy(struct OceanTex *ot)
+OceanTex *BKE_texture_ocean_copy(const OceanTex *ot)
{
OceanTex *otn = MEM_dupallocN(ot);
@@ -1485,9 +1485,11 @@ bool BKE_texture_dependsOnTime(const struct Tex *texture)
/* ------------------------------------------------------------------------- */
-void BKE_texture_get_value(
+void BKE_texture_get_value_ex(
const Scene *scene, Tex *texture,
- float *tex_co, TexResult *texres, bool use_color_management)
+ float *tex_co, TexResult *texres,
+ struct ImagePool *pool,
+ bool use_color_management)
{
int result_type;
bool do_color_manage = false;
@@ -1497,7 +1499,7 @@ void BKE_texture_get_value(
}
/* no node textures for now */
- result_type = multitex_ext_safe(texture, tex_co, texres, NULL, do_color_manage, false);
+ result_type = multitex_ext_safe(texture, tex_co, texres, pool, do_color_manage, false);
/* if the texture gave an RGB value, we assume it didn't give a valid
* intensity, since this is in the context of modifiers don't use perceptual color conversion.
@@ -1510,3 +1512,40 @@ void BKE_texture_get_value(
copy_v3_fl(&texres->tr, texres->tin);
}
}
+
+void BKE_texture_get_value(
+ const Scene *scene, Tex *texture,
+ float *tex_co, TexResult *texres, bool use_color_management)
+{
+ BKE_texture_get_value_ex(scene, texture, tex_co, texres, NULL, use_color_management);
+}
+
+static void texture_nodes_fetch_images_for_pool(bNodeTree *ntree, struct ImagePool *pool)
+{
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_TEX_IMAGE && node->id != NULL) {
+ Image *image = (Image *)node->id;
+ BKE_image_pool_acquire_ibuf(image, NULL, pool);
+ }
+ else if (node->type == NODE_GROUP && node->id != NULL) {
+ /* TODO(sergey): Do we need to control recursion here? */
+ bNodeTree *nested_tree = (bNodeTree *)node->id;
+ texture_nodes_fetch_images_for_pool(nested_tree, pool);
+ }
+ }
+}
+
+/* Make sure all images used by texture are loaded into pool. */
+void BKE_texture_fetch_images_for_pool(Tex *texture, struct ImagePool *pool)
+{
+ if (texture->nodetree != NULL) {
+ texture_nodes_fetch_images_for_pool(texture->nodetree, pool);
+ }
+ else {
+ if (texture->type == TEX_IMAGE) {
+ if (texture->ima != NULL) {
+ BKE_image_pool_acquire_ibuf(texture->ima, NULL, pool);
+ }
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index a56fc0f9abe..9120d384a16 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -44,12 +44,13 @@
#include "DNA_scene_types.h"
#include "BLI_utildefines.h"
+#include "BLI_bitmap_draw_2d.h"
#include "BLI_ghash.h"
#include "BLI_math.h"
#include "BLI_math_base.h"
#include "BLI_listbase.h"
-#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_threads.h"
#include "BLT_translation.h"
@@ -189,7 +190,7 @@ void BKE_tracking_free(MovieTracking *tracking)
}
/* Copy the whole list of tracks. */
-static void tracking_tracks_copy(ListBase *tracks_dst, ListBase *tracks_src, GHash *tracks_mapping)
+static void tracking_tracks_copy(ListBase *tracks_dst, const ListBase *tracks_src, GHash *tracks_mapping)
{
MovieTrackingTrack *track_dst, *track_src;
@@ -209,7 +210,7 @@ static void tracking_tracks_copy(ListBase *tracks_dst, ListBase *tracks_src, GHa
/* copy the whole list of plane tracks (need whole MovieTracking structures due to embedded pointers to tracks).
* WARNING: implies tracking_[dst/src] and their tracks have already been copied. */
-static void tracking_plane_tracks_copy(ListBase *plane_tracks_dst, ListBase *plane_tracks_src, GHash *tracks_mapping)
+static void tracking_plane_tracks_copy(ListBase *plane_tracks_dst, const ListBase *plane_tracks_src, GHash *tracks_mapping)
{
MovieTrackingPlaneTrack *plane_track_dst, *plane_track_src;
@@ -231,7 +232,7 @@ static void tracking_plane_tracks_copy(ListBase *plane_tracks_dst, ListBase *pla
/* Copy reconstruction structure. */
static void tracking_reconstruction_copy(
- MovieTrackingReconstruction *reconstruction_dst, MovieTrackingReconstruction *reconstruction_src)
+ MovieTrackingReconstruction *reconstruction_dst, const MovieTrackingReconstruction *reconstruction_src)
{
*reconstruction_dst = *reconstruction_src;
if (reconstruction_src->cameras) {
@@ -241,18 +242,14 @@ static void tracking_reconstruction_copy(
/* Copy stabilization structure. */
static void tracking_stabilization_copy(
- MovieTrackingStabilization *stabilization_dst, MovieTrackingStabilization *stabilization_src,
- GHash *tracks_mapping)
+ MovieTrackingStabilization *stabilization_dst, const MovieTrackingStabilization *stabilization_src)
{
*stabilization_dst = *stabilization_src;
- if (stabilization_src->rot_track) {
- stabilization_dst->rot_track = BLI_ghash_lookup(tracks_mapping, stabilization_src->rot_track);
- }
}
/* Copy tracking object. */
static void tracking_object_copy(
- MovieTrackingObject *object_dst, MovieTrackingObject *object_src, GHash *tracks_mapping)
+ MovieTrackingObject *object_dst, const MovieTrackingObject *object_src, GHash *tracks_mapping)
{
*object_dst = *object_src;
tracking_tracks_copy(&object_dst->tracks, &object_src->tracks, tracks_mapping);
@@ -261,7 +258,7 @@ static void tracking_object_copy(
}
/* Copy list of tracking objects. */
-static void tracking_objects_copy(ListBase *objects_dst, ListBase *objects_src, GHash *tracks_mapping)
+static void tracking_objects_copy(ListBase *objects_dst, const ListBase *objects_src, GHash *tracks_mapping)
{
MovieTrackingObject *object_dst, *object_src;
@@ -275,7 +272,7 @@ static void tracking_objects_copy(ListBase *objects_dst, ListBase *objects_src,
}
/* Copy tracking structure content. */
-void BKE_tracking_copy(MovieTracking *tracking_dst, MovieTracking *tracking_src)
+void BKE_tracking_copy(MovieTracking *tracking_dst, const MovieTracking *tracking_src)
{
GHash *tracks_mapping = BLI_ghash_ptr_new(__func__);
@@ -284,7 +281,7 @@ void BKE_tracking_copy(MovieTracking *tracking_dst, MovieTracking *tracking_src)
tracking_tracks_copy(&tracking_dst->tracks, &tracking_src->tracks, tracks_mapping);
tracking_plane_tracks_copy(&tracking_dst->plane_tracks, &tracking_src->plane_tracks, tracks_mapping);
tracking_reconstruction_copy(&tracking_dst->reconstruction, &tracking_src->reconstruction);
- tracking_stabilization_copy(&tracking_dst->stabilization, &tracking_src->stabilization, tracks_mapping);
+ tracking_stabilization_copy(&tracking_dst->stabilization, &tracking_src->stabilization);
if (tracking_src->act_track) {
tracking_dst->act_track = BLI_ghash_lookup(tracks_mapping, tracking_src->act_track);
}
@@ -316,7 +313,7 @@ void BKE_tracking_copy(MovieTracking *tracking_dst, MovieTracking *tracking_src)
}
/* Initialize motion tracking settings to default values,
- * used when new movie clip datablock is creating.
+ * used when new movie clip datablock is created.
*/
void BKE_tracking_settings_init(MovieTracking *tracking)
{
@@ -334,10 +331,22 @@ void BKE_tracking_settings_init(MovieTracking *tracking)
tracking->settings.object_distance = 1;
tracking->stabilization.scaleinf = 1.0f;
+ tracking->stabilization.anchor_frame = 1;
+ zero_v2(tracking->stabilization.target_pos);
+ tracking->stabilization.target_rot = 0.0f;
+ tracking->stabilization.scale = 1.0f;
+
+ tracking->stabilization.act_track = 0;
+ tracking->stabilization.act_rot_track = 0;
+ tracking->stabilization.tot_track = 0;
+ tracking->stabilization.tot_rot_track = 0;
+
+ tracking->stabilization.scaleinf = 1.0f;
tracking->stabilization.locinf = 1.0f;
tracking->stabilization.rotinf = 1.0f;
tracking->stabilization.maxscale = 2.0f;
tracking->stabilization.filter = TRACKING_FILTER_BILINEAR;
+ tracking->stabilization.flag |= TRACKING_SHOW_STAB_TRACKS;
BKE_tracking_object_add(tracking, "Camera");
}
@@ -552,6 +561,7 @@ MovieTrackingTrack *BKE_tracking_track_add(MovieTracking *tracking, ListBase *tr
track->flag = settings->default_flag;
track->algorithm_flag = settings->default_algorithm_flag;
track->weight = settings->default_weight;
+ track->weight_stab = settings->default_weight;
memset(&marker, 0, sizeof(marker));
marker.pos[0] = x;
@@ -590,6 +600,12 @@ MovieTrackingTrack *BKE_tracking_track_duplicate(MovieTrackingTrack *track)
new_track->markers = MEM_dupallocN(new_track->markers);
+ /* Orevent duplicate from being used for 2D stabilization.
+ * If necessary, it shall be added explicitly.
+ */
+ new_track->flag &= ~TRACK_USE_2D_STAB;
+ new_track->flag &= ~TRACK_USE_2D_STAB_ROT;
+
return new_track;
}
@@ -958,8 +974,11 @@ static void track_mask_set_pixel_cb(int x, int x_end, int y, void *user_data)
}
static void track_mask_gpencil_layer_rasterize(int frame_width, int frame_height,
- MovieTrackingMarker *marker, bGPDlayer *layer,
- float *mask, int mask_width, int mask_height)
+ const float region_min[2],
+ bGPDlayer *layer,
+ float *mask,
+ int mask_width,
+ int mask_height)
{
bGPDframe *frame = layer->frames.first;
TrackMaskSetPixelData data;
@@ -978,13 +997,14 @@ static void track_mask_gpencil_layer_rasterize(int frame_width, int frame_height
point = mask_points = MEM_callocN(2 * stroke->totpoints * sizeof(int),
"track mask rasterization points");
for (int i = 0; i < stroke->totpoints; i++, point += 2) {
- point[0] = (stroke_points[i].x - marker->search_min[0]) * frame_width;
- point[1] = (stroke_points[i].y - marker->search_min[1]) * frame_height;
+ point[0] = stroke_points[i].x * frame_width - region_min[0];
+ point[1] = stroke_points[i].y * frame_height - region_min[1];
}
/* TODO: add an option to control whether AA is enabled or not */
- fill_poly_v2i_n(0, 0, mask_width, mask_height,
- (const int (*)[2])mask_points, stroke->totpoints,
- track_mask_set_pixel_cb, &data);
+ BLI_bitmap_draw_2d_poly_v2i_n(
+ 0, 0, mask_width, mask_height,
+ (const int (*)[2])mask_points, stroke->totpoints,
+ track_mask_set_pixel_cb, &data);
MEM_freeN(mask_points);
}
stroke = stroke->next;
@@ -993,26 +1013,42 @@ static void track_mask_gpencil_layer_rasterize(int frame_width, int frame_height
}
}
-float *BKE_tracking_track_get_mask(int frame_width, int frame_height,
- MovieTrackingTrack *track, MovieTrackingMarker *marker)
+/* Region is in pixel space, relative to marker's center. */
+float *tracking_track_get_mask_for_region(int frame_width, int frame_height,
+ const float region_min[2],
+ const float region_max[2],
+ MovieTrackingTrack *track)
{
float *mask = NULL;
bGPDlayer *layer = track_mask_gpencil_layer_get(track);
- int mask_width, mask_height;
-
- mask_width = (marker->search_max[0] - marker->search_min[0]) * frame_width;
- mask_height = (marker->search_max[1] - marker->search_min[1]) * frame_height;
-
- if (layer) {
+ if (layer != NULL) {
+ const int mask_width = region_max[0] - region_min[0];
+ const int mask_height = region_max[1] - region_min[1];
mask = MEM_callocN(mask_width * mask_height * sizeof(float), "track mask");
-
- track_mask_gpencil_layer_rasterize(frame_width, frame_height, marker, layer,
- mask, mask_width, mask_height);
+ track_mask_gpencil_layer_rasterize(frame_width, frame_height,
+ region_min,
+ layer,
+ mask,
+ mask_width, mask_height);
}
-
return mask;
}
+float *BKE_tracking_track_get_mask(int frame_width, int frame_height,
+ MovieTrackingTrack *track,
+ MovieTrackingMarker *marker)
+{
+ /* Convert normalized space marker's search area to pixel-space region. */
+ const float region_min[2] = {marker->search_min[0] * frame_width,
+ marker->search_min[1] * frame_height};
+ const float region_max[2] = {marker->search_max[0] * frame_width,
+ marker->search_max[1] * frame_height};
+ return tracking_track_get_mask_for_region(frame_width, frame_height,
+ region_min,
+ region_max,
+ track);
+}
+
float BKE_tracking_track_get_weight_for_marker(MovieClip *clip, MovieTrackingTrack *track, MovieTrackingMarker *marker)
{
FCurve *weight_fcurve;
diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c
index 3b56ea271d0..9475925cdda 100644
--- a/source/blender/blenkernel/intern/tracking_auto.c
+++ b/source/blender/blenkernel/intern/tracking_auto.c
@@ -36,8 +36,9 @@
#include "DNA_movieclip_types.h"
#include "DNA_object_types.h" /* SELECT */
-#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_threads.h"
#include "BLI_math.h"
#include "BKE_movieclip.h"
@@ -76,6 +77,9 @@ typedef struct AutoTrackContext {
int num_tracks; /* Number of tracks being tracked. */
AutoTrackOptions *options; /* Per-tracking track options. */
+ /* Array of all tracks, indexed by track_index. */
+ MovieTrackingTrack **tracks;
+
bool backwards;
bool sequence;
int first_frame;
@@ -306,8 +310,15 @@ AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip,
BLI_spin_init(&context->spin_lock);
+ int num_total_tracks = BLI_listbase_count(tracksbase);
+ context->tracks =
+ MEM_callocN(sizeof(MovieTrackingTrack*) * num_total_tracks,
+ "auto track pointers");
+
context->image_accessor =
- tracking_image_accessor_new(context->clips, 1, user->framenr);
+ tracking_image_accessor_new(context->clips, 1,
+ context->tracks, num_total_tracks,
+ user->framenr);
context->autotrack =
libmv_autoTrackNew(context->image_accessor->libmv_accessor);
@@ -361,6 +372,7 @@ AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip,
options->use_keyframe_match =
track->pattern_match == TRACK_MATCH_KEYFRAME;
}
+ context->tracks[track_index] = track;
++track_index;
}
@@ -565,6 +577,7 @@ void BKE_autotrack_context_free(AutoTrackContext *context)
libmv_autoTrackDestroy(context->autotrack);
tracking_image_accessor_destroy(context->image_accessor);
MEM_freeN(context->options);
+ MEM_freeN(context->tracks);
BLI_spin_end(&context->spin_lock);
MEM_freeN(context);
}
diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c
index eb224020977..b8dfb217c16 100644
--- a/source/blender/blenkernel/intern/tracking_stabilize.c
+++ b/source/blender/blenkernel/intern/tracking_stabilize.c
@@ -21,6 +21,7 @@
* Contributor(s): Blender Foundation,
* Sergey Sharybin
* Keir Mierle
+ * Ichthyostega
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -28,292 +29,1487 @@
/** \file blender/blenkernel/intern/tracking_stabilize.c
* \ingroup bke
*
- * This file contains implementation of 2D frame stabilization.
+ * This file contains implementation of 2D image stabilization.
*/
#include <limits.h>
#include "DNA_movieclip_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_anim_types.h"
+#include "RNA_access.h"
#include "BLI_utildefines.h"
+#include "BLI_sort_utils.h"
+#include "BLI_math_vector.h"
#include "BLI_math.h"
#include "BKE_tracking.h"
+#include "BKE_movieclip.h"
+#include "BKE_fcurve.h"
+#include "BLI_ghash.h"
+#include "MEM_guardedalloc.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
-/* Calculate median point of markers of tracks marked as used for
- * 2D stabilization.
- *
- * NOTE: frame number should be in clip space, not scene space
+
+/* == Parameterization constants == */
+
+/* When measuring the scale changes relative to the rotation pivot point, it
+ * might happen accidentally that a probe point (tracking point), which doesn't
+ * actually move on a circular path, gets very close to the pivot point, causing
+ * the measured scale contribution to go toward infinity. We damp this undesired
+ * effect by adding a bias (floor) to the measured distances, which will
+ * dominate very small distances and thus cause the corresponding track's
+ * contribution to diminish.
+ * Measurements happen in normalized (0...1) coordinates within a frame.
+ */
+static float SCALE_ERROR_LIMIT_BIAS = 0.01f;
+
+/* When to consider a track as completely faded out.
+ * This is used in conjunction with the "disabled" flag of the track
+ * to determine start positions, end positions and gaps
+ */
+static float EPSILON_WEIGHT = 0.005f;
+
+
+
+/* == private working data == */
+
+/* Per track baseline for stabilization, defined at reference frame.
+ * A track's reference frame is chosen as close as possible to the (global)
+ * anchor_frame. Baseline holds the constant part of each track's contribution
+ * to the observed movement; it is calculated at initialization pass, using the
+ * measurement value at reference frame plus the average contribution to fill
+ * the gap between global anchor_frame and the reference frame for this track.
+ * This struct with private working data is associated to the local call context
+ * via `StabContext::private_track_data`
*/
-static bool stabilization_median_point_get(MovieTracking *tracking, int framenr, float median[2])
+typedef struct TrackStabilizationBase {
+ float stabilization_offset_base[2];
+
+ /* measured relative to translated pivot */
+ float stabilization_rotation_base[2][2];
+
+ /* measured relative to translated pivot */
+ float stabilization_scale_base;
+
+ bool is_init_for_stabilization;
+ FCurve *track_weight_curve;
+} TrackStabilizationBase;
+
+/* Tracks are reordered for initialization, starting as close as possible to
+ * anchor_frame
+ */
+typedef struct TrackInitOrder {
+ int sort_value;
+ int reference_frame;
+ MovieTrackingTrack *data;
+} TrackInitOrder;
+
+/* Per frame private working data, for accessing possibly animated values. */
+typedef struct StabContext {
+ MovieClip *clip;
+ MovieTracking *tracking;
+ MovieTrackingStabilization *stab;
+ GHash *private_track_data;
+ FCurve *locinf;
+ FCurve *rotinf;
+ FCurve *scaleinf;
+ FCurve *target_pos[2];
+ FCurve *target_rot;
+ FCurve *target_scale;
+ bool use_animation;
+} StabContext;
+
+
+static TrackStabilizationBase *access_stabilization_baseline_data(
+ StabContext *ctx,
+ MovieTrackingTrack *track)
{
- bool ok = false;
- float min[2], max[2];
- MovieTrackingTrack *track;
+ return BLI_ghash_lookup(ctx->private_track_data, track);
+}
+
+static void attach_stabilization_baseline_data(
+ StabContext *ctx,
+ MovieTrackingTrack *track,
+ TrackStabilizationBase *private_data)
+{
+ BLI_ghash_insert(ctx->private_track_data, track, private_data);
+}
- INIT_MINMAX2(min, max);
+static void discard_stabilization_baseline_data(void *val)
+{
+ if (val != NULL) {
+ MEM_freeN(val);
+ }
+}
- track = tracking->tracks.first;
- while (track) {
- if (track->flag & TRACK_USE_2D_STAB) {
- MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
- minmax_v2v2_v2(min, max, marker->pos);
+/* == access animated values for given frame == */
+
+static FCurve *retrieve_stab_animation(MovieClip *clip,
+ const char *data_path,
+ int idx)
+{
+ return id_data_find_fcurve(&clip->id,
+ &clip->tracking.stabilization,
+ &RNA_MovieTrackingStabilization,
+ data_path,
+ idx,
+ NULL);
+}
+
+static FCurve *retrieve_track_weight_animation(MovieClip *clip,
+ MovieTrackingTrack *track)
+{
+ return id_data_find_fcurve(&clip->id,
+ track,
+ &RNA_MovieTrackingTrack,
+ "weight_stab",
+ 0,
+ NULL);
+}
+
+static float fetch_from_fcurve(FCurve *animationCurve,
+ int framenr,
+ StabContext *ctx,
+ float default_value)
+{
+ if (ctx && ctx->use_animation && animationCurve) {
+ int scene_framenr = BKE_movieclip_remap_clip_to_scene_frame(ctx->clip,
+ framenr);
+ return evaluate_fcurve(animationCurve, scene_framenr);
+ }
+ return default_value;
+}
+
- ok = true;
+static float get_animated_locinf(StabContext *ctx, int framenr)
+{
+ return fetch_from_fcurve(ctx->locinf, framenr, ctx, ctx->stab->locinf);
+}
+
+static float get_animated_rotinf(StabContext *ctx, int framenr)
+{
+ return fetch_from_fcurve(ctx->rotinf, framenr, ctx, ctx->stab->rotinf);
+}
+
+static float get_animated_scaleinf(StabContext *ctx, int framenr)
+{
+ return fetch_from_fcurve(ctx->scaleinf, framenr, ctx, ctx->stab->scaleinf);
+}
+
+static void get_animated_target_pos(StabContext *ctx,
+ int framenr,
+ float target_pos[2])
+{
+ target_pos[0] = fetch_from_fcurve(ctx->target_pos[0],
+ framenr,
+ ctx,
+ ctx->stab->target_pos[0]);
+ target_pos[1] = fetch_from_fcurve(ctx->target_pos[1],
+ framenr,
+ ctx,
+ ctx->stab->target_pos[1]);
+}
+
+static float get_animated_target_rot(StabContext *ctx, int framenr)
+{
+ return fetch_from_fcurve(ctx->target_rot,
+ framenr,
+ ctx,
+ ctx->stab->target_rot);
+}
+
+static float get_animated_target_scale(StabContext *ctx, int framenr)
+{
+ return fetch_from_fcurve(ctx->target_scale, framenr, ctx, ctx->stab->scale);
+}
+
+static float get_animated_weight(StabContext *ctx,
+ MovieTrackingTrack *track,
+ int framenr)
+{
+ TrackStabilizationBase *working_data =
+ access_stabilization_baseline_data(ctx, track);
+ if (working_data && working_data->track_weight_curve) {
+ int scene_framenr = BKE_movieclip_remap_clip_to_scene_frame(ctx->clip,
+ framenr);
+ return evaluate_fcurve(working_data->track_weight_curve, scene_framenr);
+ }
+ /* Use weight at global 'current frame' as fallback default. */
+ return track->weight_stab;
+}
+
+static void use_values_from_fcurves(StabContext *ctx, bool toggle)
+{
+ if (ctx != NULL) {
+ ctx->use_animation = toggle;
+ }
+}
+
+
+/* Prepare per call private working area.
+ * Used for access to possibly animated values: retrieve available F-curves.
+ */
+static StabContext *initialize_stabilization_working_context(MovieClip *clip)
+{
+ StabContext *ctx = MEM_callocN(sizeof(StabContext),
+ "2D stabilization animation runtime data");
+ ctx->clip = clip;
+ ctx->tracking = &clip->tracking;
+ ctx->stab = &clip->tracking.stabilization;
+ ctx->private_track_data = BLI_ghash_ptr_new(
+ "2D stabilization per track private working data");
+ ctx->locinf = retrieve_stab_animation(clip, "influence_location", 0);
+ ctx->rotinf = retrieve_stab_animation(clip, "influence_rotation", 0);
+ ctx->scaleinf = retrieve_stab_animation(clip, "influence_scale", 0);
+ ctx->target_pos[0] = retrieve_stab_animation(clip, "target_pos", 0);
+ ctx->target_pos[1] = retrieve_stab_animation(clip, "target_pos", 1);
+ ctx->target_rot = retrieve_stab_animation(clip, "target_rot", 0);
+ ctx->target_scale = retrieve_stab_animation(clip, "target_zoom", 0);
+ ctx->use_animation = true;
+ return ctx;
+}
+
+/* Discard all private working data attached to this call context.
+ * NOTE: We allocate the record for the per track baseline contribution
+ * locally for each call context (i.e. call to
+ * BKE_tracking_stabilization_data_get()
+ * Thus it is correct to discard all allocations found within the
+ * corresponding _local_ GHash
+ */
+static void discard_stabilization_working_context(StabContext *ctx)
+{
+ if (ctx != NULL) {
+ BLI_ghash_free(ctx->private_track_data,
+ NULL,
+ discard_stabilization_baseline_data);
+ MEM_freeN(ctx);
+ }
+}
+
+static bool is_init_for_stabilization(StabContext *ctx,
+ MovieTrackingTrack *track)
+{
+ TrackStabilizationBase *working_data =
+ access_stabilization_baseline_data(ctx, track);
+ return (working_data != NULL && working_data->is_init_for_stabilization);
+}
+
+static bool is_usable_for_stabilization(StabContext *ctx,
+ MovieTrackingTrack *track)
+{
+ return (track->flag & TRACK_USE_2D_STAB) &&
+ is_init_for_stabilization(ctx, track);
+}
+
+static bool is_effectively_disabled(StabContext *ctx,
+ MovieTrackingTrack *track,
+ MovieTrackingMarker *marker)
+{
+ return (marker->flag & MARKER_DISABLED) ||
+ (EPSILON_WEIGHT > get_animated_weight(ctx, track, marker->framenr));
+}
+
+
+static int search_closest_marker_index(MovieTrackingTrack *track,
+ int ref_frame)
+{
+ MovieTrackingMarker *markers = track->markers;
+ int end = track->markersnr;
+ int i = track->last_marker;
+
+ i = MAX2(0, i);
+ i = MIN2(i, end - 1);
+ for ( ; i < end - 1 && markers[i].framenr <= ref_frame; ++i);
+ for ( ; 0 < i && markers[i].framenr > ref_frame; --i);
+
+ track->last_marker = i;
+ return i;
+}
+
+static void retrieve_next_higher_usable_frame(StabContext *ctx,
+ MovieTrackingTrack *track,
+ int i,
+ int ref_frame,
+ int *next_higher)
+{
+ MovieTrackingMarker *markers = track->markers;
+ int end = track->markersnr;
+ BLI_assert(0 <= i && i < end);
+
+ while (i < end &&
+ (markers[i].framenr < ref_frame ||
+ is_effectively_disabled(ctx, track, &markers[i])))
+ {
+ ++i;
+ }
+ if (i < end && markers[i].framenr < *next_higher) {
+ BLI_assert(markers[i].framenr >= ref_frame);
+ *next_higher = markers[i].framenr;
+ }
+}
+
+static void retrieve_next_lower_usable_frame(StabContext *ctx,
+ MovieTrackingTrack *track,
+ int i,
+ int ref_frame,
+ int *next_lower)
+{
+ MovieTrackingMarker *markers = track->markers;
+ BLI_assert(0 <= i && i < track->markersnr);
+ while (i >= 0 &&
+ (markers[i].framenr > ref_frame ||
+ is_effectively_disabled(ctx, track, &markers[i])))
+ {
+ --i;
+ }
+ if (0 <= i && markers[i].framenr > *next_lower) {
+ BLI_assert(markers[i].framenr <= ref_frame);
+ *next_lower = markers[i].framenr;
+ }
+}
+
+/* Find closest frames with usable stabilization data.
+ * A frame counts as _usable_ when there is at least one track marked for
+ * translation stabilization, which has an enabled tracking marker at this very
+ * frame. We search both for the next lower and next higher position, to allow
+ * the caller to interpolate gaps and to extrapolate at the ends of the
+ * definition range.
+ *
+ * NOTE: Regarding performance note that the individual tracks will cache the
+ * last search position.
+ */
+static void find_next_working_frames(StabContext *ctx,
+ int framenr,
+ int *next_lower,
+ int *next_higher)
+{
+ for (MovieTrackingTrack *track = ctx->tracking->tracks.first;
+ track != NULL;
+ track = track->next)
+ {
+ if (is_usable_for_stabilization(ctx, track)) {
+ int startpoint = search_closest_marker_index(track, framenr);
+ retrieve_next_higher_usable_frame(ctx,
+ track,
+ startpoint,
+ framenr,
+ next_higher);
+ retrieve_next_lower_usable_frame(ctx,
+ track,
+ startpoint,
+ framenr,
+ next_lower);
}
+ }
+}
- track = track->next;
+
+/* Find active (enabled) marker closest to the reference frame. */
+static MovieTrackingMarker *get_closest_marker(StabContext *ctx,
+ MovieTrackingTrack *track,
+ int ref_frame)
+{
+ int next_lower = MINAFRAME;
+ int next_higher = MAXFRAME;
+ int i = search_closest_marker_index(track, ref_frame);
+ retrieve_next_higher_usable_frame(ctx, track, i, ref_frame, &next_higher);
+ retrieve_next_lower_usable_frame(ctx, track, i, ref_frame, &next_lower);
+
+ if ((next_higher - ref_frame) < (ref_frame - next_lower)) {
+ return BKE_tracking_marker_get_exact(track, next_higher);
}
+ else {
+ return BKE_tracking_marker_get_exact(track, next_lower);
+ }
+}
- median[0] = (max[0] + min[0]) / 2.0f;
- median[1] = (max[1] + min[1]) / 2.0f;
- return ok;
+/* Retrieve tracking data, if available and applicable for this frame.
+ * The returned weight value signals the validity; data recorded for this
+ * tracking marker on the exact requested frame is output with the full weight
+ * of this track, while gaps in the data sequence cause the weight to go to zero.
+ */
+static MovieTrackingMarker *get_tracking_data_point(
+ StabContext *ctx,
+ MovieTrackingTrack *track,
+ int framenr,
+ float *r_weight)
+{
+ MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, framenr);
+ if (marker != NULL && !(marker->flag & MARKER_DISABLED)) {
+ *r_weight = get_animated_weight(ctx, track, framenr);
+ return marker;
+ }
+ else {
+ /* No marker at this frame (=gap) or marker disabled. */
+ *r_weight = 0.0f;
+ return NULL;
+ }
}
-/* Calculate stabilization data (translation, scale and rotation) from
- * given median of first and current frame medians, tracking data and
- * frame number.
+
+/* Define the reference point for rotation/scale measurement and compensation.
+ * The stabilizator works by assuming the image was distorted by a affine linear
+ * transform, i.e. it was rotated and stretched around this reference point
+ * (pivot point) and then shifted laterally. Any scale and orientation changes
+ * will be picked up relative to this point. And later the image will be
+ * stabilized by rotating around this point. The result can only be as
+ * accurate as this pivot point actually matches the real rotation center
+ * of the actual movements. Thus any scheme to define a pivot point is
+ * always guesswork.
*
- * NOTE: frame number should be in clip space, not scene space
+ * As a simple default, we use the weighted average of the location markers
+ * of the current frame as pivot point. TODO It is planned to add further
+ * options, like e.g. anchoring the pivot point at the canvas. Moreover,
+ * it is planned to allow for a user controllable offset.
*/
-static void stabilization_calculate_data(MovieTracking *tracking, int framenr, int width, int height,
- const float firstmedian[2], const float median[2],
- float translation[2], float *scale, float *angle)
+static void setup_pivot(const float ref_pos[2], float r_pivot[2])
{
- MovieTrackingStabilization *stab = &tracking->stabilization;
+ zero_v2(r_pivot); /* TODO: add an animated offset position here. */
+ add_v2_v2(r_pivot, ref_pos);
+}
+
+
+/* Calculate the contribution of a single track at the time position (frame) of
+ * the given marker. Each track has a local reference frame, which is as close
+ * as possible to the global anchor_frame. Thus the translation contribution is
+ * comprised of the offset relative to the image position at that reference
+ * frame, plus a guess of the contribution for the time span between the
+ * anchor_frame and the local reference frame of this track. The constant part
+ * of this contribution is precomputed initially. At the anchor_frame, by
+ * definition the contribution of all tracks is zero, keeping the frame in place.
+ *
+ * track_ref is per track baseline contribution at reference frame; filled in at
+ * initialization
+ * marker is tracking data to use as contribution for current frame.
+ * result_offset is a total cumulated contribution of this track,
+ * relative to the stabilization anchor_frame,
+ * in normalized (0...1) coordinates.
+ */
+static void translation_contribution(TrackStabilizationBase *track_ref,
+ MovieTrackingMarker *marker,
+ float result_offset[2])
+{
+ add_v2_v2v2(result_offset,
+ track_ref->stabilization_offset_base,
+ marker->pos);
+}
- *scale = (stab->scale - 1.0f) * stab->scaleinf + 1.0f;
- *angle = 0.0f;
+/* Similar to the ::translation_contribution(), the rotation contribution is
+ * comprised of the contribution by this individual track, and the averaged
+ * contribution from anchor_frame to the ref point of this track.
+ * - Contribution is in terms of angles, -pi < angle < +pi, and all averaging
+ * happens in this domain.
+ * - Yet the actual measurement happens as vector between pivot and the current
+ * tracking point
+ * - Currently we use the center of frame as approximation for the rotation pivot
+ * point.
+ * - Moreover, the pivot point has to be compensated for the already determined
+ * shift offset, in order to get the pure rotation around the pivot.
+ * To turn this into a _contribution_, the likewise corrected angle at the
+ * reference frame has to be subtracted, to get only the pure angle difference
+ * this tracking point has captured.
+ * - To get from vectors to angles, we have to go through an arcus tangens,
+ * which involves the issue of the definition range: the resulting angles will
+ * flip by 360deg when the measured vector passes from the 2nd to the third
+ * quadrant, thus messing up the average calculation. Since _any_ tracking
+ * point might be used, these problems are quite common in practice.
+ * - Thus we perform the subtraction of the reference and the addition of the
+ * baseline contribution in polar coordinates as simple addition of angles;
+ * since these parts are fixed, we can bake them into a rotation matrix.
+ * With this approach, the border of the arcus tangens definition range will
+ * be reached only, when the _whole_ contribution approaches +- 180deg,
+ * meaning we've already tilted the frame upside down. This situation is way
+ * less common and can be tolerated.
+ * - As an additional feature, when activated, also changes in image scale
+ * relative to the rotation center can be picked up. To handle those values
+ * in the same framework, we average the scales as logarithms.
+ *
+ * aspect is a total aspect ratio of the undistorted image (includes fame and
+ * pixel aspect). The function returns a quality factor, which can be used
+ * to damp the contributions of points in close proximity to the pivot point,
+ * since such contributions might be dominated by rounding errors and thus
+ * poison the calculated average. When the quality factor goes towards zero,
+ * the weight of this contribution should be reduced accordingly.
+ */
+static float rotation_contribution(TrackStabilizationBase *track_ref,
+ MovieTrackingMarker *marker,
+ const float aspect,
+ const float pivot[2],
+ float *result_angle,
+ float *result_scale)
+{
+ float len, quality;
+ float pos[2];
+ sub_v2_v2v2(pos, marker->pos, pivot);
- translation[0] = (firstmedian[0] - median[0]) * width * (*scale);
- translation[1] = (firstmedian[1] - median[1]) * height * (*scale);
+ pos[0] *= aspect;
+ mul_m2v2(track_ref->stabilization_rotation_base, pos);
- mul_v2_fl(translation, stab->locinf);
+ *result_angle = atan2f(pos[1],pos[0]);
- if ((stab->flag & TRACKING_STABILIZE_ROTATION) && stab->rot_track && stab->rotinf) {
- MovieTrackingMarker *marker;
- float a[2], b[2];
- float x0 = (float)width / 2.0f, y0 = (float)height / 2.0f;
- float x = median[0] * width, y = median[1] * height;
+ len = len_v2(pos);
- marker = BKE_tracking_marker_get(stab->rot_track, 1);
- sub_v2_v2v2(a, marker->pos, firstmedian);
- a[0] *= width;
- a[1] *= height;
+ /* prevent points very close to the pivot point from poisoning the result */
+ quality = 1 - expf(-len*len / SCALE_ERROR_LIMIT_BIAS*SCALE_ERROR_LIMIT_BIAS);
+ len += SCALE_ERROR_LIMIT_BIAS;
- marker = BKE_tracking_marker_get(stab->rot_track, framenr);
- sub_v2_v2v2(b, marker->pos, median);
- b[0] *= width;
- b[1] *= height;
+ *result_scale = len * track_ref->stabilization_scale_base;
+ BLI_assert(0.0 < *result_scale);
- *angle = -atan2f(a[0] * b[1] - a[1] * b[0], a[0] * b[0] + a[1] * b[1]);
- *angle *= stab->rotinf;
+ return quality;
+}
- /* convert to rotation around image center */
- translation[0] -= (x0 + (x - x0) * cosf(*angle) - (y - y0) * sinf(*angle) - x) * (*scale);
- translation[1] -= (y0 + (x - x0) * sinf(*angle) + (y - y0) * cosf(*angle) - y) * (*scale);
- }
+
+/* Workaround to allow for rotation around an arbitrary pivot point.
+ * Currently, the public API functions do not support this flexibility.
+ * Rather, rotation will always be applied around a fixed origin.
+ * As a workaround, we shift the image after rotation to match the
+ * desired rotation centre. And since this offset needs to be applied
+ * after the rotation and scaling, we can collapse it with the
+ * translation compensation, which is also a lateral shift (offset).
+ * The offset to apply is intended_pivot - rotated_pivot
+ */
+static void compensate_rotation_center(const int size, float aspect,
+ const float angle,
+ const float scale,
+ const float pivot[2],
+ float result_translation[2])
+{
+ const float origin[2] = {0.5f*aspect*size, 0.5f*size};
+ float intended_pivot[2], rotated_pivot[2];
+ float rotation_mat[2][2];
+
+ copy_v2_v2(intended_pivot, pivot);
+ copy_v2_v2(rotated_pivot, pivot);
+ angle_to_mat2(rotation_mat, +angle);
+ sub_v2_v2(rotated_pivot, origin);
+ mul_m2v2(rotation_mat, rotated_pivot);
+ mul_v2_fl(rotated_pivot, scale);
+ add_v2_v2(rotated_pivot, origin);
+ add_v2_v2(result_translation, intended_pivot);
+ sub_v2_v2(result_translation, rotated_pivot);
}
-/* Calculate factor of a scale, which will eliminate black areas
- * appearing on the frame caused by frame translation.
+
+/* Weighted average of the per track cumulated contributions at given frame.
+ * Returns truth if all desired calculations could be done and all averages are
+ * available.
+ *
+ * NOTE: Even if the result is not `true`, the returned translation and angle
+ * are always sensible and as good as can be. Especially in the
+ * initialization phase we might not be able to get any average (yet) or
+ * get only a translation value. Since initialization visits tracks in a
+ * specific order, starting from anchor_frame, the result is logically
+ * correct non the less. But under normal operation conditions,
+ * a result of `false` should disable the stabilization function
*/
-static float stabilization_calculate_autoscale_factor(MovieTracking *tracking, int width, int height)
+static bool average_track_contributions(StabContext *ctx,
+ int framenr,
+ float aspect,
+ float r_translation[2],
+ float r_pivot[2],
+ float *r_angle,
+ float *r_scale_step)
{
- float firstmedian[2];
+ bool ok;
+ float weight_sum;
+ MovieTrackingTrack *track;
+ MovieTracking *tracking = ctx->tracking;
MovieTrackingStabilization *stab = &tracking->stabilization;
- float aspect = tracking->camera.pixel_aspect;
-
- /* Early output if stabilization data is already up-to-date. */
- if (stab->ok)
- return stab->scale;
-
- /* See comment in BKE_tracking_stabilization_data_get about first frame. */
- if (stabilization_median_point_get(tracking, 1, firstmedian)) {
- int sfra = INT_MAX, efra = INT_MIN, cfra;
- float scale = 1.0f;
- MovieTrackingTrack *track;
-
- stab->scale = 1.0f;
-
- /* Calculate frame range of tracks used for stabilization. */
- track = tracking->tracks.first;
- while (track) {
- if (track->flag & TRACK_USE_2D_STAB ||
- ((stab->flag & TRACKING_STABILIZE_ROTATION) && track == stab->rot_track))
- {
- sfra = min_ii(sfra, track->markers[0].framenr);
- efra = max_ii(efra, track->markers[track->markersnr - 1].framenr);
- }
+ float ref_pos[2];
+ BLI_assert(stab->flag & TRACKING_2D_STABILIZATION);
+
+ zero_v2(r_translation);
+ *r_scale_step = 0.0f; /* logarithm */
+ *r_angle = 0.0f;
- track = track->next;
+ zero_v2(ref_pos);
+
+ ok = false;
+ weight_sum = 0.0f;
+ for (track = tracking->tracks.first; track; track = track->next) {
+ if (!is_init_for_stabilization(ctx, track)) {
+ continue;
}
+ if (track->flag & TRACK_USE_2D_STAB) {
+ float weight = 0.0f;
+ MovieTrackingMarker *marker = get_tracking_data_point(ctx,
+ track,
+ framenr,
+ &weight);
+ if (marker) {
+ TrackStabilizationBase *stabilization_base =
+ access_stabilization_baseline_data(ctx, track);
+ BLI_assert(stabilization_base != NULL);
+ float offset[2];
+ weight_sum += weight;
+ translation_contribution(stabilization_base, marker, offset);
+ r_translation[0] += weight * offset[0];
+ r_translation[1] += weight * offset[1];
+ ref_pos[0] += weight * marker->pos[0];
+ ref_pos[1] += weight * marker->pos[1];
+ ok |= (weight_sum > EPSILON_WEIGHT);
+ }
+ }
+ }
+ if (!ok) {
+ return false;
+ }
+
+ ref_pos[0] /= weight_sum;
+ ref_pos[1] /= weight_sum;
+ r_translation[0] /= weight_sum;
+ r_translation[1] /= weight_sum;
+ setup_pivot(ref_pos, r_pivot);
- /* For every frame we calculate scale factor needed to eliminate black
- * area and choose largest scale factor as final one.
+ if (!(stab->flag & TRACKING_STABILIZE_ROTATION)) {
+ return ok;
+ }
+
+ ok = false;
+ weight_sum = 0.0f;
+ for (track = tracking->tracks.first; track; track = track->next) {
+ if (!is_init_for_stabilization(ctx, track)) {
+ continue;
+ }
+ if (track->flag & TRACK_USE_2D_STAB_ROT) {
+ float weight = 0.0f;
+ MovieTrackingMarker *marker = get_tracking_data_point(ctx,
+ track,
+ framenr,
+ &weight);
+ if (marker) {
+ TrackStabilizationBase *stabilization_base =
+ access_stabilization_baseline_data(ctx, track);
+ BLI_assert(stabilization_base != NULL);
+ float rotation, scale, quality;
+ quality = rotation_contribution(stabilization_base,
+ marker,
+ aspect,
+ r_pivot,
+ &rotation,
+ &scale);
+ weight *= quality;
+ weight_sum += weight;
+ *r_angle += rotation * weight;
+ if (stab->flag & TRACKING_STABILIZE_SCALE) {
+ *r_scale_step += logf(scale) * weight;
+ }
+ else {
+ *r_scale_step = 0;
+ }
+ ok |= (weight_sum > EPSILON_WEIGHT);
+ }
+ }
+ }
+ if (ok) {
+ *r_scale_step /= weight_sum;
+ *r_angle /= weight_sum;
+ }
+ else {
+ /* We reach this point because translation could be calculated,
+ * but rotation/scale found no data to work on.
*/
- for (cfra = sfra; cfra <= efra; cfra++) {
- float median[2];
- float translation[2], angle, tmp_scale;
- int i;
- float mat[4][4];
- float points[4][2] = {{0.0f, 0.0f}, {0.0f, height}, {width, height}, {width, 0.0f}};
- float si, co;
+ *r_scale_step = 0.0f;
+ *r_angle = 0.0f;
+ }
+ return true;
+}
- stabilization_median_point_get(tracking, cfra, median);
- stabilization_calculate_data(tracking, cfra, width, height, firstmedian, median, translation,
- &tmp_scale, &angle);
+/* Calculate weight center of location tracks for given frame.
+ * This function performs similar calculations as average_track_contributions(),
+ * but does not require the tracks to be initialized for stabilisation. Moreover,
+ * when there is no usable tracking data for the given frame number, data from
+ * a neighbouring frame is used. Thus this function can be used to calculate
+ * a starting point on initialization.
+ */
+static void average_marker_positions(StabContext *ctx, int framenr, float r_ref_pos[2])
+{
+ bool ok = false;
+ float weight_sum;
+ MovieTrackingTrack *track;
+ MovieTracking *tracking = ctx->tracking;
- BKE_tracking_stabilization_data_to_mat4(width, height, aspect, translation, 1.0f, angle, mat);
+ zero_v2(r_ref_pos);
+ weight_sum = 0.0f;
+ for (track = tracking->tracks.first; track; track = track->next) {
+ if (track->flag & TRACK_USE_2D_STAB) {
+ float weight = 0.0f;
+ MovieTrackingMarker *marker =
+ get_tracking_data_point(ctx, track, framenr, &weight);
+ if (marker) {
+ weight_sum += weight;
+ r_ref_pos[0] += weight * marker->pos[0];
+ r_ref_pos[1] += weight * marker->pos[1];
+ ok |= (weight_sum > EPSILON_WEIGHT);
+ }
+ }
+ }
+ if (ok) {
+ r_ref_pos[0] /= weight_sum;
+ r_ref_pos[1] /= weight_sum;
+ }
+ else {
+ /* No usable tracking data on any track on this frame.
+ * Use data from neighbouring frames to extrapolate...
+ */
+ int next_lower = MINAFRAME;
+ int next_higher = MAXFRAME;
+ use_values_from_fcurves(ctx, true);
+ for (track = tracking->tracks.first; track; track = track->next) {
+ /* Note: we deliberately do not care if this track
+ * is already initialized for stabilisation */
+ if (track->flag & TRACK_USE_2D_STAB) {
+ int startpoint = search_closest_marker_index(track, framenr);
+ retrieve_next_higher_usable_frame(ctx,
+ track,
+ startpoint,
+ framenr,
+ &next_higher);
+ retrieve_next_lower_usable_frame(ctx,
+ track,
+ startpoint,
+ framenr,
+ &next_lower);
+ }
+ }
+ if (next_lower >= MINFRAME) {
+ /* use next usable frame to the left.
+ * Also default to this frame when we're in a gap */
+ average_marker_positions(ctx, next_lower, r_ref_pos);
- si = sinf(angle);
- co = cosf(angle);
+ }
+ else if (next_higher < MAXFRAME) {
+ average_marker_positions(ctx, next_higher, r_ref_pos);
+ }
+ use_values_from_fcurves(ctx, false);
+ }
+}
- for (i = 0; i < 4; i++) {
- int j;
- float a[3] = {0.0f, 0.0f, 0.0f}, b[3] = {0.0f, 0.0f, 0.0f};
- copy_v3_v3(a, points[i]);
- copy_v3_v3(b, points[(i + 1) % 4]);
+/* Linear interpolation of data retrieved at two measurement points.
+ * This function is used to fill gaps in the middle of the covered area,
+ * at frames without any usable tracks for stabilization.
+ *
+ * framenr is a position to interpolate for.
+ * frame_a is a valid measurement point below framenr
+ * frame_b is a valid measurement point above framenr
+ * Returns truth if both measurements could actually be retrieved.
+ * Otherwise output parameters remain unaltered
+ */
+static bool interpolate_averaged_track_contributions(StabContext *ctx,
+ int framenr,
+ int frame_a,
+ int frame_b,
+ const float aspect,
+ float r_translation[2],
+ float r_pivot[2],
+ float *r_angle,
+ float *r_scale_step)
+{
+ float t, s;
+ float trans_a[2], trans_b[2];
+ float angle_a, angle_b;
+ float scale_a, scale_b;
+ float pivot_a[2], pivot_b[2];
+ bool success = false;
+
+ BLI_assert(frame_a <= frame_b);
+ BLI_assert(frame_a <= framenr);
+ BLI_assert(framenr <= frame_b);
+
+ t = ((float)framenr - frame_a) / (frame_b - frame_a);
+ s = 1.0f - t;
+
+ success = average_track_contributions(ctx, frame_a, aspect, trans_a, pivot_a, &angle_a, &scale_a);
+ if (!success) {
+ return false;
+ }
+ success = average_track_contributions(ctx, frame_b, aspect, trans_b, pivot_b, &angle_b, &scale_b);
+ if (!success) {
+ return false;
+ }
- mul_m4_v3(mat, a);
- mul_m4_v3(mat, b);
+ interp_v2_v2v2(r_translation, trans_a, trans_b, t);
+ interp_v2_v2v2(r_pivot, pivot_a, pivot_b, t);
+ *r_scale_step = s * scale_a + t * scale_b;
+ *r_angle = s * angle_a + t * angle_b;
+ return true;
+}
- for (j = 0; j < 4; j++) {
- float point[3] = {points[j][0], points[j][1], 0.0f};
- float v1[3], v2[3];
- sub_v3_v3v3(v1, b, a);
- sub_v3_v3v3(v2, point, a);
+/* Reorder tracks starting with those providing a tracking data frame
+ * closest to the global anchor_frame. Tracks with a gap at anchor_frame or
+ * starting farer away from anchor_frame altogether will be visited later.
+ * This allows to build up baseline contributions incrementally.
+ *
+ * order is an array for sorting the tracks. Must be of suitable size to hold
+ * all tracks.
+ * Returns number of actually usable tracks, can be less than the overall number
+ * of tracks.
+ *
+ * NOTE: After returning, the order array holds entries up to the number of
+ * usable tracks, appropriately sorted starting with the closest tracks.
+ * Initialization includes disabled tracks, since they might be enabled
+ * through automation later.
+ */
+static int establish_track_initialization_order(StabContext *ctx,
+ TrackInitOrder *order)
+{
+ size_t tracknr = 0;
+ MovieTrackingTrack *track;
+ MovieTracking *tracking = ctx->tracking;
+ int anchor_frame = tracking->stabilization.anchor_frame;
- if (cross_v2v2(v1, v2) >= 0.0f) {
- const float rotDx[4][2] = {{1.0f, 0.0f}, {0.0f, -1.0f}, {-1.0f, 0.0f}, {0.0f, 1.0f}};
- const float rotDy[4][2] = {{0.0f, 1.0f}, {1.0f, 0.0f}, {0.0f, -1.0f}, {-1.0f, 0.0f}};
+ for (track = tracking->tracks.first; track != NULL; track = track->next) {
+ MovieTrackingMarker *marker;
+ order[tracknr].data = track;
+ marker = get_closest_marker(ctx, track, anchor_frame);
+ if (marker != NULL &&
+ (track->flag & (TRACK_USE_2D_STAB | TRACK_USE_2D_STAB_ROT)))
+ {
+ order[tracknr].sort_value = abs(marker->framenr - anchor_frame);
+ order[tracknr].reference_frame = marker->framenr;
+ ++tracknr;
+ }
+ }
+ if (tracknr) {
+ qsort(order, tracknr, sizeof(TrackInitOrder), BLI_sortutil_cmp_int);
+ }
+ return tracknr;
+}
+
+
+/* Setup the constant part of this track's contribution to the determined frame
+ * movement. Tracks usually don't provide tracking data for every frame. Thus,
+ * for determining data at a given frame, we split up the contribution into a
+ * part covered by actual measurements on this track, and the initial gap
+ * between this track's reference frame and the global anchor_frame.
+ * The (missing) data for the gap can be substituted by the average offset
+ * observed by the other tracks covering the gap. This approximation doesn't
+ * introduce wrong data, but it records data with incorrect weight. A totally
+ * correct solution would require us to average the contribution per frame, and
+ * then integrate stepwise over all frames -- which of course would be way more
+ * expensive, especially for longer clips. To the contrary, our solution
+ * cumulates the total contribution per track and averages afterwards over all
+ * tracks; it can thus be calculated just based on the data of a single frame,
+ * plus the "baseline" for the reference frame, which is what we are computing
+ * here.
+ *
+ * Since we're averaging _contributions_, we have to calculate the _difference_
+ * of the measured position at current frame and the position at the reference
+ * frame. But the "reference" part of this difference is constant and can thus
+ * be packed together with the baseline contribution into a single precomputed
+ * vector per track.
+ *
+ * In case of the rotation contribution, the principle is the same, but we have
+ * to compensate for the already determined translation and measure the pure
+ * rotation, simply because this is how we model the offset: shift plus rotation
+ * around the shifted rotation center. To circumvent problems with the
+ * definition range of the arcus tangens function, we perform this baseline
+ * addition and reference angle subtraction in polar coordinates and bake this
+ * operation into a precomputed rotation matrix.
+ *
+ * track is a track to be initialized to initialize
+ * reference_frame is a local frame for this track, the closest pick to the
+ * global anchor_frame.
+ * aspect is a total aspect ratio of the undistorted image (includes fame and
+ * pixel aspect).
+ * target_pos is a possibly animated target position as set by the user for
+ * the reference_frame
+ * average_translation is a value observed by the _other_ tracks for the gap
+ * between reference_frame and anchor_frame. This
+ * average must not contain contributions of frames
+ * not yet initialized
+ * average_angle in a similar way, the rotation value observed by the
+ * _other_ tracks.
+ * average_scale_step is an image scale factor observed on average by the other
+ * tracks for this frame. This value is recorded and
+ * averaged as logarithm. The recorded scale changes
+ * are damped for very small contributions, to limit
+ * the effect of probe points approaching the pivot
+ * too closely.
+ *
+ * NOTE: when done, this track is marked as initialized
+ */
+static void initialize_track_for_stabilization(StabContext *ctx,
+ MovieTrackingTrack *track,
+ int reference_frame,
+ float aspect,
+ const float average_translation[2],
+ const float pivot[2],
+ const float average_angle,
+ const float average_scale_step)
+{
+ float pos[2], angle, len;
+ TrackStabilizationBase *local_data =
+ access_stabilization_baseline_data(ctx, track);
+ MovieTrackingMarker *marker =
+ BKE_tracking_marker_get_exact(track, reference_frame);
+ /* Logic for initialization order ensures there *is* a marker on that
+ * very frame.
+ */
+ BLI_assert(marker != NULL);
+ BLI_assert(local_data != NULL);
- float dx = translation[0] * rotDx[j][0] + translation[1] * rotDx[j][1],
- dy = translation[0] * rotDy[j][0] + translation[1] * rotDy[j][1];
+ /* Per track baseline value for translation. */
+ sub_v2_v2v2(local_data->stabilization_offset_base,
+ average_translation,
+ marker->pos);
- float w, h, E, F, G, H, I, J, K, S;
+ /* Per track baseline value for rotation. */
+ sub_v2_v2v2(pos, marker->pos, pivot);
- if (j % 2) {
- w = (float)height / 2.0f;
- h = (float)width / 2.0f;
- }
- else {
- w = (float)width / 2.0f;
- h = (float)height / 2.0f;
- }
+ pos[0] *= aspect;
+ angle = average_angle - atan2f(pos[1],pos[0]);
+ angle_to_mat2(local_data->stabilization_rotation_base, angle);
- E = -w * co + h * si;
- F = -h * co - w * si;
+ /* Per track baseline value for zoom. */
+ len = len_v2(pos) + SCALE_ERROR_LIMIT_BIAS;
+ local_data->stabilization_scale_base = expf(average_scale_step) / len;
- if ((i % 2) == (j % 2)) {
- G = -w * co - h * si;
- H = h * co - w * si;
- }
- else {
- G = w * co + h * si;
- H = -h * co + w * si;
- }
+ local_data->is_init_for_stabilization = true;
+}
- I = F - H;
- J = G - E;
- K = G * F - E * H;
- S = (-w * I - h * J) / (dx * I + dy * J + K);
+static void initialize_all_tracks(StabContext *ctx, float aspect)
+{
+ size_t i, track_cnt = 0;
+ MovieClip *clip = ctx->clip;
+ MovieTracking *tracking = ctx->tracking;
+ MovieTrackingTrack *track;
+ TrackInitOrder *order;
- scale = max_ff(scale, S);
- }
- }
- }
+ /* Attempt to start initialization at anchor_frame.
+ * By definition, offset contribution is zero there.
+ */
+ int reference_frame = tracking->stabilization.anchor_frame;
+ float average_angle=0, average_scale_step=0;
+ float average_translation[2], average_pos[2], pivot[2];
+ zero_v2(average_translation);
+ zero_v2(pivot);
+
+ /* Initialize private working data. */
+ for (track = tracking->tracks.first; track != NULL; track = track->next) {
+ TrackStabilizationBase *local_data =
+ access_stabilization_baseline_data(ctx, track);
+ if (!local_data) {
+ local_data = MEM_callocN(sizeof(TrackStabilizationBase),
+ "2D stabilization per track baseline data");
+ attach_stabilization_baseline_data(ctx, track, local_data);
}
+ BLI_assert(local_data != NULL);
+ local_data->track_weight_curve = retrieve_track_weight_animation(clip,
+ track);
+ local_data->is_init_for_stabilization = false;
- stab->scale = scale;
+ ++track_cnt;
+ }
+ if (!track_cnt) {
+ return;
+ }
- if (stab->maxscale > 0.0f)
- stab->scale = min_ff(stab->scale, stab->maxscale);
+ order = MEM_mallocN(track_cnt * sizeof(TrackInitOrder),
+ "stabilization track order");
+ if (!order) {
+ return;
}
- else {
- stab->scale = 1.0f;
+
+ track_cnt = establish_track_initialization_order(ctx, order);
+ if (track_cnt == 0) {
+ goto cleanup;
}
- stab->ok = true;
+ /* starting point for pivot, before having initialized any track */
+ average_marker_positions(ctx, reference_frame, average_pos);
+ setup_pivot(average_pos, pivot);
+
+ for (i = 0; i < track_cnt; ++i) {
+ track = order[i].data;
+ if (reference_frame != order[i].reference_frame) {
+ reference_frame = order[i].reference_frame;
+ average_track_contributions(ctx,
+ reference_frame,
+ aspect,
+ average_translation,
+ pivot,
+ &average_angle,
+ &average_scale_step);
+ }
+ initialize_track_for_stabilization(ctx,
+ track,
+ reference_frame,
+ aspect,
+ average_translation,
+ pivot,
+ average_angle,
+ average_scale_step);
+ }
- return stab->scale;
+cleanup:
+ MEM_freeN(order);
}
-/* Get stabilization data (translation, scaling and angle) for a given frame.
+
+/* Retrieve the measurement of frame movement by averaging contributions of
+ * active tracks.
+ *
+ * translation is a measurement in normalized 0..1 coordinates.
+ * angle is a measurement in radians -pi..+pi counter clockwise relative to
+ * translation compensated frame center
+ * scale_step is a measurement of image scale changes, in logarithmic scale
+ * (zero means scale == 1)
+ * Returns calculation enabled and all data retrieved as expected for this frame.
*
- * NOTE: frame number should be in clip space, not scene space
+ * NOTE: when returning `false`, output parameters are reset to neutral values.
*/
-void BKE_tracking_stabilization_data_get(MovieTracking *tracking, int framenr, int width, int height,
- float translation[2], float *scale, float *angle)
+static bool stabilization_determine_offset_for_frame(StabContext *ctx,
+ int framenr,
+ float aspect,
+ float r_translation[2],
+ float r_pivot[2],
+ float *r_angle,
+ float *r_scale_step)
{
- float firstmedian[2], median[2];
- MovieTrackingStabilization *stab = &tracking->stabilization;
+ bool success = false;
/* Early output if stabilization is disabled. */
- if ((stab->flag & TRACKING_2D_STABILIZATION) == 0) {
- zero_v2(translation);
- *scale = 1.0f;
- *angle = 0.0f;
+ if ((ctx->stab->flag & TRACKING_2D_STABILIZATION) == 0) {
+ zero_v2(r_translation);
+ *r_scale_step = 0.0f;
+ *r_angle = 0.0f;
+ return false;
+ }
- return;
+ success = average_track_contributions(ctx,
+ framenr,
+ aspect,
+ r_translation,
+ r_pivot,
+ r_angle,
+ r_scale_step);
+ if (!success) {
+ /* Try to hold extrapolated settings beyond the definition range
+ * and to interpolate in gaps without any usable tracking data
+ * to prevent sudden jump to image zero position.
+ */
+ int next_lower = MINAFRAME;
+ int next_higher = MAXFRAME;
+ use_values_from_fcurves(ctx, true);
+ find_next_working_frames(ctx, framenr, &next_lower, &next_higher);
+ if (next_lower >= MINFRAME && next_higher < MAXFRAME) {
+ success = interpolate_averaged_track_contributions(ctx,
+ framenr,
+ next_lower,
+ next_higher,
+ aspect,
+ r_translation,
+ r_pivot,
+ r_angle,
+ r_scale_step);
+ }
+ else if (next_higher < MAXFRAME) {
+ /* Before start of stabilized range: extrapolate start point
+ * settings.
+ */
+ success = average_track_contributions(ctx,
+ next_higher,
+ aspect,
+ r_translation,
+ r_pivot,
+ r_angle,
+ r_scale_step);
+ }
+ else if (next_lower >= MINFRAME) {
+ /* After end of stabilized range: extrapolate end point settings. */
+ success = average_track_contributions(ctx,
+ next_lower,
+ aspect,
+ r_translation,
+ r_pivot,
+ r_angle,
+ r_scale_step);
+ }
+ use_values_from_fcurves(ctx, false);
}
+ return success;
+}
- /* Even if tracks does not start at frame 1, their position will
- * be estimated at this frame, which will give reasonable result
- * in most of cases.
- *
- * However, it's still better to replace this with real first
- * frame number at which tracks are appearing.
+/* Calculate stabilization data (translation, scale and rotation) from given raw
+ * measurements. Result is in absolute image dimensions (expanded image, square
+ * pixels), includes automatic or manual scaling and compensates for a target
+ * frame position, if given.
+ *
+ * size is a size of the expanded image, the width in pixels is size * aspect.
+ * aspect is a ratio (width / height) of the effective canvas (square pixels).
+ * do_compensate denotes whether to actually output values necessary to
+ * _compensate_ the determined frame movement.
+ * Otherwise, the effective target movement is returned.
+ */
+static void stabilization_calculate_data(StabContext *ctx,
+ int framenr,
+ int size,
+ float aspect,
+ bool do_compensate,
+ float scale_step,
+ float r_translation[2],
+ float r_pivot[2],
+ float *r_scale,
+ float *r_angle)
+{
+ float target_pos[2], target_scale;
+ float scaleinf = get_animated_scaleinf(ctx, framenr);
+
+ if (ctx->stab->flag & TRACKING_STABILIZE_SCALE) {
+ *r_scale = expf(scale_step * scaleinf); /* Averaged in log scale */
+ }
+ else {
+ *r_scale = 1.0f;
+ }
+
+ mul_v2_fl(r_translation, get_animated_locinf(ctx, framenr));
+ *r_angle *= get_animated_rotinf(ctx, framenr);
+
+ /* Compensate for a target frame position.
+ * This allows to follow tracking / panning shots in a semi manual fashion,
+ * when animating the settings for the target frame position.
+ */
+ get_animated_target_pos(ctx, framenr, target_pos);
+ sub_v2_v2(r_translation, target_pos);
+ *r_angle -= get_animated_target_rot(ctx, framenr);
+ target_scale = get_animated_target_scale(ctx, framenr);
+ if (target_scale != 0.0f) {
+ *r_scale /= target_scale;
+ /* target_scale is an expected/intended reference zoom value */
+ }
+
+ /* Convert from relative to absolute coordinates, square pixels. */
+ r_translation[0] *= (float)size * aspect;
+ r_translation[1] *= (float)size;
+ r_pivot[0] *= (float)size * aspect;
+ r_pivot[1] *= (float)size;
+
+ /* Output measured data, or inverse of the measured values for
+ * compensation?
*/
- if (stabilization_median_point_get(tracking, 1, firstmedian)) {
- stabilization_median_point_get(tracking, framenr, median);
+ if (do_compensate) {
+ mul_v2_fl(r_translation, -1.0f);
+ *r_angle *= -1.0f;
+ if (*r_scale != 0.0f) {
+ *r_scale = 1.0f / *r_scale;
+ }
+ }
+}
+
+static void stabilization_data_to_mat4(float pixel_aspect,
+ const float pivot[2],
+ const float translation[2],
+ float scale,
+ float angle,
+ float r_mat[4][4])
+{
+ float translation_mat[4][4], rotation_mat[4][4], scale_mat[4][4],
+ pivot_mat[4][4], inv_pivot_mat[4][4],
+ aspect_mat[4][4], inv_aspect_mat[4][4];
+ float scale_vector[3] = {scale, scale, 1.0f};
- if ((stab->flag & TRACKING_AUTOSCALE) == 0)
- stab->scale = 1.0f;
+ unit_m4(translation_mat);
+ unit_m4(rotation_mat);
+ unit_m4(scale_mat);
+ unit_m4(aspect_mat);
+ unit_m4(pivot_mat);
+ unit_m4(inv_pivot_mat);
- if (!stab->ok) {
- if (stab->flag & TRACKING_AUTOSCALE)
- stabilization_calculate_autoscale_factor(tracking, width, height);
+ /* aspect ratio correction matrix */
+ aspect_mat[0][0] /= pixel_aspect;
+ invert_m4_m4(inv_aspect_mat, aspect_mat);
- stabilization_calculate_data(tracking, framenr, width, height, firstmedian, median,
- translation, scale, angle);
+ add_v2_v2(pivot_mat[3], pivot);
+ sub_v2_v2(inv_pivot_mat[3], pivot);
- stab->ok = true;
+ size_to_mat4(scale_mat, scale_vector); /* scale matrix */
+ add_v2_v2(translation_mat[3], translation); /* translation matrix */
+ rotate_m4(rotation_mat, 'Z', angle); /* rotation matrix */
+
+ /* Compose transformation matrix. */
+ mul_m4_series(r_mat, aspect_mat, translation_mat,
+ pivot_mat, scale_mat, rotation_mat, inv_pivot_mat,
+ inv_aspect_mat);
+}
+
+/* Calculate scale factor necessary to eliminate black image areas
+ * caused by the compensating movements of the stabilizator.
+ * This function visits every frame where stabilisation data is
+ * available and determines the factor for this frame. The overall
+ * largest factor found is returned as result.
+ *
+ * NOTE: all tracks need to be initialized before calling this function.
+ */
+static float calculate_autoscale_factor(StabContext *ctx,
+ int size,
+ float aspect)
+{
+ MovieTrackingStabilization *stab = ctx->stab;
+ float pixel_aspect = ctx->tracking->camera.pixel_aspect;
+ int height = size, width = aspect*size;
+
+ int sfra = INT_MAX, efra = INT_MIN, cfra;
+ float scale = 1.0f, scale_step = 0.0f;
+ MovieTrackingTrack *track;
+
+ /* Calculate maximal frame range of tracks where stabilization is active. */
+ for (track = ctx->tracking->tracks.first; track; track = track->next) {
+ if ((track->flag & TRACK_USE_2D_STAB) ||
+ ((stab->flag & TRACKING_STABILIZE_ROTATION) &&
+ (track->flag & TRACK_USE_2D_STAB_ROT)))
+ {
+ int first_frame = track->markers[0].framenr;
+ int last_frame = track->markers[track->markersnr - 1].framenr;
+ sfra = min_ii(sfra, first_frame);
+ efra = max_ii(efra, last_frame);
}
- else {
- stabilization_calculate_data(tracking, framenr, width, height, firstmedian, median,
- translation, scale, angle);
+ }
+
+ use_values_from_fcurves(ctx, true);
+ for (cfra = sfra; cfra <= efra; cfra++) {
+ float translation[2], pivot[2], angle, tmp_scale;
+ float mat[4][4];
+ const float points[4][2] = {{0.0f, 0.0f},
+ {0.0f, height},
+ {width, height},
+ {width, 0.0f}};
+ const bool do_compensate = true;
+ /* Calculate stabilization parameters for the current frame. */
+ stabilization_determine_offset_for_frame(ctx,
+ cfra,
+ aspect,
+ translation,
+ pivot,
+ &angle,
+ &scale_step);
+ stabilization_calculate_data(ctx,
+ cfra,
+ size,
+ aspect,
+ do_compensate,
+ scale_step,
+ translation,
+ pivot,
+ &tmp_scale,
+ &angle);
+ /* Compose transformation matrix. */
+ /* NOTE: Here we operate in NON-COMPENSATED coordinates, meaning we have
+ * to construct transformation matrix using proper pivot point.
+ * Compensation for that will happen later on.
+ */
+ stabilization_data_to_mat4(pixel_aspect,
+ pivot,
+ translation,
+ tmp_scale,
+ angle,
+ mat);
+ /* Investigate the transformed border lines for this frame;
+ * find out, where it cuts the original frame.
+ */
+ for (int edge_index = 0; edge_index < 4; edge_index++) {
+ /* Calculate coordinates of stabilized frame edge points.
+ * Use matrix multiplication here so we operate in homogeneous
+ * coordinates.
+ */
+ float stable_edge_p1[3], stable_edge_p2[3];
+ copy_v2_v2(stable_edge_p1, points[edge_index]);
+ copy_v2_v2(stable_edge_p2, points[(edge_index + 1) % 4]);
+ stable_edge_p1[2] = stable_edge_p2[2] = 0.0f;
+ mul_m4_v3(mat, stable_edge_p1);
+ mul_m4_v3(mat, stable_edge_p2);
+ /* Now we iterate over all original frame corners (we call them
+ * 'point' here) to see if there's black area between stabilized
+ * frame edge and original point.
+ */
+ for (int point_index = 0; point_index < 4; point_index++) {
+ const float point[3] = {points[point_index][0],
+ points[point_index][1],
+ 0.0f};
+ /* Calculate vector which goes from first edge point to
+ * second one.
+ */
+ float stable_edge_vec[3];
+ sub_v3_v3v3(stable_edge_vec, stable_edge_p2, stable_edge_p1);
+ /* Calculate vector which connects current frame point to
+ * first edge point.
+ */
+ float point_to_edge_start_vec[3];
+ sub_v3_v3v3(point_to_edge_start_vec, point, stable_edge_p1);
+ /* Use this two vectors to check whether frame point is inside
+ * of the stabilized frame or not.
+ * If the point is inside, there is no black area happening
+ * and no scaling required for it.
+ */
+ if (cross_v2v2(stable_edge_vec, point_to_edge_start_vec) >= 0.0f) {
+ /* We are scaling around motion-compensated pivot point. */
+ float scale_pivot[2];
+ add_v2_v2v2(scale_pivot, pivot, translation);
+ /* Calculate line which goes via `point` and parallel to
+ * the stabilized frame edge. This line is coming via
+ * `point` and `point2` at the end.
+ */
+ float point2[2];
+ add_v2_v2v2(point2, point, stable_edge_vec);
+ /* Calculate actual distance between pivot point and
+ * the stabilized frame edge. Then calculate distance
+ * between pivot point and line which goes via actual
+ * corner and is parallel to the edge.
+ *
+ * Dividing one by another will give us required scale
+ * factor to get rid of black areas.
+ */
+ float real_dist = dist_to_line_v2(scale_pivot,
+ stable_edge_p1,
+ stable_edge_p2);
+ float required_dist = dist_to_line_v2(scale_pivot,
+ point,
+ point2);
+ const float S = required_dist / real_dist;
+ scale = max_ff(scale, S);
+ }
+ }
}
}
+ if (stab->maxscale > 0.0f) {
+ scale = min_ff(scale, stab->maxscale);
+ }
+ use_values_from_fcurves(ctx, false);
+
+ return scale;
+}
+
+
+/* Prepare working data and determine reference point for each track.
+ *
+ * NOTE: These calculations _could_ be cached and reused for all frames of the
+ * same clip. However, since proper initialization depends on (weight)
+ * animation and setup of tracks, ensuring consistency of cached init data
+ * turns out to be tricky, hard to maintain and generally not worth the
+ * effort. Thus we'll re-initialize on every frame.
+ */
+static StabContext *init_stabilizer(MovieClip *clip, int size, float aspect)
+{
+ StabContext *ctx = initialize_stabilization_working_context(clip);
+ BLI_assert(ctx != NULL);
+ initialize_all_tracks(ctx, aspect);
+ if (ctx->stab->flag & TRACKING_AUTOSCALE) {
+ ctx->stab->scale = 1.0;
+ ctx->stab->scale = calculate_autoscale_factor(ctx, size, aspect);
+ }
+ /* By default, just use values for the global current frame. */
+ use_values_from_fcurves(ctx, false);
+ return ctx;
+}
+
+
+/* === public interface functions === */
+
+/* Get stabilization data (translation, scaling and angle) for a given frame.
+ * Returned data describes how to compensate the detected movement, but with any
+ * chosen scale factor already applied and any target frame position already
+ * compensated. In case stabilization fails or is disabled, neutral values are
+ * returned.
+ *
+ * framenr is a frame number, relative to the clip (not relative to the scene
+ * timeline)
+ * width is an effective width of the canvas (square pixels), used to scale the
+ * determined translation
+ *
+ * Outputs:
+ * - translation of the lateral shift, absolute canvas coordinates
+ * (square pixels).
+ * - scale of the scaling to apply
+ * - angle of the rotation angle, relative to the frame center
+ */
+/* TODO(sergey): Use r_ prefix for output parameters here. */
+void BKE_tracking_stabilization_data_get(MovieClip *clip,
+ int framenr,
+ int width,
+ int height,
+ float translation[2],
+ float *scale,
+ float *angle)
+{
+ StabContext *ctx = NULL;
+ MovieTracking *tracking = &clip->tracking;
+ bool enabled = (tracking->stabilization.flag & TRACKING_2D_STABILIZATION);
+ /* Might become a parameter of a stabilization compositor node. */
+ bool do_compensate = true;
+ float scale_step = 0.0f;
+ float pixel_aspect = tracking->camera.pixel_aspect;
+ float aspect = (float)width * pixel_aspect / height;
+ int size = height;
+ float pivot[2];
+
+ if (enabled) {
+ ctx = init_stabilizer(clip, size, aspect);
+ }
+
+ if (enabled &&
+ stabilization_determine_offset_for_frame(ctx,
+ framenr,
+ aspect,
+ translation,
+ pivot,
+ angle,
+ &scale_step))
+ {
+ stabilization_calculate_data(ctx,
+ framenr,
+ size,
+ aspect,
+ do_compensate,
+ scale_step,
+ translation,
+ pivot,
+ scale,
+ angle);
+ compensate_rotation_center(size,
+ aspect,
+ *angle,
+ *scale,
+ pivot,
+ translation);
+ }
else {
zero_v2(translation);
*scale = 1.0f;
*angle = 0.0f;
}
+ discard_stabilization_working_context(ctx);
}
-/* Stabilize given image buffer using stabilization data for
- * a specified frame number.
+/* Stabilize given image buffer using stabilization data for a specified
+ * frame number.
*
- * NOTE: frame number should be in clip space, not scene space
+ * NOTE: frame number should be in clip space, not scene space.
*/
-ImBuf *BKE_tracking_stabilize_frame(MovieTracking *tracking, int framenr, ImBuf *ibuf,
- float translation[2], float *scale, float *angle)
+/* TODO(sergey): Use r_ prefix for output parameters here. */
+ImBuf *BKE_tracking_stabilize_frame(MovieClip *clip,
+ int framenr,
+ ImBuf *ibuf,
+ float translation[2],
+ float *scale,
+ float *angle)
{
float tloc[2], tscale, tangle;
+ MovieTracking *tracking = &clip->tracking;
MovieTrackingStabilization *stab = &tracking->stabilization;
ImBuf *tmpibuf;
int width = ibuf->x, height = ibuf->y;
- float aspect = tracking->camera.pixel_aspect;
+ float pixel_aspect = tracking->camera.pixel_aspect;
float mat[4][4];
int j, filter = tracking->stabilization.filter;
void (*interpolation)(struct ImBuf *, struct ImBuf *, float, float, int, int) = NULL;
@@ -349,8 +1545,12 @@ ImBuf *BKE_tracking_stabilize_frame(MovieTracking *tracking, int framenr, ImBuf
tmpibuf = IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->planes, ibuf_flags);
/* Calculate stabilization matrix. */
- BKE_tracking_stabilization_data_get(tracking, framenr, width, height, tloc, &tscale, &tangle);
- BKE_tracking_stabilization_data_to_mat4(ibuf->x, ibuf->y, aspect, tloc, tscale, tangle, mat);
+ BKE_tracking_stabilization_data_get(clip, framenr, width, height, tloc, &tscale, &tangle);
+ BKE_tracking_stabilization_data_to_mat4(ibuf->x, ibuf->y, pixel_aspect, tloc, tscale, tangle, mat);
+
+ /* The following code visits each nominal target grid position
+ * and picks interpolated data "backwards" from source.
+ * thus we need the inverse of the transformation to apply. */
invert_m4(mat);
if (filter == TRACKING_FILTER_NEAREST)
@@ -397,48 +1597,44 @@ ImBuf *BKE_tracking_stabilize_frame(MovieTracking *tracking, int framenr, ImBuf
return tmpibuf;
}
-/* Get 4x4 transformation matrix which corresponds to
- * stabilization data and used for easy coordinate
- * transformation.
+
+/* Build a 4x4 transformation matrix based on the given 2D stabilization data.
+ * mat is a 4x4 matrix in homogeneous coordinates, adapted to the
+ * final image buffer size and compensated for pixel aspect ratio,
+ * ready for direct OpenGL drawing.
*
- * NOTE: The reason it is 4x4 matrix is because it's
- * used for OpenGL drawing directly.
+ * TODO(sergey): The signature of this function should be changed. we actually
+ * don't need the dimensions of the image buffer. Instead we
+ * should consider to provide the pivot point of the rotation as a
+ * further stabilization data parameter.
*/
-void BKE_tracking_stabilization_data_to_mat4(int width, int height, float aspect,
- float translation[2], float scale, float angle,
- float mat[4][4])
+void BKE_tracking_stabilization_data_to_mat4(int buffer_width,
+ int buffer_height,
+ float pixel_aspect,
+ float translation[2],
+ float scale,
+ float angle,
+ float r_mat[4][4])
{
- float translation_mat[4][4], rotation_mat[4][4], scale_mat[4][4],
- center_mat[4][4], inv_center_mat[4][4],
- aspect_mat[4][4], inv_aspect_mat[4][4];
- float scale_vector[3] = {scale, scale, scale};
-
- unit_m4(translation_mat);
- unit_m4(rotation_mat);
- unit_m4(scale_mat);
- unit_m4(center_mat);
- unit_m4(aspect_mat);
-
- /* aspect ratio correction matrix */
- aspect_mat[0][0] = 1.0f / aspect;
- invert_m4_m4(inv_aspect_mat, aspect_mat);
-
- /* image center as rotation center
- *
- * Rotation matrix is constructing in a way rotation happens around image center,
- * and it's matter of calculating translation in a way, that applying translation
- * after rotation would make it so rotation happens around median point of tracks
- * used for translation stabilization.
+ /* Since we cannot receive the real pivot point coordinates (API limitation),
+ * we perform the rotation/scale around the center of frame.
+ * Then we correct by an additional shift, which was calculated in
+ * compensate_rotation_center() and "sneaked in" as additional offset
+ * in the translation parameter. This works, since translation needs to be
+ * applied after rotation/scale anyway. Thus effectively the image gets
+ * rotated around the desired pivot point
*/
- center_mat[3][0] = (float)width / 2.0f;
- center_mat[3][1] = (float)height / 2.0f;
- invert_m4_m4(inv_center_mat, center_mat);
-
- size_to_mat4(scale_mat, scale_vector); /* scale matrix */
- add_v2_v2(translation_mat[3], translation); /* translation matrix */
- rotate_m4(rotation_mat, 'Z', angle); /* rotation matrix */
-
- /* compose transformation matrix */
- mul_m4_series(mat, translation_mat, center_mat, aspect_mat, rotation_mat, inv_aspect_mat,
- scale_mat, inv_center_mat);
+ /* TODO(sergey) pivot shouldn't be calculated here, rather received
+ * as a parameter.
+ */
+ float pivot[2];
+ pivot[0] = 0.5f * pixel_aspect * buffer_width;
+ pivot[1] = 0.5f * buffer_height;
+ /* Compose transformation matrix. */
+ stabilization_data_to_mat4(pixel_aspect,
+ pivot,
+ translation,
+ scale,
+ angle,
+ r_mat);
}
diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c
index a90b1dee927..a95399562d5 100644
--- a/source/blender/blenkernel/intern/tracking_util.c
+++ b/source/blender/blenkernel/intern/tracking_util.c
@@ -42,8 +42,8 @@
#include "BLI_math.h"
#include "BLI_listbase.h"
#include "BLI_ghash.h"
-#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -625,17 +625,17 @@ static ImBuf *make_grayscale_ibuf_copy(ImBuf *ibuf)
*/
size = (size_t)grayscale->x * (size_t)grayscale->y * sizeof(float);
grayscale->channels = 1;
- if ((grayscale->rect_float = MEM_mapallocN(size, "tracking grayscale image"))) {
+ if ((grayscale->rect_float = MEM_mapallocN(size, "tracking grayscale image")) != NULL) {
grayscale->mall |= IB_rectfloat;
grayscale->flags |= IB_rectfloat;
- }
- for (i = 0; i < grayscale->x * grayscale->y; ++i) {
- const float *pixel = ibuf->rect_float + ibuf->channels * i;
+ for (i = 0; i < grayscale->x * grayscale->y; ++i) {
+ const float *pixel = ibuf->rect_float + ibuf->channels * i;
- grayscale->rect_float[i] = 0.2126f * pixel[0] +
- 0.7152f * pixel[1] +
- 0.0722f * pixel[2];
+ grayscale->rect_float[i] = 0.2126f * pixel[0] +
+ 0.7152f * pixel[1] +
+ 0.0722f * pixel[2];
+ }
}
return grayscale;
@@ -653,14 +653,14 @@ static void ibuf_to_float_image(const ImBuf *ibuf, libmv_FloatImage *float_image
static ImBuf *float_image_to_ibuf(libmv_FloatImage *float_image)
{
ImBuf *ibuf = IMB_allocImBuf(float_image->width, float_image->height, 32, 0);
- size_t size = (size_t)ibuf->x * (size_t)ibuf->y *
- float_image->channels * sizeof(float);
+ size_t size = (size_t)ibuf->x * (size_t)ibuf->y * float_image->channels * sizeof(float);
ibuf->channels = float_image->channels;
- if ((ibuf->rect_float = MEM_mapallocN(size, "tracking grayscale image"))) {
+ if ((ibuf->rect_float = MEM_mapallocN(size, "tracking grayscale image")) != NULL) {
ibuf->mall |= IB_rectfloat;
ibuf->flags |= IB_rectfloat;
+
+ memcpy(ibuf->rect_float, float_image->buffer, size);
}
- memcpy(ibuf->rect_float, float_image->buffer, size);
return ibuf;
}
@@ -875,8 +875,64 @@ static void accessor_release_image_callback(libmv_CacheKey cache_key)
IMB_freeImBuf(ibuf);
}
+static libmv_CacheKey accessor_get_mask_for_track_callback(
+ libmv_FrameAccessorUserData* user_data,
+ int clip_index,
+ int frame,
+ int track_index,
+ const libmv_Region *region,
+ float **r_destination,
+ int *r_width,
+ int *r_height)
+{
+ /* Perform sanity checks first. */
+ TrackingImageAccessor *accessor = (TrackingImageAccessor *) user_data;
+ BLI_assert(clip_index < accessor->num_clips);
+ BLI_assert(track_index < accessor->num_tracks);
+ MovieTrackingTrack *track = accessor->tracks[track_index];
+ /* Early output, track does not use mask. */
+ if ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_MASK) == 0) {
+ return NULL;
+ }
+ MovieClip *clip = accessor->clips[clip_index];
+ /* Construct fake user so we can access movie clip. */
+ MovieClipUser user;
+ int scene_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, frame);
+ BKE_movieclip_user_set_frame(&user, scene_frame);
+ user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
+ user.render_flag = 0;
+ /* Get frame width and height so we can convert stroke coordinates
+ * and other things from normalized to pixel space.
+ */
+ int frame_width, frame_height;
+ BKE_movieclip_get_size(clip, &user, &frame_width, &frame_height);
+ /* Actual mask sampling. */
+ MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, frame);
+ const float region_min[2] = {region->min[0] - marker->pos[0] * frame_width,
+ region->min[1] - marker->pos[1] * frame_height};
+ const float region_max[2] = {region->max[0] - marker->pos[0] * frame_width,
+ region->max[1] - marker->pos[1] * frame_height};
+ *r_destination = tracking_track_get_mask_for_region(frame_width, frame_height,
+ region_min,
+ region_max,
+ track);
+ *r_width = region->max[0] - region->min[0];
+ *r_height = region->max[1] - region->min[1];
+ return *r_destination;
+}
+
+static void accessor_release_mask_callback(libmv_CacheKey cache_key)
+{
+ if (cache_key != NULL) {
+ float *mask = (float *)cache_key;
+ MEM_freeN(mask);
+ }
+}
+
TrackingImageAccessor *tracking_image_accessor_new(MovieClip *clips[MAX_ACCESSOR_CLIP],
int num_clips,
+ MovieTrackingTrack **tracks,
+ int num_tracks,
int start_frame)
{
TrackingImageAccessor *accessor =
@@ -891,12 +947,16 @@ TrackingImageAccessor *tracking_image_accessor_new(MovieClip *clips[MAX_ACCESSOR
memcpy(accessor->clips, clips, num_clips * sizeof(MovieClip *));
accessor->num_clips = num_clips;
+ accessor->tracks = tracks;
+ accessor->num_tracks = num_tracks;
accessor->start_frame = start_frame;
accessor->libmv_accessor =
libmv_FrameAccessorNew((libmv_FrameAccessorUserData *) accessor,
accessor_get_image_callback,
- accessor_release_image_callback);
+ accessor_release_image_callback,
+ accessor_get_mask_for_track_callback,
+ accessor_release_mask_callback);
return accessor;
}
diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c
new file mode 100644
index 00000000000..82fface7d06
--- /dev/null
+++ b/source/blender/blenkernel/intern/workspace.c
@@ -0,0 +1,432 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "BLI_utildefines.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+#include "BLI_listbase.h"
+
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_screen.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 "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);
+ return new_workspace;
+}
+
+void BKE_workspace_free(WorkSpace *workspace)
+{
+ for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first, *relation_next;
+ relation;
+ relation = relation_next)
+ {
+ relation_next = relation->next;
+ workspace_relation_remove(&workspace->hook_layout_relations, relation);
+ }
+ BLI_freelistN(&workspace->layouts);
+ BLI_freelistN(&workspace->transform_orientations);
+}
+
+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(
+ WorkSpace *workspace,
+ bScreen *screen,
+ const char *name)
+{
+ WorkSpaceLayout *layout = MEM_callocN(sizeof(*layout), __func__);
+
+ BLI_assert(!workspaces_is_screen_used(G.main, screen));
+ layout->screen = screen;
+ 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)
+{
+ BKE_libblock_free(bmain, BKE_workspace_layout_screen_get(layout));
+ BLI_freelinkN(&workspace->layouts, layout);
+}
+
+/* -------------------------------------------------------------------- */
+/* General Utils */
+
+void BKE_workspace_transform_orientation_remove(
+ WorkSpace *workspace, TransformOrientation *orientation)
+{
+ for (WorkSpaceLayout *layout = workspace->layouts.first; layout; layout = layout->next) {
+ BKE_screen_transform_orientation_remove(BKE_workspace_layout_screen_get(layout), workspace, orientation);
+ }
+
+ BLI_freelinkN(&workspace->transform_orientations, orientation);
+}
+
+TransformOrientation *BKE_workspace_transform_orientation_find(
+ const WorkSpace *workspace, const int index)
+{
+ return BLI_findlink(&workspace->transform_orientations, index);
+}
+
+/**
+ * \return the index that \a orientation has within \a workspace's transform-orientation list or -1 if not found.
+ */
+int BKE_workspace_transform_orientation_get_index(
+ const WorkSpace *workspace, const TransformOrientation *orientation)
+{
+ return BLI_findindex(&workspace->transform_orientations, orientation);
+}
+
+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) {
+ BLI_LISTBASE_CIRCULAR_BACKWARD_BEGIN(&workspace->layouts, iter_layout, start)
+ {
+ if (!callback(iter_layout, arg)) {
+ return iter_layout;
+ }
+ }
+ BLI_LISTBASE_CIRCULAR_BACKWARD_END(&workspace->layouts, iter_layout, start);
+ }
+ else {
+ BLI_LISTBASE_CIRCULAR_FORWARD_BEGIN(&workspace->layouts, iter_layout, start)
+ {
+ if (!callback(iter_layout, arg)) {
+ return iter_layout;
+ }
+ }
+ BLI_LISTBASE_CIRCULAR_FORWARD_END(&workspace->layouts, iter_layout, start)
+ }
+
+ return NULL;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* 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);
+}
+
+#ifdef USE_WORKSPACE_MODE
+ObjectMode BKE_workspace_object_mode_get(const WorkSpace *workspace)
+{
+ return workspace->object_mode;
+}
+void BKE_workspace_object_mode_set(WorkSpace *workspace, const ObjectMode mode)
+{
+ workspace->object_mode = mode;
+}
+#endif
+
+ListBase *BKE_workspace_transform_orientations_get(WorkSpace *workspace)
+{
+ return &workspace->transform_orientations;
+}
+
+SceneLayer *BKE_workspace_render_layer_get(const WorkSpace *workspace)
+{
+ return workspace->render_layer;
+}
+void BKE_workspace_render_layer_set(WorkSpace *workspace, SceneLayer *layer)
+{
+ workspace->render_layer = layer;
+}
+
+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);
+}
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index de1e3187a70..363c36e644d 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -119,7 +119,7 @@ World *add_world(Main *bmain, const char *name)
return wrld;
}
-World *BKE_world_copy(Main *bmain, World *wrld)
+World *BKE_world_copy(Main *bmain, const World *wrld)
{
World *wrldn;
int a;
@@ -158,8 +158,6 @@ World *localize_world(World *wrld)
if (wrld->mtex[a]) {
wrldn->mtex[a] = MEM_mallocN(sizeof(MTex), "localize_world");
memcpy(wrldn->mtex[a], wrld->mtex[a], sizeof(MTex));
- /* free world decrements */
- id_us_plus((ID *)wrldn->mtex[a]->tex);
}
}
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 9dbc045f1b0..156b74f5c3d 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -69,10 +69,14 @@ typedef struct FFMpegContext {
int ffmpeg_video_bitrate;
int ffmpeg_audio_bitrate;
int ffmpeg_gop_size;
+ int ffmpeg_max_b_frames;
int ffmpeg_autosplit;
int ffmpeg_autosplit_count;
bool ffmpeg_preview;
+ int ffmpeg_crf; /* set to 0 to not use CRF mode; we have another flag for lossless anyway. */
+ int ffmpeg_preset; /* see FFMpegPreset */
+
AVFormatContext *outfile;
AVStream *video_stream;
AVStream *audio_stream;
@@ -440,7 +444,7 @@ static void set_ffmpeg_property_option(AVCodecContext *c, IDProperty *prop, AVDi
param = strchr(name, ':');
if (param) {
- *param++ = 0;
+ *param++ = '\0';
}
switch (prop->type) {
@@ -560,10 +564,38 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int
}
c->gop_size = context->ffmpeg_gop_size;
- c->bit_rate = context->ffmpeg_video_bitrate * 1000;
- c->rc_max_rate = rd->ffcodecdata.rc_max_rate * 1000;
- c->rc_min_rate = rd->ffcodecdata.rc_min_rate * 1000;
- c->rc_buffer_size = rd->ffcodecdata.rc_buffer_size * 1024;
+ c->max_b_frames = context->ffmpeg_max_b_frames;
+
+ if (context->ffmpeg_crf >= 0) {
+ ffmpeg_dict_set_int(&opts, "crf", context->ffmpeg_crf);
+ }
+ else {
+ c->bit_rate = context->ffmpeg_video_bitrate * 1000;
+ c->rc_max_rate = rd->ffcodecdata.rc_max_rate * 1000;
+ c->rc_min_rate = rd->ffcodecdata.rc_min_rate * 1000;
+ c->rc_buffer_size = rd->ffcodecdata.rc_buffer_size * 1024;
+ }
+
+ if (context->ffmpeg_preset) {
+ char const *preset_name;
+ switch (context->ffmpeg_preset) {
+ case FFM_PRESET_ULTRAFAST: preset_name = "ultrafast"; break;
+ case FFM_PRESET_SUPERFAST: preset_name = "superfast"; break;
+ case FFM_PRESET_VERYFAST: preset_name = "veryfast"; break;
+ case FFM_PRESET_FASTER: preset_name = "faster"; break;
+ case FFM_PRESET_FAST: preset_name = "fast"; break;
+ case FFM_PRESET_MEDIUM: preset_name = "medium"; break;
+ case FFM_PRESET_SLOW: preset_name = "slow"; break;
+ case FFM_PRESET_SLOWER: preset_name = "slower"; break;
+ case FFM_PRESET_VERYSLOW: preset_name = "veryslow"; break;
+ default:
+ printf("Unknown preset number %i, ignoring.\n", context->ffmpeg_preset);
+ preset_name = NULL;
+ }
+ if (preset_name != NULL) {
+ av_dict_set(&opts, "preset", preset_name, 0);
+ }
+ }
#if 0
/* this options are not set in ffmpeg.c and leads to artifacts with MPEG-4
@@ -819,6 +851,12 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int
context->ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate;
context->ffmpeg_gop_size = rd->ffcodecdata.gop_size;
context->ffmpeg_autosplit = rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT;
+ context->ffmpeg_crf = rd->ffcodecdata.constant_rate_factor;
+ context->ffmpeg_preset = rd->ffcodecdata.ffmpeg_preset;
+
+ if ((rd->ffcodecdata.flags & FFMPEG_USE_MAX_B_FRAMES) != 0) {
+ context->ffmpeg_max_b_frames = rd->ffcodecdata.max_b_frames;
+ }
/* Determine the correct filename */
ffmpeg_filepath_get(context, name, rd, context->ffmpeg_preview, suffix);
@@ -852,12 +890,16 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int
/* Returns after this must 'goto fail;' */
of->oformat = fmt;
- of->packet_size = rd->ffcodecdata.mux_packet_size;
- if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
- ffmpeg_dict_set_int(&opts, "muxrate", rd->ffcodecdata.mux_rate);
- }
- else {
- av_dict_set(&opts, "muxrate", "0", 0);
+
+ /* Only bother with setting packet size & mux rate when CRF is not used. */
+ if (context->ffmpeg_crf == 0) {
+ of->packet_size = rd->ffcodecdata.mux_packet_size;
+ if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
+ ffmpeg_dict_set_int(&opts, "muxrate", rd->ffcodecdata.mux_rate);
+ }
+ else {
+ av_dict_set(&opts, "muxrate", "0", 0);
+ }
}
ffmpeg_dict_set_int(&opts, "preload", (int)(0.5 * AV_TIME_BASE));
@@ -1073,7 +1115,7 @@ static void ffmpeg_filepath_get(FFMpegContext *context, char *string, RenderData
BLI_make_existing_file(string);
- autosplit[0] = 0;
+ autosplit[0] = '\0';
if ((rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT) != 0) {
if (context) {
@@ -1096,7 +1138,7 @@ static void ffmpeg_filepath_get(FFMpegContext *context, char *string, RenderData
strcat(string, *exts);
}
else {
- *(string + strlen(string) - strlen(*fe)) = 0;
+ *(string + strlen(string) - strlen(*fe)) = '\0';
strcat(string, autosplit);
strcat(string, *fe);
}
@@ -1226,7 +1268,7 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
if (is_autosplit == false) {
if (context->audio_mixdown_device) {
AUD_Device_free(context->audio_mixdown_device);
- context->audio_mixdown_device = 0;
+ context->audio_mixdown_device = NULL;
}
}
#endif
@@ -1242,50 +1284,50 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
/* Close the video codec */
- if (context->video_stream && context->video_stream->codec) {
+ if (context->video_stream != NULL && context->video_stream->codec != NULL) {
avcodec_close(context->video_stream->codec);
PRINT("zero video stream %p\n", context->video_stream);
- context->video_stream = 0;
+ context->video_stream = NULL;
}
- if (context->audio_stream && context->audio_stream->codec) {
+ if (context->audio_stream != NULL && context->audio_stream->codec != NULL) {
avcodec_close(context->audio_stream->codec);
- context->audio_stream = 0;
+ context->audio_stream = NULL;
}
/* free the temp buffer */
- if (context->current_frame) {
+ if (context->current_frame != NULL) {
delete_picture(context->current_frame);
- context->current_frame = 0;
+ context->current_frame = NULL;
}
- if (context->outfile && context->outfile->oformat) {
+ if (context->outfile != NULL && context->outfile->oformat) {
if (!(context->outfile->oformat->flags & AVFMT_NOFILE)) {
avio_close(context->outfile->pb);
}
}
- if (context->outfile) {
+ if (context->outfile != NULL) {
avformat_free_context(context->outfile);
- context->outfile = 0;
+ context->outfile = NULL;
}
- if (context->audio_input_buffer) {
+ if (context->audio_input_buffer != NULL) {
av_free(context->audio_input_buffer);
- context->audio_input_buffer = 0;
+ context->audio_input_buffer = NULL;
}
#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
- if (context->audio_output_buffer) {
+ if (context->audio_output_buffer != NULL) {
av_free(context->audio_output_buffer);
- context->audio_output_buffer = 0;
+ context->audio_output_buffer = NULL;
}
#endif
- if (context->audio_deinterleave_buffer) {
+ if (context->audio_deinterleave_buffer != NULL) {
av_free(context->audio_deinterleave_buffer);
- context->audio_deinterleave_buffer = 0;
+ context->audio_deinterleave_buffer = NULL;
}
- if (context->img_convert_ctx) {
+ if (context->img_convert_ctx != NULL) {
sws_freeContext(context->img_convert_ctx);
- context->img_convert_ctx = 0;
+ context->img_convert_ctx = NULL;
}
}
@@ -1384,8 +1426,8 @@ static IDProperty *BKE_ffmpeg_property_add(RenderData *rd, const char *type, con
int BKE_ffmpeg_property_add_string(RenderData *rd, const char *type, const char *str)
{
AVCodecContext c;
- const AVOption *o = 0;
- const AVOption *p = 0;
+ const AVOption *o = NULL;
+ const AVOption *p = NULL;
char name_[128];
char *name;
char *param;
@@ -1393,7 +1435,7 @@ int BKE_ffmpeg_property_add_string(RenderData *rd, const char *type, const char
avcodec_get_context_defaults3(&c, NULL);
- strncpy(name_, str, sizeof(name_));
+ BLI_strncpy(name_, str, sizeof(name_));
name = name_;
while (*name == ' ') name++;
@@ -1404,7 +1446,7 @@ int BKE_ffmpeg_property_add_string(RenderData *rd, const char *type, const char
param = strchr(name, ' ');
}
if (param) {
- *param++ = 0;
+ *param++ = '\0';
while (*param == ' ') param++;
}
@@ -1503,14 +1545,6 @@ static void ffmpeg_set_expert_options(RenderData *rd)
BKE_ffmpeg_property_add_string(rd, "video", "fast-pskip:1");
BKE_ffmpeg_property_add_string(rd, "video", "wpredp:2");
#endif
-
- if (rd->ffcodecdata.flags & FFMPEG_LOSSLESS_OUTPUT) {
-#ifdef FFMPEG_HAVE_DEPRECATED_FLAGS2
- BKE_ffmpeg_property_add_string(rd, "video", "cqp:0");
-#else
- BKE_ffmpeg_property_add_string(rd, "video", "qp:0");
-#endif
- }
}
else if (codec_id == AV_CODEC_ID_DNXHD) {
if (rd->ffcodecdata.flags & FFMPEG_LOSSLESS_OUTPUT)
@@ -1622,9 +1656,10 @@ void BKE_ffmpeg_image_type_verify(RenderData *rd, ImageFormatData *imf)
rd->ffcodecdata.audio_codec <= 0 ||
rd->ffcodecdata.video_bitrate <= 1)
{
- rd->ffcodecdata.codec = AV_CODEC_ID_MPEG2VIDEO;
-
- BKE_ffmpeg_preset_set(rd, FFMPEG_PRESET_DVD);
+ BKE_ffmpeg_preset_set(rd, FFMPEG_PRESET_H264);
+ rd->ffcodecdata.constant_rate_factor = FFM_CRF_MEDIUM;
+ rd->ffcodecdata.ffmpeg_preset = FFM_PRESET_MEDIUM;
+ rd->ffcodecdata.type = FFMPEG_MKV;
}
if (rd->ffcodecdata.type == FFMPEG_OGG) {
rd->ffcodecdata.type = FFMPEG_MPEG2;
diff --git a/source/blender/blenkernel/intern/writeframeserver.c b/source/blender/blenkernel/intern/writeframeserver.c
index 212af76a7e8..4757186f546 100644
--- a/source/blender/blenkernel/intern/writeframeserver.c
+++ b/source/blender/blenkernel/intern/writeframeserver.c
@@ -268,11 +268,7 @@ int BKE_frameserver_loop(void *context_v, RenderData *rd, ReportList *UNUSED(rep
struct timeval tv;
struct sockaddr_in addr;
int len, rval;
-#ifdef FREE_WINDOWS
- int socklen;
-#else
unsigned int socklen;
-#endif
char buf[4096];
FrameserverContext *context = context_v;
diff --git a/source/blender/blenkernel/tracking_private.h b/source/blender/blenkernel/tracking_private.h
index 591ee4d0d01..1a68a1cac6a 100644
--- a/source/blender/blenkernel/tracking_private.h
+++ b/source/blender/blenkernel/tracking_private.h
@@ -105,6 +105,13 @@ struct MovieTrackingMarker *tracking_get_keyframed_marker(
int current_frame,
bool backwards);
+/*********************** Masking *************************/
+
+float *tracking_track_get_mask_for_region(int frame_width, int frame_height,
+ const float region_min[2],
+ const float region_max[2],
+ MovieTrackingTrack *track);
+
/*********************** Frame accessr *************************/
struct libmv_FrameAccessor;
@@ -114,12 +121,16 @@ typedef struct TrackingImageAccessor {
struct MovieCache *cache;
struct MovieClip *clips[MAX_ACCESSOR_CLIP];
int num_clips;
+ struct MovieTrackingTrack **tracks;
+ int num_tracks;
int start_frame;
struct libmv_FrameAccessor *libmv_accessor;
} TrackingImageAccessor;
TrackingImageAccessor *tracking_image_accessor_new(MovieClip *clips[MAX_ACCESSOR_CLIP],
int num_clips,
+ MovieTrackingTrack **tracks,
+ int num_tracks,
int start_frame);
void tracking_image_accessor_destroy(TrackingImageAccessor *accessor);
diff --git a/source/blender/blenlib/BLI_alloca.h b/source/blender/blenlib/BLI_alloca.h
index b44e6c66d2a..4fa69a24966 100644
--- a/source/blender/blenlib/BLI_alloca.h
+++ b/source/blender/blenlib/BLI_alloca.h
@@ -29,10 +29,6 @@
/* BLI_array_alloca / alloca */
-#if defined(__MINGW32__)
-# include <malloc.h> /* mingw needs for alloca() */
-#endif
-
#if defined(__GNUC__) || defined(__clang__)
#if defined(__cplusplus) && (__cplusplus > 199711L)
#define BLI_array_alloca(arr, realsize) \
diff --git a/source/blender/blenlib/BLI_array.h b/source/blender/blenlib/BLI_array.h
index c645ff06c00..74f24c808ff 100644
--- a/source/blender/blenlib/BLI_array.h
+++ b/source/blender/blenlib/BLI_array.h
@@ -137,8 +137,8 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static,
#define BLI_array_free(arr) \
if (arr && (char *)arr != _##arr##_static) { \
- BLI_array_fake_user(arr); \
- MEM_freeN(arr); \
+ BLI_array_fake_user(arr); \
+ MEM_freeN(arr); \
} (void)0
#define BLI_array_pop(arr) ( \
diff --git a/source/blender/blenlib/BLI_bitmap_draw_2d.h b/source/blender/blenlib/BLI_bitmap_draw_2d.h
new file mode 100644
index 00000000000..fe890e94f1b
--- /dev/null
+++ b/source/blender/blenlib/BLI_bitmap_draw_2d.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 *****
+ */
+
+#ifndef __BLI_BITMAP_DRAW_2D_H__
+#define __BLI_BITMAP_DRAW_2D_H__
+
+/** \file BLI_bitmap_draw_2d.h
+ * \ingroup bli
+ */
+
+void BLI_bitmap_draw_2d_line_v2v2i(
+ const int p1[2], const int p2[2],
+ bool (*callback)(int, int, void *), void *userData);
+
+void BLI_bitmap_draw_2d_poly_v2i_n(
+ const int xmin, const int ymin, const int xmax, const int ymax,
+ const int polyXY[][2], const int polyCorners,
+ void (*callback)(int x, int x_end, int y, void *), void *userData);
+
+#endif /* __BLI_BITMAP_DRAW_2D_H__ */
diff --git a/source/blender/blenlib/BLI_callbacks.h b/source/blender/blenlib/BLI_callbacks.h
index fdffbeb4c8d..be53d1f603b 100644
--- a/source/blender/blenlib/BLI_callbacks.h
+++ b/source/blender/blenlib/BLI_callbacks.h
@@ -49,8 +49,6 @@ typedef enum {
BLI_CB_EVT_LOAD_POST,
BLI_CB_EVT_SAVE_PRE,
BLI_CB_EVT_SAVE_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_VERSION_UPDATE,
diff --git a/source/blender/blenlib/BLI_compiler_attrs.h b/source/blender/blenlib/BLI_compiler_attrs.h
index f0d32670229..4c548654e33 100644
--- a/source/blender/blenlib/BLI_compiler_attrs.h
+++ b/source/blender/blenlib/BLI_compiler_attrs.h
@@ -92,4 +92,12 @@
# define ATTR_PRINTF_FORMAT(format_param, dots_param)
#endif
+/* Use to suppress '-Wimplicit-fallthrough' (in place of 'break'). */
+#if defined(__GNUC__) && (__GNUC__ >= 7) /* gcc7.0+ only */
+#define ATTR_FALLTHROUGH __attribute__((fallthrough))
+#else
+#define ATTR_FALLTHROUGH ((void)0)
+#endif
+
+
#endif /* __BLI_COMPILER_ATTRS_H__ */
diff --git a/source/blender/blenlib/BLI_compiler_compat.h b/source/blender/blenlib/BLI_compiler_compat.h
index 8edbc25bcbc..01fc9d70207 100644
--- a/source/blender/blenlib/BLI_compiler_compat.h
+++ b/source/blender/blenlib/BLI_compiler_compat.h
@@ -32,11 +32,6 @@
# define alloca _alloca
#endif
-/* alloca is defined here for MinGW32 */
-#ifdef __MINGW32__
-# include <malloc.h>
-#endif
-
#if defined(__cplusplus) && ((__cplusplus >= 201103L) || defined(_MSC_VER))
# define HAS_CPP11_FEATURES
#endif
diff --git a/source/blender/blenlib/BLI_dynlib.h b/source/blender/blenlib/BLI_dynlib.h
index 7d5eb888021..310db9ea051 100644
--- a/source/blender/blenlib/BLI_dynlib.h
+++ b/source/blender/blenlib/BLI_dynlib.h
@@ -34,7 +34,7 @@
typedef struct DynamicLibrary DynamicLibrary;
-DynamicLibrary *BLI_dynlib_open(char *name);
+DynamicLibrary *BLI_dynlib_open(const char *name);
void *BLI_dynlib_find_symbol(DynamicLibrary *lib, const char *symname);
char *BLI_dynlib_get_error_as_string(DynamicLibrary *lib);
void BLI_dynlib_close(DynamicLibrary *lib);
diff --git a/source/blender/blenlib/BLI_dynstr.h b/source/blender/blenlib/BLI_dynstr.h
index 7aa1c30e449..b26accc7f78 100644
--- a/source/blender/blenlib/BLI_dynstr.h
+++ b/source/blender/blenlib/BLI_dynstr.h
@@ -43,11 +43,14 @@
#include "BLI_compiler_attrs.h"
struct DynStr;
+struct MemArena;
/** The abstract DynStr type */
typedef struct DynStr DynStr;
DynStr *BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+DynStr *BLI_dynstr_new_memarena(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+
void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr) ATTR_NONNULL();
void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len) ATTR_NONNULL();
@@ -56,8 +59,9 @@ void BLI_dynstr_vappendf(DynStr *__restrict ds, const char *__restrict format
int BLI_dynstr_get_len(DynStr *ds) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
char *BLI_dynstr_get_cstring(DynStr *ds) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-
void BLI_dynstr_get_cstring_ex(DynStr *__restrict ds, char *__restrict str) ATTR_NONNULL();
+
+void BLI_dynstr_clear(DynStr *ds) ATTR_NONNULL();
void BLI_dynstr_free(DynStr *ds) ATTR_NONNULL();
#endif /* __BLI_DYNSTR_H__ */
diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h
index 91d139c7085..5c1fa57886a 100644
--- a/source/blender/blenlib/BLI_fileops.h
+++ b/source/blender/blenlib/BLI_fileops.h
@@ -65,10 +65,8 @@ int BLI_create_symlink(const char *path, const char *to) ATTR_NONNULL();
/* keep in sync with the definition of struct direntry in BLI_fileops_types.h */
#ifdef WIN32
-# if defined(_MSC_VER) || defined(__MINGW64__)
+# if defined(_MSC_VER)
typedef struct _stat64 BLI_stat_t;
-# elif defined(__MINGW32__)
-typedef struct _stati64 BLI_stat_t;
# else
typedef struct _stat BLI_stat_t;
# endif
diff --git a/source/blender/blenlib/BLI_fileops_types.h b/source/blender/blenlib/BLI_fileops_types.h
index 0cf8c8ddb4a..0ffa3276f1f 100644
--- a/source/blender/blenlib/BLI_fileops_types.h
+++ b/source/blender/blenlib/BLI_fileops_types.h
@@ -35,7 +35,7 @@
#include <sys/stat.h>
-#if defined(WIN32) && !defined(FREE_WINDOWS)
+#if defined(WIN32)
typedef unsigned int mode_t;
#endif
@@ -50,10 +50,8 @@ struct direntry {
const char *relname;
const char *path;
#ifdef WIN32 /* keep in sync with the definition of BLI_stat_t in BLI_fileops.h */
-# if defined(_MSC_VER) || defined(__MINGW64__)
+# if defined(_MSC_VER)
struct _stat64 s;
-# elif defined(__MINGW32__)
- struct _stati64 s;
# else
struct _stat s;
# endif
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index 7e3a009ede8..8bf5c3da90d 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -32,6 +32,7 @@
* \ingroup bli
*/
+#include "BLI_blenlib.h"
#include "BLI_sys_types.h" /* for bool */
#include "BLI_compiler_attrs.h"
@@ -167,6 +168,8 @@ unsigned int BLI_ghashutil_inthash_p_murmur(const void *ptr);
unsigned int BLI_ghashutil_inthash_p_simple(const void *ptr);
bool BLI_ghashutil_intcmp(const void *a, const void *b);
+size_t BLI_ghashutil_combine_hash(size_t hash_a, size_t hash_b);
+
unsigned int BLI_ghashutil_uinthash_v4(const unsigned int key[4]);
#define BLI_ghashutil_inthash_v4(key) ( \
@@ -294,6 +297,25 @@ double BLI_ghash_calc_quality(GHash *gh);
double BLI_gset_calc_quality(GSet *gs);
#endif /* GHASH_INTERNAL_API */
+#define GHASH_FOREACH_BEGIN(type, var, what) \
+ do { \
+ GHashIterator gh_iter##var; \
+ GHASH_ITER(gh_iter##var, what) { \
+ type var = (type)(BLI_ghashIterator_getValue(&gh_iter##var)); \
+
+#define GHASH_FOREACH_END() \
+ } \
+ } while(0)
+
+#define GSET_FOREACH_BEGIN(type, var, what) \
+ do { \
+ GSetIterator gh_iter##var; \
+ GSET_ITER(gh_iter##var, what) { \
+ type var = (type)(BLI_gsetIterator_getKey(&gh_iter##var));
+
+#define GSET_FOREACH_END() \
+ } \
+ } while(0)
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_hash.h b/source/blender/blenlib/BLI_hash.h
new file mode 100644
index 00000000000..e849e5f8f61
--- /dev/null
+++ b/source/blender/blenlib/BLI_hash.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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_HASH_H__
+#define __BLI_HASH_H__
+
+/** \file BLI_hash.h
+ * \ingroup bli
+ */
+
+BLI_INLINE unsigned int BLI_hash_int_2d(unsigned int kx, unsigned int ky)
+{
+#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
+
+ unsigned int a, b, c;
+
+ a = b = c = 0xdeadbeef + (2 << 2) + 13;
+ a += kx;
+ b += ky;
+
+ c ^= b; c -= rot(b, 14);
+ a ^= c; a -= rot(c, 11);
+ b ^= a; b -= rot(a, 25);
+ c ^= b; c -= rot(b, 16);
+ a ^= c; a -= rot(c, 4);
+ b ^= a; b -= rot(a, 14);
+ c ^= b; c -= rot(b, 24);
+
+ return c;
+
+#undef rot
+}
+
+BLI_INLINE unsigned int BLI_hash_string(const char *str)
+{
+ unsigned int i = 0, c;
+
+ while ((c = *str++)) {
+ i = i * 37 + c;
+ }
+ return i;
+}
+
+BLI_INLINE unsigned int BLI_hash_int(unsigned int k)
+{
+ return BLI_hash_int_2d(k, 0);
+}
+
+#endif // __BLI_HASH_H__
diff --git a/source/blender/blenlib/BLI_iterator.h b/source/blender/blenlib/BLI_iterator.h
new file mode 100644
index 00000000000..a2ec21d89b3
--- /dev/null
+++ b/source/blender/blenlib/BLI_iterator.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.
+ *
+ * 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 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; \
+ for (callback_begin(&iter_macro, (_data_in)); \
+ iter_macro.valid; \
+ callback_next(&iter_macro)) \
+ { \
+ _instance = (_type ) iter_macro.current;
+
+#define ITER_END \
+ } \
+ callback_end_func(&iter_macro); \
+}
+
+#endif /* __BLI_ITERATOR_H__ */
diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h
index 91d39801645..564659ad21e 100644
--- a/source/blender/blenlib/BLI_kdopbvh.h
+++ b/source/blender/blenlib/BLI_kdopbvh.h
@@ -36,7 +36,7 @@
*/
#ifdef __cplusplus
-extern "C" {
+extern "C" {
#endif
struct BVHTree;
@@ -62,7 +62,7 @@ typedef struct BVHTreeNearest {
int index; /* the index of the nearest found (untouched if none is found within a dist radius from the given coordinates) */
float co[3]; /* nearest coordinates (untouched it none is found within a dist radius from the given coordinates) */
float no[3]; /* normal at nearest coordinates (untouched it none is found within a dist radius from the given coordinates) */
- float dist_sq; /* squared distance to search arround */
+ float dist_sq; /* squared distance to search around */
int flags;
} BVHTreeNearest;
@@ -95,10 +95,6 @@ typedef void (*BVHTree_NearestPointCallback)(void *userdata, int index, const fl
/* callback must update hit in case it finds a nearest successful hit */
typedef void (*BVHTree_RayCastCallback)(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit);
-/* callback must update nearest in case it finds a nearest result */
-typedef void (*BVHTree_NearestToRayCallback)(void *userdata, const float ray_co[3], const float ray_dir[3],
- const float scale[3], int index, BVHTreeNearest *nearest);
-
/* callback to check if 2 nodes overlap (use thread if intersection results need to be stored) */
typedef bool (*BVHTree_OverlapCallback)(void *userdata, int index_a, int index_b, int thread);
@@ -143,18 +139,6 @@ int BLI_bvhtree_find_nearest(
BVHTree *tree, const float co[3], BVHTreeNearest *nearest,
BVHTree_NearestPointCallback callback, void *userdata);
-int BLI_bvhtree_find_nearest_to_ray_angle(
- BVHTree *tree, const float co[3], const float dir[3],
- const bool ray_is_normalized, const float scale[3],
- BVHTreeNearest *nearest,
- BVHTree_NearestToRayCallback callback, void *userdata);
-
-int BLI_bvhtree_find_nearest_to_ray(
- BVHTree *tree, const float co[3], const float dir[3],
- const bool ray_is_normalized, const float scale[3],
- BVHTreeNearest *nearest,
- BVHTree_NearestToRayCallback callback, void *userdata);
-
int BLI_bvhtree_ray_cast_ex(
BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit,
BVHTree_RayCastCallback callback, void *userdata,
diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h
index 9dfa80006de..c1e28d5ebc3 100644
--- a/source/blender/blenlib/BLI_listbase.h
+++ b/source/blender/blenlib/BLI_listbase.h
@@ -67,14 +67,17 @@ void *BLI_poptail(ListBase *listbase) ATTR_NONNULL(1);
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1);
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1);
+void BLI_insertlinkreplace(ListBase *listbase, void *v_l_src, void *v_l_dst) ATTR_NONNULL(1, 2, 3);
void BLI_listbase_sort(struct ListBase *listbase, int (*cmp)(const void *, const void *)) ATTR_NONNULL(1, 2);
void BLI_listbase_sort_r(ListBase *listbase, int (*cmp)(void *, const void *, const void *), void *thunk) ATTR_NONNULL(1, 2);
+bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) ATTR_NONNULL();
void BLI_freelist(struct ListBase *listbase) ATTR_NONNULL(1);
int BLI_listbase_count_ex(const struct ListBase *listbase, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
void BLI_listbase_swaplinks(struct ListBase *listbase, void *vlinka, void *vlinkb) ATTR_NONNULL(1, 2);
+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_duplicatelist(struct ListBase *dst, const struct ListBase *src) ATTR_NONNULL(1, 2);
@@ -123,6 +126,11 @@ if ((lb)->last && (lb_init || (lb_init = (lb)->last))) { \
(lb_iter != lb_init)); \
}
+#define LINKLIST_FOREACH(type, var, list) \
+ for (type var = (type)((list)->first); \
+ var != NULL; \
+ var = (type)(((Link*)(var))->next))
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index e97a250cd24..0126e30d900 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -85,63 +85,6 @@ static const int NAN_INT = 0x7FC00000;
# define NAN_FLT (*((float *)(&NAN_INT)))
#endif
-/* do not redefine functions from C99, POSIX.1-2001 or MSVC12 (partial C99) */
-#if !(defined(_ISOC99_SOURCE) || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || defined(_MSC_VER))
-
-#ifndef sqrtf
-#define sqrtf(a) ((float)sqrt(a))
-#endif
-#ifndef powf
-#define powf(a, b) ((float)pow(a, b))
-#endif
-#ifndef cosf
-#define cosf(a) ((float)cos(a))
-#endif
-#ifndef sinf
-#define sinf(a) ((float)sin(a))
-#endif
-#ifndef acosf
-#define acosf(a) ((float)acos(a))
-#endif
-#ifndef asinf
-#define asinf(a) ((float)asin(a))
-#endif
-#ifndef atan2f
-#define atan2f(a, b) ((float)atan2(a, b))
-#endif
-#ifndef tanf
-#define tanf(a) ((float)tan(a))
-#endif
-#ifndef atanf
-#define atanf(a) ((float)atan(a))
-#endif
-#ifndef floorf
-#define floorf(a) ((float)floor(a))
-#endif
-#ifndef ceilf
-#define ceilf(a) ((float)ceil(a))
-#endif
-#ifndef fabsf
-#define fabsf(a) ((float)fabs(a))
-#endif
-#ifndef logf
-#define logf(a) ((float)log(a))
-#endif
-#ifndef expf
-#define expf(a) ((float)exp(a))
-#endif
-#ifndef fmodf
-#define fmodf(a, b) ((float)fmod(a, b))
-#endif
-#ifndef hypotf
-#define hypotf(a, b) ((float)hypot(a, b))
-#endif
-#ifndef copysignf
-#define copysignf(a, b) ((float)copysign(a, b))
-#endif
-
-#endif /* C99, POSIX.1-2001 or MSVC12 (partial C99) */
-
#if BLI_MATH_DO_INLINE
#include "intern/math_base_inline.c"
#endif
diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h
index 5e6b1256d30..34fc52c12c0 100644
--- a/source/blender/blenlib/BLI_math_color.h
+++ b/source/blender/blenlib/BLI_math_color.h
@@ -141,7 +141,11 @@ MINLINE void float_to_byte_dither_v3(unsigned char b[3], const float f[3], float
#define rgba_char_args_set_fl(col, r, g, b, a) \
rgba_char_args_set(col, (r) * 255, (g) * 255, (b) * 255, (a) * 255)
+#define rgba_float_args_set_ch(col, r, g, b, a) \
+ rgba_float_args_set(col, (r) / 255.0f, (g) / 255.0f, (b) / 255.0f, (a) / 255.0f)
+
MINLINE void rgba_char_args_set(char col[4], const char r, const char g, const char b, const char a);
+MINLINE void rgba_float_args_set(float col[4], const float r, const float g, const float b, const float a);
MINLINE void rgba_char_args_test_set(char col[4], const char r, const char g, const char b, const char a);
MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack);
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 026ab9a9980..0afb7aa9990 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -44,9 +44,6 @@ extern "C" {
/********************************** Polygons *********************************/
-void cent_tri_v3(float r[3], const float a[3], const float b[3], const float c[3]);
-void cent_quad_v3(float r[3], const float a[3], const float b[3], const float c[3], const float d[3]);
-
float normal_tri_v3(float r[3], const float a[3], const float b[3], const float c[3]);
float normal_quad_v3(float r[3], const float a[3], const float b[3], const float c[3], const float d[3]);
float normal_poly_v3(float r[3], const float verts[][3], unsigned int nr);
@@ -296,23 +293,10 @@ void isect_ray_aabb_v3_precalc(
bool isect_ray_aabb_v3(
const struct IsectRayAABB_Precalc *data,
const float bb_min[3], const float bb_max[3], float *tmin);
-
-struct NearestRayToAABB_Precalc {
- float ray_origin[3];
- float ray_direction[3];
- float ray_inv_dir[3];
- float cdot_axis[3];
- float idiag_sq[3];
- bool sign[3];
-};
-
-void dist_squared_ray_to_aabb_v3_precalc(
- struct NearestRayToAABB_Precalc *data,
- const float ray_origin[3], const float ray_direction[3]);
-float dist_squared_ray_to_aabb_v3(
- const struct NearestRayToAABB_Precalc *data,
+bool isect_ray_aabb_v3_simple(
+ const float orig[3], const float dir[3],
const float bb_min[3], const float bb_max[3],
- bool r_axis_closest[3]);
+ float *tmin, float *tmax);
/* other */
bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const float radius,
@@ -325,18 +309,11 @@ 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]);
-void plot_line_v2v2i(const int p1[2], const int p2[2], bool (*callback)(int, int, void *), void *userData);
-void fill_poly_v2i_n(
- const int xmin, const int ymin, const int xmax, const int ymax,
- const int polyXY[][2], const int polyCorners,
- void (*callback)(int x, int x_end, int y, void *), void *userData);
/****************************** Interpolation ********************************/
-
-/* tri or quad, d can be NULL */
-void interp_weights_face_v3(float w[4],
- const float a[3], const float b[3], const float c[3], const float d[3], const float p[3]);
+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]);
/* also returns three indices of the triangle actually used */
-void interp_weights_face_v3_index(int tri[3], float w[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float co[3]);
+void interp_weights_quad_v3_index(int tri[3], float w[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float co[3]);
void interp_weights_poly_v3(float w[], float v[][3], const int n, const float co[3]);
void interp_weights_poly_v2(float w[], float v[][2], const int n, const float co[2]);
@@ -401,6 +378,8 @@ void box_minmax_bounds_m4(float min[3], float max[3],
void map_to_tube(float *r_u, float *r_v, const float x, const float y, const float z);
void map_to_sphere(float *r_u, float *r_v, const float x, const float y, const float z);
+void map_to_plane_v2_v3v3(float r_co[2], const float co[3], const float no[3]);
+void map_to_plane_axis_angle_v2_v3v3fl(float r_co[2], const float co[3], const float axis[3], const float angle);
/********************************** Normals **********************************/
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index 8124e07dd47..90aff1fcbbc 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -46,31 +46,43 @@ 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();
@@ -100,27 +112,28 @@ void _va_mul_m4_series_9(float R[4][4], float M1[4][4], float M2[4][4], float M3
#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 +144,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 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 rotate_m2(float mat[2][2], 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 +251,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 +273,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 +285,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_rotation.h b/source/blender/blenlib/BLI_math_rotation.h
index 24c20ee7b50..e059327a490 100644
--- a/source/blender/blenlib/BLI_math_rotation.h
+++ b/source/blender/blenlib/BLI_math_rotation.h
@@ -122,8 +122,9 @@ void mat3_to_axis_angle(float axis[3], float *angle, float M[3][3]);
void mat4_to_axis_angle(float axis[3], float *angle, float M[4][4]);
void quat_to_axis_angle(float axis[3], float *angle, const float q[4]);
-void axis_angle_to_mat3_single(float R[3][3], const char axis, const float angle);
void angle_to_mat2(float R[2][2], const float angle);
+void axis_angle_to_mat3_single(float R[3][3], const char axis, const float angle);
+void axis_angle_to_mat4_single(float R[4][4], const char axis, const float angle);
void axis_angle_to_quat_single(float q[4], const char axis, const float angle);
@@ -217,8 +218,12 @@ float angle_wrap_deg(float angle);
float angle_compat_rad(float angle, float angle_compat);
-int mat3_from_axis_conversion(int from_forward, int from_up, int to_forward, int to_up,
- float r_mat[3][3]);
+bool mat3_from_axis_conversion(
+ int src_forward, int src_up, int dst_forward, int dst_up,
+ float r_mat[3][3]);
+bool mat3_from_axis_conversion_single(
+ int src_axis, int dst_axis,
+ float r_mat[3][3]);
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index d15fe1a95dc..120f3bb5ac3 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -123,7 +123,7 @@ MINLINE void mul_v4_fl(float r[4], float f);
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 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(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;
@@ -151,6 +151,7 @@ MINLINE void negate_v3_short(short r[3]);
MINLINE void negate_v3_db(double r[3]);
MINLINE void invert_v2(float r[2]);
+MINLINE void invert_v3(float r[3]);
MINLINE void abs_v2(float r[2]);
MINLINE void abs_v2_v2(float r[2], const float a[2]);
@@ -234,6 +235,7 @@ void mid_v3_v3v3(float r[3], const float a[3], const float b[3]);
void mid_v2_v2v2(float r[2], const float a[2], const float b[2]);
void mid_v3_v3v3v3(float v[3], const float v1[3], const float v2[3], const float v3[3]);
void mid_v3_v3v3v3v3(float v[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
+void mid_v3_v3_array(float r[3], const float (*vec_arr)[3], const unsigned int nbr);
void mid_v3_v3v3_angle_weighted(float r[3], const float a[3], const float b[3]);
void mid_v3_angle_weighted(float r[3]);
@@ -285,6 +287,8 @@ float angle_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT;
float angle_v3v3v3(const float a[3], const float b[3], const float c[3]) ATTR_WARN_UNUSED_RESULT;
float cos_v3v3v3(const float p1[3], const float p2[3], const float p3[3]) ATTR_WARN_UNUSED_RESULT;
float cos_v2v2v2(const float p1[2], const float p2[2], const float p3[2]) ATTR_WARN_UNUSED_RESULT;
+float angle_on_axis_v3v3_v3(const float v1[3], const float v2[3], const float axis[3]) ATTR_WARN_UNUSED_RESULT;
+float angle_signed_on_axis_v3v3_v3(const float v1[3], const float v2[3], const float axis[3]) ATTR_WARN_UNUSED_RESULT;
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT;
float angle_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3]) ATTR_WARN_UNUSED_RESULT;
float angle_signed_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3]) ATTR_WARN_UNUSED_RESULT;
@@ -298,12 +302,15 @@ void project_v2_v2v2(float out[2], const float p[2], const float v_proj[2]);
void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3]);
void project_plane_v3_v3v3(float out[3], const float p[3], const float v_plane[3]);
void project_plane_v2_v2v2(float out[2], const float p[2], const float v_plane[2]);
+void project_plane_normalized_v3_v3v3(float out[3], const float p[3], const float v_plane[3]);
+void project_plane_normalized_v2_v2v2(float out[2], const float p[2], const float v_plane[2]);
void project_v3_plane(float out[3], const float plane_no[3], const float plane_co[3]);
void reflect_v3_v3v3(float out[3], const float vec[3], const float normal[3]);
void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3]);
void ortho_v3_v3(float out[3], const float v[3]);
void ortho_v2_v2(float out[2], const float v[2]);
void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3]);
+void rotate_v2_v2fl(float r[2], const float p[2], const float angle);
void rotate_v3_v3v3fl(float v[3], const float p[3], const float axis[3], const float angle);
void rotate_normalized_v3_v3v3fl(float out[3], const float p[3], const float axis[3], const float angle);
@@ -319,6 +326,7 @@ void print_vn(const char *str, const float v[], const int n);
#define print_v4_id(v) print_v4(STRINGIFY(v), v)
#define print_vn_id(v, n) print_vn(STRINGIFY(v), v, 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]);
diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h
index 1a626ff44bd..b59e7f99d59 100644
--- a/source/blender/blenlib/BLI_path_util.h
+++ b/source/blender/blenlib/BLI_path_util.h
@@ -39,20 +39,12 @@ extern "C" {
struct ListBase;
-#ifdef WIN32
-#define SEP '\\'
-#define ALTSEP '/'
-#else
-#define SEP '/'
-#define ALTSEP '\\'
-#endif
-
void BLI_setenv(const char *env, const char *val) ATTR_NONNULL(1);
void BLI_setenv_if_new(const char *env, const char *val) ATTR_NONNULL(1);
void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file);
void BLI_make_exist(char *dir);
-void BLI_make_existing_file(const char *name);
+bool BLI_make_existing_file(const char *name);
void BLI_split_dirfile(const char *string, char *dir, char *file, const size_t dirlen, const size_t filelen);
void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen);
void BLI_split_file_part(const char *string, char *file, const size_t filelen);
@@ -60,7 +52,13 @@ void BLI_path_append(char *__restrict dst, const size_t maxlen,
const char *__restrict file) ATTR_NONNULL();
void BLI_join_dirfile(char *__restrict string, const size_t maxlen,
const char *__restrict dir, const char *__restrict file) ATTR_NONNULL();
+size_t BLI_path_join(
+ char *__restrict dst, const size_t dst_len,
+ const char *path_first, ...) ATTR_NONNULL(1, 3) ATTR_SENTINEL(0);
const char *BLI_path_basename(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+bool BLI_path_name_at_index(
+ const char *__restrict path, const int index,
+ int *__restrict r_offset, int *__restrict r_len) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
#if 0
typedef enum bli_rebase_state {
@@ -83,7 +81,6 @@ bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen);
#endif
bool BLI_path_program_search(char *fullname, const size_t maxlen, const char *name);
-void BLI_getlastdir(const char *dir, char *last, const size_t maxlen);
bool BLI_testextensie(const char *str, const char *ext) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
bool BLI_testextensie_n(const char *str, ...) ATTR_NONNULL(1) ATTR_SENTINEL(0);
bool BLI_testextensie_array(const char *str, const char **ext_array) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
@@ -91,13 +88,8 @@ bool BLI_testextensie_glob(const char *str, const char *ext_fnmatch) ATTR_NONNUL
bool BLI_replace_extension(char *path, size_t maxlen, const char *ext) ATTR_NONNULL();
bool BLI_ensure_extension(char *path, size_t maxlen, const char *ext) ATTR_NONNULL();
bool BLI_ensure_filename(char *filepath, size_t maxlen, const char *filename) ATTR_NONNULL();
-bool BLI_uniquename(struct ListBase *list, void *vlink, const char *defname, char delim, int name_offs, int len);
-bool BLI_uniquename_cb(bool (*unique_check)(void *arg, const char *name),
- void *arg, const char *defname, char delim, char *name, int name_len);
-void BLI_newname(char *name, int add);
int BLI_stringdec(const char *string, char *head, char *start, unsigned short *numlen);
void BLI_stringenc(char *string, const char *head, const char *tail, unsigned short numlen, int pic);
-int BLI_split_name_num(char *left, int *nr, const char *name, const char delim);
/* removes trailing slash */
void BLI_cleanup_file(const char *relabase, char *path) ATTR_NONNULL(2);
@@ -148,6 +140,18 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char
# define FILE_MAX 1024
#endif
+#ifdef WIN32
+# define SEP '\\'
+# define ALTSEP '/'
+# define SEP_STR "\\"
+# define ALTSEP_STR "/"
+#else
+# define SEP '/'
+# define ALTSEP '\\'
+# define SEP_STR "/"
+# define ALTSEP_STR "\\"
+#endif
+
/* Parent and current dir helpers. */
#define FILENAME_PARENT ".."
#define FILENAME_CURRENT "."
diff --git a/source/blender/blenlib/BLI_rect.h b/source/blender/blenlib/BLI_rect.h
index 59bf3644912..21b9c75ac35 100644
--- a/source/blender/blenlib/BLI_rect.h
+++ b/source/blender/blenlib/BLI_rect.h
@@ -47,6 +47,8 @@ bool BLI_rcti_is_empty(const struct rcti *rect);
bool BLI_rctf_is_empty(const struct rctf *rect);
void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax);
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax);
+void BLI_rctf_init_pt_radius(struct rctf *rect, const float xy[2], float size);
+void BLI_rcti_init_pt_radius(struct rcti *rect, const int xy[2], int size);
void BLI_rcti_init_minmax(struct rcti *rect);
void BLI_rctf_init_minmax(struct rctf *rect);
void BLI_rcti_do_minmax_v(struct rcti *rect, const int xy[2]);
@@ -95,6 +97,7 @@ void BLI_rctf_union(struct rctf *rctf1, const struct rctf *rctf2);
void BLI_rcti_rctf_copy(struct rcti *dst, const struct rctf *src);
void BLI_rctf_rcti_copy(struct rctf *dst, const struct rcti *src);
void BLI_rcti_rctf_copy_floor(struct rcti *dst, const struct rctf *src);
+void BLI_rcti_rctf_copy_round(struct rcti *dst, const struct rctf *src);
void BLI_rctf_rotate_expand(rctf *dst, const rctf *src, const float angle);
diff --git a/source/blender/blenlib/BLI_stack.h b/source/blender/blenlib/BLI_stack.h
index 222005ee92e..d54f2a7bab2 100644
--- a/source/blender/blenlib/BLI_stack.h
+++ b/source/blender/blenlib/BLI_stack.h
@@ -30,6 +30,10 @@
#include "BLI_compiler_attrs.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef struct BLI_Stack BLI_Stack;
BLI_Stack *BLI_stack_new_ex(
@@ -55,4 +59,8 @@ size_t BLI_stack_count(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONN
bool BLI_stack_is_empty(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __BLI_STACK_H__ */
diff --git a/source/blender/blenlib/BLI_strict_flags.h b/source/blender/blenlib/BLI_strict_flags.h
index 964ee06469d..86b7285655e 100644
--- a/source/blender/blenlib/BLI_strict_flags.h
+++ b/source/blender/blenlib/BLI_strict_flags.h
@@ -30,6 +30,8 @@
#ifdef __GNUC__
# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 /* gcc4.6+ only */
# pragma GCC diagnostic error "-Wsign-compare"
+# endif
+# if __GNUC__ >= 6 /* gcc6+ only */
# pragma GCC diagnostic error "-Wconversion"
# endif
# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 408
diff --git a/source/blender/blenlib/BLI_string_utf8.h b/source/blender/blenlib/BLI_string_utf8.h
index 0740b574c1a..32504a88b48 100644
--- a/source/blender/blenlib/BLI_string_utf8.h
+++ b/source/blender/blenlib/BLI_string_utf8.h
@@ -36,8 +36,8 @@ extern "C" {
char *BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL();
size_t BLI_strncpy_utf8_rlen(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL();
char *BLI_strncat_utf8(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL();
-int BLI_utf8_invalid_byte(const char *str, int length) ATTR_NONNULL();
-int BLI_utf8_invalid_strip(char *str, int length) ATTR_NONNULL();
+ptrdiff_t BLI_utf8_invalid_byte(const char *str, size_t length) ATTR_NONNULL();
+int BLI_utf8_invalid_strip(char *str, size_t length) ATTR_NONNULL();
int BLI_str_utf8_size(const char *p) ATTR_NONNULL(); /* warning, can return -1 on bad chars */
int BLI_str_utf8_size_safe(const char *p) ATTR_NONNULL();
diff --git a/source/blender/blenlib/BLI_string_utils.h b/source/blender/blenlib/BLI_string_utils.h
new file mode 100644
index 00000000000..bb19ed574bb
--- /dev/null
+++ b/source/blender/blenlib/BLI_string_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.
+ *
+ * The Original Code is Copyright (C) 2017 by the Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_STRING_UTILS_H__
+#define __BLI_STRING_UTILS_H__
+
+/** \file BLI_string_utils.h
+ * \ingroup bli
+ */
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "BLI_compiler_attrs.h"
+
+struct ListBase;
+
+typedef bool (*UniquenameCheckCallback)(void *arg, const char *name);
+
+size_t BLI_split_name_num(char *left, int *nr, const char *name, const char delim);
+
+void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len);
+void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len);
+
+void BLI_string_flip_side_name(char *r_name, const char *from_name, const bool strip_number, const size_t name_len);
+
+bool BLI_uniquename_cb(
+ UniquenameCheckCallback unique_check, void *arg, const char *defname, char delim, char *name, size_t name_len);
+bool BLI_uniquename(
+ struct ListBase *list, void *vlink, const char *defname, char delim, int name_offs, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BLI_STRING_UTILS_H__ */
diff --git a/source/blender/blenlib/BLI_sys_types.h b/source/blender/blenlib/BLI_sys_types.h
index 7929e1d6551..9477f61713c 100644
--- a/source/blender/blenlib/BLI_sys_types.h
+++ b/source/blender/blenlib/BLI_sys_types.h
@@ -65,8 +65,8 @@ typedef uint64_t u_int64_t;
#include <inttypes.h>
-/* MinGW and MSVC >= 2010 */
-#elif defined(FREE_WINDOWS) || defined(_MSC_VER)
+/* MSVC >= 2010 */
+#elif defined(_MSC_VER)
#include <stdint.h>
#else
@@ -80,6 +80,11 @@ typedef uint64_t u_int64_t;
#include <stddef.h> /* size_t define */
#include <stdbool.h>
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned long ulong;
+typedef unsigned char uchar;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_system.h b/source/blender/blenlib/BLI_system.h
index cb8cb6f5a0d..f51b9623803 100644
--- a/source/blender/blenlib/BLI_system.h
+++ b/source/blender/blenlib/BLI_system.h
@@ -21,15 +21,14 @@
#ifndef __BLI_SYSTEM_H__
#define __BLI_SYSTEM_H__
+#include <stdio.h>
+
/** \file BLI_system.h
* \ingroup bli
*/
int BLI_cpu_support_sse2(void);
-
-#if defined(NDEBUG) || !defined(__BLI_UTILDEFINES_H__)
void BLI_system_backtrace(FILE *fp);
-#endif
/* getpid */
#ifdef WIN32
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h
index 967e0be6d0a..721327d26a8 100644
--- a/source/blender/blenlib/BLI_task.h
+++ b/source/blender/blenlib/BLI_task.h
@@ -81,6 +81,7 @@ typedef void (*TaskFreeFunction)(TaskPool *__restrict pool, void *taskdata, int
TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata);
TaskPool *BLI_task_pool_create_background(TaskScheduler *scheduler, void *userdata);
+TaskPool *BLI_task_pool_create_suspended(TaskScheduler *scheduler, void *userdata);
void BLI_task_pool_free(TaskPool *pool);
void BLI_task_pool_push_ex(
@@ -95,14 +96,6 @@ void BLI_task_pool_push_from_thread(TaskPool *pool, TaskRunFunction run,
void BLI_task_pool_work_and_wait(TaskPool *pool);
/* cancel all tasks, keep worker threads running */
void BLI_task_pool_cancel(TaskPool *pool);
-/* stop all worker threads */
-void BLI_task_pool_stop(TaskPool *pool);
-
-/* get number of threads allowed to be used by this pool */
-int BLI_pool_get_num_threads(TaskPool *pool);
-
-/* set number of threads allowed to be used by this pool */
-void BLI_pool_set_num_threads(TaskPool *pool, int num_threads);
/* for worker threads, test if canceled */
bool BLI_task_pool_canceled(TaskPool *pool);
@@ -113,8 +106,12 @@ void *BLI_task_pool_userdata(TaskPool *pool);
/* optional mutex to use from run function */
ThreadMutex *BLI_task_pool_user_mutex(TaskPool *pool);
-/* number of tasks done, for stats, don't use this to make decisions */
-size_t BLI_task_pool_tasks_done(TaskPool *pool);
+/* Delayed push, use that to reduce thread overhead by accumulating
+ * all new tasks into local queue first and pushing it to scheduler
+ * from within a single mutex lock.
+ */
+void BLI_task_pool_delayed_push_begin(TaskPool *pool, int thread_id);
+void BLI_task_pool_delayed_push_end(TaskPool *pool, int thread_id);
/* Parallel for routines */
typedef void (*TaskParallelRangeFunc)(void *userdata, const int iter);
diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h
index d504e503c68..72ac6bd0080 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -633,7 +633,7 @@ extern bool BLI_memory_is_zero(const void *arr, const size_t arr_size);
* for aborting need to define WITH_ASSERT_ABORT
*/
#ifndef NDEBUG
-extern void BLI_system_backtrace(FILE *fp);
+# include "BLI_system.h"
# ifdef WITH_ASSERT_ABORT
# define _BLI_DUMMY_ABORT abort
# else
@@ -674,6 +674,9 @@ extern void BLI_system_backtrace(FILE *fp);
# define BLI_STATIC_ASSERT(a, msg)
#endif
+#define BLI_STATIC_ASSERT_ALIGN(st, align) \
+ BLI_STATIC_ASSERT((sizeof(st) % (align) == 0), "Structure must be strictly aligned")
+
/* hints for branch prediction, only use in code that runs a _lot_ where */
#ifdef __GNUC__
# define LIKELY(x) __builtin_expect(!!(x), 1)
diff --git a/source/blender/blenlib/BLI_winstuff.h b/source/blender/blenlib/BLI_winstuff.h
index b421b7dbb90..6fbbed01400 100644
--- a/source/blender/blenlib/BLI_winstuff.h
+++ b/source/blender/blenlib/BLI_winstuff.h
@@ -37,15 +37,6 @@
# error "This include is for Windows only!"
#endif
-#ifdef FREE_WINDOWS
-# ifdef WINVER
-# undef WINVER
-# endif
-
-/* Some stuff requires WINVER 0x500, but mingw's default is 0x400 */
-# define WINVER 0x0501
-#endif
-
#define WIN32_LEAN_AND_MEAN
#ifndef WIN32_SKIP_HKEY_PROTECTION
@@ -94,7 +85,7 @@ extern "C" {
# define snprintf _snprintf
#endif
-#if defined(_MSC_VER) || (defined(FREE_WINDOWS) && !defined(FREE_WINDOWS64))
+#if defined(_MSC_VER)
# define R_OK 4
# define W_OK 2
// not accepted by access() on windows
@@ -102,28 +93,22 @@ extern "C" {
# define F_OK 0
#endif
-#ifndef FREE_WINDOWS
typedef unsigned int mode_t;
-#endif
/* use functions that take a 64 bit offset for files larger than 4GB */
-#ifndef FREE_WINDOWS
-# include <stdio.h>
-# define fseek(stream, offset, origin) _fseeki64(stream, offset, origin)
-# define ftell(stream) _ftelli64(stream)
-# define lseek(fd, offset, origin) _lseeki64(fd, offset, origin)
-# define tell(fd) _telli64(fd)
-#endif
+#include <stdio.h>
+#define fseek(stream, offset, origin) _fseeki64(stream, offset, origin)
+#define ftell(stream) _ftelli64(stream)
+#define lseek(fd, offset, origin) _lseeki64(fd, offset, origin)
+#define tell(fd) _telli64(fd)
+
-/* mingw using _SSIZE_T_ to declare ssize_t type */
#ifndef _SSIZE_T_
# define _SSIZE_T_
/* python uses HAVE_SSIZE_T */
# ifndef HAVE_SSIZE_T
# define HAVE_SSIZE_T 1
-# ifndef FREE_WINDOWS64
typedef long ssize_t;
-# endif
# endif
#endif
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 9978d1d19af..dc81ce000ea 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -56,6 +56,7 @@ set(SRC
intern/array_store_utils.c
intern/array_utils.c
intern/astar.c
+ intern/bitmap_draw_2d.c
intern/boxpack2d.c
intern/buffer.c
intern/callbacks.c
@@ -108,6 +109,7 @@ set(SRC
intern/string.c
intern/string_cursor_utf8.c
intern/string_utf8.c
+ intern/string_utils.c
intern/system.c
intern/task.c
intern/threads.c
@@ -127,6 +129,7 @@ set(SRC
BLI_array_utils.h
BLI_astar.h
BLI_bitmap.h
+ BLI_bitmap_draw_2d.h
BLI_blenlib.h
BLI_boxpack2d.h
BLI_buffer.h
@@ -149,9 +152,11 @@ set(SRC
BLI_ghash.h
BLI_graph.h
BLI_gsqueue.h
+ BLI_hash.h
BLI_hash_md5.h
BLI_hash_mm2a.h
BLI_heap.h
+ BLI_iterator.h
BLI_jitter.h
BLI_kdopbvh.h
BLI_kdtree.h
@@ -193,6 +198,7 @@ set(SRC
BLI_string.h
BLI_string_cursor_utf8.h
BLI_string_utf8.h
+ BLI_string_utils.h
BLI_sys_types.h
BLI_system.h
BLI_task.h
diff --git a/source/blender/blenlib/PIL_time_utildefines.h b/source/blender/blenlib/PIL_time_utildefines.h
index 9157e04a7bf..412cfb3a090 100644
--- a/source/blender/blenlib/PIL_time_utildefines.h
+++ b/source/blender/blenlib/PIL_time_utildefines.h
@@ -80,9 +80,10 @@
} \
const float _delta_##var = TIMEIT_VALUE(var); \
_sum_##var += _delta_##var; \
+ _num_##var++; \
printf("time end (" #var "): %.6f" " " AT "\n", _delta_##var); \
- printf("time averaged (" #var "): %.6f" " " AT "\n", \
- (_sum_##var / ++_num_##var)); \
+ printf("time averaged (" #var "): %.6f (total: %.6f, in %d runs)\n", \
+ (_sum_##var / _num_##var), _sum_##var, (int)_num_##var); \
fflush(stdout); \
} (void)0
diff --git a/source/blender/blenlib/intern/BLI_dynstr.c b/source/blender/blenlib/intern/BLI_dynstr.c
index ecd4a6e6b09..bce6614beb5 100644
--- a/source/blender/blenlib/intern/BLI_dynstr.c
+++ b/source/blender/blenlib/intern/BLI_dynstr.c
@@ -35,6 +35,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
+#include "BLI_memarena.h"
#include "BLI_string.h"
#include "BLI_dynstr.h"
@@ -64,6 +65,7 @@ struct DynStrElem {
struct DynStr {
DynStrElem *elems, *last;
int curlen;
+ MemArena *memarena;
};
/***/
@@ -78,11 +80,32 @@ DynStr *BLI_dynstr_new(void)
DynStr *ds = MEM_mallocN(sizeof(*ds), "DynStr");
ds->elems = ds->last = NULL;
ds->curlen = 0;
+ ds->memarena = NULL;
return ds;
}
/**
+ * Create a new DynStr.
+ *
+ * \return Pointer to a new DynStr.
+ */
+DynStr *BLI_dynstr_new_memarena(void)
+{
+ DynStr *ds = MEM_mallocN(sizeof(*ds), "DynStr");
+ ds->elems = ds->last = NULL;
+ ds->curlen = 0;
+ ds->memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+
+ return ds;
+}
+
+BLI_INLINE void *dynstr_alloc(DynStr *__restrict ds, size_t size)
+{
+ return ds->memarena ? BLI_memarena_alloc(ds->memarena, size) : malloc(size);
+}
+
+/**
* Append a c-string to a DynStr.
*
* \param ds The DynStr to append to.
@@ -90,10 +113,10 @@ DynStr *BLI_dynstr_new(void)
*/
void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr)
{
- DynStrElem *dse = malloc(sizeof(*dse));
+ DynStrElem *dse = dynstr_alloc(ds, sizeof(*dse));
int cstrlen = strlen(cstr);
- dse->str = malloc(cstrlen + 1);
+ dse->str = dynstr_alloc(ds, cstrlen + 1);
memcpy(dse->str, cstr, cstrlen + 1);
dse->next = NULL;
@@ -114,10 +137,10 @@ void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr)
*/
void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len)
{
- DynStrElem *dse = malloc(sizeof(*dse));
+ DynStrElem *dse = dynstr_alloc(ds, sizeof(*dse));
int cstrlen = BLI_strnlen(cstr, len);
- dse->str = malloc(cstrlen + 1);
+ dse->str = dynstr_alloc(ds, cstrlen + 1);
memcpy(dse->str, cstr, cstrlen);
dse->str[cstrlen] = '\0';
dse->next = NULL;
@@ -296,22 +319,41 @@ char *BLI_dynstr_get_cstring(DynStr *ds)
}
/**
+ * Clear the DynStr
+ *
+ * \param ds The DynStr to clear.
+ */
+void BLI_dynstr_clear(DynStr *ds)
+{
+ if (ds->memarena) {
+ BLI_memarena_clear(ds->memarena);
+ }
+ else {
+ for (DynStrElem *dse_next, *dse = ds->elems; dse; dse = dse_next) {
+ dse_next = dse->next;
+
+ free(dse->str);
+ free(dse);
+ }
+ }
+
+ ds->elems = ds->last = NULL;
+ ds->curlen = 0;
+}
+
+/**
* Free the DynStr
*
* \param ds The DynStr to free.
*/
void BLI_dynstr_free(DynStr *ds)
{
- DynStrElem *dse;
-
- for (dse = ds->elems; dse; ) {
- DynStrElem *n = dse->next;
-
- free(dse->str);
- free(dse);
-
- dse = n;
+ if (ds->memarena) {
+ BLI_memarena_free(ds->memarena);
}
-
+ else {
+ BLI_dynstr_clear(ds);
+ }
+
MEM_freeN(ds);
}
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index f943a8119c4..69dee12c713 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -116,6 +116,12 @@ struct GHash {
};
+/* -------------------------------------------------------------------- */
+/* GHash API */
+
+/** \name Internal Utility API
+ * \{ */
+
BLI_INLINE void ghash_entry_copy(
GHash *gh_dst, Entry *dst, GHash *gh_src, Entry *src,
GHashKeyCopyFP keycopyfp, GHashValCopyFP valcopyfp)
@@ -132,12 +138,6 @@ BLI_INLINE void ghash_entry_copy(
}
}
-/* -------------------------------------------------------------------- */
-/* GHash API */
-
-/** \name Internal Utility API
- * \{ */
-
/**
* Get the full hash for a key.
*/
@@ -1225,6 +1225,11 @@ bool BLI_ghashutil_intcmp(const void *a, const void *b)
return (a != b);
}
+size_t BLI_ghashutil_combine_hash(size_t hash_a, size_t hash_b)
+{
+ return hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2));
+}
+
/**
* This function implements the widely used "djb" hash apparently posted
* by Daniel Bernstein to comp.lang.c some time ago. The 32 bit
@@ -1588,7 +1593,7 @@ double BLI_ghash_calc_quality_ex(
if (r_variance) {
/* We already know our mean (i.e. load factor), easy to compute variance.
- * See http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass_algorithm
+ * See https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass_algorithm
*/
double sum = 0.0;
for (i = 0; i < gh->nbuckets; i++) {
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index b14007a88cb..e5ca53a0193 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -55,12 +55,20 @@
#include "BLI_stack.h"
#include "BLI_kdopbvh.h"
#include "BLI_math.h"
-#include "BLI_strict_flags.h"
#include "BLI_task.h"
+#include "BLI_strict_flags.h"
+
/* used for iterative_raycast */
// #define USE_SKIP_LINKS
+/* Use to print balanced output. */
+// #define USE_PRINT_TREE
+
+/* Check tree is valid. */
+// #define USE_VERIFY_TREE
+
+
#define MAX_TREETYPE 32
/* Setting zero so we can catch bugs in BLI_task/KDOPBVH.
@@ -129,7 +137,7 @@ typedef struct BVHOverlapData_Thread {
} BVHOverlapData_Thread;
typedef struct BVHNearestData {
- BVHTree *tree;
+ const BVHTree *tree;
const float *co;
BVHTree_NearestPointCallback callback;
void *userdata;
@@ -139,7 +147,7 @@ typedef struct BVHNearestData {
} BVHNearestData;
typedef struct BVHRayCastData {
- BVHTree *tree;
+ const BVHTree *tree;
BVHTree_RayCastCallback callback;
void *userdata;
@@ -159,29 +167,6 @@ typedef struct BVHRayCastData {
BVHTreeRayHit hit;
} BVHRayCastData;
-typedef struct BVHNearestRayData {
- BVHTree *tree;
- BVHTree_NearestToRayCallback callback;
- void *userdata;
-
- struct {
- bool sign[3];
- float origin[3];
- float direction[3];
-
- float direction_scaled_square[3];
- float inv_dir[3];
-
- float cdot_axis[3];
- } ray;
-
- bool pick_smallest[3];
-
- BVHTreeNearest nearest;
-
- float scale[3];
-} BVHNearestRayData;
-
/** \} */
@@ -194,9 +179,9 @@ typedef struct BVHNearestRayData {
*/
const float bvhtree_kdop_axes[13][3] = {
- {1.0, 0, 0}, {0, 1.0, 0}, {0, 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, 0}, {1.0, 0, 1.0}, {0, 1.0, 1.0}, {1.0, -1.0, 0}, {1.0, 0, -1.0},
- {0, 1.0, -1.0}
+ {1.0, 0, 0}, {0, 1.0, 0}, {0, 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, 0}, {1.0, 0, 1.0}, {0, 1.0, 1.0}, {1.0, -1.0, 0}, {1.0, 0, -1.0}, {0, 1.0, -1.0}
};
@@ -344,11 +329,16 @@ static int bvh_partition(BVHNode **a, int lo, int hi, BVHNode *x, int axis)
{
int i = lo, j = hi;
while (1) {
- while ((a[i])->bv[axis] < x->bv[axis]) i++;
+ while (a[i]->bv[axis] < x->bv[axis]) {
+ i++;
+ }
j--;
- while (x->bv[axis] < (a[j])->bv[axis]) j--;
- if (!(i < j))
+ while (x->bv[axis] < a[j]->bv[axis]) {
+ j--;
+ }
+ if (!(i < j)) {
return i;
+ }
SWAP(BVHNode *, a[i], a[j]);
i++;
}
@@ -450,19 +440,18 @@ static void sort_along_axis(BVHTree *tree, int start, int end, int axis)
* \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
* - every node to the right of a[n] are greater or equal to it */
-static int partition_nth_element(BVHNode **a, int _begin, int _end, int n, int axis)
+static void partition_nth_element(BVHNode **a, int begin, int end, const int n, const int axis)
{
- int begin = _begin, end = _end, cut;
while (end - begin > 3) {
- cut = bvh_partition(a, begin, end, bvh_medianof3(a, begin, (begin + end) / 2, end - 1, axis), axis);
- if (cut <= n)
+ const int cut = bvh_partition(a, begin, end, bvh_medianof3(a, begin, (begin + end) / 2, end - 1, axis), axis);
+ if (cut <= n) {
begin = cut;
- else
+ }
+ else {
end = cut;
+ }
}
bvh_insertionsort(a, begin, end, axis);
-
- return n;
}
#ifdef USE_SKIP_LINKS
@@ -487,7 +476,7 @@ static void build_skip_links(BVHTree *tree, BVHNode *node, BVHNode *left, BVHNod
/*
* BVHTree bounding volumes functions
*/
-static void create_kdop_hull(BVHTree *tree, BVHNode *node, const float *co, int numpoints, int moving)
+static void create_kdop_hull(const BVHTree *tree, BVHNode *node, const float *co, int numpoints, int moving)
{
float newminmax;
float *bv = node->bv;
@@ -514,7 +503,7 @@ static void create_kdop_hull(BVHTree *tree, BVHNode *node, const float *co, int
/**
* \note depends on the fact that the BVH's for each face is already build
*/
-static void refit_kdop_hull(BVHTree *tree, BVHNode *node, int start, int end)
+static void refit_kdop_hull(const BVHTree *tree, BVHNode *node, int start, int end)
{
float newmin, newmax;
float *bv = node->bv;
@@ -589,10 +578,12 @@ static void node_join(BVHTree *tree, BVHNode *node)
}
}
-/*
+#ifdef USE_PRINT_TREE
+
+/**
* Debug and information functions
*/
-#if 0
+
static void bvhtree_print_tree(BVHTree *tree, BVHNode *node, int depth)
{
int i;
@@ -615,26 +606,29 @@ static void bvhtree_print_tree(BVHTree *tree, BVHNode *node, int depth)
static void bvhtree_info(BVHTree *tree)
{
- printf("BVHTree info\n");
- printf("tree_type = %d, axis = %d, epsilon = %f\n", tree->tree_type, tree->axis, tree->epsilon);
- printf("nodes = %d, branches = %d, leafs = %d\n", tree->totbranch + tree->totleaf, tree->totbranch, tree->totleaf);
- printf("Memory per node = %ldbytes\n", sizeof(BVHNode) + sizeof(BVHNode *) * tree->tree_type + sizeof(float) * tree->axis);
- printf("BV memory = %dbytes\n", (int)MEM_allocN_len(tree->nodebv));
-
- printf("Total memory = %ldbytes\n", sizeof(BVHTree) +
- MEM_allocN_len(tree->nodes) +
- MEM_allocN_len(tree->nodearray) +
- MEM_allocN_len(tree->nodechild) +
- MEM_allocN_len(tree->nodebv));
-
-// bvhtree_print_tree(tree, tree->nodes[tree->totleaf], 0);
-}
-#endif
+ printf("BVHTree Info: tree_type = %d, axis = %d, epsilon = %f\n",
+ tree->tree_type, tree->axis, tree->epsilon);
+ printf("nodes = %d, branches = %d, leafs = %d\n",
+ tree->totbranch + tree->totleaf, tree->totbranch, tree->totleaf);
+ printf("Memory per node = %ubytes\n",
+ (uint)(sizeof(BVHNode) + sizeof(BVHNode *) * tree->tree_type + sizeof(float) * tree->axis));
+ printf("BV memory = %ubytes\n",
+ (uint)MEM_allocN_len(tree->nodebv));
-#if 0
+ printf("Total memory = %ubytes\n",
+ (uint)(sizeof(BVHTree) +
+ MEM_allocN_len(tree->nodes) +
+ MEM_allocN_len(tree->nodearray) +
+ MEM_allocN_len(tree->nodechild) +
+ MEM_allocN_len(tree->nodebv)));
+ bvhtree_print_tree(tree, tree->nodes[tree->totleaf], 0);
+}
+#endif /* USE_PRINT_TREE */
+
+#ifdef USE_VERIFY_TREE
-static void verify_tree(BVHTree *tree)
+static void bvhtree_verify(BVHTree *tree)
{
int i, j, check = 0;
@@ -672,12 +666,14 @@ static void verify_tree(BVHTree *tree)
}
}
- printf("branches: %d, leafs: %d, total: %d\n", tree->totbranch, tree->totleaf, tree->totbranch + tree->totleaf);
+ printf("branches: %d, leafs: %d, total: %d\n",
+ tree->totbranch, tree->totleaf, tree->totbranch + tree->totleaf);
}
-#endif
+#endif /* USE_VERIFY_TREE */
/* Helper data and structures to build a min-leaf generalized implicit tree
- * This code can be easily reduced (basicly this is only method to calculate pow(k, n) in O(1).. and stuff like that) */
+ * This code can be easily reduced
+ * (basicly this is only method to calculate pow(k, n) in O(1).. and stuff like that) */
typedef struct BVHBuildHelper {
int tree_type; /* */
int totleafs; /* */
@@ -689,7 +685,7 @@ typedef struct BVHBuildHelper {
} BVHBuildHelper;
-static void build_implicit_tree_helper(BVHTree *tree, BVHBuildHelper *data)
+static void build_implicit_tree_helper(const BVHTree *tree, BVHBuildHelper *data)
{
int depth = 0;
int remain;
@@ -719,7 +715,7 @@ static void build_implicit_tree_helper(BVHTree *tree, BVHBuildHelper *data)
}
// return the min index of all the leafs archivable with the given branch
-static int implicit_leafs_index(BVHBuildHelper *data, int depth, int child_index)
+static int implicit_leafs_index(const BVHBuildHelper *data, const int depth, const int child_index)
{
int min_leaf_index = child_index * data->leafs_per_child[depth - 1];
if (min_leaf_index <= data->remain_leafs)
@@ -734,8 +730,8 @@ static int implicit_leafs_index(BVHBuildHelper *data, int depth, int child_index
* Generalized implicit tree build
*
* An implicit tree is a tree where its structure is implied, thus there is no need to store child pointers or indexs.
- * Its possible to find the position of the child or the parent with simple maths (multiplication and adittion). This type
- * of tree is for example used on heaps.. where node N has its childs at indexs N*2 and N*2+1.
+ * Its possible to find the position of the child or the parent with simple maths (multiplication and adittion).
+ * This type of tree is for example used on heaps.. where node N has its childs at indexs N*2 and N*2+1.
*
* Although in this case the tree type is general.. and not know until runtime.
* tree_type stands for the maximum number of childs that a tree node can have.
@@ -776,7 +772,7 @@ static int implicit_needed_branches(int tree_type, int leafs)
*
* TODO: This can be optimized a bit by doing a specialized nth_element instead of K nth_elements
*/
-static void split_leafs(BVHNode **leafs_array, int *nth, int partitions, int split_axis)
+static void split_leafs(BVHNode **leafs_array, const int nth[], const int partitions, const int split_axis)
{
int i;
for (i = 0; i < partitions - 1; i++) {
@@ -788,14 +784,14 @@ static void split_leafs(BVHNode **leafs_array, int *nth, int partitions, int spl
}
typedef struct BVHDivNodesData {
- BVHTree *tree;
+ const BVHTree *tree;
BVHNode *branches_array;
BVHNode **leafs_array;
int tree_type;
int tree_offset;
- BVHBuildHelper *data;
+ const BVHBuildHelper *data;
int depth;
int i;
@@ -808,7 +804,7 @@ static void non_recursive_bvh_div_nodes_task_cb(void *userdata, const int j)
int k;
const int parent_level_index = j - data->i;
- BVHNode *parent = data->branches_array + j;
+ BVHNode *parent = &data->branches_array[j];
int nth_positions[MAX_TREETYPE + 1];
char split_axis;
@@ -847,7 +843,7 @@ static void non_recursive_bvh_div_nodes_task_cb(void *userdata, const int j)
const int child_leafs_end = implicit_leafs_index(data->data, data->depth + 1, child_level_index + 1);
if (child_leafs_end - child_leafs_begin > 1) {
- parent->children[k] = data->branches_array + child_index;
+ parent->children[k] = &data->branches_array[child_index];
parent->children[k]->parent = parent;
}
else if (child_leafs_end - child_leafs_begin == 1) {
@@ -878,7 +874,8 @@ static void non_recursive_bvh_div_nodes_task_cb(void *userdata, const int j)
* To archive this is necessary to find how much leafs are accessible from a certain branch, BVHBuildHelper
* implicit_needed_branches and implicit_leafs_index are auxiliary functions to solve that "optimal-split".
*/
-static void non_recursive_bvh_div_nodes(BVHTree *tree, BVHNode *branches_array, BVHNode **leafs_array, int num_leafs)
+static void non_recursive_bvh_div_nodes(
+ const BVHTree *tree, BVHNode *branches_array, BVHNode **leafs_array, int num_leafs)
{
int i;
@@ -890,13 +887,13 @@ static void non_recursive_bvh_div_nodes(BVHTree *tree, BVHNode *branches_array,
int depth;
/* set parent from root node to NULL */
- BVHNode *tmp = branches_array + 0;
+ BVHNode *tmp = &branches_array[0];
tmp->parent = NULL;
/* Most of bvhtree code relies on 1-leaf trees having at least one branch
* We handle that special case here */
if (num_leafs == 1) {
- BVHNode *root = branches_array + 0;
+ BVHNode *root = &branches_array[0];
refit_kdop_hull(tree, root, 0, num_leafs);
root->main_axis = get_largest_axis(root->bv) / 2;
root->totnode = 1;
@@ -918,16 +915,24 @@ static void non_recursive_bvh_div_nodes(BVHTree *tree, BVHNode *branches_array,
/* Loop tree levels (log N) loops */
for (i = 1, depth = 1; i <= num_branches; i = i * tree_type + tree_offset, depth++) {
const int first_of_next_level = i * tree_type + tree_offset;
- const int end_j = min_ii(first_of_next_level, num_branches + 1); /* index of last branch on this level */
+ const int i_stop = min_ii(first_of_next_level, num_branches + 1); /* index of last branch on this level */
/* Loop all branches on this level */
cb_data.first_of_next_level = first_of_next_level;
cb_data.i = i;
cb_data.depth = depth;
- BLI_task_parallel_range(
- i, end_j, &cb_data, non_recursive_bvh_div_nodes_task_cb,
- num_leafs > KDOPBVH_THREAD_LEAF_THRESHOLD);
+ if (true) {
+ BLI_task_parallel_range(
+ i, i_stop, &cb_data, non_recursive_bvh_div_nodes_task_cb,
+ num_leafs > KDOPBVH_THREAD_LEAF_THRESHOLD);
+ }
+ else {
+ /* Less hassle for debugging. */
+ for (int i_task = i; i_task < i_stop; i_task++) {
+ non_recursive_bvh_div_nodes_task_cb(&cb_data, i_task);
+ }
+ }
}
}
@@ -1044,7 +1049,8 @@ void BLI_bvhtree_balance(BVHTree *tree)
BVHNode *branches_array = tree->nodearray + tree->totleaf;
BVHNode **leafs_array = tree->nodes;
- /* This function should only be called once (some big bug goes here if its being called more than once per tree) */
+ /* This function should only be called once
+ * (some big bug goes here if its being called more than once per tree) */
BLI_assert(tree->totbranch == 0);
/* Build the implicit tree */
@@ -1060,7 +1066,13 @@ void BLI_bvhtree_balance(BVHTree *tree)
build_skip_links(tree, tree->nodes[tree->totleaf], NULL, NULL);
#endif
- /* bvhtree_info(tree); */
+#ifdef USE_VERIFY_TREE
+ bvhtree_verify(tree);
+#endif
+
+#ifdef USE_PRINT_TREE
+ bvhtree_info(tree);
+#endif
}
void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoints)
@@ -1493,7 +1505,8 @@ static void bfs_find_nearest(BVHNearestData *data, BVHNode *node)
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)
+ 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");
@@ -1900,453 +1913,6 @@ void BLI_bvhtree_ray_cast_all(
/* -------------------------------------------------------------------- */
-/** \name BLI_bvhtree_find_nearest_to_ray functions
- *
- * \{ */
-
-static void dist_squared_ray_to_aabb_scaled_v3_precalc(
- BVHNearestRayData *data,
- const float ray_origin[3], const float ray_direction[3],
- const bool ray_is_normalized, const float scale[3])
-{
- if (scale) {
- copy_v3_v3(data->scale, scale);
- }
- else {
- copy_v3_fl(data->scale, 1.0f);
- }
- /* un-normalize ray */
- if (ray_is_normalized && scale &&
- (data->scale[0] != 1.0f || data->scale[1] != 1.0f || data->scale[2] != 1.0f))
- {
- data->ray.direction[0] = ray_direction[0] * data->scale[0];
- data->ray.direction[1] = ray_direction[1] * data->scale[1];
- data->ray.direction[2] = ray_direction[2] * data->scale[2];
-
- mul_v3_v3fl(data->ray.direction, ray_direction, 1 / len_v3(data->ray.direction));
- }
- else {
- copy_v3_v3(data->ray.direction, ray_direction);
- }
-
- float dir_sq[3];
-
- for (int i = 0; i < 3; i++) {
- data->ray.origin[i] = ray_origin[i];
- data->ray.inv_dir[i] = (data->ray.direction[i] != 0.0f) ?
- (1.0f / data->ray.direction[i]) : FLT_MAX;
- /* It has to be in function of `ray.inv_dir`,
- * since the division of 1 by 0.0f, can be -inf or +inf */
- data->ray.sign[i] = (data->ray.inv_dir[i] < 0.0f);
-
- data->ray.direction_scaled_square[i] = data->ray.direction[i] * data->scale[i];
-
- dir_sq[i] = SQUARE(data->ray.direction_scaled_square[i]);
-
- data->ray.direction_scaled_square[i] *= data->scale[i];
- }
-
- /* `diag_sq` Length square of each face diagonal */
- float diag_sq[3] = {
- dir_sq[1] + dir_sq[2],
- dir_sq[0] + dir_sq[2],
- dir_sq[0] + dir_sq[1],
- };
-
- data->ray.cdot_axis[0] = (diag_sq[0] != 0.0f) ? data->ray.direction[0] / diag_sq[0] : FLT_MAX;
- data->ray.cdot_axis[1] = (diag_sq[1] != 0.0f) ? data->ray.direction[1] / diag_sq[1] : FLT_MAX;
- data->ray.cdot_axis[2] = (diag_sq[2] != 0.0f) ? data->ray.direction[2] / diag_sq[2] : FLT_MAX;
-}
-
-/**
- * Returns the squared distance from a ray to a bound-box `AABB`.
- * It is based on `fast_ray_nearest_hit` solution to obtain
- * the coordinates of the nearest edge of Bound Box to the ray
- */
-MINLINE float dist_squared_ray_to_aabb_scaled_v3__impl(
- const BVHNearestRayData *data,
- const float bv[6], float *r_depth_sq, bool r_axis_closest[3])
-{
-
- /* `tmin` is a vector that has the smaller distances to each of the
- * infinite planes of the `AABB` faces (hit in nearest face X plane,
- * nearest face Y plane and nearest face Z plane) */
- float local_bvmin[3], local_bvmax[3];
-
- if (data->ray.sign[0]) {
- local_bvmin[0] = bv[1];
- local_bvmax[0] = bv[0];
- }
- else {
- local_bvmin[0] = bv[0];
- local_bvmax[0] = bv[1];
- }
-
- if (data->ray.sign[1]) {
- local_bvmin[1] = bv[3];
- local_bvmax[1] = bv[2];
- }
- else {
- local_bvmin[1] = bv[2];
- local_bvmax[1] = bv[3];
- }
-
- if (data->ray.sign[2]) {
- local_bvmin[2] = bv[5];
- local_bvmax[2] = bv[4];
- }
- else {
- local_bvmin[2] = bv[4];
- local_bvmax[2] = bv[5];
- }
-
- sub_v3_v3(local_bvmin, data->ray.origin);
- sub_v3_v3(local_bvmax, data->ray.origin);
-
- const float tmin[3] = {
- local_bvmin[0] * data->ray.inv_dir[0],
- local_bvmin[1] * data->ray.inv_dir[1],
- local_bvmin[2] * data->ray.inv_dir[2],
- };
-
- /* `tmax` is a vector that has the longer distances to each of the
- * infinite planes of the `AABB` faces (hit in farthest face X plane,
- * farthest face Y plane and farthest face Z plane) */
- const float tmax[3] = {
- local_bvmax[0] * data->ray.inv_dir[0],
- local_bvmax[1] * data->ray.inv_dir[1],
- local_bvmax[2] * data->ray.inv_dir[2],
- };
- /* `v1` and `v3` is be the coordinates of the nearest `AABB` edge to the ray*/
- float v1[3], v2[3];
- /* `rtmin` is the highest value of the smaller distances. == max_axis_v3(tmin)
- * `rtmax` is the lowest value of longer distances. == min_axis_v3(tmax)*/
- float rtmin, rtmax, mul;
- /* `main_axis` is the axis equivalent to edge close to the ray */
- int main_axis;
-
- r_axis_closest[0] = false;
- r_axis_closest[1] = false;
- r_axis_closest[2] = false;
-
- /* *** min_axis_v3(tmax) *** */
- if ((tmax[0] <= tmax[1]) && (tmax[0] <= tmax[2])) {
- // printf("# Hit in X %s\n", data->sign[0] ? "min", "max");
- rtmax = tmax[0];
- v1[0] = v2[0] = local_bvmax[0];
- mul = local_bvmax[0] * data->ray.direction_scaled_square[0];
- main_axis = 3;
- r_axis_closest[0] = data->ray.sign[0];
- }
- else if ((tmax[1] <= tmax[0]) && (tmax[1] <= tmax[2])) {
- // printf("# Hit in Y %s\n", data->sign[1] ? "min", "max");
- rtmax = tmax[1];
- v1[1] = v2[1] = local_bvmax[1];
- mul = local_bvmax[1] * data->ray.direction_scaled_square[1];
- main_axis = 2;
- r_axis_closest[1] = data->ray.sign[1];
- }
- else {
- // printf("# Hit in Z %s\n", data->sign[2] ? "min", "max");
- rtmax = tmax[2];
- v1[2] = v2[2] = local_bvmax[2];
- mul = local_bvmax[2] * data->ray.direction_scaled_square[2];
- main_axis = 1;
- r_axis_closest[2] = data->ray.sign[2];
- }
-
- /* *** max_axis_v3(tmin) *** */
- if ((tmin[0] >= tmin[1]) && (tmin[0] >= tmin[2])) {
- // printf("# To X %s\n", data->sign[0] ? "max", "min");
- rtmin = tmin[0];
- v1[0] = v2[0] = local_bvmin[0];
- mul += local_bvmin[0] * data->ray.direction_scaled_square[0];
- main_axis -= 3;
- r_axis_closest[0] = !data->ray.sign[0];
- }
- else if ((tmin[1] >= tmin[0]) && (tmin[1] >= tmin[2])) {
- // printf("# To Y %s\n", data->sign[1] ? "max", "min");
- rtmin = tmin[1];
- v1[1] = v2[1] = local_bvmin[1];
- mul += local_bvmin[1] * data->ray.direction_scaled_square[1];
- main_axis -= 1;
- r_axis_closest[1] = !data->ray.sign[1];
- }
- else {
- // printf("# To Z %s\n", data->sign[2] ? "max", "min");
- rtmin = tmin[2];
- v1[2] = v2[2] = local_bvmin[2];
- mul += local_bvmin[2] * data->ray.direction_scaled_square[2];
- main_axis -= 2;
- r_axis_closest[2] = !data->ray.sign[2];
- }
- /* *** end min/max axis *** */
-
- if (main_axis < 0)
- main_axis += 3;
-
- /* if rtmin < rtmax, ray intersect `AABB` */
- if (rtmin <= rtmax) {
-#ifdef IGNORE_BEHIND_RAY
- /* `if rtmax < depth_min`, the whole `AABB` is behind us */
- if (rtmax < min_depth) {
- return fallback;
- }
-#endif
- const float proj = rtmin * data->ray.direction[main_axis];
-
- if (data->ray.sign[main_axis])
- r_axis_closest[main_axis] = (proj - local_bvmax[main_axis]) < (local_bvmin[main_axis] - proj);
- else
- r_axis_closest[main_axis] = (proj - local_bvmin[main_axis]) < (local_bvmax[main_axis] - proj);
-
- //if (r_depth_sq)
- // *r_depth_sq = SQUARE(rtmin);
-
- return 0.0f;
- }
-#ifdef IGNORE_BEHIND_RAY
- /* `if rtmin < depth_min`, the whole `AABB` is behing us */
- else if (rtmin < min_depth) {
- return fallback;
- }
-#endif
-
- if (data->ray.sign[main_axis]) {
- v1[main_axis] = local_bvmax[main_axis];
- v2[main_axis] = local_bvmin[main_axis];
- }
- else {
- v1[main_axis] = local_bvmin[main_axis];
- v2[main_axis] = local_bvmax[main_axis];
- }
- {
- /* `proj` equals to nearest point on the ray closest to the edge `v1 v2` of the `AABB`. */
- const float proj = mul * data->ray.cdot_axis[main_axis];
- float depth_sq, r_point[3];
- if (v1[main_axis] > proj) { /* the nearest point to the ray is the point v1 */
- r_axis_closest[main_axis] = true;
- /* `depth` is equivalent the distance of the the projection of v1 on the ray */
- depth_sq = mul + data->ray.direction_scaled_square[main_axis] * v1[main_axis];
-
- copy_v3_v3(r_point, v1);
- }
- else if (v2[main_axis] < proj) { /* the nearest point of the ray is the point v2 */
- r_axis_closest[main_axis] = false;
-
- depth_sq = mul + data->ray.direction_scaled_square[main_axis] * v2[main_axis];
-
- copy_v3_v3(r_point, v2);
- }
- else { /* the nearest point of the ray is on the edge of the `AABB`. */
- r_axis_closest[main_axis] = (proj - v1[main_axis]) < (v2[main_axis] - proj);
-
- depth_sq = mul + data->ray.direction_scaled_square[main_axis] * proj;
-#if 0
- r_point[0] = main_axis == 0 ? proj : v2[0];
- r_point[1] = main_axis == 1 ? proj : v2[1];
- r_point[2] = main_axis == 2 ? proj : v2[2];
-#else
- v2[main_axis] = proj;
- copy_v3_v3(r_point, v2);
-#endif
- }
- depth_sq *= depth_sq;
-
- if (r_depth_sq)
- *r_depth_sq = depth_sq;
-
- /* TODO: scale can be optional */
- r_point[0] *= data->scale[0];
- r_point[1] *= data->scale[1];
- r_point[2] *= data->scale[2];
-
- return len_squared_v3(r_point) - depth_sq;
- }
-}
-
-/**
- * <pre>
- * + r_point
- * |
- * | dist
- * |
- * +----depth----+orig <-- dir
- *
- * tangent = dist/depth
- * </pre>
- */
-static float calc_tangent_sq(BVHNearestRayData *data, BVHNode *node)
-{
- float depth_sq;
- const float dist_sq = dist_squared_ray_to_aabb_scaled_v3__impl(
- data, node->bv, &depth_sq, data->pick_smallest);
-
- return (dist_sq != 0.0f) ? (dist_sq / depth_sq) : 0.0f;
-}
-
-static float calc_dist_sq_to_ray(BVHNearestRayData *data, BVHNode *node)
-{
- return dist_squared_ray_to_aabb_scaled_v3__impl(
- data, node->bv, NULL,
- data->pick_smallest);
-}
-
-static void dfs_find_lowest_tangent_dfs(BVHNearestRayData *data, BVHNode *node)
-{
- if (node->totnode == 0) {
- if (data->callback) {
- data->callback(data->userdata, data->ray.origin, data->ray.direction,
- data->scale, node->index, &data->nearest);
- }
- else {
- data->nearest.index = node->index;
- data->nearest.dist_sq = calc_tangent_sq(data, node);
- /* TODO: return a value to the data->nearest.co
- * not urgent however since users currently define own callbacks */
- }
- }
- else {
- int i;
- /* First pick the closest node to dive on */
- if (data->pick_smallest[node->main_axis]) {
- for (i = 0; i != node->totnode; i++) {
- if (calc_tangent_sq(data, node->children[i]) < data->nearest.dist_sq) {
- dfs_find_lowest_tangent_dfs(data, node->children[i]);
- }
- }
- }
- else {
- for (i = node->totnode - 1; i >= 0; i--) {
- if (calc_tangent_sq(data, node->children[i]) < data->nearest.dist_sq) {
- dfs_find_lowest_tangent_dfs(data, node->children[i]);
- }
- }
- }
- }
-}
-
-static void dfs_find_nearest_to_ray_dfs(BVHNearestRayData *data, BVHNode *node)
-{
- if (node->totnode == 0) {
- if (data->callback) {
- data->callback(data->userdata, data->ray.origin, data->ray.direction,
- data->scale, node->index, &data->nearest);
- }
- else {
- data->nearest.index = node->index;
- data->nearest.dist_sq = calc_dist_sq_to_ray(data, node);
- /* TODO: return a value to the data->nearest.co
- * not urgent however since users currently define own callbacks */
- }
- }
- else {
- int i;
- /* First pick the closest node to dive on */
- if (data->pick_smallest[node->main_axis]) {
- for (i = 0; i != node->totnode; i++) {
- if (calc_dist_sq_to_ray(data, node->children[i]) < data->nearest.dist_sq) {
- dfs_find_nearest_to_ray_dfs(data, node->children[i]);
- }
- }
- }
- else {
- for (i = node->totnode - 1; i >= 0; i--) {
- if (calc_dist_sq_to_ray(data, node->children[i]) < data->nearest.dist_sq) {
- dfs_find_nearest_to_ray_dfs(data, node->children[i]);
- }
- }
- }
- }
-}
-
-/**
- * Returns the point whose tangent defined by the angle between the point and ray is the lowest
- * nearest.dist_sq returns the angle's tangent
- */
-int BLI_bvhtree_find_nearest_to_ray_angle(
- BVHTree *tree, const float co[3], const float dir[3],
- const bool ray_is_normalized, const float scale[3],
- BVHTreeNearest *nearest,
- BVHTree_NearestToRayCallback callback, void *userdata)
-{
- BVHNearestRayData data;
- BVHNode *root = tree->nodes[tree->totleaf];
-
- data.tree = tree;
-
- data.callback = callback;
- data.userdata = userdata;
-
- dist_squared_ray_to_aabb_scaled_v3_precalc(&data, co, dir, ray_is_normalized, scale);
-
- if (nearest) {
- memcpy(&data.nearest, nearest, sizeof(*nearest));
- }
- else {
- data.nearest.index = -1;
- data.nearest.dist_sq = FLT_MAX;
- }
-
- /* dfs search */
- if (root) {
- if (calc_tangent_sq(&data, root) < data.nearest.dist_sq)
- dfs_find_lowest_tangent_dfs(&data, root);
- }
-
- /* copy back results */
- if (nearest) {
- memcpy(nearest, &data.nearest, sizeof(*nearest));
- }
-
- return data.nearest.index;
-}
-
-/* return the nearest point to ray */
-int BLI_bvhtree_find_nearest_to_ray(
- BVHTree *tree, const float co[3], const float dir[3],
- const bool ray_is_normalized, const float scale[3],
- BVHTreeNearest *nearest,
- BVHTree_NearestToRayCallback callback, void *userdata)
-{
- BVHNearestRayData data;
- BVHNode *root = tree->nodes[tree->totleaf];
-
- data.tree = tree;
-
- data.callback = callback;
- data.userdata = userdata;
-
- dist_squared_ray_to_aabb_scaled_v3_precalc(&data, co, dir, ray_is_normalized, scale);
-
- if (nearest) {
- memcpy(&data.nearest, nearest, sizeof(*nearest));
- }
- else {
- data.nearest.index = -1;
- data.nearest.dist_sq = FLT_MAX;
- }
-
- /* dfs search */
- if (root) {
- if (calc_dist_sq_to_ray(&data, root) < data.nearest.dist_sq) {
- dfs_find_nearest_to_ray_dfs(&data, root);
- }
- }
-
- /* copy back results */
- if (nearest) {
- memcpy(nearest, &data.nearest, sizeof(*nearest));
- }
-
- return data.nearest.index;
-}
-
-/** \} */
-
-
-/* -------------------------------------------------------------------- */
-
/** \name BLI_bvhtree_range_query
*
* Allocs and fills an array with the indexs of node that are on the given spherical range (center, radius).
diff --git a/source/blender/blenlib/intern/array_store.c b/source/blender/blenlib/intern/array_store.c
index 6000c1a680c..d3a63aceb89 100644
--- a/source/blender/blenlib/intern/array_store.c
+++ b/source/blender/blenlib/intern/array_store.c
@@ -217,15 +217,12 @@
/** \name Internal Structs
* \{ */
-typedef unsigned int uint;
-typedef unsigned char ubyte;
-
typedef uint64_t hash_key;
typedef struct BArrayInfo {
size_t chunk_stride;
- uint chunk_count;
+ // uint chunk_count; /* UNUSED (other values are derived from this) */
/* pre-calculated */
size_t chunk_byte_size;
@@ -291,7 +288,7 @@ typedef struct BChunkList {
/* a chunk of an array */
typedef struct BChunk {
- const ubyte *data;
+ const uchar *data;
size_t data_len;
/** number of #BChunkList using this. */
int users;
@@ -332,7 +329,7 @@ static size_t bchunk_list_size(const BChunkList *chunk_list);
* \{ */
static BChunk *bchunk_new(
- BArrayMemory *bs_mem, const ubyte *data, const size_t data_len)
+ BArrayMemory *bs_mem, const uchar *data, const size_t data_len)
{
BChunk *chunk = BLI_mempool_alloc(bs_mem->chunk);
chunk->data = data;
@@ -345,9 +342,9 @@ static BChunk *bchunk_new(
}
static BChunk *bchunk_new_copydata(
- BArrayMemory *bs_mem, const ubyte *data, const size_t data_len)
+ BArrayMemory *bs_mem, const uchar *data, const size_t data_len)
{
- ubyte *data_copy = MEM_mallocN(data_len, __func__);
+ uchar *data_copy = MEM_mallocN(data_len, __func__);
memcpy(data_copy, data, data_len);
return bchunk_new(bs_mem, data_copy, data_len);
}
@@ -367,7 +364,7 @@ static void bchunk_decref(
static bool bchunk_data_compare(
const BChunk *chunk,
- const ubyte *data_base, const size_t data_base_len,
+ const uchar *data_base, const size_t data_base_len,
const size_t offset)
{
if (offset + (size_t)chunk->data_len <= data_base_len) {
@@ -426,14 +423,14 @@ static void bchunk_list_decref(
#ifdef USE_VALIDATE_LIST_DATA_PARTIAL
static size_t bchunk_list_data_check(
- const BChunkList *chunk_list, const ubyte *data)
+ const BChunkList *chunk_list, const uchar *data)
{
- size_t total_size = 0;
+ size_t offset = 0;
for (BChunkRef *cref = chunk_list->chunk_refs.first; cref; cref = cref->next) {
- if (memcmp(&data[total_size], cref->link->data, cref->link->data_len) != 0) {
+ if (memcmp(&data[offset], cref->link->data, cref->link->data_len) != 0) {
return false;
}
- total_size += cref->link->data_len;
+ offset += cref->link->data_len;
}
return true;
}
@@ -466,7 +463,7 @@ static void bchunk_list_ensure_min_size_last(
chunk_list->chunk_refs.last = cref->prev;
chunk_list->chunk_refs_len -= 1;
- ubyte *data_merge = MEM_mallocN(data_merge_len, __func__);
+ uchar *data_merge = MEM_mallocN(data_merge_len, __func__);
memcpy(data_merge, chunk_prev->data, chunk_prev->data_len);
memcpy(&data_merge[chunk_prev->data_len], chunk_curr->data, chunk_curr->data_len);
@@ -487,8 +484,8 @@ static void bchunk_list_ensure_min_size_last(
/* merge and split */
const size_t data_prev_len = split;
const size_t data_curr_len = data_merge_len - split;
- ubyte *data_prev = MEM_mallocN(data_prev_len, __func__);
- ubyte *data_curr = MEM_mallocN(data_curr_len, __func__);
+ uchar *data_prev = MEM_mallocN(data_prev_len, __func__);
+ uchar *data_curr = MEM_mallocN(data_curr_len, __func__);
if (data_prev_len <= chunk_prev->data_len) {
const size_t data_curr_shrink_len = chunk_prev->data_len - data_prev_len;
@@ -579,7 +576,7 @@ static void bchunk_list_calc_trim_len(
/**
* Append and don't manage merging small chunks.
*/
-static bool bchunk_list_append_only(
+static void bchunk_list_append_only(
BArrayMemory *bs_mem,
BChunkList *chunk_list, BChunk *chunk)
{
@@ -588,7 +585,6 @@ static bool bchunk_list_append_only(
cref->link = chunk;
chunk_list->chunk_refs_len += 1;
chunk->users += 1;
- return chunk;
}
/**
@@ -598,11 +594,10 @@ static bool bchunk_list_append_only(
static void bchunk_list_append_data(
const BArrayInfo *info, BArrayMemory *bs_mem,
BChunkList *chunk_list,
- const ubyte *data, const size_t data_len)
+ const uchar *data, const size_t data_len)
{
BLI_assert(data_len != 0);
- // printf("data_len: %d\n", data_len);
#ifdef USE_MERGE_CHUNKS
BLI_assert(data_len <= info->chunk_byte_size_max);
@@ -614,13 +609,13 @@ static void bchunk_list_append_data(
const size_t data_merge_len = chunk_prev->data_len + data_len;
/* realloc for single user */
if (cref->link->users == 1) {
- ubyte *data_merge = MEM_reallocN((void *)cref->link->data, data_merge_len);
+ uchar *data_merge = MEM_reallocN((void *)cref->link->data, data_merge_len);
memcpy(&data_merge[chunk_prev->data_len], data, data_len);
cref->link->data = data_merge;
cref->link->data_len = data_merge_len;
}
else {
- ubyte *data_merge = MEM_mallocN(data_merge_len, __func__);
+ uchar *data_merge = MEM_mallocN(data_merge_len, __func__);
memcpy(data_merge, chunk_prev->data, chunk_prev->data_len);
memcpy(&data_merge[chunk_prev->data_len], data, data_len);
cref->link = bchunk_new(bs_mem, data_merge, data_merge_len);
@@ -640,7 +635,7 @@ static void bchunk_list_append_data(
/* don't run this, instead preemptively avoid creating a chunk only to merge it (above). */
#if 0
#ifdef USE_MERGE_CHUNKS
- bchunk_list_ensure_min_size_last(info, bs_mem, chunk_list, chunk_size_min);
+ bchunk_list_ensure_min_size_last(info, bs_mem, chunk_list);
#endif
#endif
}
@@ -655,7 +650,7 @@ static void bchunk_list_append_data(
static void bchunk_list_append_data_n(
const BArrayInfo *info, BArrayMemory *bs_mem,
BChunkList *chunk_list,
- const ubyte *data, size_t data_len)
+ const uchar *data, size_t data_len)
{
size_t data_trim_len, data_last_chunk_len;
bchunk_list_calc_trim_len(info, data_len, &data_trim_len, &data_last_chunk_len);
@@ -715,7 +710,7 @@ static void bchunk_list_append(
static void bchunk_list_fill_from_array(
const BArrayInfo *info, BArrayMemory *bs_mem,
BChunkList *chunk_list,
- const ubyte *data,
+ const uchar *data,
const size_t data_len)
{
BLI_assert(BLI_listbase_is_empty(&chunk_list->chunk_refs));
@@ -766,13 +761,13 @@ static void bchunk_list_fill_from_array(
#define HASH_INIT (5381)
-BLI_INLINE uint hash_data_single(const ubyte p)
+BLI_INLINE uint hash_data_single(const uchar p)
{
return (HASH_INIT << 5) + HASH_INIT + (unsigned int)p;
}
/* hash bytes, from BLI_ghashutil_strhash_n */
-static uint hash_data(const ubyte *key, size_t n)
+static uint hash_data(const uchar *key, size_t n)
{
const signed char *p;
unsigned int h = HASH_INIT;
@@ -789,7 +784,7 @@ static uint hash_data(const ubyte *key, size_t n)
#ifdef USE_HASH_TABLE_ACCUMULATE
static void hash_array_from_data(
- const BArrayInfo *info, const ubyte *data_slice, const size_t data_slice_len,
+ const BArrayInfo *info, const uchar *data_slice, const size_t data_slice_len,
hash_key *hash_array)
{
if (info->chunk_stride != 1) {
@@ -878,12 +873,12 @@ static void hash_accum_single(hash_key *hash_array, const size_t hash_array_len,
static hash_key key_from_chunk_ref(
const BArrayInfo *info, const BChunkRef *cref,
- /* avoid reallicating each time */
+ /* avoid reallocating each time */
hash_key *hash_store, const size_t hash_store_len)
{
/* in C, will fill in a reusable array */
BChunk *chunk = cref->link;
- BLI_assert(info->accum_read_ahead_bytes * info->chunk_stride);
+ BLI_assert((info->accum_read_ahead_bytes * info->chunk_stride) != 0);
if (info->accum_read_ahead_bytes <= chunk->data_len) {
hash_key key;
@@ -900,7 +895,7 @@ static hash_key key_from_chunk_ref(
key = hash_store[0];
/* cache the key */
- if (key == HASH_TABLE_KEY_UNSET) {
+ if (UNLIKELY(key == HASH_TABLE_KEY_UNSET)) {
key = HASH_TABLE_KEY_FALLBACK;
}
chunk->key = key;
@@ -930,12 +925,12 @@ static hash_key key_from_chunk_ref(
static const BChunkRef *table_lookup(
const BArrayInfo *info, BTableRef **table, const size_t table_len, const size_t i_table_start,
- const ubyte *data, const size_t data_len, const size_t offset, const hash_key *table_hash_array)
+ const uchar *data, const size_t data_len, const size_t offset, const hash_key *table_hash_array)
{
size_t size_left = data_len - offset;
hash_key key = table_hash_array[((offset - i_table_start) / info->chunk_stride)];
size_t key_index = (size_t)(key % (hash_key)table_len);
- for (BTableRef *tref = table[key_index]; tref; tref = tref->next) {
+ for (const BTableRef *tref = table[key_index]; tref; tref = tref->next) {
const BChunkRef *cref = tref->cref;
#ifdef USE_HASH_TABLE_KEY_CACHE
if (cref->link->key == key)
@@ -986,7 +981,7 @@ static hash_key key_from_chunk_ref(const BArrayInfo *info, const BChunkRef *cref
static const BChunkRef *table_lookup(
const BArrayInfo *info, BTableRef **table, const size_t table_len, const uint UNUSED(i_table_start),
- const ubyte *data, const size_t data_len, const size_t offset, const hash_key *UNUSED(table_hash_array))
+ const uchar *data, const size_t data_len, const size_t offset, const hash_key *UNUSED(table_hash_array))
{
const size_t data_hash_len = BCHUNK_HASH_LEN * info->chunk_stride; /* TODO, cache */
@@ -1026,7 +1021,7 @@ static const BChunkRef *table_lookup(
*/
static BChunkList *bchunk_list_from_data_merge(
const BArrayInfo *info, BArrayMemory *bs_mem,
- const ubyte *data, const size_t data_len_original,
+ const uchar *data, const size_t data_len_original,
const BChunkList *chunk_list_reference)
{
ASSERT_CHUNKLIST_SIZE(chunk_list_reference, chunk_list_reference->total_size);
@@ -1043,10 +1038,8 @@ static BChunkList *bchunk_list_from_data_merge(
size_t i_prev = 0;
#ifdef USE_FASTPATH_CHUNKS_FIRST
- bool full_match = false;
-
{
- full_match = true;
+ bool full_match = true;
const BChunkRef *cref = chunk_list_reference->chunk_refs.first;
while (i_prev < data_len_original) {
@@ -1434,7 +1427,7 @@ BArrayStore *BLI_array_store_create(
BArrayStore *bs = MEM_callocN(sizeof(BArrayStore), __func__);
bs->info.chunk_stride = stride;
- bs->info.chunk_count = chunk_count;
+ // bs->info.chunk_count = chunk_count;
bs->info.chunk_byte_size = chunk_count * stride;
#ifdef USE_MERGE_CHUNKS
@@ -1567,7 +1560,7 @@ BArrayState *BLI_array_store_state_add(
const void *data, const size_t data_len,
const BArrayState *state_reference)
{
- /* ensure we're aligned to the stride */
+ /* ensure we're aligned to the stride */
BLI_assert((data_len % bs->info.chunk_stride) == 0);
#ifdef USE_PARANOID_CHECKS
@@ -1580,7 +1573,7 @@ BArrayState *BLI_array_store_state_add(
if (state_reference) {
chunk_list = bchunk_list_from_data_merge(
&bs->info, &bs->memory,
- (const ubyte *)data, data_len,
+ (const uchar *)data, data_len,
/* re-use reference chunks */
state_reference->chunk_list);
}
@@ -1589,7 +1582,7 @@ BArrayState *BLI_array_store_state_add(
bchunk_list_fill_from_array(
&bs->info, &bs->memory,
chunk_list,
- (const ubyte *)data, data_len);
+ (const uchar *)data, data_len);
}
chunk_list->users += 1;
@@ -1656,7 +1649,7 @@ void BLI_array_store_state_data_get(
BLI_assert(data_test_len == state->chunk_list->total_size);
#endif
- ubyte *data_step = (ubyte *)data;
+ uchar *data_step = (uchar *)data;
for (BChunkRef *cref = state->chunk_list->chunk_refs.first; cref; cref = cref->next) {
BLI_assert(cref->link->users > 0);
memcpy(data_step, cref->link->data, cref->link->data_len);
diff --git a/source/blender/blenlib/intern/astar.c b/source/blender/blenlib/intern/astar.c
index 21d974de1c4..0020dbe4612 100644
--- a/source/blender/blenlib/intern/astar.c
+++ b/source/blender/blenlib/intern/astar.c
@@ -35,7 +35,7 @@
* in addition to distance already walked. This heuristic allows more efficiency
* in finding optimal path.
*
- * Implementation based on Wikipedia A* page [http://en.wikipedia.org/wiki/A*_search_algorithm].
+ * Implementation based on Wikipedia A* page [https://en.wikipedia.org/wiki/A*_search_algorithm].
*
* Note that most memory handling here is done through two different MemArena's. Those should also be used to allocate
* custom data needed to a specific use of A*.
diff --git a/source/blender/blenlib/intern/bitmap_draw_2d.c b/source/blender/blenlib/intern/bitmap_draw_2d.c
new file mode 100644
index 00000000000..e77e8cf40d0
--- /dev/null
+++ b/source/blender/blenlib/intern/bitmap_draw_2d.c
@@ -0,0 +1,336 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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: some of this file.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ * */
+
+/** \file blender/blenlib/intern/bitmap_draw_2d.c
+ * \ingroup bli
+ *
+ * Utility functions for primitive drawing operations.
+ */
+
+#include <limits.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_bitmap_draw_2d.h"
+
+#include "BLI_math_base.h"
+#include "BLI_sort.h"
+#include "BLI_utildefines.h"
+
+#include "BLI_strict_flags.h"
+
+/* -------------------------------------------------------------------- */
+/* Draw Line */
+
+/**
+ * Plot a line from \a p1 to \a p2 (inclusive).
+ *
+ * \note For clipped line drawing, see: http://stackoverflow.com/a/40902741/432509
+ */
+void BLI_bitmap_draw_2d_line_v2v2i(
+ const int p1[2], const int p2[2],
+ bool (*callback)(int, int, void *), void *userData)
+{
+ /* Bresenham's line algorithm. */
+ int x1 = p1[0];
+ int y1 = p1[1];
+ int x2 = p2[0];
+ int y2 = p2[1];
+
+ if (callback(x1, y1, userData) == 0) {
+ return;
+ }
+
+ /* if x1 == x2 or y1 == y2, then it does not matter what we set here */
+ const int sign_x = (x2 > x1) ? 1 : -1;
+ const int sign_y = (y2 > y1) ? 1 : -1;
+
+ const int delta_x = (sign_x == 1) ? (x2 - x1) : (x1 - x2);
+ const int delta_y = (sign_y == 1) ? (y2 - y1) : (y1 - y2);
+
+ const int delta_x_step = delta_x * 2;
+ const int delta_y_step = delta_y * 2;
+
+ if (delta_x >= delta_y) {
+ /* error may go below zero */
+ int error = delta_y_step - delta_x;
+
+ while (x1 != x2) {
+ if (error >= 0) {
+ if (error || (sign_x == 1)) {
+ y1 += sign_y;
+ error -= delta_x_step;
+ }
+ /* else do nothing */
+ }
+ /* else do nothing */
+
+ x1 += sign_x;
+ error += delta_y_step;
+
+ if (callback(x1, y1, userData) == 0) {
+ return;
+ }
+ }
+ }
+ else {
+ /* error may go below zero */
+ int error = delta_x_step - delta_y;
+
+ while (y1 != y2) {
+ if (error >= 0) {
+ if (error || (sign_y == 1)) {
+ x1 += sign_x;
+ error -= delta_y_step;
+ }
+ /* else do nothing */
+ }
+ /* else do nothing */
+
+ y1 += sign_y;
+ error += delta_x_step;
+
+ if (callback(x1, y1, userData) == 0) {
+ return;
+ }
+ }
+ }
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Draw Filled Polygon */
+
+/* sort edge-segments on y, then x axis */
+static int draw_poly_v2i_n__span_y_sort(const void *a_p, const void *b_p, void *verts_p)
+{
+ const int (*verts)[2] = verts_p;
+ const int *a = a_p;
+ const int *b = b_p;
+ const int *co_a = verts[a[0]];
+ const int *co_b = verts[b[0]];
+
+ if (co_a[1] < co_b[1]) {
+ return -1;
+ }
+ else if (co_a[1] > co_b[1]) {
+ return 1;
+ }
+ else if (co_a[0] < co_b[0]) {
+ return -1;
+ }
+ else if (co_a[0] > co_b[0]) {
+ return 1;
+ }
+ else {
+ /* co_a & co_b are identical, use the line closest to the x-min */
+ const int *co = co_a;
+ co_a = verts[a[1]];
+ co_b = verts[b[1]];
+ int ord = (((co_b[0] - co[0]) * (co_a[1] - co[1])) -
+ ((co_a[0] - co[0]) * (co_b[1] - co[1])));
+ if (ord > 0) {
+ return -1;
+ }
+ if (ord < 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Draws a filled polyon with support for self intersections.
+ *
+ * \param callback: Takes the x, y coords and x-span (\a x_end is not inclusive),
+ * note that \a x_end will always be greater than \a x, so we can use:
+ *
+ * \code{.c}
+ * do {
+ * func(x, y);
+ * } while (++x != x_end);
+ * \endcode
+ */
+void BLI_bitmap_draw_2d_poly_v2i_n(
+ const int xmin, const int ymin, const int xmax, const int ymax,
+ const int verts[][2], const int nr,
+ void (*callback)(int x, int x_end, int y, void *), void *userData)
+{
+ /* Originally by Darel Rex Finley, 2007.
+ * Optimized by Campbell Barton, 2016 to track sorted intersections. */
+
+ int (*span_y)[2] = MEM_mallocN(sizeof(*span_y) * (size_t)nr, __func__);
+ int span_y_len = 0;
+
+ for (int i_curr = 0, i_prev = nr - 1; i_curr < nr; i_prev = i_curr++) {
+ const int *co_prev = verts[i_prev];
+ const int *co_curr = verts[i_curr];
+
+ if (co_prev[1] != co_curr[1]) {
+ /* Any segments entirely above or below the area of interest can be skipped. */
+ if ((min_ii(co_prev[1], co_curr[1]) >= ymax) ||
+ (max_ii(co_prev[1], co_curr[1]) < ymin))
+ {
+ continue;
+ }
+
+ int *s = span_y[span_y_len++];
+ if (co_prev[1] < co_curr[1]) {
+ s[0] = i_prev;
+ s[1] = i_curr;
+ }
+ else {
+ s[0] = i_curr;
+ s[1] = i_prev;
+ }
+ }
+ }
+
+ BLI_qsort_r(span_y, (size_t)span_y_len, sizeof(*span_y), draw_poly_v2i_n__span_y_sort, (void *)verts);
+
+ struct NodeX {
+ int span_y_index;
+ int x;
+ } *node_x = MEM_mallocN(sizeof(*node_x) * (size_t)(nr + 1), __func__);
+ int node_x_len = 0;
+
+ int span_y_index = 0;
+ if (span_y_len != 0 && verts[span_y[0][0]][1] < ymin) {
+ while ((span_y_index < span_y_len) &&
+ (verts[span_y[span_y_index][0]][1] < ymin))
+ {
+ BLI_assert(verts[span_y[span_y_index][0]][1] <
+ verts[span_y[span_y_index][1]][1]);
+ if (verts[span_y[span_y_index][1]][1] >= ymin) {
+ struct NodeX *n = &node_x[node_x_len++];
+ n->span_y_index = span_y_index;
+ }
+ span_y_index += 1;
+ }
+ }
+
+ /* Loop through the rows of the image. */
+ for (int pixel_y = ymin; pixel_y < ymax; pixel_y++) {
+ bool is_sorted = true;
+ bool do_remove = false;
+
+ for (int i = 0, x_ix_prev = INT_MIN; i < node_x_len; i++) {
+ struct NodeX *n = &node_x[i];
+ const int *s = span_y[n->span_y_index];
+ const int *co_prev = verts[s[0]];
+ const int *co_curr = verts[s[1]];
+
+ BLI_assert(co_prev[1] < pixel_y && co_curr[1] >= pixel_y);
+
+ const double x = (co_prev[0] - co_curr[0]);
+ const double y = (co_prev[1] - co_curr[1]);
+ const double y_px = (pixel_y - co_curr[1]);
+ const int x_ix = (int)((double)co_curr[0] + ((y_px / y) * x));
+ n->x = x_ix;
+
+ if (is_sorted && (x_ix_prev > x_ix)) {
+ is_sorted = false;
+ }
+ if (do_remove == false && co_curr[1] == pixel_y) {
+ do_remove = true;
+ }
+ x_ix_prev = x_ix;
+ }
+
+ /* Sort the nodes, via a simple "Bubble" sort. */
+ if (is_sorted == false) {
+ int i = 0;
+ const int node_x_end = node_x_len - 1;
+ while (i < node_x_end) {
+ if (node_x[i].x > node_x[i + 1].x) {
+ SWAP(struct NodeX, node_x[i], node_x[i + 1]);
+ if (i != 0) {
+ i -= 1;
+ }
+ }
+ else {
+ i += 1;
+ }
+ }
+ }
+
+ /* Fill the pixels between node pairs. */
+ for (int i = 0; i < node_x_len; i += 2) {
+ int x_src = node_x[i].x;
+ int x_dst = node_x[i + 1].x;
+
+ if (x_src >= xmax) {
+ break;
+ }
+
+ if (x_dst > xmin) {
+ if (x_src < xmin) {
+ x_src = xmin;
+ }
+ if (x_dst > xmax) {
+ x_dst = xmax;
+ }
+ /* for single call per x-span */
+ if (x_src < x_dst) {
+ callback(x_src - xmin, x_dst - xmin, pixel_y - ymin, userData);
+ }
+ }
+ }
+
+ /* Clear finalized nodes in one pass, only when needed
+ * (avoids excessive array-resizing). */
+ if (do_remove == true) {
+ int i_dst = 0;
+ for (int i_src = 0; i_src < node_x_len; i_src += 1) {
+ const int *s = span_y[node_x[i_src].span_y_index];
+ const int *co = verts[s[1]];
+ if (co[1] != pixel_y) {
+ if (i_dst != i_src) {
+ /* x is initialized for the next pixel_y (no need to adjust here) */
+ node_x[i_dst].span_y_index = node_x[i_src].span_y_index;
+ }
+ i_dst += 1;
+ }
+ }
+ node_x_len = i_dst;
+ }
+
+ /* Scan for new x-nodes */
+ while ((span_y_index < span_y_len) &&
+ (verts[span_y[span_y_index][0]][1] == pixel_y))
+ {
+ /* note, node_x these are just added at the end,
+ * not ideal but sorting once will resolve. */
+
+ /* x is initialized for the next pixel_y */
+ struct NodeX *n = &node_x[node_x_len++];
+ n->span_y_index = span_y_index;
+ span_y_index += 1;
+ }
+ }
+
+ MEM_freeN(span_y);
+ MEM_freeN(node_x);
+}
diff --git a/source/blender/blenlib/intern/dynlib.c b/source/blender/blenlib/intern/dynlib.c
index b47c2ee60a6..51b91fb360f 100644
--- a/source/blender/blenlib/intern/dynlib.c
+++ b/source/blender/blenlib/intern/dynlib.c
@@ -50,7 +50,7 @@ struct DynamicLibrary {
#include "utf_winfunc.h"
#include "utfconv.h"
-DynamicLibrary *BLI_dynlib_open(char *name)
+DynamicLibrary *BLI_dynlib_open(const char *name)
{
DynamicLibrary *lib;
void *handle;
@@ -106,7 +106,7 @@ void BLI_dynlib_close(DynamicLibrary *lib)
#include <dlfcn.h>
-DynamicLibrary *BLI_dynlib_open(char *name)
+DynamicLibrary *BLI_dynlib_open(const char *name)
{
DynamicLibrary *lib;
void *handle = dlopen(name, RTLD_LAZY);
diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c
index db4b3bcf20c..1df7f6f81e4 100644
--- a/source/blender/blenlib/intern/fileops.c
+++ b/source/blender/blenlib/intern/fileops.c
@@ -42,9 +42,6 @@
#include "zlib.h"
#ifdef WIN32
-# ifdef __MINGW32__
-# include <ctype.h>
-# endif
# include <io.h>
# include "BLI_winstuff.h"
# include "BLI_callbacks.h"
@@ -265,7 +262,7 @@ void *BLI_gzopen(const char *filename, const char *mode)
/* temporary #if until we update all libraries to 1.2.7
* for correct wide char path handling */
-#if ZLIB_VERNUM >= 0x1270 && !defined(FREE_WINDOWS)
+#if ZLIB_VERNUM >= 0x1270
UTF16_ENCODE(filename);
gzfile = gzopen_w(filename_16, mode);
diff --git a/source/blender/blenlib/intern/hash_mm2a.c b/source/blender/blenlib/intern/hash_mm2a.c
index af6ef4f355f..e8ca9244f25 100644
--- a/source/blender/blenlib/intern/hash_mm2a.c
+++ b/source/blender/blenlib/intern/hash_mm2a.c
@@ -36,6 +36,8 @@
* for temporary data.
*/
+#include "BLI_compiler_attrs.h"
+
#include "BLI_hash_mm2a.h" /* own include */
/* Helpers. */
@@ -128,10 +130,10 @@ uint32_t BLI_hash_mm2(const unsigned char *data, size_t len, uint32_t seed)
switch (len) {
case 3:
h ^= data[2] << 16;
- /* fall through */
+ ATTR_FALLTHROUGH;
case 2:
h ^= data[1] << 8;
- /* fall through */
+ ATTR_FALLTHROUGH;
case 1:
h ^= data[0];
h *= MM2A_M;
diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c
index ebee2c7941c..0a6d575c7d6 100644
--- a/source/blender/blenlib/intern/listbase.c
+++ b/source/blender/blenlib/intern/listbase.c
@@ -170,6 +170,34 @@ void BLI_listbase_swaplinks(ListBase *listbase, void *vlinka, void *vlinkb)
}
/**
+ * Swaps \a vlinka and \a vlinkb from their respective lists. Assumes they are both already in their lista!
+ */
+void BLI_listbases_swaplinks(ListBase *listbasea, ListBase *listbaseb, void *vlinka, void *vlinkb)
+{
+ Link *linka = vlinka;
+ Link *linkb = vlinkb;
+ Link linkc = {NULL};
+
+ if (!linka || !linkb) {
+ return;
+ }
+
+ /* Temporary link to use as placeholder of the links positions */
+ BLI_insertlinkafter(listbasea, linka, &linkc);
+
+ /* Bring linka into linkb position */
+ BLI_remlink(listbasea, linka);
+ BLI_insertlinkafter(listbaseb, linkb, linka);
+
+ /* Bring linkb into linka position */
+ BLI_remlink(listbaseb, linkb);
+ BLI_insertlinkafter(listbasea, &linkc, linkb);
+
+ /* Remove temporary link */
+ BLI_remlink(listbasea, &linkc);
+}
+
+/**
* Removes the head from \a listbase and returns it.
*/
void *BLI_pophead(ListBase *listbase)
@@ -344,6 +372,78 @@ void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
/**
+ * Insert a link in place of another, without changing it's position in the list.
+ *
+ * Puts `vnewlink` in the position of `vreplacelink`, removing `vreplacelink`.
+ * - `vreplacelink` *must* be in the list.
+ * - `vnewlink` *must not* be in the list.
+ */
+void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlink)
+{
+ Link *l_old = vreplacelink;
+ Link *l_new = vnewlink;
+
+ /* update adjacent links */
+ if (l_old->next != NULL) {
+ l_old->next->prev = l_new;
+ }
+ if (l_old->prev != NULL) {
+ l_old->prev->next = l_new;
+ }
+
+ /* set direct links */
+ l_new->next = l_old->next;
+ l_new->prev = l_old->prev;
+
+ /* update list */
+ if (listbase->first == l_old) {
+ listbase->first = l_new;
+ }
+ if (listbase->last == l_old) {
+ listbase->last = l_new;
+ }
+}
+
+/**
+ * Reinsert \a vlink relative to its current position but offset by \a step. Doesn't move
+ * item if new position would exceed list (could optionally move to head/tail).
+ *
+ * \param step: Absolute value defines step size, sign defines direction. E.g pass -1
+ * to move \a vlink before previous, or 1 to move behind next.
+ * \return If position of \a vlink has changed.
+ */
+bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step)
+{
+ Link *link = vlink;
+ Link *hook = link;
+ const bool is_up = step < 0;
+
+ if (step == 0) {
+ return false;
+ }
+ BLI_assert(BLI_findindex(listbase, link) != -1);
+
+ /* find link to insert before/after */
+ for (int i = 0; i < ABS(step); i++) {
+ hook = is_up ? hook->prev : hook->next;
+ if (!hook) {
+ return false;
+ }
+ }
+
+ /* reinsert link */
+ BLI_remlink(listbase, vlink);
+ if (is_up) {
+ BLI_insertlinkbefore(listbase, hook, vlink);
+ }
+ else {
+ BLI_insertlinkafter(listbase, hook, vlink);
+ }
+ return true;
+}
+
+
+/**
* Removes and disposes of the entire contents of listbase using direct free(3).
*/
void BLI_freelist(ListBase *listbase)
@@ -592,7 +692,7 @@ void *BLI_rfindptr(const ListBase *listbase, const void *ptr, const int offset)
}
/**
- * Returns the 1-based index of the first element of listbase which contains the specified
+ * Returns the 0-based index of the first element of listbase which contains the specified
* null-terminated string at the specified offset, or -1 if not found.
*/
int BLI_findstringindex(const ListBase *listbase, const char *id, const int offset)
diff --git a/source/blender/blenlib/intern/math_color.c b/source/blender/blenlib/intern/math_color.c
index 6d7d24c79c3..cb39134af45 100644
--- a/source/blender/blenlib/intern/math_color.c
+++ b/source/blender/blenlib/intern/math_color.c
@@ -359,8 +359,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)
diff --git a/source/blender/blenlib/intern/math_color_blend_inline.c b/source/blender/blenlib/intern/math_color_blend_inline.c
index 048ab71c6dc..dc3874f83a2 100644
--- a/source/blender/blenlib/intern/math_color_blend_inline.c
+++ b/source/blender/blenlib/intern/math_color_blend_inline.c
@@ -444,7 +444,7 @@ MINLINE void blend_color_vividlight_byte(unsigned char dst[4], unsigned const ch
else if (src2[i] == 0) {
temp = 0;
}
- else if (src2[i] > 127) {
+ else if (src2[i] > 127) {
temp = min_ii(((src1[i]) * 255) / (2 * (255 - src2[i])), 255);
}
else {
diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c
index abb8ff35a45..bc3a1ee3e90 100644
--- a/source/blender/blenlib/intern/math_color_inline.c
+++ b/source/blender/blenlib/intern/math_color_inline.c
@@ -239,6 +239,14 @@ MINLINE void rgba_char_args_set(char col[4], const char r, const char g, const c
col[3] = a;
}
+MINLINE void rgba_float_args_set(float col[4], const float r, const float g, const float b, const float a)
+{
+ col[0] = r;
+ col[1] = g;
+ col[2] = b;
+ col[3] = a;
+}
+
MINLINE void rgba_char_args_test_set(char col[4], const char r, const char g, const char b, const char a)
{
if (col[3] == 0) {
@@ -269,7 +277,7 @@ MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack)
/**
* ITU-R BT.709 primaries
- * http://en.wikipedia.org/wiki/Relative_luminance
+ * https://en.wikipedia.org/wiki/Relative_luminance
*
* Real values are:
* ``Y = 0.2126390059(R) + 0.7151686788(G) + 0.0721923154(B)``
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index effbe3f9770..7e26a99c93d 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -37,20 +37,6 @@
/********************************** Polygons *********************************/
-void cent_tri_v3(float cent[3], const float v1[3], const float v2[3], const float v3[3])
-{
- cent[0] = (v1[0] + v2[0] + v3[0]) / 3.0f;
- cent[1] = (v1[1] + v2[1] + v3[1]) / 3.0f;
- cent[2] = (v1[2] + v2[2] + v3[2]) / 3.0f;
-}
-
-void cent_quad_v3(float cent[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3])
-{
- cent[0] = 0.25f * (v1[0] + v2[0] + v3[0] + v4[0]);
- cent[1] = 0.25f * (v1[1] + v2[1] + v3[1] + v4[1]);
- cent[2] = 0.25f * (v1[2] + v2[2] + v3[2] + v4[2]);
-}
-
void cross_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
{
float n1[3], n2[3];
@@ -586,8 +572,8 @@ float dist_squared_to_ray_v3(
}
/**
* 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).
- * \param depth: the distance of r_point projection on ray to the ray_origin.
+ * \param r_point: Is the point on segment closest to ray (or to ray_origin if the ray and the segment are parallel).
+ * \param r_depth: the distance of r_point projection on ray to the ray_origin.
*/
float dist_squared_ray_to_seg_v3(
const float ray_origin[3], const float ray_direction[3],
@@ -1842,7 +1828,7 @@ bool isect_tri_tri_epsilon_v3(
(range[0].max < range[1].min)) == 0)
{
if (r_i1 && r_i2) {
- project_plane_v3_v3v3(plane_co, plane_co, plane_no);
+ project_plane_normalized_v3_v3v3(plane_co, plane_co, plane_no);
madd_v3_v3v3fl(r_i1, plane_co, plane_no, max_ff(range[0].min, range[1].min));
madd_v3_v3v3fl(r_i2, plane_co, plane_no, min_ff(range[0].max, range[1].max));
}
@@ -2323,222 +2309,32 @@ bool isect_ray_aabb_v3(
return true;
}
-void dist_squared_ray_to_aabb_v3_precalc(
- struct NearestRayToAABB_Precalc *data,
- const float ray_origin[3], const float ray_direction[3])
-{
- float dir_sq[3];
-
- for (int i = 0; i < 3; i++) {
- data->ray_origin[i] = ray_origin[i];
- data->ray_direction[i] = ray_direction[i];
- data->ray_inv_dir[i] = (data->ray_direction[i] != 0.0f) ? (1.0f / data->ray_direction[i]) : FLT_MAX;
- /* It has to be a function of `ray_inv_dir`,
- * since the division of 1 by 0.0f, can be -inf or +inf */
- data->sign[i] = (data->ray_inv_dir[i] < 0.0f);
-
- dir_sq[i] = SQUARE(data->ray_direction[i]);
- }
-
- /* `diag_sq` Length square of each face diagonal */
- float diag_sq[3] = {
- dir_sq[1] + dir_sq[2],
- dir_sq[0] + dir_sq[2],
- dir_sq[0] + dir_sq[1],
- };
- data->idiag_sq[0] = (diag_sq[0] > FLT_EPSILON) ? (1.0f / diag_sq[0]) : FLT_MAX;
- data->idiag_sq[1] = (diag_sq[1] > FLT_EPSILON) ? (1.0f / diag_sq[1]) : FLT_MAX;
- data->idiag_sq[2] = (diag_sq[2] > FLT_EPSILON) ? (1.0f / diag_sq[2]) : FLT_MAX;
-
- data->cdot_axis[0] = data->ray_direction[0] * data->idiag_sq[0];
- data->cdot_axis[1] = data->ray_direction[1] * data->idiag_sq[1];
- data->cdot_axis[2] = data->ray_direction[2] * data->idiag_sq[2];
-}
-
-/**
- * Returns the squared distance from a ray to a bound-box `AABB`.
- * It is based on `fast_ray_nearest_hit` solution to obtain
- * the coordinates of the nearest edge of Bound Box to the ray
+/*
+ * Test a bounding box (AABB) for ray intersection
+ * assumes the ray is already local to the boundbox space
*/
-float dist_squared_ray_to_aabb_v3(
- const struct NearestRayToAABB_Precalc *data,
+bool isect_ray_aabb_v3_simple(
+ const float orig[3], const float dir[3],
const float bb_min[3], const float bb_max[3],
- bool r_axis_closest[3])
-{
- /* `tmin` is a vector that has the smaller distances to each of the
- * infinite planes of the `AABB` faces (hit in nearest face X plane,
- * nearest face Y plane and nearest face Z plane) */
- float local_bvmin[3], local_bvmax[3];
-
- if (data->sign[0] == 0) {
- local_bvmin[0] = bb_min[0] - data->ray_origin[0];
- local_bvmax[0] = bb_max[0] - data->ray_origin[0];
- }
- else {
- local_bvmin[0] = bb_max[0] - data->ray_origin[0];
- local_bvmax[0] = bb_min[0] - data->ray_origin[0];
- }
-
- if (data->sign[1] == 0) {
- local_bvmin[1] = bb_min[1] - data->ray_origin[1];
- local_bvmax[1] = bb_max[1] - data->ray_origin[1];
- }
- else {
- local_bvmin[1] = bb_max[1] - data->ray_origin[1];
- local_bvmax[1] = bb_min[1] - data->ray_origin[1];
- }
-
- if (data->sign[2] == 0) {
- local_bvmin[2] = bb_min[2] - data->ray_origin[2];
- local_bvmax[2] = bb_max[2] - data->ray_origin[2];
- }
- else {
- local_bvmin[2] = bb_max[2] - data->ray_origin[2];
- local_bvmax[2] = bb_min[2] - data->ray_origin[2];
- }
-
- const float tmin[3] = {
- local_bvmin[0] * data->ray_inv_dir[0],
- local_bvmin[1] * data->ray_inv_dir[1],
- local_bvmin[2] * data->ray_inv_dir[2],
- };
-
- /* `tmax` is a vector that has the longer distances to each of the
- * infinite planes of the `AABB` faces (hit in farthest face X plane,
- * farthest face Y plane and farthest face Z plane) */
- const float tmax[3] = {
- local_bvmax[0] * data->ray_inv_dir[0],
- local_bvmax[1] * data->ray_inv_dir[1],
- local_bvmax[2] * data->ray_inv_dir[2],
- };
- /* `v1` and `v3` is be the coordinates of the nearest `AABB` edge to the ray*/
- float v1[3], v2[3];
- /* `rtmin` is the highest value of the smaller distances. == max_axis_v3(tmin)
- * `rtmax` is the lowest value of longer distances. == min_axis_v3(tmax)*/
- float rtmin, rtmax, mul, rdist;
- /* `main_axis` is the axis equivalent to edge close to the ray */
- int main_axis;
-
- r_axis_closest[0] = false;
- r_axis_closest[1] = false;
- r_axis_closest[2] = false;
-
- /* *** min_axis_v3(tmax) *** */
- if ((tmax[0] <= tmax[1]) && (tmax[0] <= tmax[2])) {
- // printf("# Hit in X %s\n", data->sign[0] ? "min", "max");
- rtmax = tmax[0];
- v1[0] = v2[0] = local_bvmax[0];
- mul = local_bvmax[0] * data->ray_direction[0];
- main_axis = 3;
- r_axis_closest[0] = data->sign[0];
- }
- else if ((tmax[1] <= tmax[0]) && (tmax[1] <= tmax[2])) {
- // printf("# Hit in Y %s\n", data->sign[1] ? "min", "max");
- rtmax = tmax[1];
- v1[1] = v2[1] = local_bvmax[1];
- mul = local_bvmax[1] * data->ray_direction[1];
- main_axis = 2;
- r_axis_closest[1] = data->sign[1];
- }
- else {
- // printf("# Hit in Z %s\n", data->sign[2] ? "min", "max");
- rtmax = tmax[2];
- v1[2] = v2[2] = local_bvmax[2];
- mul = local_bvmax[2] * data->ray_direction[2];
- main_axis = 1;
- r_axis_closest[2] = data->sign[2];
- }
-
- /* *** max_axis_v3(tmin) *** */
- if ((tmin[0] >= tmin[1]) && (tmin[0] >= tmin[2])) {
- // printf("# To X %s\n", data->sign[0] ? "max", "min");
- rtmin = tmin[0];
- v1[0] = v2[0] = local_bvmin[0];
- mul += local_bvmin[0] * data->ray_direction[0];
- main_axis -= 3;
- r_axis_closest[0] = !data->sign[0];
- }
- else if ((tmin[1] >= tmin[0]) && (tmin[1] >= tmin[2])) {
- // printf("# To Y %s\n", data->sign[1] ? "max", "min");
- rtmin = tmin[1];
- v1[1] = v2[1] = local_bvmin[1];
- mul += local_bvmin[1] * data->ray_direction[1];
- main_axis -= 1;
- r_axis_closest[1] = !data->sign[1];
- }
- else {
- // printf("# To Z %s\n", data->sign[2] ? "max", "min");
- rtmin = tmin[2];
- v1[2] = v2[2] = local_bvmin[2];
- mul += local_bvmin[2] * data->ray_direction[2];
- main_axis -= 2;
- r_axis_closest[2] = !data->sign[2];
- }
- /* *** end min/max axis *** */
-
-
- /* `if rtmax < 0`, the whole `AABB` is behing us */
- if ((rtmax < 0.0f) && (rtmin < 0.0f)) {
- return FLT_MAX;
- }
-
- if (main_axis < 0) {
- main_axis += 3;
- }
-
- if (data->sign[main_axis] == 0) {
- v1[main_axis] = local_bvmin[main_axis];
- v2[main_axis] = local_bvmax[main_axis];
- }
- else {
- v1[main_axis] = local_bvmax[main_axis];
- v2[main_axis] = local_bvmin[main_axis];
- }
-
- /* if rtmin < rtmax, ray intersect `AABB` */
- if (rtmin <= rtmax) {
- const float proj = rtmin * data->ray_direction[main_axis];
- rdist = 0.0f;
- r_axis_closest[main_axis] = (proj - v1[main_axis]) < (v2[main_axis] - proj);
- }
+ float *tmin, float *tmax)
+{
+ double t[7];
+ float hit_dist[2];
+ t[1] = (double)(bb_min[0] - orig[0]) / dir[0];
+ t[2] = (double)(bb_max[0] - orig[0]) / dir[0];
+ t[3] = (double)(bb_min[1] - orig[1]) / dir[1];
+ t[4] = (double)(bb_max[1] - orig[1]) / dir[1];
+ t[5] = (double)(bb_min[2] - orig[2]) / dir[2];
+ t[6] = (double)(bb_max[2] - orig[2]) / dir[2];
+ hit_dist[0] = (float)fmax(fmax(fmin(t[1], t[2]), fmin(t[3], t[4])), fmin(t[5], t[6]));
+ hit_dist[1] = (float)fmin(fmin(fmax(t[1], t[2]), fmax(t[3], t[4])), fmax(t[5], t[6]));
+ if ((hit_dist[1] < 0 || hit_dist[0] > hit_dist[1]))
+ return false;
else {
- /* `proj` equals to nearest point on the ray closest to the edge `v1 v2` of the `AABB`. */
- const float proj = mul * data->cdot_axis[main_axis];
- float depth;
- if (v1[main_axis] > proj) { /* the nearest point to the ray is the point v1 */
- /* `depth` is equivalent the distance from the origin to the point v1,
- * Here's a faster way to calculate the dot product of v1 and ray
- * (depth = dot_v3v3(v1, data->ray.direction))*/
- depth = mul + data->ray_direction[main_axis] * v1[main_axis];
- rdist = len_squared_v3(v1) - SQUARE(depth);
- r_axis_closest[main_axis] = true;
- }
- else if (v2[main_axis] < proj) { /* the nearest point of the ray is the point v2 */
- depth = mul + data->ray_direction[main_axis] * v2[main_axis];
- rdist = len_squared_v3(v2) - SQUARE(depth);
- r_axis_closest[main_axis] = false;
- }
- else { /* the nearest point of the ray is on the edge of the `AABB`. */
- float v[2];
- mul *= data->idiag_sq[main_axis];
- if (main_axis == 0) {
- v[0] = (mul * data->ray_direction[1]) - v1[1];
- v[1] = (mul * data->ray_direction[2]) - v1[2];
- }
- else if (main_axis == 1) {
- v[0] = (mul * data->ray_direction[0]) - v1[0];
- v[1] = (mul * data->ray_direction[2]) - v1[2];
- }
- else {
- v[0] = (mul * data->ray_direction[0]) - v1[0];
- v[1] = (mul * data->ray_direction[1]) - v1[1];
- }
- rdist = len_squared_v2(v);
- r_axis_closest[main_axis] = (proj - v1[main_axis]) < (v2[main_axis] - proj);
- }
+ if (tmin) *tmin = hit_dist[0];
+ if (tmax) *tmax = hit_dist[1];
+ return true;
}
-
- return rdist;
}
/* find closest point to p on line through (l1, l2) and return lambda,
@@ -2885,142 +2681,6 @@ bool clip_segment_v3_plane_n(
return true;
}
-void plot_line_v2v2i(const int p1[2], const int p2[2], bool (*callback)(int, int, void *), void *userData)
-{
- int x1 = p1[0];
- int y1 = p1[1];
- int x2 = p2[0];
- int y2 = p2[1];
-
- signed char ix;
- signed char iy;
-
- /* if x1 == x2 or y1 == y2, then it does not matter what we set here */
- int delta_x = (x2 > x1 ? ((void)(ix = 1), x2 - x1) : ((void)(ix = -1), x1 - x2)) << 1;
- int delta_y = (y2 > y1 ? ((void)(iy = 1), y2 - y1) : ((void)(iy = -1), y1 - y2)) << 1;
-
- if (callback(x1, y1, userData) == 0) {
- return;
- }
-
- if (delta_x >= delta_y) {
- /* error may go below zero */
- int error = delta_y - (delta_x >> 1);
-
- while (x1 != x2) {
- if (error >= 0) {
- if (error || (ix > 0)) {
- y1 += iy;
- error -= delta_x;
- }
- /* else do nothing */
- }
- /* else do nothing */
-
- x1 += ix;
- error += delta_y;
-
- if (callback(x1, y1, userData) == 0) {
- return;
- }
- }
- }
- else {
- /* error may go below zero */
- int error = delta_x - (delta_y >> 1);
-
- while (y1 != y2) {
- if (error >= 0) {
- if (error || (iy > 0)) {
- x1 += ix;
- error -= delta_y;
- }
- /* else do nothing */
- }
- /* else do nothing */
-
- y1 += iy;
- error += delta_x;
-
- if (callback(x1, y1, userData) == 0) {
- return;
- }
- }
- }
-}
-
-/**
- * \param callback: Takes the x, y coords and x-span (\a x_end is not inclusive),
- * note that \a x_end will always be greater than \a x, so we can use:
- *
- * \code{.c}
- * do {
- * func(x, y);
- * } while (++x != x_end);
- * \endcode
- */
-void fill_poly_v2i_n(
- const int xmin, const int ymin, const int xmax, const int ymax,
- const int verts[][2], const int nr,
- void (*callback)(int x, int x_end, int y, void *), void *userData)
-{
- /* originally by Darel Rex Finley, 2007 */
-
- int nodes, pixel_y, i, j, swap;
- int *node_x = MEM_mallocN(sizeof(*node_x) * (size_t)(nr + 1), __func__);
-
- /* Loop through the rows of the image. */
- for (pixel_y = ymin; pixel_y < ymax; pixel_y++) {
-
- /* Build a list of nodes. */
- nodes = 0; j = nr - 1;
- for (i = 0; i < nr; i++) {
- if ((verts[i][1] < pixel_y && verts[j][1] >= pixel_y) ||
- (verts[j][1] < pixel_y && verts[i][1] >= pixel_y))
- {
- node_x[nodes++] = (int)(verts[i][0] +
- ((double)(pixel_y - verts[i][1]) / (verts[j][1] - verts[i][1])) *
- (verts[j][0] - verts[i][0]));
- }
- j = i;
- }
-
- /* Sort the nodes, via a simple "Bubble" sort. */
- i = 0;
- while (i < nodes - 1) {
- if (node_x[i] > node_x[i + 1]) {
- SWAP_TVAL(swap, node_x[i], node_x[i + 1]);
- if (i) i--;
- }
- else {
- i++;
- }
- }
-
- /* Fill the pixels between node pairs. */
- for (i = 0; i < nodes; i += 2) {
- if (node_x[i] >= xmax) break;
- if (node_x[i + 1] > xmin) {
- if (node_x[i ] < xmin) node_x[i ] = xmin;
- if (node_x[i + 1] > xmax) node_x[i + 1] = xmax;
-
-#if 0
- /* for many x/y calls */
- for (j = node_x[i]; j < node_x[i + 1]; j++) {
- callback(j - xmin, pixel_y - ymin, userData);
- }
-#else
- /* for single call per x-span */
- if (node_x[i] < node_x[i + 1]) {
- callback(node_x[i] - xmin, node_x[i + 1] - xmin, pixel_y - ymin, userData);
- }
-#endif
- }
- }
- }
- MEM_freeN(node_x);
-}
-
/****************************** Axis Utils ********************************/
/**
@@ -3100,7 +2760,15 @@ static bool barycentric_weights(const float v1[3], const float v2[3], const floa
}
}
-void interp_weights_face_v3(float w[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float co[3])
+void interp_weights_tri_v3(float w[3], const float v1[3], const float v2[3], const float v3[3], const float co[3])
+{
+ float n[3];
+
+ normal_tri_v3(n, v1, v2, v3);
+ barycentric_weights(v1, v2, v3, co, n, w);
+}
+
+void interp_weights_quad_v3(float w[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float co[3])
{
float w2[3];
@@ -3113,7 +2781,7 @@ void interp_weights_face_v3(float w[4], const float v1[3], const float v2[3], co
w[1] = 1.0f;
else if (equals_v3v3(co, v3))
w[2] = 1.0f;
- else if (v4 && equals_v3v3(co, v4))
+ else if (equals_v3v3(co, v4))
w[3] = 1.0f;
else {
/* otherwise compute barycentric interpolation weights */
@@ -3121,39 +2789,28 @@ void interp_weights_face_v3(float w[4], const float v1[3], const float v2[3], co
bool degenerate;
sub_v3_v3v3(n1, v1, v3);
- if (v4) {
- sub_v3_v3v3(n2, v2, v4);
- }
- else {
- sub_v3_v3v3(n2, v2, v3);
- }
+ sub_v3_v3v3(n2, v2, v4);
cross_v3_v3v3(n, n1, n2);
- /* OpenGL seems to split this way, so we do too */
- if (v4) {
- degenerate = barycentric_weights(v1, v2, v4, co, n, w);
- SWAP(float, w[2], w[3]);
+ degenerate = barycentric_weights(v1, v2, v4, co, n, w);
+ SWAP(float, w[2], w[3]);
- if (degenerate || (w[0] < 0.0f)) {
- /* if w[1] is negative, co is on the other side of the v1-v3 edge,
- * so we interpolate using the other triangle */
- degenerate = barycentric_weights(v2, v3, v4, co, n, w2);
+ if (degenerate || (w[0] < 0.0f)) {
+ /* if w[1] is negative, co is on the other side of the v1-v3 edge,
+ * so we interpolate using the other triangle */
+ degenerate = barycentric_weights(v2, v3, v4, co, n, w2);
- if (!degenerate) {
- w[0] = 0.0f;
- w[1] = w2[0];
- w[2] = w2[1];
- w[3] = w2[2];
- }
+ if (!degenerate) {
+ w[0] = 0.0f;
+ w[1] = w2[0];
+ w[2] = w2[1];
+ w[3] = w2[2];
}
}
- else {
- barycentric_weights(v1, v2, v3, co, n, w);
- }
}
}
-void interp_weights_face_v3_index(int tri[3], float w[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float co[3])
+void interp_weights_quad_v3_index(int tri[3], float w[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float co[3])
{
float w2[3];
@@ -3259,6 +2916,9 @@ bool barycentric_coords_v2(const float v1[2], const float v2[2], const float v3[
/**
* \note: using #cross_tri_v2 means locations outside the triangle are correctly weighted
+ *
+ * \note This is *exactly* the same calculation as #resolve_tri_uv_v2,
+ * although it has double precision and is used for texture baking, so keep both.
*/
void barycentric_weights_v2(const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
{
@@ -3298,9 +2958,11 @@ void barycentric_weights_v2_persp(const float v1[4], const float v2[4], const fl
}
}
-/* same as #barycentric_weights_v2 but works with a quad,
+/**
+ * same as #barycentric_weights_v2 but works with a quad,
* note: untested for values outside the quad's bounds
- * this is #interp_weights_poly_v2 expanded for quads only */
+ * this is #interp_weights_poly_v2 expanded for quads only
+ */
void barycentric_weights_v2_quad(const float v1[2], const float v2[2], const float v3[2], const float v4[2],
const float co[2], float w[4])
{
@@ -3753,6 +3415,8 @@ void interp_cubic_v3(float x[3], float v[3], const float x1[3], const float v1[3
* Barycentric reverse
*
* Compute coordinates (u, v) for point \a st with respect to triangle (\a st0, \a st1, \a st2)
+ *
+ * \note same basic result as #barycentric_weights_v2, see it's comment for details.
*/
void resolve_tri_uv_v2(float r_uv[2], const float st[2],
const float st0[2], const float st1[2], const float st2[2])
@@ -3964,6 +3628,9 @@ void interp_barycentric_tri_v3(float data[3][3], float u, float v, float res[3])
/***************************** View & Projection *****************************/
+/**
+ * Matches `glOrtho` result.
+ */
void orthographic_m4(float matrix[4][4], const float left, const float right, const float bottom, const float top,
const float nearClip, const float farClip)
{
@@ -3984,6 +3651,9 @@ void orthographic_m4(float matrix[4][4], const float left, const float right, co
matrix[3][2] = -(farClip + nearClip) / Zdelta;
}
+/**
+ * Matches `glFrustum` result.
+ */
void perspective_m4(float mat[4][4], const float left, const float right, const float bottom, const float top,
const float nearClip, const float farClip)
{
@@ -4118,10 +3788,9 @@ void lookat_m4(float mat[4][4], float vx, float vy, float vz, float px, float py
float sine, cosine, hyp, hyp1, dx, dy, dz;
float mat1[4][4];
- unit_m4(mat);
unit_m4(mat1);
- rotate_m4(mat, 'Z', -twist);
+ axis_angle_to_mat4_single(mat, 'Z', -twist);
dx = px - vx;
dy = py - vy;
@@ -4261,6 +3930,26 @@ void map_to_sphere(float *r_u, float *r_v, const float x, const float y, const f
}
}
+void map_to_plane_v2_v3v3(float r_co[2], const float co[3], const float no[3])
+{
+ float target[3] = {0.0f, 0.0f, 1.0f};
+ float axis[3];
+
+ cross_v3_v3v3(axis, no, target);
+ normalize_v3(axis);
+
+ map_to_plane_axis_angle_v2_v3v3fl(r_co, co, axis, angle_normalized_v3v3(no, target));
+}
+
+void map_to_plane_axis_angle_v2_v3v3fl(float r_co[2], const float co[3], const float axis[3], const float angle)
+{
+ float tmp[3];
+
+ rotate_normalized_v3_v3v3fl(tmp, co, axis, angle);
+
+ copy_v2_v2(r_co, tmp);
+}
+
/********************************* Normals **********************************/
void accumulate_vertex_normals_tri(
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index c9c61d5c878..7677d545e07 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -74,23 +74,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 +105,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 +131,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 +177,107 @@ 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] */
+ 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];
- 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];
+ 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];
- 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];
+ 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];
- 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];
+ 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];
+}
+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 +293,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 +316,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_);
@@ -434,7 +479,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 +492,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 +507,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 +517,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 +525,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 +533,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 +549,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 +559,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 +570,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 +580,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 +589,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 +601,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 +618,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 +641,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 +650,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 +658,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 +678,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 +742,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 +752,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 +761,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 +770,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 +779,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 +788,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 +804,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 +840,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;
@@ -830,7 +884,7 @@ bool invert_m4(float m[4][4])
* 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;
@@ -908,7 +962,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);
@@ -924,7 +978,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]);
@@ -965,7 +1019,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);
@@ -987,7 +1041,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))
@@ -1165,7 +1220,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;
@@ -1179,7 +1234,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;
@@ -1194,7 +1249,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;
@@ -1209,7 +1264,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;
@@ -1224,7 +1279,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];
@@ -1252,7 +1307,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);
@@ -1274,14 +1329,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++) {
@@ -1310,7 +1365,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++) {
@@ -1319,7 +1374,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++) {
@@ -1329,7 +1384,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];
@@ -1338,7 +1393,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];
@@ -1354,7 +1409,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;
@@ -1420,7 +1475,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;
@@ -1488,14 +1543,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]);
@@ -1505,7 +1560,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];
@@ -1514,7 +1569,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 +1578,16 @@ float mat4_to_scale(float mat[4][4])
return len_v3(unit_vec);
}
-void mat3_to_rot_size(float rot[3][3], float size[3], float mat3[3][3])
+/** Return 2D scale (in XY plane) of given mat4. */
+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};
+ mul_mat3_m4_v3(M, unit_vec);
+ return len_v3(unit_vec);
+}
+
+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]);
@@ -1535,7 +1599,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 */
@@ -1546,7 +1610,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 */
@@ -1564,7 +1628,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);
@@ -1581,7 +1645,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*
@@ -1625,53 +1689,48 @@ void translate_m4(float mat[4][4], float Tx, float Ty, float Tz)
mat[3][2] += (Tx * mat[0][2] + Ty * mat[1][2] + Tz * mat[2][2]);
}
+/* TODO: enum for axis? */
+/**
+ * Rotate a matrix in-place.
+ *
+ * \note To create a new rotation matrix see:
+ * #axis_angle_to_mat4_single, #axis_angle_to_mat3_single, #angle_to_mat2
+ * (axis & angle args are compatible).
+ */
void rotate_m4(float mat[4][4], const char axis, const float angle)
{
- int col;
- float temp[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- float cosine, sine;
+ const float angle_cos = cosf(angle);
+ const float angle_sin = sinf(angle);
assert(axis >= 'X' && axis <= 'Z');
- cosine = cosf(angle);
- sine = sinf(angle);
switch (axis) {
case 'X':
- for (col = 0; col < 4; col++)
- temp[col] = cosine * mat[1][col] + sine * mat[2][col];
- for (col = 0; col < 4; col++) {
- mat[2][col] = -sine * mat[1][col] + cosine * mat[2][col];
- mat[1][col] = temp[col];
+ for (int col = 0; col < 4; col++) {
+ float temp = angle_cos * mat[1][col] + angle_sin * mat[2][col];
+ mat[2][col] = -angle_sin * mat[1][col] + angle_cos * mat[2][col];
+ mat[1][col] = temp;
}
break;
case 'Y':
- for (col = 0; col < 4; col++)
- temp[col] = cosine * mat[0][col] - sine * mat[2][col];
- for (col = 0; col < 4; col++) {
- mat[2][col] = sine * mat[0][col] + cosine * mat[2][col];
- mat[0][col] = temp[col];
+ for (int col = 0; col < 4; col++) {
+ float temp = angle_cos * mat[0][col] - angle_sin * mat[2][col];
+ mat[2][col] = angle_sin * mat[0][col] + angle_cos * mat[2][col];
+ mat[0][col] = temp;
}
break;
case 'Z':
- for (col = 0; col < 4; col++)
- temp[col] = cosine * mat[0][col] + sine * mat[1][col];
- for (col = 0; col < 4; col++) {
- mat[1][col] = -sine * mat[0][col] + cosine * mat[1][col];
- mat[0][col] = temp[col];
+ for (int col = 0; col < 4; col++) {
+ float temp = angle_cos * mat[0][col] + angle_sin * mat[1][col];
+ mat[1][col] = -angle_sin * mat[0][col] + angle_cos * mat[1][col];
+ mat[0][col] = temp;
}
break;
}
}
-void rotate_m2(float mat[2][2], const float angle)
-{
- mat[0][0] = mat[1][1] = cosf(angle);
- mat[0][1] = sinf(angle);
- mat[1][0] = -mat[0][1];
-}
-
/**
* Scale or rotate around a pivot point,
* a convenience function to avoid having to do inline.
@@ -1694,7 +1753,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];
@@ -1717,7 +1776,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];
@@ -1744,18 +1803,18 @@ void blend_m4_m4m4(float out[4][4], float dst[4][4], float src[4][4], const floa
/**
* A polar-decomposition-based interpolation between matrix A and matrix B.
*
- * \note This code is about five times slower as the 'naive' interpolation done by \a blend_m3_m3m3
- * (it typically remains below 2 usec on an average i74700, while \a blend_m3_m3m3 remains below 0.4 usec).
+ * \note This code is about five times slower as the 'naive' interpolation done by #blend_m3_m3m3
+ * (it typically remains below 2 usec on an average i74700, while #blend_m3_m3m3 remains below 0.4 usec).
* However, it gives expected results even with non-uniformaly scaled matrices, see T46418 for an example.
*
* Based on "Matrix Animation and Polar Decomposition", by Ken Shoemake & Tom Duff
*
- * @return R the interpolated matrix.
- * @param A the intput matrix which is totally effective with \a t = 0.0.
- * @param B the intput matrix which is totally effective with \a t = 1.0.
- * @param t the interpolation factor.
+ * \param R: Resulting interpolated matrix.
+ * \param A: Input matrix which is totally effective with `t = 0.0`.
+ * \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. */
@@ -1783,14 +1842,14 @@ void interp_m3_m3m3(float R[3][3], float A[3][3], float B[3][3], const float t)
}
/**
- * Complete transform matrix interpolation, based on polar-decomposition-based interpolation from interp_m3_m3m3.
+ * Complete transform matrix interpolation, based on polar-decomposition-based interpolation from #interp_m3_m3m3.
*
- * @return R the interpolated matrix.
- * @param A the intput matrix which is totally effective with \a t = 0.0.
- * @param B the intput matrix which is totally effective with \a t = 1.0.
- * @param t the interpolation factor.
+ * \param R: Resulting interpolated matrix.
+ * \param A: Input matrix which is totally effective with `t = 0.0`.
+ * \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];
@@ -1811,27 +1870,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]) &&
@@ -1839,14 +1898,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]) &&
@@ -1937,7 +1996,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]);
@@ -1946,7 +2005,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]);
@@ -2400,7 +2459,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) */
@@ -2421,7 +2480,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)) {
@@ -2433,14 +2492,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];
@@ -2488,7 +2547,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);
@@ -2506,7 +2565,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 b285a74b8ac..23bd5e60e22 100644
--- a/source/blender/blenlib/intern/math_rotation.c
+++ b/source/blender/blenlib/intern/math_rotation.c
@@ -84,8 +84,6 @@ void mul_qt_qtqt(float q[4], const float q1[4], const float q2[4])
* \note:
* Assumes a unit quaternion?
*
- * \note: multiplying by 3x3 matrix is ~25% faster.
- *
* in fact not, but you may want to use a unit quat, read on...
*
* Shortcut for 'q v q*' when \a v is actually a quaternion.
@@ -98,6 +96,8 @@ void mul_qt_qtqt(float q[4], const float q1[4], const float q2[4])
*
* For people used to python mathutils, its like:
* def mul_qt_v3(q, v): (q * Quaternion((0.0, v[0], v[1], v[2])) * q.conjugated())[1:]
+ *
+ * \note: multiplying by 3x3 matrix is ~25% faster.
*/
void mul_qt_v3(const float q[4], float v[3])
{
@@ -1009,6 +1009,13 @@ void mat4_to_axis_angle(float axis[3], float *angle, float mat[4][4])
quat_to_axis_angle(axis, angle, q);
}
+void axis_angle_to_mat4_single(float mat[4][4], const char axis, const float angle)
+{
+ float mat3[3][3];
+ axis_angle_to_mat3_single(mat3, axis, angle);
+ copy_m4_m3(mat, mat3);
+}
+
/* rotation matrix from a single axis */
void axis_angle_to_mat3_single(float mat[3][3], const char axis, const float angle)
{
@@ -2140,38 +2147,37 @@ BLI_INLINE int _axis_signed(const int axis)
return (axis < 3) ? axis : axis - 3;
}
-/*
+/**
* Each argument us an axis in ['X', 'Y', 'Z', '-X', '-Y', '-Z']
* where the first 2 are a source and the second 2 are the target.
*/
-int mat3_from_axis_conversion(int from_forward, int from_up, int to_forward, int to_up,
- float r_mat[3][3])
+bool mat3_from_axis_conversion(
+ int src_forward, int src_up, int dst_forward, int dst_up,
+ float r_mat[3][3])
{
// from functools import reduce
int value;
- unsigned int i;
- if (from_forward == to_forward && from_up == to_up) {
+ if (src_forward == dst_forward && src_up == dst_up) {
unit_m3(r_mat);
return false;
}
- if ((_axis_signed(from_forward) == _axis_signed(from_up)) ||
- (_axis_signed(to_forward) == _axis_signed(to_up)))
+ if ((_axis_signed(src_forward) == _axis_signed(src_up)) ||
+ (_axis_signed(dst_forward) == _axis_signed(dst_up)))
{
/* we could assert here! */
unit_m3(r_mat);
return false;
}
- value = ((from_forward << (0 * 3)) |
- (from_up << (1 * 3)) |
- (to_forward << (2 * 3)) |
- (to_up << (3 * 3)));
+ value = ((src_forward << (0 * 3)) |
+ (src_up << (1 * 3)) |
+ (dst_forward << (2 * 3)) |
+ (dst_up << (3 * 3)));
- for (i = 0; i < (sizeof(_axis_convert_matrix) / sizeof(*_axis_convert_matrix)); i++) {
- unsigned int j;
- for (j = 0; j < (sizeof(*_axis_convert_lut) / sizeof(*_axis_convert_lut[0])); j++) {
+ for (uint i = 0; i < (sizeof(_axis_convert_matrix) / sizeof(*_axis_convert_matrix)); i++) {
+ for (uint j = 0; j < (sizeof(*_axis_convert_lut) / sizeof(*_axis_convert_lut[0])); j++) {
if (_axis_convert_lut[i][j] == value) {
copy_m3_m3(r_mat, _axis_convert_matrix[i]);
return true;
@@ -2182,3 +2188,27 @@ int mat3_from_axis_conversion(int from_forward, int from_up, int to_forward, int
// BLI_assert(0);
return false;
}
+
+/**
+ * Use when the second axis can be guessed.
+ */
+bool mat3_from_axis_conversion_single(
+ int src_axis, int dst_axis,
+ float r_mat[3][3])
+{
+ if (src_axis == dst_axis) {
+ unit_m3(r_mat);
+ return false;
+ }
+
+ /* Pick predictable next axis. */
+ int src_axis_next = (src_axis + 1) % 3;
+ int dst_axis_next = (dst_axis + 1) % 3;
+
+ if ((src_axis < 3) != (dst_axis < 3)) {
+ /* Flip both axis so matrix sign remains positive. */
+ dst_axis_next += 3;
+ }
+
+ return mat3_from_axis_conversion(src_axis, src_axis_next, dst_axis, dst_axis_next, r_mat);
+}
diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c
index 95d5c9fde87..40a78adcefe 100644
--- a/source/blender/blenlib/intern/math_vector.c
+++ b/source/blender/blenlib/intern/math_vector.c
@@ -280,6 +280,16 @@ void mid_v3_v3v3v3v3(float v[3], const float v1[3], const float v2[3], const flo
v[2] = (v1[2] + v2[2] + v3[2] + v4[2]) / 4.0f;
}
+void mid_v3_v3_array(float r[3], const float (*vec_arr)[3], const unsigned int nbr)
+{
+ const float factor = 1.0f / (float)nbr;
+ zero_v3(r);
+
+ for (unsigned int i = 0; i < nbr; i++) {
+ madd_v3_v3fl(r, vec_arr[i], factor);
+ }
+}
+
/**
* Specialized function for calculating normals.
* fastpath for:
@@ -508,38 +518,27 @@ float angle_normalized_v2v2(const float v1[2], const float v2[2])
}
/**
- * angle between 2 vectors defined by 3 coords, about an axis. */
-float angle_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3])
+ * Angle between 2 vectors, about an axis (axis can be considered a plane).
+ */
+float angle_on_axis_v3v3_v3(const float v1[3], const float v2[3], const float axis[3])
{
- float v1_proj[3], v2_proj[3], tproj[3];
-
- sub_v3_v3v3(v1_proj, v1, v2);
- sub_v3_v3v3(v2_proj, v3, v2);
+ float v1_proj[3], v2_proj[3];
/* project the vectors onto the axis */
- project_v3_v3v3(tproj, v1_proj, axis);
- sub_v3_v3(v1_proj, tproj);
-
- project_v3_v3v3(tproj, v2_proj, axis);
- sub_v3_v3(v2_proj, tproj);
+ project_plane_normalized_v3_v3v3(v1_proj, v1, axis);
+ project_plane_normalized_v3_v3v3(v2_proj, v2, axis);
return angle_v3v3(v1_proj, v2_proj);
}
-float angle_signed_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3])
+float angle_signed_on_axis_v3v3_v3(const float v1[3], const float v2[3], const float axis[3])
{
float v1_proj[3], v2_proj[3], tproj[3];
float angle;
- sub_v3_v3v3(v1_proj, v1, v2);
- sub_v3_v3v3(v2_proj, v3, v2);
-
/* project the vectors onto the axis */
- project_v3_v3v3(tproj, v1_proj, axis);
- sub_v3_v3(v1_proj, tproj);
-
- project_v3_v3v3(tproj, v2_proj, axis);
- sub_v3_v3(v2_proj, tproj);
+ project_plane_normalized_v3_v3v3(v1_proj, v1, axis);
+ project_plane_normalized_v3_v3v3(v2_proj, v2, axis);
angle = angle_v3v3(v1_proj, v2_proj);
@@ -552,6 +551,29 @@ float angle_signed_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const
return angle;
}
+/**
+ * Angle between 2 vectors defined by 3 coords, about an axis (axis can be considered a plane).
+ */
+float angle_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3])
+{
+ float vec1[3], vec2[3];
+
+ sub_v3_v3v3(vec1, v1, v2);
+ sub_v3_v3v3(vec2, v3, v2);
+
+ return angle_on_axis_v3v3_v3(vec1, vec2, axis);
+}
+
+float angle_signed_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3])
+{
+ float vec1[3], vec2[3];
+
+ sub_v3_v3v3(vec1, v1, v2);
+ sub_v3_v3v3(vec2, v3, v2);
+
+ return angle_signed_on_axis_v3v3_v3(vec1, vec2, axis);
+}
+
void angle_tri_v3(float angles[3], const float v1[3], const float v2[3], const float v3[3])
{
float ed1[3], ed2[3], ed3[3];
@@ -659,6 +681,25 @@ void project_plane_v2_v2v2(float out[2], const float p[2], const float v_plane[2
out[1] = p[1] - (mul * v_plane[1]);
}
+void project_plane_normalized_v3_v3v3(float out[3], const float p[3], const float v_plane[3])
+{
+ BLI_ASSERT_UNIT_V3(v_plane);
+ const float mul = dot_v3v3(p, v_plane);
+
+ out[0] = p[0] - (mul * v_plane[0]);
+ out[1] = p[1] - (mul * v_plane[1]);
+ out[2] = p[2] - (mul * v_plane[2]);
+}
+
+void project_plane_normalized_v2_v2v2(float out[2], const float p[2], const float v_plane[2])
+{
+ BLI_ASSERT_UNIT_V2(v_plane);
+ const float mul = dot_v2v2(p, v_plane);
+
+ out[0] = p[0] - (mul * v_plane[0]);
+ out[1] = p[1] - (mul * v_plane[1]);
+}
+
/* project a vector on a plane defined by normal and a plane point p */
void project_v3_plane(float out[3], const float plane_no[3], const float plane_co[3])
{
@@ -687,7 +728,19 @@ void bisect_v3_v3v3v3(float out[3], const float v1[3], const float v2[3], const
/**
* Returns a reflection vector from a vector and a normal vector
- * reflect = vec - ((2 * DotVecs(vec, mirror)) * mirror)
+ * reflect = vec - ((2 * dot(vec, mirror)) * mirror).
+ *
+ * <pre>
+ * v
+ * + ^
+ * \ |
+ * \|
+ * + normal: axis of reflection
+ * /
+ * /
+ * +
+ * out: result (negate for a 'bounce').
+ * </pre>
*/
void reflect_v3_v3v3(float out[3], const float v[3], const float normal[3])
{
@@ -772,6 +825,20 @@ void ortho_v2_v2(float out[2], const float v[2])
}
/**
+ * Rotate a point \a p by \a angle around origin (0, 0)
+ */
+void rotate_v2_v2fl(float r[2], const float p[2], const float angle)
+{
+ const float co = cosf(angle);
+ const float si = sinf(angle);
+
+ BLI_assert(r != p);
+
+ r[0] = co * p[0] - si * p[1];
+ r[1] = si * p[0] + co * p[1];
+}
+
+/**
* Rotate a point \a p by \a angle around an arbitrary unit length \a axis.
* http://local.wasp.uwa.edu.au/~pbourke/geometry/
*/
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index e9fb77f6302..4f658ef015f 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -479,8 +479,19 @@ MINLINE void mul_v2_v2_ccw(float r[2], const float mat[2], const float vec[2])
r[1] = mat[1] * vec[0] + (+mat[0]) * vec[1];
}
-/* note: could add a matrix inline */
-MINLINE float mul_project_m4_v3_zfac(float mat[4][4], const float co[3])
+/**
+ * Convenience function to get the projected depth of a position.
+ * This avoids creating a temporary 4D vector and multiplying it - only for the 4th component.
+ *
+ * Matches logic for:
+ *
+ * \code{.c}
+ * float co_4d[4] = {co[0], co[1], co[2], 1.0};
+ * mul_m4_v4(mat, co_4d);
+ * return co_4d[3];
+ * \endcode
+ */
+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]) +
@@ -647,6 +658,14 @@ MINLINE void invert_v2(float r[2])
r[1] = 1.0f / r[1];
}
+MINLINE void invert_v3(float r[3])
+{
+ BLI_assert(!ELEM(0.0f, r[0], r[1], r[2]));
+ r[0] = 1.0f / r[0];
+ r[1] = 1.0f / r[1];
+ r[2] = 1.0f / r[2];
+}
+
MINLINE void abs_v2(float r[2])
{
r[0] = fabsf(r[0]);
@@ -949,6 +968,12 @@ MINLINE float normalize_v3(float n[3])
return normalize_v3_v3(n, n);
}
+MINLINE void normal_float_to_short_v2(short out[2], const float in[2])
+{
+ out[0] = (short) (in[0] * 32767.0f);
+ out[1] = (short) (in[1] * 32767.0f);
+}
+
MINLINE void normal_short_to_float_v3(float out[3], const short in[3])
{
out[0] = in[0] * (1.0f / 32767.0f);
diff --git a/source/blender/blenlib/intern/noise.c b/source/blender/blenlib/intern/noise.c
index f834c5b4c74..347640aae0d 100644
--- a/source/blender/blenlib/intern/noise.c
+++ b/source/blender/blenlib/intern/noise.c
@@ -1394,6 +1394,11 @@ static float voronoi_CrS(float x, float y, float z)
/* returns unsigned cellnoise */
static float cellNoiseU(float x, float y, float z)
{
+ /* avoid precision issues on unit coordinates */
+ x = (x + 0.000001f)*0.999999f;
+ y = (y + 0.000001f)*0.999999f;
+ z = (z + 0.000001f)*0.999999f;
+
int xi = (int)(floor(x));
int yi = (int)(floor(y));
int zi = (int)(floor(z));
@@ -1411,6 +1416,11 @@ float cellNoise(float x, float y, float z)
/* returns a vector/point/color in ca, using point hasharray directly */
void cellNoiseV(float x, float y, float z, float ca[3])
{
+ /* avoid precision issues on unit coordinates */
+ x = (x + 0.000001f)*0.999999f;
+ y = (y + 0.000001f)*0.999999f;
+ z = (z + 0.000001f)*0.999999f;
+
int xi = (int)(floor(x));
int yi = (int)(floor(y));
int zi = (int)(floor(z));
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index ded10ad7713..4b3a74d02ae 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -63,9 +63,6 @@
#include "MEM_guardedalloc.h"
-/* local */
-#define UNIQUE_NAME_MAX 128
-
/* Declarations */
#ifdef WIN32
@@ -147,162 +144,6 @@ void BLI_stringenc(char *string, const char *head, const char *tail, unsigned sh
sprintf(string, "%s%.*d%s", head, numlen, MAX2(0, pic), tail);
}
-/**
- * Looks for a numeric suffix preceded by delim character on the end of
- * name, puts preceding part into *left and value of suffix into *nr.
- * Returns the length of *left.
- *
- * Foo.001 -> "Foo", 1
- * Returning the length of "Foo"
- *
- * \param left Where to return copy of part preceding delim
- * \param nr Where to return value of numeric suffix
- * \param name String to split
- * \param delim Delimiter character
- * \return Length of \a left
- */
-int BLI_split_name_num(char *left, int *nr, const char *name, const char delim)
-{
- const int name_len = strlen(name);
-
- *nr = 0;
- memcpy(left, name, (name_len + 1) * sizeof(char));
-
- /* name doesn't end with a delimiter "foo." */
- if ((name_len > 1 && name[name_len - 1] == delim) == 0) {
- int a = name_len;
- while (a--) {
- if (name[a] == delim) {
- left[a] = '\0'; /* truncate left part here */
- *nr = atol(name + a + 1);
- /* casting down to an int, can overflow for large numbers */
- if (*nr < 0)
- *nr = 0;
- return a;
- }
- else if (isdigit(name[a]) == 0) {
- /* non-numeric suffix - give up */
- break;
- }
- }
- }
-
- return name_len;
-}
-
-/**
- * Ensures name is unique (according to criteria specified by caller in unique_check callback),
- * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
- *
- * \param unique_check Return true if name is not unique
- * \param arg Additional arg to unique_check--meaning is up to caller
- * \param defname To initialize name if latter is empty
- * \param delim Delimits numeric suffix in name
- * \param name Name to be ensured unique
- * \param name_len Maximum length of name area
- * \return true if there if the name was changed
- */
-bool BLI_uniquename_cb(bool (*unique_check)(void *arg, const char *name),
- void *arg, const char *defname, char delim, char *name, int name_len)
-{
- if (name[0] == '\0') {
- BLI_strncpy(name, defname, name_len);
- }
-
- if (unique_check(arg, name)) {
- char numstr[16];
- char tempname[UNIQUE_NAME_MAX];
- char left[UNIQUE_NAME_MAX];
- int number;
- int len = BLI_split_name_num(left, &number, name, delim);
- do {
- /* add 1 to account for \0 */
- const int numlen = BLI_snprintf(numstr, sizeof(numstr), "%c%03d", delim, ++number) + 1;
-
- /* highly unlikely the string only has enough room for the number
- * but support anyway */
- if ((len == 0) || (numlen >= name_len)) {
- /* number is know not to be utf-8 */
- BLI_strncpy(tempname, numstr, name_len);
- }
- else {
- char *tempname_buf;
- tempname_buf = tempname + BLI_strncpy_utf8_rlen(tempname, left, name_len - numlen);
- memcpy(tempname_buf, numstr, numlen);
- }
- } while (unique_check(arg, tempname));
-
- BLI_strncpy(name, tempname, name_len);
-
- return true;
- }
-
- return false;
-}
-
-/* little helper macro for BLI_uniquename */
-#ifndef GIVE_STRADDR
-# define GIVE_STRADDR(data, offset) ( ((char *)data) + offset)
-#endif
-
-/* Generic function to set a unique name. It is only designed to be used in situations
- * where the name is part of the struct, and also that the name is at most UNIQUE_NAME_MAX chars long.
- *
- * For places where this is used, see constraint.c for example...
- *
- * name_offs: should be calculated using offsetof(structname, membername) macro from stddef.h
- * len: maximum length of string (to prevent overflows, etc.)
- * defname: the name that should be used by default if none is specified already
- * delim: the character which acts as a delimiter between parts of the name
- */
-static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, int name_offs)
-{
- Link *link;
-
- for (link = list->first; link; link = link->next) {
- if (link != vlink) {
- if (STREQ(GIVE_STRADDR(link, name_offs), name)) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-static bool uniquename_unique_check(void *arg, const char *name)
-{
- struct {ListBase *lb; void *vlink; int name_offs; } *data = arg;
- return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offs);
-}
-
-/**
- * Ensures that the specified block has a unique name within the containing list,
- * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
- *
- * \param list List containing the block
- * \param vlink The block to check the name for
- * \param defname To initialize block name if latter is empty
- * \param delim Delimits numeric suffix in name
- * \param name_offs Offset of name within block structure
- * \param name_len Maximum length of name area
- */
-bool BLI_uniquename(ListBase *list, void *vlink, const char *defname, char delim, int name_offs, int name_len)
-{
- struct {ListBase *lb; void *vlink; int name_offs; } data;
- data.lb = list;
- data.vlink = vlink;
- data.name_offs = name_offs;
-
- assert((name_len > 1) && (name_len <= UNIQUE_NAME_MAX));
-
- /* See if we are given an empty string */
- if (ELEM(NULL, vlink, defname))
- return false;
-
- return BLI_uniquename_cb(uniquename_unique_check, &data, defname, delim, GIVE_STRADDR(vlink, name_offs), name_len);
-}
-
static int BLI_path_unc_prefix_len(const char *path); /* defined below in same file */
/* ******************** string encoding ***************** */
@@ -430,7 +271,7 @@ void BLI_cleanup_file(const char *relabase, char *path)
* \return true if \a fname was changed, false otherwise.
*
* For now, simply replaces reserved chars (as listed in
- * http://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words )
+ * https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words )
* by underscores ('_').
*
* \note Space case ' ' is a bit of an edge case here - in theory it is allowed, but again can be an issue
@@ -1326,52 +1167,16 @@ bool BLI_path_program_search(
}
/**
- * Copies into *last the part of *dir following the second-last slash.
- */
-void BLI_getlastdir(const char *dir, char *last, const size_t maxlen)
-{
- const char *s = dir;
- const char *lslash = NULL;
- const char *prevslash = NULL;
- while (*s) {
- if ((*s == '\\') || (*s == '/')) {
- prevslash = lslash;
- lslash = s;
- }
- s++;
- }
- if (prevslash) {
- BLI_strncpy(last, prevslash + 1, maxlen);
- }
- else {
- BLI_strncpy(last, dir, maxlen);
- }
-}
-
-
-/**
* Sets the specified environment variable to the specified value,
* and clears it if val == NULL.
*/
void BLI_setenv(const char *env, const char *val)
{
/* free windows */
-#if (defined(WIN32) || defined(WIN64)) && defined(FREE_WINDOWS)
- char *envstr;
- if (val)
- envstr = BLI_sprintfN("%s=%s", env, val);
- else
- envstr = BLI_sprintfN("%s=", env);
-
- putenv(envstr);
- MEM_freeN(envstr);
-
- /* non-free windows */
-#elif (defined(WIN32) || defined(WIN64)) /* not free windows */
+#if (defined(WIN32) || defined(WIN64))
uputenv(env, val);
-
#else
/* linux/osx/bsd */
if (val)
@@ -1417,14 +1222,16 @@ void BLI_make_exist(char *dir)
/**
* Ensures that the parent directory of *name exists.
+ *
+ * \return true on success (i.e. given path now exists on FS), false otherwise.
*/
-void BLI_make_existing_file(const char *name)
+bool BLI_make_existing_file(const char *name)
{
char di[FILE_MAX];
BLI_split_dir_part(name, di, sizeof(di));
/* make if the dir doesn't exist */
- BLI_dir_create_recursive(di);
+ return BLI_dir_create_recursive(di);
}
/**
@@ -1774,6 +1581,90 @@ void BLI_join_dirfile(char *__restrict dst, const size_t maxlen, const char *__r
}
/**
+ * Join multiple strings into a path, ensuring only a single path separator between each,
+ * and trailing slash is kept.
+ *
+ * \note If you want a trailing slash, add ``SEP_STR`` as the last path argument,
+ * duplicate slashes will be cleaned up.
+ */
+size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *path, ...)
+{
+ if (UNLIKELY(dst_len == 0)) {
+ return 0;
+ }
+ const size_t dst_last = dst_len - 1;
+ size_t ofs = BLI_strncpy_rlen(dst, path, dst_len);
+
+ if (ofs == dst_last) {
+ return ofs;
+ }
+
+ /* remove trailing slashes, unless there are _only_ trailing slashes
+ * (allow "//" as the first argument). */
+ bool has_trailing_slash = false;
+ if (ofs != 0) {
+ size_t len = ofs;
+ while ((len != 0) && ELEM(path[len - 1], SEP, ALTSEP)) {
+ len -= 1;
+ }
+ if (len != 0) {
+ ofs = len;
+ }
+ has_trailing_slash = (path[len] != '\0');
+ }
+
+ va_list args;
+ va_start(args, path);
+ while ((path = (const char *) va_arg(args, const char *))) {
+ has_trailing_slash = false;
+ const char *path_init = path;
+ while (ELEM(path[0], SEP, ALTSEP)) {
+ path++;
+ }
+ size_t len = strlen(path);
+ if (len != 0) {
+ while ((len != 0) && ELEM(path[len - 1], SEP, ALTSEP)) {
+ len -= 1;
+ }
+
+ if (len != 0) {
+ /* the very first path may have a slash at the end */
+ if (ofs && !ELEM(dst[ofs - 1], SEP, ALTSEP)) {
+ dst[ofs++] = SEP;
+ if (ofs == dst_last) {
+ break;
+ }
+ }
+ has_trailing_slash = (path[len] != '\0');
+ if (ofs + len >= dst_last) {
+ len = dst_last - ofs;
+ }
+ memcpy(&dst[ofs], path, len);
+ ofs += len;
+ if (ofs == dst_last) {
+ break;
+ }
+ }
+ }
+ else {
+ has_trailing_slash = (path_init != path);
+ }
+ }
+ va_end(args);
+
+ if (has_trailing_slash) {
+ if ((ofs != dst_last) && (ofs != 0) && (ELEM(dst[ofs - 1], SEP, ALTSEP) == 0)) {
+ dst[ofs++] = SEP;
+ }
+ }
+
+ BLI_assert(ofs <= dst_last);
+ dst[ofs] = '\0';
+
+ return ofs;
+}
+
+/**
* like pythons os.path.basename()
*
* \return The pointer into \a path string immediately after last slash,
@@ -1785,6 +1676,71 @@ const char *BLI_path_basename(const char *path)
return filename ? filename + 1 : path;
}
+/**
+ * Get an element of the path at an index, eg:
+ * "/some/path/file.txt" where an index of...
+ * - 0 or -3: "some"
+ * - 1 or -2: "path"
+ * - 2 or -1: "file.txt"
+ *
+ * Ignores multiple slashes at any point in the path (including start/end).
+ */
+bool BLI_path_name_at_index(const char *path, const int index, int *r_offset, int *r_len)
+{
+ if (index >= 0) {
+ int index_step = 0;
+ int prev = -1;
+ int i = 0;
+ while (true) {
+ const char c = path[i];
+ if (ELEM(c, SEP, ALTSEP, '\0')) {
+ if (prev + 1 != i) {
+ prev += 1;
+ if (index_step == index) {
+ *r_offset = prev;
+ *r_len = i - prev;
+ /* printf("!!! %d %d\n", start, end); */
+ return true;
+ }
+ index_step += 1;
+ }
+ if (c == '\0') {
+ break;
+ }
+ prev = i;
+ }
+ i += 1;
+ }
+ return false;
+ }
+ else {
+ /* negative number, reverse where -1 is the last element */
+ int index_step = -1;
+ int prev = strlen(path);
+ int i = prev - 1;
+ while (true) {
+ const char c = i >= 0 ? path[i] : '\0';
+ if (ELEM(c, SEP, ALTSEP, '\0')) {
+ if (prev - 1 != i) {
+ i += 1;
+ if (index_step == index) {
+ *r_offset = i;
+ *r_len = prev - i;
+ return true;
+ }
+ index_step -= 1;
+ }
+ if (c == '\0') {
+ break;
+ }
+ prev = i;
+ }
+ i -= 1;
+ }
+ return false;
+ }
+}
+
/* UNUSED */
#if 0
/**
diff --git a/source/blender/blenlib/intern/polyfill2d.c b/source/blender/blenlib/intern/polyfill2d.c
index 8d9881e4539..5f9b92198a5 100644
--- a/source/blender/blenlib/intern/polyfill2d.c
+++ b/source/blender/blenlib/intern/polyfill2d.c
@@ -21,8 +21,15 @@
/** \file blender/blenlib/intern/polyfill2d.c
* \ingroup bli
*
- * A simple implementation of the ear cutting algorithm
- * to triangulate simple polygons without holes.
+ * An ear clipping algorithm to triangulate single boundary polygons.
+ *
+ * Details:
+ *
+ * - The algorithm guarantees all triangles are assigned (number of coords - 2)
+ * and that triangles will have non-overlapping indices (even for degenerate geometry).
+ * - Self-intersections are considered degenerate (resulting triangles will overlap).
+ * - While multiple polygons aren't supported, holes can still be defined using *key-holes*
+ * (where the polygon doubles back on its self with *exactly* matching coordinates).
*
* \note
*
@@ -74,6 +81,12 @@ typedef signed char eSign;
#ifdef USE_KDTREE
/**
+ * Spatial optimization for point-in-triangle intersection checks.
+ * The simple version of this algorithm is ``O(n^2)`` complexity
+ * (every point needing to check the triangle defined by every other point),
+ * Using a binary-tree reduces the complexity to ``O(n log n)``
+ * plus some overhead of creating the tree.
+ *
* This is a single purpose KDTree based on BLI_kdtree with some modifications
* to better suit polyfill2d.
*
@@ -92,24 +105,24 @@ typedef bool axis_t;
/* use for sorting */
typedef struct KDTreeNode2D_head {
- unsigned int neg, pos;
- unsigned int index;
+ uint neg, pos;
+ uint index;
} KDTreeNode2D_head;
typedef struct KDTreeNode2D {
- unsigned int neg, pos;
- unsigned int index;
+ uint neg, pos;
+ uint index;
axis_t axis; /* range is only (0-1) */
- unsigned short flag;
- unsigned int parent;
+ ushort flag;
+ uint parent;
} KDTreeNode2D;
struct KDTree2D {
KDTreeNode2D *nodes;
const float (*coords)[2];
- unsigned int root;
- unsigned int totnode;
- unsigned int *nodes_map; /* index -> node lookup */
+ uint root;
+ uint totnode;
+ uint *nodes_map; /* index -> node lookup */
};
struct KDRange2D {
@@ -127,14 +140,14 @@ typedef struct PolyFill {
struct PolyIndex *indices; /* vertex aligned */
const float (*coords)[2];
- unsigned int coords_tot;
+ uint coords_tot;
#ifdef USE_CONVEX_SKIP
- unsigned int coords_tot_concave;
+ uint coords_tot_concave;
#endif
/* A polygon with n vertices has a triangulation of n-2 triangles. */
- unsigned int (*tris)[3];
- unsigned int tris_tot;
+ uint (*tris)[3];
+ uint tris_tot;
#ifdef USE_KDTREE
struct KDTree2D kdtree;
@@ -145,7 +158,7 @@ typedef struct PolyFill {
/* circular linklist */
typedef struct PolyIndex {
struct PolyIndex *next, *prev;
- unsigned int index;
+ uint index;
eSign sign;
} PolyIndex;
@@ -199,7 +212,7 @@ static eSign span_tri_v2_sign(const float v1[2], const float v2[2], const float
#ifdef USE_KDTREE
-#define KDNODE_UNSET ((unsigned int)-1)
+#define KDNODE_UNSET ((uint)-1)
enum {
KDNODE_FLAG_REMOVED = (1 << 0),
@@ -207,7 +220,7 @@ enum {
static void kdtree2d_new(
struct KDTree2D *tree,
- unsigned int tot,
+ uint tot,
const float (*coords)[2])
{
/* set by caller */
@@ -222,11 +235,11 @@ static void kdtree2d_new(
*/
static void kdtree2d_init(
struct KDTree2D *tree,
- const unsigned int coords_tot,
+ const uint coords_tot,
const PolyIndex *indices)
{
KDTreeNode2D *node;
- unsigned int i;
+ uint i;
for (i = 0, node = tree->nodes; i < coords_tot; i++) {
if (indices[i].sign != CONVEX) {
@@ -238,15 +251,15 @@ static void kdtree2d_init(
}
}
- BLI_assert(tree->totnode == (unsigned int)(node - tree->nodes));
+ BLI_assert(tree->totnode == (uint)(node - tree->nodes));
}
-static unsigned int kdtree2d_balance_recursive(
- KDTreeNode2D *nodes, unsigned int totnode, axis_t axis,
- const float (*coords)[2], const unsigned int ofs)
+static uint kdtree2d_balance_recursive(
+ KDTreeNode2D *nodes, uint totnode, axis_t axis,
+ const float (*coords)[2], const uint ofs)
{
KDTreeNode2D *node;
- unsigned int neg, pos, median, i, j;
+ uint neg, pos, median, i, j;
if (totnode <= 0) {
return KDNODE_UNSET;
@@ -304,7 +317,7 @@ static void kdtree2d_balance(
static void kdtree2d_init_mapping(
struct KDTree2D *tree)
{
- unsigned int i;
+ uint i;
KDTreeNode2D *node;
for (i = 0, node = tree->nodes; i < tree->totnode; i++, node++) {
@@ -325,9 +338,9 @@ static void kdtree2d_init_mapping(
static void kdtree2d_node_remove(
struct KDTree2D *tree,
- unsigned int index)
+ uint index)
{
- unsigned int node_index = tree->nodes_map[index];
+ uint node_index = tree->nodes_map[index];
KDTreeNode2D *node;
if (node_index == KDNODE_UNSET) {
@@ -349,7 +362,7 @@ static void kdtree2d_node_remove(
{
KDTreeNode2D *node_parent = &tree->nodes[node->parent];
- BLI_assert((unsigned int)(node - tree->nodes) == node_index);
+ BLI_assert((uint)(node - tree->nodes) == node_index);
if (node_parent->neg == node_index) {
node_parent->neg = KDNODE_UNSET;
}
@@ -370,7 +383,7 @@ static void kdtree2d_node_remove(
static bool kdtree2d_isect_tri_recursive(
const struct KDTree2D *tree,
- const unsigned int tri_index[3],
+ const uint tri_index[3],
const float *tri_coords[3],
const float tri_center[2],
const struct KDRange2D bounds[2],
@@ -433,10 +446,10 @@ static bool kdtree2d_isect_tri_recursive(
static bool kdtree2d_isect_tri(
struct KDTree2D *tree,
- const unsigned int ind[3])
+ const uint ind[3])
{
const float *vs[3];
- unsigned int i;
+ uint i;
struct KDRange2D bounds[2] = {
{FLT_MAX, -FLT_MAX},
{FLT_MAX, -FLT_MAX},
@@ -462,7 +475,7 @@ static bool kdtree2d_isect_tri(
#endif /* USE_KDTREE */
-static unsigned int *pf_tri_add(PolyFill *pf)
+static uint *pf_tri_add(PolyFill *pf)
{
return pf->tris[pf->tris_tot++];
}
@@ -483,7 +496,7 @@ static void pf_coord_remove(PolyFill *pf, PolyIndex *pi)
pf->indices = pi->next;
}
#ifdef DEBUG
- pi->index = (unsigned int)-1;
+ pi->index = (uint)-1;
pi->next = pi->prev = NULL;
#endif
@@ -581,7 +594,7 @@ static void pf_triangulate(PolyFill *pf)
}
if (pf->coords_tot == 3) {
- unsigned int *tri = pf_tri_add(pf);
+ uint *tri = pf_tri_add(pf);
pi_ear = pf->indices;
tri[0] = pi_ear->index; pi_ear = pi_ear->next;
tri[1] = pi_ear->index; pi_ear = pi_ear->next;
@@ -614,10 +627,10 @@ static PolyIndex *pf_ear_tip_find(
)
{
/* localize */
- const unsigned int coords_tot = pf->coords_tot;
+ const uint coords_tot = pf->coords_tot;
PolyIndex *pi_ear;
- unsigned int i;
+ uint i;
#ifdef USE_CLIP_EVEN
pi_ear = pi_ear_init;
@@ -675,7 +688,7 @@ static bool pf_ear_tip_check(PolyFill *pf, PolyIndex *pi_ear_tip)
#endif
#if defined(USE_CONVEX_SKIP) && !defined(USE_KDTREE)
- unsigned int coords_tot_concave_checked = 0;
+ uint coords_tot_concave_checked = 0;
#endif
@@ -684,8 +697,8 @@ static bool pf_ear_tip_check(PolyFill *pf, PolyIndex *pi_ear_tip)
#ifdef USE_CONVEX_SKIP_TEST
/* check if counting is wrong */
{
- unsigned int coords_tot_concave_test = 0;
- unsigned int i = pf->coords_tot;
+ uint coords_tot_concave_test = 0;
+ uint i = pf->coords_tot;
while (i--) {
if (coords_sign[indices[i]] != CONVEX) {
coords_tot_concave_test += 1;
@@ -707,7 +720,7 @@ static bool pf_ear_tip_check(PolyFill *pf, PolyIndex *pi_ear_tip)
#ifdef USE_KDTREE
{
- const unsigned int ind[3] = {
+ const uint ind[3] = {
pi_ear_tip->index,
pi_ear_tip->next->index,
pi_ear_tip->prev->index};
@@ -758,7 +771,7 @@ static bool pf_ear_tip_check(PolyFill *pf, PolyIndex *pi_ear_tip)
static void pf_ear_tip_cut(PolyFill *pf, PolyIndex *pi_ear_tip)
{
- unsigned int *tri = pf_tri_add(pf);
+ uint *tri = pf_tri_add(pf);
tri[0] = pi_ear_tip->prev->index;
tri[1] = pi_ear_tip->index;
@@ -773,15 +786,15 @@ static void pf_ear_tip_cut(PolyFill *pf, PolyIndex *pi_ear_tip)
static void polyfill_prepare(
PolyFill *pf,
const float (*coords)[2],
- const unsigned int coords_tot,
+ const uint coords_tot,
int coords_sign,
- unsigned int (*r_tris)[3],
+ uint (*r_tris)[3],
PolyIndex *r_indices)
{
/* localize */
PolyIndex *indices = r_indices;
- unsigned int i;
+ uint i;
/* assign all polyfill members here */
pf->indices = r_indices;
@@ -819,7 +832,7 @@ static void polyfill_prepare(
}
else {
/* reversed */
- unsigned int n = coords_tot - 1;
+ uint n = coords_tot - 1;
for (i = 0; i < coords_tot; i++) {
indices[i].next = &indices[i + 1];
indices[i].prev = &indices[i - 1];
@@ -863,9 +876,9 @@ static void polyfill_calc(
*/
void BLI_polyfill_calc_arena(
const float (*coords)[2],
- const unsigned int coords_tot,
+ const uint coords_tot,
const int coords_sign,
- unsigned int (*r_tris)[3],
+ uint (*r_tris)[3],
struct MemArena *arena)
{
@@ -919,9 +932,9 @@ void BLI_polyfill_calc_arena(
*/
void BLI_polyfill_calc(
const float (*coords)[2],
- const unsigned int coords_tot,
+ const uint coords_tot,
const int coords_sign,
- unsigned int (*r_tris)[3])
+ uint (*r_tris)[3])
{
PolyFill pf;
PolyIndex *indices = BLI_array_alloca(indices, coords_tot);
diff --git a/source/blender/blenlib/intern/polyfill2d_beautify.c b/source/blender/blenlib/intern/polyfill2d_beautify.c
index 46f9251bea7..896177f436c 100644
--- a/source/blender/blenlib/intern/polyfill2d_beautify.c
+++ b/source/blender/blenlib/intern/polyfill2d_beautify.c
@@ -239,8 +239,9 @@ static void polyedge_beauty_cost_update_single(
const float cost = polyedge_rotate_beauty_calc(coords, tris, e);
/* We can get cases where both choices generate very small negative costs, which leads to infinite loop.
* Anyway, costs above that are not worth recomputing, maybe we could even optimize it to a smaller limit?
- * See T43578. */
- if (cost < -FLT_EPSILON) {
+ * Actually, FLT_EPSILON is too small in some cases, 1e-6f seems to work OK hopefully?
+ * See T43578, T49478. */
+ if (cost < -1e-6f) {
eheap_table[i] = BLI_heap_insert(eheap, cost, e);
}
else {
diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c
index 9d5a4630f68..e0c4cbe9990 100644
--- a/source/blender/blenlib/intern/rct.c
+++ b/source/blender/blenlib/intern/rct.c
@@ -351,6 +351,22 @@ void BLI_rcti_init(rcti *rect, int xmin, int xmax, int ymin, int ymax)
}
}
+void BLI_rctf_init_pt_radius(rctf *rect, const float xy[2], float size)
+{
+ rect->xmin = xy[0] - size;
+ rect->xmax = xy[0] + size;
+ rect->ymin = xy[1] - size;
+ rect->ymax = xy[1] + size;
+}
+
+void BLI_rcti_init_pt_radius(rcti *rect, const int xy[2], int size)
+{
+ rect->xmin = xy[0] - size;
+ rect->xmax = xy[0] + size;
+ rect->ymin = xy[1] - size;
+ rect->ymax = xy[1] + size;
+}
+
void BLI_rcti_init_minmax(rcti *rect)
{
rect->xmin = rect->ymin = INT_MAX;
@@ -420,20 +436,16 @@ void BLI_rctf_recenter(rctf *rect, float x, float y)
/* change width & height around the central location */
void BLI_rcti_resize(rcti *rect, int x, int y)
{
- rect->xmin = rect->xmax = BLI_rcti_cent_x(rect);
- rect->ymin = rect->ymax = BLI_rcti_cent_y(rect);
- rect->xmin -= x / 2;
- rect->ymin -= y / 2;
+ rect->xmin = BLI_rcti_cent_x(rect) - (x / 2);
+ rect->ymin = BLI_rcti_cent_y(rect) - (y / 2);
rect->xmax = rect->xmin + x;
rect->ymax = rect->ymin + y;
}
void BLI_rctf_resize(rctf *rect, float x, float y)
{
- rect->xmin = rect->xmax = BLI_rctf_cent_x(rect);
- rect->ymin = rect->ymax = BLI_rctf_cent_y(rect);
- rect->xmin -= x * 0.5f;
- rect->ymin -= y * 0.5f;
+ rect->xmin = BLI_rctf_cent_x(rect) - (x * 0.5f);
+ rect->ymin = BLI_rctf_cent_y(rect) - (y * 0.5f);
rect->xmax = rect->xmin + x;
rect->ymax = rect->ymin + y;
}
@@ -681,6 +693,14 @@ void BLI_rcti_rctf_copy_floor(rcti *dst, const rctf *src)
dst->ymax = floorf(src->ymax);
}
+void BLI_rcti_rctf_copy_round(rcti *dst, const rctf *src)
+{
+ dst->xmin = floorf(src->xmin + 0.5f);
+ dst->xmax = floorf(src->xmax + 0.5f);
+ dst->ymin = floorf(src->ymin + 0.5f);
+ dst->ymax = floorf(src->ymax + 0.5f);
+}
+
void BLI_rctf_rcti_copy(rctf *dst, const rcti *src)
{
dst->xmin = src->xmin;
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/smallhash.c b/source/blender/blenlib/intern/smallhash.c
index 0b976e9612e..ccac221d836 100644
--- a/source/blender/blenlib/intern/smallhash.c
+++ b/source/blender/blenlib/intern/smallhash.c
@@ -34,7 +34,7 @@
* based on a doubling hashing approach (non-chaining) which uses more buckets then entries
* stepping over buckets when two keys share the same hash so any key can find a free bucket.
*
- * See: http://en.wikipedia.org/wiki/Double_hashing
+ * See: https://en.wikipedia.org/wiki/Double_hashing
*
* \warning This should _only_ be used for small hashes where allocating a hash every time is unacceptable.
* Otherwise #GHash should be used instead.
diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c
index 3edc00a8c1a..b819c513fbd 100644
--- a/source/blender/blenlib/intern/storage.c
+++ b/source/blender/blenlib/intern/storage.c
@@ -113,7 +113,7 @@ double BLI_dir_free_space(const char *dir)
#ifdef WIN32
DWORD sectorspc, bytesps, freec, clusters;
char tmp[4];
-
+
tmp[0] = '\\'; tmp[1] = 0; /* Just a failsafe */
if (dir[0] == '/' || dir[0] == '\\') {
tmp[0] = '\\';
@@ -139,10 +139,10 @@ double BLI_dir_free_space(const char *dir)
char name[FILE_MAXDIR], *slash;
int len = strlen(dir);
-
+
if (len >= FILE_MAXDIR) /* path too long */
return -1;
-
+
strcpy(name, dir);
if (len) {
@@ -194,7 +194,7 @@ size_t BLI_file_size(const char *path)
*/
int BLI_exists(const char *name)
{
-#if defined(WIN32)
+#if defined(WIN32)
BLI_stat_t st;
wchar_t *tmp_16 = alloc_utf16_from_8(name, 1);
int len, res;
@@ -253,10 +253,8 @@ int BLI_stat(const char *path, BLI_stat_t *buffer)
int BLI_wstat(const wchar_t *path, BLI_stat_t *buffer)
{
-#if defined(_MSC_VER) || defined(__MINGW64__)
+#if defined(_MSC_VER)
return _wstat64(path, buffer);
-#elif defined(__MINGW32__)
- return _wstati64(path, buffer);
#else
return _wstat(path, buffer);
#endif
@@ -372,7 +370,7 @@ LinkNode *BLI_file_read_as_lines(const char *name)
size_t size;
if (!fp) return NULL;
-
+
fseek(fp, 0, SEEK_END);
size = (size_t)ftell(fp);
fseek(fp, 0, SEEK_SET);
@@ -385,7 +383,7 @@ LinkNode *BLI_file_read_as_lines(const char *name)
buf = MEM_mallocN(size, "file_as_lines");
if (buf) {
size_t i, last = 0;
-
+
/*
* size = because on win32 reading
* all the bytes in the file will return
@@ -403,10 +401,10 @@ LinkNode *BLI_file_read_as_lines(const char *name)
last = i + 1;
}
}
-
+
MEM_freeN(buf);
}
-
+
fclose(fp);
return lines.list;
@@ -424,23 +422,13 @@ void BLI_file_free_lines(LinkNode *lines)
bool BLI_file_older(const char *file1, const char *file2)
{
#ifdef WIN32
-#ifndef __MINGW32__
struct _stat st1, st2;
-#else
- struct _stati64 st1, st2;
-#endif
UTF16_ENCODE(file1);
UTF16_ENCODE(file2);
-
-#ifndef __MINGW32__
+
if (_wstat(file1_16, &st1)) return false;
if (_wstat(file2_16, &st2)) return false;
-#else
- if (_wstati64(file1_16, &st1)) return false;
- if (_wstati64(file2_16, &st2)) return false;
-#endif
-
UTF16_UN_ENCODE(file2);
UTF16_UN_ENCODE(file1);
diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c
index f62ffe9e985..6022732025b 100644
--- a/source/blender/blenlib/intern/string.c
+++ b/source/blender/blenlib/intern/string.c
@@ -332,7 +332,7 @@ size_t BLI_strescape(char *__restrict dst, const char *__restrict src, const siz
goto escape_finish;
case '\\':
case '"':
- /* fall-through */
+ ATTR_FALLTHROUGH;
/* less common but should also be support */
case '\t':
@@ -346,7 +346,7 @@ size_t BLI_strescape(char *__restrict dst, const char *__restrict src, const siz
/* not enough space to escape */
break;
}
- /* fall-through */
+ ATTR_FALLTHROUGH;
default:
*dst = *src;
break;
diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c
index 96033615cf5..229a97a2fa7 100644
--- a/source/blender/blenlib/intern/string_utf8.c
+++ b/source/blender/blenlib/intern/string_utf8.c
@@ -47,6 +47,19 @@
// #define DEBUG_STRSIZE
+/* array copied from glib's gutf8.c, */
+/* Note: last two values (0xfe and 0xff) are forbidden in utf-8, so they are considered 1 byte length too. */
+static const size_t utf8_skip_data[256] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1
+};
+
/* from libswish3, originally called u8_isvalid(),
* modified to return the index of the bad character (byte index not utf).
* http://svn.swish-e.org/libswish3/trunk/src/libswish3/utf8.c r3044 - campbell */
@@ -56,73 +69,91 @@
* length is in bytes, since without knowing whether the string is valid
* it's hard to know how many characters there are! */
-static const char trailingBytesForUTF8[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
-};
-
-int BLI_utf8_invalid_byte(const char *str, int length)
+/**
+ * Find first utf-8 invalid byte in given \a str, of \a length bytes.
+ *
+ * \return the offset of the first invalid byte.
+ */
+ptrdiff_t BLI_utf8_invalid_byte(const char *str, size_t length)
{
- const unsigned char *p, *pend = (const unsigned char *)str + length;
+ const unsigned char *p, *perr, *pend = (const unsigned char *)str + length;
unsigned char c;
int ab;
- for (p = (const unsigned char *)str; p < pend; p++) {
+ for (p = (const unsigned char *)str; p < pend; p++, length--) {
c = *p;
+ perr = p; /* Erroneous char is always the first of an invalid utf8 sequence... */
+ if (ELEM(c, 0xfe, 0xff, 0x00)) /* Those three values are not allowed in utf8 string. */
+ goto utf8_error;
if (c < 128)
continue;
if ((c & 0xc0) != 0xc0)
goto utf8_error;
- ab = trailingBytesForUTF8[c];
- if (length < ab)
+
+ /* Note that since we always increase p (and decrease length) by one byte in main loop, we only add/subtract
+ * extra utf8 bytes in code below
+ * (ab number, aka number of bytes remaining in the utf8 sequence after the initial one). */
+ ab = (int)utf8_skip_data[c] - 1;
+ if (length <= ab) {
goto utf8_error;
- length -= ab;
+ }
- p++;
/* Check top bits in the second byte */
+ p++;
+ length--;
if ((*p & 0xc0) != 0x80)
goto utf8_error;
/* Check for overlong sequences for each different length */
switch (ab) {
- /* Check for xx00 000x */
- case 1:
- if ((c & 0x3e) == 0) goto utf8_error;
- continue; /* We know there aren't any more bytes to check */
-
- /* Check for 1110 0000, xx0x xxxx */
- case 2:
- if (c == 0xe0 && (*p & 0x20) == 0) goto utf8_error;
- break;
-
- /* Check for 1111 0000, xx00 xxxx */
- case 3:
- if (c == 0xf0 && (*p & 0x30) == 0) goto utf8_error;
- break;
-
- /* Check for 1111 1000, xx00 0xxx */
- case 4:
- if (c == 0xf8 && (*p & 0x38) == 0) goto utf8_error;
- break;
-
- /* Check for leading 0xfe or 0xff,
- * and then for 1111 1100, xx00 00xx */
- case 5:
- if (c == 0xfe || c == 0xff ||
- (c == 0xfc && (*p & 0x3c) == 0)) goto utf8_error;
- break;
+ case 1:
+ /* Check for xx00 000x */
+ if ((c & 0x3e) == 0) goto utf8_error;
+ continue; /* We know there aren't any more bytes to check */
+
+ case 2:
+ /* Check for 1110 0000, xx0x xxxx */
+ if (c == 0xe0 && (*p & 0x20) == 0) goto utf8_error;
+ /* Some special cases, see section 5 of utf-8 decoder stress-test by Markus Kuhn
+ * (https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt). */
+ /* From section 5.1 (and 5.2) */
+ if (c == 0xed) {
+ if (*p == 0xa0 && *(p + 1) == 0x80) goto utf8_error;
+ if (*p == 0xad && *(p + 1) == 0xbf) goto utf8_error;
+ if (*p == 0xae && *(p + 1) == 0x80) goto utf8_error;
+ if (*p == 0xaf && *(p + 1) == 0xbf) goto utf8_error;
+ if (*p == 0xb0 && *(p + 1) == 0x80) goto utf8_error;
+ if (*p == 0xbe && *(p + 1) == 0x80) goto utf8_error;
+ if (*p == 0xbf && *(p + 1) == 0xbf) goto utf8_error;
+ }
+ /* From section 5.3 */
+ if (c == 0xef) {
+ if (*p == 0xbf && *(p + 1) == 0xbe) goto utf8_error;
+ if (*p == 0xbf && *(p + 1) == 0xbf) goto utf8_error;
+ }
+ break;
+
+ case 3:
+ /* Check for 1111 0000, xx00 xxxx */
+ if (c == 0xf0 && (*p & 0x30) == 0) goto utf8_error;
+ break;
+
+ case 4:
+ /* Check for 1111 1000, xx00 0xxx */
+ if (c == 0xf8 && (*p & 0x38) == 0) goto utf8_error;
+ break;
+
+ case 5:
+ /* Check for 1111 1100, xx00 00xx */
+ if (c == 0xfc && (*p & 0x3c) == 0) goto utf8_error;
+ break;
}
/* Check for valid bytes after the 2nd, if any; all must start 10 */
while (--ab > 0) {
- if ((*(p + 1) & 0xc0) != 0x80) goto utf8_error;
- p++; /* do this after so we get usable offset - campbell */
+ p++;
+ length--;
+ if ((*p & 0xc0) != 0x80) goto utf8_error;
}
}
@@ -130,18 +161,24 @@ int BLI_utf8_invalid_byte(const char *str, int length)
utf8_error:
- return (int)((const char *)p - (const char *)str) - 1;
+ return ((const char *)perr - (const char *)str);
}
-int BLI_utf8_invalid_strip(char *str, int length)
+/**
+ * Remove any invalid utf-8 byte (taking into account multi-bytes sequence of course).
+ *
+ * \return number of stripped bytes.
+ */
+int BLI_utf8_invalid_strip(char *str, size_t length)
{
- int bad_char, tot = 0;
+ ptrdiff_t bad_char;
+ int tot = 0;
BLI_assert(str[length] == '\0');
while ((bad_char = BLI_utf8_invalid_byte(str, length)) != -1) {
str += bad_char;
- length -= bad_char;
+ length -= (size_t)(bad_char + 1);
if (length == 0) {
/* last character bad, strip it */
@@ -151,7 +188,7 @@ int BLI_utf8_invalid_strip(char *str, int length)
}
else {
/* strip, keep looking */
- memmove(str, str + 1, (size_t)length);
+ memmove(str, str + 1, length + 1); /* +1 for NULL char! */
tot++;
}
}
@@ -162,31 +199,17 @@ int BLI_utf8_invalid_strip(char *str, int length)
/* compatible with BLI_strncpy, but esnure no partial utf8 chars */
-/* array copied from glib's gutf8.c,
- * note: this looks to be at odd's with 'trailingBytesForUTF8',
- * need to find out what gives here! - campbell */
-static const size_t utf8_skip_data[256] = {
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1
-};
-
#define BLI_STR_UTF8_CPY(dst, src, maxncpy) \
{ \
size_t utf8_size; \
while (*src != '\0' && (utf8_size = utf8_skip_data[*src]) < maxncpy) {\
maxncpy -= utf8_size; \
switch (utf8_size) { \
- case 6: *dst ++ = *src ++; \
- case 5: *dst ++ = *src ++; \
- case 4: *dst ++ = *src ++; \
- case 3: *dst ++ = *src ++; \
- case 2: *dst ++ = *src ++; \
+ case 6: *dst ++ = *src ++; ATTR_FALLTHROUGH; \
+ case 5: *dst ++ = *src ++; ATTR_FALLTHROUGH; \
+ case 4: *dst ++ = *src ++; ATTR_FALLTHROUGH; \
+ case 3: *dst ++ = *src ++; ATTR_FALLTHROUGH; \
+ case 2: *dst ++ = *src ++; ATTR_FALLTHROUGH; \
case 1: *dst ++ = *src ++; \
} \
} \
diff --git a/source/blender/blenlib/intern/string_utils.c b/source/blender/blenlib/intern/string_utils.c
new file mode 100644
index 00000000000..8d91a55a5ad
--- /dev/null
+++ b/source/blender/blenlib/intern/string_utils.c
@@ -0,0 +1,385 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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 the Blender FOundation.
+ * All rights reserved.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/blenlib/intern/string_utils.c
+ * \ingroup bli
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_string_utf8.h"
+#include "BLI_string_utils.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_listBase.h"
+
+
+#ifdef __GNUC__
+# pragma GCC diagnostic error "-Wsign-conversion"
+#endif
+
+/**
+ * Looks for a numeric suffix preceded by delim character on the end of
+ * name, puts preceding part into *left and value of suffix into *nr.
+ * Returns the length of *left.
+ *
+ * Foo.001 -> "Foo", 1
+ * Returning the length of "Foo"
+ *
+ * \param left Where to return copy of part preceding delim
+ * \param nr Where to return value of numeric suffix
+ * \param name String to split
+ * \param delim Delimiter character
+ * \return Length of \a left
+ */
+size_t BLI_split_name_num(char *left, int *nr, const char *name, const char delim)
+{
+ const size_t name_len = strlen(name);
+
+ *nr = 0;
+ memcpy(left, name, (name_len + 1) * sizeof(char));
+
+ /* name doesn't end with a delimiter "foo." */
+ if ((name_len > 1 && name[name_len - 1] == delim) == 0) {
+ size_t a = name_len;
+ while (a--) {
+ if (name[a] == delim) {
+ left[a] = '\0'; /* truncate left part here */
+ *nr = atol(name + a + 1);
+ /* casting down to an int, can overflow for large numbers */
+ if (*nr < 0)
+ *nr = 0;
+ return a;
+ }
+ else if (isdigit(name[a]) == 0) {
+ /* non-numeric suffix - give up */
+ break;
+ }
+ }
+ }
+
+ return name_len;
+}
+
+static bool is_char_sep(const char c)
+{
+ return ELEM(c, '.', ' ', '-', '_');
+}
+
+/**
+ * based on `BLI_split_dirfile()` / `os.path.splitext()`,
+ * `"a.b.c"` -> (`"a.b"`, `".c"`).
+ */
+void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len)
+{
+ size_t len = BLI_strnlen(string, str_len);
+ size_t i;
+
+ r_body[0] = r_suf[0] = '\0';
+
+ for (i = len; i > 0; i--) {
+ if (is_char_sep(string[i])) {
+ BLI_strncpy(r_body, string, i + 1);
+ BLI_strncpy(r_suf, string + i, (len + 1) - i);
+ return;
+ }
+ }
+
+ memcpy(r_body, string, len + 1);
+}
+
+/**
+ * `"a.b.c"` -> (`"a."`, `"b.c"`)
+ */
+void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len)
+{
+ size_t len = BLI_strnlen(string, str_len);
+ size_t i;
+
+ r_body[0] = r_pre[0] = '\0';
+
+ for (i = 1; i < len; i++) {
+ if (is_char_sep(string[i])) {
+ i++;
+ BLI_strncpy(r_pre, string, i + 1);
+ BLI_strncpy(r_body, string + i, (len + 1) - i);
+ return;
+ }
+ }
+
+ BLI_strncpy(r_body, string, len);
+}
+
+/**
+ * Finds the best possible flipped (left/right) name. For renaming; check for unique names afterwards.
+ *
+ * \param r_name flipped name, assumed to be a pointer to a string of at least \a name_len size.
+ * \param from_name original name, assumed to be a pointer to a string of at least \a name_len size.
+ * \param strip_number If set, remove number extensions.
+ */
+void BLI_string_flip_side_name(char *r_name, const char *from_name, const bool strip_number, const size_t name_len)
+{
+ size_t len;
+ char *prefix = alloca(name_len); /* The part before the facing */
+ char *suffix = alloca(name_len); /* The part after the facing */
+ char *replace = alloca(name_len); /* The replacement string */
+ char *number = alloca(name_len); /* The number extension string */
+ char *index = NULL;
+ bool is_set = false;
+
+ *prefix = *suffix = *replace = *number = '\0';
+
+ /* always copy the name, since this can be called with an uninitialized string */
+ BLI_strncpy(r_name, from_name, name_len);
+
+ len = BLI_strnlen(from_name, name_len);
+ if (len < 3) {
+ /* we don't do names like .R or .L */
+ return;
+ }
+
+ /* We first check the case with a .### extension, let's find the last period */
+ if (isdigit(r_name[len - 1])) {
+ index = strrchr(r_name, '.'); // last occurrence
+ if (index && isdigit(index[1])) { // doesnt handle case bone.1abc2 correct..., whatever!
+ if (strip_number == false) {
+ BLI_strncpy(number, index, name_len);
+ }
+ *index = 0;
+ len = BLI_strnlen(r_name, name_len);
+ }
+ }
+
+ BLI_strncpy(prefix, r_name, name_len);
+
+ /* first case; separator . - _ with extensions r R l L */
+ if ((len > 1) && is_char_sep(r_name[len - 2])) {
+ is_set = true;
+ switch (r_name[len - 1]) {
+ case 'l':
+ prefix[len - 1] = 0;
+ strcpy(replace, "r");
+ break;
+ case 'r':
+ prefix[len - 1] = 0;
+ strcpy(replace, "l");
+ break;
+ case 'L':
+ prefix[len - 1] = 0;
+ strcpy(replace, "R");
+ break;
+ case 'R':
+ prefix[len - 1] = 0;
+ strcpy(replace, "L");
+ break;
+ default:
+ is_set = false;
+ }
+ }
+
+ /* case; beginning with r R l L, with separator after it */
+ if (!is_set && is_char_sep(r_name[1])) {
+ is_set = true;
+ switch (r_name[0]) {
+ case 'l':
+ strcpy(replace, "r");
+ BLI_strncpy(suffix, r_name + 1, name_len);
+ prefix[0] = 0;
+ break;
+ case 'r':
+ strcpy(replace, "l");
+ BLI_strncpy(suffix, r_name + 1, name_len);
+ prefix[0] = 0;
+ break;
+ case 'L':
+ strcpy(replace, "R");
+ BLI_strncpy(suffix, r_name + 1, name_len);
+ prefix[0] = 0;
+ break;
+ case 'R':
+ strcpy(replace, "L");
+ BLI_strncpy(suffix, r_name + 1, name_len);
+ prefix[0] = 0;
+ break;
+ default:
+ is_set = false;
+ }
+ }
+
+ if (!is_set && len > 5) {
+ /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */
+ if (((index = BLI_strcasestr(prefix, "right")) == prefix) ||
+ (index == prefix + len - 5))
+ {
+ is_set = true;
+ if (index[0] == 'r') {
+ strcpy(replace, "left");
+ }
+ else {
+ strcpy(replace, (index[1] == 'I') ? "LEFT" : "Left");
+ }
+ *index = 0;
+ BLI_strncpy(suffix, index + 5, name_len);
+ }
+ else if (((index = BLI_strcasestr(prefix, "left")) == prefix) ||
+ (index == prefix + len - 4))
+ {
+ is_set = true;
+ if (index[0] == 'l') {
+ strcpy(replace, "right");
+ }
+ else {
+ strcpy(replace, (index[1] == 'E') ? "RIGHT" : "Right");
+ }
+ *index = 0;
+ BLI_strncpy(suffix, index + 4, name_len);
+ }
+ }
+
+ BLI_snprintf(r_name, name_len, "%s%s%s%s", prefix, replace, suffix, number);
+}
+
+
+/* Unique name utils. */
+
+/**
+ * Ensures name is unique (according to criteria specified by caller in unique_check callback),
+ * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
+ *
+ * \param unique_check Return true if name is not unique
+ * \param arg Additional arg to unique_check--meaning is up to caller
+ * \param defname To initialize name if latter is empty
+ * \param delim Delimits numeric suffix in name
+ * \param name Name to be ensured unique
+ * \param name_len Maximum length of name area
+ * \return true if there if the name was changed
+ */
+bool BLI_uniquename_cb(
+ UniquenameCheckCallback unique_check, void *arg, const char *defname, char delim, char *name, size_t name_len)
+{
+ if (name[0] == '\0') {
+ BLI_strncpy(name, defname, name_len);
+ }
+
+ if (unique_check(arg, name)) {
+ char numstr[16];
+ char *tempname = alloca(name_len);
+ char *left = alloca(name_len);
+ int number;
+ size_t len = BLI_split_name_num(left, &number, name, delim);
+ do {
+ /* add 1 to account for \0 */
+ const size_t numlen = BLI_snprintf(numstr, sizeof(numstr), "%c%03d", delim, ++number) + 1;
+
+ /* highly unlikely the string only has enough room for the number
+ * but support anyway */
+ if ((len == 0) || (numlen >= name_len)) {
+ /* number is know not to be utf-8 */
+ BLI_strncpy(tempname, numstr, name_len);
+ }
+ else {
+ char *tempname_buf;
+ tempname_buf = tempname + BLI_strncpy_utf8_rlen(tempname, left, name_len - numlen);
+ memcpy(tempname_buf, numstr, numlen);
+ }
+ } while (unique_check(arg, tempname));
+
+ BLI_strncpy(name, tempname, name_len);
+
+ return true;
+ }
+
+ return false;
+}
+
+/* little helper macro for BLI_uniquename */
+#ifndef GIVE_STRADDR
+# define GIVE_STRADDR(data, offset) ( ((char *)data) + offset)
+#endif
+
+/* Generic function to set a unique name. It is only designed to be used in situations
+ * where the name is part of the struct.
+ *
+ * For places where this is used, see constraint.c for example...
+ *
+ * name_offs: should be calculated using offsetof(structname, membername) macro from stddef.h
+ * len: maximum length of string (to prevent overflows, etc.)
+ * defname: the name that should be used by default if none is specified already
+ * delim: the character which acts as a delimiter between parts of the name
+ */
+static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, int name_offs)
+{
+ Link *link;
+
+ for (link = list->first; link; link = link->next) {
+ if (link != vlink) {
+ if (STREQ(GIVE_STRADDR(link, name_offs), name)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static bool uniquename_unique_check(void *arg, const char *name)
+{
+ struct {ListBase *lb; void *vlink; int name_offs; } *data = arg;
+ return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offs);
+}
+
+/**
+ * Ensures that the specified block has a unique name within the containing list,
+ * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
+ *
+ * \param list List containing the block
+ * \param vlink The block to check the name for
+ * \param defname To initialize block name if latter is empty
+ * \param delim Delimits numeric suffix in name
+ * \param name_offs Offset of name within block structure
+ * \param name_len Maximum length of name area
+ */
+bool BLI_uniquename(ListBase *list, void *vlink, const char *defname, char delim, int name_offs, size_t name_len)
+{
+ struct {ListBase *lb; void *vlink; int name_offs; } data;
+ data.lb = list;
+ data.vlink = vlink;
+ data.name_offs = name_offs;
+
+ BLI_assert(name_len > 1);
+
+ /* See if we are given an empty string */
+ if (ELEM(NULL, vlink, defname))
+ return false;
+
+ return BLI_uniquename_cb(uniquename_unique_check, &data, defname, delim, GIVE_STRADDR(vlink, name_offs), name_len);
+}
diff --git a/source/blender/blenlib/intern/system.c b/source/blender/blenlib/intern/system.c
index 5d1bdd6d978..863622f2546 100644
--- a/source/blender/blenlib/intern/system.c
+++ b/source/blender/blenlib/intern/system.c
@@ -25,6 +25,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include "BLI_utildefines.h"
#include "BLI_system.h"
#include "MEM_guardedalloc.h"
@@ -34,7 +35,7 @@
# include <execinfo.h>
#elif defined(WIN32)
# include <windows.h>
-# include <DbgHelp.h>
+# include <dbghelp.h>
#endif
int BLI_cpu_support_sse2(void)
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
index bd7b7f9cdbd..e050f3148b8 100644
--- a/source/blender/blenlib/intern/task.c
+++ b/source/blender/blenlib/intern/task.c
@@ -48,6 +48,39 @@
*/
#define MEMPOOL_SIZE 256
+/* Number of tasks which are pushed directly to local thread queue.
+ *
+ * This allows thread to fetch next task without locking the whole queue.
+ */
+#define LOCAL_QUEUE_SIZE 1
+
+/* Number of tasks which are allowed to be scheduled in a delayed manner.
+ *
+ * This allows to use less locks per graph node children schedule. More details
+ * could be found at TaskThreadLocalStorage::do_delayed_push.
+ */
+#define DELAYED_QUEUE_SIZE 4096
+
+#ifndef NDEBUG
+# define ASSERT_THREAD_ID(scheduler, thread_id) \
+ do { \
+ if (!BLI_thread_is_main()) { \
+ TaskThread *thread = pthread_getspecific(scheduler->tls_id_key); \
+ if (thread == NULL) { \
+ BLI_assert(thread_id == 0); \
+ } \
+ else { \
+ BLI_assert(thread_id == thread->id); \
+ } \
+ } \
+ else { \
+ BLI_assert(thread_id == 0); \
+ } \
+ } while (false)
+#else
+# define ASSERT_THREAD_ID(scheduler, thread_id)
+#endif
+
typedef struct Task {
struct Task *next, *prev;
@@ -102,13 +135,35 @@ typedef struct TaskMemPoolStats {
} TaskMemPoolStats;
#endif
+typedef struct TaskThreadLocalStorage {
+ /* Memory pool for faster task allocation.
+ * The idea is to re-use memory of finished/discarded tasks by this thread.
+ */
+ TaskMemPool task_mempool;
+
+ /* Local queue keeps thread alive by keeping small amount of tasks ready
+ * to be picked up without causing global thread locks for synchronization.
+ */
+ int num_local_queue;
+ Task *local_queue[LOCAL_QUEUE_SIZE];
+
+ /* Thread can be marked for delayed tasks push. This is helpful when it's
+ * know that lots of subsequent task pushed will happen from the same thread
+ * without "interrupting" for task execution.
+ *
+ * We try to accumulate as much tasks as possible in a local queue without
+ * any locks first, and then we push all of them into a scheduler's queue
+ * from within a single mutex lock.
+ */
+ bool do_delayed_push;
+ int num_delayed_queue;
+ Task *delayed_queue[DELAYED_QUEUE_SIZE];
+} TaskThreadLocalStorage;
+
struct TaskPool {
TaskScheduler *scheduler;
volatile size_t num;
- volatile size_t done;
- size_t num_threads;
- size_t currently_running_tasks;
ThreadMutex num_mutex;
ThreadCondition num_cond;
@@ -116,6 +171,11 @@ struct TaskPool {
ThreadMutex user_mutex;
volatile bool do_cancel;
+ volatile bool do_work;
+
+ volatile bool is_suspended;
+ ListBase suspended_queue;
+ size_t num_suspended;
/* If set, this pool may never be work_and_wait'ed, which means TaskScheduler
* has to use its special background fallback thread in case we are in
@@ -123,16 +183,20 @@ struct TaskPool {
*/
bool run_in_background;
- /* This pool is used for caching task pointers for thread id 0.
- * This could either point to a global scheduler's task_mempool[0] if the
- * pool is handled form the main thread or point to task_mempool_local
- * otherwise.
- *
- * This way we solve possible threading conflicts accessing same global
- * memory pool from multiple threads from which wait_work() is called.
+ /* This is a task scheduler's ID of a thread at which pool was constructed.
+ * It will be used to access task TLS.
+ */
+ int thread_id;
+
+ /* For the pools which are created from non-main thread which is not a
+ * scheduler worker thread we can't re-use any of scheduler's threads TLS
+ * and have to use our own one.
*/
- TaskMemPool *task_mempool;
- TaskMemPool task_mempool_local;
+ bool use_local_tls;
+ TaskThreadLocalStorage local_tls;
+#ifndef NDEBUG
+ pthread_t creator_thread_id;
+#endif
#ifdef DEBUG_STATS
TaskMemPoolStats *mempool_stats;
@@ -142,7 +206,6 @@ struct TaskPool {
struct TaskScheduler {
pthread_t *threads;
struct TaskThread *task_threads;
- TaskMemPool *task_mempool;
int num_threads;
bool background_thread_only;
@@ -151,15 +214,19 @@ struct TaskScheduler {
ThreadCondition queue_cond;
volatile bool do_exit;
+
+ /* NOTE: In pthread's TLS we store the whole TaskThread structure. */
+ pthread_key_t tls_id_key;
};
typedef struct TaskThread {
TaskScheduler *scheduler;
int id;
+ TaskThreadLocalStorage tls;
} TaskThread;
/* Helper */
-static void task_data_free(Task *task, const int thread_id)
+BLI_INLINE void task_data_free(Task *task, const int thread_id)
{
if (task->free_taskdata) {
if (task->freedata) {
@@ -171,28 +238,54 @@ static void task_data_free(Task *task, const int thread_id)
}
}
-BLI_INLINE TaskMemPool *get_task_mempool(TaskPool *pool, const int thread_id)
+BLI_INLINE void initialize_task_tls(TaskThreadLocalStorage *tls)
+{
+ memset(tls, 0, sizeof(TaskThreadLocalStorage));
+}
+
+BLI_INLINE TaskThreadLocalStorage *get_task_tls(TaskPool *pool,
+ const int thread_id)
{
+ TaskScheduler *scheduler = pool->scheduler;
+ BLI_assert(thread_id >= 0);
+ BLI_assert(thread_id <= scheduler->num_threads);
+ if (pool->use_local_tls && thread_id == 0) {
+ BLI_assert(pool->thread_id == 0);
+ BLI_assert(!BLI_thread_is_main());
+ BLI_assert(pthread_equal(pthread_self(), pool->creator_thread_id));
+ return &pool->local_tls;
+ }
if (thread_id == 0) {
- return pool->task_mempool;
+ BLI_assert(BLI_thread_is_main());
+ return &scheduler->task_threads[pool->thread_id].tls;
+ }
+ return &scheduler->task_threads[thread_id].tls;
+}
+
+BLI_INLINE void free_task_tls(TaskThreadLocalStorage *tls)
+{
+ TaskMemPool *task_mempool = &tls->task_mempool;
+ for (int i = 0; i < task_mempool->num_tasks; ++i) {
+ MEM_freeN(task_mempool->tasks[i]);
}
- return &pool->scheduler->task_mempool[thread_id];
}
static Task *task_alloc(TaskPool *pool, const int thread_id)
{
- assert(thread_id <= pool->scheduler->num_threads);
+ BLI_assert(thread_id <= pool->scheduler->num_threads);
if (thread_id != -1) {
- assert(thread_id >= 0);
- TaskMemPool *mem_pool = get_task_mempool(pool, thread_id);
+ BLI_assert(thread_id >= 0);
+ BLI_assert(thread_id <= pool->scheduler->num_threads);
+ TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id);
+ TaskMemPool *task_mempool = &tls->task_mempool;
/* Try to re-use task memory from a thread local storage. */
- if (mem_pool->num_tasks > 0) {
- --mem_pool->num_tasks;
+ if (task_mempool->num_tasks > 0) {
+ --task_mempool->num_tasks;
/* Success! We've just avoided task allocation. */
#ifdef DEBUG_STATS
pool->mempool_stats[thread_id].num_reuse++;
#endif
- return mem_pool->tasks[mem_pool->num_tasks];
+ return task_mempool->tasks[task_mempool->num_tasks];
}
/* We are doomed to allocate new task data. */
#ifdef DEBUG_STATS
@@ -205,13 +298,17 @@ static Task *task_alloc(TaskPool *pool, const int thread_id)
static void task_free(TaskPool *pool, Task *task, const int thread_id)
{
task_data_free(task, thread_id);
- assert(thread_id >= 0);
- assert(thread_id <= pool->scheduler->num_threads);
- TaskMemPool *mem_pool = get_task_mempool(pool, thread_id);
- if (mem_pool->num_tasks < MEMPOOL_SIZE - 1) {
+ BLI_assert(thread_id >= 0);
+ BLI_assert(thread_id <= pool->scheduler->num_threads);
+ if (thread_id == 0) {
+ BLI_assert(pool->use_local_tls || BLI_thread_is_main());
+ }
+ TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id);
+ TaskMemPool *task_mempool = &tls->task_mempool;
+ if (task_mempool->num_tasks < MEMPOOL_SIZE - 1) {
/* Successfully allowed the task to be re-used later. */
- mem_pool->tasks[mem_pool->num_tasks] = task;
- ++mem_pool->num_tasks;
+ task_mempool->tasks[task_mempool->num_tasks] = task;
+ ++task_mempool->num_tasks;
}
else {
/* Local storage saturated, no other way than just discard
@@ -237,8 +334,6 @@ static void task_pool_num_decrease(TaskPool *pool, size_t done)
BLI_assert(pool->num >= done);
pool->num -= done;
- atomic_sub_z(&pool->currently_running_tasks, done);
- pool->done += done;
if (pool->num == 0)
BLI_condition_notify_all(&pool->num_cond);
@@ -246,11 +341,11 @@ static void task_pool_num_decrease(TaskPool *pool, size_t done)
BLI_mutex_unlock(&pool->num_mutex);
}
-static void task_pool_num_increase(TaskPool *pool)
+static void task_pool_num_increase(TaskPool *pool, size_t new)
{
BLI_mutex_lock(&pool->num_mutex);
- pool->num++;
+ pool->num += new;
BLI_condition_notify_all(&pool->num_cond);
BLI_mutex_unlock(&pool->num_mutex);
@@ -292,15 +387,10 @@ static bool task_scheduler_thread_wait_pop(TaskScheduler *scheduler, Task **task
continue;
}
- if (pool->num_threads == 0 ||
- pool->currently_running_tasks < pool->num_threads)
- {
- *task = current_task;
- found_task = true;
- atomic_add_z(&pool->currently_running_tasks, 1);
- BLI_remlink(&scheduler->queue, *task);
- break;
- }
+ *task = current_task;
+ found_task = true;
+ BLI_remlink(&scheduler->queue, *task);
+ break;
}
if (!found_task)
BLI_condition_wait(&scheduler->queue_cond, &scheduler->queue_mutex);
@@ -311,23 +401,51 @@ static bool task_scheduler_thread_wait_pop(TaskScheduler *scheduler, Task **task
return true;
}
+BLI_INLINE void handle_local_queue(TaskThreadLocalStorage *tls,
+ const int thread_id)
+{
+ BLI_assert(!tls->do_delayed_push);
+ while (tls->num_local_queue > 0) {
+ /* We pop task from queue before handling it so handler of the task can
+ * push next job to the local queue.
+ */
+ tls->num_local_queue--;
+ Task *local_task = tls->local_queue[tls->num_local_queue];
+ /* TODO(sergey): Double-check work_and_wait() doesn't handle other's
+ * pool tasks.
+ */
+ TaskPool *local_pool = local_task->pool;
+ local_task->run(local_pool, local_task->taskdata, thread_id);
+ task_free(local_pool, local_task, thread_id);
+ }
+ BLI_assert(!tls->do_delayed_push);
+}
+
static void *task_scheduler_thread_run(void *thread_p)
{
TaskThread *thread = (TaskThread *) thread_p;
+ TaskThreadLocalStorage *tls = &thread->tls;
TaskScheduler *scheduler = thread->scheduler;
int thread_id = thread->id;
Task *task;
+ pthread_setspecific(scheduler->tls_id_key, thread);
+
/* keep popping off tasks */
while (task_scheduler_thread_wait_pop(scheduler, &task)) {
TaskPool *pool = task->pool;
/* run task */
+ BLI_assert(!tls->do_delayed_push);
task->run(pool, task->taskdata, thread_id);
+ BLI_assert(!tls->do_delayed_push);
/* delete task */
task_free(pool, task, thread_id);
+ /* Handle all tasks from local queue. */
+ handle_local_queue(tls, thread_id);
+
/* notify pool task was done */
task_pool_num_decrease(pool, 1);
}
@@ -357,30 +475,35 @@ TaskScheduler *BLI_task_scheduler_create(int num_threads)
/* Add background-only thread if needed. */
if (num_threads == 0) {
- scheduler->background_thread_only = true;
- num_threads = 1;
+ scheduler->background_thread_only = true;
+ num_threads = 1;
}
+ scheduler->task_threads = MEM_mallocN(sizeof(TaskThread) * (num_threads + 1),
+ "TaskScheduler task threads");
+
+ /* Initialize TLS for main thread. */
+ initialize_task_tls(&scheduler->task_threads[0].tls);
+
+ pthread_key_create(&scheduler->tls_id_key, NULL);
+
/* launch threads that will be waiting for work */
if (num_threads > 0) {
int i;
scheduler->num_threads = num_threads;
scheduler->threads = MEM_callocN(sizeof(pthread_t) * num_threads, "TaskScheduler threads");
- scheduler->task_threads = MEM_callocN(sizeof(TaskThread) * num_threads, "TaskScheduler task threads");
for (i = 0; i < num_threads; i++) {
- TaskThread *thread = &scheduler->task_threads[i];
+ TaskThread *thread = &scheduler->task_threads[i + 1];
thread->scheduler = scheduler;
thread->id = i + 1;
+ initialize_task_tls(&thread->tls);
if (pthread_create(&scheduler->threads[i], NULL, task_scheduler_thread_run, thread) != 0) {
fprintf(stderr, "TaskScheduler failed to launch thread %d/%d\n", i, num_threads);
}
}
-
- scheduler->task_mempool = MEM_callocN(sizeof(*scheduler->task_mempool) * (num_threads + 1),
- "TaskScheduler task_mempool");
}
return scheduler;
@@ -396,6 +519,8 @@ void BLI_task_scheduler_free(TaskScheduler *scheduler)
BLI_condition_notify_all(&scheduler->queue_cond);
BLI_mutex_unlock(&scheduler->queue_mutex);
+ pthread_key_delete(scheduler->tls_id_key);
+
/* delete threads */
if (scheduler->threads) {
int i;
@@ -410,17 +535,12 @@ void BLI_task_scheduler_free(TaskScheduler *scheduler)
/* Delete task thread data */
if (scheduler->task_threads) {
- MEM_freeN(scheduler->task_threads);
- }
-
- /* Delete task memory pool */
- if (scheduler->task_mempool) {
- for (int i = 0; i <= scheduler->num_threads; ++i) {
- for (int j = 0; j < scheduler->task_mempool[i].num_tasks; ++j) {
- MEM_freeN(scheduler->task_mempool[i].tasks[j]);
- }
+ for (int i = 0; i < scheduler->num_threads + 1; ++i) {
+ TaskThreadLocalStorage *tls = &scheduler->task_threads[i].tls;
+ free_task_tls(tls);
}
- MEM_freeN(scheduler->task_mempool);
+
+ MEM_freeN(scheduler->task_threads);
}
/* delete leftover tasks */
@@ -443,7 +563,7 @@ int BLI_task_scheduler_num_threads(TaskScheduler *scheduler)
static void task_scheduler_push(TaskScheduler *scheduler, Task *task, TaskPriority priority)
{
- task_pool_num_increase(task->pool);
+ task_pool_num_increase(task->pool, 1);
/* add task to queue */
BLI_mutex_lock(&scheduler->queue_mutex);
@@ -457,6 +577,27 @@ static void task_scheduler_push(TaskScheduler *scheduler, Task *task, TaskPriori
BLI_mutex_unlock(&scheduler->queue_mutex);
}
+static void task_scheduler_push_all(TaskScheduler *scheduler,
+ TaskPool *pool,
+ Task **tasks,
+ int num_tasks)
+{
+ if (num_tasks == 0) {
+ return;
+ }
+
+ task_pool_num_increase(pool, num_tasks);
+
+ BLI_mutex_lock(&scheduler->queue_mutex);
+
+ for (int i = 0; i < num_tasks; i++) {
+ BLI_addhead(&scheduler->queue, tasks[i]);
+ }
+
+ BLI_condition_notify_all(&scheduler->queue_cond);
+ BLI_mutex_unlock(&scheduler->queue_mutex);
+}
+
static void task_scheduler_clear(TaskScheduler *scheduler, TaskPool *pool)
{
Task *task, *nexttask;
@@ -469,7 +610,7 @@ static void task_scheduler_clear(TaskScheduler *scheduler, TaskPool *pool)
nexttask = task->next;
if (task->pool == pool) {
- task_data_free(task, 0);
+ task_data_free(task, pool->thread_id);
BLI_freelinkN(&scheduler->queue, task);
done++;
@@ -484,7 +625,10 @@ static void task_scheduler_clear(TaskScheduler *scheduler, TaskPool *pool)
/* Task Pool */
-static TaskPool *task_pool_create_ex(TaskScheduler *scheduler, void *userdata, const bool is_background)
+static TaskPool *task_pool_create_ex(TaskScheduler *scheduler,
+ void *userdata,
+ const bool is_background,
+ const bool is_suspended)
{
TaskPool *pool = MEM_mallocN(sizeof(TaskPool), "TaskPool");
@@ -502,11 +646,13 @@ static TaskPool *task_pool_create_ex(TaskScheduler *scheduler, void *userdata, c
pool->scheduler = scheduler;
pool->num = 0;
- pool->done = 0;
- pool->num_threads = 0;
- pool->currently_running_tasks = 0;
pool->do_cancel = false;
+ pool->do_work = false;
+ pool->is_suspended = is_suspended;
+ pool->num_suspended = 0;
+ pool->suspended_queue.first = pool->suspended_queue.last = NULL;
pool->run_in_background = is_background;
+ pool->use_local_tls = false;
BLI_mutex_init(&pool->num_mutex);
BLI_condition_init(&pool->num_cond);
@@ -515,11 +661,26 @@ static TaskPool *task_pool_create_ex(TaskScheduler *scheduler, void *userdata, c
BLI_mutex_init(&pool->user_mutex);
if (BLI_thread_is_main()) {
- pool->task_mempool = scheduler->task_mempool;
+ pool->thread_id = 0;
}
else {
- pool->task_mempool = &pool->task_mempool_local;
- pool->task_mempool_local.num_tasks = 0;
+ TaskThread *thread = pthread_getspecific(scheduler->tls_id_key);
+ if (thread == NULL) {
+ /* NOTE: Task pool is created from non-main thread which is not
+ * managed by the task scheduler. We identify ourselves as thread ID
+ * 0 but we do not use scheduler's TLS storage and use our own
+ * instead to avoid any possible threading conflicts.
+ */
+ pool->thread_id = 0;
+ pool->use_local_tls = true;
+#ifndef NDEBUG
+ pool->creator_thread_id = pthread_self();
+#endif
+ initialize_task_tls(&pool->local_tls);
+ }
+ else {
+ pool->thread_id = thread->id;
+ }
}
#ifdef DEBUG_STATS
@@ -546,7 +707,7 @@ static TaskPool *task_pool_create_ex(TaskScheduler *scheduler, void *userdata, c
*/
TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata)
{
- return task_pool_create_ex(scheduler, userdata, false);
+ return task_pool_create_ex(scheduler, userdata, false, false);
}
/**
@@ -561,25 +722,28 @@ TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata)
*/
TaskPool *BLI_task_pool_create_background(TaskScheduler *scheduler, void *userdata)
{
- return task_pool_create_ex(scheduler, userdata, true);
+ return task_pool_create_ex(scheduler, userdata, true, false);
+}
+
+/**
+ * Similar to BLI_task_pool_create() but does not schedule any tasks for execution
+ * for until BLI_task_pool_work_and_wait() is called. This helps reducing therading
+ * overhead when pushing huge amount of small initial tasks from the main thread.
+ */
+TaskPool *BLI_task_pool_create_suspended(TaskScheduler *scheduler, void *userdata)
+{
+ return task_pool_create_ex(scheduler, userdata, false, true);
}
void BLI_task_pool_free(TaskPool *pool)
{
- BLI_task_pool_stop(pool);
+ BLI_task_pool_cancel(pool);
BLI_mutex_end(&pool->num_mutex);
BLI_condition_end(&pool->num_cond);
BLI_mutex_end(&pool->user_mutex);
- /* Free local memory pool, those pointers are lost forever. */
- if (pool->task_mempool == &pool->task_mempool_local) {
- for (int i = 0; i < pool->task_mempool_local.num_tasks; i++) {
- MEM_freeN(pool->task_mempool_local.tasks[i]);
- }
- }
-
#ifdef DEBUG_STATS
printf("Thread ID Allocated Reused Discarded\n");
for (int i = 0; i < pool->scheduler->num_threads + 1; ++i) {
@@ -592,24 +756,68 @@ void BLI_task_pool_free(TaskPool *pool)
MEM_freeN(pool->mempool_stats);
#endif
+ if (pool->use_local_tls) {
+ free_task_tls(&pool->local_tls);
+ }
+
MEM_freeN(pool);
BLI_end_threaded_malloc();
}
+BLI_INLINE bool task_can_use_local_queues(TaskPool *pool, int thread_id)
+{
+ return (thread_id != -1 && (thread_id != pool->thread_id || pool->do_work));
+}
+
static void task_pool_push(
TaskPool *pool, TaskRunFunction run, void *taskdata,
bool free_taskdata, TaskFreeFunction freedata, TaskPriority priority,
int thread_id)
{
+ /* Allocate task and fill it's properties. */
Task *task = task_alloc(pool, thread_id);
-
task->run = run;
task->taskdata = taskdata;
task->free_taskdata = free_taskdata;
task->freedata = freedata;
task->pool = pool;
-
+ /* For suspended pools we put everything yo a global queue first
+ * and exit as soon as possible.
+ *
+ * This tasks will be moved to actual execution when pool is
+ * activated by work_and_wait().
+ */
+ if (pool->is_suspended) {
+ BLI_addhead(&pool->suspended_queue, task);
+ atomic_fetch_and_add_z(&pool->num_suspended, 1);
+ return;
+ }
+ /* Populate to any local queue first, this is cheapest push ever. */
+ if (task_can_use_local_queues(pool, thread_id)) {
+ ASSERT_THREAD_ID(pool->scheduler, thread_id);
+ TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id);
+ /* Try to push to a local execution queue.
+ * These tasks will be picked up next.
+ */
+ if (tls->num_local_queue < LOCAL_QUEUE_SIZE) {
+ tls->local_queue[tls->num_local_queue] = task;
+ tls->num_local_queue++;
+ return;
+ }
+ /* If we are in the delayed tasks push mode, we push tasks to a
+ * temporary local queue first without any locks, and then move them
+ * to global execution queue with a single lock.
+ */
+ if (tls->do_delayed_push && tls->num_delayed_queue < DELAYED_QUEUE_SIZE) {
+ tls->delayed_queue[tls->num_delayed_queue] = task;
+ tls->num_delayed_queue++;
+ return;
+ }
+ }
+ /* Do push to a global execution ppol, slowest possible method,
+ * causes quite reasonable amount of threading overhead.
+ */
task_scheduler_push(pool->scheduler, task, priority);
}
@@ -634,8 +842,25 @@ void BLI_task_pool_push_from_thread(TaskPool *pool, TaskRunFunction run,
void BLI_task_pool_work_and_wait(TaskPool *pool)
{
+ TaskThreadLocalStorage *tls = get_task_tls(pool, pool->thread_id);
TaskScheduler *scheduler = pool->scheduler;
+ if (atomic_fetch_and_and_uint8((uint8_t *)&pool->is_suspended, 0)) {
+ if (pool->num_suspended) {
+ task_pool_num_increase(pool, pool->num_suspended);
+ BLI_mutex_lock(&scheduler->queue_mutex);
+
+ BLI_movelisttolist(&scheduler->queue, &pool->suspended_queue);
+
+ BLI_condition_notify_all(&scheduler->queue_cond);
+ BLI_mutex_unlock(&scheduler->queue_mutex);
+ }
+ }
+
+ pool->do_work = true;
+
+ ASSERT_THREAD_ID(pool->scheduler, pool->thread_id);
+
BLI_mutex_lock(&pool->num_mutex);
while (pool->num != 0) {
@@ -649,16 +874,12 @@ void BLI_task_pool_work_and_wait(TaskPool *pool)
/* find task from this pool. if we get a task from another pool,
* we can get into deadlock */
- if (pool->num_threads == 0 ||
- pool->currently_running_tasks < pool->num_threads)
- {
- for (task = scheduler->queue.first; task; task = task->next) {
- if (task->pool == pool) {
- work_task = task;
- found_task = true;
- BLI_remlink(&scheduler->queue, task);
- break;
- }
+ for (task = scheduler->queue.first; task; task = task->next) {
+ if (task->pool == pool) {
+ work_task = task;
+ found_task = true;
+ BLI_remlink(&scheduler->queue, task);
+ break;
}
}
@@ -667,11 +888,15 @@ void BLI_task_pool_work_and_wait(TaskPool *pool)
/* if found task, do it, otherwise wait until other tasks are done */
if (found_task) {
/* run task */
- atomic_add_z(&pool->currently_running_tasks, 1);
- work_task->run(pool, work_task->taskdata, 0);
+ BLI_assert(!tls->do_delayed_push);
+ work_task->run(pool, work_task->taskdata, pool->thread_id);
+ BLI_assert(!tls->do_delayed_push);
/* delete task */
- task_free(pool, task, 0);
+ task_free(pool, task, pool->thread_id);
+
+ /* Handle all tasks from local queue. */
+ handle_local_queue(tls, pool->thread_id);
/* notify pool task was done */
task_pool_num_decrease(pool, 1);
@@ -686,22 +911,8 @@ void BLI_task_pool_work_and_wait(TaskPool *pool)
}
BLI_mutex_unlock(&pool->num_mutex);
-}
-
-int BLI_pool_get_num_threads(TaskPool *pool)
-{
- if (pool->num_threads != 0) {
- return pool->num_threads;
- }
- else {
- return BLI_task_scheduler_num_threads(pool->scheduler);
- }
-}
-void BLI_pool_set_num_threads(TaskPool *pool, int num_threads)
-{
- /* NOTE: Don't try to modify threads while tasks are running! */
- pool->num_threads = num_threads;
+ handle_local_queue(tls, pool->thread_id);
}
void BLI_task_pool_cancel(TaskPool *pool)
@@ -719,13 +930,6 @@ void BLI_task_pool_cancel(TaskPool *pool)
pool->do_cancel = false;
}
-void BLI_task_pool_stop(TaskPool *pool)
-{
- task_scheduler_clear(pool->scheduler, pool);
-
- BLI_assert(pool->num == 0);
-}
-
bool BLI_task_pool_canceled(TaskPool *pool)
{
return pool->do_cancel;
@@ -741,9 +945,28 @@ ThreadMutex *BLI_task_pool_user_mutex(TaskPool *pool)
return &pool->user_mutex;
}
-size_t BLI_task_pool_tasks_done(TaskPool *pool)
+void BLI_task_pool_delayed_push_begin(TaskPool *pool, int thread_id)
+{
+ if (task_can_use_local_queues(pool, thread_id)) {
+ ASSERT_THREAD_ID(pool->scheduler, thread_id);
+ TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id);
+ tls->do_delayed_push = true;
+ }
+}
+
+void BLI_task_pool_delayed_push_end(TaskPool *pool, int thread_id)
{
- return pool->done;
+ if (task_can_use_local_queues(pool, thread_id)) {
+ ASSERT_THREAD_ID(pool->scheduler, thread_id);
+ TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id);
+ BLI_assert(tls->do_delayed_push);
+ task_scheduler_push_all(pool->scheduler,
+ pool,
+ tls->delayed_queue,
+ tls->num_delayed_queue);
+ tls->do_delayed_push = false;
+ tls->num_delayed_queue = 0;
+ }
}
/* Parallel range routines */
@@ -780,9 +1003,10 @@ BLI_INLINE bool parallel_range_next_iter_get(
ParallelRangeState * __restrict state,
int * __restrict iter, int * __restrict count)
{
- uint32_t previter = atomic_fetch_and_add_uint32((uint32_t *)(&state->iter), state->chunk_size);
+ uint32_t uval = atomic_fetch_and_add_uint32((uint32_t *)(&state->iter), state->chunk_size);
+ int previter = *(int32_t *)&uval;
- *iter = (int)previter;
+ *iter = previter;
*count = max_ii(0, min_ii(state->chunk_size, state->stop - previter));
return (previter < state->stop);
@@ -903,7 +1127,7 @@ static void task_parallel_range_ex(
atomic_fetch_and_add_uint32((uint32_t *)(&state.iter), 0);
if (use_userdata_chunk) {
- userdata_chunk_array = MALLOCA(userdata_chunk_size * num_tasks);
+ userdata_chunk_array = MALLOCA(userdata_chunk_size * num_tasks);
}
for (i = 0; i < num_tasks; i++) {
@@ -915,7 +1139,8 @@ static void task_parallel_range_ex(
BLI_task_pool_push_from_thread(task_pool,
parallel_range_func,
userdata_chunk_local, false,
- TASK_PRIORITY_HIGH, 0);
+ TASK_PRIORITY_HIGH,
+ task_pool->thread_id);
}
BLI_task_pool_work_and_wait(task_pool);
@@ -1121,7 +1346,8 @@ void BLI_task_parallel_listbase(
BLI_task_pool_push_from_thread(task_pool,
parallel_listbase_func,
NULL, false,
- TASK_PRIORITY_HIGH, 0);
+ TASK_PRIORITY_HIGH,
+ task_pool->thread_id);
}
BLI_task_pool_work_and_wait(task_pool);
diff --git a/source/blender/blenlib/intern/threads.c b/source/blender/blenlib/intern/threads.c
index b60981802aa..abf611d1245 100644
--- a/source/blender/blenlib/intern/threads.c
+++ b/source/blender/blenlib/intern/threads.c
@@ -54,6 +54,8 @@
# include <sys/time.h>
#endif
+#include "atomic_ops.h"
+
#if defined(__APPLE__) && defined(_OPENMP) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 2) && !defined(__clang__)
# define USE_APPLE_OMP_FIX
#endif
@@ -124,7 +126,7 @@ static pthread_mutex_t _colormanage_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _fftw_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _view3d_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_t mainid;
-static int thread_levels = 0; /* threads can be invoked inside threads */
+static unsigned int thread_levels = 0; /* threads can be invoked inside threads */
static int num_threads_override = 0;
/* just a max for security reasons */
@@ -198,9 +200,9 @@ void BLI_init_threads(ListBase *threadbase, void *(*do_thread)(void *), int tot)
tslot->avail = 1;
}
}
-
- BLI_spin_lock(&_malloc_lock);
- if (thread_levels == 0) {
+
+ unsigned int level = atomic_fetch_and_add_u(&thread_levels, 1);
+ if (level == 0) {
MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread);
#ifdef USE_APPLE_OMP_FIX
@@ -210,9 +212,6 @@ void BLI_init_threads(ListBase *threadbase, void *(*do_thread)(void *), int tot)
thread_tls_data = pthread_getspecific(gomp_tls_key);
#endif
}
-
- thread_levels++;
- BLI_spin_unlock(&_malloc_lock);
}
/* amount of available threads */
@@ -331,11 +330,10 @@ void BLI_end_threads(ListBase *threadbase)
BLI_freelistN(threadbase);
}
- BLI_spin_lock(&_malloc_lock);
- thread_levels--;
- if (thread_levels == 0)
+ unsigned int level = atomic_sub_and_fetch_u(&thread_levels, 1);
+ if (level == 0) {
MEM_set_lock_callback(NULL, NULL);
- BLI_spin_unlock(&_malloc_lock);
+ }
}
/* System Information */
@@ -812,26 +810,22 @@ void BLI_thread_queue_wait_finish(ThreadQueue *queue)
void BLI_begin_threaded_malloc(void)
{
- /* Used for debug only */
- /* BLI_assert(thread_levels >= 0); */
-
- BLI_spin_lock(&_malloc_lock);
- if (thread_levels == 0) {
+ unsigned int level = atomic_fetch_and_add_u(&thread_levels, 1);
+ if (level == 0) {
MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread);
+ /* There is a little chance that two threads will meed to acces to a
+ * scheduler which was not yet created from main thread. which could
+ * cause scheduler created multiple times.
+ */
+ BLI_task_scheduler_get();
}
- thread_levels++;
- BLI_spin_unlock(&_malloc_lock);
}
void BLI_end_threaded_malloc(void)
{
- /* Used for debug only */
- /* BLI_assert(thread_levels >= 0); */
-
- BLI_spin_lock(&_malloc_lock);
- thread_levels--;
- if (thread_levels == 0)
+ unsigned int level = atomic_sub_and_fetch_u(&thread_levels, 1);
+ if (level == 0) {
MEM_set_lock_callback(NULL, NULL);
- BLI_spin_unlock(&_malloc_lock);
+ }
}
diff --git a/source/blender/blenlib/intern/winstuff.c b/source/blender/blenlib/intern/winstuff.c
index 3b06b7df09a..d6834428376 100644
--- a/source/blender/blenlib/intern/winstuff.c
+++ b/source/blender/blenlib/intern/winstuff.c
@@ -160,8 +160,6 @@ void RegisterBlendExtension(void)
GetSystemDirectory(SysDir, FILE_MAXDIR);
#ifdef _WIN64
ThumbHandlerDLL = "BlendThumb64.dll";
-#elif defined(__MINGW32__)
- ThumbHandlerDLL = "BlendThumb.dll";
#else
IsWow64Process(GetCurrentProcess(), &IsWOW64);
if (IsWOW64 == true)
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index c85cf128643..fe38fc86c84 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -39,15 +39,18 @@ extern "C" {
struct BlendThumbnail;
struct bScreen;
struct LinkNode;
+struct ListBase;
struct Main;
struct MemFile;
struct ReportList;
struct Scene;
+struct SceneLayer;
struct UserDef;
struct View3D;
struct bContext;
struct BHead;
struct FileData;
+struct wmWindowManager;
typedef struct BlendHandle BlendHandle;
@@ -64,18 +67,39 @@ typedef struct BlendFileData {
int fileflags;
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 SceneLayer *cur_render_layer; /* layer to activate in workspaces when reading without UI */
+
BlenFileType type;
} BlendFileData;
-BlendFileData *BLO_read_from_file(const char *filepath, struct ReportList *reports);
-BlendFileData *BLO_read_from_memory(const void *mem, int memsize, struct ReportList *reports);
+typedef struct WorkspaceConfigFileData {
+ struct Main *main; /* has to be freed when done reading file data */
+
+ struct ListBase workspaces;
+} WorkspaceConfigFileData;
+
+
+/* skip reading some data-block types (may want to skip screen data too). */
+typedef enum eBLOReadSkip {
+ BLO_READ_SKIP_NONE = 0,
+ BLO_READ_SKIP_USERDEF = (1 << 0),
+ BLO_READ_SKIP_DATA = (1 << 1),
+} eBLOReadSkip;
+#define BLO_READ_SKIP_ALL \
+ (BLO_READ_SKIP_USERDEF | BLO_READ_SKIP_DATA)
+
+BlendFileData *BLO_read_from_file(
+ const char *filepath,
+ struct ReportList *reports, eBLOReadSkip skip_flag);
+BlendFileData *BLO_read_from_memory(
+ const void *mem, int memsize,
+ struct ReportList *reports, eBLOReadSkip skip_flag);
BlendFileData *BLO_read_from_memfile(
struct Main *oldmain, const char *filename, struct MemFile *memfile,
- struct ReportList *reports);
+ struct ReportList *reports, eBLOReadSkip skip_flag);
void BLO_blendfiledata_free(BlendFileData *bfd);
@@ -85,6 +109,7 @@ BlendHandle *BLO_blendhandle_from_memory(const void *mem, int memsize);
struct LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype, int *tot_names);
struct LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *tot_prev);
struct LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh);
+struct LinkNode *BLO_blendhandle_get_appendable_groups(BlendHandle *bh);
void BLO_blendhandle_close(BlendHandle *bh);
@@ -100,9 +125,9 @@ 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 short flag,
- struct Scene *scene, struct View3D *v3d,
+ struct Scene *scene, struct SceneLayer *sl,
const bool use_placeholders, const bool force_indirect);
-void BLO_library_link_end(struct Main *mainl, BlendHandle **bh, short flag, struct Scene *scene, struct View3D *v3d);
+void BLO_library_link_end(struct Main *mainl, BlendHandle **bh, short flag, struct Scene *scene, struct SceneLayer *sl);
void BLO_library_link_copypaste(struct Main *mainl, BlendHandle *bh);
@@ -111,7 +136,9 @@ void *BLO_library_read_struct(struct FileData *fd, struct BHead *bh, const char
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 SceneLayer *cur_render_layer);
typedef void (*BLOExpandDoitCallback) (void *fdhandle, struct Main *mainvar, void *idv);
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
index 8cb9ef837b2..0a678cfe6f8 100644
--- a/source/blender/blenloader/CMakeLists.txt
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -29,6 +29,7 @@ set(INC
../blenkernel
../blenlib
../blentranslation
+ ../depsgraph
../imbuf
../makesdna
../makesrna
@@ -53,6 +54,7 @@ set(SRC
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/writefile.c
@@ -69,6 +71,12 @@ if(WITH_BUILDINFO)
add_definitions(-DWITH_BUILDINFO)
endif()
+if(WITH_PYTHON)
+ if(WITH_PYTHON_SECURITY)
+ add_definitions(-DWITH_PYTHON_SECURITY)
+ endif()
+endif()
+
if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c
index be893177b3b..73109413271 100644
--- a/source/blender/blenloader/intern/readblenentry.c
+++ b/source/blender/blenloader/intern/readblenentry.c
@@ -317,7 +317,9 @@ void BLO_blendhandle_close(BlendHandle *bh)
* \param reports If the return value is NULL, errors indicating the cause of the failure.
* \return The data of the file.
*/
-BlendFileData *BLO_read_from_file(const char *filepath, ReportList *reports)
+BlendFileData *BLO_read_from_file(
+ const char *filepath,
+ ReportList *reports, eBLOReadSkip skip_flags)
{
BlendFileData *bfd = NULL;
FileData *fd;
@@ -325,6 +327,7 @@ BlendFileData *BLO_read_from_file(const char *filepath, ReportList *reports)
fd = blo_openblenderfile(filepath, reports);
if (fd) {
fd->reports = reports;
+ fd->skip_flags = skip_flags;
bfd = blo_read_file_internal(fd, filepath);
blo_freefiledata(fd);
}
@@ -341,7 +344,9 @@ BlendFileData *BLO_read_from_file(const char *filepath, ReportList *reports)
* \param reports If the return value is NULL, errors indicating the cause of the failure.
* \return The data of the file.
*/
-BlendFileData *BLO_read_from_memory(const void *mem, int memsize, ReportList *reports)
+BlendFileData *BLO_read_from_memory(
+ const void *mem, int memsize,
+ ReportList *reports, eBLOReadSkip skip_flags)
{
BlendFileData *bfd = NULL;
FileData *fd;
@@ -349,6 +354,7 @@ BlendFileData *BLO_read_from_memory(const void *mem, int memsize, ReportList *re
fd = blo_openblendermemory(mem, memsize, reports);
if (fd) {
fd->reports = reports;
+ fd->skip_flags = skip_flags;
bfd = blo_read_file_internal(fd, "");
blo_freefiledata(fd);
}
@@ -362,7 +368,9 @@ BlendFileData *BLO_read_from_memory(const void *mem, int memsize, ReportList *re
* \param oldmain old main, from which we will keep libraries and other datablocks that should not have changed.
* \param filename current file, only for retrieving library data.
*/
-BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFile *memfile, ReportList *reports)
+BlendFileData *BLO_read_from_memfile(
+ Main *oldmain, const char *filename, MemFile *memfile,
+ ReportList *reports, eBLOReadSkip skip_flags)
{
BlendFileData *bfd = NULL;
FileData *fd;
@@ -371,6 +379,7 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFil
fd = blo_openblendermemfile(memfile, reports);
if (fd) {
fd->reports = reports;
+ fd->skip_flags = skip_flags;
BLI_strncpy(fd->relabase, filename, sizeof(fd->relabase));
/* clear ob->proxy_from pointers in old main */
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index b86fa066007..988101e4bcb 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -53,6 +53,10 @@
/* 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"
@@ -72,6 +76,7 @@
#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"
@@ -84,6 +89,7 @@
#include "DNA_object_types.h"
#include "DNA_packedFile_types.h"
#include "DNA_particle_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_property_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_text_types.h"
@@ -98,10 +104,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"
@@ -120,15 +129,16 @@
#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_layer.h"
#include "BKE_library.h" // for which_libbase
#include "BKE_library_idmap.h"
#include "BKE_library_query.h"
#include "BKE_idcode.h"
+#include "BKE_idprop.h"
#include "BKE_material.h"
#include "BKE_main.h" // for Main
#include "BKE_mesh.h" // for ME_ defines (patching)
@@ -147,6 +157,9 @@
#include "BKE_outliner_treehash.h"
#include "BKE_sound.h"
#include "BKE_colortools.h"
+#include "BKE_workspace.h"
+
+#include "DEG_depsgraph.h"
#include "NOD_common.h"
#include "NOD_socket.h"
@@ -237,7 +250,6 @@ 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);
@@ -531,6 +543,8 @@ void blo_split_main(ListBase *mainlist, Main *main)
for (Library *lib = main->library.first; lib; lib = lib->id.next, i++) {
Main *libmain = BKE_main_new();
libmain->curlib = lib;
+ libmain->versionfile = lib->versionfile;
+ libmain->subversionfile = lib->subversionfile;
BLI_addtail(mainlist, libmain);
lib->temp_index = i;
lib_main_array[i] = libmain;
@@ -562,6 +576,10 @@ static void read_file_version(FileData *fd, Main *main)
break;
}
}
+ if (main->curlib) {
+ main->curlib->versionfile = main->versionfile;
+ main->curlib->subversionfile = main->subversionfile;
+ }
}
#ifdef USE_GHASH_BHEAD
@@ -1995,7 +2013,7 @@ static void test_pointer_array(FileData *fd, void **mat)
/* ************ READ ID Properties *************** */
static void IDP_DirectLinkProperty(IDProperty *prop, int switch_endian, FileData *fd);
-static void IDP_LibLinkProperty(IDProperty *prop, int switch_endian, FileData *fd);
+static void IDP_LibLinkProperty(IDProperty *prop, FileData *fd);
static void IDP_DirectLinkIDPArray(IDProperty *prop, int switch_endian, FileData *fd)
{
@@ -2100,8 +2118,19 @@ static void IDP_DirectLinkProperty(IDProperty *prop, int switch_endian, FileData
BLI_endian_switch_int32(&prop->data.val2);
BLI_endian_switch_int64((int64_t *)&prop->data.val);
}
-
break;
+ case IDP_INT:
+ case IDP_FLOAT:
+ case IDP_ID:
+ break; /* Nothing special to do here. */
+ default:
+ /* Unknown IDP type, nuke it (we cannot handle unknown types everywhere in code,
+ * IDP are way too polymorphic to do it safely. */
+ printf("%s: found unknown IDProperty type %d, reset to Integer one !\n", __func__, prop->type);
+ /* Note: we do not attempt to free unknown prop, we have no way to know how to do that! */
+ prop->type = IDP_INT;
+ prop->subtype = 0;
+ IDP_Int(prop) = 0;
}
}
@@ -2126,10 +2155,39 @@ static void _IDP_DirectLinkGroup_OrFree(IDProperty **prop, int switch_endian, Fi
}
}
-/* stub function */
-static void IDP_LibLinkProperty(IDProperty *UNUSED(prop), int UNUSED(switch_endian), FileData *UNUSED(fd))
+static void IDP_LibLinkProperty(IDProperty *prop, FileData *fd)
{
- /* Should we do something here, prop should be ensured to be non-NULL first... */
+ if (!prop)
+ return;
+
+ switch (prop->type) {
+ case IDP_ID: /* PointerProperty */
+ {
+ void *newaddr = newlibadr_us(fd, NULL, IDP_Id(prop));
+ if (IDP_Id(prop) && !newaddr && G.debug) {
+ printf("Error while loading \"%s\". Data not found in file!\n", prop->name);
+ }
+ prop->data.pointer = newaddr;
+ break;
+ }
+ case IDP_IDPARRAY: /* CollectionProperty */
+ {
+ IDProperty *idp_array = IDP_IDPArray(prop);
+ for (int i = 0; i < prop->len; i++) {
+ IDP_LibLinkProperty(&(idp_array[i]), fd);
+ }
+ break;
+ }
+ case IDP_GROUP: /* PointerProperty */
+ {
+ for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) {
+ IDP_LibLinkProperty(loop, fd);
+ }
+ break;
+ }
+ default:
+ break; /* Nothing to do for other IDProps. */
+ }
}
/* ************ READ IMAGE PREVIEW *************** */
@@ -2147,6 +2205,7 @@ static PreviewImage *direct_link_preview_image(FileData *fd, PreviewImage *old_p
prv->gputexture[i] = NULL;
}
prv->icon_id = 0;
+ prv->tag = 0;
}
return prv;
@@ -2185,19 +2244,19 @@ static void direct_link_curvemapping(FileData *fd, CurveMapping *cumap)
/* library brush linking after fileread */
static void lib_link_brush(FileData *fd, Main *main)
{
- Brush *brush;
-
/* only link ID pointers */
- for (brush = main->brush.first; brush; brush = brush->id.next) {
+ for (Brush *brush = main->brush.first; brush; brush = brush->id.next) {
if (brush->id.tag & LIB_TAG_NEED_LINK) {
- brush->id.tag &= ~LIB_TAG_NEED_LINK;
-
+ IDP_LibLinkProperty(brush->id.properties, fd);
+
/* brush->(mask_)mtex.obj is ignored on purpose? */
brush->mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mtex.tex);
brush->mask_mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mask_mtex.tex);
brush->clone.image = newlibadr(fd, brush->id.lib, brush->clone.image);
brush->toggle_brush = newlibadr(fd, brush->id.lib, brush->toggle_brush);
brush->paint_curve = newlibadr_us(fd, brush->id.lib, brush->paint_curve);
+
+ brush->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -2220,13 +2279,13 @@ static void direct_link_brush(FileData *fd, Brush *brush)
}
/* ************ READ Palette *************** */
-static void lib_link_palette(FileData *UNUSED(fd), Main *main)
+static void lib_link_palette(FileData *fd, Main *main)
{
- Palette *palette;
-
/* only link ID pointers */
- for (palette = main->palettes.first; palette; palette = palette->id.next) {
+ for (Palette *palette = main->palettes.first; palette; palette = palette->id.next) {
if (palette->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(palette->id.properties, fd);
+
palette->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
@@ -2238,13 +2297,13 @@ static void direct_link_palette(FileData *fd, Palette *palette)
link_list(fd, &palette->colors);
}
-static void lib_link_paint_curve(FileData *UNUSED(fd), Main *main)
+static void lib_link_paint_curve(FileData *fd, Main *main)
{
- PaintCurve *pc;
-
/* only link ID pointers */
- for (pc = main->paintcurves.first; pc; pc = pc->id.next) {
+ for (PaintCurve *pc = main->paintcurves.first; pc; pc = pc->id.next) {
if (pc->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(pc->id.properties, fd);
+
pc->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
@@ -2496,21 +2555,26 @@ static void direct_link_fcurves(FileData *fd, ListBase *list)
static void lib_link_action(FileData *fd, Main *main)
{
- bAction *act;
- bActionChannel *chan;
-
- for (act = main->action.first; act; act = act->id.next) {
+ for (bAction *act = main->action.first; act; act = act->id.next) {
if (act->id.tag & LIB_TAG_NEED_LINK) {
- act->id.tag &= ~LIB_TAG_NEED_LINK;
+ IDP_LibLinkProperty(act->id.properties, fd);
// XXX deprecated - old animation system <<<
- for (chan=act->chanbase.first; chan; chan=chan->next) {
+ for (bActionChannel *chan = act->chanbase.first; chan; chan = chan->next) {
chan->ipo = newlibadr_us(fd, act->id.lib, chan->ipo);
lib_link_constraint_channels(fd, &act->id, &chan->constraintChannels);
}
// >>> XXX deprecated - old animation system
lib_link_fcurves(fd, &act->id, &act->curves);
+
+ for (TimeMarker *marker = act->markers.first; marker; marker = marker->next) {
+ if (marker->camera) {
+ marker->camera = newlibadr(fd, act->id.lib, marker->camera);
+ }
+ }
+
+ act->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -2697,32 +2761,102 @@ static void direct_link_animdata(FileData *fd, AnimData *adt)
static void lib_link_cachefiles(FileData *fd, Main *bmain)
{
- CacheFile *cache_file;
-
/* only link ID pointers */
- for (cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) {
+ for (CacheFile *cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) {
if (cache_file->id.tag & LIB_TAG_NEED_LINK) {
- cache_file->id.tag &= ~LIB_TAG_NEED_LINK;
- }
-
- BLI_listbase_clear(&cache_file->object_paths);
- cache_file->handle = NULL;
-
- if (cache_file->adt) {
+ IDP_LibLinkProperty(cache_file->id.properties, fd);
lib_link_animdata(fd, &cache_file->id, cache_file->adt);
+
+ cache_file->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
static void direct_link_cachefile(FileData *fd, CacheFile *cache_file)
{
+ BLI_listbase_clear(&cache_file->object_paths);
cache_file->handle = NULL;
+ cache_file->handle_mutex = NULL;
/* relink animdata */
cache_file->adt = newdataadr(fd, cache_file->adt);
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) {
+ bScreen *screen = newlibadr(fd, id->lib, BKE_workspace_layout_screen_get(layout));
+
+ layout_next = layout->next;
+ if (screen) {
+ BKE_workspace_layout_screen_set(layout, screen);
+
+ if (ID_IS_LINKED_DATABLOCK(id)) {
+ screen->winid = 0;
+ if (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, BKE_workspace_transform_orientations_get(workspace));
+
+ 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);
+ }
+
+ if (ID_IS_LINKED_DATABLOCK(&workspace->id)) {
+ /* Appending workspace so render layer is likely from a different scene. Unset
+ * now, when activating workspace later we set a valid one from current scene. */
+ BKE_workspace_render_layer_set(workspace, NULL);
+ }
+
+ /* 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);
+ }
+ }
+ }
+}
+
+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 */
@@ -2738,19 +2872,13 @@ static void direct_link_motionpath(FileData *fd, bMotionPath *mpath)
/* ************ READ NODE TREE *************** */
-static void lib_link_node_socket(FileData *fd, ID *UNUSED(id), bNodeSocket *sock)
-{
- /* Link ID Properties -- and copy this comment EXACTLY for easy finding
- * of library blocks that implement this.*/
- IDP_LibLinkProperty(sock->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
-}
-
/* Single node tree (also used for material/scene trees), ntree is not NULL */
static void lib_link_ntree(FileData *fd, ID *id, bNodeTree *ntree)
{
bNode *node;
bNodeSocket *sock;
+ IDP_LibLinkProperty(ntree->id.properties, fd);
lib_link_animdata(fd, &ntree->id, ntree->adt);
ntree->gpd = newlibadr_us(fd, id->lib, ntree->gpd);
@@ -2758,32 +2886,35 @@ static void lib_link_ntree(FileData *fd, ID *id, bNodeTree *ntree)
for (node = ntree->nodes.first; node; node = node->next) {
/* Link ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
- IDP_LibLinkProperty(node->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ IDP_LibLinkProperty(node->prop, fd);
- node->id= newlibadr_us(fd, id->lib, node->id);
+ node->id = newlibadr_us(fd, id->lib, node->id);
- for (sock = node->inputs.first; sock; sock = sock->next)
- lib_link_node_socket(fd, id, sock);
- for (sock = node->outputs.first; sock; sock = sock->next)
- lib_link_node_socket(fd, id, sock);
+ for (sock = node->inputs.first; sock; sock = sock->next) {
+ IDP_LibLinkProperty(sock->prop, fd);
+ }
+ for (sock = node->outputs.first; sock; sock = sock->next) {
+ IDP_LibLinkProperty(sock->prop, fd);
+ }
}
- for (sock = ntree->inputs.first; sock; sock = sock->next)
- lib_link_node_socket(fd, id, sock);
- for (sock = ntree->outputs.first; sock; sock = sock->next)
- lib_link_node_socket(fd, id, sock);
+ for (sock = ntree->inputs.first; sock; sock = sock->next) {
+ IDP_LibLinkProperty(sock->prop, fd);
+ }
+ for (sock = ntree->outputs.first; sock; sock = sock->next) {
+ IDP_LibLinkProperty(sock->prop, fd);
+ }
}
/* library ntree linking after fileread */
static void lib_link_nodetree(FileData *fd, Main *main)
{
- bNodeTree *ntree;
-
/* only link ID pointers */
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) {
+ for (bNodeTree *ntree = main->nodetree.first; ntree; ntree = ntree->id.next) {
if (ntree->id.tag & LIB_TAG_NEED_LINK) {
- ntree->id.tag &= ~LIB_TAG_NEED_LINK;
lib_link_ntree(fd, &ntree->id, ntree);
+
+ ntree->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -3074,7 +3205,7 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
else if (ntree->type==NTREE_COMPOSIT) {
if (ELEM(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT))
direct_link_curvemapping(fd, node->storage);
- else if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
+ else if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_R_LAYERS, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
((ImageUser *)node->storage)->ok = 1;
}
else if ( ntree->type==NTREE_TEXTURE) {
@@ -3229,6 +3360,11 @@ static void direct_link_constraints(FileData *fd, ListBase *lb)
con->flag |= CONSTRAINT_SPACEONCE;
break;
}
+ case CONSTRAINT_TYPE_TRANSFORM_CACHE:
+ {
+ bTransformCacheConstraint *data = con->data;
+ data->reader = NULL;
+ }
}
}
}
@@ -3271,6 +3407,8 @@ static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose)
pchan->bone = BLI_ghash_lookup(bone_hash, pchan->name);
+ IDP_LibLinkProperty(pchan->prop, fd);
+
pchan->custom = newlibadr_us(fd, arm->id.lib, pchan->custom);
if (UNLIKELY(pchan->bone == NULL)) {
rebuild = true;
@@ -3286,18 +3424,31 @@ 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);
}
}
+static void lib_link_bones(FileData *fd, Bone *bone)
+{
+ IDP_LibLinkProperty(bone->prop, fd);
+
+ for (Bone *curbone = bone->childbase.first; curbone; curbone = curbone->next) {
+ lib_link_bones(fd, curbone);
+ }
+}
+
static void lib_link_armature(FileData *fd, Main *main)
{
- bArmature *arm;
-
- for (arm = main->armature.first; arm; arm = arm->id.next) {
+ for (bArmature *arm = main->armature.first; arm; arm = arm->id.next) {
if (arm->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(arm->id.properties, fd);
lib_link_animdata(fd, &arm->id, arm->adt);
+
+ for (Bone *curbone = arm->bonebase.first; curbone; curbone = curbone->next) {
+ lib_link_bones(fd, curbone);
+ }
+
arm->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
@@ -3342,14 +3493,13 @@ static void direct_link_armature(FileData *fd, bArmature *arm)
static void lib_link_camera(FileData *fd, Main *main)
{
- Camera *ca;
-
- for (ca = main->camera.first; ca; ca = ca->id.next) {
+ for (Camera *ca = main->camera.first; ca; ca = ca->id.next) {
if (ca->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(ca->id.properties, fd);
lib_link_animdata(fd, &ca->id, ca->adt);
ca->ipo = newlibadr_us(fd, ca->id.lib, ca->ipo); // XXX deprecated - old animation system
-
+
ca->dof_ob = newlibadr(fd, ca->id.lib, ca->dof_ob);
ca->id.tag &= ~LIB_TAG_NEED_LINK;
@@ -3368,16 +3518,13 @@ static void direct_link_camera(FileData *fd, Camera *ca)
static void lib_link_lamp(FileData *fd, Main *main)
{
- Lamp *la;
- MTex *mtex;
- int a;
-
- for (la = main->lamp.first; la; la = la->id.next) {
+ for (Lamp *la = main->lamp.first; la; la = la->id.next) {
if (la->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(la->id.properties, fd);
lib_link_animdata(fd, &la->id, la->adt);
- for (a = 0; a < MAX_MTEX; a++) {
- mtex = la->mtex[a];
+ 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);
@@ -3434,17 +3581,11 @@ void blo_do_versions_key_uidgen(Key *key)
static void lib_link_key(FileData *fd, Main *main)
{
- Key *key;
-
- for (key = main->key.first; key; key = key->id.next) {
- /*check if we need to generate unique ids for the shapekeys*/
- if (!key->uidgen) {
- blo_do_versions_key_uidgen(key);
- }
-
+ for (Key *key = main->key.first; key; key = key->id.next) {
BLI_assert((key->id.tag & LIB_TAG_EXTERN) == 0);
if (key->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(key->id.properties, fd);
lib_link_animdata(fd, &key->id, key->adt);
key->ipo = newlibadr_us(fd, key->id.lib, key->ipo); // XXX deprecated - old animation system
@@ -3507,15 +3648,14 @@ static void direct_link_key(FileData *fd, Key *key)
static void lib_link_mball(FileData *fd, Main *main)
{
- MetaBall *mb;
- int a;
-
- for (mb = main->mball.first; mb; mb = mb->id.next) {
+ for (MetaBall *mb = main->mball.first; mb; mb = mb->id.next) {
if (mb->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(mb->id.properties, fd);
lib_link_animdata(fd, &mb->id, mb->adt);
- for (a = 0; a < mb->totcol; a++)
+ for (int a = 0; a < mb->totcol; a++) {
mb->mat[a] = newlibadr_us(fd, mb->id.lib, mb->mat[a]);
+ }
mb->ipo = newlibadr_us(fd, mb->id.lib, mb->ipo); // XXX deprecated - old animation system
@@ -3544,18 +3684,15 @@ static void direct_link_mball(FileData *fd, MetaBall *mb)
static void lib_link_world(FileData *fd, Main *main)
{
- World *wrld;
- MTex *mtex;
- int a;
-
- for (wrld = main->world.first; wrld; wrld = wrld->id.next) {
+ for (World *wrld = main->world.first; wrld; wrld = wrld->id.next) {
if (wrld->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(wrld->id.properties, fd);
lib_link_animdata(fd, &wrld->id, wrld->adt);
wrld->ipo = newlibadr_us(fd, wrld->id.lib, wrld->ipo); // XXX deprecated - old animation system
- for (a=0; a < MAX_MTEX; a++) {
- mtex = wrld->mtex[a];
+ 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);
@@ -3596,12 +3733,12 @@ static void direct_link_world(FileData *fd, World *wrld)
/* ************ READ VFONT ***************** */
-static void lib_link_vfont(FileData *UNUSED(fd), Main *main)
+static void lib_link_vfont(FileData *fd, Main *main)
{
- VFont *vf;
-
- for (vf = main->vfont.first; vf; vf = vf->id.next) {
+ for (VFont *vf = main->vfont.first; vf; vf = vf->id.next) {
if (vf->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(vf->id.properties, fd);
+
vf->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
@@ -3616,12 +3753,12 @@ static void direct_link_vfont(FileData *fd, VFont *vf)
/* ************ READ TEXT ****************** */
-static void lib_link_text(FileData *UNUSED(fd), Main *main)
+static void lib_link_text(FileData *fd, Main *main)
{
- Text *text;
-
- for (text = main->text.first; text; text = text->id.next) {
+ for (Text *text = main->text.first; text; text = text->id.next) {
if (text->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(text->id.properties, fd);
+
text->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
@@ -3670,11 +3807,9 @@ static void direct_link_text(FileData *fd, Text *text)
static void lib_link_image(FileData *fd, Main *main)
{
- Image *ima;
-
- for (ima = main->image.first; ima; ima = ima->id.next) {
+ for (Image *ima = main->image.first; ima; ima = ima->id.next) {
if (ima->id.tag & LIB_TAG_NEED_LINK) {
- IDP_LibLinkProperty(ima->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ IDP_LibLinkProperty(ima->id.properties, fd);
ima->id.tag &= ~LIB_TAG_NEED_LINK;
}
@@ -3739,15 +3874,14 @@ static void direct_link_image(FileData *fd, Image *ima)
static void lib_link_curve(FileData *fd, Main *main)
{
- Curve *cu;
- int a;
-
- for (cu = main->curve.first; cu; cu = cu->id.next) {
+ for (Curve *cu = main->curve.first; cu; cu = cu->id.next) {
if (cu->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(cu->id.properties, fd);
lib_link_animdata(fd, &cu->id, cu->adt);
- for (a = 0; a < cu->totcol; a++)
+ for (int a = 0; a < cu->totcol; a++) {
cu->mat[a] = newlibadr_us(fd, cu->id.lib, cu->mat[a]);
+ }
cu->bevobj = newlibadr(fd, cu->id.lib, cu->bevobj);
cu->taperobj = newlibadr(fd, cu->id.lib, cu->taperobj);
@@ -3813,6 +3947,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);
@@ -3832,10 +3967,9 @@ static void direct_link_curve(FileData *fd, Curve *cu)
static void lib_link_texture(FileData *fd, Main *main)
{
- Tex *tex;
-
- for (tex = main->tex.first; tex; tex = tex->id.next) {
+ for (Tex *tex = main->tex.first; tex; tex = tex->id.next) {
if (tex->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(tex->id.properties, fd);
lib_link_animdata(fd, &tex->id, tex->adt);
tex->ima = newlibadr_us(fd, tex->id.lib, tex->ima);
@@ -3911,23 +4045,20 @@ static void direct_link_texture(FileData *fd, Tex *tex)
static void lib_link_material(FileData *fd, Main *main)
{
- Material *ma;
- MTex *mtex;
- int a;
-
- for (ma = main->mat.first; ma; ma = ma->id.next) {
+ for (Material *ma = main->mat.first; ma; ma = ma->id.next) {
if (ma->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(ma->id.properties, fd);
lib_link_animdata(fd, &ma->id, ma->adt);
/* Link ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
- IDP_LibLinkProperty(ma->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ IDP_LibLinkProperty(ma->id.properties, fd);
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 (a = 0; a < MAX_MTEX; a++) {
- mtex = ma->mtex[a];
+ 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);
@@ -4058,14 +4189,11 @@ static void lib_link_partdeflect(FileData *fd, ID *id, PartDeflect *pd)
static void lib_link_particlesettings(FileData *fd, Main *main)
{
- ParticleSettings *part;
- ParticleDupliWeight *dw;
- MTex *mtex;
- int a;
-
- for (part = main->particle.first; part; part = part->id.next) {
+ for (ParticleSettings *part = main->particle.first; part; part = part->id.next) {
if (part->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(part->id.properties, fd);
lib_link_animdata(fd, &part->id, part->adt);
+
part->ipo = newlibadr_us(fd, part->id.lib, part->ipo); // XXX deprecated - old animation system
part->dup_ob = newlibadr(fd, part->id.lib, part->dup_ob);
@@ -4085,6 +4213,7 @@ 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)) {
@@ -4103,8 +4232,14 @@ static void lib_link_particlesettings(FileData *fd, Main *main)
if (index_ok) {
/* if we have indexes, let's use them */
for (dw = part->dupliweights.first; dw; dw = dw->next) {
- GroupObject *go = (GroupObject *)BLI_findlink(&part->dup_group->gobject, dw->index);
- dw->ob = go ? go->ob : NULL;
+ /* 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 {
@@ -4143,8 +4278,8 @@ static void lib_link_particlesettings(FileData *fd, Main *main)
}
}
- for (a = 0; a < MAX_MTEX; a++) {
- mtex= part->mtex[a];
+ for (int a = 0; a < MAX_MTEX; a++) {
+ MTex *mtex= part->mtex[a];
if (mtex) {
mtex->tex = newlibadr_us(fd, part->id.lib, mtex->tex);
mtex->object = newlibadr(fd, part->id.lib, mtex->object);
@@ -4263,12 +4398,15 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles)
psys->flag &= ~PSYS_KEYED;
}
-
+
if (psys->particles && psys->particles->boid) {
pa = psys->particles;
pa->boid = newdataadr(fd, pa->boid);
- for (a=1, pa++; a<psys->totpart; a++, pa++)
- pa->boid = (pa-1)->boid + 1;
+ pa->boid->ground = NULL; /* This is purely runtime data, but still can be an issue if left dangling. */
+ for (a = 1, pa++; a < psys->totpart; a++, pa++) {
+ pa->boid = (pa - 1)->boid + 1;
+ pa->boid->ground = NULL;
+ }
}
else if (psys->particles) {
for (a=0, pa=psys->particles; a<psys->totpart; a++, pa++)
@@ -4317,55 +4455,14 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles)
psys->tree = NULL;
psys->bvhtree = 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;
@@ -4376,7 +4473,7 @@ static void lib_link_mesh(FileData *fd, Main *main)
/* Link ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
- IDP_LibLinkProperty(me->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ IDP_LibLinkProperty(me->id.properties, fd);
lib_link_animdata(fd, &me->id, me->adt);
/* this check added for python created meshes */
@@ -4392,19 +4489,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*/
@@ -4560,7 +4647,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 */
@@ -4580,18 +4666,13 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh)
mesh->bb = NULL;
mesh->edit_btmesh = NULL;
mesh->edit_strands = NULL;
+ mesh->batch_cache = NULL;
/* 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) {
@@ -4650,10 +4731,9 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh)
static void lib_link_latt(FileData *fd, Main *main)
{
- Lattice *lt;
-
- for (lt = main->latt.first; lt; lt = lt->id.next) {
+ for (Lattice *lt = main->latt.first; lt; lt = lt->id.next) {
if (lt->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(lt->id.properties, fd);
lib_link_animdata(fd, &lt->id, lt->adt);
lt->ipo = newlibadr_us(fd, lt->id.lib, lt->ipo); // XXX deprecated - old animation system
@@ -4672,6 +4752,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);
@@ -4681,12 +4762,12 @@ static void direct_link_latt(FileData *fd, Lattice *lt)
/* ************ READ OBJECT ***************** */
static void lib_link_modifiers__linkModifiers(
- void *userData, Object *ob, ID **idpoin, int cd_flag)
+ void *userData, Object *ob, ID **idpoin, int cb_flag)
{
FileData *fd = userData;
*idpoin = newlibadr(fd, ob->id.lib, *idpoin);
- if (*idpoin != NULL && (cd_flag & IDWALK_USER) != 0) {
+ if (*idpoin != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
id_us_plus_no_lib(*idpoin);
}
}
@@ -4697,17 +4778,13 @@ static void lib_link_modifiers(FileData *fd, Object *ob)
static void lib_link_object(FileData *fd, Main *main)
{
- Object *ob;
- PartEff *paf;
- bSensor *sens;
- bController *cont;
- bActuator *act;
- void *poin;
- int warn=0, a;
-
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ bool warn = false;
+
+ for (Object *ob = main->object.first; ob; ob = ob->id.next) {
if (ob->id.tag & LIB_TAG_NEED_LINK) {
- IDP_LibLinkProperty(ob->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ int a;
+
+ IDP_LibLinkProperty(ob->id.properties, fd);
lib_link_animdata(fd, &ob->id, ob->adt);
// XXX deprecated - old animation system <<<
@@ -4718,7 +4795,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_DUPLIGROUP;
+ }
ob->proxy = newlibadr_us(fd, ob->id.lib, ob->proxy);
if (ob->proxy) {
@@ -4739,17 +4824,17 @@ static void lib_link_object(FileData *fd, Main *main)
}
ob->proxy_group = newlibadr(fd, ob->id.lib, ob->proxy_group);
- poin = ob->data;
+ void *poin = ob->data;
ob->data = newlibadr_us(fd, ob->id.lib, ob->data);
- if (ob->data==NULL && poin!=NULL) {
+ if (ob->data == NULL && poin != NULL) {
if (ob->id.lib)
printf("Can't find obdata of %s lib %s\n", ob->id.name + 2, ob->id.lib->name);
else
printf("Object %s lost data.\n", ob->id.name + 2);
ob->type = OB_EMPTY;
- warn = 1;
+ warn = true;
if (ob->pose) {
/* we can't call #BKE_pose_free() here because of library linking
@@ -4776,7 +4861,7 @@ static void lib_link_object(FileData *fd, Main *main)
/* Only expand so as not to loose any object materials that might be set. */
if (totcol_data && (*totcol_data > ob->totcol)) {
/* printf("'%s' %d -> %d\n", ob->id.name, ob->totcol, *totcol_data); */
- BKE_material_resize_object(ob, *totcol_data, false);
+ BKE_material_resize_object(main, ob, *totcol_data, false);
}
}
@@ -4795,13 +4880,13 @@ static void lib_link_object(FileData *fd, Main *main)
lib_link_nlastrips(fd, &ob->id, &ob->nlastrips);
// >>> XXX deprecated - old animation system
- for (paf = ob->effect.first; paf; paf = paf->next) {
+ for (PartEff *paf = ob->effect.first; paf; paf = paf->next) {
if (paf->type == EFF_PARTICLE) {
paf->group = newlibadr_us(fd, ob->id.lib, paf->group);
}
}
- for (sens = ob->sensors.first; sens; sens = sens->next) {
+ 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]);
@@ -4812,7 +4897,7 @@ static void lib_link_object(FileData *fd, Main *main)
}
}
- for (cont = ob->controllers.first; cont; cont = cont->next) {
+ 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]);
@@ -4824,86 +4909,117 @@ static void lib_link_object(FileData *fd, Main *main)
cont->totslinks = 0;
}
- for (act = ob->actuators.first; act; act = act->next) {
- if (act->type == ACT_SOUND) {
- bSoundActuator *sa = act->data;
- sa->sound= newlibadr_us(fd, ob->id.lib, sa->sound);
- }
- else if (act->type == ACT_GAME) {
- /* bGameActuator *ga= act->data; */
- }
- else if (act->type == ACT_CAMERA) {
- bCameraActuator *ca = act->data;
- ca->ob= newlibadr(fd, ob->id.lib, ca->ob);
- }
- /* leave this one, it's obsolete but necessary to read for conversion */
- else if (act->type == ACT_ADD_OBJECT) {
- bAddObjectActuator *eoa = act->data;
- if (eoa) eoa->ob= newlibadr(fd, ob->id.lib, eoa->ob);
- }
- else if (act->type == ACT_OBJECT) {
- bObjectActuator *oa = act->data;
- if (oa == NULL) {
- init_actuator(act);
+ 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;
}
- else {
- oa->reference = newlibadr(fd, ob->id.lib, oa->reference);
+ 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;
}
- }
- else if (act->type == ACT_EDIT_OBJECT) {
- bEditObjectActuator *eoa = act->data;
- if (eoa == NULL) {
- init_actuator(act);
+ /* 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;
}
- else {
- eoa->ob= newlibadr(fd, ob->id.lib, eoa->ob);
- eoa->me= newlibadr(fd, ob->id.lib, eoa->me);
+ case ACT_OBJECT:
+ {
+ bObjectActuator *oa = act->data;
+ if (oa == NULL) {
+ init_actuator(act);
+ }
+ else {
+ oa->reference = newlibadr(fd, ob->id.lib, oa->reference);
+ }
+ break;
}
- }
- else if (act->type == ACT_SCENE) {
- bSceneActuator *sa = act->data;
- sa->camera= newlibadr(fd, ob->id.lib, sa->camera);
- sa->scene= newlibadr(fd, ob->id.lib, sa->scene);
- }
- else if (act->type == ACT_ACTION) {
- bActionActuator *aa = act->data;
- aa->act= newlibadr_us(fd, ob->id.lib, aa->act);
- }
- else if (act->type == ACT_SHAPEACTION) {
- bActionActuator *aa = act->data;
- aa->act= newlibadr_us(fd, ob->id.lib, aa->act);
- }
- else if (act->type == ACT_PROPERTY) {
- bPropertyActuator *pa = act->data;
- pa->ob= newlibadr(fd, ob->id.lib, pa->ob);
- }
- else if (act->type == ACT_MESSAGE) {
- bMessageActuator *ma = act->data;
- ma->toObject= newlibadr(fd, ob->id.lib, ma->toObject);
- }
- else if (act->type == ACT_2DFILTER) {
- bTwoDFilterActuator *_2dfa = act->data;
- _2dfa->text= newlibadr(fd, ob->id.lib, _2dfa->text);
- }
- else if (act->type == ACT_PARENT) {
- bParentActuator *parenta = act->data;
- parenta->ob = newlibadr(fd, ob->id.lib, parenta->ob);
- }
- else if (act->type == ACT_STATE) {
- /* bStateActuator *statea = act->data; */
- }
- else if (act->type == ACT_ARMATURE) {
- bArmatureActuator *arma= act->data;
- arma->target= newlibadr(fd, ob->id.lib, arma->target);
- arma->subtarget= newlibadr(fd, ob->id.lib, arma->subtarget);
- }
- else if (act->type == ACT_STEERING) {
- bSteeringActuator *steeringa = act->data;
- steeringa->target = newlibadr(fd, ob->id.lib, steeringa->target);
- steeringa->navmesh = newlibadr(fd, ob->id.lib, steeringa->navmesh);
- }
- else if (act->type == ACT_MOUSE) {
- /* bMouseActuator *moa= act->data; */
+ 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;
}
}
@@ -4993,6 +5109,8 @@ 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;
}
pose->ikdata = NULL;
if (pose->ikparam != NULL) {
@@ -5075,6 +5193,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
smd->domain->tex = NULL;
smd->domain->tex_shadow = NULL;
smd->domain->tex_wt = NULL;
+ smd->domain->coba = newdataadr(fd, smd->domain->coba);
smd->domain->effector_weights = newdataadr(fd, smd->domain->effector_weights);
if (!smd->domain->effector_weights)
@@ -5180,6 +5299,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
collmd->time_x = collmd->time_xnew = -1000;
collmd->mvert_num = 0;
collmd->tri_num = 0;
+ collmd->is_static = false;
collmd->bvhtree = NULL;
collmd->tri = NULL;
@@ -5284,6 +5404,41 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
csmd->delta_cache = NULL;
csmd->delta_cache_num = 0;
}
+ else if (md->type == eModifierType_MeshSequenceCache) {
+ MeshSeqCacheModifierData *msmcd = (MeshSeqCacheModifierData *)md;
+ msmcd->reader = NULL;
+ }
+ else if (md->type == eModifierType_SurfaceDeform) {
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
+
+ smd->verts = newdataadr(fd, smd->verts);
+
+ if (smd->verts) {
+ for (int i = 0; i < smd->numverts; i++) {
+ smd->verts[i].binds = newdataadr(fd, smd->verts[i].binds);
+
+ if (smd->verts[i].binds) {
+ for (int j = 0; j < smd->verts[i].numbinds; j++) {
+ smd->verts[i].binds[j].vert_inds = newdataadr(fd, smd->verts[i].binds[j].vert_inds);
+ smd->verts[i].binds[j].vert_weights = newdataadr(fd, smd->verts[i].binds[j].vert_weights);
+
+ if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+ if (smd->verts[i].binds[j].vert_inds)
+ BLI_endian_switch_uint32_array(smd->verts[i].binds[j].vert_inds, smd->verts[i].binds[j].numverts);
+
+ if (smd->verts[i].binds[j].vert_weights) {
+ if (smd->verts[i].binds[j].mode == MOD_SDEF_MODE_CENTROID ||
+ smd->verts[i].binds[j].mode == MOD_SDEF_MODE_LOOPTRI)
+ BLI_endian_switch_float_array(smd->verts[i].binds[j].vert_weights, 3);
+ else
+ BLI_endian_switch_float_array(smd->verts[i].binds[j].vert_weights, smd->verts[i].binds[j].numverts);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
}
@@ -5303,6 +5458,9 @@ static void direct_link_object(FileData *fd, Object *ob)
*/
ob->recalc = 0;
+ /* XXX This should not be needed - but seems like it can happen in some cases, so for now play safe... */
+ ob->proxy_from = NULL;
+
/* loading saved files with editmode enabled works, but for undo we like
* to stay in object mode during undo presses so keep editmode disabled.
*
@@ -5327,6 +5485,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);
@@ -5513,6 +5672,7 @@ static void direct_link_object(FileData *fd, Object *ob)
ob->derivedDeform = NULL;
ob->derivedFinal = NULL;
BLI_listbase_clear(&ob->gpulamp);
+ BLI_listbase_clear(&ob->drawdata);
link_list(fd, &ob->pc_ids);
/* Runtime curve data */
@@ -5529,6 +5689,8 @@ static void direct_link_object(FileData *fd, Object *ob)
ob->currentlod = ob->lodlevels.first;
ob->preview = direct_link_preview_image(fd, ob->preview);
+
+ ob->base_collection_properties = NULL;
}
/* ************ READ SCENE ***************** */
@@ -5593,26 +5755,35 @@ static bool scene_validate_setscene__liblink(Scene *sce, const int totscene)
}
#endif
-static void lib_link_scene(FileData *fd, Main *main)
+static void lib_link_scene_collection(FileData *fd, Library *lib, SceneCollection *sc)
{
- Scene *sce;
- Base *base, *next;
- Sequence *seq;
- SceneRenderLayer *srl;
- TimeMarker *marker;
- FreestyleModuleConfig *fmc;
- FreestyleLineSet *fls;
+ for (LinkData *link = sc->objects.first; link; link = link->next) {
+ link->data = newlibadr_us(fd, lib, link->data);
+ BLI_assert(link->data);
+ }
+
+ for (LinkData *link = sc->filter_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);
+ }
+}
+static void lib_link_scene(FileData *fd, Main *main)
+{
#ifdef USE_SETSCENE_CHECK
bool need_check_set = false;
int totscene = 0;
#endif
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (Scene *sce = main->scene.first; sce; sce = sce->id.next) {
if (sce->id.tag & LIB_TAG_NEED_LINK) {
/* Link ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
- IDP_LibLinkProperty(sce->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ IDP_LibLinkProperty(sce->id.properties, fd);
lib_link_animdata(fd, &sce->id, sce->adt);
lib_link_keyingsets(fd, &sce->id, &sce->keyingsets);
@@ -5656,22 +5827,25 @@ static void lib_link_scene(FileData *fd, Main *main)
hair_edit->shape_object = newlibadr(fd, sce->id.lib, hair_edit->shape_object);
}
- for (base = sce->base.first; base; base = next) {
- next = base->next;
+ for (BaseLegacy *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);
}
}
+ Sequence *seq;
SEQ_BEGIN (sce->ed, seq)
{
+ IDP_LibLinkProperty(seq->prop, fd);
+
if (seq->ipo) seq->ipo = newlibadr_us(fd, sce->id.lib, seq->ipo); // XXX deprecated - old animation system
seq->scene_sound = NULL;
if (seq->scene) {
@@ -5708,15 +5882,11 @@ static void lib_link_scene(FileData *fd, Main *main)
}
SEQ_END
-#ifdef DURIAN_CAMERA_SWITCH
- for (marker = sce->markers.first; marker; marker = marker->next) {
+ for (TimeMarker *marker = sce->markers.first; marker; marker = marker->next) {
if (marker->camera) {
marker->camera = newlibadr(fd, sce->id.lib, marker->camera);
}
}
-#else
- (void)marker;
-#endif
BKE_sequencer_update_muting(sce->ed);
BKE_sequencer_update_sound_bounds_all(sce);
@@ -5739,13 +5909,13 @@ static void lib_link_scene(FileData *fd, Main *main)
composite_patch(sce->nodetree, sce);
}
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
+ 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 (fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
+ for (FreestyleModuleConfig *fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
fmc->script = newlibadr(fd, sce->id.lib, fmc->script);
}
- for (fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
+ for (FreestyleLineSet *fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
fls->linestyle = newlibadr_us(fd, sce->id.lib, fls->linestyle);
fls->group = newlibadr_us(fd, sce->id.lib, fls->group);
}
@@ -5756,6 +5926,19 @@ static void lib_link_scene(FileData *fd, Main *main)
/* Motion Tracking */
sce->clip = newlibadr_us(fd, sce->id.lib, sce->clip);
+ lib_link_scene_collection(fd, sce->id.lib, sce->collection);
+
+ for (SceneLayer *sl = sce->render_layers.first; sl; sl = sl->next) {
+ /* tag scene layer to update for collection tree evaluation */
+ sl->flag |= SCENE_LAYER_ENGINE_DIRTY;
+ for (Base *base = sl->object_bases.first; base; base = base->next) {
+ /* we only bump the use count for the collection objects */
+ base->object = newlibadr(fd, sce->id.lib, base->object);
+ base->flag |= BASE_DIRTY_ENGINE_SETTINGS;
+ base->collection_properties = NULL;
+ }
+ }
+
#ifdef USE_SETSCENE_CHECK
if (sce->set != NULL) {
/* link flag for scenes with set would be reset later,
@@ -5779,7 +5962,7 @@ static void lib_link_scene(FileData *fd, Main *main)
#ifdef USE_SETSCENE_CHECK
if (need_check_set) {
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (Scene *sce = main->scene.first; sce; sce = sce->id.next) {
if (sce->id.tag & LIB_TAG_NEED_LINK) {
sce->id.tag &= ~LIB_TAG_NEED_LINK;
if (!scene_validate_setscene__liblink(sce, totscene)) {
@@ -5859,18 +6042,69 @@ static void direct_link_view_settings(FileData *fd, ColorManagedViewSettings *vi
direct_link_curvemapping(fd, view_settings->curve_mapping);
}
-static void direct_link_scene(FileData *fd, Scene *sce)
+static void direct_link_scene_collection(FileData *fd, SceneCollection *sc)
+{
+ link_list(fd, &sc->objects);
+ link_list(fd, &sc->filter_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 direct_link_layer_collections(FileData *fd, ListBase *lb)
+{
+ link_list(fd, lb);
+ for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ lc->scene_collection = newdataadr(fd, lc->scene_collection);
+
+ link_list(fd, &lc->object_bases);
+
+ for (LinkData *link = lc->object_bases.first; link; link = link->next) {
+ link->data = newdataadr(fd, link->data);
+ }
+
+ link_list(fd, &lc->overrides);
+
+ if (lc->properties) {
+ lc->properties = newdataadr(fd, lc->properties);
+ IDP_DirectLinkGroup_OrFree(&lc->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ BKE_layer_collection_engine_settings_validate_collection(lc);
+ }
+ lc->properties_evaluated = NULL;
+
+ direct_link_layer_collections(fd, &lc->layer_collections);
+ }
+}
+
+/**
+ * Workspaces store a render layer pointer which can only be read after scene is read.
+ */
+static void direct_link_workspace_link_scene_data(
+ FileData *fd, const Scene *scene, const ListBase *workspaces)
+{
+ for (WorkSpace *workspace = workspaces->first; workspace; workspace = workspace->id.next) {
+ SceneLayer *layer = newdataadr(fd, BKE_workspace_render_layer_get(workspace));
+ /* only set when layer is from the scene we read */
+ if (layer && (BLI_findindex(&scene->render_layers, layer) != -1)) {
+ BKE_workspace_render_layer_set(workspace, layer);
+ }
+ }
+}
+
+static void direct_link_scene(FileData *fd, Scene *sce, Main *bmain)
{
Editing *ed;
Sequence *seq;
MetaStack *ms;
RigidBodyWorld *rbw;
+ SceneLayer *sl;
SceneRenderLayer *srl;
sce->theDag = NULL;
- sce->depsgraph = NULL;
+ sce->depsgraph_legacy = NULL;
sce->obedit = NULL;
- sce->stats = NULL;
sce->fps_info = NULL;
sce->customdata_mask_modal = 0;
sce->lay_updated = 0;
@@ -5902,6 +6136,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
sce->toolsettings->imapaint.paintcursor = NULL;
sce->toolsettings->particle.paintcursor = NULL;
sce->toolsettings->particle.scene = NULL;
+ sce->toolsettings->particle.scene_layer = NULL;
sce->toolsettings->particle.object = NULL;
sce->toolsettings->gp_sculpt.paintcursor = NULL;
sce->toolsettings->hair_edit.paint_cursor = NULL;
@@ -5915,6 +6150,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
sce->toolsettings->wpaint->wpaint_prev = NULL;
sce->toolsettings->wpaint->tot = 0;
}
+
/* relink grease pencil drawing brushes */
link_list(fd, &sce->toolsettings->gp_brushes);
for (bGPDbrush *brush = sce->toolsettings->gp_brushes.first; brush; brush = brush->next) {
@@ -5931,6 +6167,12 @@ static void direct_link_scene(FileData *fd, Scene *sce)
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);
+ }
}
if (sce->ed) {
@@ -5991,9 +6233,13 @@ static void direct_link_scene(FileData *fd, Scene *sce)
seq->strip->transform = NULL;
}
if (seq->flag & SEQ_USE_PROXY) {
- seq->strip->proxy = newdataadr(
- fd, seq->strip->proxy);
- seq->strip->proxy->anim = NULL;
+ seq->strip->proxy = newdataadr(fd, seq->strip->proxy);
+ if (seq->strip->proxy) {
+ seq->strip->proxy->anim = NULL;
+ }
+ else {
+ BKE_sequencer_proxy_set(seq, true);
+ }
}
else {
seq->strip->proxy = NULL;
@@ -6064,10 +6310,15 @@ static void direct_link_scene(FileData *fd, Scene *sce)
}
link_list(fd, &(sce->markers));
- link_list(fd, &(sce->transform_spaces));
+ link_list(fd, &(sce->transform_spaces)); /* only for old files */
link_list(fd, &(sce->r.layers));
link_list(fd, &(sce->r.views));
+
+ 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));
}
@@ -6109,6 +6360,43 @@ static void direct_link_scene(FileData *fd, Scene *sce)
sce->preview = direct_link_preview_image(fd, sce->preview);
direct_link_curvemapping(fd, &sce->r.mblur_shutter_curve);
+
+ /* this runs before the very first doversion */
+ if (sce->collection) {
+ sce->collection = newdataadr(fd, sce->collection);
+ direct_link_scene_collection(fd, sce->collection);
+ }
+
+ /* insert into global old-new map for reading without UI (link_global accesses it again) */
+ link_glob_list(fd, &sce->render_layers);
+ for (sl = sce->render_layers.first; sl; sl = sl->next) {
+ sl->stats = NULL;
+ link_list(fd, &sl->object_bases);
+ sl->basact = newdataadr(fd, sl->basact);
+ direct_link_layer_collections(fd, &sl->layer_collections);
+
+ if (sl->properties != NULL) {
+ sl->properties = newdataadr(fd, sl->properties);
+ BLI_assert(sl->properties != NULL);
+ IDP_DirectLinkGroup_OrFree(&sl->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ BKE_scene_layer_engine_settings_validate_layer(sl);
+ }
+
+ sl->properties_evaluated = NULL;
+
+ BLI_listbase_clear(&sl->drawdata);
+ }
+
+ sce->collection_properties = newdataadr(fd, sce->collection_properties);
+ IDP_DirectLinkGroup_OrFree(&sce->collection_properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+
+ sce->layer_properties = newdataadr(fd, sce->layer_properties);
+ IDP_DirectLinkGroup_OrFree(&sce->layer_properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+
+ BKE_layer_collection_engine_settings_validate_scene(sce);
+ BKE_scene_layer_engine_settings_validate_scene(sce);
+
+ direct_link_workspace_link_scene_data(fd, sce, &bmain->workspaces);
}
/* ************ READ WM ***************** */
@@ -6121,6 +6409,12 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
link_list(fd, &wm->windows);
for (win = wm->windows.first; win; win = win->next) {
+ 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);
+
win->ghostwin = NULL;
win->eventstate = NULL;
win->curswin = NULL;
@@ -6183,8 +6477,15 @@ static void lib_link_windowmanager(FileData *fd, Main *main)
for (wm = main->wm.first; wm; wm = wm->id.next) {
if (wm->id.tag & LIB_TAG_NEED_LINK) {
- for (win = wm->windows.first; win; win = win->next)
+ /* 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);
+ }
wm->id.tag &= ~LIB_TAG_NEED_LINK;
}
@@ -6196,13 +6497,12 @@ static void lib_link_windowmanager(FileData *fd, Main *main)
/* relink's grease pencil data's refs */
static void lib_link_gpencil(FileData *fd, Main *main)
{
- bGPdata *gpd;
-
- for (gpd = main->gpencil.first; gpd; gpd = gpd->id.next) {
+ for (bGPdata *gpd = main->gpencil.first; gpd; gpd = gpd->id.next) {
if (gpd->id.tag & LIB_TAG_NEED_LINK) {
- 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;
}
}
}
@@ -6264,193 +6564,215 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
* check lib pointers in call below */
static void lib_link_screen(FileData *fd, Main *main)
{
- bScreen *sc;
- ScrArea *sa;
-
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ 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);
- 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;
+ /* deprecated, but needed for versioning (will be NULL'ed then) */
+ sc->scene = newlibadr(fd, sc->id.lib, sc->scene);
sc->animtimer = NULL; /* saved in rare cases */
sc->scrubbing = false;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
-
+ for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
sa->full = newlibadr(fd, sc->id.lib, sa->full);
- for (sl = sa->spacedata.first; sl; sl= sl->next) {
- if (sl->spacetype == 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 (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;
}
-
- 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);
+ 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;
}
- if (v3d->localvd) {
- v3d->localvd->camera = newlibadr(fd, sc->id.lib, v3d->localvd->camera);
+ 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;
}
- }
- else if (sl->spacetype == 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);
+ 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;
}
- }
- else if (sl->spacetype == SPACE_BUTS) {
- SpaceButs *sbuts = (SpaceButs *)sl;
- sbuts->pinid = newlibadr(fd, sc->id.lib, sbuts->pinid);
- if (sbuts->pinid == NULL) {
- sbuts->flag &= ~SB_PIN_CONTEXT;
+ 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;
}
- }
- else if (sl->spacetype == SPACE_FILE) {
- ;
- }
- else if (sl->spacetype == 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);
+ 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;
}
-
- saction->action = newlibadr(fd, sc->id.lib, saction->action);
- }
- else if (sl->spacetype == 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);
- }
- else if (sl->spacetype == 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);
+ 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;
- }
- else if (sl->spacetype == 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);
+ st->text= newlibadr(fd, sc->id.lib, st->text);
+ break;
}
- }
- else if (sl->spacetype == SPACE_TEXT) {
- SpaceText *st= (SpaceText *)sl;
-
- st->text= newlibadr(fd, sc->id.lib, st->text);
- }
- else if (sl->spacetype == 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);
+ case SPACE_SCRIPT:
+ {
+ SpaceScript *scpt = (SpaceScript *)sl;
+ /*scpt->script = NULL; - 2.45 set to null, better re-run the script */
if (scpt->script) {
- SCRIPT_SET_NULL(scpt->script);
+ scpt->script = newlibadr(fd, sc->id.lib, scpt->script);
+ if (scpt->script) {
+ SCRIPT_SET_NULL(scpt->script);
+ }
}
+ break;
}
- }
- else if (sl->spacetype == 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;
+ 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);
- BLI_mempool_iternew(so->treestore, &iter);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
- tselem->id = newlibadr(fd, NULL, tselem->id);
+ if (!path->nodetree)
+ break;
}
- if (so->treehash) {
- /* rebuild hash table, because it depends on ids too */
- so->storeflag |= SO_TREESTORE_REBUILD;
+
+ /* remaining path entries are invalid, remove */
+ for (; path; path = path_next) {
+ path_next = path->next;
+
+ BLI_remlink(&snode->treepath, path);
+ MEM_freeN(path);
}
- }
- }
- else if (sl->spacetype == 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;
+
+ /* 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
- path->nodetree = newlibadr_us(fd, sc->id.lib, path->nodetree);
-
- if (!path->nodetree)
- break;
+ else {
+ snode->edittree = NULL;
+ }
+ break;
}
-
- /* remaining path entries are invalid, remove */
- for (; path; path = path_next) {
- path_next = path->next;
-
- BLI_remlink(&snode->treepath, path);
- MEM_freeN(path);
+ 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;
}
-
- /* 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;
+ case SPACE_LOGIC:
+ {
+ SpaceLogic *slogic = (SpaceLogic *)sl;
+
+ slogic->gpd = newlibadr_us(fd, sc->id.lib, slogic->gpd);
+ break;
}
- else
- snode->edittree = NULL;
- }
- else if (sl->spacetype == 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);
- }
- else if (sl->spacetype == SPACE_LOGIC) {
- SpaceLogic *slogic = (SpaceLogic *)sl;
-
- slogic->gpd = newlibadr_us(fd, sc->id.lib, slogic->gpd);
+ default:
+ break;
}
}
}
@@ -6557,56 +6879,59 @@ 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_workspace_scene_data_restore(wmWindow *win, Scene *scene)
{
- 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;
- /* 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 (win->screen == NULL)
- win->screen = curscreen;
-
- win->screen->winid = win->winid;
+ if (v3d->camera == NULL || v3d->scenelock) {
+ v3d->camera = scene->camera;
+ }
+
+ if (v3d->localvd) {
+ /*Base *base;*/
+
+ v3d->localvd->camera = 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 = scene->lay;
+ }
+ }
}
}
-
-
- 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) {
+}
+
+static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map, Main *newmain, WorkSpaceLayout *layout)
+{
+ bScreen *screen = BKE_workspace_layout_screen_get(layout);
+
+ /* 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) {
@@ -6617,27 +6942,6 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
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;
@@ -6708,10 +7012,13 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
* since it gets initialized later */
sima->iuser.scene = NULL;
- sima->scopes.waveform_1 = NULL;
- sima->scopes.waveform_2 = NULL;
- sima->scopes.waveform_3 = NULL;
- sima->scopes.vecscope = NULL;
+#if 0
+ /* Those are allocated and freed by space code, no need to handle them here. */
+ MEM_SAFE_FREE(sima->scopes.waveform_1);
+ MEM_SAFE_FREE(sima->scopes.waveform_2);
+ MEM_SAFE_FREE(sima->scopes.waveform_3);
+ MEM_SAFE_FREE(sima->scopes.vecscope);
+#endif
sima->scopes.ok = 0;
/* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
@@ -6837,6 +7144,44 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
}
}
}
+}
+
+/**
+ * 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, SceneLayer *cur_render_layer)
+{
+ struct IDNameLib_Map *id_map = BKE_main_idmap_create(newmain);
+
+ for (WorkSpace *workspace = newmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ ListBase *layouts = BKE_workspace_layouts_get(workspace);
+
+ for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
+ lib_link_workspace_layout_restore(id_map, newmain, layout);
+ }
+ BKE_workspace_render_layer_set(workspace, cur_render_layer);
+ }
+
+ 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;
+
+ 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;
+ }
+ BKE_workspace_active_set(win->workspace_hook, workspace);
+
+ /* keep cursor location through undo */
+ copy_v3_v3(win->scene->cursor, oldscene->cursor);
+ lib_link_workspace_scene_data_restore(win, win->scene);
+
+ BLI_assert(win->screen == NULL);
+ }
/* update IDs stored in all possible clipboards */
lib_link_clipboard_restore(id_map);
@@ -6890,6 +7235,7 @@ static void direct_link_region(FileData *fd, ARegion *ar, int spacetype)
rv3d->sms = NULL;
rv3d->smooth_timer = NULL;
rv3d->compositor = NULL;
+ rv3d->viewport = NULL;
}
}
}
@@ -6906,6 +7252,7 @@ static void direct_link_region(FileData *fd, ARegion *ar, int spacetype)
ar->type = NULL;
ar->swap = 0;
ar->do_draw = 0;
+ ar->manipulator_map = NULL;
ar->regiontimer = NULL;
memset(&ar->drawrct, 0, sizeof(ar->drawrct));
}
@@ -6952,6 +7299,8 @@ static bool direct_link_screen(FileData *fd, bScreen *sc)
sc->mainwin = sc->subwinactive= 0; /* indices */
sc->swap = 0;
+ sc->preview = direct_link_preview_image(fd, sc->preview);
+
/* edges */
for (se = sc->edgebase.first; se; se = se->next) {
se->v1 = newdataadr(fd, se->v1);
@@ -7317,17 +7666,37 @@ 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->speaker.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->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)
{
- Speaker *spk;
-
- for (spk = main->speaker.first; spk; spk = spk->id.next) {
+ for (Speaker *spk = main->speaker.first; spk; spk = spk->id.next) {
if (spk->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(spk->id.properties, fd);
lib_link_animdata(fd, &spk->id, spk->adt);
spk->sound = newlibadr_us(fd, spk->id.lib, spk->sound);
+
spk->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
@@ -7377,14 +7746,15 @@ static void direct_link_sound(FileData *fd, bSound *sound)
static void lib_link_sound(FileData *fd, Main *main)
{
- bSound *sound;
-
- for (sound = main->sound.first; sound; sound = sound->id.next) {
+ for (bSound *sound = main->sound.first; sound; sound = sound->id.next) {
if (sound->id.tag & LIB_TAG_NEED_LINK) {
- sound->id.tag &= ~LIB_TAG_NEED_LINK;
+ IDP_LibLinkProperty(sound->id.properties, fd);
+
sound->ipo = newlibadr_us(fd, sound->id.lib, sound->ipo); // XXX deprecated - old animation system
BKE_sound_load(main, sound);
+
+ sound->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -7399,17 +7769,13 @@ static void direct_link_group(FileData *fd, Group *group)
static void lib_link_group(FileData *fd, Main *main)
{
- Group *group;
- GroupObject *go;
- bool add_us;
-
- for (group = main->group.first; group; group = group->id.next) {
+ for (Group *group = main->group.first; group; group = group->id.next) {
if (group->id.tag & LIB_TAG_NEED_LINK) {
- group->id.tag &= ~LIB_TAG_NEED_LINK;
+ IDP_LibLinkProperty(group->id.properties, fd);
- add_us = false;
+ bool add_us = false;
- for (go = group->gobject.first; go; go = go->next) {
+ 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;
@@ -7420,7 +7786,9 @@ static void lib_link_group(FileData *fd, Main *main)
if (add_us) {
id_us_ensure_real(&group->id);
}
- BKE_group_object_unlink(group, NULL, NULL, NULL); /* removes NULL entries */
+ BKE_group_object_unlink(group, NULL); /* removes NULL entries */
+
+ group->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -7489,7 +7857,7 @@ static void direct_link_movieclip(FileData *fd, MovieClip *clip)
clip->tracking_context = NULL;
clip->tracking.stats = NULL;
- clip->tracking.stabilization.ok = 0;
+ /* Needed for proper versioning, will be NULL for all newer files anyway. */
clip->tracking.stabilization.rot_track = newdataadr(fd, clip->tracking.stabilization.rot_track);
clip->tracking.dopesheet.ok = 0;
@@ -7525,13 +7893,11 @@ static void lib_link_moviePlaneTracks(FileData *fd, MovieClip *clip, ListBase *t
static void lib_link_movieclip(FileData *fd, Main *main)
{
- MovieClip *clip;
-
- for (clip = main->movieclip.first; clip; clip = clip->id.next) {
+ for (MovieClip *clip = main->movieclip.first; clip; clip = clip->id.next) {
if (clip->id.tag & LIB_TAG_NEED_LINK) {
MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *object;
+ IDP_LibLinkProperty(clip->id.properties, fd);
lib_link_animdata(fd, &clip->id, clip->adt);
clip->gpd = newlibadr_us(fd, clip->id.lib, clip->gpd);
@@ -7539,7 +7905,7 @@ static void lib_link_movieclip(FileData *fd, Main *main)
lib_link_movieTracks(fd, clip, &tracking->tracks);
lib_link_moviePlaneTracks(fd, clip, &tracking->plane_tracks);
- for (object = tracking->objects.first; object; object = object->next) {
+ for (MovieTrackingObject *object = tracking->objects.first; object; object = object->next) {
lib_link_movieTracks(fd, clip, &object->tracks);
lib_link_moviePlaneTracks(fd, clip, &object->plane_tracks);
}
@@ -7616,16 +7982,12 @@ static void lib_link_mask_parent(FileData *fd, Mask *mask, MaskParent *parent)
static void lib_link_mask(FileData *fd, Main *main)
{
- Mask *mask;
-
- mask = main->mask.first;
- while (mask) {
+ for (Mask *mask = main->mask.first; mask; mask = mask->id.next) {
if (mask->id.tag & LIB_TAG_NEED_LINK) {
- MaskLayer *masklay;
-
+ IDP_LibLinkProperty(mask->id.properties, fd);
lib_link_animdata(fd, &mask->id, mask->adt);
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
+ for (MaskLayer *masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
MaskSpline *spline;
spline = masklay->splines.first;
@@ -7646,7 +8008,6 @@ static void lib_link_mask(FileData *fd, Main *main)
mask->id.tag &= ~LIB_TAG_NEED_LINK;
}
- mask = mask->id.next;
}
}
@@ -7654,18 +8015,13 @@ static void lib_link_mask(FileData *fd, Main *main)
static void lib_link_linestyle(FileData *fd, Main *main)
{
- FreestyleLineStyle *linestyle;
- LineStyleModifier *m;
- MTex *mtex;
- int a;
-
- linestyle = main->linestyle.first;
- while (linestyle) {
+ for (FreestyleLineStyle *linestyle = main->linestyle.first; linestyle; linestyle = linestyle->id.next) {
if (linestyle->id.tag & LIB_TAG_NEED_LINK) {
- linestyle->id.tag &= ~LIB_TAG_NEED_LINK;
+ LineStyleModifier *m;
- IDP_LibLinkProperty(linestyle->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ IDP_LibLinkProperty(linestyle->id.properties, fd);
lib_link_animdata(fd, &linestyle->id, linestyle->adt);
+
for (m = linestyle->color_modifiers.first; m; m = m->next) {
switch (m->type) {
case LS_MODIFIER_DISTANCE_FROM_OBJECT:
@@ -7696,8 +8052,8 @@ static void lib_link_linestyle(FileData *fd, Main *main)
break;
}
}
- for (a=0; a < MAX_MTEX; a++) {
- mtex = linestyle->mtex[a];
+ for (int a = 0; a < MAX_MTEX; a++) {
+ MTex *mtex = linestyle->mtex[a];
if (mtex) {
mtex->tex = newlibadr_us(fd, linestyle->id.lib, mtex->tex);
mtex->object = newlibadr(fd, linestyle->id.lib, mtex->object);
@@ -7707,8 +8063,9 @@ static void lib_link_linestyle(FileData *fd, Main *main)
lib_link_ntree(fd, &linestyle->id, linestyle->nodetree);
linestyle->nodetree->id.lib = linestyle->id.lib;
}
+
+ linestyle->id.tag &= ~LIB_TAG_NEED_LINK;
}
- linestyle = linestyle->id.next;
}
}
@@ -7944,6 +8301,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";
@@ -7956,6 +8314,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";
@@ -8092,12 +8451,16 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
id->lib = main->curlib;
id->us = ID_FAKE_USERS(id);
id->icon_id = 0;
+ id->newid = NULL; /* Needed because .blend may have been saved with crap value here... */
/* this case cannot be direct_linked: it's just the ID part */
if (bhead->code == ID_ID) {
return blo_nextbhead(fd, bhead);
}
-
+
+ /* That way, we know which datablock needs do_versions (required currently for linking). */
+ id->tag |= LIB_TAG_NEW;
+
/* need a name for the mallocN, just for debugging and sane prints on leaks */
allocname = dataname(GS(id->name));
@@ -8115,7 +8478,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
wrong_id = direct_link_screen(fd, (bScreen *)id);
break;
case ID_SCE:
- direct_link_scene(fd, (Scene *)id);
+ direct_link_scene(fd, (Scene *)id, main);
break;
case ID_OB:
direct_link_object(fd, (Object *)id);
@@ -8171,6 +8534,9 @@ 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);
break;
@@ -8210,6 +8576,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);
@@ -8255,7 +8624,8 @@ static BHead *read_global(BlendFileData *bfd, FileData *fd, BHead *bhead)
bfd->curscreen = fg->curscreen;
bfd->curscene = fg->curscene;
-
+ bfd->cur_render_layer = fg->cur_render_layer;
+
MEM_freeN(fg);
fd->globalf = bfd->globalf;
@@ -8267,6 +8637,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_render_layer = newglobadr(fd, bfd->cur_render_layer);
bfd->curscreen = newlibadr(fd, NULL, bfd->curscreen);
bfd->curscene = newlibadr(fd, NULL, bfd->curscene);
// this happens in files older than 2.35
@@ -8275,26 +8646,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
- // 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)
@@ -8348,6 +8699,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! */
@@ -8355,14 +8707,14 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
/* don't forget to set version number in BKE_blender_version.h! */
}
-#if 0 // XXX: disabled for now... we still don't have this in the right place in the loading code for it to work
-static void do_versions_after_linking(FileData *fd, Library *lib, Main *main)
+static void do_versions_after_linking(Main *main)
{
- /* old Animation System (using IPO's) needs to be converted to the new Animato system */
- if (main->versionfile < 250)
- do_versions_ipos_to_animato(main);
+// printf("%s for %s (%s), %d.%d\n", __func__, main->curlib ? main->curlib->name : main->name,
+// main->curlib ? "LIB" : "MAIN", main->versionfile, main->subversionfile);
+
+ do_versions_after_linking_270(main);
+ do_versions_after_linking_280(main);
}
-#endif
static void lib_link_all(FileData *fd, Main *main)
{
@@ -8376,12 +8728,13 @@ static void lib_link_all(FileData *fd, Main *main)
lib_link_screen(fd, main);
lib_link_scene(fd, main);
lib_link_object(fd, main);
+ lib_link_mesh(fd, main);
lib_link_curve(fd, main);
lib_link_mball(fd, main);
lib_link_material(fd, main);
lib_link_texture(fd, main);
lib_link_image(fd, main);
- lib_link_ipo(fd, main); // XXX deprecated... still needs to be maintained for version patches still
+ lib_link_ipo(fd, main); /* XXX deprecated... still needs to be maintained for version patches still */
lib_link_key(fd, main);
lib_link_world(fd, main);
lib_link_lamp(fd, main);
@@ -8389,12 +8742,13 @@ 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_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_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_paint_curve(fd, main);
@@ -8404,10 +8758,9 @@ 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_mesh(fd, main); /* as last: tpage images with users at zero */
-
- lib_link_library(fd, main); /* only init users */
+ lib_link_library(fd, main); /* only init users */
}
static void direct_link_keymapitem(FileData *fd, wmKeyMapItem *kmi)
@@ -8531,7 +8884,12 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
bhead = read_global(bfd, fd, bhead);
break;
case USER:
- bhead = read_userdef(bfd, fd, bhead);
+ if (fd->skip_flags & BLO_READ_SKIP_USERDEF) {
+ bhead = blo_nextbhead(fd, bhead);
+ }
+ else {
+ bhead = read_userdef(bfd, fd, bhead);
+ }
break;
case ENDB:
bhead = NULL;
@@ -8540,15 +8898,25 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
case ID_ID:
/* Always adds to the most recently loaded ID_LI block, see direct_link_library.
* This is part of the file format definition. */
- bhead = read_libblock(fd, mainlist.last, bhead, LIB_TAG_READ | LIB_TAG_EXTERN, NULL);
+ if (fd->skip_flags & BLO_READ_SKIP_DATA) {
+ bhead = blo_nextbhead(fd, bhead);
+ }
+ else {
+ 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 */
case ID_SCRN:
bhead->code = ID_SCR;
- /* deliberate pass on to default */
+ /* pass on to default */
+ ATTR_FALLTHROUGH;
default:
- bhead = read_libblock(fd, bfd->main, bhead, LIB_TAG_LOCAL, NULL);
+ if (fd->skip_flags & BLO_READ_SKIP_DATA) {
+ bhead = blo_nextbhead(fd, bhead);
+ }
+ else {
+ bhead = read_libblock(fd, bfd->main, bhead, LIB_TAG_LOCAL, NULL);
+ }
}
}
@@ -8563,7 +8931,20 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
blo_join_main(&mainlist);
lib_link_all(fd, bfd->main);
- //do_versions_after_linking(fd, NULL, bfd->main); // XXX: not here (or even in this function at all)! this causes crashes on many files - Aligorith (July 04, 2010)
+
+ /* Skip in undo case. */
+ if (fd->memfile == NULL) {
+ /* Yep, second splitting... but this is a very cheap operation, so no big deal. */
+ blo_split_main(&mainlist, bfd->main);
+ for (Main *mainvar = mainlist.first; mainvar; mainvar = mainvar->next) {
+ BLI_assert(mainvar->versionfile != 0);
+ do_versions_after_linking(mainvar);
+ }
+ blo_join_main(&mainlist);
+ }
+
+ BKE_main_id_tag_all(bfd->main, LIB_TAG_NEW, false);
+
lib_verify_nodetree(bfd->main, true);
fix_relpaths_library(fd->relabase, bfd->main); /* make all relative paths, relative to the open blend file */
@@ -8764,6 +9145,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);
@@ -8800,6 +9186,31 @@ static void expand_constraint_channels(FileData *fd, Main *mainvar, ListBase *ch
}
}
+static void expand_idprops(FileData *fd, Main *mainvar, IDProperty *prop)
+{
+ if (!prop)
+ return;
+
+ switch (prop->type) {
+ case IDP_ID:
+ expand_doit(fd, mainvar, IDP_Id(prop));
+ break;
+ case IDP_IDPARRAY:
+ {
+ IDProperty *idp_array = IDP_IDPArray(prop);
+ for (int i = 0; i < prop->len; i++) {
+ expand_idprops(fd, mainvar, &idp_array[i]);
+ }
+ break;
+ }
+ case IDP_GROUP:
+ for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) {
+ expand_idprops(fd, mainvar, loop);
+ }
+ break;
+ }
+}
+
static void expand_fmodifiers(FileData *fd, Main *mainvar, ListBase *list)
{
FModifier *fcm;
@@ -8857,6 +9268,12 @@ static void expand_action(FileData *fd, Main *mainvar, bAction *act)
/* F-Curves in Action */
expand_fcurves(fd, mainvar, &act->curves);
+
+ for (TimeMarker *marker = act->markers.first; marker; marker = marker->next) {
+ if (marker->camera) {
+ expand_doit(fd, mainvar, marker->camera);
+ }
+ }
}
static void expand_keyingsets(FileData *fd, Main *mainvar, ListBase *list)
@@ -8979,6 +9396,7 @@ static void expand_key(FileData *fd, Main *mainvar, Key *key)
static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree)
{
bNode *node;
+ bNodeSocket *sock;
if (ntree->adt)
expand_animdata(fd, mainvar, ntree->adt);
@@ -8987,10 +9405,22 @@ static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree)
expand_doit(fd, mainvar, ntree->gpd);
for (node = ntree->nodes.first; node; node = node->next) {
- if (node->id && node->type != CMP_NODE_R_LAYERS)
+ if (node->id && node->type != CMP_NODE_R_LAYERS) {
expand_doit(fd, mainvar, node->id);
+ }
+
+ expand_idprops(fd, mainvar, node->prop);
+
+ for (sock = node->inputs.first; sock; sock = sock->next)
+ expand_doit(fd, mainvar, sock->prop);
+ for (sock = node->outputs.first; sock; sock = sock->next)
+ expand_doit(fd, mainvar, sock->prop);
}
+ for (sock = ntree->inputs.first; sock; sock = sock->next)
+ expand_doit(fd, mainvar, sock->prop);
+ for (sock = ntree->outputs.first; sock; sock = sock->next)
+ expand_doit(fd, mainvar, sock->prop);
}
static void expand_texture(FileData *fd, Main *mainvar, Tex *tex)
@@ -9034,6 +9464,10 @@ static void expand_material(FileData *fd, Main *mainvar, Material *ma)
if (ma->group)
expand_doit(fd, mainvar, ma->group);
+
+ if (ma->edit_image) {
+ expand_doit(fd, mainvar, ma->edit_image);
+ }
}
static void expand_lamp(FileData *fd, Main *mainvar, Lamp *la)
@@ -9123,9 +9557,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);
@@ -9136,46 +9568,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() */
@@ -9208,17 +9600,6 @@ static void expand_constraints(FileData *fd, Main *mainvar, ListBase *lb)
}
}
-#if 0 /* Disabled as it doesn't actually do anything except recurse... */
-static void expand_bones(FileData *fd, Main *mainvar, Bone *bone)
-{
- Bone *curBone;
-
- for (curBone = bone->childbase.first; curBone; curBone=curBone->next) {
- expand_bones(fd, mainvar, curBone);
- }
-}
-#endif
-
static void expand_pose(FileData *fd, Main *mainvar, bPose *pose)
{
bPoseChannel *chan;
@@ -9228,28 +9609,32 @@ static void expand_pose(FileData *fd, Main *mainvar, bPose *pose)
for (chan = pose->chanbase.first; chan; chan = chan->next) {
expand_constraints(fd, mainvar, &chan->constraints);
+ expand_idprops(fd, mainvar, chan->prop);
expand_doit(fd, mainvar, chan->custom);
}
}
+static void expand_bones(FileData *fd, Main *mainvar, Bone *bone)
+{
+ expand_idprops(fd, mainvar, bone->prop);
+
+ for (Bone *curBone = bone->childbase.first; curBone; curBone = curBone->next) {
+ expand_bones(fd, mainvar, curBone);
+ }
+}
+
static void expand_armature(FileData *fd, Main *mainvar, bArmature *arm)
-{
+{
if (arm->adt)
expand_animdata(fd, mainvar, arm->adt);
-
-#if 0 /* Disabled as this currently only recurses down the chain doing nothing */
- {
- Bone *curBone;
-
- for (curBone = arm->bonebase.first; curBone; curBone=curBone->next) {
- expand_bones(fd, mainvar, curBone);
- }
+
+ for (Bone *curBone = arm->bonebase.first; curBone; curBone = curBone->next) {
+ expand_bones(fd, mainvar, curBone);
}
-#endif
}
static void expand_object_expandModifiers(
- void *userData, Object *UNUSED(ob), ID **idpoin, int UNUSED(cd_flag))
+ void *userData, Object *UNUSED(ob), ID **idpoin, int UNUSED(cb_flag))
{
struct { FileData *fd; Main *mainvar; } *data= userData;
@@ -9425,9 +9810,24 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob)
}
}
+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 (LinkData *link = sc->filter_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);
+ }
+}
+
static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
{
- Base *base;
+ BaseLegacy *base;
SceneRenderLayer *srl;
FreestyleModuleConfig *module;
FreestyleLineSet *lineset;
@@ -9473,6 +9873,8 @@ static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
SEQ_BEGIN (sce->ed, seq)
{
+ expand_idprops(fd, mainvar, seq->prop);
+
if (seq->scene) expand_doit(fd, mainvar, seq->scene);
if (seq->scene_camera) expand_doit(fd, mainvar, seq->scene_camera);
if (seq->clip) expand_doit(fd, mainvar, seq->clip);
@@ -9487,19 +9889,15 @@ static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
expand_doit(fd, mainvar, sce->rigidbody_world->constraints);
}
-#ifdef DURIAN_CAMERA_SWITCH
- {
- TimeMarker *marker;
-
- for (marker = sce->markers.first; marker; marker = marker->next) {
- if (marker->camera) {
- expand_doit(fd, mainvar, marker->camera);
- }
+ for (TimeMarker *marker = sce->markers.first; marker; marker = marker->next) {
+ if (marker->camera) {
+ expand_doit(fd, mainvar, marker->camera);
}
}
-#endif
expand_doit(fd, mainvar, sce->clip);
+
+ expand_scene_collection(fd, mainvar, sce->collection);
}
static void expand_camera(FileData *fd, Main *mainvar, Camera *ca)
@@ -9530,6 +9928,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)
@@ -9603,6 +10007,15 @@ static void expand_gpencil(FileData *fd, Main *mainvar, bGPdata *gpd)
expand_animdata(fd, mainvar, gpd->adt);
}
+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));
+ }
+}
+
/**
* Set the callback func used over all ID data found by \a BLO_expand_main func.
*
@@ -9636,6 +10049,8 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
id = lbarray[a]->first;
while (id) {
if (id->tag & LIB_TAG_NEED_EXPAND) {
+ expand_idprops(fd, mainvar, id->properties);
+
switch (GS(id->name)) {
case ID_OB:
expand_object(fd, mainvar, (Object *)id);
@@ -9679,6 +10094,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;
@@ -9715,6 +10133,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;
}
do_it = true;
@@ -9743,11 +10164,11 @@ 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 void give_base_to_objects(
+ Main *mainvar, Scene *scene, SceneLayer *sl, SceneCollection *sc, Library *lib, const short flag)
{
Object *ob;
Base *base;
- const unsigned int active_lay = (flag & FILE_ACTIVELAY) ? BKE_screen_view3d_layer_active(v3d, scene) : 0;
const bool is_link = (flag & FILE_LINK) != 0;
BLI_assert(scene);
@@ -9767,19 +10188,22 @@ static void give_base_to_objects(Main *mainvar, Scene *scene, View3D *v3d, Libra
}
if (do_it) {
- base = MEM_callocN(sizeof(Base), __func__);
- BLI_addtail(&scene->base, base);
+ CLAMP_MIN(ob->id.us, 0);
- if (active_lay) {
- ob->lay = active_lay;
- }
+ BKE_collection_object_add(scene, sc, ob);
+ base = BKE_scene_layer_base_find(sl, ob);
+ BKE_scene_object_base_flag_sync_from_base(base);
- base->lay = ob->lay;
- base->object = ob;
- base->flag = ob->flag;
+ if (flag & FILE_AUTOSELECT) {
+ /* Note that link_object_postprocess() already checks for FILE_AUTOSELECT flag,
+ * but it will miss objects from non-instanciated groups... */
+ if (base->flag & BASE_SELECTABLED) {
+ base->flag |= BASE_SELECTED;
+ BKE_scene_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 */
+ }
- 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;
@@ -9789,12 +10213,12 @@ 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))
+ Main *mainvar, Scene *scene, SceneLayer *sl, SceneCollection *sc,
+ Library *UNUSED(lib), const short UNUSED(flag))
{
Group *group;
Base *base;
Object *ob;
- const unsigned int active_lay = BKE_screen_view3d_layer_active(v3d, scene);
/* give all objects which are tagged a base */
for (group = mainvar->group.first; group; group = group->id.next) {
@@ -9805,14 +10229,17 @@ static void give_base_to_groups(
/* 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;
- /* 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;
+ BKE_collection_object_add(scene, sc, ob);
+ base = BKE_scene_layer_base_find(sl, ob);
+
+ if (base->flag & BASE_SELECTABLED) {
+ 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);
+ sl->basact = base;
/* assign the group */
ob->dup_group = group;
@@ -9889,31 +10316,42 @@ static ID *link_named_part(
return id;
}
-static void link_object_postprocess(ID *id, Scene *scene, View3D *v3d, const short flag)
+static SceneCollection *get_scene_collection_active_or_create(struct Scene *scene, struct SceneLayer *sl, const short flag)
+{
+ LayerCollection *lc = NULL;
+
+ if (flag & FILE_ACTIVE_COLLECTION) {
+ lc = BKE_layer_collection_get_active_ensure(scene, sl);
+ }
+ else {
+ SceneCollection *sc = BKE_collection_add(scene, NULL, NULL);
+ lc = BKE_collection_link(sl, sc);
+ }
+
+ return lc->scene_collection;
+}
+
+static void link_object_postprocess(ID *id, Scene *scene, SceneLayer *sl, const short flag)
{
if (scene) {
+ /* link to scene */
Base *base;
Object *ob;
-
- base = MEM_callocN(sizeof(Base), "app_nam_part");
- BLI_addtail(&scene->base, base);
+ SceneCollection *sc;
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);
+
+ sc = get_scene_collection_active_or_create(scene, sl, flag);
+ BKE_collection_object_add(scene, sc, ob);
+ base = BKE_scene_layer_base_find(sl, 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_SELECTABLED) {
+ base->flag |= BASE_SELECTED;
+ BKE_scene_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 */
}
}
@@ -9956,12 +10394,12 @@ 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 short flag,
- Scene *scene, View3D *v3d, const bool use_placeholders, const bool force_indirect)
+ Scene *scene, SceneLayer *sl, const bool use_placeholders, const bool force_indirect)
{
ID *id = link_named_part(mainl, fd, idcode, name, use_placeholders, force_indirect);
if (id && (GS(id->name) == ID_OB)) { /* loose object: give a base */
- link_object_postprocess(id, scene, v3d, flag);
+ link_object_postprocess(id, scene, sl, flag);
}
else if (id && (GS(id->name) == ID_GR)) {
/* tag as needing to be instantiated */
@@ -10005,11 +10443,11 @@ ID *BLO_library_link_named_part(Main *mainl, BlendHandle **bh, const short idcod
ID *BLO_library_link_named_part_ex(
Main *mainl, BlendHandle **bh,
const short idcode, const char *name, const short flag,
- Scene *scene, View3D *v3d,
+ Scene *scene, SceneLayer *sl,
const bool use_placeholders, const bool force_indirect)
{
FileData *fd = (FileData*)(*bh);
- return link_named_part_ex(mainl, fd, idcode, name, flag, scene, v3d, use_placeholders, force_indirect);
+ return link_named_part_ex(mainl, fd, idcode, name, flag, scene, sl, use_placeholders, force_indirect);
}
static void link_id_part(ReportList *reports, FileData *fd, Main *mainvar, ID *id, ID **r_id)
@@ -10095,8 +10533,34 @@ Main *BLO_library_link_begin(Main *mainvar, BlendHandle **bh, const char *filepa
return library_link_begin(mainvar, &fd, filepath);
}
+static void split_main_newid(Main *mainptr, Main *main_newid)
+{
+ /* We only copy the necessary subset of data in this temp main. */
+ main_newid->versionfile = mainptr->versionfile;
+ main_newid->subversionfile = mainptr->subversionfile;
+ BLI_strncpy(main_newid->name, mainptr->name, sizeof(main_newid->name));
+ main_newid->curlib = mainptr->curlib;
+
+ ListBase *lbarray[MAX_LIBARRAY];
+ ListBase *lbarray_newid[MAX_LIBARRAY];
+ int i = set_listbasepointers(mainptr, lbarray);
+ set_listbasepointers(main_newid, lbarray_newid);
+ while (i--) {
+ BLI_listbase_clear(lbarray_newid[i]);
+
+ for (ID *id = lbarray[i]->first, *idnext; id; id = idnext) {
+ idnext = id->next;
+
+ if (id->tag & LIB_TAG_NEW) {
+ BLI_remlink(lbarray[i], id);
+ BLI_addtail(lbarray_newid[i], id);
+ }
+ }
+ }
+}
+
/* 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, Scene *scene, SceneLayer *sl)
{
Main *mainvar;
Library *curlib;
@@ -10123,10 +10587,28 @@ static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene
blo_join_main((*fd)->mainlist);
mainvar = (*fd)->mainlist->first;
- MEM_freeN((*fd)->mainlist);
mainl = NULL; /* blo_join_main free's mainl, cant use anymore */
lib_link_all(*fd, 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};
+ 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);
+
+ do_versions_after_linking(&main_newid);
+
+ add_main_to_main(mainvar, &main_newid);
+ }
+ blo_join_main((*fd)->mainlist);
+ mainvar = (*fd)->mainlist->first;
+ MEM_freeN((*fd)->mainlist);
+
+ BKE_main_id_tag_all(mainvar, LIB_TAG_NEW, false);
+
lib_verify_nodetree(mainvar, false);
fix_relpaths_library(G.main->name, mainvar); /* make all relative paths, relative to the open blend file */
@@ -10134,10 +10616,11 @@ static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene
* Only directly linked objects & groups 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);
+ SceneCollection *sc = get_scene_collection_active_or_create(scene, sl, FILE_ACTIVE_COLLECTION);
+ give_base_to_objects(mainvar, scene, sl, sc, curlib, flag);
if (flag & FILE_GROUP_INSTANCE) {
- give_base_to_groups(mainvar, scene, v3d, curlib, flag);
+ give_base_to_groups(mainvar, scene, sl, sc, curlib, flag);
}
}
else {
@@ -10163,12 +10646,12 @@ static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene
* \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 sl The scene layer in which to instantiate objects/groups (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, short flag, Scene *scene, SceneLayer *sl)
{
FileData *fd = (FileData*)(*bh);
- library_link_end(mainl, &fd, flag, scene, v3d);
+ library_link_end(mainl, &fd, flag, scene, sl);
*bh = (BlendHandle*)fd;
}
@@ -10297,6 +10780,9 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
else {
mainptr->curlib->filedata = NULL;
mainptr->curlib->id.tag |= LIB_TAG_MISSING;
+ /* Set lib version to current main one... Makes assert later happy. */
+ mainptr->versionfile = mainptr->curlib->versionfile = mainl->versionfile;
+ mainptr->subversionfile = mainptr->curlib->subversionfile = mainl->subversionfile;
}
if (fd == NULL) {
@@ -10366,14 +10852,19 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
}
/* do versions, link, and free */
+ Main main_newid = {0};
for (mainptr = mainl->next; mainptr; mainptr = mainptr->next) {
- /* some mains still have to be read, then
- * versionfile is still zero! */
+ /* 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);
+
if (mainptr->curlib->filedata) // can be zero... with shift+f1 append
- do_versions(mainptr->curlib->filedata, mainptr->curlib, mainptr);
+ do_versions(mainptr->curlib->filedata, mainptr->curlib, &main_newid);
else
- do_versions(basefd, NULL, mainptr);
+ do_versions(basefd, NULL, &main_newid);
+
+ add_main_to_main(mainptr, &main_newid);
}
if (mainptr->curlib->filedata)
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index 7719aaa2b0d..299c66f2bbb 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;
@@ -81,6 +83,8 @@ typedef struct FileData {
int id_name_offs; /* used to retrieve ID names from (bhead+1) */
int globalf, fileflags; /* for do_versions patching */
+ eBLOReadSkip skip_flags; /* skip some data-blocks */
+
struct OldNewMap *datamap;
struct OldNewMap *globmap;
struct OldNewMap *libmap;
@@ -169,6 +173,10 @@ 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 *main);
void blo_do_versions_260(struct FileData *fd, struct Library *lib, struct Main *main);
void blo_do_versions_270(struct FileData *fd, struct Library *lib, struct Main *main);
+void blo_do_versions_280(struct FileData *fd, struct Library *lib, struct Main *main);
+
+void do_versions_after_linking_270(struct Main *main);
+void do_versions_after_linking_280(struct Main *main);
#endif
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index 1956a17d57b..0895b956563 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -736,7 +736,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
if (main->versionfile < 250) {
bScreen *screen;
Scene *scene;
- Base *base;
+ BaseLegacy *base;
Material *ma;
Camera *cam;
Mesh *me;
@@ -1119,8 +1119,6 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
sce->gm.matmode = GAME_MAT_MULTITEX;
else
sce->gm.matmode = GAME_MAT_TEXFACE;
-
- sce->gm.flag |= GAME_DISPLAY_LISTS;
}
for (ob = main->object.first; ob; ob = ob->id.next) {
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index 907baab0aee..77542d8deb9 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -56,6 +56,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -999,7 +1000,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
{
/* convert extended ascii to utf-8 for text editor */
Text *text;
- for (text = main->text.first; text; text = text->id.next)
+ for (text = main->text.first; text; text = text->id.next) {
if (!(text->flags & TXT_ISEXT)) {
TextLine *tl;
@@ -1012,6 +1013,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
text->curc = 0;
}
}
+ }
}
{
/* set new dynamic paint values */
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index af95649a559..cb7c46d24f3 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -34,6 +34,7 @@
/* allow readfile to use deprecated functionality */
#define DNA_DEPRECATED_ALLOW
+#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
@@ -46,23 +47,29 @@
#include "DNA_screen_types.h"
#include "DNA_object_force.h"
#include "DNA_object_types.h"
+#include "DNA_mask_types.h"
#include "DNA_mesh_types.h"
#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"
#include "DNA_genfile.h"
+#include "BKE_animsys.h"
#include "BKE_colortools.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_mask.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
#include "BKE_scene.h"
#include "BKE_sequencer.h"
#include "BKE_screen.h"
+#include "BKE_tracking.h"
#include "BKE_gpencil.h"
#include "BLI_math.h"
@@ -71,10 +78,31 @@
#include "BLO_readfile.h"
+#include "NOD_common.h"
+#include "NOD_socket.h"
+#include "NOD_composite.h"
+
#include "readfile.h"
#include "MEM_guardedalloc.h"
+/**
+ * Setup rotation stabilization from ancient single track spec.
+ * Former Version of 2D stabilization used a single tracking marker to determine the rotation
+ * to be compensated. Now several tracks can contribute to rotation detection and this feature
+ * is enabled by the MovieTrackingTrack#flag on a per track base.
+ */
+static void migrate_single_rot_stabilization_track_settings(MovieTrackingStabilization *stab)
+{
+ if (stab->rot_track) {
+ if (!(stab->rot_track->flag & TRACK_USE_2D_STAB_ROT)) {
+ stab->tot_rot_track++;
+ stab->rot_track->flag |= TRACK_USE_2D_STAB_ROT;
+ }
+ }
+ stab->rot_track = NULL; /* this field is now ignored */
+}
+
static void do_version_constraints_radians_degrees_270_1(ListBase *lb)
{
bConstraint *con;
@@ -173,6 +201,89 @@ static void do_version_bones_super_bbone(ListBase *lb)
}
}
+/* TODO(sergey): Consider making it somewhat more generic function in BLI_anim.h. */
+static void anim_change_prop_name(FCurve *fcu,
+ const char *prefix,
+ const char *old_prop_name,
+ const char *new_prop_name)
+{
+ const char *old_path = BLI_sprintfN("%s.%s", prefix, old_prop_name);
+ if (STREQ(fcu->rna_path, old_path)) {
+ MEM_freeN(fcu->rna_path);
+ fcu->rna_path = BLI_sprintfN("%s.%s", prefix, new_prop_name);
+ }
+ MEM_freeN((char *)old_path);
+}
+
+static void do_version_hue_sat_node(bNodeTree *ntree, bNode *node)
+{
+ if (node->storage == NULL) {
+ return;
+ }
+
+ /* Make sure new sockets are properly created. */
+ node_verify_socket_templates(ntree, node);
+ /* Convert value from old storage to new sockets. */
+ NodeHueSat *nhs = node->storage;
+ bNodeSocket *hue = nodeFindSocket(node, SOCK_IN, "Hue"),
+ *saturation = nodeFindSocket(node, SOCK_IN, "Saturation"),
+ *value = nodeFindSocket(node, SOCK_IN, "Value");
+ ((bNodeSocketValueFloat *)hue->default_value)->value = nhs->hue;
+ ((bNodeSocketValueFloat *)saturation->default_value)->value = nhs->sat;
+ ((bNodeSocketValueFloat *)value->default_value)->value = nhs->val;
+ /* Take care of possible animation. */
+ AnimData *adt = BKE_animdata_from_id(&ntree->id);
+ if (adt != NULL && adt->action != NULL) {
+ const char *prefix = BLI_sprintfN("nodes[\"%s\"]", node->name);
+ for (FCurve *fcu = adt->action->curves.first; fcu != NULL; fcu = fcu->next) {
+ if (STRPREFIX(fcu->rna_path, prefix)) {
+ anim_change_prop_name(fcu, prefix, "color_hue", "inputs[1].default_value");
+ anim_change_prop_name(fcu, prefix, "color_saturation", "inputs[2].default_value");
+ anim_change_prop_name(fcu, prefix, "color_value", "inputs[3].default_value");
+ }
+ }
+ MEM_freeN((char *)prefix);
+ }
+ /* Free storage, it is no longer used. */
+ MEM_freeN(node->storage);
+ node->storage = NULL;
+}
+
+static void do_versions_compositor_render_passes_storage(bNode *node)
+{
+ int pass_index = 0;
+ const char *sockname;
+ for (bNodeSocket *sock = node->outputs.first; sock && pass_index < 31; sock = sock->next, pass_index++) {
+ if (sock->storage == NULL) {
+ NodeImageLayer *sockdata = MEM_callocN(sizeof(NodeImageLayer), "node image layer");
+ sock->storage = sockdata;
+ BLI_strncpy(sockdata->pass_name, node_cmp_rlayers_sock_to_pass(pass_index), sizeof(sockdata->pass_name));
+
+ if (pass_index == 0) sockname = "Image";
+ else if (pass_index == 1) sockname = "Alpha";
+ else sockname = node_cmp_rlayers_sock_to_pass(pass_index);
+ BLI_strncpy(sock->name, sockname, sizeof(sock->name));
+ }
+ }
+}
+
+static void do_versions_compositor_render_passes(bNodeTree *ntree)
+{
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_R_LAYERS) {
+ /* First we make sure existing sockets have proper names.
+ * This is important because otherwise verification will
+ * drop links from sockets which were renamed.
+ */
+ do_versions_compositor_render_passes_storage(node);
+ /* Make sure new sockets are properly created. */
+ node_verify_socket_templates(ntree, node);
+ /* Make sure all possibly created sockets have proper storage. */
+ do_versions_compositor_render_passes_storage(node);
+ }
+ }
+}
+
void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
{
if (!MAIN_VERSION_ATLEAST(main, 270, 0)) {
@@ -1125,12 +1236,19 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
SEQ_BEGIN (scene->ed, seq)
{
- if (seq->type == SEQ_TYPE_TEXT) {
- TextVars *data = seq->effectdata;
- if (data->color[3] == 0.0f) {
- copy_v4_fl(data->color, 1.0f);
- data->shadow_color[3] = 1.0f;
- }
+ if (seq->type != SEQ_TYPE_TEXT) {
+ continue;
+ }
+
+ if (seq->effectdata == NULL) {
+ struct SeqEffectHandle effect_handle = BKE_sequence_get_effect(seq);
+ effect_handle.init(seq);
+ }
+
+ TextVars *data = seq->effectdata;
+ if (data->color[3] == 0.0f) {
+ copy_v4_fl(data->color, 1.0f);
+ data->shadow_color[3] = 1.0f;
}
}
SEQ_END
@@ -1184,7 +1302,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
for (Camera *camera = main->camera.first; camera != NULL; camera = camera->id.next) {
if (camera->stereo.pole_merge_angle_from == 0.0f &&
- camera->stereo.pole_merge_angle_to == 0.0f)
+ camera->stereo.pole_merge_angle_to == 0.0f)
{
camera->stereo.pole_merge_angle_from = DEG2RADF(60.0f);
camera->stereo.pole_merge_angle_to = DEG2RADF(75.0f);
@@ -1246,7 +1364,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
if (!MAIN_VERSION_ATLEAST(main, 277, 3)) {
/* ------- init of grease pencil initialization --------------- */
- if (!DNA_struct_elem_find(fd->filesdna, "bGPDstroke", "bGPDpalettecolor", "palcolor")) {
+ if (!DNA_struct_elem_find(fd->filesdna, "bGPDstroke", "bGPDpalettecolor", "*palcolor")) {
for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
ToolSettings *ts = scene->toolsettings;
/* initialize use position for sculpt brushes */
@@ -1288,27 +1406,36 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
/* set color attributes */
copy_v4_v4(palcolor->color, gpl->color);
copy_v4_v4(palcolor->fill, gpl->fill);
- palcolor->flag = gpl->flag;
+
+ if (gpl->flag & GP_LAYER_HIDE) palcolor->flag |= PC_COLOR_HIDE;
+ 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;
+
/* set tint color */
ARRAY_SET_ITEMS(gpl->tintcolor, 0.0f, 0.0f, 0.0f, 0.0f);
-
+
+ /* flush relevant layer-settings to strokes */
for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
/* set stroke to palette and force recalculation */
- strcpy(gps->colorname, gpl->info);
+ 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 */
for (int i = 0; i < gps->totpoints; i++) {
gps->points[i].strength = 1.0f;
}
-
}
}
}
+
/* set thickness to 0 (now it is a factor to override stroke thickness) */
gpl->thickness = 0.0f;
}
@@ -1321,4 +1448,265 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
/* ------- end of grease pencil initialization --------------- */
}
+ if (!MAIN_VERSION_ATLEAST(main, 278, 0)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "MovieTrackingTrack", "float", "weight_stab")) {
+ MovieClip *clip;
+ for (clip = main->movieclip.first; clip; clip = clip->id.next) {
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *tracking_object;
+ for (tracking_object = tracking->objects.first;
+ tracking_object != NULL;
+ tracking_object = tracking_object->next)
+ {
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
+ MovieTrackingTrack *track;
+ for (track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ track->weight_stab = track->weight;
+ }
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "MovieTrackingStabilization", "int", "tot_rot_track")) {
+ MovieClip *clip;
+ for (clip = main->movieclip.first; clip != NULL; clip = clip->id.next) {
+ if (clip->tracking.stabilization.rot_track) {
+ migrate_single_rot_stabilization_track_settings(&clip->tracking.stabilization);
+ }
+ if (clip->tracking.stabilization.scale == 0.0f) {
+ /* ensure init.
+ * Was previously used for autoscale only,
+ * now used always (as "target scale") */
+ clip->tracking.stabilization.scale = 1.0f;
+ }
+ /* blender prefers 1-based frame counting;
+ * thus using frame 1 as reference typically works best */
+ clip->tracking.stabilization.anchor_frame = 1;
+ /* by default show the track lists expanded, to improve "discoverability" */
+ clip->tracking.stabilization.flag |= TRACKING_SHOW_STAB_TRACKS;
+ /* deprecated, not used anymore */
+ clip->tracking.stabilization.ok = false;
+ }
+ }
+ }
+ if (!MAIN_VERSION_ATLEAST(main, 278, 2)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "FFMpegCodecData", "int", "ffmpeg_preset")) {
+ for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ /* "medium" is the preset FFmpeg uses when no presets are given. */
+ scene->r.ffcodecdata.ffmpeg_preset = FFM_PRESET_MEDIUM;
+ }
+ }
+ if (!DNA_struct_elem_find(fd->filesdna, "FFMpegCodecData", "int", "constant_rate_factor")) {
+ for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ /* fall back to behaviour from before we introduced CRF for old files */
+ scene->r.ffcodecdata.constant_rate_factor = FFM_CRF_NONE;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "SmokeModifierData", "float", "slice_per_voxel")) {
+ Object *ob;
+ ModifierData *md;
+
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Smoke) {
+ SmokeModifierData *smd = (SmokeModifierData *)md;
+ if (smd->domain) {
+ smd->domain->slice_per_voxel = 5.0f;
+ smd->domain->slice_depth = 0.5f;
+ smd->domain->display_thickness = 1.0f;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 278, 3)) {
+ for (Scene *scene = main->scene.first; scene != NULL; scene = scene->id.next) {
+ if (scene->toolsettings != NULL) {
+ ToolSettings *ts = scene->toolsettings;
+ ParticleEditSettings *pset = &ts->particle;
+ for (int a = 0; a < PE_TOT_BRUSH; a++) {
+ if (pset->brush[a].count == 0) {
+ pset->brush[a].count = 10;
+ }
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "RigidBodyCon", "float", "spring_stiffness_ang_x")) {
+ Object *ob;
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ RigidBodyCon *rbc = ob->rigidbody_constraint;
+ if (rbc) {
+ rbc->spring_stiffness_ang_x = 10.0;
+ rbc->spring_stiffness_ang_y = 10.0;
+ rbc->spring_stiffness_ang_z = 10.0;
+ rbc->spring_damping_ang_x = 0.5;
+ rbc->spring_damping_ang_y = 0.5;
+ rbc->spring_damping_ang_z = 0.5;
+ }
+ }
+ }
+
+ /* constant detail for sculpting is now a resolution value instead of
+ * a percentage, we reuse old DNA struct member but convert it */
+ for (Scene *scene = main->scene.first; scene != NULL; scene = scene->id.next) {
+ if (scene->toolsettings != NULL) {
+ ToolSettings *ts = scene->toolsettings;
+ if (ts->sculpt && ts->sculpt->constant_detail != 0.0f) {
+ ts->sculpt->constant_detail = 100.0f / ts->sculpt->constant_detail;
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 278, 4)) {
+ const float sqrt_3 = (float)M_SQRT3;
+ for (Brush *br = main->brush.first; br; br = br->id.next) {
+ br->fill_threshold /= sqrt_3;
+ }
+
+ /* Custom motion paths */
+ if (!DNA_struct_elem_find(fd->filesdna, "bMotionPath", "int", "line_thickness")) {
+ Object *ob;
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ bMotionPath *mpath;
+ bPoseChannel *pchan;
+ mpath = ob->mpath;
+ if (mpath) {
+ mpath->color[0] = 1.0f;
+ mpath->color[1] = 0.0f;
+ mpath->color[2] = 0.0f;
+ mpath->line_thickness = 1;
+ mpath->flag |= MOTIONPATH_FLAG_LINES;
+ }
+ /* bones motion path */
+ if (ob->pose) {
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ mpath = pchan->mpath;
+ if (mpath) {
+ mpath->color[0] = 1.0f;
+ mpath->color[1] = 0.0f;
+ mpath->color[2] = 0.0f;
+ mpath->line_thickness = 1;
+ mpath->flag |= MOTIONPATH_FLAG_LINES;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 278, 5)) {
+ /* Mask primitive adding code was not initializing correctly id_type of its points' parent. */
+ for (Mask *mask = main->mask.first; mask; mask = mask->id.next) {
+ for (MaskLayer *mlayer = mask->masklayers.first; mlayer; mlayer = mlayer->next) {
+ for (MaskSpline *mspline = mlayer->splines.first; mspline; mspline = mspline->next) {
+ int i = 0;
+ for (MaskSplinePoint *mspoint = mspline->points; i < mspline->tot_point; mspoint++, i++) {
+ if (mspoint->parent.id_type == 0) {
+ BKE_mask_parent_init(&mspoint->parent);
+ }
+ }
+ }
+ }
+ }
+
+ /* Fix for T50736, Glare comp node using same var for two different things. */
+ if (!DNA_struct_elem_find(fd->filesdna, "NodeGlare", "char", "star_45")) {
+ FOREACH_NODETREE(main, ntree, id) {
+ if (ntree->type == NTREE_COMPOSIT) {
+ ntreeSetTypes(NULL, ntree);
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_GLARE) {
+ NodeGlare *ndg = node->storage;
+ switch (ndg->type) {
+ case 2: /* Grrrr! magic numbers :( */
+ ndg->streaks = ndg->angle;
+ break;
+ case 0:
+ ndg->star_45 = ndg->angle != 0;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ } FOREACH_NODETREE_END
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "SurfaceDeformModifierData", "float", "mat[4][4]")) {
+ for (Object *ob = main->object.first; ob; ob = ob->id.next) {
+ for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_SurfaceDeform) {
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
+ unit_m4(smd->mat);
+ }
+ }
+ }
+ }
+
+ FOREACH_NODETREE(main, ntree, id) {
+ if (ntree->type == NTREE_COMPOSIT) {
+ do_versions_compositor_render_passes(ntree);
+ }
+ } FOREACH_NODETREE_END
+ }
+
+ {
+ for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ if (scene->r.im_format.exr_codec == R_IMF_EXR_CODEC_DWAB) {
+ scene->r.im_format.exr_codec = R_IMF_EXR_CODEC_DWAA;
+ }
+ }
+
+ /* Fix related to VGroup modifiers creating named defgroup CD layers! See T51520. */
+ for (Mesh *me = main->mesh.first; me; me = me->id.next) {
+ CustomData_set_layer_name(&me->vdata, CD_MDEFORMVERT, 0, "");
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DDebug", "char", "background")) {
+ bScreen *screen;
+
+ for (screen = main->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) {
+ switch (sl->spacetype) {
+ case SPACE_VIEW3D:
+ {
+ View3D *v3d = (View3D *)sl;
+ v3d->debug.background = V3D_DEBUG_BACKGROUND_NONE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void do_versions_after_linking_270(Main *main)
+{
+ /* To be added to next subversion bump! */
+ {
+ FOREACH_NODETREE(main, ntree, id) {
+ if (ntree->type == NTREE_COMPOSIT) {
+ ntreeSetTypes(NULL, ntree);
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_HUE_SAT) {
+ do_version_hue_sat_node(ntree, node);
+ }
+ }
+ }
+ } FOREACH_NODETREE_END
+ }
}
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
new file mode 100644
index 00000000000..d76a121376c
--- /dev/null
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -0,0 +1,451 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "DNA_object_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_gpu_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_layer_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_genfile.h"
+#include "DNA_workspace_types.h"
+
+#include "BKE_collection.h"
+#include "BKE_customdata.h"
+#include "BKE_idprop.h"
+#include "BKE_layer.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_node.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_workspace.h"
+
+#include "BLI_listbase.h"
+#include "BLI_mempool.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.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;
+ SceneLayer *layer = BKE_scene_layer_from_scene_get(screen->scene);
+ ListBase *transform_orientations;
+
+ 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);
+ }
+ BKE_workspace_layout_add(workspace, screen, screen->id.name + 2);
+ BKE_workspace_render_layer_set(workspace, layer);
+
+ transform_orientations = BKE_workspace_transform_orientations_get(workspace);
+ BLI_duplicatelist(transform_orientations, &screen->scene->transform_spaces);
+ }
+}
+
+/**
+ * \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;
+ WorkSpace *workspace = BLI_findstring(&bmain->workspaces, screen->id.name + 2, offsetof(ID, name) + 2);
+ 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);
+
+ win->scene = screen->scene;
+ /* 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;
+ }
+}
+
+void do_versions_after_linking_280(Main *main)
+{
+ if (!MAIN_VERSION_ATLEAST(main, 280, 0)) {
+ for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ /* since we don't have access to FileData we check the (always valid) first render layer instead */
+ if (scene->render_layers.first == NULL) {
+ SceneCollection *sc_master = BKE_collection_master(scene);
+ BLI_strncpy(sc_master->name, "Master Collection", sizeof(sc_master->name));
+
+ SceneCollection *collections[20] = {NULL};
+ bool is_visible[20];
+
+ int lay_used = 0;
+ for (int i = 0; i < 20; i++) {
+ char name[MAX_NAME];
+
+ BLI_snprintf(name, sizeof(collections[i]->name), "Collection %d", i + 1);
+ collections[i] = BKE_collection_add(scene, sc_master, name);
+
+ is_visible[i] = (scene->lay & (1 << i));
+ }
+
+ for (Base *base = scene->base.first; base; base = base->next) {
+ lay_used |= base->lay & ((1 << 20) - 1); /* ignore localview */
+
+ for (int i = 0; i < 20; i++) {
+ if ((base->lay & (1 << i)) != 0) {
+ BKE_collection_object_add(scene, collections[i], base->object);
+ }
+ }
+
+ if (base->flag & SELECT) {
+ base->object->flag |= SELECT;
+ }
+ else {
+ base->object->flag &= ~SELECT;
+ }
+ }
+
+ scene->active_layer = 0;
+
+ if (!BKE_scene_uses_blender_game(scene)) {
+ for (SceneRenderLayer *srl = scene->r.layers.first; srl; srl = srl->next) {
+
+ SceneLayer *sl = BKE_scene_layer_add(scene, srl->name);
+ BKE_scene_layer_engine_set(sl, scene->r.engine);
+
+ if (srl->mat_override) {
+ BKE_collection_override_datablock_add((LayerCollection *)sl->layer_collections.first, "material", (ID *)srl->mat_override);
+ }
+
+ if (srl->light_override && BKE_scene_uses_blender_internal(scene)) {
+ /* not sure how we handle this, pending until we design the override system */
+ TODO_LAYER_OVERRIDE;
+ }
+
+ if (srl->lay != scene->lay) {
+ /* unlink master collection */
+ BKE_collection_unlink(sl, sl->layer_collections.first);
+
+ /* add new collection bases */
+ for (int i = 0; i < 20; i++) {
+ if ((srl->lay & (1 << i)) != 0) {
+ BKE_collection_link(sl, collections[i]);
+ }
+ }
+ }
+
+ /* for convenience set the same active object in all the layers */
+ if (scene->basact) {
+ sl->basact = BKE_scene_layer_base_find(sl, scene->basact->object);
+ }
+
+ for (Base *base = sl->object_bases.first; base; base = base->next) {
+ if ((base->flag & BASE_SELECTABLED) && (base->object->flag & SELECT)) {
+ base->flag |= BASE_SELECTED;
+ }
+ }
+
+ /* TODO: passes, samples, mask_layesr, exclude, ... */
+ }
+
+ if (BLI_findlink(&scene->render_layers, scene->r.actlay)) {
+ scene->active_layer = scene->r.actlay;
+ }
+ }
+
+ SceneLayer *sl = BKE_scene_layer_add(scene, "Viewport");
+
+ /* In this particular case we can safely assume the data struct */
+ LayerCollection *lc = ((LayerCollection *)sl->layer_collections.first)->layer_collections.first;
+ for (int i = 0; i < 20; i++) {
+ if (!is_visible[i]) {
+ lc->flag &= ~COLLECTION_VISIBLE;
+ }
+ lc = lc->next;
+ }
+
+ /* convert active base */
+ if (scene->basact) {
+ sl->basact = BKE_scene_layer_base_find(sl, scene->basact->object);
+ }
+
+ /* convert selected bases */
+ for (Base *base = scene->base.first; base; base = base->next) {
+ if ((base->flag & BASE_SELECTABLED) && (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;
+ }
+
+ /* TODO: copy scene render data to layer */
+
+ /* Cleanup */
+ for (int i = 0; i < 20; i++) {
+ if ((lay_used & (1 << i)) == 0) {
+ BKE_collection_remove(scene, collections[i]);
+ }
+ }
+
+ /* Fallback name if only one layer was found in the original file */
+ if (BLI_listbase_count_ex(&sc_master->scene_collections, 2) == 1) {
+ BKE_collection_rename(scene, sc_master->scene_collections.first, "Default Collection");
+ }
+
+ /* 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;
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 280, 0)) {
+ for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) {
+ /* same render-layer as do_version_workspaces_after_lib_link will activate,
+ * so same layer as BKE_scene_layer_from_workspace_get would return */
+ SceneLayer *layer = screen->scene->render_layers.first;
+
+ 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 *soutliner = (SpaceOops *)sl;
+
+ soutliner->outlinevis = SO_ACT_LAYER;
+
+ if (BLI_listbase_count_ex(&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(main, 280, 1)) {
+ do_version_workspaces_after_lib_link(main);
+ }
+}
+
+static void do_version_layer_collections_idproperties(ListBase *lb)
+{
+ IDPropertyTemplate val = {0};
+ for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ lc->properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
+ BKE_layer_collection_engine_settings_create(lc->properties);
+
+ /* No overrides at first */
+ for (IDProperty *prop = lc->properties->data.group.first; prop; prop = prop->next) {
+ while (prop->data.group.first) {
+ IDP_FreeFromGroup(prop, prop->data.group.first);
+ }
+ }
+
+ /* Do it recursively */
+ do_version_layer_collections_idproperties(&lc->layer_collections);
+ }
+}
+
+void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
+{
+ if (!MAIN_VERSION_ATLEAST(main, 280, 0)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "Scene", "ListBase", "render_layers")) {
+ for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ /* Master Collection */
+ scene->collection = MEM_callocN(sizeof(SceneCollection), "Master Collection");
+ BLI_strncpy(scene->collection->name, "Master Collection", sizeof(scene->collection->name));
+ }
+ }
+
+ if (DNA_struct_elem_find(fd->filesdna, "LayerCollection", "ListBase", "engine_settings") &&
+ !DNA_struct_elem_find(fd->filesdna, "LayerCollection", "IDProperty", "properties"))
+ {
+ for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
+ do_version_layer_collections_idproperties(&sl->layer_collections);
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 280, 1)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "bleedexp")) {
+ for (Lamp *la = main->lamp.first; la; la = la->id.next) {
+ la->bleedexp = 120.0f;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "GPUDOFSettings", "float", "ratio")) {
+ for (Camera *ca = main->camera.first; ca; ca = ca->id.next) {
+ ca->gpu_dof.ratio = 1.0f;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "SceneLayer", "IDProperty", "*properties")) {
+ for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
+ IDPropertyTemplate val = {0};
+ sl->properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
+ BKE_scene_layer_engine_settings_create(sl->properties);
+ }
+ }
+ }
+
+ /* MTexPoly now removed. */
+ if (DNA_struct_find(fd->filesdna, "MTexPoly")) {
+ const int cd_mtexpoly = 15; /* CD_MTEXPOLY, deprecated */
+ for (Mesh *me = main->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 (!DNA_struct_elem_find(fd->filesdna, "View3D", "short", "custom_orientation_index")) {
+ for (bScreen *screen = main->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;
+ if (v3d->twmode >= V3D_MANIP_CUSTOM) {
+ v3d->custom_orientation_index = v3d->twmode - V3D_MANIP_CUSTOM;
+ v3d->twmode = V3D_MANIP_CUSTOM;
+ }
+ else {
+ v3d->custom_orientation_index = -1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ {
+ {
+ /* 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. */
+ bool error = false;
+ FOREACH_NODETREE(main, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_EEVEE_METALLIC && STREQ(node->idname, "ShaderNodeOutputMetallic")) {
+ BLI_strncpy(node->idname, "ShaderNodeEeveeMetallic", sizeof(node->idname));
+ error = true;
+ }
+
+ if (node->type == SH_NODE_EEVEE_SPECULAR && STREQ(node->idname, "ShaderNodeOutputSpecular")) {
+ BLI_strncpy(node->idname, "ShaderNodeEeveeSpecular", sizeof(node->idname));
+ error = true;
+ }
+ }
+ }
+ } FOREACH_NODETREE_END
+ if (error) {
+ BKE_report(fd->reports, RPT_ERROR, "Eevee material conversion problem. Error in console");
+ printf("You need to connect Eevee Metallic and Specular shader nodes to new material output nodes.\n");
+ }
+ }
+ }
+}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index ec817b9b261..50f96a6d438 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -28,6 +28,7 @@
#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"
@@ -39,10 +40,12 @@
#include "DNA_mesh_types.h"
#include "DNA_material_types.h"
#include "DNA_object_types.h"
+#include "DNA_workspace_types.h"
#include "BKE_brush.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_workspace.h"
#include "BLO_readfile.h"
@@ -68,6 +71,44 @@ void BLO_update_defaults_userpref_blend(void)
* 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;
+
+#ifdef WITH_PYTHON_SECURITY
+ /* use alternative setting for security nuts
+ * otherwise we'd need to patch the binary blob - startup.blend.c */
+ U.flag |= USER_SCRIPT_AUTOEXEC_DISABLE;
+#else
+ U.flag &= ~USER_SCRIPT_AUTOEXEC_DISABLE;
+#endif
+}
+
+/**
+ * New workspace design: Remove all screens/workspaces except of "Default" one and rename the workspace to "General".
+ * For compatibility, a new workspace has been created for each screen of old files,
+ * we only want one workspace and one screen in the default startup file however.
+ */
+static void update_defaults_startup_workspaces(Main *bmain)
+{
+ WorkSpace *workspace_default = NULL;
+
+ for (WorkSpace *workspace = bmain->workspaces.first, *workspace_next; workspace; workspace = workspace_next) {
+ workspace_next = workspace->id.next;
+
+ if (STREQ(workspace->id.name + 2, "Default")) {
+ /* don't rename within iterator, renaming causes listbase to be re-sorted */
+ workspace_default = workspace;
+ }
+ else {
+ BKE_workspace_remove(bmain, workspace);
+ }
+ }
+
+ /* rename "Default" workspace to "General" */
+ BKE_libblock_rename(bmain, (ID *)workspace_default, "General");
+ BLI_assert(BLI_listbase_count(BKE_workspace_layouts_get(workspace_default)) == 1);
}
/**
@@ -76,6 +117,8 @@ void BLO_update_defaults_userpref_blend(void)
void BLO_update_defaults_startup_blend(Main *bmain)
{
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));
+
scene->r.im_format.planes = R_IMF_PLANES_RGBA;
scene->r.im_format.compress = 15;
@@ -147,6 +190,7 @@ void BLO_update_defaults_startup_blend(Main *bmain)
ParticleEditSettings *pset = &ts->particle;
for (int a = 0; a < PE_TOT_BRUSH; a++) {
pset->brush[a].strength = 0.5f;
+ pset->brush[a].count = 10;
}
pset->brush[PE_BRUSH_CUT].strength = 1.0f;
}
@@ -165,20 +209,18 @@ void BLO_update_defaults_startup_blend(Main *bmain)
linestyle->chain_count = 10;
}
- 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;
+ update_defaults_startup_workspaces(bmain);
- for (space_link = area->spacedata.first; space_link; space_link = space_link->next) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *area = screen->areabase.first; area; area = area->next) {
+ for (SpaceLink *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;
}
}
- for (ar = area->regionbase.first; ar; ar = ar->next) {
+ for (ARegion *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);
@@ -229,13 +271,13 @@ void BLO_update_defaults_startup_blend(Main *bmain)
/* remove polish brush (flatten/contrast does the same) */
br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Polish");
if (br) {
- BKE_libblock_free(bmain, br);
+ BKE_libblock_delete(bmain, br);
}
/* remove brush brush (huh?) from some modes (draw brushes do the same) */
br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Brush");
if (br) {
- BKE_libblock_free(bmain, br);
+ BKE_libblock_delete(bmain, br);
}
/* remove draw brush from texpaint (draw brushes do the same) */
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index f2d42849bcc..67b629222a2 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -319,55 +319,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 +354,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);
@@ -916,23 +860,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 196) {
- Mesh *me = main->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 (main->versionfile <= 200) {
Object *ob = main->object.first;
while (ob) {
@@ -2296,11 +2223,12 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
/* during 2.41 images with this name were used for viewer node output, lets fix that */
if (main->versionfile == 241) {
Image *ima;
- for (ima = main->image.first; ima; ima = ima->id.next)
+ for (ima = main->image.first; ima; ima = ima->id.next) {
if (STREQ(ima->name, "Compositor")) {
strcpy(ima->id.name + 2, "Viewer Node");
strcpy(ima->name, "Viewer Node");
}
+ }
}
}
@@ -3289,14 +3217,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
-
- if (main->versionfile < 246 || (main->versionfile == 246 && main->subversionfile < 1)) {
- Mesh *me;
-
- for (me = main->mesh.first; me; me = me->id.next)
- alphasort_version_246(fd, lib, me);
- }
-
if (main->versionfile < 246 || (main->versionfile == 246 && main->subversionfile < 1)) {
Object *ob;
for (ob = main->object.first; ob; ob = ob->id.next) {
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 346e9391f74..bf50ba8975a 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -49,7 +49,7 @@
* <bh.len> int, len data after BHead
* <bh.old> void, old pointer
* <bh.SDNAnr> int
- * <bh.nr> int, in case of array: amount of structs
+ * <bh.nr> int, in case of array: number of structs
* data
* ...
* ...
@@ -78,7 +78,7 @@
* - write #TEST (#RenderInfo struct. 128x128 blend file preview is optional).
* - write #GLOB (#FileGlobal struct) (some global vars).
* - write #DNA1 (#SDNA struct)
- * - write #USER (#UserDef struct) if filename is ``~/X.XX/config/startup.blend``.
+ * - write #USER (#UserDef struct) if filename is ``~/.config/blender/X.XX/config/startup.blend``.
*/
@@ -102,6 +102,10 @@
/* 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"
@@ -120,6 +124,7 @@
#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,6 +135,7 @@
#include "DNA_object_force.h"
#include "DNA_packedFile_types.h"
#include "DNA_particle_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_property_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
@@ -146,6 +152,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"
@@ -172,6 +179,7 @@
#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 */
@@ -797,30 +805,22 @@ static void write_fcurves(WriteData *wd, ListBase *fcurves)
}
}
-static void write_actions(WriteData *wd, ListBase *idbase)
+static void write_action(WriteData *wd, bAction *act)
{
- bAction *act;
- bActionGroup *grp;
- TimeMarker *marker;
-
- for (act = idbase->first; act; act = act->id.next) {
- if (act->id.us > 0 || wd->current) {
- writestruct(wd, ID_AC, bAction, 1, act);
- write_iddata(wd, &act->id);
+ if (act->id.us > 0 || wd->current) {
+ writestruct(wd, ID_AC, bAction, 1, act);
+ write_iddata(wd, &act->id);
- write_fcurves(wd, &act->curves);
+ write_fcurves(wd, &act->curves);
- for (grp = act->groups.first; grp; grp = grp->next) {
- writestruct(wd, DATA, bActionGroup, 1, grp);
- }
+ for (bActionGroup *grp = act->groups.first; grp; grp = grp->next) {
+ writestruct(wd, DATA, bActionGroup, 1, grp);
+ }
- for (marker = act->markers.first; marker; marker = marker->next) {
- writestruct(wd, DATA, TimeMarker, 1, marker);
- }
+ for (TimeMarker *marker = act->markers.first; marker; marker = marker->next) {
+ writestruct(wd, DATA, TimeMarker, 1, marker);
}
}
-
- mywrite_flush(wd);
}
static void write_keyingsets(WriteData *wd, ListBase *list)
@@ -914,20 +914,22 @@ static void write_curvemapping(WriteData *wd, CurveMapping *cumap)
static void write_node_socket(WriteData *wd, bNodeTree *UNUSED(ntree), bNode *node, bNodeSocket *sock)
{
#ifdef USE_NODE_COMPAT_CUSTOMNODES
- /* forward compatibility code, so older blenders still open */
- sock->stack_type = 1;
-
- if (node->type == NODE_GROUP) {
- bNodeTree *ngroup = (bNodeTree *)node->id;
- if (ngroup) {
- /* for node groups: look up the deprecated groupsock pointer */
- sock->groupsock = ntreeFindSocketInterface(ngroup, sock->in_out, sock->identifier);
- BLI_assert(sock->groupsock != NULL);
-
- /* node group sockets now use the generic identifier string to verify group nodes,
- * old blender uses the own_index.
- */
- sock->own_index = sock->groupsock->own_index;
+ /* forward compatibility code, so older blenders still open (not for undo) */
+ if (wd->current == NULL) {
+ sock->stack_type = 1;
+
+ if (node->type == NODE_GROUP) {
+ bNodeTree *ngroup = (bNodeTree *)node->id;
+ if (ngroup) {
+ /* for node groups: look up the deprecated groupsock pointer */
+ sock->groupsock = ntreeFindSocketInterface(ngroup, sock->in_out, sock->identifier);
+ BLI_assert(sock->groupsock != NULL);
+
+ /* node group sockets now use the generic identifier string to verify group nodes,
+ * old blender uses the own_index.
+ */
+ sock->own_index = sock->groupsock->own_index;
+ }
}
}
#endif
@@ -967,7 +969,7 @@ static void write_node_socket_interface(WriteData *wd, bNodeTree *UNUSED(ntree),
}
}
/* this is only direct data, tree itself should have been written */
-static void write_nodetree(WriteData *wd, bNodeTree *ntree)
+static void write_nodetree_nolib(WriteData *wd, bNodeTree *ntree)
{
bNode *node;
bNodeSocket *sock;
@@ -1028,6 +1030,25 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree)
{
/* pass */
}
+ else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_GLARE)) {
+ /* Simple forward compat for fix for T50736.
+ * Not ideal (there is no ideal solution here), but should do for now. */
+ NodeGlare *ndg = node->storage;
+ /* Not in undo case. */
+ if (!wd->current) {
+ switch (ndg->type) {
+ case 2: /* Grrrr! magic numbers :( */
+ ndg->angle = ndg->streaks;
+ break;
+ case 0:
+ ndg->angle = ndg->star_45;
+ break;
+ default:
+ break;
+ }
+ }
+ writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage);
+ }
else {
writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage);
}
@@ -1039,7 +1060,7 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree)
writestruct(wd, DATA, NodeImageMultiFileSocket, 1, sock->storage);
}
}
- if (node->type == CMP_NODE_IMAGE) {
+ if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_R_LAYERS)) {
/* write extra socket info */
for (sock = node->outputs.first; sock; sock = sock->next) {
writestruct(wd, DATA, NodeImageLayer, 1, sock->storage);
@@ -1063,10 +1084,13 @@ static void write_nodetree(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, SceneLayer **r_render_layer)
{
wmWindowManager *wm;
wmWindow *window = NULL;
+ WorkSpace *workspace;
/* find a global current screen in the first open window, to have
* a reasonable default for reading in older versions */
@@ -1090,8 +1114,11 @@ static void current_screen_compat(Main *mainvar, bScreen **r_screen, bool use_ac
window = wm->windows.first;
}
}
+ workspace = (window) ? BKE_workspace_active_get(window->workspace_hook) : NULL;
- *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_render_layer = (window) ? BKE_workspace_render_layer_get(workspace) : NULL;
}
typedef struct RenderInfo {
@@ -1107,13 +1134,11 @@ static void write_renderinfo(WriteData *wd, Main *mainvar)
{
bScreen *curscreen;
Scene *sce, *curscene = NULL;
+ SceneLayer *render_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, &render_layer);
for (sce = mainvar->scene.first; sce; sce = sce->id.next) {
if (sce->id.lib == NULL && (sce == curscene || (sce->r.scemode & R_BG_RENDER))) {
@@ -1276,70 +1301,60 @@ static void write_pointcaches(WriteData *wd, ListBase *ptcaches)
}
}
}
-static void write_particlesettings(WriteData *wd, ListBase *idbase)
-{
- ParticleSettings *part;
- ParticleDupliWeight *dw;
- GroupObject *go;
- int a;
- part = idbase->first;
- while (part) {
- if (part->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_PA, ParticleSettings, 1, part);
- write_iddata(wd, &part->id);
+static void write_particlesettings(WriteData *wd, ParticleSettings *part)
+{
+ if (part->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_PA, ParticleSettings, 1, part);
+ write_iddata(wd, &part->id);
- if (part->adt) {
- write_animdata(wd, part->adt);
- }
- writestruct(wd, DATA, PartDeflect, 1, part->pd);
- writestruct(wd, DATA, PartDeflect, 1, part->pd2);
- writestruct(wd, DATA, EffectorWeights, 1, part->effector_weights);
+ if (part->adt) {
+ write_animdata(wd, part->adt);
+ }
+ writestruct(wd, DATA, PartDeflect, 1, part->pd);
+ writestruct(wd, DATA, PartDeflect, 1, part->pd2);
+ writestruct(wd, DATA, EffectorWeights, 1, part->effector_weights);
- if (part->clumpcurve) {
- write_curvemapping(wd, part->clumpcurve);
- }
- if (part->roughcurve) {
- write_curvemapping(wd, part->roughcurve);
- }
+ if (part->clumpcurve) {
+ write_curvemapping(wd, part->clumpcurve);
+ }
+ if (part->roughcurve) {
+ write_curvemapping(wd, part->roughcurve);
+ }
- dw = part->dupliweights.first;
- for (; dw; dw = dw->next) {
- /* update indices */
+ for (ParticleDupliWeight *dw = part->dupliweights.first; dw; dw = dw->next) {
+ /* update indices, but only if dw->ob is set (can be NULL after loading e.g.) */
+ if (dw->ob != NULL) {
dw->index = 0;
if (part->dup_group) { /* can be NULL if lining fails or set to None */
- go = part->dup_group->gobject.first;
- while (go && go->ob != dw->ob) {
- go = go->next;
- dw->index++;
- }
+ for (GroupObject *go = part->dup_group->gobject.first;
+ go && go->ob != dw->ob;
+ go = go->next, dw->index++);
}
- writestruct(wd, DATA, ParticleDupliWeight, 1, dw);
}
+ writestruct(wd, DATA, ParticleDupliWeight, 1, dw);
+ }
- if (part->boids && part->phystype == PART_PHYS_BOIDS) {
- BoidState *state = part->boids->states.first;
-
- writestruct(wd, DATA, BoidSettings, 1, part->boids);
+ if (part->boids && part->phystype == PART_PHYS_BOIDS) {
+ writestruct(wd, DATA, BoidSettings, 1, part->boids);
- for (; state; state = state->next) {
- write_boid_state(wd, state);
- }
- }
- if (part->fluid && part->phystype == PART_PHYS_FLUID) {
- writestruct(wd, DATA, SPHFluidSettings, 1, part->fluid);
+ for (BoidState *state = part->boids->states.first; state; state = state->next) {
+ write_boid_state(wd, state);
}
+ }
+ if (part->fluid && part->phystype == PART_PHYS_FLUID) {
+ writestruct(wd, DATA, SPHFluidSettings, 1, part->fluid);
+ }
- for (a = 0; a < MAX_MTEX; a++) {
- if (part->mtex[a]) {
- writestruct(wd, DATA, MTex, 1, part->mtex[a]);
- }
+ for (int a = 0; a < MAX_MTEX; a++) {
+ if (part->mtex[a]) {
+ writestruct(wd, DATA, MTex, 1, part->mtex[a]);
}
}
- part = part->id.next;
}
}
+
static void write_particlesystems(WriteData *wd, ListBase *particles)
{
ParticleSystem *psys = particles->first;
@@ -1684,6 +1699,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;
@@ -1721,6 +1743,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]));
@@ -1730,11 +1754,12 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
smd->domain->point_cache[1]->step = 1;
write_pointcaches(wd, &(smd->domain->ptcaches[1]));
- }
- writestruct(wd, DATA, SmokeDomainSettings, 1, smd->domain);
+ if (smd->domain->coba) {
+ writestruct(wd, DATA, ColorBand, 1, smd->domain->coba);
+ }
+
- if (smd->domain) {
/* cleanup the fake pointcache */
BKE_ptcache_free_list(&smd->domain->ptcaches[1]);
smd->domain->point_cache[1] = NULL;
@@ -1826,242 +1851,208 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
writedata(wd, DATA, sizeof(float[3]) * csmd->bind_coords_num, csmd->bind_coords);
}
}
- }
-}
+ else if (md->type == eModifierType_SurfaceDeform) {
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
-static void write_objects(WriteData *wd, ListBase *idbase)
-{
- Object *ob;
+ writestruct(wd, DATA, SDefVert, smd->numverts, smd->verts);
- ob = idbase->first;
- while (ob) {
- if (ob->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_OB, Object, 1, ob);
- write_iddata(wd, &ob->id);
+ if (smd->verts) {
+ for (int i = 0; i < smd->numverts; i++) {
+ writestruct(wd, DATA, SDefBind, smd->verts[i].numbinds, smd->verts[i].binds);
- if (ob->adt) {
- write_animdata(wd, ob->adt);
- }
+ if (smd->verts[i].binds) {
+ for (int j = 0; j < smd->verts[i].numbinds; j++) {
+ writedata(wd, DATA, sizeof(int) * smd->verts[i].binds[j].numverts, smd->verts[i].binds[j].vert_inds);
- /* direct data */
- 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;
- if (arm && ob->pose && arm->act_bone) {
- BLI_strncpy(ob->pose->proxy_act_bone, arm->act_bone->name, sizeof(ob->pose->proxy_act_bone));
+ if (smd->verts[i].binds[j].mode == MOD_SDEF_MODE_CENTROID ||
+ smd->verts[i].binds[j].mode == MOD_SDEF_MODE_LOOPTRI)
+ {
+ writedata(wd, DATA, sizeof(float) * 3, smd->verts[i].binds[j].vert_weights);
+ }
+ else {
+ writedata(wd, DATA, sizeof(float) * smd->verts[i].binds[j].numverts, smd->verts[i].binds[j].vert_weights);
+ }
+ }
+ }
}
}
+ }
+ }
+}
- write_pose(wd, ob->pose);
- write_defgroups(wd, &ob->defbase);
- write_constraints(wd, &ob->constraints);
- write_motionpath(wd, ob->mpath);
+static void write_object(WriteData *wd, Object *ob)
+{
+ if (ob->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_OB, Object, 1, ob);
+ write_iddata(wd, &ob->id);
- writestruct(wd, DATA, PartDeflect, 1, ob->pd);
- writestruct(wd, DATA, SoftBody, 1, ob->soft);
- if (ob->soft) {
- write_pointcaches(wd, &ob->soft->ptcaches);
- writestruct(wd, DATA, EffectorWeights, 1, ob->soft->effector_weights);
- }
- writestruct(wd, DATA, BulletSoftBody, 1, ob->bsoft);
+ if (ob->adt) {
+ write_animdata(wd, ob->adt);
+ }
- if (ob->rigidbody_object) {
- /* TODO: if any extra data is added to handle duplis, will need separate function then */
- writestruct(wd, DATA, RigidBodyOb, 1, ob->rigidbody_object);
- }
- if (ob->rigidbody_constraint) {
- writestruct(wd, DATA, RigidBodyCon, 1, ob->rigidbody_constraint);
- }
+ /* direct data */
+ 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_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) {
- writestruct(wd, DATA, ImageUser, 1, ob->iuser);
+ if (ob->type == OB_ARMATURE) {
+ bArmature *arm = ob->data;
+ if (arm && ob->pose && arm->act_bone) {
+ BLI_strncpy(ob->pose->proxy_act_bone, arm->act_bone->name, sizeof(ob->pose->proxy_act_bone));
}
+ }
- write_particlesystems(wd, &ob->particlesystem);
- write_modifiers(wd, &ob->modifiers);
+ 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);
- writelist(wd, DATA, LinkData, &ob->pc_ids);
- writelist(wd, DATA, LodLevel, &ob->lodlevels);
+ writestruct(wd, DATA, PartDeflect, 1, ob->pd);
+ writestruct(wd, DATA, SoftBody, 1, ob->soft);
+ if (ob->soft) {
+ write_pointcaches(wd, &ob->soft->ptcaches);
+ writestruct(wd, DATA, EffectorWeights, 1, ob->soft->effector_weights);
}
+ writestruct(wd, DATA, BulletSoftBody, 1, ob->bsoft);
- write_previews(wd, ob->preview);
+ if (ob->rigidbody_object) {
+ /* TODO: if any extra data is added to handle duplis, will need separate function then */
+ writestruct(wd, DATA, RigidBodyOb, 1, ob->rigidbody_object);
+ }
+ if (ob->rigidbody_constraint) {
+ writestruct(wd, DATA, RigidBodyCon, 1, ob->rigidbody_constraint);
+ }
- ob = ob->id.next;
- }
+ if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) {
+ writestruct(wd, DATA, ImageUser, 1, ob->iuser);
+ }
- mywrite_flush(wd);
-}
+ write_particlesystems(wd, &ob->particlesystem);
+ write_modifiers(wd, &ob->modifiers);
+ writelist(wd, DATA, LinkData, &ob->pc_ids);
+ writelist(wd, DATA, LodLevel, &ob->lodlevels);
-static void write_vfonts(WriteData *wd, ListBase *idbase)
-{
- VFont *vf;
- PackedFile *pf;
+ write_previews(wd, ob->preview);
+ }
+}
- vf = idbase->first;
- while (vf) {
- if (vf->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_VF, VFont, 1, vf);
- write_iddata(wd, &vf->id);
- /* direct data */
+static void write_vfont(WriteData *wd, VFont *vf)
+{
+ if (vf->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_VF, VFont, 1, vf);
+ write_iddata(wd, &vf->id);
- if (vf->packedfile) {
- pf = vf->packedfile;
- writestruct(wd, DATA, PackedFile, 1, pf);
- writedata(wd, DATA, pf->size, pf->data);
- }
+ /* direct data */
+ if (vf->packedfile) {
+ PackedFile *pf = vf->packedfile;
+ writestruct(wd, DATA, PackedFile, 1, pf);
+ writedata(wd, DATA, pf->size, pf->data);
}
-
- vf = vf->id.next;
}
-
- mywrite_flush(wd);
}
-static void write_keys(WriteData *wd, ListBase *idbase)
+static void write_key(WriteData *wd, Key *key)
{
- Key *key;
- KeyBlock *kb;
-
- key = idbase->first;
- while (key) {
- if (key->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_KE, Key, 1, key);
- write_iddata(wd, &key->id);
-
- if (key->adt) {
- write_animdata(wd, key->adt);
- }
+ if (key->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_KE, Key, 1, key);
+ write_iddata(wd, &key->id);
- /* direct data */
- kb = key->block.first;
- while (kb) {
- writestruct(wd, DATA, KeyBlock, 1, kb);
- if (kb->data) {
- writedata(wd, DATA, kb->totelem * key->elemsize, kb->data);
- }
- kb = kb->next;
- }
+ if (key->adt) {
+ write_animdata(wd, key->adt);
}
- key = key->id.next;
+ /* direct data */
+ for (KeyBlock *kb = key->block.first; kb; kb = kb->next) {
+ writestruct(wd, DATA, KeyBlock, 1, kb);
+ if (kb->data) {
+ writedata(wd, DATA, kb->totelem * key->elemsize, kb->data);
+ }
+ }
}
-
- mywrite_flush(wd);
}
-static void write_cameras(WriteData *wd, ListBase *idbase)
+static void write_camera(WriteData *wd, Camera *cam)
{
- Camera *cam;
-
- cam = idbase->first;
- while (cam) {
- if (cam->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_CA, Camera, 1, cam);
- write_iddata(wd, &cam->id);
+ if (cam->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_CA, Camera, 1, cam);
+ write_iddata(wd, &cam->id);
- if (cam->adt) {
- write_animdata(wd, cam->adt);
- }
+ if (cam->adt) {
+ write_animdata(wd, cam->adt);
}
-
- cam = cam->id.next;
}
}
-static void write_mballs(WriteData *wd, ListBase *idbase)
+static void write_mball(WriteData *wd, MetaBall *mb)
{
- MetaBall *mb;
- MetaElem *ml;
-
- mb = idbase->first;
- while (mb) {
- if (mb->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_MB, MetaBall, 1, mb);
- write_iddata(wd, &mb->id);
+ if (mb->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_MB, MetaBall, 1, mb);
+ write_iddata(wd, &mb->id);
- /* direct data */
- writedata(wd, DATA, sizeof(void *) * mb->totcol, mb->mat);
- if (mb->adt) {
- write_animdata(wd, mb->adt);
- }
+ /* direct data */
+ writedata(wd, DATA, sizeof(void *) * mb->totcol, mb->mat);
+ if (mb->adt) {
+ write_animdata(wd, mb->adt);
+ }
- ml = mb->elems.first;
- while (ml) {
- writestruct(wd, DATA, MetaElem, 1, ml);
- ml = ml->next;
- }
+ for (MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
+ writestruct(wd, DATA, MetaElem, 1, ml);
}
- mb = mb->id.next;
}
}
-static void write_curves(WriteData *wd, ListBase *idbase)
+static void write_curve(WriteData *wd, Curve *cu)
{
- Curve *cu;
- Nurb *nu;
-
- cu = idbase->first;
- while (cu) {
- if (cu->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_CU, Curve, 1, cu);
- write_iddata(wd, &cu->id);
+ if (cu->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_CU, Curve, 1, cu);
+ write_iddata(wd, &cu->id);
- /* direct data */
- writedata(wd, DATA, sizeof(void *) * cu->totcol, cu->mat);
- if (cu->adt) {
- write_animdata(wd, cu->adt);
- }
+ /* direct data */
+ writedata(wd, DATA, sizeof(void *) * cu->totcol, cu->mat);
+ if (cu->adt) {
+ write_animdata(wd, cu->adt);
+ }
- if (cu->vfont) {
- writedata(wd, DATA, cu->len + 1, cu->str);
- writestruct(wd, DATA, CharInfo, cu->len_wchar + 1, cu->strinfo);
- writestruct(wd, DATA, TextBox, cu->totbox, cu->tb);
+ if (cu->vfont) {
+ writedata(wd, DATA, cu->len + 1, cu->str);
+ writestruct(wd, DATA, CharInfo, cu->len_wchar + 1, cu->strinfo);
+ writestruct(wd, DATA, TextBox, cu->totbox, cu->tb);
+ }
+ else {
+ /* is also the order of reading */
+ for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) {
+ writestruct(wd, DATA, Nurb, 1, nu);
}
- else {
- /* is also the order of reading */
- nu = cu->nurb.first;
- while (nu) {
- writestruct(wd, DATA, Nurb, 1, nu);
- nu = nu->next;
+ for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ writestruct(wd, DATA, BezTriple, nu->pntsu, nu->bezt);
}
- nu = cu->nurb.first;
- while (nu) {
- if (nu->type == CU_BEZIER) {
- writestruct(wd, DATA, BezTriple, nu->pntsu, nu->bezt);
+ else {
+ writestruct(wd, DATA, BPoint, nu->pntsu * nu->pntsv, nu->bp);
+ if (nu->knotsu) {
+ writedata(wd, DATA, KNOTSU(nu) * sizeof(float), nu->knotsu);
}
- else {
- writestruct(wd, DATA, BPoint, nu->pntsu * nu->pntsv, nu->bp);
- if (nu->knotsu) {
- writedata(wd, DATA, KNOTSU(nu) * sizeof(float), nu->knotsu);
- }
- if (nu->knotsv) {
- writedata(wd, DATA, KNOTSV(nu) * sizeof(float), nu->knotsv);
- }
+ if (nu->knotsv) {
+ writedata(wd, DATA, KNOTSV(nu) * sizeof(float), nu->knotsv);
}
- nu = nu->next;
}
}
}
- cu = cu->id.next;
}
-
- mywrite_flush(wd);
}
static void write_dverts(WriteData *wd, int count, MDeformVert *dvlist)
@@ -2151,6 +2142,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) {
@@ -2178,408 +2173,351 @@ static void write_customdata(
}
}
-static void write_meshes(WriteData *wd, ListBase *idbase)
+static void write_mesh(WriteData *wd, Mesh *mesh)
{
- Mesh *mesh;
- bool save_for_old_blender = false;
-
#ifdef USE_BMESH_SAVE_AS_COMPAT
- save_for_old_blender = wd->use_mesh_compat; /* option to save with older mesh format */
+ const bool save_for_old_blender = wd->use_mesh_compat; /* option to save with older mesh format */
+#else
+ const bool save_for_old_blender = false;
#endif
- mesh = idbase->first;
- while (mesh) {
- CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE];
- CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE];
- CustomDataLayer *flayers = NULL, flayers_buff[CD_TEMP_CHUNK_SIZE];
- CustomDataLayer *llayers = NULL, llayers_buff[CD_TEMP_CHUNK_SIZE];
- CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE];
-
- if (mesh->id.us > 0 || wd->current) {
- /* write LibData */
- if (!save_for_old_blender) {
- /* write a copy of the mesh, don't modify in place because it is
- * not thread safe for threaded renders that are reading this */
- Mesh *old_mesh = mesh;
- Mesh copy_mesh = *mesh;
- mesh = &copy_mesh;
+ CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *flayers = NULL, flayers_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *llayers = NULL, llayers_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE];
+
+ if (mesh->id.us > 0 || wd->current) {
+ /* write LibData */
+ if (!save_for_old_blender) {
+ /* write a copy of the mesh, don't modify in place because it is
+ * not thread safe for threaded renders that are reading this */
+ Mesh *old_mesh = mesh;
+ Mesh copy_mesh = *mesh;
+ mesh = &copy_mesh;
#ifdef USE_BMESH_SAVE_WITHOUT_MFACE
- /* cache only - don't write */
- mesh->mface = NULL;
- mesh->totface = 0;
- memset(&mesh->fdata, 0, sizeof(mesh->fdata));
+ /* cache only - don't write */
+ mesh->mface = NULL;
+ mesh->totface = 0;
+ memset(&mesh->fdata, 0, sizeof(mesh->fdata));
#endif /* USE_BMESH_SAVE_WITHOUT_MFACE */
- /**
- * Those calls:
- * - Reduce mesh->xdata.totlayer to number of layers to write.
- * - Fill xlayers with those layers to be written.
- * Note that mesh->xdata is from now on invalid for Blender, but this is why the whole mesh is
- * a temp local copy!
- */
- CustomData_file_write_prepare(&mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff));
- CustomData_file_write_prepare(&mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff));
+ /**
+ * Those calls:
+ * - Reduce mesh->xdata.totlayer to number of layers to write.
+ * - Fill xlayers with those layers to be written.
+ * Note that mesh->xdata is from now on invalid for Blender, but this is why the whole mesh is
+ * a temp local copy!
+ */
+ CustomData_file_write_prepare(&mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff));
+ CustomData_file_write_prepare(&mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff));
#ifndef USE_BMESH_SAVE_WITHOUT_MFACE /* Do not copy org fdata in this case!!! */
- CustomData_file_write_prepare(&mesh->fdata, &flayers, flayers_buff, ARRAY_SIZE(flayers_buff));
+ CustomData_file_write_prepare(&mesh->fdata, &flayers, flayers_buff, ARRAY_SIZE(flayers_buff));
#else
- flayers = flayers_buff;
+ flayers = flayers_buff;
#endif
- CustomData_file_write_prepare(&mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff));
- CustomData_file_write_prepare(&mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
+ CustomData_file_write_prepare(&mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff));
+ CustomData_file_write_prepare(&mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
- writestruct_at_address(wd, ID_ME, Mesh, 1, old_mesh, mesh);
- write_iddata(wd, &mesh->id);
+ writestruct_at_address(wd, ID_ME, Mesh, 1, old_mesh, mesh);
+ write_iddata(wd, &mesh->id);
- /* direct data */
- if (mesh->adt) {
- write_animdata(wd, mesh->adt);
- }
+ /* direct data */
+ if (mesh->adt) {
+ write_animdata(wd, mesh->adt);
+ }
- writedata(wd, DATA, sizeof(void *) * mesh->totcol, mesh->mat);
- writedata(wd, DATA, sizeof(MSelect) * mesh->totselect, mesh->mselect);
+ writedata(wd, DATA, sizeof(void *) * mesh->totcol, mesh->mat);
+ writedata(wd, DATA, sizeof(MSelect) * mesh->totselect, mesh->mselect);
- write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, vlayers, -1, 0);
- write_customdata(wd, &mesh->id, mesh->totedge, &mesh->edata, elayers, -1, 0);
- /* fdata is really a dummy - written so slots align */
- write_customdata(wd, &mesh->id, mesh->totface, &mesh->fdata, flayers, -1, 0);
- write_customdata(wd, &mesh->id, mesh->totloop, &mesh->ldata, llayers, -1, 0);
- write_customdata(wd, &mesh->id, mesh->totpoly, &mesh->pdata, players, -1, 0);
+ write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, vlayers, -1, 0);
+ write_customdata(wd, &mesh->id, mesh->totedge, &mesh->edata, elayers, -1, 0);
+ /* fdata is really a dummy - written so slots align */
+ write_customdata(wd, &mesh->id, mesh->totface, &mesh->fdata, flayers, -1, 0);
+ write_customdata(wd, &mesh->id, mesh->totloop, &mesh->ldata, llayers, -1, 0);
+ write_customdata(wd, &mesh->id, mesh->totpoly, &mesh->pdata, players, -1, 0);
- /* restore pointer */
- mesh = old_mesh;
- }
- else {
+ /* restore pointer */
+ mesh = old_mesh;
+ }
+ else {
#ifdef USE_BMESH_SAVE_AS_COMPAT
- /* write a copy of the mesh, don't modify in place because it is
- * not thread safe for threaded renders that are reading this */
- Mesh *old_mesh = mesh;
- Mesh copy_mesh = *mesh;
- mesh = &copy_mesh;
-
- mesh->mpoly = NULL;
- mesh->mface = NULL;
- mesh->totface = 0;
- mesh->totpoly = 0;
- mesh->totloop = 0;
- CustomData_reset(&mesh->fdata);
- CustomData_reset(&mesh->pdata);
- CustomData_reset(&mesh->ldata);
- mesh->edit_btmesh = NULL;
+ /* write a copy of the mesh, don't modify in place because it is
+ * not thread safe for threaded renders that are reading this */
+ Mesh *old_mesh = mesh;
+ Mesh copy_mesh = *mesh;
+ mesh = &copy_mesh;
+
+ mesh->mpoly = NULL;
+ mesh->mface = NULL;
+ mesh->totface = 0;
+ mesh->totpoly = 0;
+ mesh->totloop = 0;
+ CustomData_reset(&mesh->fdata);
+ CustomData_reset(&mesh->pdata);
+ CustomData_reset(&mesh->ldata);
+ mesh->edit_btmesh = NULL;
mesh->edit_strands = NULL;
- /* now fill in polys to mfaces */
- /* XXX This breaks writing design, by using temp allocated memory, which will likely generate
- * duplicates in stored 'old' addresses.
- * This is very bad, but do not see easy way to avoid this, aside from generating those data
- * outside of save process itself.
- * Maybe we can live with this, though?
- */
- mesh->totface = BKE_mesh_mpoly_to_mface(&mesh->fdata, &old_mesh->ldata, &old_mesh->pdata,
- mesh->totface, old_mesh->totloop, old_mesh->totpoly);
+ /* now fill in polys to mfaces */
+ /* XXX This breaks writing design, by using temp allocated memory, which will likely generate
+ * duplicates in stored 'old' addresses.
+ * This is very bad, but do not see easy way to avoid this, aside from generating those data
+ * outside of save process itself.
+ * Maybe we can live with this, though?
+ */
+ mesh->totface = BKE_mesh_mpoly_to_mface(
+ &mesh->fdata, &old_mesh->ldata, &old_mesh->pdata,
+ mesh->totface, old_mesh->totloop, old_mesh->totpoly);
- BKE_mesh_update_customdata_pointers(mesh, false);
+ BKE_mesh_update_customdata_pointers(mesh, false);
- CustomData_file_write_prepare(&mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff));
- CustomData_file_write_prepare(&mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff));
- CustomData_file_write_prepare(&mesh->fdata, &flayers, flayers_buff, ARRAY_SIZE(flayers_buff));
+ CustomData_file_write_prepare(&mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff));
+ CustomData_file_write_prepare(&mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff));
+ CustomData_file_write_prepare(&mesh->fdata, &flayers, flayers_buff, ARRAY_SIZE(flayers_buff));
#if 0
- CustomData_file_write_prepare(&mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff));
- CustomData_file_write_prepare(&mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
+ CustomData_file_write_prepare(&mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff));
+ CustomData_file_write_prepare(&mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
#endif
- writestruct_at_address(wd, ID_ME, Mesh, 1, old_mesh, mesh);
- write_iddata(wd, &mesh->id);
+ writestruct_at_address(wd, ID_ME, Mesh, 1, old_mesh, mesh);
+ write_iddata(wd, &mesh->id);
- /* direct data */
- if (mesh->adt) {
- write_animdata(wd, mesh->adt);
- }
+ /* direct data */
+ if (mesh->adt) {
+ write_animdata(wd, mesh->adt);
+ }
- writedata(wd, DATA, sizeof(void *) * mesh->totcol, mesh->mat);
- /* writedata(wd, DATA, sizeof(MSelect) * mesh->totselect, mesh->mselect); */ /* pre-bmesh NULL's */
+ writedata(wd, DATA, sizeof(void *) * mesh->totcol, mesh->mat);
+ /* writedata(wd, DATA, sizeof(MSelect) * mesh->totselect, mesh->mselect); */ /* pre-bmesh NULL's */
- write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, vlayers, -1, 0);
- write_customdata(wd, &mesh->id, mesh->totedge, &mesh->edata, elayers, -1, 0);
- write_customdata(wd, &mesh->id, mesh->totface, &mesh->fdata, flayers, -1, 0);
- /* harmless for older blender versioins but _not_ writing these keeps file size down */
+ write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, vlayers, -1, 0);
+ write_customdata(wd, &mesh->id, mesh->totedge, &mesh->edata, elayers, -1, 0);
+ write_customdata(wd, &mesh->id, mesh->totface, &mesh->fdata, flayers, -1, 0);
+ /* harmless for older blender versioins but _not_ writing these keeps file size down */
#if 0
- write_customdata(wd, &mesh->id, mesh->totloop, &mesh->ldata, llayers, -1, 0);
- write_customdata(wd, &mesh->id, mesh->totpoly, &mesh->pdata, players, -1, 0);
+ write_customdata(wd, &mesh->id, mesh->totloop, &mesh->ldata, llayers, -1, 0);
+ write_customdata(wd, &mesh->id, mesh->totpoly, &mesh->pdata, players, -1, 0);
#endif
- CustomData_free(&mesh->fdata, mesh->totface);
- flayers = NULL;
+ CustomData_free(&mesh->fdata, mesh->totface);
+ flayers = NULL;
- /* restore pointer */
- mesh = old_mesh;
+ /* restore pointer */
+ mesh = old_mesh;
#endif /* USE_BMESH_SAVE_AS_COMPAT */
- }
- }
-
- if (vlayers && vlayers != vlayers_buff) {
- MEM_freeN(vlayers);
}
- if (elayers && elayers != elayers_buff) {
- MEM_freeN(elayers);
- }
- if (flayers && flayers != flayers_buff) {
- MEM_freeN(flayers);
- }
- if (llayers && llayers != llayers_buff) {
- MEM_freeN(llayers);
- }
- if (players && players != players_buff) {
- MEM_freeN(players);
- }
-
- mesh = mesh->id.next;
}
- mywrite_flush(wd);
+ if (vlayers && vlayers != vlayers_buff) {
+ MEM_freeN(vlayers);
+ }
+ if (elayers && elayers != elayers_buff) {
+ MEM_freeN(elayers);
+ }
+ if (flayers && flayers != flayers_buff) {
+ MEM_freeN(flayers);
+ }
+ if (llayers && llayers != llayers_buff) {
+ MEM_freeN(llayers);
+ }
+ if (players && players != players_buff) {
+ MEM_freeN(players);
+ }
}
-static void write_lattices(WriteData *wd, ListBase *idbase)
+static void write_lattice(WriteData *wd, Lattice *lt)
{
- Lattice *lt;
-
- lt = idbase->first;
- while (lt) {
- if (lt->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_LT, Lattice, 1, lt);
- write_iddata(wd, &lt->id);
-
- /* write animdata */
- if (lt->adt) {
- write_animdata(wd, lt->adt);
- }
+ if (lt->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_LT, Lattice, 1, lt);
+ write_iddata(wd, &lt->id);
- /* direct data */
- writestruct(wd, DATA, BPoint, lt->pntsu * lt->pntsv * lt->pntsw, lt->def);
+ /* write animdata */
+ if (lt->adt) {
+ write_animdata(wd, lt->adt);
+ }
- write_dverts(wd, lt->pntsu * lt->pntsv * lt->pntsw, lt->dvert);
+ /* direct data */
+ writestruct(wd, DATA, BPoint, lt->pntsu * lt->pntsv * lt->pntsw, lt->def);
- }
- lt = lt->id.next;
+ write_dverts(wd, lt->pntsu * lt->pntsv * lt->pntsw, lt->dvert);
}
-
- mywrite_flush(wd);
}
-static void write_images(WriteData *wd, ListBase *idbase)
+static void write_image(WriteData *wd, Image *ima)
{
- Image *ima;
- PackedFile *pf;
- ImageView *iv;
- ImagePackedFile *imapf;
-
- ima = idbase->first;
- while (ima) {
- if (ima->id.us > 0 || wd->current) {
- /* Some trickery to keep forward compatibility of packed images. */
- BLI_assert(ima->packedfile == NULL);
- if (ima->packedfiles.first != NULL) {
- imapf = ima->packedfiles.first;
- ima->packedfile = imapf->packedfile;
- }
+ if (ima->id.us > 0 || wd->current) {
+ ImagePackedFile *imapf;
- /* write LibData */
- writestruct(wd, ID_IM, Image, 1, ima);
- write_iddata(wd, &ima->id);
-
- for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) {
- writestruct(wd, DATA, ImagePackedFile, 1, imapf);
- if (imapf->packedfile) {
- pf = imapf->packedfile;
- writestruct(wd, DATA, PackedFile, 1, pf);
- writedata(wd, DATA, pf->size, pf->data);
- }
- }
+ /* Some trickery to keep forward compatibility of packed images. */
+ BLI_assert(ima->packedfile == NULL);
+ if (ima->packedfiles.first != NULL) {
+ imapf = ima->packedfiles.first;
+ ima->packedfile = imapf->packedfile;
+ }
- write_previews(wd, ima->preview);
+ /* write LibData */
+ writestruct(wd, ID_IM, Image, 1, ima);
+ write_iddata(wd, &ima->id);
- for (iv = ima->views.first; iv; iv = iv->next) {
- writestruct(wd, DATA, ImageView, 1, iv);
+ for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) {
+ writestruct(wd, DATA, ImagePackedFile, 1, imapf);
+ if (imapf->packedfile) {
+ PackedFile *pf = imapf->packedfile;
+ writestruct(wd, DATA, PackedFile, 1, pf);
+ writedata(wd, DATA, pf->size, pf->data);
}
- writestruct(wd, DATA, Stereo3dFormat, 1, ima->stereo3d_format);
+ }
- ima->packedfile = NULL;
+ write_previews(wd, ima->preview);
+
+ for (ImageView *iv = ima->views.first; iv; iv = iv->next) {
+ writestruct(wd, DATA, ImageView, 1, iv);
}
- ima = ima->id.next;
- }
+ writestruct(wd, DATA, Stereo3dFormat, 1, ima->stereo3d_format);
- mywrite_flush(wd);
+ ima->packedfile = NULL;
+ }
}
-static void write_textures(WriteData *wd, ListBase *idbase)
+static void write_texture(WriteData *wd, Tex *tex)
{
- Tex *tex;
-
- tex = idbase->first;
- while (tex) {
- if (tex->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_TE, Tex, 1, tex);
- write_iddata(wd, &tex->id);
+ if (tex->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_TE, Tex, 1, tex);
+ write_iddata(wd, &tex->id);
- if (tex->adt) {
- write_animdata(wd, tex->adt);
- }
+ if (tex->adt) {
+ write_animdata(wd, tex->adt);
+ }
- /* direct data */
- 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);
+ /* direct data */
+ 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);
}
-
- /* nodetree is integral part of texture, no libdata */
- if (tex->nodetree) {
- writestruct(wd, DATA, bNodeTree, 1, tex->nodetree);
- write_nodetree(wd, tex->nodetree);
+ 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);
+ }
- write_previews(wd, tex->preview);
+ /* nodetree is integral part of texture, no libdata */
+ if (tex->nodetree) {
+ writestruct(wd, DATA, bNodeTree, 1, tex->nodetree);
+ write_nodetree_nolib(wd, tex->nodetree);
}
- tex = tex->id.next;
- }
- mywrite_flush(wd);
+ write_previews(wd, tex->preview);
+ }
}
-static void write_materials(WriteData *wd, ListBase *idbase)
+static void write_material(WriteData *wd, Material *ma)
{
- Material *ma;
- int a;
-
- ma = idbase->first;
- while (ma) {
- if (ma->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_MA, Material, 1, ma);
- write_iddata(wd, &ma->id);
-
- if (ma->adt) {
- write_animdata(wd, ma->adt);
- }
+ if (ma->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_MA, Material, 1, ma);
+ write_iddata(wd, &ma->id);
- for (a = 0; a < MAX_MTEX; a++) {
- if (ma->mtex[a]) {
- writestruct(wd, DATA, MTex, 1, ma->mtex[a]);
- }
- }
+ if (ma->adt) {
+ write_animdata(wd, ma->adt);
+ }
- if (ma->ramp_col) {
- writestruct(wd, DATA, ColorBand, 1, ma->ramp_col);
- }
- if (ma->ramp_spec) {
- writestruct(wd, DATA, ColorBand, 1, ma->ramp_spec);
+ for (int a = 0; a < MAX_MTEX; a++) {
+ if (ma->mtex[a]) {
+ writestruct(wd, DATA, MTex, 1, ma->mtex[a]);
}
+ }
- /* nodetree is integral part of material, no libdata */
- if (ma->nodetree) {
- writestruct(wd, DATA, bNodeTree, 1, ma->nodetree);
- write_nodetree(wd, ma->nodetree);
- }
+ if (ma->ramp_col) {
+ writestruct(wd, DATA, ColorBand, 1, ma->ramp_col);
+ }
+ if (ma->ramp_spec) {
+ writestruct(wd, DATA, ColorBand, 1, ma->ramp_spec);
+ }
- write_previews(wd, ma->preview);
+ /* nodetree is integral part of material, no libdata */
+ if (ma->nodetree) {
+ writestruct(wd, DATA, bNodeTree, 1, ma->nodetree);
+ write_nodetree_nolib(wd, ma->nodetree);
}
- ma = ma->id.next;
+
+ write_previews(wd, ma->preview);
}
}
-static void write_worlds(WriteData *wd, ListBase *idbase)
+static void write_world(WriteData *wd, World *wrld)
{
- World *wrld;
- int a;
-
- wrld = idbase->first;
- while (wrld) {
- if (wrld->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_WO, World, 1, wrld);
- write_iddata(wd, &wrld->id);
-
- if (wrld->adt) {
- write_animdata(wd, wrld->adt);
- }
+ if (wrld->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_WO, World, 1, wrld);
+ write_iddata(wd, &wrld->id);
- for (a = 0; a < MAX_MTEX; a++) {
- if (wrld->mtex[a]) {
- writestruct(wd, DATA, MTex, 1, wrld->mtex[a]);
- }
- }
+ if (wrld->adt) {
+ write_animdata(wd, wrld->adt);
+ }
- /* nodetree is integral part of world, no libdata */
- if (wrld->nodetree) {
- writestruct(wd, DATA, bNodeTree, 1, wrld->nodetree);
- write_nodetree(wd, wrld->nodetree);
+ for (int a = 0; a < MAX_MTEX; a++) {
+ if (wrld->mtex[a]) {
+ writestruct(wd, DATA, MTex, 1, wrld->mtex[a]);
}
+ }
- write_previews(wd, wrld->preview);
+ /* nodetree is integral part of world, no libdata */
+ if (wrld->nodetree) {
+ writestruct(wd, DATA, bNodeTree, 1, wrld->nodetree);
+ write_nodetree_nolib(wd, wrld->nodetree);
}
- wrld = wrld->id.next;
+
+ write_previews(wd, wrld->preview);
}
}
-static void write_lamps(WriteData *wd, ListBase *idbase)
+static void write_lamp(WriteData *wd, Lamp *la)
{
- Lamp *la;
- int a;
-
- la = idbase->first;
- while (la) {
- if (la->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_LA, Lamp, 1, la);
- write_iddata(wd, &la->id);
-
- if (la->adt) {
- write_animdata(wd, la->adt);
- }
-
- /* direct data */
- for (a = 0; a < MAX_MTEX; a++) {
- if (la->mtex[a]) {
- writestruct(wd, DATA, MTex, 1, la->mtex[a]);
- }
- }
+ if (la->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_LA, Lamp, 1, la);
+ write_iddata(wd, &la->id);
- if (la->curfalloff) {
- write_curvemapping(wd, la->curfalloff);
- }
+ if (la->adt) {
+ write_animdata(wd, la->adt);
+ }
- /* nodetree is integral part of lamps, no libdata */
- if (la->nodetree) {
- writestruct(wd, DATA, bNodeTree, 1, la->nodetree);
- write_nodetree(wd, la->nodetree);
+ /* direct data */
+ for (int a = 0; a < MAX_MTEX; a++) {
+ if (la->mtex[a]) {
+ writestruct(wd, DATA, MTex, 1, la->mtex[a]);
}
+ }
- write_previews(wd, la->preview);
+ if (la->curfalloff) {
+ write_curvemapping(wd, la->curfalloff);
+ }
+ /* nodetree is integral part of lamps, no libdata */
+ if (la->nodetree) {
+ writestruct(wd, DATA, bNodeTree, 1, la->nodetree);
+ write_nodetree_nolib(wd, la->nodetree);
}
- la = la->id.next;
- }
- mywrite_flush(wd);
+ write_previews(wd, la->preview);
+ }
}
static void write_sequence_modifiers(WriteData *wd, ListBase *modbase)
@@ -2623,290 +2561,308 @@ static void write_paint(WriteData *wd, Paint *p)
}
}
-static void write_scenes(WriteData *wd, ListBase *scebase)
+static void write_scene_collection(WriteData *wd, SceneCollection *sc)
{
- Scene *sce;
- Base *base;
- Editing *ed;
- Sequence *seq;
- MetaStack *ms;
- Strip *strip;
- TimeMarker *marker;
- TransformOrientation *ts;
- SceneRenderLayer *srl;
- SceneRenderView *srv;
- ToolSettings *tos;
- FreestyleModuleConfig *fmc;
- FreestyleLineSet *fls;
-
- sce = scebase->first;
- while (sce) {
- /* write LibData */
- writestruct(wd, ID_SCE, Scene, 1, sce);
- write_iddata(wd, &sce->id);
+ writestruct(wd, DATA, SceneCollection, 1, sc);
+
+ writelist(wd, DATA, LinkData, &sc->objects);
+ writelist(wd, DATA, LinkData, &sc->filter_objects);
+
+ for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
+ write_scene_collection(wd, nsc);
+ }
+}
+
+static void write_layer_collections(WriteData *wd, ListBase *lb)
+{
+ for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ writestruct(wd, DATA, LayerCollection, 1, lc);
- if (sce->adt) {
- write_animdata(wd, sce->adt);
+ writelist(wd, DATA, LinkData, &lc->object_bases);
+ writelist(wd, DATA, CollectionOverride, &lc->overrides);
+
+ if (lc->properties) {
+ IDP_WriteProperty(lc->properties, wd);
}
- write_keyingsets(wd, &sce->keyingsets);
- /* direct data */
- base = sce->base.first;
- while (base) {
- writestruct(wd, DATA, Base, 1, base);
- base = base->next;
- }
-
- tos = sce->toolsettings;
- writestruct(wd, DATA, ToolSettings, 1, tos);
- if (tos->vpaint) {
- writestruct(wd, DATA, VPaint, 1, tos->vpaint);
- write_paint(wd, &tos->vpaint->paint);
- }
- if (tos->wpaint) {
- writestruct(wd, DATA, VPaint, 1, tos->wpaint);
- write_paint(wd, &tos->wpaint->paint);
- }
- if (tos->sculpt) {
- writestruct(wd, DATA, Sculpt, 1, tos->sculpt);
- write_paint(wd, &tos->sculpt->paint);
- }
- if (tos->uvsculpt) {
- writestruct(wd, DATA, UvSculpt, 1, tos->uvsculpt);
- write_paint(wd, &tos->uvsculpt->paint);
- }
- /* write grease-pencil drawing brushes to file */
- writelist(wd, DATA, bGPDbrush, &tos->gp_brushes);
- for (bGPDbrush *brush = tos->gp_brushes.first; brush; brush = brush->next) {
- if (brush->cur_sensitivity) {
- write_curvemapping(wd, brush->cur_sensitivity);
- }
- if (brush->cur_strength) {
- write_curvemapping(wd, brush->cur_strength);
- }
- if (brush->cur_jitter) {
- write_curvemapping(wd, brush->cur_jitter);
- }
+ write_layer_collections(wd, &lc->layer_collections);
+ }
+}
+
+static void write_scene(WriteData *wd, Scene *sce)
+{
+ /* write LibData */
+ writestruct(wd, ID_SCE, Scene, 1, sce);
+ write_iddata(wd, &sce->id);
+
+ if (sce->adt) {
+ write_animdata(wd, sce->adt);
+ }
+ write_keyingsets(wd, &sce->keyingsets);
+
+ /* direct data */
+ for (BaseLegacy *base = sce->base.first; base; base = base->next) {
+ writestruct(wd, DATA, BaseLegacy, 1, base);
+ }
+
+ ToolSettings *tos = sce->toolsettings;
+ writestruct(wd, DATA, ToolSettings, 1, tos);
+ if (tos->vpaint) {
+ writestruct(wd, DATA, VPaint, 1, tos->vpaint);
+ write_paint(wd, &tos->vpaint->paint);
+ }
+ if (tos->wpaint) {
+ writestruct(wd, DATA, VPaint, 1, tos->wpaint);
+ write_paint(wd, &tos->wpaint->paint);
+ }
+ if (tos->sculpt) {
+ writestruct(wd, DATA, Sculpt, 1, tos->sculpt);
+ write_paint(wd, &tos->sculpt->paint);
+ }
+ if (tos->uvsculpt) {
+ writestruct(wd, DATA, UvSculpt, 1, tos->uvsculpt);
+ write_paint(wd, &tos->uvsculpt->paint);
+ }
+ /* write grease-pencil drawing brushes to file */
+ writelist(wd, DATA, bGPDbrush, &tos->gp_brushes);
+ for (bGPDbrush *brush = tos->gp_brushes.first; brush; brush = brush->next) {
+ if (brush->cur_sensitivity) {
+ write_curvemapping(wd, brush->cur_sensitivity);
+ }
+ if (brush->cur_strength) {
+ write_curvemapping(wd, brush->cur_strength);
}
-
+ if (brush->cur_jitter) {
+ write_curvemapping(wd, brush->cur_jitter);
+ }
+ }
+ /* write grease-pencil custom ipo curve to file */
+ if (tos->gp_interpolate.custom_ipo) {
+ write_curvemapping(wd, tos->gp_interpolate.custom_ipo);
+ }
- write_paint(wd, &tos->imapaint.paint);
- ed = sce->ed;
- if (ed) {
- writestruct(wd, DATA, Editing, 1, ed);
+ write_paint(wd, &tos->imapaint.paint);
- /* reset write flags too */
+ Editing *ed = sce->ed;
+ if (ed) {
+ Sequence *seq;
- SEQ_BEGIN(ed, seq)
- {
- if (seq->strip) {
- seq->strip->done = false;
- }
- writestruct(wd, DATA, Sequence, 1, seq);
- }
- SEQ_END
+ writestruct(wd, DATA, Editing, 1, ed);
- SEQ_BEGIN(ed, seq)
- {
- if (seq->strip && seq->strip->done == 0) {
- /* write strip with 'done' at 0 because readfile */
-
- if (seq->effectdata) {
- switch (seq->type) {
- case SEQ_TYPE_COLOR:
- writestruct(wd, DATA, SolidColorVars, 1, seq->effectdata);
- break;
- case SEQ_TYPE_SPEED:
- writestruct(wd, DATA, SpeedControlVars, 1, seq->effectdata);
- break;
- case SEQ_TYPE_WIPE:
- writestruct(wd, DATA, WipeVars, 1, seq->effectdata);
- break;
- case SEQ_TYPE_GLOW:
- writestruct(wd, DATA, GlowVars, 1, seq->effectdata);
- break;
- case SEQ_TYPE_TRANSFORM:
- writestruct(wd, DATA, TransformVars, 1, seq->effectdata);
- break;
- case SEQ_TYPE_GAUSSIAN_BLUR:
- writestruct(wd, DATA, GaussianBlurVars, 1, seq->effectdata);
- break;
- case SEQ_TYPE_TEXT:
- writestruct(wd, DATA, TextVars, 1, seq->effectdata);
- break;
- }
- }
+ /* reset write flags too */
- writestruct(wd, DATA, Stereo3dFormat, 1, seq->stereo3d_format);
+ SEQ_BEGIN(ed, seq)
+ {
+ if (seq->strip) {
+ seq->strip->done = false;
+ }
+ writestruct(wd, DATA, Sequence, 1, seq);
+ }
+ SEQ_END
- strip = seq->strip;
- writestruct(wd, DATA, Strip, 1, strip);
- if (seq->flag & SEQ_USE_CROP && strip->crop) {
- writestruct(wd, DATA, StripCrop, 1, strip->crop);
- }
- if (seq->flag & SEQ_USE_TRANSFORM && strip->transform) {
- writestruct(wd, DATA, StripTransform, 1, strip->transform);
- }
- if (seq->flag & SEQ_USE_PROXY && strip->proxy) {
- writestruct(wd, DATA, StripProxy, 1, strip->proxy);
- }
- if (seq->type == SEQ_TYPE_IMAGE) {
- writestruct(wd, DATA, StripElem,
- MEM_allocN_len(strip->stripdata) / sizeof(struct StripElem),
- strip->stripdata);
- }
- else if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) {
- writestruct(wd, DATA, StripElem, 1, strip->stripdata);
+ SEQ_BEGIN(ed, seq)
+ {
+ if (seq->strip && seq->strip->done == 0) {
+ /* write strip with 'done' at 0 because readfile */
+
+ if (seq->effectdata) {
+ switch (seq->type) {
+ case SEQ_TYPE_COLOR:
+ writestruct(wd, DATA, SolidColorVars, 1, seq->effectdata);
+ break;
+ case SEQ_TYPE_SPEED:
+ writestruct(wd, DATA, SpeedControlVars, 1, seq->effectdata);
+ break;
+ case SEQ_TYPE_WIPE:
+ writestruct(wd, DATA, WipeVars, 1, seq->effectdata);
+ break;
+ case SEQ_TYPE_GLOW:
+ writestruct(wd, DATA, GlowVars, 1, seq->effectdata);
+ break;
+ case SEQ_TYPE_TRANSFORM:
+ writestruct(wd, DATA, TransformVars, 1, seq->effectdata);
+ break;
+ case SEQ_TYPE_GAUSSIAN_BLUR:
+ writestruct(wd, DATA, GaussianBlurVars, 1, seq->effectdata);
+ break;
+ case SEQ_TYPE_TEXT:
+ writestruct(wd, DATA, TextVars, 1, seq->effectdata);
+ break;
}
-
- strip->done = true;
}
- if (seq->prop) {
- IDP_WriteProperty(seq->prop, wd);
+ writestruct(wd, DATA, Stereo3dFormat, 1, seq->stereo3d_format);
+
+ Strip *strip = seq->strip;
+ writestruct(wd, DATA, Strip, 1, strip);
+ if (seq->flag & SEQ_USE_CROP && strip->crop) {
+ writestruct(wd, DATA, StripCrop, 1, strip->crop);
+ }
+ if (seq->flag & SEQ_USE_TRANSFORM && strip->transform) {
+ writestruct(wd, DATA, StripTransform, 1, strip->transform);
+ }
+ if (seq->flag & SEQ_USE_PROXY && strip->proxy) {
+ writestruct(wd, DATA, StripProxy, 1, strip->proxy);
+ }
+ if (seq->type == SEQ_TYPE_IMAGE) {
+ writestruct(wd, DATA, StripElem,
+ MEM_allocN_len(strip->stripdata) / sizeof(struct StripElem),
+ strip->stripdata);
+ }
+ else if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) {
+ writestruct(wd, DATA, StripElem, 1, strip->stripdata);
}
- write_sequence_modifiers(wd, &seq->modifiers);
+ strip->done = true;
}
- SEQ_END
- /* new; meta stack too, even when its nasty restore code */
- for (ms = ed->metastack.first; ms; ms = ms->next) {
- writestruct(wd, DATA, MetaStack, 1, ms);
+ if (seq->prop) {
+ IDP_WriteProperty(seq->prop, wd);
}
+
+ write_sequence_modifiers(wd, &seq->modifiers);
}
+ SEQ_END
- if (sce->r.avicodecdata) {
- writestruct(wd, DATA, AviCodecData, 1, sce->r.avicodecdata);
- if (sce->r.avicodecdata->lpFormat) {
- writedata(wd, DATA, sce->r.avicodecdata->cbFormat, sce->r.avicodecdata->lpFormat);
- }
- if (sce->r.avicodecdata->lpParms) {
- writedata(wd, DATA, sce->r.avicodecdata->cbParms, sce->r.avicodecdata->lpParms);
- }
+ /* new; meta stack too, even when its nasty restore code */
+ for (MetaStack *ms = ed->metastack.first; ms; ms = ms->next) {
+ writestruct(wd, DATA, MetaStack, 1, ms);
}
+ }
- if (sce->r.qtcodecdata) {
- writestruct(wd, DATA, QuicktimeCodecData, 1, sce->r.qtcodecdata);
- if (sce->r.qtcodecdata->cdParms) {
- writedata(wd, DATA, sce->r.qtcodecdata->cdSize, sce->r.qtcodecdata->cdParms);
- }
+ if (sce->r.avicodecdata) {
+ writestruct(wd, DATA, AviCodecData, 1, sce->r.avicodecdata);
+ if (sce->r.avicodecdata->lpFormat) {
+ writedata(wd, DATA, sce->r.avicodecdata->cbFormat, sce->r.avicodecdata->lpFormat);
}
- if (sce->r.ffcodecdata.properties) {
- IDP_WriteProperty(sce->r.ffcodecdata.properties, wd);
+ if (sce->r.avicodecdata->lpParms) {
+ writedata(wd, DATA, sce->r.avicodecdata->cbParms, sce->r.avicodecdata->lpParms);
}
+ }
- /* writing dynamic list of TimeMarkers to the blend file */
- for (marker = sce->markers.first; marker; marker = marker->next) {
- writestruct(wd, DATA, TimeMarker, 1, marker);
+ if (sce->r.qtcodecdata) {
+ writestruct(wd, DATA, QuicktimeCodecData, 1, sce->r.qtcodecdata);
+ if (sce->r.qtcodecdata->cdParms) {
+ writedata(wd, DATA, sce->r.qtcodecdata->cdSize, sce->r.qtcodecdata->cdParms);
}
+ }
+ if (sce->r.ffcodecdata.properties) {
+ IDP_WriteProperty(sce->r.ffcodecdata.properties, wd);
+ }
- /* writing dynamic list of TransformOrientations to the blend file */
- for (ts = sce->transform_spaces.first; ts; ts = ts->next) {
- writestruct(wd, DATA, TransformOrientation, 1, ts);
- }
+ /* writing dynamic list of TimeMarkers to the blend file */
+ for (TimeMarker *marker = sce->markers.first; marker; marker = marker->next) {
+ writestruct(wd, DATA, TimeMarker, 1, marker);
+ }
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
- writestruct(wd, DATA, SceneRenderLayer, 1, srl);
- for (fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
- writestruct(wd, DATA, FreestyleModuleConfig, 1, fmc);
- }
- for (fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
- writestruct(wd, DATA, FreestyleLineSet, 1, fls);
- }
+ 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);
}
-
- /* writing MultiView to the blend file */
- for (srv = sce->r.views.first; srv; srv = srv->next) {
- writestruct(wd, DATA, SceneRenderView, 1, srv);
+ for (FreestyleModuleConfig *fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
+ writestruct(wd, DATA, FreestyleModuleConfig, 1, fmc);
}
-
- if (sce->nodetree) {
- writestruct(wd, DATA, bNodeTree, 1, sce->nodetree);
- write_nodetree(wd, sce->nodetree);
+ for (FreestyleLineSet *fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
+ writestruct(wd, DATA, FreestyleLineSet, 1, fls);
}
+ }
- write_view_settings(wd, &sce->view_settings);
+ /* writing MultiView to the blend file */
+ for (SceneRenderView *srv = sce->r.views.first; srv; srv = srv->next) {
+ writestruct(wd, DATA, SceneRenderView, 1, srv);
+ }
- /* writing RigidBodyWorld data to the blend file */
- if (sce->rigidbody_world) {
- writestruct(wd, DATA, RigidBodyWorld, 1, sce->rigidbody_world);
- writestruct(wd, DATA, EffectorWeights, 1, sce->rigidbody_world->effector_weights);
- write_pointcaches(wd, &(sce->rigidbody_world->ptcaches));
- }
+ if (sce->nodetree) {
+ writestruct(wd, DATA, bNodeTree, 1, sce->nodetree);
+ write_nodetree_nolib(wd, sce->nodetree);
+ }
- write_previews(wd, sce->preview);
- write_curvemapping_curves(wd, &sce->r.mblur_shutter_curve);
+ write_view_settings(wd, &sce->view_settings);
- sce = sce->id.next;
+ /* writing RigidBodyWorld data to the blend file */
+ if (sce->rigidbody_world) {
+ writestruct(wd, DATA, RigidBodyWorld, 1, sce->rigidbody_world);
+ writestruct(wd, DATA, EffectorWeights, 1, sce->rigidbody_world->effector_weights);
+ write_pointcaches(wd, &(sce->rigidbody_world->ptcaches));
}
- mywrite_flush(wd);
-}
+ write_previews(wd, sce->preview);
+ write_curvemapping_curves(wd, &sce->r.mblur_shutter_curve);
+ write_scene_collection(wd, sce->collection);
-static void write_gpencils(WriteData *wd, ListBase *lb)
-{
- bGPdata *gpd;
- bGPDlayer *gpl;
- bGPDframe *gpf;
- bGPDstroke *gps;
- bGPDpalette *palette;
-
- for (gpd = lb->first; gpd; gpd = gpd->id.next) {
- if (gpd->id.us > 0 || wd->current) {
- /* write gpd data block to file */
- writestruct(wd, ID_GD, bGPdata, 1, gpd);
- write_iddata(wd, &gpd->id);
-
- if (gpd->adt) {
- write_animdata(wd, gpd->adt);
- }
+ for (SceneLayer *sl = sce->render_layers.first; sl; sl = sl->next) {
+ writestruct(wd, DATA, SceneLayer, 1, sl);
+ writelist(wd, DATA, Base, &sl->object_bases);
+ if (sl->properties) {
+ IDP_WriteProperty(sl->properties, wd);
+ }
+ write_layer_collections(wd, &sl->layer_collections);
+ }
- /* write grease-pencil layers to file */
- writelist(wd, DATA, bGPDlayer, &gpd->layers);
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (sce->layer_properties) {
+ IDP_WriteProperty(sce->layer_properties, wd);
+ }
- /* write this layer's frames to file */
- writelist(wd, DATA, bGPDframe, &gpl->frames);
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if (sce->collection_properties) {
+ IDP_WriteProperty(sce->collection_properties, wd);
+ }
+}
- /* write strokes */
- writelist(wd, DATA, bGPDstroke, &gpf->strokes);
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- writestruct(wd, DATA, bGPDspoint, gps->totpoints, gps->points);
- }
+static void write_gpencil(WriteData *wd, bGPdata *gpd)
+{
+ if (gpd->id.us > 0 || wd->current) {
+ /* write gpd data block to file */
+ writestruct(wd, ID_GD, bGPdata, 1, gpd);
+ write_iddata(wd, &gpd->id);
+
+ if (gpd->adt) {
+ write_animdata(wd, gpd->adt);
+ }
+
+ /* write grease-pencil layers to file */
+ writelist(wd, DATA, bGPDlayer, &gpd->layers);
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* write this layer's frames to file */
+ writelist(wd, DATA, bGPDframe, &gpl->frames);
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* write strokes */
+ 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 grease-pencil palettes */
- writelist(wd, DATA, bGPDpalette, &gpd->palettes);
- for (palette = gpd->palettes.first; palette; palette = palette->next) {
- writelist(wd, DATA, bGPDpalettecolor, &palette->colors);
- }
}
- }
- mywrite_flush(wd);
+ /* 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_windowmanagers(WriteData *wd, ListBase *lb)
+static void write_windowmanager(WriteData *wd, wmWindowManager *wm)
{
- wmWindowManager *wm;
- wmWindow *win;
+ writestruct(wd, ID_WM, wmWindowManager, 1, wm);
+ write_iddata(wd, &wm->id);
- for (wm = lb->first; wm; wm = wm->id.next) {
- writestruct(wd, ID_WM, wmWindowManager, 1, wm);
- write_iddata(wd, &wm->id);
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
- for (win = wm->windows.first; win; win = win->next) {
- writestruct(wd, DATA, wmWindow, 1, win);
- writestruct(wd, DATA, Stereo3dFormat, 1, win->stereo3d_format);
+ /* update deprecated screen member (for so loading in 2.7x uses the correct screen) */
+ win->screen = BKE_workspace_active_screen_get(win->workspace_hook);
+ if (win->screen) {
+ BLI_strncpy(win->screenname, win->screen->id.name + 2, sizeof(win->screenname));
}
- }
- /* typically flushing wouldn't be needed however this data _always_ changes,
- * so flush here for more efficient undo. */
- mywrite_flush(wd);
+ writestruct(wd, DATA, wmWindow, 1, win);
+ writestruct(wd, DATA, WorkSpaceInstanceHook, 1, win->workspace_hook);
+ writestruct(wd, DATA, Stereo3dFormat, 1, win->stereo3d_format);
+
+ /* data is written, clear deprecated data again */
+ win->screen = NULL;
+ }
}
static void write_region(WriteData *wd, ARegion *ar, int spacetype)
@@ -2989,184 +2945,171 @@ static void write_soops(WriteData *wd, SpaceOops *so)
}
}
-static void write_screens(WriteData *wd, ListBase *scrbase)
+static void write_screen(WriteData *wd, bScreen *sc)
{
- bScreen *sc;
- ScrArea *sa;
- ScrVert *sv;
- ScrEdge *se;
+ /* 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);
- sc = scrbase->first;
- while (sc) {
+ write_previews(wd, sc->preview);
- /* 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 (sv = sc->vertbase.first; sv; sv = sv->next) {
- writestruct(wd, DATA, ScrVert, 1, sv);
- }
-
- for (se = sc->edgebase.first; se; se = se->next) {
- writestruct(wd, DATA, ScrEdge, 1, se);
- }
-
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
- Panel *pa;
- uiList *ui_list;
- uiPreview *ui_preview;
- PanelCategoryStack *pc_act;
- ARegion *ar;
+ /* direct data */
+ for (ScrVert *sv = sc->vertbase.first; sv; sv = sv->next) {
+ writestruct(wd, DATA, ScrVert, 1, sv);
+ }
- writestruct(wd, DATA, ScrArea, 1, sa);
+ for (ScrEdge *se = sc->edgebase.first; se; se = se->next) {
+ writestruct(wd, DATA, ScrEdge, 1, se);
+ }
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- write_region(wd, ar, sa->spacetype);
+ 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 (pa = ar->panels.first; pa; pa = pa->next) {
- writestruct(wd, DATA, Panel, 1, pa);
- }
+ writestruct(wd, DATA, ScrArea, 1, sa);
- for (pc_act = ar->panels_category_active.first; pc_act; pc_act = pc_act->next) {
- writestruct(wd, DATA, PanelCategoryStack, 1, pc_act);
- }
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ write_region(wd, ar, sa->spacetype);
- for (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next) {
- write_uilist(wd, ui_list);
- }
-
- for (ui_preview = ar->ui_previews.first; ui_preview; ui_preview = ui_preview->next) {
- writestruct(wd, DATA, uiPreview, 1, ui_preview);
- }
+ for (pa = ar->panels.first; pa; pa = pa->next) {
+ writestruct(wd, DATA, Panel, 1, pa);
}
- sl = sa->spacedata.first;
- while (sl) {
- for (ar = sl->regionbase.first; ar; ar = ar->next) {
- write_region(wd, ar, sl->spacetype);
- }
+ for (pc_act = ar->panels_category_active.first; pc_act; pc_act = pc_act->next) {
+ writestruct(wd, DATA, PanelCategoryStack, 1, pc_act);
+ }
- 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 (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next) {
+ write_uilist(wd, ui_list);
+ }
- 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;
+ for (ui_preview = ar->ui_previews.first; ui_preview; ui_preview = ui_preview->next) {
+ writestruct(wd, DATA, uiPreview, 1, ui_preview);
+ }
+ }
- /* temporarily disable ghost curves when saving */
- sipo->ghostCurves.first = sipo->ghostCurves.last = NULL;
+ 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, SpaceIpo, 1, sl);
- if (sipo->ads) {
- writestruct(wd, DATA, bDopeSheet, 1, sipo->ads);
- }
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ BGpic *bgpic;
+ writestruct(wd, DATA, View3D, 1, v3d);
- /* reenable ghost curves */
- sipo->ghostCurves = tmpGhosts;
+ for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
+ writestruct(wd, DATA, BGpic, 1, bgpic);
}
- else if (sl->spacetype == SPACE_BUTS) {
- writestruct(wd, DATA, SpaceButs, 1, sl);
+ if (v3d->localvd) {
+ writestruct(wd, DATA, View3D, 1, v3d->localvd);
}
- 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);
+ if (v3d->fx_settings.ssao) {
+ writestruct(wd, DATA, GPUSSAOSettings, 1, v3d->fx_settings.ssao);
}
- else if (sl->spacetype == SPACE_OUTLINER) {
- SpaceOops *so = (SpaceOops *)sl;
- write_soops(wd, so);
+ if (v3d->fx_settings.dof) {
+ writestruct(wd, DATA, GPUDOFSettings, 1, v3d->fx_settings.dof);
}
- 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;
+ }
+ else if (sl->spacetype == SPACE_IPO) {
+ SpaceIpo *sipo = (SpaceIpo *)sl;
+ ListBase tmpGhosts = sipo->ghostCurves;
- 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);
+ /* temporarily disable ghost curves when saving */
+ sipo->ghostCurves.first = sipo->ghostCurves.last = NULL;
- 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);
+ writestruct(wd, DATA, SpaceIpo, 1, sl);
+ if (sipo->ads) {
+ writestruct(wd, DATA, bDopeSheet, 1, sipo->ads);
}
- 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);
+ /* 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_USERPREF) {
- writestruct(wd, DATA, SpaceUserPref, 1, sl);
+ }
+ 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;
+
+ writestruct(wd, DATA, SpaceNla, 1, snla);
+ if (snla->ads) {
+ writestruct(wd, DATA, bDopeSheet, 1, snla->ads);
}
- else if (sl->spacetype == SPACE_CLIP) {
- writestruct(wd, DATA, SpaceClip, 1, sl);
+ }
+ 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);
+
+ for (path = snode->treepath.first; path; path = path->next) {
+ writestruct(wd, DATA, bNodeTreePath, 1, path);
}
- else if (sl->spacetype == SPACE_INFO) {
- writestruct(wd, DATA, SpaceInfo, 1, sl);
+ }
+ 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);
- sl = sl->next;
+ }
+ 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);
}
}
-
- sc = sc->id.next;
}
-
- mywrite_flush(wd);
}
static void write_bone(WriteData *wd, Bone *bone)
@@ -3189,156 +3132,114 @@ static void write_bone(WriteData *wd, Bone *bone)
}
}
-static void write_armatures(WriteData *wd, ListBase *idbase)
+static void write_armature(WriteData *wd, bArmature *arm)
{
- bArmature *arm;
- Bone *bone;
-
- arm = idbase->first;
- while (arm) {
- if (arm->id.us > 0 || wd->current) {
- writestruct(wd, ID_AR, bArmature, 1, arm);
- write_iddata(wd, &arm->id);
+ if (arm->id.us > 0 || wd->current) {
+ writestruct(wd, ID_AR, bArmature, 1, arm);
+ write_iddata(wd, &arm->id);
- if (arm->adt) {
- write_animdata(wd, arm->adt);
- }
+ if (arm->adt) {
+ write_animdata(wd, arm->adt);
+ }
- /* Direct data */
- bone = arm->bonebase.first;
- while (bone) {
- write_bone(wd, bone);
- bone = bone->next;
- }
+ /* Direct data */
+ for (Bone *bone = arm->bonebase.first; bone; bone = bone->next) {
+ write_bone(wd, bone);
}
- arm = arm->id.next;
}
-
- mywrite_flush(wd);
}
-static void write_texts(WriteData *wd, ListBase *idbase)
+static void write_text(WriteData *wd, Text *text)
{
- Text *text;
- TextLine *tmp;
+ if ((text->flags & TXT_ISMEM) && (text->flags & TXT_ISEXT)) {
+ text->flags &= ~TXT_ISEXT;
+ }
- text = idbase->first;
- while (text) {
- if ( (text->flags & TXT_ISMEM) && (text->flags & TXT_ISEXT)) {
- text->flags &= ~TXT_ISEXT;
- }
+ /* write LibData */
+ writestruct(wd, ID_TXT, Text, 1, text);
+ write_iddata(wd, &text->id);
- /* write LibData */
- writestruct(wd, ID_TXT, Text, 1, text);
- write_iddata(wd, &text->id);
+ if (text->name) {
+ writedata(wd, DATA, strlen(text->name) + 1, text->name);
+ }
- if (text->name) {
- writedata(wd, DATA, strlen(text->name) + 1, text->name);
+ if (!(text->flags & TXT_ISEXT)) {
+ /* now write the text data, in two steps for optimization in the readfunction */
+ for (TextLine *tmp = text->lines.first; tmp; tmp = tmp->next) {
+ writestruct(wd, DATA, TextLine, 1, tmp);
}
- if (!(text->flags & TXT_ISEXT)) {
- /* now write the text data, in two steps for optimization in the readfunction */
- tmp = text->lines.first;
- while (tmp) {
- writestruct(wd, DATA, TextLine, 1, tmp);
- tmp = tmp->next;
- }
-
- tmp = text->lines.first;
- while (tmp) {
- writedata(wd, DATA, tmp->len + 1, tmp->line);
- tmp = tmp->next;
- }
+ for (TextLine *tmp = text->lines.first; tmp; tmp = tmp->next) {
+ writedata(wd, DATA, tmp->len + 1, tmp->line);
}
-
-
- text = text->id.next;
}
-
- mywrite_flush(wd);
}
-static void write_speakers(WriteData *wd, ListBase *idbase)
+static void write_speaker(WriteData *wd, Speaker *spk)
{
- Speaker *spk;
-
- spk = idbase->first;
- while (spk) {
- if (spk->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_SPK, Speaker, 1, spk);
- write_iddata(wd, &spk->id);
+ if (spk->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_SPK, Speaker, 1, spk);
+ write_iddata(wd, &spk->id);
- if (spk->adt) {
- write_animdata(wd, spk->adt);
- }
+ if (spk->adt) {
+ write_animdata(wd, spk->adt);
}
- spk = spk->id.next;
}
}
-static void write_sounds(WriteData *wd, ListBase *idbase)
+static void write_sound(WriteData *wd, bSound *sound)
{
- bSound *sound;
+ if (sound->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_SO, bSound, 1, sound);
+ write_iddata(wd, &sound->id);
- PackedFile *pf;
+ if (sound->packedfile) {
+ PackedFile *pf = sound->packedfile;
+ writestruct(wd, DATA, PackedFile, 1, pf);
+ writedata(wd, DATA, pf->size, pf->data);
+ }
+ }
+}
- sound = idbase->first;
- while (sound) {
- if (sound->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_SO, bSound, 1, sound);
- write_iddata(wd, &sound->id);
+static void write_probe(WriteData *wd, LightProbe *prb)
+{
+ if (prb->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_LP, LightProbe, 1, prb);
+ write_iddata(wd, &prb->id);
- if (sound->packedfile) {
- pf = sound->packedfile;
- writestruct(wd, DATA, PackedFile, 1, pf);
- writedata(wd, DATA, pf->size, pf->data);
- }
+ if (prb->adt) {
+ write_animdata(wd, prb->adt);
}
- sound = sound->id.next;
}
-
- mywrite_flush(wd);
}
-static void write_groups(WriteData *wd, ListBase *idbase)
+static void write_group(WriteData *wd, Group *group)
{
- Group *group;
- GroupObject *go;
-
- for (group = idbase->first; group; group = group->id.next) {
- if (group->id.us > 0 || wd->current) {
- /* write LibData */
- writestruct(wd, ID_GR, Group, 1, group);
- write_iddata(wd, &group->id);
+ if (group->id.us > 0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_GR, Group, 1, group);
+ write_iddata(wd, &group->id);
- write_previews(wd, group->preview);
+ write_previews(wd, group->preview);
- go = group->gobject.first;
- while (go) {
- writestruct(wd, DATA, GroupObject, 1, go);
- go = go->next;
- }
+ for (GroupObject *go = group->gobject.first; go; go = go->next) {
+ writestruct(wd, DATA, GroupObject, 1, go);
}
}
-
- mywrite_flush(wd);
}
-static void write_nodetrees(WriteData *wd, ListBase *idbase)
+static void write_nodetree(WriteData *wd, bNodeTree *ntree)
{
- bNodeTree *ntree;
+ if (ntree->id.us > 0 || wd->current) {
+ writestruct(wd, ID_NT, bNodeTree, 1, ntree);
+ /* Note that trees directly used by other IDs (materials etc.) are not 'real' ID, they cannot
+ * be linked, etc., so we write actual id data here only, for 'real' ID trees. */
+ write_iddata(wd, &ntree->id);
- for (ntree = idbase->first; ntree; ntree = ntree->id.next) {
- if (ntree->id.us > 0 || wd->current) {
- writestruct(wd, ID_NT, bNodeTree, 1, ntree);
- /* Note that trees directly used by other IDs (materials etc.) are not 'real' ID, they cannot
- * be linked, etc., so we write actual id data here only, for 'real' ID trees. */
- write_iddata(wd, &ntree->id);
-
- write_nodetree(wd, ntree);
- }
+ write_nodetree_nolib(wd, ntree);
}
}
@@ -3412,53 +3313,41 @@ static void customnodes_free_deprecated_data(Main *mainvar)
}
#endif
-static void write_brushes(WriteData *wd, ListBase *idbase)
+static void write_brush(WriteData *wd, Brush *brush)
{
- Brush *brush;
+ if (brush->id.us > 0 || wd->current) {
+ writestruct(wd, ID_BR, Brush, 1, brush);
+ write_iddata(wd, &brush->id);
- for (brush = idbase->first; brush; brush = brush->id.next) {
- if (brush->id.us > 0 || wd->current) {
- writestruct(wd, ID_BR, Brush, 1, brush);
- write_iddata(wd, &brush->id);
-
- if (brush->curve) {
- write_curvemapping(wd, brush->curve);
- }
- if (brush->gradient) {
- writestruct(wd, DATA, ColorBand, 1, brush->gradient);
- }
+ if (brush->curve) {
+ write_curvemapping(wd, brush->curve);
+ }
+ if (brush->gradient) {
+ writestruct(wd, DATA, ColorBand, 1, brush->gradient);
}
}
}
-static void write_palettes(WriteData *wd, ListBase *idbase)
+static void write_palette(WriteData *wd, Palette *palette)
{
- Palette *palette;
+ if (palette->id.us > 0 || wd->current) {
+ PaletteColor *color;
+ writestruct(wd, ID_PAL, Palette, 1, palette);
+ write_iddata(wd, &palette->id);
- for (palette = idbase->first; palette; palette = palette->id.next) {
- if (palette->id.us > 0 || wd->current) {
- PaletteColor *color;
- writestruct(wd, ID_PAL, Palette, 1, palette);
- write_iddata(wd, &palette->id);
-
- for (color = palette->colors.first; color; color = color->next) {
- writestruct(wd, DATA, PaletteColor, 1, color);
- }
+ for (color = palette->colors.first; color; color = color->next) {
+ writestruct(wd, DATA, PaletteColor, 1, color);
}
}
}
-static void write_paintcurves(WriteData *wd, ListBase *idbase)
+static void write_paintcurve(WriteData *wd, PaintCurve *pc)
{
- PaintCurve *pc;
+ if (pc->id.us > 0 || wd->current) {
+ writestruct(wd, ID_PC, PaintCurve, 1, pc);
+ write_iddata(wd, &pc->id);
- for (pc = idbase->first; pc; pc = pc->id.next) {
- if (pc->id.us > 0 || wd->current) {
- writestruct(wd, ID_PC, PaintCurve, 1, pc);
- write_iddata(wd, &pc->id);
-
- writestruct(wd, DATA, PaintCurvePoint, pc->tot_points, pc->points);
- }
+ writestruct(wd, DATA, PaintCurvePoint, pc->tot_points, pc->points);
}
}
@@ -3500,103 +3389,85 @@ static void write_movieReconstruction(WriteData *wd, MovieTrackingReconstruction
}
}
-static void write_movieclips(WriteData *wd, ListBase *idbase)
+static void write_movieclip(WriteData *wd, MovieClip *clip)
{
- MovieClip *clip;
+ if (clip->id.us > 0 || wd->current) {
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *object;
- clip = idbase->first;
- while (clip) {
- if (clip->id.us > 0 || wd->current) {
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *object;
+ writestruct(wd, ID_MC, MovieClip, 1, clip);
+ write_iddata(wd, &clip->id);
- writestruct(wd, ID_MC, MovieClip, 1, clip);
- write_iddata(wd, &clip->id);
-
- if (clip->adt) {
- write_animdata(wd, clip->adt);
- }
+ if (clip->adt) {
+ write_animdata(wd, clip->adt);
+ }
- write_movieTracks(wd, &tracking->tracks);
- write_moviePlaneTracks(wd, &tracking->plane_tracks);
- write_movieReconstruction(wd, &tracking->reconstruction);
+ write_movieTracks(wd, &tracking->tracks);
+ write_moviePlaneTracks(wd, &tracking->plane_tracks);
+ write_movieReconstruction(wd, &tracking->reconstruction);
- object = tracking->objects.first;
- while (object) {
- writestruct(wd, DATA, MovieTrackingObject, 1, object);
+ object = tracking->objects.first;
+ while (object) {
+ writestruct(wd, DATA, MovieTrackingObject, 1, object);
- write_movieTracks(wd, &object->tracks);
- write_moviePlaneTracks(wd, &object->plane_tracks);
- write_movieReconstruction(wd, &object->reconstruction);
+ write_movieTracks(wd, &object->tracks);
+ write_moviePlaneTracks(wd, &object->plane_tracks);
+ write_movieReconstruction(wd, &object->reconstruction);
- object = object->next;
- }
+ object = object->next;
}
-
- clip = clip->id.next;
}
-
- mywrite_flush(wd);
}
-static void write_masks(WriteData *wd, ListBase *idbase)
+static void write_mask(WriteData *wd, Mask *mask)
{
- Mask *mask;
-
- mask = idbase->first;
- while (mask) {
- if (mask->id.us > 0 || wd->current) {
- MaskLayer *masklay;
+ if (mask->id.us > 0 || wd->current) {
+ MaskLayer *masklay;
- writestruct(wd, ID_MSK, Mask, 1, mask);
- write_iddata(wd, &mask->id);
+ writestruct(wd, ID_MSK, Mask, 1, mask);
+ write_iddata(wd, &mask->id);
- if (mask->adt) {
- write_animdata(wd, mask->adt);
- }
+ if (mask->adt) {
+ write_animdata(wd, mask->adt);
+ }
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskSpline *spline;
- MaskLayerShape *masklay_shape;
+ for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
+ MaskSpline *spline;
+ MaskLayerShape *masklay_shape;
- writestruct(wd, DATA, MaskLayer, 1, masklay);
+ writestruct(wd, DATA, MaskLayer, 1, masklay);
- for (spline = masklay->splines.first; spline; spline = spline->next) {
- int i;
+ for (spline = masklay->splines.first; spline; spline = spline->next) {
+ int i;
- void *points_deform = spline->points_deform;
- spline->points_deform = NULL;
+ void *points_deform = spline->points_deform;
+ spline->points_deform = NULL;
- writestruct(wd, DATA, MaskSpline, 1, spline);
- writestruct(wd, DATA, MaskSplinePoint, spline->tot_point, spline->points);
+ writestruct(wd, DATA, MaskSpline, 1, spline);
+ writestruct(wd, DATA, MaskSplinePoint, spline->tot_point, spline->points);
- spline->points_deform = points_deform;
+ spline->points_deform = points_deform;
- for (i = 0; i < spline->tot_point; i++) {
- MaskSplinePoint *point = &spline->points[i];
+ for (i = 0; i < spline->tot_point; i++) {
+ MaskSplinePoint *point = &spline->points[i];
- if (point->tot_uw) {
- writestruct(wd, DATA, MaskSplinePointUW, point->tot_uw, point->uw);
- }
+ if (point->tot_uw) {
+ writestruct(wd, DATA, MaskSplinePointUW, point->tot_uw, point->uw);
}
}
+ }
- for (masklay_shape = masklay->splines_shapes.first;
- masklay_shape;
- masklay_shape = masklay_shape->next)
- {
- writestruct(wd, DATA, MaskLayerShape, 1, masklay_shape);
- writedata(wd, DATA,
- masklay_shape->tot_vert * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE,
- masklay_shape->data);
- }
+ for (masklay_shape = masklay->splines_shapes.first;
+ masklay_shape;
+ masklay_shape = masklay_shape->next)
+ {
+ writestruct(wd, DATA, MaskLayerShape, 1, masklay_shape);
+ writedata(wd, DATA,
+ masklay_shape->tot_vert * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE,
+ masklay_shape->data);
}
}
-
- mask = mask->id.next;
}
-
- mywrite_flush(wd);
}
static void write_linestyle_color_modifiers(WriteData *wd, ListBase *modifiers)
@@ -3853,52 +3724,54 @@ static void write_linestyle_geometry_modifiers(WriteData *wd, ListBase *modifier
}
}
-static void write_linestyles(WriteData *wd, ListBase *idbase)
+static void write_linestyle(WriteData *wd, FreestyleLineStyle *linestyle)
{
- FreestyleLineStyle *linestyle;
- int a;
-
- for (linestyle = idbase->first; linestyle; linestyle = linestyle->id.next) {
- if (linestyle->id.us > 0 || wd->current) {
- writestruct(wd, ID_LS, FreestyleLineStyle, 1, linestyle);
- write_iddata(wd, &linestyle->id);
+ if (linestyle->id.us > 0 || wd->current) {
+ writestruct(wd, ID_LS, FreestyleLineStyle, 1, linestyle);
+ write_iddata(wd, &linestyle->id);
- if (linestyle->adt) {
- write_animdata(wd, linestyle->adt);
- }
+ if (linestyle->adt) {
+ write_animdata(wd, linestyle->adt);
+ }
- write_linestyle_color_modifiers(wd, &linestyle->color_modifiers);
- write_linestyle_alpha_modifiers(wd, &linestyle->alpha_modifiers);
- write_linestyle_thickness_modifiers(wd, &linestyle->thickness_modifiers);
- write_linestyle_geometry_modifiers(wd, &linestyle->geometry_modifiers);
- for (a = 0; a < MAX_MTEX; a++) {
- if (linestyle->mtex[a]) {
- writestruct(wd, DATA, MTex, 1, linestyle->mtex[a]);
- }
- }
- if (linestyle->nodetree) {
- writestruct(wd, DATA, bNodeTree, 1, linestyle->nodetree);
- write_nodetree(wd, linestyle->nodetree);
+ write_linestyle_color_modifiers(wd, &linestyle->color_modifiers);
+ write_linestyle_alpha_modifiers(wd, &linestyle->alpha_modifiers);
+ write_linestyle_thickness_modifiers(wd, &linestyle->thickness_modifiers);
+ write_linestyle_geometry_modifiers(wd, &linestyle->geometry_modifiers);
+ for (int a = 0; a < MAX_MTEX; a++) {
+ if (linestyle->mtex[a]) {
+ writestruct(wd, DATA, MTex, 1, linestyle->mtex[a]);
}
}
+ if (linestyle->nodetree) {
+ writestruct(wd, DATA, bNodeTree, 1, linestyle->nodetree);
+ write_nodetree_nolib(wd, linestyle->nodetree);
+ }
}
}
-static void write_cachefiles(WriteData *wd, ListBase *idbase)
+static void write_cachefile(WriteData *wd, CacheFile *cache_file)
{
- CacheFile *cache_file;
-
- for (cache_file = idbase->first; cache_file; cache_file = cache_file->id.next) {
- if (cache_file->id.us > 0 || wd->current) {
- writestruct(wd, ID_CF, CacheFile, 1, cache_file);
+ if (cache_file->id.us > 0 || wd->current) {
+ writestruct(wd, ID_CF, CacheFile, 1, cache_file);
- if (cache_file->adt) {
- write_animdata(wd, cache_file->adt);
- }
+ if (cache_file->adt) {
+ write_animdata(wd, cache_file->adt);
}
}
}
+static void write_workspace(WriteData *wd, WorkSpace *workspace)
+{
+ ListBase *layouts = BKE_workspace_layouts_get(workspace);
+ ListBase *transform_orientations = BKE_workspace_transform_orientations_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, TransformOrientation, transform_orientations);
+}
+
/* Keep it last of write_foodata functions. */
static void write_libraries(WriteData *wd, Main *main)
{
@@ -3908,7 +3781,6 @@ static void write_libraries(WriteData *wd, Main *main)
bool found_one;
for (; main; main = main->next) {
-
a = tot = set_listbasepointers(main, lbarray);
/* test: is lib being used */
@@ -3917,16 +3789,13 @@ static void write_libraries(WriteData *wd, Main *main)
}
else {
found_one = false;
- while (tot--) {
+ while (!found_one && tot--) {
for (id = lbarray[tot]->first; id; id = id->next) {
if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) {
found_one = true;
break;
}
}
- if (found_one) {
- break;
- }
}
}
@@ -3950,7 +3819,7 @@ static void write_libraries(WriteData *wd, Main *main)
for (id = lbarray[a]->first; id; id = id->next) {
if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) {
if (!BKE_idcode_is_linkable(GS(id->name))) {
- printf("ERROR: write file: datablock '%s' from lib '%s' is not linkable "
+ printf("ERROR: write file: data-block '%s' from lib '%s' is not linkable "
"but is flagged as directly linked", id->name, main->curlib->filepath);
BLI_assert(0);
}
@@ -3972,6 +3841,8 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
const bool is_undo = (wd->current != NULL);
FileGlobal fg;
bScreen *screen;
+ Scene *scene;
+ SceneLayer *render_layer;
char subvstr[8];
/* prevent mem checkers from complaining */
@@ -3979,11 +3850,12 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
memset(fg.filename, 0, sizeof(fg.filename));
memset(fg.build_hash, 0, sizeof(fg.build_hash));
- current_screen_compat(mainvar, &screen, is_undo);
+ current_screen_compat(mainvar, is_undo, &screen, &scene, &render_layer);
/* XXX still remap G */
fg.curscreen = screen;
- fg.curscene = screen ? screen->scene : NULL;
+ fg.curscene = scene;
+ fg.cur_render_layer = render_layer;
/* prevent to save this, is not good convention, and feature with concerns... */
fg.fileflags = (fileflags & ~G_FILE_FLAGS_RUNTIME);
@@ -4065,38 +3937,137 @@ static bool write_file_handle(
* avoid thumbnail detecting changes because of this. */
mywrite_flush(wd);
- write_windowmanagers(wd, &mainvar->wm);
- write_screens(wd, &mainvar->screen);
- write_movieclips(wd, &mainvar->movieclip);
- write_masks(wd, &mainvar->mask);
- write_scenes(wd, &mainvar->scene);
- write_curves(wd, &mainvar->curve);
- write_mballs(wd, &mainvar->mball);
- write_images(wd, &mainvar->image);
- write_cameras(wd, &mainvar->camera);
- write_lamps(wd, &mainvar->lamp);
- write_lattices(wd, &mainvar->latt);
- write_vfonts(wd, &mainvar->vfont);
- write_keys(wd, &mainvar->key);
- write_worlds(wd, &mainvar->world);
- write_texts(wd, &mainvar->text);
- write_speakers(wd, &mainvar->speaker);
- write_sounds(wd, &mainvar->sound);
- write_groups(wd, &mainvar->group);
- write_armatures(wd, &mainvar->armature);
- write_actions(wd, &mainvar->action);
- write_objects(wd, &mainvar->object);
- write_materials(wd, &mainvar->mat);
- write_textures(wd, &mainvar->tex);
- write_meshes(wd, &mainvar->mesh);
- write_particlesettings(wd, &mainvar->particle);
- write_nodetrees(wd, &mainvar->nodetree);
- write_brushes(wd, &mainvar->brush);
- write_palettes(wd, &mainvar->palettes);
- write_paintcurves(wd, &mainvar->paintcurves);
- write_gpencils(wd, &mainvar->gpencil);
- write_linestyles(wd, &mainvar->linestyle);
- write_cachefiles(wd, &mainvar->cachefiles);
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a = set_listbasepointers(mainvar, lbarray);
+ while (a--) {
+ ID *id = lbarray[a]->first;
+
+ if (id && GS(id->name) == ID_LI) {
+ continue; /* Libraries are handled separately below. */
+ }
+
+ for (; id; id = id->next) {
+ 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_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;
+ }
+ }
+
+ mywrite_flush(wd);
+ }
+
+ /* Special handling, operating over split Mains... */
write_libraries(wd, mainvar->next);
/* So changes above don't cause a 'DNA1' to be detected as changed on undo. */
diff --git a/source/blender/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h
index 1d76077c9f1..ed1993015f6 100644
--- a/source/blender/blentranslation/BLT_translation.h
+++ b/source/blender/blentranslation/BLT_translation.h
@@ -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"
@@ -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/CMakeLists.txt b/source/blender/blentranslation/CMakeLists.txt
index a3e85344027..c0dce5b4f0d 100644
--- a/source/blender/blentranslation/CMakeLists.txt
+++ b/source/blender/blentranslation/CMakeLists.txt
@@ -60,3 +60,5 @@ if(WIN32)
endif()
blender_add_lib(bf_blentranslation "${SRC}" "${INC}" "${INC_SYS}")
+
+add_subdirectory(msgfmt)
diff --git a/source/blender/blentranslation/msgfmt/CMakeLists.txt b/source/blender/blentranslation/msgfmt/CMakeLists.txt
new file mode 100644
index 00000000000..d2cb6f5a03b
--- /dev/null
+++ b/source/blender/blentranslation/msgfmt/CMakeLists.txt
@@ -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.
+#
+# The Original Code is Copyright (C) 2017, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Bastien Montagne.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+# -----------------------------------------------------------------------------
+# Build msgfmt executable
+
+blender_include_dirs(
+ ../../../../intern/guardedalloc
+ ../../blenlib
+)
+
+set(SRC
+ msgfmt.c
+)
+
+add_cc_flags_custom_test(msgfmt)
+
+add_executable(msgfmt ${SRC})
+
+target_link_libraries(msgfmt bf_blenlib)
+target_link_libraries(msgfmt bf_intern_guardedalloc)
+
+if(WIN32)
+ target_link_libraries(msgfmt bf_intern_utfconv)
+endif()
+
+target_link_libraries(msgfmt ${ZLIB_LIBRARIES})
+target_link_libraries(msgfmt ${PLATFORM_LINKLIBS})
diff --git a/source/blender/blentranslation/msgfmt/msgfmt.c b/source/blender/blentranslation/msgfmt/msgfmt.c
new file mode 100644
index 00000000000..487d9fee7b4
--- /dev/null
+++ b/source/blender/blentranslation/msgfmt/msgfmt.c
@@ -0,0 +1,464 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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): Bastien Montagne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/*
+ * Based on C++ version by Sergey Sharybin <sergey.vfx@gmail.com>.
+ * Based on Python script msgfmt.py from Python source code tree, which was written by
+ * Martin v. Löwis <loewis@informatik.hu-berlin.de>
+ *
+ * Generate binary message catalog from textual translation description.
+ *
+ * This program converts a textual Uniforum-style message catalog (.po file) into a binary GNU catalog (.mo file).
+ * This is essentially the same function as the GNU msgfmt program, however, it is a simpler implementation.
+ *
+ * Usage: msgfmt input.po output.po
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_dynstr.h"
+#include "BLI_fileops.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_memarena.h"
+
+#include "MEM_guardedalloc.h"
+
+
+/* Stupid stub necessary because some BLI files includes winstuff.h, which uses G a bit... */
+#ifdef WIN32
+ typedef struct Global {
+ void *dummy;
+ } Global;
+
+ Global G;
+#endif
+
+
+/* We cannot use NULL char until ultimate step, would give nightmare to our C string processing...
+ * Using one of the UTF-8 invalid bytes (as per our BLI string_utf8.c) */
+#define NULLSEP_STR "\xff"
+#define NULLSEP_CHR '\xff'
+
+typedef enum {
+ SECTION_NONE = 0,
+ SECTION_CTX = 1,
+ SECTION_ID = 2,
+ SECTION_STR = 3,
+} eSectionType;
+
+typedef struct Message {
+ DynStr *ctxt;
+ DynStr *id;
+ DynStr *str;
+
+ bool is_fuzzy;
+} Message;
+
+static char *trim(char *str)
+{
+ const size_t len = strlen(str);
+ size_t i;
+
+ if (len == 0) {
+ return str;
+ }
+
+ for (i = 0; i < len && ELEM(str[0], ' ', '\t', '\n'); str++, i++);
+
+ char *end = &str[len - 1 - i];
+ for (i = len; i > 0 && ELEM(end[0], ' ', '\t', '\n'); end--, i--);
+ end[1] = '\0';
+
+ return str;
+}
+
+static char *unescape(char *str)
+{
+ char *curr, *next;
+ for (curr = next = str; next[0] != '\0'; curr++, next++) {
+ if (next[0] == '\\') {
+ switch (next[1]) {
+ case '\0':
+ /* Get rid of trailing escape char... */
+ curr--;
+ break;
+ case '\\':
+ *curr = '\\';
+ next++;
+ break;
+ case 'n':
+ *curr = '\n';
+ next++;
+ break;
+ case 't':
+ *curr = '\t';
+ next++;
+ break;
+ default:
+ /* Get rid of useless escape char. */
+ next++;
+ *curr = *next;
+ }
+ }
+ else if (curr != next) {
+ *curr = *next;
+ }
+ }
+ *curr = '\0';
+
+ if (str[0] == '"' && *(curr - 1) == '"') {
+ *(curr - 1) = '\0';
+ return str + 1;
+ }
+ return str;
+}
+
+static int qsort_str_cmp(const void *a, const void *b)
+{
+ return strcmp(*(const char **)a, *(const char **)b);
+}
+
+static char **get_keys_sorted(GHash *messages, const uint32_t num_keys)
+{
+ GHashIterator iter;
+
+ char **keys = MEM_mallocN(sizeof(*keys) * num_keys, __func__);
+ char **k = keys;
+
+ GHASH_ITER(iter, messages) {
+ *k = BLI_ghashIterator_getKey(&iter);
+ k++;
+ }
+
+ qsort(keys, num_keys, sizeof(*keys), qsort_str_cmp);
+
+ return keys;
+}
+
+BLI_INLINE size_t uint32_to_bytes(const int value, char *bytes) {
+ size_t i;
+ for (i = 0; i < sizeof(value); i++) {
+ bytes[i] = (char) ((value >> ((int)i * 8)) & 0xff);
+ }
+ return i;
+}
+
+BLI_INLINE size_t msg_to_bytes(char *msg, char *bytes, uint32_t size) {
+ /* Note that we also perform replacing of our NULLSEP placeholder by real NULL char... */
+ size_t i;
+ for (i = 0; i < size; i++, msg++, bytes++) {
+ *bytes = (*msg == NULLSEP_CHR) ? '\0' : *msg;
+ }
+ return i;
+}
+
+typedef struct Offset {
+ uint32_t key_offset, key_len, val_offset, val_len;
+} Offset;
+
+/* Return the generated binary output. */
+static char *generate(GHash *messages, size_t *r_output_size) {
+ const uint32_t num_keys = BLI_ghash_size(messages);
+
+ /* Get list of sorted keys. */
+ char **keys = get_keys_sorted(messages, num_keys);
+ char **vals = MEM_mallocN(sizeof(*vals) * num_keys, __func__);
+ uint32_t tot_keys_len = 0;
+ uint32_t tot_vals_len = 0;
+
+ Offset *offsets = MEM_mallocN(sizeof(*offsets) * num_keys, __func__);
+
+ for (int i = 0; i < num_keys; i++) {
+ Offset *off = &offsets[i];
+
+ vals[i] = BLI_ghash_lookup(messages, keys[i]);
+
+ /* For each string, we need size and file offset.
+ * Each string is NULL terminated; the NULL does not count into the size. */
+ off->key_offset = tot_keys_len;
+ off->key_len = (uint32_t)strlen(keys[i]);
+ tot_keys_len += off->key_len + 1;
+
+ off->val_offset = tot_vals_len;
+ off->val_len = (uint32_t)strlen(vals[i]);
+ tot_vals_len += off->val_len + 1;
+ }
+
+ /* The header is 7 32-bit unsigned integers. then comes the keys index table, then the values index table. */
+ const uint32_t idx_keystart = 7 * 4;
+ const uint32_t idx_valstart = idx_keystart + 8 * num_keys;
+ /* We don't use hash tables, so the keys start right after the index tables. */
+ const uint32_t keystart = idx_valstart + 8 * num_keys;
+ /* and the values start after the keys */
+ const uint32_t valstart = keystart + tot_keys_len;
+
+ /* Final buffer representing the binary MO file. */
+ *r_output_size = valstart + tot_vals_len;
+ char *output = MEM_mallocN(*r_output_size, __func__);
+ char *h = output;
+ char *ik = output + idx_keystart;
+ char *iv = output + idx_valstart;
+ char *k = output + keystart;
+ char *v = output + valstart;
+
+ h += uint32_to_bytes(0x950412de, h); /* Magic */
+ h += uint32_to_bytes(0x0, h); /* Version */
+ h += uint32_to_bytes(num_keys, h); /* Number of entries */
+ h += uint32_to_bytes(idx_keystart, h); /* Start of key index */
+ h += uint32_to_bytes(idx_valstart, h); /* Start of value index */
+ h += uint32_to_bytes(0, h); /* Size of hash table */
+ h += uint32_to_bytes(0, h); /* Offset of hash table */
+
+ BLI_assert(h == ik);
+
+ for (int i = 0; i < num_keys; i++) {
+ Offset *off = &offsets[i];
+
+ /* The index table first has the list of keys, then the list of values.
+ * Each entry has first the size of the string, then the file offset. */
+ ik += uint32_to_bytes(off->key_len, ik);
+ ik += uint32_to_bytes(off->key_offset + keystart, ik);
+ iv += uint32_to_bytes(off->val_len, iv);
+ iv += uint32_to_bytes(off->val_offset + valstart, iv);
+
+ k += msg_to_bytes(keys[i], k, off->key_len + 1);
+ v += msg_to_bytes(vals[i], v, off->val_len + 1);
+ }
+
+ BLI_assert(ik == output + idx_valstart);
+ BLI_assert(iv == output + keystart);
+ BLI_assert(k == output + valstart);
+
+ MEM_freeN(keys);
+ MEM_freeN(vals);
+ MEM_freeN(offsets);
+
+ return output;
+}
+
+/* Add a non-fuzzy translation to the dictionary. */
+static void add(GHash *messages, MemArena *memarena, const Message *msg)
+{
+ const size_t msgctxt_len = (size_t)BLI_dynstr_get_len(msg->ctxt);
+ const size_t msgid_len = (size_t)BLI_dynstr_get_len(msg->id);
+ const size_t msgstr_len = (size_t)BLI_dynstr_get_len(msg->str);
+ const size_t msgkey_len = msgid_len + ((msgctxt_len == 0) ? 0 : msgctxt_len + 1);
+
+ if (!msg->is_fuzzy && msgstr_len != 0) {
+ char *msgkey = BLI_memarena_alloc(memarena, sizeof(*msgkey) * (msgkey_len + 1));
+ char *msgstr = BLI_memarena_alloc(memarena, sizeof(*msgstr) * (msgstr_len + 1));
+
+ if (msgctxt_len != 0) {
+ BLI_dynstr_get_cstring_ex(msg->ctxt, msgkey);
+ msgkey[msgctxt_len] = '\x04'; /* Context/msgid separator */
+ BLI_dynstr_get_cstring_ex(msg->id, &msgkey[msgctxt_len + 1]);
+ }
+ else {
+ BLI_dynstr_get_cstring_ex(msg->id, msgkey);
+ }
+
+ BLI_dynstr_get_cstring_ex(msg->str, msgstr);
+
+ BLI_ghash_insert(messages, msgkey, msgstr);
+ }
+}
+
+
+static void clear(Message *msg)
+{
+ BLI_dynstr_clear(msg->ctxt);
+ BLI_dynstr_clear(msg->id);
+ BLI_dynstr_clear(msg->str);
+ msg->is_fuzzy = false;
+}
+
+static int make(const char *input_file_name, const char *output_file_name)
+{
+ GHash *messages = BLI_ghash_new(BLI_ghashutil_strhash_p_murmur, BLI_ghashutil_strcmp, __func__);
+ MemArena *msgs_memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+
+ const char *msgctxt_kw = "msgctxt";
+ const char *msgid_kw = "msgid";
+ const char *msgid_plural_kw = "msgid_plural";
+ const char *msgstr_kw = "msgstr";
+ const size_t msgctxt_len = strlen(msgctxt_kw);
+ const size_t msgid_len = strlen(msgid_kw);
+ const size_t msgid_plural_len = strlen(msgid_plural_kw);
+ const size_t msgstr_len = strlen(msgstr_kw);
+
+ /* Note: For now, we assume file encoding is always utf-8. */
+
+ eSectionType section = SECTION_NONE;
+ bool is_plural = false;
+
+ Message msg = {
+ .ctxt = BLI_dynstr_new_memarena(),
+ .id = BLI_dynstr_new_memarena(),
+ .str = BLI_dynstr_new_memarena(),
+ .is_fuzzy = false,
+ };
+
+ LinkNode *input_file_lines = BLI_file_read_as_lines(input_file_name);
+ LinkNode *ifl = input_file_lines;
+
+ /* Parse the catalog. */
+ for (int lno = 1; ifl; ifl = ifl->next, lno++) {
+ char *l = ifl->link;
+ const bool is_comment = (l[0] == '#');
+ /* If we get a comment line after a msgstr, this is a new entry. */
+ if (is_comment) {
+ if (section == SECTION_STR) {
+ add(messages, msgs_memarena, &msg);
+ clear(&msg);
+ section = SECTION_NONE;
+ }
+ /* Record a fuzzy mark. */
+ if (l[1] == ',' && strstr(l, "fuzzy") != NULL) {
+ msg.is_fuzzy = true;
+ }
+ /* Skip comments */
+ continue;
+ }
+ if (strstr(l, msgctxt_kw) == l) {
+ if (section == SECTION_STR) {
+ /* New message, output previous section. */
+ add(messages, msgs_memarena, &msg);
+ }
+ if (!ELEM(section, SECTION_NONE, SECTION_STR)) {
+ printf("msgctxt not at start of new message on %s:%d\n", input_file_name, lno);
+ return EXIT_FAILURE;
+ }
+ section = SECTION_CTX;
+ l = l + msgctxt_len;
+ clear(&msg);
+ }
+ else if (strstr(l, msgid_plural_kw) == l) {
+ /* This is a message with plural forms. */
+ if (section != SECTION_ID) {
+ printf("msgid_plural not preceeded by msgid on %s:%d\n", input_file_name, lno);
+ return EXIT_FAILURE;
+ }
+ l = l + msgid_plural_len;
+ BLI_dynstr_append(msg.id, NULLSEP_STR); /* separator of singular and plural */
+ is_plural = true;
+ }
+ else if (strstr(l, msgid_kw) == l) {
+ if (section == SECTION_STR) {
+ add(messages, msgs_memarena, &msg);
+ }
+ if (section != SECTION_CTX) {
+ clear(&msg);
+ }
+ section = SECTION_ID;
+ l = l + msgid_len;
+ is_plural = false;
+ }
+ else if (strstr(l, msgstr_kw) == l) {
+ l = l + msgstr_len;
+ // Now we are in a msgstr section
+ section = SECTION_STR;
+ if (l[0] == '[') {
+ if (!is_plural) {
+ printf("plural without msgid_plural on %s:%d\n", input_file_name, lno);
+ return EXIT_FAILURE;
+ }
+ if ((l = strchr(l, ']')) == NULL) {
+ printf("Syntax error on %s:%d\n", input_file_name, lno);
+ return EXIT_FAILURE;
+ }
+ if (BLI_dynstr_get_len(msg.str) != 0) {
+ BLI_dynstr_append(msg.str, NULLSEP_STR); /* Separator of the various plural forms. */
+ }
+ }
+ else {
+ if (is_plural) {
+ printf("indexed msgstr required for plural on %s:%d\n", input_file_name, lno);
+ return EXIT_FAILURE;
+ }
+ }
+ }
+ /* Skip empty lines. */
+ l = trim(l);
+ if (l[0] == '\0') {
+ if (section == SECTION_STR) {
+ add(messages, msgs_memarena, &msg);
+ clear(&msg);
+ }
+ section = SECTION_NONE;
+ continue;
+ }
+ l = unescape(l);
+ if (section == SECTION_CTX) {
+ BLI_dynstr_append(msg.ctxt, l);
+ }
+ else if (section == SECTION_ID) {
+ BLI_dynstr_append(msg.id, l);
+ }
+ else if (section == SECTION_STR) {
+ BLI_dynstr_append(msg.str, l);
+ }
+ else {
+ printf("Syntax error on %s:%d\n", input_file_name, lno);
+ return EXIT_FAILURE;
+ }
+ }
+ /* Add last entry */
+ if (section == SECTION_STR) {
+ add(messages, msgs_memarena, &msg);
+ }
+
+ BLI_dynstr_free(msg.ctxt);
+ BLI_dynstr_free(msg.id);
+ BLI_dynstr_free(msg.str);
+ BLI_file_free_lines(input_file_lines);
+
+ /* Compute output */
+ size_t output_size;
+ char *output = generate(messages, &output_size);
+
+ FILE *fp = BLI_fopen(output_file_name, "wb");
+ fwrite(output, 1, output_size, fp);
+ fclose(fp);
+
+ MEM_freeN(output);
+ BLI_ghash_free(messages, NULL, NULL);
+ BLI_memarena_free(msgs_memarena);
+
+ return EXIT_SUCCESS;
+}
+
+int main(int argc, char **argv) {
+ if (argc != 3) {
+ printf("Usage: %s <input.po> <output.mo>\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+ const char *input_file = argv[1];
+ const char *output_file = argv[2];
+
+ return make(input_file, output_file);
+}
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index 0b2697d92b0..bbe5044f1bf 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -156,6 +156,8 @@ set(SRC
tools/bmesh_path_region.h
tools/bmesh_region_match.c
tools/bmesh_region_match.h
+ tools/bmesh_separate.c
+ tools/bmesh_separate.h
tools/bmesh_triangulate.c
tools/bmesh_triangulate.h
tools/bmesh_wireframe.c
diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h
index d72791449fb..ab955b7826a 100644
--- a/source/blender/bmesh/bmesh.h
+++ b/source/blender/bmesh/bmesh.h
@@ -192,9 +192,10 @@
*
* These conventions should be used throughout the bmesh module.
*
- * - ``BM_***()`` - High level BMesh API function for use anywhere.
- * - ``bmesh_***()`` - Low level API function.
+ * - ``bmesh_kernel_*()`` - Low level API, for primitive functions that others are built ontop of.
+ * - ``bmesh_***()`` - Low level API function.
* - ``bm_***()`` - 'static' functions, not apart of the API at all, but use prefix since they operate on BMesh data.
+ * - ``BM_***()`` - High level BMesh API function for use anywhere.
* - ``BMO_***()`` - High level operator API function for use anywhere.
* - ``bmo_***()`` - Low level / internal operator API functions.
* - ``_bm_***()`` - Functions which are called via macros only.
diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h
index 72ea7bd7f5d..64a5cad812a 100644
--- a/source/blender/bmesh/bmesh_class.h
+++ b/source/blender/bmesh/bmesh_class.h
@@ -225,7 +225,7 @@ typedef struct BMesh {
/* operator api stuff (must be all NULL or all alloc'd) */
struct BLI_mempool *vtoolflagpool, *etoolflagpool, *ftoolflagpool;
- unsigned int use_toolflags : 1;
+ uint use_toolflags : 1;
int toolflag_index;
struct BMOperator *currentop;
@@ -245,7 +245,7 @@ typedef struct BMesh {
/* ID of the shape key this bmesh came from */
int shapenr;
- int walkers, totflags;
+ int totflags;
ListBase selected;
BMFace *act_face;
@@ -382,7 +382,7 @@ typedef bool (*BMLoopFilterFunc)(const BMLoop *, void *user_data);
(assert(offset != -1), *((float *)((char *)(ele)->head.data + (offset))))
#define BM_ELEM_CD_GET_FLOAT_AS_UCHAR(ele, offset) \
- (assert(offset != -1), (unsigned char)(BM_ELEM_CD_GET_FLOAT(ele, offset) * 255.0f))
+ (assert(offset != -1), (uchar)(BM_ELEM_CD_GET_FLOAT(ele, offset) * 255.0f))
/*forward declarations*/
diff --git a/source/blender/bmesh/bmesh_tools.h b/source/blender/bmesh/bmesh_tools.h
index 23212dd085e..a537c3b872c 100644
--- a/source/blender/bmesh/bmesh_tools.h
+++ b/source/blender/bmesh/bmesh_tools.h
@@ -43,6 +43,7 @@ extern "C" {
#include "tools/bmesh_path.h"
#include "tools/bmesh_path_region.h"
#include "tools/bmesh_region_match.h"
+#include "tools/bmesh_separate.h"
#include "tools/bmesh_triangulate.h"
#ifdef __cplusplus
diff --git a/source/blender/bmesh/intern/bmesh_callback_generic.c b/source/blender/bmesh/intern/bmesh_callback_generic.c
index 913255bfb33..e9304e8536f 100644
--- a/source/blender/bmesh/intern/bmesh_callback_generic.c
+++ b/source/blender/bmesh/intern/bmesh_callback_generic.c
@@ -32,7 +32,7 @@
bool BM_elem_cb_check_hflag_ex(BMElem *ele, void *user_data)
{
- const unsigned int hflag_pair = GET_INT_FROM_POINTER(user_data);
+ const uint hflag_pair = GET_INT_FROM_POINTER(user_data);
const char hflag_p = (hflag_pair & 0xff);
const char hflag_n = (hflag_pair >> 8);
diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c
index 4d92baab6eb..f8ecbe1756b 100644
--- a/source/blender/bmesh/intern/bmesh_construct.c
+++ b/source/blender/bmesh/intern/bmesh_construct.c
@@ -154,7 +154,7 @@ void BM_face_copy_shared(
if (l_other && l_other != l_iter) {
BMLoop *l_src[2];
BMLoop *l_dst[2] = {l_iter, l_iter->next};
- unsigned int j;
+ uint j;
if (l_other->v == l_iter->v) {
l_src[0] = l_other;
@@ -311,7 +311,7 @@ BMFace *BM_face_create_ngon_verts(
const bool calc_winding, const bool create_edges)
{
BMEdge **edge_arr = BLI_array_alloca(edge_arr, len);
- unsigned int winding[2] = {0, 0};
+ uint winding[2] = {0, 0};
int i, i_prev = len - 1;
BMVert *v_winding[2] = {vert_arr[i_prev], vert_arr[0]};
@@ -387,15 +387,11 @@ BMFace *BM_face_create_ngon_verts(
*
* \note Since this is a vcloud there is no direction.
*/
-BMFace *BM_face_create_ngon_vcloud(
- BMesh *bm, BMVert **vert_arr, int len,
- const BMFace *f_example, const eBMCreateFlag create_flag)
+void BM_verts_sort_radial_plane(BMVert **vert_arr, int len)
{
struct SortIntByFloat *vang = BLI_array_alloca(vang, len);
BMVert **vert_arr_map = BLI_array_alloca(vert_arr_map, len);
- BMFace *f;
-
float totv_inv = 1.0f / (float)len;
int i = 0;
@@ -470,26 +466,9 @@ BMFace *BM_face_create_ngon_vcloud(
/* now calculate every points angle around the normal (signed) */
for (i = 0; i < len; i++) {
- float co[3];
- float proj_vec[3];
- float angle;
-
- /* center relative vec */
- sub_v3_v3v3(co, vert_arr[i]->co, cent);
-
- /* align to plane */
- project_v3_v3v3(proj_vec, co, nor);
- sub_v3_v3(co, proj_vec);
-
- /* now 'co' is valid - we can compare its angle against the far vec */
- angle = angle_v3v3(far_vec, co);
-
- if (dot_v3v3(co, sign_vec) < 0.0f) {
- angle = -angle;
- }
-
- vang[i].sort_value = angle;
+ vang[i].sort_value = angle_signed_on_axis_v3v3v3_v3(far, cent, vert_arr[i]->co, nor);
vang[i].data = i;
+ vert_arr_map[i] = vert_arr[i];
}
/* sort by angle and magic! - we have our ngon */
@@ -497,14 +476,9 @@ BMFace *BM_face_create_ngon_vcloud(
/* --- */
- /* create edges and find the winding (if faces are attached to any existing edges) */
for (i = 0; i < len; i++) {
- vert_arr_map[i] = vert_arr[vang[i].data];
+ vert_arr[i] = vert_arr_map[vang[i].data];
}
-
- f = BM_face_create_ngon_verts(bm, vert_arr_map, len, f_example, create_flag, true, true);
-
- return f;
}
/*************************************************************/
@@ -626,7 +600,7 @@ void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src, void
BM_elem_attrs_copy_ex(bm_src, bm_dst, ele_src, ele_dst, BM_ELEM_SELECT);
}
-void BM_elem_select_copy(BMesh *bm_dst, BMesh *UNUSED(bm_src), void *ele_dst_v, const void *ele_src_v)
+void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v)
{
BMHeader *ele_dst = ele_dst_v;
const BMHeader *ele_src = ele_src_v;
diff --git a/source/blender/bmesh/intern/bmesh_construct.h b/source/blender/bmesh/intern/bmesh_construct.h
index 06bc5465a19..a52a17cd2f3 100644
--- a/source/blender/bmesh/intern/bmesh_construct.h
+++ b/source/blender/bmesh/intern/bmesh_construct.h
@@ -34,6 +34,9 @@ bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, const int len);
bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len);
void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr, const int len);
+/* sort before creation */
+void BM_verts_sort_radial_plane(BMVert **vert_arr, int len);
+
BMFace *BM_face_create_quad_tri(
BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
const BMFace *f_example, const eBMCreateFlag create_flag);
@@ -50,15 +53,11 @@ BMFace *BM_face_create_ngon_verts(
const BMFace *f_example, const eBMCreateFlag create_flag,
const bool calc_winding, const bool create_edges);
-BMFace *BM_face_create_ngon_vcloud(
- BMesh *bm, BMVert **vert_arr, int len,
- const BMFace *f_example, const eBMCreateFlag create_flag);
-
void BM_elem_attrs_copy_ex(
BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v,
const char hflag_mask);
void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v);
-void BM_elem_select_copy(BMesh *bm_dst, BMesh *bm_src, void *ele_dst_v, const void *ele_src_v);
+void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v);
void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const struct BMAllocTemplate *allocsize);
BMesh *BM_mesh_copy(BMesh *bm_old);
diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c
index e83b752947c..4fe14fdf5c9 100644
--- a/source/blender/bmesh/intern/bmesh_core.c
+++ b/source/blender/bmesh/intern/bmesh_core.c
@@ -287,7 +287,7 @@ static BMLoop *bm_face_boundary_add(
#endif
BMLoop *l = bm_loop_create(bm, startv, starte, f, NULL /* starte->l */, create_flag);
- bmesh_radial_append(starte, l);
+ bmesh_radial_loop_append(starte, l);
#ifdef USE_BMESH_HOLES
lst->first = lst->last = l;
@@ -295,8 +295,6 @@ static BMLoop *bm_face_boundary_add(
#else
f->l_first = l;
#endif
-
- l->f = f;
return l;
}
@@ -446,26 +444,20 @@ BMFace *BM_face_create(
if (create_flag & BM_CREATE_NO_DOUBLE) {
/* Check if face already exists */
- const bool is_overlap = BM_face_exists(verts, len, &f);
- if (is_overlap) {
+ f = BM_face_exists(verts, len);
+ if (f != NULL) {
return f;
}
- else {
- BLI_assert(f == NULL);
- }
}
f = bm_face_create__internal(bm);
startl = lastl = bm_face_boundary_add(bm, f, verts[0], edges[0], create_flag);
-
- startl->v = verts[0];
- startl->e = edges[0];
+
for (i = 1; i < len; i++) {
l = bm_loop_create(bm, verts[i], edges[i], f, NULL /* edges[i]->l */, create_flag);
-
- l->f = f;
- bmesh_radial_append(edges[i], l);
+
+ bmesh_radial_loop_append(edges[i], l);
l->prev = lastl;
lastl->next = l;
@@ -904,7 +896,7 @@ void BM_face_kill(BMesh *bm, BMFace *f)
do {
l_next = l_iter->next;
- bmesh_radial_loop_remove(l_iter, l_iter->e);
+ bmesh_radial_loop_remove(l_iter->e, l_iter);
bm_kill_only_loop(bm, l_iter);
} while ((l_iter = l_next) != l_first);
@@ -949,7 +941,7 @@ void BM_face_kill_loose(BMesh *bm, BMFace *f)
l_next = l_iter->next;
e = l_iter->e;
- bmesh_radial_loop_remove(l_iter, e);
+ bmesh_radial_loop_remove(e, l_iter);
bm_kill_only_loop(bm, l_iter);
if (e->l == NULL) {
@@ -981,23 +973,8 @@ void BM_face_kill_loose(BMesh *bm, BMFace *f)
*/
void BM_edge_kill(BMesh *bm, BMEdge *e)
{
-
- if (e->l) {
- BMLoop *l = e->l, *lnext, *startl = e->l;
-
- do {
- lnext = l->radial_next;
- if (lnext->f == l->f) {
- BM_face_kill(bm, l->f);
- break;
- }
-
- BM_face_kill(bm, l->f);
-
- if (l == lnext)
- break;
- l = lnext;
- } while (l != startl);
+ while (e->l) {
+ BM_face_kill(bm, e->l->f);
}
bmesh_disk_edge_remove(e, e->v1);
@@ -1011,15 +988,8 @@ void BM_edge_kill(BMesh *bm, BMEdge *e)
*/
void BM_vert_kill(BMesh *bm, BMVert *v)
{
- if (v->e) {
- BMEdge *e, *e_next;
-
- e = v->e;
- while (v->e) {
- e_next = bmesh_disk_edge_next(e, v);
- BM_edge_kill(bm, e);
- e = e_next;
- }
+ while (v->e) {
+ BM_edge_kill(bm, v->e);
}
bm_kill_only_vert(bm, v);
@@ -1046,78 +1016,73 @@ static int UNUSED_FUNCTION(bm_loop_length)(BMLoop *l)
* \brief Loop Reverse
*
* Changes the winding order of a face from CW to CCW or vice versa.
- * This euler is a bit peculiar in comparison to others as it is its
- * own inverse.
- *
- * BMESH_TODO: reinsert validation code.
*
* \param cd_loop_mdisp_offset: Cached result of `CustomData_get_offset(&bm->ldata, CD_MDISPS)`.
* \param use_loop_mdisp_flip: When set, flip the Z-depth of the mdisp,
* (use when flipping normals, disable when mirroring, eg: symmetrize).
- *
- * \return Success
*/
-static bool bm_loop_reverse_loop(
+void bmesh_kernel_loop_reverse(
BMesh *bm, BMFace *f,
-#ifdef USE_BMESH_HOLES
- BMLoopList *lst,
-#endif
const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip)
{
+ BMLoop *l_first = f->l_first;
-#ifdef USE_BMESH_HOLES
- BMLoop *l_first = lst->first;
+ /* track previous cycles radial state */
+ BMEdge *e_prev = l_first->prev->e;
+ BMLoop *l_prev_radial_next = l_first->prev->radial_next;
+ BMLoop *l_prev_radial_prev = l_first->prev->radial_prev;
+ bool is_prev_boundary = l_prev_radial_next == l_prev_radial_next->radial_next;
+
+ BMLoop *l_iter = l_first;
+ do {
+ BMEdge *e_iter = l_iter->e;
+ BMLoop *l_iter_radial_next = l_iter->radial_next;
+ BMLoop *l_iter_radial_prev = l_iter->radial_prev;
+ bool is_iter_boundary = l_iter_radial_next == l_iter_radial_next->radial_next;
+
+#if 0
+ bmesh_radial_loop_remove(e_iter, l_iter);
+ bmesh_radial_loop_append(e_prev, l_iter);
#else
- BMLoop *l_first = f->l_first;
-#endif
+ /* inline loop reversal */
+ if (is_prev_boundary) {
+ /* boundary */
+ l_iter->radial_next = l_iter;
+ l_iter->radial_prev = l_iter;
+ }
+ else {
+ /* non-boundary, replace radial links */
+ l_iter->radial_next = l_prev_radial_next;
+ l_iter->radial_prev = l_prev_radial_prev;
+ l_prev_radial_next->radial_prev = l_iter;
+ l_prev_radial_prev->radial_next = l_iter;
+ }
- const int len = f->len;
- BMLoop *l_iter, *oldprev, *oldnext;
- BMEdge **edar = BLI_array_alloca(edar, len);
- int i, j, edok;
+ if (e_iter->l == l_iter) {
+ e_iter->l = l_iter->next;
+ }
+ l_iter->e = e_prev;
+#endif
- for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) {
- bmesh_radial_loop_remove(l_iter, (edar[i] = l_iter->e));
- }
+ SWAP(BMLoop *, l_iter->next, l_iter->prev);
- /* actually reverse the loop */
- for (i = 0, l_iter = l_first; i < len; i++) {
- oldnext = l_iter->next;
- oldprev = l_iter->prev;
- l_iter->next = oldprev;
- l_iter->prev = oldnext;
- l_iter = oldnext;
-
if (cd_loop_mdisp_offset != -1) {
MDisps *md = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_mdisp_offset);
BKE_mesh_mdisp_flip(md, use_loop_mdisp_flip);
}
- }
- if (len == 2) { /* two edged face */
- /* do some verification here! */
- l_first->e = edar[1];
- l_first->next->e = edar[0];
- }
- else {
- for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) {
- edok = 0;
- for (j = 0; j < len; j++) {
- edok = BM_verts_in_edge(l_iter->v, l_iter->next->v, edar[j]);
- if (edok) {
- l_iter->e = edar[j];
- break;
- }
- }
- }
- }
- /* rebuild radial */
- for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next)
- bmesh_radial_append(l_iter->e, l_iter);
+ e_prev = e_iter;
+ l_prev_radial_next = l_iter_radial_next;
+ l_prev_radial_prev = l_iter_radial_prev;
+ is_prev_boundary = is_iter_boundary;
+
+ /* step to next (now swapped) */
+ } while ((l_iter = l_iter->prev) != l_first);
#ifndef NDEBUG
/* validate radial */
- for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) {
+ int i;
+ for (i = 0, l_iter = l_first; i < f->len; i++, l_iter = l_iter->next) {
BM_CHECK_ELEMENT(l_iter);
BM_CHECK_ELEMENT(l_iter->e);
BM_CHECK_ELEMENT(l_iter->v);
@@ -1129,22 +1094,6 @@ static bool bm_loop_reverse_loop(
/* Loop indices are no more valid! */
bm->elem_index_dirty |= BM_LOOP;
-
- return true;
-}
-
-/**
- * \brief Flip the faces direction
- */
-bool bmesh_loop_reverse(
- BMesh *bm, BMFace *f,
- const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip)
-{
-#ifdef USE_BMESH_HOLES
- return bm_loop_reverse_loop(bm, f, f->loops.first, cd_loop_mdisp_offset, use_loop_mdisp_flip);
-#else
- return bm_loop_reverse_loop(bm, f, cd_loop_mdisp_offset, use_loop_mdisp_flip);
-#endif
}
static void bm_elements_systag_enable(void *veles, int tot, const char api_flag)
@@ -1193,7 +1142,11 @@ static int UNUSED_FUNCTION(bm_vert_systag_count_disk)(BMVert *v, const char api_
return i;
}
-static bool disk_is_flagged(BMVert *v, const char api_flag)
+/**
+ * Return true when the vertex is manifold,
+ * attached to faces which are all flagged.
+ */
+static bool bm_vert_is_manifold_flagged(BMVert *v, const char api_flag)
{
BMEdge *e = v->e;
@@ -1252,7 +1205,7 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
BLI_array_staticdeclare(deledges, BM_DEFAULT_NGON_STACK_SIZE);
BLI_array_staticdeclare(delverts, BM_DEFAULT_NGON_STACK_SIZE);
BMVert *v1 = NULL, *v2 = NULL;
- int i, tote = 0;
+ int i;
const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
if (UNLIKELY(!totface)) {
@@ -1282,13 +1235,10 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
v1 = l_iter->v;
v2 = BM_edge_other_vert(l_iter->e, l_iter->v);
}
- tote++;
}
else if (rlen == 2) {
- int d1, d2;
-
- d1 = disk_is_flagged(l_iter->e->v1, _FLAG_JF);
- d2 = disk_is_flagged(l_iter->e->v2, _FLAG_JF);
+ const bool d1 = bm_vert_is_manifold_flagged(l_iter->e->v1, _FLAG_JF);
+ const bool d2 = bm_vert_is_manifold_flagged(l_iter->e->v2, _FLAG_JF);
if (!d1 && !d2 && !BM_ELEM_API_FLAG_TEST(l_iter->e, _FLAG_JF)) {
/* don't remove an edge it makes up the side of another face
@@ -1332,7 +1282,8 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
}
/* create region face */
- f_new = tote ? BM_face_create_ngon(bm, v1, v2, edges, tote, faces[0], BM_CREATE_NOP) : NULL;
+ f_new = BLI_array_count(edges) ?
+ BM_face_create_ngon(bm, v1, v2, edges, BLI_array_count(edges), faces[0], BM_CREATE_NOP) : NULL;
if (UNLIKELY(f_new == NULL)) {
/* Invalid boundary region to join faces */
goto error;
@@ -1350,10 +1301,11 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
} while (l2 != l_iter);
if (l2 != l_iter) {
- /* I think this is correct? */
+ /* loops share an edge, shared vert depends on winding */
if (l2->v != l_iter->v) {
l2 = l2->next;
}
+ BLI_assert(l_iter->v == l2->v);
BM_elem_attrs_copy(bm, bm, l2, l_iter);
}
@@ -1362,22 +1314,15 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
#ifdef USE_BMESH_HOLES
/* add holes */
BLI_movelisttolist(&f_new->loops, &holes);
-#endif
/* update loop face pointer */
-#ifdef USE_BMESH_HOLES
- for (lst = f_new->loops.first; lst; lst = lst->next)
-#endif
- {
-#ifdef USE_BMESH_HOLES
+ for (lst = f_new->loops.first; lst; lst = lst->next) {
l_iter = l_first = lst->first;
-#else
- l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
-#endif
do {
l_iter->f = f_new;
} while ((l_iter = l_iter->next) != l_first);
}
+#endif
bm_elements_systag_disable(faces, totface, _FLAG_JF);
BM_ELEM_API_FLAG_DISABLE(f_new, _FLAG_JF);
@@ -1493,7 +1438,7 @@ static BMFace *bm_face_create__sfme(BMesh *bm, BMFace *f_example)
*
* \return A BMFace pointer
*/
-BMFace *bmesh_sfme(
+BMFace *bmesh_kernel_split_face_make_edge(
BMesh *bm, BMFace *f, BMLoop *l_v1, BMLoop *l_v2,
BMLoop **r_l,
#ifdef USE_BMESH_HOLES
@@ -1585,8 +1530,8 @@ BMFace *bmesh_sfme(
} while ((l_iter = l_iter->next) != l_first);
/* link up the new loops into the new edges radial */
- bmesh_radial_append(e, l_f1);
- bmesh_radial_append(e, l_f2);
+ bmesh_radial_loop_append(e, l_f1);
+ bmesh_radial_loop_append(e, l_f2);
f2->len = f2len;
@@ -1639,7 +1584,7 @@ BMFace *bmesh_sfme(
*
* \return The newly created BMVert pointer.
*/
-BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e)
+BMVert *bmesh_kernel_split_edge_make_vert(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e)
{
BMLoop *l_next;
BMEdge *e_new;
@@ -1693,18 +1638,18 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e)
#ifndef NDEBUG
int radlen = bmesh_radial_length(l_next);
#endif
- int first1 = 0, first2 = 0;
+ bool is_first = true;
/* Take the next loop. Remove it from radial. Split it. Append to appropriate radials */
while (l_next) {
l = l_next;
l->f->len++;
l_next = l_next != l_next->radial_next ? l_next->radial_next : NULL;
- bmesh_radial_loop_remove(l, NULL);
+ bmesh_radial_loop_unlink(l);
l_new = bm_loop_create(bm, NULL, NULL, l->f, l, 0);
l_new->prev = l;
- l_new->next = (l->next);
+ l_new->next = l->next;
l_new->prev->next = l_new;
l_new->next->prev = l_new;
l_new->v = v_new;
@@ -1715,36 +1660,26 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e)
l->e = e_new;
/* append l into e_new's rad cycle */
- if (!first1) {
- first1 = 1;
- l->radial_next = l->radial_prev = NULL;
- }
-
- if (!first2) {
- first2 = 1;
+ if (is_first) {
+ is_first = false;
l->radial_next = l->radial_prev = NULL;
}
- bmesh_radial_append(l_new->e, l_new);
- bmesh_radial_append(l->e, l);
+ bmesh_radial_loop_append(l_new->e, l_new);
+ bmesh_radial_loop_append(l->e, l);
}
else if (BM_verts_in_edge(l_new->v, l_new->next->v, e_new)) {
l_new->e = e_new;
l->e = e;
/* append l into e_new's rad cycle */
- if (!first1) {
- first1 = 1;
- l->radial_next = l->radial_prev = NULL;
- }
-
- if (!first2) {
- first2 = 1;
+ if (is_first) {
+ is_first = false;
l->radial_next = l->radial_prev = NULL;
}
- bmesh_radial_append(l_new->e, l_new);
- bmesh_radial_append(l->e, l);
+ bmesh_radial_loop_append(l_new->e, l_new);
+ bmesh_radial_loop_append(l->e, l);
}
}
@@ -1831,7 +1766,7 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e)
* faces with just 2 edges. It is up to the caller to decide what to do with
* these faces.
*/
-BMEdge *bmesh_jekv(
+BMEdge *bmesh_kernel_join_edge_kill_vert(
BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
const bool do_del, const bool check_edge_double,
const bool kill_degenerate_faces)
@@ -1839,7 +1774,6 @@ BMEdge *bmesh_jekv(
BMEdge *e_old;
BMVert *v_old, *v_target;
BMLoop *l_kill;
- bool halt = false;
#ifndef NDEBUG
int radlen, i;
bool edok;
@@ -1860,9 +1794,9 @@ BMEdge *bmesh_jekv(
e_old = bmesh_disk_edge_next(e_kill, v_kill);
v_target = BM_edge_other_vert(e_kill, v_kill);
v_old = BM_edge_other_vert(e_old, v_kill);
- halt = BM_verts_in_edge(v_kill, v_target, e_old); /* check for double edges */
-
- if (halt) {
+
+ /* check for double edges */
+ if (BM_verts_in_edge(v_kill, v_target, e_old)) {
return NULL;
}
else {
@@ -1986,7 +1920,7 @@ BMEdge *bmesh_jekv(
*
* Collapse an edge, merging surrounding data.
*
- * Unlike #BM_vert_collapse_edge & #bmesh_jekv which only handle 2 valence verts,
+ * Unlike #BM_vert_collapse_edge & #bmesh_kernel_join_edge_kill_vert which only handle 2 valence verts,
* this can handle any number of connected edges/faces.
*
* <pre>
@@ -1998,7 +1932,7 @@ BMEdge *bmesh_jekv(
* +-+-+-+ +-+-+-+
* </pre>
*/
-BMVert *bmesh_jvke(
+BMVert *bmesh_kernel_join_vert_kill_edge(
BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
const bool do_del, const bool check_edge_double,
const bool kill_degenerate_faces)
@@ -2101,7 +2035,7 @@ BMVert *bmesh_jvke(
* In the example A, faces \a f1 and \a f2 are joined by a single edge,
* and the euler can safely be used.
* In example B however, \a f1 and \a f2 are joined by multiple edges and will produce an error.
- * The caller in this case should call #bmesh_jekv on the extra edges
+ * The caller in this case should call #bmesh_kernel_join_edge_kill_vert on the extra edges
* before attempting to fuse \a f1 and \a f2.
*
* \note The order of arguments decides whether or not certain per-face attributes are present
@@ -2110,7 +2044,7 @@ BMVert *bmesh_jvke(
*
* \return A BMFace pointer
*/
-BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
+BMFace *bmesh_kernel_join_face_kill_edge(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
{
BMLoop *l_iter, *l_f1 = NULL, *l_f2 = NULL;
int newlen = 0, i, f1len = 0, f2len = 0;
@@ -2315,7 +2249,7 @@ bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src)
}
-/** \name BM_vert_separate, bmesh_vert_separate and friends
+/** \name BM_vert_separate, bmesh_kernel_vert_separate and friends
* \{ */
/* BM_edge_face_count(e) >= 1 */
@@ -2335,7 +2269,7 @@ BLI_INLINE bool bm_edge_supports_separate(const BMEdge *e)
*
* \return Success
*/
-void bmesh_vert_separate(
+void bmesh_kernel_vert_separate(
BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len,
const bool copy_select)
{
@@ -2413,7 +2347,7 @@ void bmesh_vert_separate(
v_new = BM_vert_create(bm, v->co, v, BM_CREATE_NOP);
if (copy_select) {
- BM_elem_select_copy(bm, bm, v_new, v);
+ BM_elem_select_copy(bm, v_new, v);
}
while ((e = BLI_SMALLSTACK_POP(edges))) {
@@ -2451,7 +2385,7 @@ void bmesh_vert_separate(
*
* Takes a list of edges, which have been split from their original.
*
- * Any edges which failed to split off in #bmesh_vert_separate will be merged back into the original edge.
+ * Any edges which failed to split off in #bmesh_kernel_vert_separate will be merged back into the original edge.
*
* \param edges_separate
* A list-of-lists, each list is from a single original edge (the first edge is the original),
@@ -2464,24 +2398,24 @@ void bmesh_vert_separate(
* \note this function looks like it could become slow,
* but in common cases its only going to iterate a few times.
*/
-static void bmesh_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separate)
+static void bmesh_kernel_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separate)
{
do {
LinkNode *n_orig = edges_separate->link;
do {
- BMEdge *e_orig = n_orig->link;
- LinkNode *n_step = n_orig->next;
LinkNode *n_prev = n_orig;
+ LinkNode *n_step = n_orig->next;
+ BMEdge *e_orig = n_orig->link;
do {
BMEdge *e = n_step->link;
BLI_assert(e != e_orig);
- if ((e->v1 == e_orig->v1) && (e->v2 == e_orig->v2)) {
- BM_edge_splice(bm, e_orig, e);
+ if ((e->v1 == e_orig->v1) && (e->v2 == e_orig->v2) &&
+ BM_edge_splice(bm, e_orig, e))
+ {
+ /* don't visit again */
n_prev->next = n_step->next;
- n_step = n_prev;
}
- } while ((void)
- (n_prev = n_step),
+ } while ((n_prev = n_step),
(n_step = n_step->next));
} while ((n_orig = n_orig->next) && n_orig->next);
@@ -2489,7 +2423,7 @@ static void bmesh_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separate)
}
/**
- * High level function which wraps both #bmesh_vert_separate and #bmesh_edge_separate
+ * High level function which wraps both #bmesh_kernel_vert_separate and #bmesh_kernel_edge_separate
*/
void BM_vert_separate(
BMesh *bm, BMVert *v,
@@ -2506,7 +2440,7 @@ void BM_vert_separate(
LinkNode *edges_orig = NULL;
do {
BMLoop *l_sep = e->l;
- bmesh_edge_separate(bm, e, l_sep, copy_select);
+ bmesh_kernel_edge_separate(bm, e, l_sep, copy_select);
BLI_linklist_prepend_alloca(&edges_orig, l_sep->e);
BLI_assert(e != l_sep->e);
} while (bm_edge_supports_separate(e));
@@ -2515,10 +2449,10 @@ void BM_vert_separate(
}
}
- bmesh_vert_separate(bm, v, r_vout, r_vout_len, copy_select);
+ bmesh_kernel_vert_separate(bm, v, r_vout, r_vout_len, copy_select);
if (edges_separate) {
- bmesh_vert_separate__cleanup(bm, edges_separate);
+ bmesh_kernel_vert_separate__cleanup(bm, edges_separate);
}
}
@@ -2543,7 +2477,7 @@ void BM_vert_separate_hflag(
LinkNode *edges_orig = NULL;
do {
BMLoop *l_sep = e->l;
- bmesh_edge_separate(bm, e, l_sep, copy_select);
+ bmesh_kernel_edge_separate(bm, e, l_sep, copy_select);
/* trick to avoid looping over separated edges */
if (edges_separate == NULL && edges_orig == NULL) {
e_first = l_sep->e;
@@ -2557,10 +2491,10 @@ void BM_vert_separate_hflag(
}
} while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first);
- bmesh_vert_separate(bm, v, r_vout, r_vout_len, copy_select);
+ bmesh_kernel_vert_separate(bm, v, r_vout, r_vout_len, copy_select);
if (edges_separate) {
- bmesh_vert_separate__cleanup(bm, edges_separate);
+ bmesh_kernel_vert_separate__cleanup(bm, edges_separate);
}
}
@@ -2619,8 +2553,8 @@ bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src)
l = e_src->l;
BLI_assert(BM_vert_in_edge(e_dst, l->v));
BLI_assert(BM_vert_in_edge(e_dst, l->next->v));
- bmesh_radial_loop_remove(l, e_src);
- bmesh_radial_append(e_dst, l);
+ bmesh_radial_loop_remove(e_src, l);
+ bmesh_radial_loop_append(e_dst, l);
}
BLI_assert(bmesh_radial_length(e_src->l) == 0);
@@ -2645,7 +2579,7 @@ bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src)
* \note Does nothing if \a l_sep is already the only loop in the
* edge radial.
*/
-void bmesh_edge_separate(
+void bmesh_kernel_edge_separate(
BMesh *bm, BMEdge *e, BMLoop *l_sep,
const bool copy_select)
{
@@ -2667,12 +2601,12 @@ void bmesh_edge_separate(
}
e_new = BM_edge_create(bm, e->v1, e->v2, e, BM_CREATE_NOP);
- bmesh_radial_loop_remove(l_sep, e);
- bmesh_radial_append(e_new, l_sep);
+ bmesh_radial_loop_remove(e, l_sep);
+ bmesh_radial_loop_append(e_new, l_sep);
l_sep->e = e_new;
if (copy_select) {
- BM_elem_select_copy(bm, bm, e_new, e);
+ BM_elem_select_copy(bm, e_new, e);
}
BLI_assert(bmesh_radial_length(e->l) == radlen - 1);
@@ -2691,7 +2625,7 @@ void bmesh_edge_separate(
*
* \note Will be a no-op and return original vertex if only two edges at that vertex.
*/
-BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *l_sep)
+BMVert *bmesh_kernel_unglue_region_make_vert(BMesh *bm, BMLoop *l_sep)
{
BMVert *v_new = NULL;
BMVert *v_sep = l_sep->v;
@@ -2701,10 +2635,12 @@ BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *l_sep)
/* peel the face from the edge radials on both sides of the
* loop vert, disconnecting the face from its fan */
- if (!BM_edge_is_boundary(l_sep->e))
- bmesh_edge_separate(bm, l_sep->e, l_sep, false);
- if (!BM_edge_is_boundary(l_sep->prev->e))
- bmesh_edge_separate(bm, l_sep->prev->e, l_sep->prev, false);
+ if (!BM_edge_is_boundary(l_sep->e)) {
+ bmesh_kernel_edge_separate(bm, l_sep->e, l_sep, false);
+ }
+ if (!BM_edge_is_boundary(l_sep->prev->e)) {
+ bmesh_kernel_edge_separate(bm, l_sep->prev->e, l_sep->prev, false);
+ }
/* do inline, below */
#if 0
@@ -2752,19 +2688,23 @@ BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *l_sep)
}
/**
- * A version of #bmesh_urmv_loop that disconnects multiple loops at once.
+ * A version of #bmesh_kernel_unglue_region_make_vert that disconnects multiple loops at once.
+ * The loops must all share the same vertex, can be in any order
+ * and are all moved to use a single new vertex - which is returned.
*
- * Handles the task of finding fans boundaries.
+ * This function handles the details of finding fans boundaries.
*/
-BMVert *bmesh_urmv_loop_multi(
+BMVert *bmesh_kernel_unglue_region_make_vert_multi(
BMesh *bm, BMLoop **larr, int larr_len)
{
BMVert *v_sep = larr[0]->v;
BMVert *v_new;
+ int edges_len = 0;
int i;
- bool is_mixed_any = false;
-
- BLI_SMALLSTACK_DECLARE(edges, BMEdge *);
+ /* any edges not owned by 'larr' loops connected to 'v_sep'? */
+ bool is_mixed_edge_any = false;
+ /* any loops not owned by 'larr' radially connected to 'larr' loop edges? */
+ bool is_mixed_loop_any = false;
#define LOOP_VISIT _FLAG_WALK
#define EDGE_VISIT _FLAG_WALK
@@ -2782,58 +2722,74 @@ BMVert *bmesh_urmv_loop_multi(
* while doing a radial loop (where loops may be adjacent) */
BM_ELEM_API_FLAG_ENABLE(l_sep->next, LOOP_VISIT);
BM_ELEM_API_FLAG_ENABLE(l_sep->prev, LOOP_VISIT);
- }
-
- for (i = 0; i < larr_len; i++) {
- BMLoop *l_sep = larr[i];
BMLoop *loop_pair[2] = {l_sep, l_sep->prev};
- int j;
- for (j = 0; j < ARRAY_SIZE(loop_pair); j++) {
+ for (int j = 0; j < ARRAY_SIZE(loop_pair); j++) {
BMEdge *e = loop_pair[j]->e;
if (!BM_ELEM_API_FLAG_TEST(e, EDGE_VISIT)) {
- BMLoop *l_iter, *l_first;
- bool is_mixed = false;
-
BM_ELEM_API_FLAG_ENABLE(e, EDGE_VISIT);
+ edges_len += 1;
+ }
+ }
+ }
- l_iter = l_first = e->l;
+ BMEdge **edges = BLI_array_alloca(edges, edges_len);
+ STACK_DECLARE(edges);
+
+ STACK_INIT(edges, edges_len);
+
+ {
+ BMEdge *e_first, *e_iter;
+ e_iter = e_first = v_sep->e;
+ do {
+ if (BM_ELEM_API_FLAG_TEST(e_iter, EDGE_VISIT)) {
+ BMLoop *l_iter, *l_first;
+ bool is_mixed_loop = false;
+
+ l_iter = l_first = e_iter->l;
do {
if (!BM_ELEM_API_FLAG_TEST(l_iter, LOOP_VISIT)) {
- is_mixed = true;
- is_mixed_any = true;
+ is_mixed_loop = true;
break;
}
} while ((l_iter = l_iter->radial_next) != l_first);
- if (is_mixed) {
+ if (is_mixed_loop) {
/* ensure the first loop is one we don't own so we can do a quick check below
* on the edge's loop-flag to see if the edge is mixed or not. */
- e->l = l_iter;
+ e_iter->l = l_iter;
+
+ is_mixed_loop_any = true;
}
- BLI_SMALLSTACK_PUSH(edges, e);
+
+ STACK_PUSH(edges, e_iter);
}
- }
+ else {
+ /* at least one edge attached isn't connected to our loops */
+ is_mixed_edge_any = true;
+ }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v_sep)) != e_first);
}
- if (is_mixed_any == false) {
+ BLI_assert(edges_len == STACK_SIZE(edges));
+
+ if (is_mixed_loop_any == false && is_mixed_edge_any == false) {
/* all loops in 'larr' are the sole owners of their edges.
* nothing to split away from, this is a no-op */
v_new = v_sep;
}
else {
- BMEdge *e;
-
- BLI_assert(!BLI_SMALLSTACK_IS_EMPTY(edges));
-
v_new = BM_vert_create(bm, v_sep->co, v_sep, BM_CREATE_NOP);
- while ((e = BLI_SMALLSTACK_POP(edges))) {
+
+ for (i = 0; i < STACK_SIZE(edges); i++) {
+ BMEdge *e = edges[i];
BMLoop *l_iter, *l_first, *l_next;
BMEdge *e_new;
/* disable so copied edge isn't left dirty (loop edges are cleared last too) */
BM_ELEM_API_FLAG_DISABLE(e, EDGE_VISIT);
+ /* will always be false when (is_mixed_loop_any == false) */
if (!BM_ELEM_API_FLAG_TEST(e->l, LOOP_VISIT)) {
/* edge has some loops owned by us, some owned by other loops */
BMVert *e_new_v_pair[2];
@@ -2855,8 +2811,8 @@ BMVert *bmesh_urmv_loop_multi(
do {
l_next = l_iter->radial_next;
if (BM_ELEM_API_FLAG_TEST(l_iter, LOOP_VISIT)) {
- bmesh_radial_loop_remove(l_iter, e);
- bmesh_radial_append(e_new, l_iter);
+ bmesh_radial_loop_remove(e, l_iter);
+ bmesh_radial_loop_append(e_new, l_iter);
l_iter->e = e_new;
}
} while ((l_iter = l_next) != l_first);
@@ -2922,9 +2878,9 @@ static void bmesh_edge_vert_swap__recursive(BMEdge *e, BMVert *v_dst, BMVert *v_
/**
* This function assumes l_sep is apart of a larger fan which has already been
- * isolated by calling bmesh_edge_separate to segregate it radially.
+ * isolated by calling #bmesh_kernel_edge_separate to segregate it radially.
*/
-BMVert *bmesh_urmv_loop_region(BMesh *bm, BMLoop *l_sep)
+BMVert *bmesh_kernel_unglue_region_make_vert_multi_isolated(BMesh *bm, BMLoop *l_sep)
{
BMVert *v_new = BM_vert_create(bm, l_sep->v->co, l_sep->v, BM_CREATE_NOP);
/* passing either 'l_sep->e', 'l_sep->prev->e' will work */
@@ -2933,20 +2889,6 @@ BMVert *bmesh_urmv_loop_region(BMesh *bm, BMLoop *l_sep)
return v_new;
}
-
-/**
- * \brief Unglue Region Make Vert (URMV)
- *
- * Disconnects f_sep from the vertex fan at \a v_sep
- *
- * \return The newly created BMVert
- */
-BMVert *bmesh_urmv(BMesh *bm, BMFace *f_sep, BMVert *v_sep)
-{
- BMLoop *l = BM_face_vert_share_loop(f_sep, v_sep);
- return bmesh_urmv_loop(bm, l);
-}
-
/**
* Avoid calling this where possible,
* low level function so both face pointers remain intact but point to swapped data.
diff --git a/source/blender/bmesh/intern/bmesh_core.h b/source/blender/bmesh/intern/bmesh_core.h
index fb5702bc574..fb6b66809f3 100644
--- a/source/blender/bmesh/intern/bmesh_core.h
+++ b/source/blender/bmesh/intern/bmesh_core.h
@@ -64,21 +64,16 @@ void BM_face_kill(BMesh *bm, BMFace *f);
void BM_edge_kill(BMesh *bm, BMEdge *e);
void BM_vert_kill(BMesh *bm, BMVert *v);
-void bmesh_edge_separate(
- BMesh *bm, BMEdge *e, BMLoop *l_sep,
- const bool copy_select);
bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src);
bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src);
bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b);
-void bmesh_vert_separate(
- BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len,
- const bool copy_select);
-
-bool bmesh_loop_reverse(
+void bmesh_kernel_loop_reverse(
BMesh *bm, BMFace *f,
const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip);
+void bmesh_face_swap_data(BMFace *f_a, BMFace *f_b);
+
BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del);
void BM_vert_separate(
BMesh *bm, BMVert *v, BMEdge **e_in, int e_in_len, const bool copy_select,
@@ -90,34 +85,43 @@ void BM_vert_separate_wire_hflag(
BMesh *bm, BMVert *v_dst, BMVert *v_src,
const char hflag);
-/* EULER API - For modifying structure */
-BMFace *bmesh_sfme(
+/**
+ * BMesh Kernel: For modifying structure.
+ *
+ * Names are on the verbose side but these are only for low-level access.
+ */
+void bmesh_kernel_vert_separate(
+ BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len,
+ const bool copy_select);
+void bmesh_kernel_edge_separate(
+ BMesh *bm, BMEdge *e, BMLoop *l_sep,
+ const bool copy_select);
+
+BMFace *bmesh_kernel_split_face_make_edge(
BMesh *bm, BMFace *f,
BMLoop *l1, BMLoop *l2,
BMLoop **r_l,
#ifdef USE_BMESH_HOLES
- ListBase *holes,
+ ListBase *holes,
#endif
- BMEdge *example,
- const bool no_double
- );
+ BMEdge *example,
+ const bool no_double
+ );
-BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e);
-BMEdge *bmesh_jekv(
+BMVert *bmesh_kernel_split_edge_make_vert(
+ BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e);
+BMEdge *bmesh_kernel_join_edge_kill_vert(
BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
const bool do_del, const bool check_edge_splice,
const bool kill_degenerate_faces);
-BMVert *bmesh_jvke(
+BMVert *bmesh_kernel_join_vert_kill_edge(
BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
const bool do_del, const bool check_edge_double,
const bool kill_degenerate_faces);
-BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e);
-BMVert *bmesh_urmv(BMesh *bm, BMFace *f_sep, BMVert *v_sep);
-BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *l_sep);
-BMVert *bmesh_urmv_loop_multi(
- BMesh *bm, BMLoop **larr, int larr_len);
-BMVert *bmesh_urmv_loop_region(BMesh *bm, BMLoop *l_sep);
+BMFace *bmesh_kernel_join_face_kill_edge(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e);
-void bmesh_face_swap_data(BMFace *f_a, BMFace *f_b);
+BMVert *bmesh_kernel_unglue_region_make_vert(BMesh *bm, BMLoop *l_sep);
+BMVert *bmesh_kernel_unglue_region_make_vert_multi(BMesh *bm, BMLoop **larr, int larr_len);
+BMVert *bmesh_kernel_unglue_region_make_vert_multi_isolated(BMesh *bm, BMLoop *l_sep);
#endif /* __BMESH_CORE_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.c b/source/blender/bmesh/intern/bmesh_edgeloop.c
index 5e1d9c3a98d..5780dc57d78 100644
--- a/source/blender/bmesh/intern/bmesh_edgeloop.c
+++ b/source/blender/bmesh/intern/bmesh_edgeloop.c
@@ -58,7 +58,7 @@ static int bm_vert_other_tag(
{
BMIter iter;
BMEdge *e, *e_next = NULL;
- unsigned int count = 0;
+ uint count = 0;
BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
if (BM_elem_flag_test(e, BM_ELEM_INTERNAL_TAG)) {
diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c
index 1a4b812f87f..5c076f258de 100644
--- a/source/blender/bmesh/intern/bmesh_interp.c
+++ b/source/blender/bmesh/intern/bmesh_interp.c
@@ -339,7 +339,7 @@ static bool mdisp_in_mdispquad(
compute_mdisp_quad(l_dst, l_dst_f_center, v1, v2, v3, v4, e1, e2);
/* expand quad a bit */
- cent_quad_v3(c, v1, v2, v3, v4);
+ mid_v3_v3v3v3v3(c, v1, v2, v3, v4);
sub_v3_v3(v1, c); sub_v3_v3(v2, c);
sub_v3_v3(v3, c); sub_v3_v3(v4, c);
diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c
index 961b10d848a..96154f051f9 100644
--- a/source/blender/bmesh/intern/bmesh_iterators.c
+++ b/source/blender/bmesh/intern/bmesh_iterators.c
@@ -485,9 +485,9 @@ void bmiter__face_of_vert_begin(struct BMIter__face_of_vert *iter)
{
((BMIter *)iter)->count = bmesh_disk_facevert_count(iter->vdata);
if (((BMIter *)iter)->count) {
- iter->e_first = bmesh_disk_faceedge_find_first(iter->vdata->e, iter->vdata);
+ iter->l_first = bmesh_disk_faceloop_find_first(iter->vdata->e, iter->vdata);
+ iter->e_first = iter->l_first->e;
iter->e_next = iter->e_first;
- iter->l_first = bmesh_radial_faceloop_find_first(iter->e_first->l, iter->vdata);
iter->l_next = iter->l_first;
}
else {
@@ -526,9 +526,9 @@ void bmiter__loop_of_vert_begin(struct BMIter__loop_of_vert *iter)
{
((BMIter *)iter)->count = bmesh_disk_facevert_count(iter->vdata);
if (((BMIter *)iter)->count) {
- iter->e_first = bmesh_disk_faceedge_find_first(iter->vdata->e, iter->vdata);
+ iter->l_first = bmesh_disk_faceloop_find_first(iter->vdata->e, iter->vdata);
+ iter->e_first = iter->l_first->e;
iter->e_next = iter->e_first;
- iter->l_first = bmesh_radial_faceloop_find_first(iter->e_first->l, iter->vdata);
iter->l_next = iter->l_first;
}
else {
diff --git a/source/blender/bmesh/intern/bmesh_iterators.h b/source/blender/bmesh/intern/bmesh_iterators.h
index 0551d824131..ab066682081 100644
--- a/source/blender/bmesh/intern/bmesh_iterators.h
+++ b/source/blender/bmesh/intern/bmesh_iterators.h
@@ -211,12 +211,12 @@ void *BMO_iter_as_arrayN(
int BM_iter_mesh_bitmap_from_filter(
const char itype, BMesh *bm,
- unsigned int *bitmap,
+ uint *bitmap,
bool (*test_fn)(BMElem *, void *user_data),
void *user_data);
int BM_iter_mesh_bitmap_from_filter_tessface(
BMesh *bm,
- unsigned int *bitmap,
+ uint *bitmap,
bool (*test_fn)(BMFace *, void *user_data),
void *user_data);
diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c
index 1f64f7b74cc..1d16dbc1836 100644
--- a/source/blender/bmesh/intern/bmesh_log.c
+++ b/source/blender/bmesh/intern/bmesh_log.c
@@ -45,7 +45,7 @@
#include "bmesh.h"
#include "bmesh_log.h"
-#include "range_tree_c_api.h"
+#include "range_tree.h"
#include "BLI_strict_flags.h"
@@ -88,7 +88,7 @@ struct BMLog {
/* Mapping from unique IDs to vertices and faces
*
- * Each vertex and face in the log gets a unique unsigned integer
+ * Each vertex and face in the log gets a unique uinteger
* assigned. That ID is taken from the set managed by the
* unused_ids range tree.
*
@@ -120,7 +120,7 @@ typedef struct {
} BMLogVert;
typedef struct {
- unsigned int v_ids[3];
+ uint v_ids[3];
char hflag;
} BMLogFace;
@@ -131,14 +131,14 @@ typedef struct {
#define logkey_cmp BLI_ghashutil_intcmp
/* Get the vertex's unique ID from the log */
-static unsigned int bm_log_vert_id_get(BMLog *log, BMVert *v)
+static uint bm_log_vert_id_get(BMLog *log, BMVert *v)
{
BLI_assert(BLI_ghash_haskey(log->elem_to_id, v));
return GET_UINT_FROM_POINTER(BLI_ghash_lookup(log->elem_to_id, v));
}
/* Set the vertex's unique ID in the log */
-static void bm_log_vert_id_set(BMLog *log, BMVert *v, unsigned int id)
+static void bm_log_vert_id_set(BMLog *log, BMVert *v, uint id)
{
void *vid = SET_UINT_IN_POINTER(id);
@@ -147,7 +147,7 @@ static void bm_log_vert_id_set(BMLog *log, BMVert *v, unsigned int id)
}
/* Get a vertex from its unique ID */
-static BMVert *bm_log_vert_from_id(BMLog *log, unsigned int id)
+static BMVert *bm_log_vert_from_id(BMLog *log, uint id)
{
void *key = SET_UINT_IN_POINTER(id);
BLI_assert(BLI_ghash_haskey(log->id_to_elem, key));
@@ -155,14 +155,14 @@ static BMVert *bm_log_vert_from_id(BMLog *log, unsigned int id)
}
/* Get the face's unique ID from the log */
-static unsigned int bm_log_face_id_get(BMLog *log, BMFace *f)
+static uint bm_log_face_id_get(BMLog *log, BMFace *f)
{
BLI_assert(BLI_ghash_haskey(log->elem_to_id, f));
return GET_UINT_FROM_POINTER(BLI_ghash_lookup(log->elem_to_id, f));
}
/* Set the face's unique ID in the log */
-static void bm_log_face_id_set(BMLog *log, BMFace *f, unsigned int id)
+static void bm_log_face_id_set(BMLog *log, BMFace *f, uint id)
{
void *fid = SET_UINT_IN_POINTER(id);
@@ -171,7 +171,7 @@ static void bm_log_face_id_set(BMLog *log, BMFace *f, unsigned int id)
}
/* Get a face from its unique ID */
-static BMFace *bm_log_face_from_id(BMLog *log, unsigned int id)
+static BMFace *bm_log_face_from_id(BMLog *log, uint id)
{
void *key = SET_UINT_IN_POINTER(id);
BLI_assert(BLI_ghash_haskey(log->id_to_elem, key));
@@ -255,7 +255,7 @@ static void bm_log_verts_unmake(BMesh *bm, BMLog *log, GHash *verts)
GHASH_ITER (gh_iter, verts) {
void *key = BLI_ghashIterator_getKey(&gh_iter);
BMLogVert *lv = BLI_ghashIterator_getValue(&gh_iter);
- unsigned int id = GET_UINT_FROM_POINTER(key);
+ uint id = GET_UINT_FROM_POINTER(key);
BMVert *v = bm_log_vert_from_id(log, id);
/* Ensure the log has the final values of the vertex before
@@ -271,7 +271,7 @@ static void bm_log_faces_unmake(BMesh *bm, BMLog *log, GHash *faces)
GHashIterator gh_iter;
GHASH_ITER (gh_iter, faces) {
void *key = BLI_ghashIterator_getKey(&gh_iter);
- unsigned int id = GET_UINT_FROM_POINTER(key);
+ uint id = GET_UINT_FROM_POINTER(key);
BMFace *f = bm_log_face_from_id(log, id);
BMEdge *e_tri[3];
BMLoop *l_iter;
@@ -333,7 +333,7 @@ static void bm_log_vert_values_swap(BMesh *bm, BMLog *log, GHash *verts)
GHASH_ITER (gh_iter, verts) {
void *key = BLI_ghashIterator_getKey(&gh_iter);
BMLogVert *lv = BLI_ghashIterator_getValue(&gh_iter);
- unsigned int id = GET_UINT_FROM_POINTER(key);
+ uint id = GET_UINT_FROM_POINTER(key);
BMVert *v = bm_log_vert_from_id(log, id);
float mask;
short normal[3];
@@ -355,7 +355,7 @@ static void bm_log_face_values_swap(BMLog *log, GHash *faces)
GHASH_ITER (gh_iter, faces) {
void *key = BLI_ghashIterator_getKey(&gh_iter);
BMLogFace *lf = BLI_ghashIterator_getValue(&gh_iter);
- unsigned int id = GET_UINT_FROM_POINTER(key);
+ uint id = GET_UINT_FROM_POINTER(key);
BMFace *f = bm_log_face_from_id(log, id);
SWAP(char, f->head.hflag, lf->hflag);
@@ -374,13 +374,13 @@ static void bm_log_assign_ids(BMesh *bm, BMLog *log)
/* Generate vertex IDs */
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- unsigned int id = range_tree_uint_take_any(log->unused_ids);
+ uint id = range_tree_uint_take_any(log->unused_ids);
bm_log_vert_id_set(log, v, id);
}
/* Generate face IDs */
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- unsigned int id = range_tree_uint_take_any(log->unused_ids);
+ uint id = range_tree_uint_take_any(log->unused_ids);
bm_log_face_id_set(log, f, id);
}
}
@@ -425,7 +425,7 @@ static void bm_log_id_ghash_retake(RangeTreeUInt *unused_ids, GHash *id_ghash)
GHASH_ITER (gh_iter, id_ghash) {
void *key = BLI_ghashIterator_getKey(&gh_iter);
- unsigned int id = GET_UINT_FROM_POINTER(key);
+ uint id = GET_UINT_FROM_POINTER(key);
range_tree_uint_retake(unused_ids, id);
}
@@ -433,8 +433,8 @@ static void bm_log_id_ghash_retake(RangeTreeUInt *unused_ids, GHash *id_ghash)
static int uint_compare(const void *a_v, const void *b_v)
{
- const unsigned int *a = a_v;
- const unsigned int *b = b_v;
+ const uint *a = a_v;
+ const uint *b = b_v;
return (*a) < (*b);
}
@@ -446,10 +446,10 @@ static int uint_compare(const void *a_v, const void *b_v)
* 10 -> 3
* 3 -> 1
*/
-static GHash *bm_log_compress_ids_to_indices(unsigned int *ids, unsigned int totid)
+static GHash *bm_log_compress_ids_to_indices(uint *ids, uint totid)
{
GHash *map = BLI_ghash_int_new_ex(__func__, totid);
- unsigned int i;
+ uint i;
qsort(ids, totid, sizeof(*ids), uint_compare);
@@ -469,7 +469,7 @@ static void bm_log_id_ghash_release(BMLog *log, GHash *id_ghash)
GHASH_ITER (gh_iter, id_ghash) {
void *key = BLI_ghashIterator_getKey(&gh_iter);
- unsigned int id = GET_UINT_FROM_POINTER(key);
+ uint id = GET_UINT_FROM_POINTER(key);
range_tree_uint_release(log->unused_ids, id);
}
}
@@ -480,7 +480,7 @@ static void bm_log_id_ghash_release(BMLog *log, GHash *id_ghash)
BMLog *BM_log_create(BMesh *bm)
{
BMLog *log = MEM_callocN(sizeof(*log), __func__);
- const unsigned int reserve_num = (unsigned int)(bm->totvert + bm->totface);
+ const uint reserve_num = (uint)(bm->totvert + bm->totface);
log->unused_ids = range_tree_uint_alloc(0, (unsigned)-1);
log->id_to_elem = BLI_ghash_new_ex(logkey_hash, logkey_cmp, __func__, reserve_num);
@@ -593,8 +593,8 @@ int BM_log_length(const BMLog *log)
/* Apply a consistent ordering to BMesh vertices */
void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
{
- unsigned int *varr;
- unsigned int *farr;
+ uint *varr;
+ uint *farr;
GHash *id_to_idx;
@@ -602,7 +602,7 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
BMVert *v;
BMFace *f;
- unsigned int i;
+ uint i;
/* Put all vertex IDs into an array */
varr = MEM_mallocN(sizeof(int) * (size_t)bm->totvert, __func__);
@@ -617,7 +617,7 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
}
/* Create BMVert index remap array */
- id_to_idx = bm_log_compress_ids_to_indices(varr, (unsigned int)bm->totvert);
+ id_to_idx = bm_log_compress_ids_to_indices(varr, (uint)bm->totvert);
BM_ITER_MESH_INDEX (v, &bm_iter, bm, BM_VERTS_OF_MESH, i) {
const unsigned id = bm_log_vert_id_get(log, v);
const void *key = SET_UINT_IN_POINTER(id);
@@ -627,7 +627,7 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
BLI_ghash_free(id_to_idx, NULL, NULL);
/* Create BMFace index remap array */
- id_to_idx = bm_log_compress_ids_to_indices(farr, (unsigned int)bm->totface);
+ id_to_idx = bm_log_compress_ids_to_indices(farr, (uint)bm->totface);
BM_ITER_MESH_INDEX (f, &bm_iter, bm, BM_FACES_OF_MESH, i) {
const unsigned id = bm_log_face_id_get(log, f);
const void *key = SET_UINT_IN_POINTER(id);
@@ -835,7 +835,7 @@ void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_o
{
BMLogEntry *entry = log->current_entry;
BMLogVert *lv;
- unsigned int v_id = bm_log_vert_id_get(log, v);
+ uint v_id = bm_log_vert_id_get(log, v);
void *key = SET_UINT_IN_POINTER(v_id);
void **val_p;
@@ -859,7 +859,7 @@ void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_o
void BM_log_vert_added(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
{
BMLogVert *lv;
- unsigned int v_id = range_tree_uint_take_any(log->unused_ids);
+ uint v_id = range_tree_uint_take_any(log->unused_ids);
void *key = SET_UINT_IN_POINTER(v_id);
bm_log_vert_id_set(log, v, v_id);
@@ -876,7 +876,7 @@ void BM_log_vert_added(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
void BM_log_face_modified(BMLog *log, BMFace *f)
{
BMLogFace *lf;
- unsigned int f_id = bm_log_face_id_get(log, f);
+ uint f_id = bm_log_face_id_get(log, f);
void *key = SET_UINT_IN_POINTER(f_id);
lf = bm_log_face_alloc(log, f);
@@ -892,7 +892,7 @@ void BM_log_face_modified(BMLog *log, BMFace *f)
void BM_log_face_added(BMLog *log, BMFace *f)
{
BMLogFace *lf;
- unsigned int f_id = range_tree_uint_take_any(log->unused_ids);
+ uint f_id = range_tree_uint_take_any(log->unused_ids);
void *key = SET_UINT_IN_POINTER(f_id);
/* Only triangles are supported for now */
@@ -922,7 +922,7 @@ void BM_log_face_added(BMLog *log, BMFace *f)
void BM_log_vert_removed(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
{
BMLogEntry *entry = log->current_entry;
- unsigned int v_id = bm_log_vert_id_get(log, v);
+ uint v_id = bm_log_vert_id_get(log, v);
void *key = SET_UINT_IN_POINTER(v_id);
/* if it has a key, it shouldn't be NULL */
@@ -963,7 +963,7 @@ void BM_log_vert_removed(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
void BM_log_face_removed(BMLog *log, BMFace *f)
{
BMLogEntry *entry = log->current_entry;
- unsigned int f_id = bm_log_face_id_get(log, f);
+ uint f_id = bm_log_face_id_get(log, f);
void *key = SET_UINT_IN_POINTER(f_id);
/* if it has a key, it shouldn't be NULL */
@@ -991,11 +991,11 @@ void BM_log_all_added(BMesh *bm, BMLog *log)
/* avoid unnecessary resizing on initialization */
if (BLI_ghash_size(log->current_entry->added_verts) == 0) {
- BLI_ghash_reserve(log->current_entry->added_verts, (unsigned int)bm->totvert);
+ BLI_ghash_reserve(log->current_entry->added_verts, (uint)bm->totvert);
}
if (BLI_ghash_size(log->current_entry->added_faces) == 0) {
- BLI_ghash_reserve(log->current_entry->added_faces, (unsigned int)bm->totface);
+ BLI_ghash_reserve(log->current_entry->added_faces, (uint)bm->totface);
}
/* Log all vertices as newly created */
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
index 7178a8132d2..7f2032d5f53 100644
--- a/source/blender/bmesh/intern/bmesh_marking.c
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -70,7 +70,7 @@ static void recount_totsels(BMesh *bm)
}
}
-/** \name BMesh helper functions for selection flushing.
+/** \name BMesh helper functions for selection & hide flushing.
* \{ */
static bool bm_vert_is_edge_select_any_other(const BMVert *v, const BMEdge *e_first)
@@ -102,6 +102,20 @@ static bool bm_vert_is_edge_select_any(const BMVert *v)
}
#endif
+static bool bm_vert_is_edge_visible_any(const BMVert *v)
+{
+ if (v->e) {
+ 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 = bmesh_disk_edge_next(e_iter, v)) != e_first);
+ }
+ return false;
+}
+
static bool bm_edge_is_face_select_any_other(BMLoop *l_first)
{
const BMLoop *l_iter = l_first;
@@ -131,6 +145,20 @@ static bool bm_edge_is_face_select_any(const BMEdge *e)
}
#endif
+static bool bm_edge_is_face_visible_any(const BMEdge *e)
+{
+ if (e->l) {
+ 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;
+}
+
/** \} */
/**
@@ -1198,87 +1226,111 @@ void BM_mesh_elem_hflag_enable_all(
/***************** Mesh Hiding stuff *********** */
+/**
+ * Hide unless any connected elements are visible.
+ * Run this after hiding a connected edge or face.
+ */
static void vert_flush_hide_set(BMVert *v)
{
- BMIter iter;
- BMEdge *e;
- bool hide = true;
-
- BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- hide = hide && BM_elem_flag_test(e, BM_ELEM_HIDDEN);
- }
-
- BM_elem_flag_set(v, BM_ELEM_HIDDEN, hide);
+ BM_elem_flag_set(v, BM_ELEM_HIDDEN, !bm_vert_is_edge_visible_any(v));
}
-static void edge_flush_hide(BMEdge *e)
+/**
+ * Hide unless any connected elements are visible.
+ * Run this after hiding a connected face.
+ */
+static void edge_flush_hide_set(BMEdge *e)
{
- BMIter iter;
- BMFace *f;
- bool hide = true;
-
- BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) {
- hide = hide && BM_elem_flag_test(f, BM_ELEM_HIDDEN);
- }
-
- BM_elem_flag_set(e, BM_ELEM_HIDDEN, hide);
+ BM_elem_flag_set(e, BM_ELEM_HIDDEN, !bm_edge_is_face_visible_any(e));
}
void BM_vert_hide_set(BMVert *v, const bool hide)
{
/* vert hiding: vert + surrounding edges and faces */
- BMIter iter, fiter;
- BMEdge *e;
- BMFace *f;
-
BLI_assert(v->head.htype == BM_VERT);
+ if (hide) {
+ BLI_assert(!BM_elem_flag_test(v, BM_ELEM_SELECT));
+ }
BM_elem_flag_set(v, BM_ELEM_HIDDEN, hide);
- BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- BM_elem_flag_set(e, BM_ELEM_HIDDEN, hide);
-
- BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
- BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide);
- }
+ if (v->e) {
+ BMEdge *e_iter, *e_first;
+ e_iter = e_first = v->e;
+ do {
+ BM_elem_flag_set(e_iter, BM_ELEM_HIDDEN, hide);
+ if (e_iter->l) {
+ const BMLoop *l_radial_iter, *l_radial_first;
+ l_radial_iter = l_radial_first = e_iter->l;
+ do {
+ BM_elem_flag_set(l_radial_iter->f, BM_ELEM_HIDDEN, hide);
+ } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
+ }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
}
}
void BM_edge_hide_set(BMEdge *e, const bool hide)
{
- BMIter iter;
- BMFace *f;
- /* BMVert *v; */
-
BLI_assert(e->head.htype == BM_EDGE);
+ if (hide) {
+ BLI_assert(!BM_elem_flag_test(e, BM_ELEM_SELECT));
+ }
/* edge hiding: faces around the edge */
- BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) {
- BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide);
+ if (e->l) {
+ const BMLoop *l_iter, *l_first;
+ l_iter = l_first = e->l;
+ do {
+ BM_elem_flag_set(l_iter->f, BM_ELEM_HIDDEN, hide);
+ } while ((l_iter = l_iter->radial_next) != l_first);
}
BM_elem_flag_set(e, BM_ELEM_HIDDEN, hide);
/* hide vertices if necessary */
- vert_flush_hide_set(e->v1);
- vert_flush_hide_set(e->v2);
+ if (hide) {
+ vert_flush_hide_set(e->v1);
+ vert_flush_hide_set(e->v2);
+ }
+ else {
+ BM_elem_flag_disable(e->v1, BM_ELEM_HIDDEN);
+ BM_elem_flag_disable(e->v2, BM_ELEM_HIDDEN);
+ }
}
void BM_face_hide_set(BMFace *f, const bool hide)
{
- BMIter iter;
- BMLoop *l;
-
BLI_assert(f->head.htype == BM_FACE);
+ if (hide) {
+ BLI_assert(!BM_elem_flag_test(f, BM_ELEM_SELECT));
+ }
BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide);
- BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) {
- edge_flush_hide(l->e);
+ if (hide) {
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter;
+
+ l_iter = l_first;
+ do {
+ edge_flush_hide_set(l_iter->e);
+ } while ((l_iter = l_iter->next) != l_first);
+
+ l_iter = l_first;
+ do {
+ vert_flush_hide_set(l_iter->v);
+ } while ((l_iter = l_iter->next) != l_first);
}
+ else {
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter;
- BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) {
- vert_flush_hide_set(l->v);
+ l_iter = l_first;
+ do {
+ BM_elem_flag_disable(l_iter->e, BM_ELEM_HIDDEN);
+ BM_elem_flag_disable(l_iter->v, BM_ELEM_HIDDEN);
+ } while ((l_iter = l_iter->next) != l_first);
}
}
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index 57a6d8d2e1a..d5d9e4abe2c 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -486,8 +486,7 @@ static void bm_mesh_edges_sharp_tag(
BMesh *bm, const float (*vnos)[3], const float (*fnos)[3], float split_angle,
float (*r_lnos)[3])
{
- BMIter eiter, viter;
- BMVert *v;
+ BMIter eiter;
BMEdge *e;
int i;
@@ -498,19 +497,13 @@ static void bm_mesh_edges_sharp_tag(
}
{
- char htype = BM_LOOP;
+ char htype = BM_VERT | BM_LOOP;
if (fnos) {
htype |= BM_FACE;
}
BM_mesh_elem_index_ensure(bm, htype);
}
- /* Clear all vertices' tags (means they are all smooth for now). */
- BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
- BM_elem_index_set(v, i); /* set_inline */
- BM_elem_flag_disable(v, BM_ELEM_TAG);
- }
-
/* This first loop checks which edges are actually smooth, and pre-populate lnos with vnos (as if they were
* all smooth).
*/
@@ -551,20 +544,45 @@ static void bm_mesh_edges_sharp_tag(
no = vnos ? vnos[BM_elem_index_get(l_b->v)] : l_b->v->no;
copy_v3_v3(r_lnos[BM_elem_index_get(l_b)], no);
}
- else {
- /* Sharp edge, tag its verts as such. */
- BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
- BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
+ }
+ }
+
+ bm->elem_index_dirty &= ~BM_EDGE;
+}
+
+/* Check whether gievn loop is part of an unknown-so-far cyclic smooth fan, or not.
+ * Needed because cyclic smooth fans have no obvious 'entry point', and yet we need to walk them once, and only once. */
+static bool bm_mesh_loop_check_cyclic_smooth_fan(BMLoop *l_curr)
+{
+ BMLoop *lfan_pivot_next = l_curr;
+ BMEdge *e_next = l_curr->e;
+
+ BLI_assert(!BM_elem_flag_test(lfan_pivot_next, BM_ELEM_TAG));
+ BM_elem_flag_enable(lfan_pivot_next, BM_ELEM_TAG);
+
+ while (true) {
+ /* Much simpler than in sibling code with basic Mesh data! */
+ lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot_next, &e_next);
+
+ if (!lfan_pivot_next || !BM_elem_flag_test(e_next, BM_ELEM_TAG)) {
+ /* Sharp loop/edge, so not a cyclic smooth fan... */
+ return false;
+ }
+ /* Smooth loop/edge... */
+ else if (BM_elem_flag_test(lfan_pivot_next, BM_ELEM_TAG)) {
+ if (lfan_pivot_next == l_curr) {
+ /* We walked around a whole cyclic smooth fan without finding any already-processed loop, means we can
+ * use initial l_curr/l_prev edge as start for this smooth fan. */
+ return true;
}
+ /* ... already checked in some previous looping, we can abort. */
+ return false;
}
else {
- /* Sharp edge, tag its verts as such. */
- BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
- BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
+ /* ... we can skip it in future, and keep checking the smooth fan. */
+ BM_elem_flag_enable(lfan_pivot_next, BM_ELEM_TAG);
}
}
-
- bm->elem_index_dirty &= ~(BM_EDGE | BM_VERT);
}
/* BMesh version of BKE_mesh_normals_loop_split() in mesh_evaluate.c
@@ -587,13 +605,11 @@ static void bm_mesh_loops_calc_normals(
BLI_Stack *edge_vectors = NULL;
{
- char htype = BM_LOOP;
+ char htype = 0;
if (vcos) {
htype |= BM_VERT;
}
- if (fnos) {
- htype |= BM_FACE;
- }
+ /* Face/Loop indices are set inline below. */
BM_mesh_elem_index_ensure(bm, htype);
}
@@ -606,6 +622,21 @@ static void bm_mesh_loops_calc_normals(
edge_vectors = BLI_stack_new(sizeof(float[3]), __func__);
}
+ /* Clear all loops' tags (means none are to be skipped for now). */
+ int index_face, index_loop = 0;
+ BM_ITER_MESH_INDEX (f_curr, &fiter, bm, BM_FACES_OF_MESH, index_face) {
+ BMLoop *l_curr, *l_first;
+
+ BM_elem_index_set(f_curr, index_face); /* set_inline */
+
+ l_curr = l_first = BM_FACE_FIRST_LOOP(f_curr);
+ 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);
+
/* We now know edges that can be smoothed (they are tagged), and edges that will be hard (they aren't).
* Now, time to generate the normals.
*/
@@ -614,16 +645,16 @@ static void bm_mesh_loops_calc_normals(
l_curr = l_first = BM_FACE_FIRST_LOOP(f_curr);
do {
+ /* 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. */
+ /* Note: In theory, we could make bm_mesh_loop_check_cyclic_smooth_fan() store mlfan_pivot's in a stack,
+ * to avoid having to fan again around the vert during actual computation of clnor & clnorspace.
+ * However, this would complicate the code, add more memory usage, and BM_vert_step_fan_loop()
+ * is quite cheap in term of CPU cycles, so really think it's not worth it. */
if (BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) &&
- (!r_lnors_spacearr || BM_elem_flag_test(l_curr->v, BM_ELEM_TAG)))
+ (BM_elem_flag_test(l_curr, BM_ELEM_TAG) || !bm_mesh_loop_check_cyclic_smooth_fan(l_curr)))
{
- /* A smooth edge, and we are not generating lnors_spacearr, or the related vertex is sharp.
- * We skip it because it is either:
- * - in the middle of a 'smooth fan' already computed (or that will be as soon as we hit
- * one of its ends, i.e. one of its two sharp edges), or...
- * - the related vertex is a "full smooth" one, in which case pre-populated normals from vertex
- * are just fine!
- */
}
else if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) &&
!BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG))
@@ -1481,23 +1512,6 @@ int BM_mesh_elem_count(BMesh *bm, const char htype)
}
}
-/**
- * Special case: Python uses custom-data layers to hold PyObject references.
- * These have to be kept in-place, else the PyObject's we point to, wont point back to us.
- *
- * \note ``ele_src`` Is a duplicate, so we don't need to worry about getting in a feedback loop.
- *
- * \note If there are other customdata layers which need this functionality, it should be generalized.
- * However #BM_mesh_remap is currently the only place where this is done.
- */
-static void bm_mesh_remap_cd_update(
- BMHeader *ele_dst, BMHeader *ele_src,
- const int cd_elem_pyptr)
-{
- void **pyptr_dst_p = BM_ELEM_CD_GET_VOID_P(((BMElem *)ele_dst), cd_elem_pyptr);
- void **pyptr_src_p = BM_ELEM_CD_GET_VOID_P(((BMElem *)ele_src), cd_elem_pyptr);
- *pyptr_dst_p = *pyptr_src_p;
-}
/**
* Remaps the vertices, edges and/or faces of the bmesh as indicated by vert/edge/face_idx arrays
@@ -1513,9 +1527,9 @@ static void bm_mesh_remap_cd_update(
*/
void BM_mesh_remap(
BMesh *bm,
- const unsigned int *vert_idx,
- const unsigned int *edge_idx,
- const unsigned int *face_idx)
+ const uint *vert_idx,
+ const uint *edge_idx,
+ const uint *face_idx)
{
/* Mapping old to new pointers. */
GHash *vptr_map = NULL, *eptr_map = NULL, *fptr_map = NULL;
@@ -1538,7 +1552,9 @@ void BM_mesh_remap(
if (vert_idx) {
BMVert **verts_pool, *verts_copy, **vep;
int i, totvert = bm->totvert;
- const unsigned int *new_idx;
+ const uint *new_idx;
+ /* Special case: Python uses custom - data layers to hold PyObject references.
+ * These have to be kept in - place, else the PyObject's we point to, wont point back to us. */
const int cd_vert_pyptr = CustomData_get_offset(&bm->vdata, CD_BM_ELEM_PYPTR);
/* Init the old-to-new vert pointers mapping */
@@ -1547,9 +1563,14 @@ void BM_mesh_remap(
/* Make a copy of all vertices. */
verts_pool = bm->vtable;
verts_copy = MEM_mallocN(sizeof(BMVert) * totvert, "BM_mesh_remap verts copy");
+ void **pyptrs = (cd_vert_pyptr != -1) ? MEM_mallocN(sizeof(void *) * totvert, __func__) : NULL;
for (i = totvert, ve = verts_copy + totvert - 1, vep = verts_pool + totvert - 1; i--; ve--, vep--) {
*ve = **vep;
/* printf("*vep: %p, verts_pool[%d]: %p\n", *vep, i, verts_pool[i]);*/
+ if (cd_vert_pyptr != -1) {
+ void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)ve), cd_vert_pyptr);
+ pyptrs[i] = *pyptr;
+ }
}
/* Copy back verts to their new place, and update old2new pointers mapping. */
@@ -1562,20 +1583,26 @@ void BM_mesh_remap(
/* printf("mapping vert from %d to %d (%p/%p to %p)\n", i, *new_idx, *vep, verts_pool[i], new_vep);*/
BLI_ghash_insert(vptr_map, *vep, new_vep);
if (cd_vert_pyptr != -1) {
- bm_mesh_remap_cd_update(&(*vep)->head, &new_vep->head, cd_vert_pyptr);
+ void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)new_vep), cd_vert_pyptr);
+ *pyptr = pyptrs[*new_idx];
}
}
bm->elem_index_dirty |= BM_VERT;
bm->elem_table_dirty |= BM_VERT;
MEM_freeN(verts_copy);
+ if (pyptrs) {
+ MEM_freeN(pyptrs);
+ }
}
/* Remap Edges */
if (edge_idx) {
BMEdge **edges_pool, *edges_copy, **edp;
int i, totedge = bm->totedge;
- const unsigned int *new_idx;
+ const uint *new_idx;
+ /* Special case: Python uses custom - data layers to hold PyObject references.
+ * These have to be kept in - place, else the PyObject's we point to, wont point back to us. */
const int cd_edge_pyptr = CustomData_get_offset(&bm->edata, CD_BM_ELEM_PYPTR);
/* Init the old-to-new vert pointers mapping */
@@ -1584,8 +1611,13 @@ void BM_mesh_remap(
/* Make a copy of all vertices. */
edges_pool = bm->etable;
edges_copy = MEM_mallocN(sizeof(BMEdge) * totedge, "BM_mesh_remap edges copy");
+ void **pyptrs = (cd_edge_pyptr != -1) ? MEM_mallocN(sizeof(void *) * totedge, __func__) : NULL;
for (i = totedge, ed = edges_copy + totedge - 1, edp = edges_pool + totedge - 1; i--; ed--, edp--) {
*ed = **edp;
+ if (cd_edge_pyptr != -1) {
+ void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)ed), cd_edge_pyptr);
+ pyptrs[i] = *pyptr;
+ }
}
/* Copy back verts to their new place, and update old2new pointers mapping. */
@@ -1598,20 +1630,26 @@ void BM_mesh_remap(
BLI_ghash_insert(eptr_map, *edp, new_edp);
/* printf("mapping edge from %d to %d (%p/%p to %p)\n", i, *new_idx, *edp, edges_pool[i], new_edp);*/
if (cd_edge_pyptr != -1) {
- bm_mesh_remap_cd_update(&(*edp)->head, &new_edp->head, cd_edge_pyptr);
+ void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)new_edp), cd_edge_pyptr);
+ *pyptr = pyptrs[*new_idx];
}
}
bm->elem_index_dirty |= BM_EDGE;
bm->elem_table_dirty |= BM_EDGE;
MEM_freeN(edges_copy);
+ if (pyptrs) {
+ MEM_freeN(pyptrs);
+ }
}
/* Remap Faces */
if (face_idx) {
BMFace **faces_pool, *faces_copy, **fap;
int i, totface = bm->totface;
- const unsigned int *new_idx;
+ const uint *new_idx;
+ /* Special case: Python uses custom - data layers to hold PyObject references.
+ * These have to be kept in - place, else the PyObject's we point to, wont point back to us. */
const int cd_poly_pyptr = CustomData_get_offset(&bm->pdata, CD_BM_ELEM_PYPTR);
/* Init the old-to-new vert pointers mapping */
@@ -1620,8 +1658,13 @@ void BM_mesh_remap(
/* Make a copy of all vertices. */
faces_pool = bm->ftable;
faces_copy = MEM_mallocN(sizeof(BMFace) * totface, "BM_mesh_remap faces copy");
+ void **pyptrs = (cd_poly_pyptr != -1) ? MEM_mallocN(sizeof(void *) * totface, __func__) : NULL;
for (i = totface, fa = faces_copy + totface - 1, fap = faces_pool + totface - 1; i--; fa--, fap--) {
*fa = **fap;
+ if (cd_poly_pyptr != -1) {
+ void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)fa), cd_poly_pyptr);
+ pyptrs[i] = *pyptr;
+ }
}
/* Copy back verts to their new place, and update old2new pointers mapping. */
@@ -1633,7 +1676,8 @@ void BM_mesh_remap(
*new_fap = *fa;
BLI_ghash_insert(fptr_map, *fap, new_fap);
if (cd_poly_pyptr != -1) {
- bm_mesh_remap_cd_update(&(*fap)->head, &new_fap->head, cd_poly_pyptr);
+ void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)new_fap), cd_poly_pyptr);
+ *pyptr = pyptrs[*new_idx];
}
}
@@ -1641,6 +1685,9 @@ void BM_mesh_remap(
bm->elem_table_dirty |= BM_FACE;
MEM_freeN(faces_copy);
+ if (pyptrs) {
+ MEM_freeN(pyptrs);
+ }
}
/* And now, fix all vertices/edges/faces/loops pointers! */
@@ -2008,4 +2055,4 @@ void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags)
vpool_dst, epool_dst, NULL, fpool_dst);
bm->use_toolflags = use_toolflags;
-} \ No newline at end of file
+}
diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h
index 6a9540c3b60..01f11f6f942 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.h
+++ b/source/blender/bmesh/intern/bmesh_mesh.h
@@ -34,7 +34,7 @@ void BM_mesh_elem_toolflags_ensure(BMesh *bm);
void BM_mesh_elem_toolflags_clear(BMesh *bm);
struct BMeshCreateParams {
- unsigned int use_toolflags : 1;
+ uint use_toolflags : 1;
};
BMesh *BM_mesh_create(
@@ -88,9 +88,9 @@ int BM_mesh_elem_count(BMesh *bm, const char htype);
void BM_mesh_remap(
BMesh *bm,
- const unsigned int *vert_idx,
- const unsigned int *edge_idx,
- const unsigned int *face_idx);
+ const uint *vert_idx,
+ const uint *edge_idx,
+ const uint *face_idx);
void BM_mesh_rebuild(
BMesh *bm, const struct BMeshCreateParams *params,
diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_conv.c
index 998dbee67a4..e73d2f70dbe 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_conv.c
@@ -101,42 +101,6 @@
/* XXX stupid hack: linker otherwise strips bmesh_strands_conv.c because it is not used inside bmesh */
void *__dummy_hack__ = &BM_strands_count_psys_keys;
-/**
- * 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;
@@ -238,7 +202,7 @@ void BM_mesh_bm_from_me(
BMEdge *e, **etable = NULL;
BMFace *f;
float (*keyco)[3] = NULL;
- int totuv, totloops, i, j;
+ int totloops, i, j;
CustomDataMask mask = CD_MASK_BMESH | params->cd_mask_extra;
/* free custom data */
@@ -270,13 +234,6 @@ void BM_mesh_bm_from_me(
CustomData_copy(&me->ldata, &bm->ldata, mask, CD_CALLOC, 0);
CustomData_copy(&me->pdata, &bm->pdata, mask, 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);
- }
-
if ((params->active_shapekey != 0) && (me->key != NULL)) {
actkey = BLI_findlink(&me->key->block, params->active_shapekey - 1);
}
@@ -949,6 +906,10 @@ void BM_mesh_bm_to_me(
/* propagate edited basis offsets to other shapes */
if (apply_offset) {
add_v3_v3(fp, *ofs_pt++);
+ /* Apply back new coordinates of offsetted shapekeys into BMesh.
+ * Otherwise, in case we call again BM_mesh_bm_to_me on same BMesh, we'll apply diff from previous
+ * call to BM_mesh_bm_to_me, to shapekey values from *original creation of the BMesh*. See T50524. */
+ copy_v3_v3(BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset), fp);
}
fp += 3;
diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.h b/source/blender/bmesh/intern/bmesh_mesh_conv.h
index 892b9bef486..e69f3d6c489 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_conv.h
@@ -44,11 +44,11 @@ char BM_mesh_cd_flag_from_bmesh(BMesh *bm);
struct BMeshFromMeshParams {
- unsigned int calc_face_normal : 1;
+ uint calc_face_normal : 1;
/* add a vertex CD_SHAPE_KEYINDEX layer */
- unsigned int add_key_index : 1;
+ uint add_key_index : 1;
/* set vertex coordinates from the shapekey */
- unsigned int use_shapekey : 1;
+ uint use_shapekey : 1;
/* define the active shape key (index + 1) */
int active_shapekey;
int64_t cd_mask_extra;
@@ -59,7 +59,7 @@ void BM_mesh_bm_from_me(
ATTR_NONNULL(1, 3);
struct BMeshToMeshParams {
- unsigned int calc_tessface : 1;
+ uint calc_tessface : 1;
int64_t cd_mask_extra;
};
void BM_mesh_bm_to_me(
diff --git a/source/blender/bmesh/intern/bmesh_mesh_validate.c b/source/blender/bmesh/intern/bmesh_mesh_validate.c
index 478194735f3..7c9ebc800a3 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_validate.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_validate.c
@@ -64,7 +64,7 @@ bool BM_mesh_validate(BMesh *bm)
int i, j;
- errtot = -1;
+ errtot = -1; /* 'ERRMSG' next line will set at zero */
fprintf(stderr, "\n");
ERRMSG("This is a debugging function and not intended for general use, running slow test!");
@@ -187,15 +187,22 @@ bool BM_mesh_validate(BMesh *bm)
} while ((l_iter = l_iter->next) != l_first);
if (j != f->len) {
- ERRMSG("face %d: has length if %d but should be %d", i, f->len, j);
+ ERRMSG("face %d: has length of %d but should be %d", i, f->len, j);
}
+
+ /* leave elements un-tagged, not essential but nice to avoid unintended dirty tag use later. */
+ do {
+ BM_elem_flag_disable(l_iter, BM_ELEM_INTERNAL_TAG);
+ BM_elem_flag_disable(l_iter->v, BM_ELEM_INTERNAL_TAG);
+ BM_elem_flag_disable(l_iter->e, BM_ELEM_INTERNAL_TAG);
+ } while ((l_iter = l_iter->next) != l_first);
}
BLI_edgehash_free(edge_hash, NULL);
+ const bool is_valid = (errtot == 0);
ERRMSG("Finished - errors %d", errtot);
-
- return (errtot == 0);
+ return is_valid;
}
diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c
index d3c847de64e..1cd51528e06 100644
--- a/source/blender/bmesh/intern/bmesh_mods.c
+++ b/source/blender/bmesh/intern/bmesh_mods.c
@@ -104,7 +104,6 @@ bool BM_vert_dissolve(BMesh *bm, BMVert *v)
*/
bool BM_disk_dissolve(BMesh *bm, BMVert *v)
{
- BMFace *f, *f2;
BMEdge *e, *keepedge = NULL, *baseedge = NULL;
int len = 0;
@@ -132,16 +131,17 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v)
#if 0
/* handle specific case for three-valence. solve it by
* increasing valence to four. this may be hackish. . */
- BMLoop *loop = e->l;
- if (loop->v == v) loop = loop->next;
- if (!BM_face_split(bm, loop->f, v, loop->v, NULL, NULL, false))
+ BMLoop *l_a = BM_face_vert_share_loop(e->l->f, v);
+ BMLoop *l_b = (e->l->v == v) ? e->l->next : e->l;
+
+ if (!BM_face_split(bm, e->l->f, l_a, l_b, NULL, NULL, false))
return false;
if (!BM_disk_dissolve(bm, v)) {
return false;
}
#else
- if (UNLIKELY(!BM_faces_join_pair(bm, e->l->f, e->l->radial_next->f, e, true))) {
+ if (UNLIKELY(!BM_faces_join_pair(bm, e->l, e->l->radial_next, true))) {
return false;
}
else if (UNLIKELY(!BM_vert_collapse_faces(bm, v->e, v, 1.0, true, false, true))) {
@@ -159,11 +159,10 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v)
}
/* handle two-valence */
- f = e->l->f;
- f2 = e->l->radial_next->f;
-
- if (f != f2 && !BM_faces_join_pair(bm, f, f2, e, true)) {
- return false;
+ if (e->l != e->l->radial_next) {
+ if (!BM_faces_join_pair(bm, e->l, e->l->radial_next, true)) {
+ return false;
+ }
}
return true;
@@ -176,9 +175,9 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v)
done = true;
e = v->e;
do {
- f = NULL;
+ BMFace *f = NULL;
if (BM_edge_is_manifold(e) && (e != baseedge) && (e != keepedge)) {
- f = BM_faces_join_pair(bm, e->l->f, e->l->radial_next->f, e, true);
+ f = BM_faces_join_pair(bm, e->l, e->l->radial_next, true);
/* return if couldn't join faces in manifold
* conditions */
/* !disabled for testing why bad things happen */
@@ -204,12 +203,9 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v)
if (e->l) {
/* get remaining two faces */
- f = e->l->f;
- f2 = e->l->radial_next->f;
-
- if (f != f2) {
+ if (e->l != e->l->radial_next) {
/* join two remaining faces */
- if (!BM_faces_join_pair(bm, f, f2, e, true)) {
+ if (!BM_faces_join_pair(bm, e->l, e->l->radial_next, true)) {
return false;
}
}
@@ -224,30 +220,24 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v)
*
* Joins two adjacent faces together.
*
- * Because this method calls to #BM_faces_join to do its work, if a pair
- * of faces share multiple edges, the pair of faces will be joined at
- * every edge (not just edge \a e). This part of the functionality might need
- * to be reconsidered.
+ * \note This method calls to #BM_faces_join to do its work.
+ * This means connected edges which also share the two faces will be joined.
*
* If the windings do not match the winding of the new face will follow
- * \a f_a's winding (i.e. \a f_b will be reversed before the join).
+ * \a l_a's winding (i.e. \a l_b will be reversed before the join).
*
- * \return pointer to the combined face
+ * \return The combined face or NULL on failure.
*/
-BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f_a, BMFace *f_b, BMEdge *e, const bool do_del)
+BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del)
{
- BMFace *faces[2] = {f_a, f_b};
-
- BMLoop *l_a = BM_face_edge_share_loop(f_a, e);
- BMLoop *l_b = BM_face_edge_share_loop(f_b, e);
-
- BLI_assert(l_a && l_b);
+ BLI_assert((l_a != l_b) && (l_a->e == l_b->e));
if (l_a->v == l_b->v) {
const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
- bmesh_loop_reverse(bm, f_b, cd_loop_mdisp_offset, true);
+ bmesh_kernel_loop_reverse(bm, l_b->f, cd_loop_mdisp_offset, true);
}
-
+
+ BMFace *faces[2] = {l_a->f, l_b->f};
return BM_faces_join(bm, faces, 2, do_del);
}
@@ -298,9 +288,9 @@ BMFace *BM_face_split(
}
#ifdef USE_BMESH_HOLES
- f_new = bmesh_sfme(bm, f, l_a, l_b, r_l, NULL, example, no_double);
+ f_new = bmesh_kernel_split_face_make_edge(bm, f, l_a, l_b, r_l, NULL, example, no_double);
#else
- f_new = bmesh_sfme(bm, f, l_a, l_b, r_l, example, no_double);
+ f_new = bmesh_kernel_split_face_make_edge(bm, f, l_a, l_b, r_l, example, no_double);
#endif
if (f_new) {
@@ -356,7 +346,7 @@ BMFace *BM_face_split_n(
BMLoop **r_l, BMEdge *example)
{
BMFace *f_new, *f_tmp;
- BMLoop *l_dummy;
+ BMLoop *l_new;
BMEdge *e, *e_new;
BMVert *v_new;
// BMVert *v_a = l_a->v; /* UNUSED */
@@ -378,24 +368,21 @@ BMFace *BM_face_split_n(
}
f_tmp = BM_face_copy(bm, bm, f, true, true);
-
- if (!r_l)
- r_l = &l_dummy;
#ifdef USE_BMESH_HOLES
- f_new = bmesh_sfme(bm, f, l_a, l_b, r_l, NULL, example, false);
+ f_new = bmesh_kernel_split_face_make_edge(bm, f, l_a, l_b, &l_new, NULL, example, false);
#else
- f_new = bmesh_sfme(bm, f, l_a, l_b, r_l, example, false);
+ f_new = bmesh_kernel_split_face_make_edge(bm, f, l_a, l_b, &l_new, example, false);
#endif
- /* bmesh_sfme returns in r_l a Loop for f_new going from v_a to v_b.
- * The radial_next is for f and goes from v_b to v_a */
+ /* bmesh_kernel_split_face_make_edge returns in 'l_new' a Loop for f_new going from 'v_a' to 'v_b'.
+ * The radial_next is for 'f' and goes from 'v_b' to 'v_a' */
if (f_new) {
- e = (*r_l)->e;
+ e = l_new->e;
for (i = 0; i < n; i++) {
- v_new = bmesh_semv(bm, v_b, e, &e_new);
+ v_new = bmesh_kernel_split_edge_make_vert(bm, v_b, e, &e_new);
BLI_assert(v_new != NULL);
- /* bmesh_semv returns in e_new the edge going from v_new to tv */
+ /* bmesh_kernel_split_edge_make_vert returns in 'e_new' the edge going from 'v_new' to 'v_b' */
copy_v3_v3(v_new->co, cos[i]);
/* interpolate the loop data for the loops with (v == v_new), using orig face */
@@ -415,6 +402,10 @@ BMFace *BM_face_split_n(
BM_face_verts_kill(bm, f_tmp);
+ if (r_l) {
+ *r_l = l_new;
+ }
+
return f_new;
}
@@ -516,7 +507,7 @@ BMEdge *BM_vert_collapse_faces(
/* single face or no faces */
/* same as BM_vert_collapse_edge() however we already
* have vars to perform this operation so don't call. */
- e_new = bmesh_jekv(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces);
+ e_new = bmesh_kernel_join_edge_kill_vert(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces);
/* e_new = BM_edge_exists(tv, tv2); */ /* same as return above */
}
@@ -551,7 +542,7 @@ BMEdge *BM_vert_collapse_edge(
BMVert *tv2 = BM_edge_other_vert(e2, v_kill);
if (tv2) {
/* only action, other calls here only get the edge to return */
- e_new = bmesh_jekv(bm, e_kill, v_kill, do_del);
+ e_new = bmesh_kernel_join_edge_kill_vert(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces);
}
}
}
@@ -573,7 +564,7 @@ BMVert *BM_edge_collapse(
BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
const bool do_del, const bool kill_degenerate_faces)
{
- return bmesh_jvke(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces);
+ return bmesh_kernel_join_vert_kill_edge(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces);
}
/**
@@ -598,18 +589,13 @@ BMVert *BM_edge_collapse(
BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
{
BMVert *v_new, *v_other;
+ BMEdge *e_new;
BMFace **oldfaces = NULL;
- BMEdge *e_dummy;
BLI_array_staticdeclare(oldfaces, 32);
const int cd_loop_mdisp_offset = BM_edge_is_wire(e) ? -1 : CustomData_get_offset(&bm->ldata, CD_MDISPS);
BLI_assert(BM_vert_in_edge(e, v) == true);
- /* we need this for handling multi-res */
- if (!r_e) {
- r_e = &e_dummy;
- }
-
/* do we have a multi-res layer? */
if (cd_loop_mdisp_offset != -1) {
BMLoop *l;
@@ -630,17 +616,20 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
}
v_other = BM_edge_other_vert(e, v);
- v_new = bmesh_semv(bm, v, e, r_e);
+ v_new = bmesh_kernel_split_edge_make_vert(bm, v, e, &e_new);
+ if (r_e != NULL) {
+ *r_e = e_new;
+ }
BLI_assert(v_new != NULL);
- BLI_assert(BM_vert_in_edge(*r_e, v) && BM_vert_in_edge(*r_e, v_new));
+ BLI_assert(BM_vert_in_edge(e_new, v) && BM_vert_in_edge(e_new, v_new));
BLI_assert(BM_vert_in_edge(e, v_new) && BM_vert_in_edge(e, v_other));
sub_v3_v3v3(v_new->co, v_other->co, v->co);
madd_v3_v3v3fl(v_new->co, v->co, v_new->co, fac);
- (*r_e)->head.hflag = e->head.hflag;
- BM_elem_attrs_copy(bm, bm, e, *r_e);
+ e_new->head.hflag = e->head.hflag;
+ BM_elem_attrs_copy(bm, bm, e, e_new);
/* v->v_new->v2 */
BM_data_interp_face_vert_edge(bm, v_other, v, v_new, e, fac);
@@ -656,7 +645,7 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
BM_face_calc_center_mean(oldfaces[i], f_center_old);
for (j = 0; j < 2; j++) {
- BMEdge *e1 = j ? *r_e : e;
+ BMEdge *e1 = j ? e_new : e;
BMLoop *l;
l = e1->l;
@@ -689,7 +678,7 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
/* fix boundaries a bit, doesn't work too well quite yet */
#if 0
for (j = 0; j < 2; j++) {
- BMEdge *e1 = j ? *r_e : e;
+ BMEdge *e1 = j ? e_new : e;
BMLoop *l, *l2;
l = e1->l;
@@ -991,6 +980,7 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f
BMLoop *l1, *l2;
BMFace *f;
BMEdge *e_new = NULL;
+ char f_active_prev = 0;
char f_hflag_prev_1;
char f_hflag_prev_2;
@@ -1041,8 +1031,18 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f
f_hflag_prev_1 = l1->f->head.hflag;
f_hflag_prev_2 = l2->f->head.hflag;
+ /* maintain active face */
+ if (bm->act_face == l1->f) {
+ f_active_prev = 1;
+ }
+ else if (bm->act_face == l2->f) {
+ f_active_prev = 2;
+ }
+
+ const bool is_flipped = !BM_edge_is_contiguous(e);
+
/* don't delete the edge, manually remove the edge after so we can copy its attributes */
- f = BM_faces_join_pair(bm, l1->f, l2->f, e, true);
+ f = BM_faces_join_pair(bm, BM_face_edge_share_loop(l1->f, e), BM_face_edge_share_loop(l2->f, e), true);
if (f == NULL) {
return NULL;
@@ -1062,6 +1062,22 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f
if (BM_edge_face_pair(e_new, &fa, &fb)) {
fa->head.hflag = f_hflag_prev_1;
fb->head.hflag = f_hflag_prev_2;
+
+ if (f_active_prev == 1) {
+ bm->act_face = fa;
+ }
+ else if (f_active_prev == 2) {
+ bm->act_face = fb;
+ }
+
+ if (is_flipped) {
+ BM_face_normal_flip(bm, fb);
+
+ if (ccw) {
+ /* needed otherwise ccw toggles direction */
+ e_new->l = e_new->l->radial_next;
+ }
+ }
}
}
else {
@@ -1074,23 +1090,18 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f
/**
* \brief Rip a single face from a vertex fan
*/
-BMVert *BM_face_vert_separate(BMesh *bm, BMFace *sf, BMVert *sv)
+BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *l_sep)
{
- return bmesh_urmv(bm, sf, sv);
+ return bmesh_kernel_unglue_region_make_vert(bm, l_sep);
}
-/**
- * \brief Rip a single face from a vertex fan
- *
- * \note same as #BM_face_vert_separate but faster (avoids a loop lookup)
- */
-BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *sl)
+BMVert *BM_face_loop_separate_multi_isolated(BMesh *bm, BMLoop *l_sep)
{
- return bmesh_urmv_loop(bm, sl);
+ return bmesh_kernel_unglue_region_make_vert_multi_isolated(bm, l_sep);
}
-BMVert *BM_face_loop_separate_multi(
- BMesh *bm, BMLoop **larr, int larr_len)
+BMVert *BM_face_loop_separate_multi(BMesh *bm, BMLoop **larr, int larr_len)
{
- return bmesh_urmv_loop_multi(bm, larr, larr_len);
+ return bmesh_kernel_unglue_region_make_vert_multi(bm, larr, larr_len);
}
+
diff --git a/source/blender/bmesh/intern/bmesh_mods.h b/source/blender/bmesh/intern/bmesh_mods.h
index 2e557e3b606..330a714418d 100644
--- a/source/blender/bmesh/intern/bmesh_mods.h
+++ b/source/blender/bmesh/intern/bmesh_mods.h
@@ -31,7 +31,7 @@ bool BM_vert_dissolve(BMesh *bm, BMVert *v);
bool BM_disk_dissolve(BMesh *bm, BMVert *v);
-BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e, const bool do_del);
+BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del);
/** see: bmesh_polygon_edgenet.h for #BM_face_split_edgenet */
@@ -86,9 +86,8 @@ enum {
};
-BMVert *BM_face_vert_separate(BMesh *bm, BMFace *sf, BMVert *sv);
-BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *sl);
-BMVert *BM_face_loop_separate_multi(
- BMesh *bm, BMLoop **larr, int larr_len);
+BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *l_sep);
+BMVert *BM_face_loop_separate_multi_isolated(BMesh *bm, BMLoop *l_sep);
+BMVert *BM_face_loop_separate_multi(BMesh *bm, BMLoop **larr, int larr_len);
#endif /* __BMESH_MODS_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index 79c2f80d6aa..a55df234264 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -1037,7 +1037,7 @@ static BMOpDefine bmo_extrude_face_region_def = {
/* slots_in */
{{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* edges and faces */
{"edges_exclude", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_EMPTY}},
- {"use_keep_orig", BMO_OP_SLOT_BOOL}, /* keep original geometry */
+ {"use_keep_orig", BMO_OP_SLOT_BOOL}, /* keep original geometry (requires ``geom`` to include edges). */
{"use_select_history", BMO_OP_SLOT_BOOL}, /* pass to duplicate */
{{'\0'}},
},
@@ -1284,7 +1284,7 @@ static BMOpDefine bmo_bisect_plane_def = {
{"clear_inner", BMO_OP_SLOT_BOOL}, /* when enabled. remove all geometry on the negative side of the plane */
{{'\0'}},
},
- {{"geom_cut.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE}}, /* output new geometry from the cut */
+ {{"geom_cut.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE}}, /* output geometry aligned with the plane (new and existing) */
{"geom.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* input and output geometry (result of cut) */
{{'\0'}}},
bmo_bisect_plane_exec,
@@ -1635,7 +1635,8 @@ static BMOpDefine bmo_create_icosphere_def = {
static BMOpDefine bmo_create_monkey_def = {
"create_monkey",
/* slots_in */
- {{"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */
+ {{"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */
+ {"calc_uvs", BMO_OP_SLOT_BOOL}, /* calculate default UVs */
{{'\0'}},
},
/* slots_out */
@@ -1740,6 +1741,8 @@ static BMOpDefine bmo_bevel_def = {
},
/* 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 */
{{'\0'}},
},
@@ -1911,7 +1914,6 @@ static BMOpDefine bmo_wireframe_def = {
{"use_even_offset", BMO_OP_SLOT_BOOL},
{"use_crease", BMO_OP_SLOT_BOOL},
{"crease_weight", BMO_OP_SLOT_FLT},
- {"thickness", BMO_OP_SLOT_FLT},
{"use_relative_offset", BMO_OP_SLOT_BOOL},
{"material_offset", BMO_OP_SLOT_INT},
{{'\0'}},
diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c
index 706a7f74ed2..44445aae25a 100644
--- a/source/blender/bmesh/intern/bmesh_operators.c
+++ b/source/blender/bmesh/intern/bmesh_operators.c
@@ -128,7 +128,7 @@ void BMO_pop(BMesh *bm)
static void bmo_op_slots_init(const BMOSlotType *slot_types, BMOpSlot *slot_args)
{
BMOpSlot *slot;
- unsigned int i;
+ uint i;
for (i = 0; slot_types[i].type; i++) {
slot = &slot_args[i];
slot->slot_name = slot_types[i].name;
@@ -149,7 +149,7 @@ static void bmo_op_slots_init(const BMOSlotType *slot_types, BMOpSlot *slot_args
static void bmo_op_slots_free(const BMOSlotType *slot_types, BMOpSlot *slot_args)
{
BMOpSlot *slot;
- unsigned int i;
+ uint i;
for (i = 0; slot_types[i].type; i++) {
slot = &slot_args[i];
switch (slot->slot_type) {
@@ -311,9 +311,9 @@ void _bmo_slot_copy(
}
else {
/* check types */
- const unsigned int tot = slot_src->len;
- unsigned int i;
- unsigned int out = 0;
+ const uint tot = slot_src->len;
+ uint i;
+ uint out = 0;
BMElem **ele_src = (BMElem **)slot_src->data.buf;
for (i = 0; i < tot; i++, ele_src++) {
if ((*ele_src)->head.htype & dst_elem_flag) {
@@ -333,8 +333,8 @@ void _bmo_slot_copy(
}
else {
/* only copy compatible elements */
- const unsigned int tot = slot_src->len;
- unsigned int i;
+ const uint tot = slot_src->len;
+ uint i;
BMElem **ele_src = (BMElem **)slot_src->data.buf;
BMElem **ele_dst = (BMElem **)slot_dst->data.buf;
for (i = 0; i < tot; i++, ele_src++) {
@@ -1639,8 +1639,8 @@ static int bmo_name_to_slotcode_check(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], cons
int BMO_opcode_from_opname(const char *opname)
{
- const unsigned int tot = bmo_opdefines_total;
- unsigned int i;
+ const uint tot = bmo_opdefines_total;
+ uint i;
for (i = 0; i < tot; i++) {
if (STREQ(bmo_opdefines[i]->opname, opname)) {
return i;
diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h
index 0a4fb1d56a4..80b57eb3565 100644
--- a/source/blender/bmesh/intern/bmesh_operators.h
+++ b/source/blender/bmesh/intern/bmesh_operators.h
@@ -77,13 +77,13 @@ enum {
/* similar face selection slot values */
enum {
SIMFACE_MATERIAL = 201,
- SIMFACE_IMAGE,
SIMFACE_AREA,
SIMFACE_SIDES,
SIMFACE_PERIMETER,
SIMFACE_NORMAL,
SIMFACE_COPLANAR,
SIMFACE_SMOOTH,
+ SIMFACE_FACEMAP,
#ifdef WITH_FREESTYLE
SIMFACE_FREESTYLE
#endif
@@ -141,12 +141,19 @@ void BM_mesh_esubdivide(
const short use_only_quads,
const int seed);
-void BM_mesh_calc_uvs_grid(BMesh *bm, const unsigned int x_segments, const unsigned int y_segments, const short oflag);
-void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag);
-void BM_mesh_calc_uvs_circle(BMesh *bm, float mat[4][4], const float radius, const short oflag);
+void BM_mesh_calc_uvs_grid(
+ BMesh *bm, const uint x_segments, const uint y_segments,
+ const short oflag, const int cd_loop_uv_offset);
+void BM_mesh_calc_uvs_sphere(
+ BMesh *bm,
+ const short oflag, const int cd_loop_uv_offset);
+void BM_mesh_calc_uvs_circle(
+ BMesh *bm, float mat[4][4], const float radius,
+ const short oflag, const int cd_loop_uv_offset);
void BM_mesh_calc_uvs_cone(
BMesh *bm, float mat[4][4],
- const float radius_top, const float radius_bottom, const int segments, const bool cap_ends, const short oflag);
+ const float radius_top, const float radius_bottom, const int segments, const bool cap_ends,
+ const short oflag, const int cd_loop_uv_offset);
void BM_mesh_calc_uvs_cube(BMesh *bm, const short oflag);
#include "intern/bmesh_operator_api_inline.h"
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
index c500d7b9ec2..a4621b45fe6 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -132,7 +132,7 @@ static void bm_face_calc_poly_center_mean_vertex_cos(
*/
void BM_face_calc_tessellation(
const BMFace *f, const bool use_fixed_quad,
- BMLoop **r_loops, unsigned int (*r_index)[3])
+ BMLoop **r_loops, uint (*r_index)[3])
{
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
BMLoop *l_iter;
@@ -196,7 +196,7 @@ void BM_face_calc_point_in_face(const BMFace *f, float r_co[3])
* but without this we can't be sure the point is inside a concave face. */
const int tottri = f->len - 2;
BMLoop **loops = BLI_array_alloca(loops, f->len);
- unsigned int (*index)[3] = BLI_array_alloca(index, tottri);
+ uint (*index)[3] = BLI_array_alloca(index, tottri);
int j;
int j_best = 0; /* use as fallback when unset */
float area_best = -1.0f;
@@ -225,24 +225,16 @@ void BM_face_calc_point_in_face(const BMFace *f, float r_co[3])
*/
float BM_face_calc_area(const BMFace *f)
{
+ /* inline 'area_poly_v3' logic, avoid creating a temp array */
const BMLoop *l_iter, *l_first;
- float (*verts)[3] = BLI_array_alloca(verts, f->len);
- float area;
- unsigned int i = 0;
+ float n[3];
+ zero_v3(n);
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
- copy_v3_v3(verts[i++], l_iter->v->co);
+ add_newell_cross_v3_v3v3(n, l_iter->v->co, l_iter->next->v->co);
} while ((l_iter = l_iter->next) != l_first);
-
- if (f->len == 3) {
- area = area_tri_v3(verts[0], verts[1], verts[2]);
- }
- else {
- area = area_poly_v3((const float (*)[3])verts, f->len);
- }
-
- return area;
+ return len_v3(n) * 0.5f;
}
/**
@@ -583,11 +575,11 @@ void BM_face_calc_center_mean_weighted(const BMFace *f, float r_cent[3])
* Rotates a polygon so that it's
* normal is pointing towards the mesh Z axis
*/
-void poly_rotate_plane(const float normal[3], float (*verts)[3], const unsigned int nverts)
+void poly_rotate_plane(const float normal[3], float (*verts)[3], const uint nverts)
{
float mat[3][3];
float co[3];
- unsigned int i;
+ uint i;
co[2] = 0.0f;
@@ -852,7 +844,7 @@ void BM_face_normal_flip_ex(
BMesh *bm, BMFace *f,
const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip)
{
- bmesh_loop_reverse(bm, f, cd_loop_mdisp_offset, use_loop_mdisp_flip);
+ bmesh_kernel_loop_reverse(bm, f, cd_loop_mdisp_offset, use_loop_mdisp_flip);
negate_v3(f->no);
}
@@ -949,7 +941,7 @@ void BM_face_triangulate(
{
BMLoop **loops = BLI_array_alloca(loops, f->len);
- unsigned int (*tris)[3] = BLI_array_alloca(tris, f->len);
+ uint (*tris)[3] = BLI_array_alloca(tris, f->len);
const int totfilltri = f->len - 2;
const int last_tri = f->len - 3;
int i;
@@ -1433,7 +1425,7 @@ void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptri
float axis_mat[3][3];
float (*projverts)[2];
- unsigned int (*tris)[3];
+ uint (*tris)[3];
const int totfilltri = efa->len - 2;
@@ -1459,7 +1451,7 @@ void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptri
for (j = 0; j < totfilltri; j++) {
BMLoop **l_ptr = looptris[i++];
- unsigned int *tri = tris[j];
+ uint *tri = tris[j];
l_ptr[0] = l_arr[tri[0]];
l_ptr[1] = l_arr[tri[1]];
diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h
index 1e50a504875..d944f3a8bc5 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.h
+++ b/source/blender/bmesh/intern/bmesh_polygon.h
@@ -36,7 +36,7 @@ void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptr
void BM_face_calc_tessellation(
const BMFace *f, const bool use_fixed_quad,
- BMLoop **r_loops, unsigned int (*r_index)[3]);
+ BMLoop **r_loops, uint (*r_index)[3]);
void BM_face_calc_point_in_face(const BMFace *f, float r_co[3]);
float BM_face_calc_normal(const BMFace *f, float r_no[3]) ATTR_NONNULL();
float BM_face_calc_normal_vcos(
diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
index 5ee0e904a33..e515f9af63f 100644
--- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
+++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
@@ -62,15 +62,16 @@
#define EDGE_NET _FLAG_WALK
/* tag verts we've visit */
#define VERT_VISIT _FLAG_WALK
+#define VERT_IN_QUEUE _FLAG_WALK_ALT
struct VertOrder {
float angle;
BMVert *v;
};
-static unsigned int bm_edge_flagged_radial_count(BMEdge *e)
+static uint bm_edge_flagged_radial_count(BMEdge *e)
{
- unsigned int count = 0;
+ uint count = 0;
BMLoop *l;
if ((l = e->l)) {
@@ -133,7 +134,7 @@ static bool bm_face_split_edgenet_find_loop_pair(
e = e_first = v_init->e;
do {
if (BM_ELEM_API_FLAG_TEST(e, EDGE_NET)) {
- const unsigned int count = bm_edge_flagged_radial_count(e);
+ const uint count = bm_edge_flagged_radial_count(e);
if (count == 1) {
BLI_SMALLSTACK_PUSH(edges_boundary, e);
edges_boundary_len++;
@@ -161,7 +162,7 @@ static bool bm_face_split_edgenet_find_loop_pair(
e_pair[1] = BLI_SMALLSTACK_POP(edges_boundary);
if (edges_boundary_len > 2) {
- BLI_SMALLSTACK_SWAP(edges_search, edges_wire);
+ BLI_SMALLSTACK_SWAP(edges_search, edges_boundary);
}
}
else {
@@ -238,7 +239,7 @@ static bool bm_face_split_edgenet_find_loop_pair_exists(
e = e_first = v_init->e;
do {
if (BM_ELEM_API_FLAG_TEST(e, EDGE_NET)) {
- const unsigned int count = bm_edge_flagged_radial_count(e);
+ const uint count = bm_edge_flagged_radial_count(e);
if (count == 1) {
edges_boundary_len++;
}
@@ -274,7 +275,7 @@ static bool bm_face_split_edgenet_find_loop_pair_exists(
static bool bm_face_split_edgenet_find_loop_walk(
BMVert *v_init, const float face_normal[3],
/* cache to avoid realloc every time */
- struct VertOrder *edge_order, const unsigned int edge_order_len,
+ struct VertOrder *edge_order, const uint edge_order_len,
BMEdge *e_pair[2])
{
/* fast-path for the common case (avoid push-pop).
@@ -381,7 +382,7 @@ walk_nofork:
/* sort by angle if needed */
if (STACK_SIZE(edge_order) > 1) {
- unsigned int j;
+ uint j;
BMVert *v_prev = BM_edge_other_vert(v->e, v);
for (j = 0; j < STACK_SIZE(edge_order); j++) {
@@ -420,7 +421,7 @@ finally:
static bool bm_face_split_edgenet_find_loop(
BMVert *v_init, const float face_normal[3], float face_normal_matrix[3][3],
/* cache to avoid realloc every time */
- struct VertOrder *edge_order, const unsigned int edge_order_len,
+ struct VertOrder *edge_order, const uint edge_order_len,
BMVert **r_face_verts, int *r_face_verts_len)
{
BMEdge *e_pair[2];
@@ -434,7 +435,7 @@ static bool bm_face_split_edgenet_find_loop(
(bm_edge_flagged_radial_count(e_pair[1]) == 1));
if (bm_face_split_edgenet_find_loop_walk(v_init, face_normal, edge_order, edge_order_len, e_pair)) {
- unsigned int i = 0;
+ uint i = 0;
r_face_verts[i++] = v_init;
v = BM_edge_other_vert(e_pair[1], v_init);
@@ -474,7 +475,7 @@ bool BM_face_split_edgenet(
int i;
struct VertOrder *edge_order;
- const unsigned int edge_order_len = edge_net_len + 2;
+ const uint edge_order_len = edge_net_len + 2;
BMVert *v;
@@ -512,13 +513,21 @@ bool BM_face_split_edgenet(
} while ((l_iter = l_iter->next) != l_first);
#endif
+ /* Note: 'VERT_IN_QUEUE' is often not needed at all,
+ * however in rare cases verts are added multiple times to the queue,
+ * that on it's own is harmless but in _very_ rare cases,
+ * the queue will overflow its maximum size,
+ * so we better be strict about this! see: T51539 */
for (i = 0; i < edge_net_len; i++) {
BM_ELEM_API_FLAG_ENABLE(edge_net[i], EDGE_NET);
+ BM_ELEM_API_FLAG_DISABLE(edge_net[i]->v1, VERT_IN_QUEUE);
+ BM_ELEM_API_FLAG_DISABLE(edge_net[i]->v2, VERT_IN_QUEUE);
}
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
BM_ELEM_API_FLAG_ENABLE(l_iter->e, EDGE_NET);
+ BM_ELEM_API_FLAG_DISABLE(l_iter->v, VERT_IN_QUEUE);
} while ((l_iter = l_iter->next) != l_first);
float face_normal_matrix[3][3];
@@ -527,8 +536,10 @@ bool BM_face_split_edgenet(
/* any vert can be used to begin with */
STACK_PUSH(vert_queue, l_first->v);
+ BM_ELEM_API_FLAG_ENABLE(l_first->v, VERT_IN_QUEUE);
while ((v = STACK_POP(vert_queue))) {
+ BM_ELEM_API_FLAG_DISABLE(v, VERT_IN_QUEUE);
if (bm_face_split_edgenet_find_loop(
v, f->no, face_normal_matrix,
edge_order, edge_order_len, face_verts, &face_verts_len))
@@ -558,8 +569,12 @@ bool BM_face_split_edgenet(
* (verts between boundary and manifold edges) */
l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
do {
- if (bm_face_split_edgenet_find_loop_pair_exists(l_iter->v)) {
+ /* Avoid adding to queue multiple times (not common but happens). */
+ if (!BM_ELEM_API_FLAG_TEST(l_iter->v, VERT_IN_QUEUE) &&
+ bm_face_split_edgenet_find_loop_pair_exists(l_iter->v))
+ {
STACK_PUSH(vert_queue, l_iter->v);
+ BM_ELEM_API_FLAG_ENABLE(l_iter->v, VERT_IN_QUEUE);
}
} while ((l_iter = l_iter->next) != l_first);
}
@@ -721,13 +736,13 @@ BLI_INLINE bool edge_isect_verts_point_2d(
*/
struct EdgeGroupIsland {
LinkNode edge_links; /* keep first */
- unsigned int vert_len, edge_len;
+ uint vert_len, edge_len;
/* Set the following vars once we have >1 groups */
/* when when an edge in a previous group connects to this one,
* so theres no need to create one pointing back. */
- unsigned int has_prev_edge : 1;
+ uint has_prev_edge : 1;
/* verts in the group which has the lowest & highest values,
* the lower vertex is connected to the first edge */
@@ -758,7 +773,7 @@ struct Edges_VertVert_BVHTreeTest {
BMVert *v_origin;
BMVert *v_other;
- const unsigned int *vert_range;
+ const uint *vert_range;
};
struct Edges_VertRay_BVHTreeTest {
@@ -766,7 +781,7 @@ struct Edges_VertRay_BVHTreeTest {
BMVert *v_origin;
- const unsigned int *vert_range;
+ const uint *vert_range;
};
static void bvhtree_test_edges_isect_2d_vert_cb(
@@ -831,12 +846,12 @@ static void bvhtree_test_edges_isect_2d_ray_cb(
struct EdgeGroup_FindConnection_Args {
BVHTree *bvhtree;
BMEdge **edge_arr;
- unsigned int edge_arr_len;
+ uint edge_arr_len;
BMEdge **edge_arr_new;
- unsigned int edge_arr_new_len;
+ uint edge_arr_new_len;
- const unsigned int *vert_range;
+ const uint *vert_range;
};
static BMEdge *test_edges_isect_2d_vert(
@@ -869,7 +884,7 @@ static BMEdge *test_edges_isect_2d_vert(
/* check existing connections (no spatial optimization here since we're continually adding). */
if (LIKELY(index == -1)) {
float t_best = 1.0f;
- for (unsigned int i = 0; i < args->edge_arr_new_len; i++) {
+ for (uint i = 0; i < args->edge_arr_new_len; i++) {
float co_isect[2];
if (UNLIKELY(edge_isect_verts_point_2d(args->edge_arr_new[i], v_origin, v_other, co_isect))) {
const float t_test = line_point_factor_v2(co_isect, v_origin->co, v_other->co);
@@ -914,7 +929,7 @@ static BMEdge *test_edges_isect_2d_ray(
/* check existing connections (no spatial optimization here since we're continually adding). */
if (LIKELY(index != -1)) {
- for (unsigned int i = 0; i < args->edge_arr_new_len; i++) {
+ for (uint i = 0; i < args->edge_arr_new_len; i++) {
BMEdge *e = args->edge_arr_new[i];
float dist_new;
if (isect_ray_seg_v2(v_origin->co, dir, e->v1->co, e->v2->co, &dist_new, NULL)) {
@@ -1031,7 +1046,7 @@ static BMVert *bm_face_split_edgenet_partial_connect(BMesh *bm, BMVert *v_delimi
/* initial check - see if we have 3+ flagged edges attached to 'v_delimit'
* if not, we can early exit */
LinkNode *e_delimit_list = NULL;
- unsigned int e_delimit_list_len = 0;
+ uint e_delimit_list_len = 0;
#define EDGE_NOT_IN_STACK BM_ELEM_INTERNAL_TAG
#define VERT_NOT_IN_STACK BM_ELEM_INTERNAL_TAG
@@ -1169,10 +1184,10 @@ static bool bm_vert_partial_connect_check_overlap(
*/
bool BM_face_split_edgenet_connect_islands(
BMesh *bm,
- BMFace *f, BMEdge **edge_net_init, const unsigned int edge_net_init_len,
+ BMFace *f, BMEdge **edge_net_init, const uint edge_net_init_len,
bool use_partial_connect,
MemArena *mem_arena,
- BMEdge ***r_edge_net_new, unsigned int *r_edge_net_new_len)
+ BMEdge ***r_edge_net_new, uint *r_edge_net_new_len)
{
/* -------------------------------------------------------------------- */
/* This function has 2 main parts.
@@ -1186,7 +1201,7 @@ bool BM_face_split_edgenet_connect_islands(
* (avoid thrashing the area when the initial check isn't so intensive on the stack).
*/
- const unsigned int edge_arr_len = (unsigned int)edge_net_init_len + (unsigned int)f->len;
+ const uint edge_arr_len = (uint)edge_net_init_len + (uint)f->len;
BMEdge **edge_arr = BLI_array_alloca(edge_arr, edge_arr_len);
bool ok = false;
@@ -1197,7 +1212,7 @@ bool BM_face_split_edgenet_connect_islands(
#define VERT_NOT_IN_STACK BM_ELEM_INTERNAL_TAG
{
- unsigned int i = edge_net_init_len;
+ uint i = edge_net_init_len;
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
@@ -1206,7 +1221,7 @@ bool BM_face_split_edgenet_connect_islands(
BLI_assert(i == edge_arr_len);
}
- for (unsigned int i = 0; i < edge_arr_len; i++) {
+ for (uint i = 0; i < edge_arr_len; i++) {
BM_elem_flag_enable(edge_arr[i], EDGE_NOT_IN_STACK);
BM_elem_flag_enable(edge_arr[i]->v1, VERT_NOT_IN_STACK);
BM_elem_flag_enable(edge_arr[i]->v2, VERT_NOT_IN_STACK);
@@ -1224,12 +1239,12 @@ bool BM_face_split_edgenet_connect_islands(
struct {
struct TempVertPair *list;
- unsigned int len;
+ uint len;
int *remap; /* temp -> orig mapping */
} temp_vert_pairs = {NULL};
if (use_partial_connect) {
- for (unsigned int i = 0; i < edge_net_init_len; i++) {
+ for (uint i = 0; i < edge_net_init_len; i++) {
for (unsigned j = 0; j < 2; j++) {
BMVert *v_delimit = (&edge_arr[i]->v1)[j];
BMVert *v_other;
@@ -1254,19 +1269,19 @@ bool BM_face_split_edgenet_connect_islands(
- unsigned int group_arr_len = 0;
+ uint group_arr_len = 0;
LinkNode *group_head = NULL;
{
/* scan 'edge_arr' backwards so the outer face boundary is handled first
* (since its likely to be the largest) */
- unsigned int edge_index = (edge_arr_len - 1);
- unsigned int edge_in_group_tot = 0;
+ uint edge_index = (edge_arr_len - 1);
+ uint edge_in_group_tot = 0;
BLI_SMALLSTACK_DECLARE(vstack, BMVert *);
while (true) {
LinkNode *edge_links = NULL;
- unsigned int unique_verts_in_group = 0, unique_edges_in_group = 0;
+ uint unique_verts_in_group = 0, unique_edges_in_group = 0;
/* list of groups */
BLI_assert(BM_elem_flag_test(edge_arr[edge_index]->v1, VERT_NOT_IN_STACK));
@@ -1333,7 +1348,7 @@ bool BM_face_split_edgenet_connect_islands(
#define VERT_IN_ARRAY BM_ELEM_INTERNAL_TAG
struct EdgeGroupIsland **group_arr = BLI_memarena_alloc(mem_arena, sizeof(*group_arr) * group_arr_len);
- unsigned int vert_arr_len = 0;
+ uint vert_arr_len = 0;
/* sort groups by lowest value vertex */
{
/* fill 'groups_arr' in reverse order so the boundary face is first */
@@ -1389,7 +1404,7 @@ bool BM_face_split_edgenet_connect_islands(
/* we don't know how many unique verts there are connecting the edges, so over-alloc */
BMVert **vert_arr = BLI_memarena_alloc(mem_arena, sizeof(*vert_arr) * vert_arr_len);
/* map vertex -> group index */
- unsigned int *verts_group_table = BLI_memarena_alloc(mem_arena, sizeof(*verts_group_table) * vert_arr_len);
+ uint *verts_group_table = BLI_memarena_alloc(mem_arena, sizeof(*verts_group_table) * vert_arr_len);
float (*vert_coords_backup)[3] = BLI_memarena_alloc(mem_arena, sizeof(*vert_coords_backup) * vert_arr_len);
@@ -1398,7 +1413,7 @@ bool BM_face_split_edgenet_connect_islands(
const float f_co_ref[3] = {UNPACK3(BM_FACE_FIRST_LOOP(f)->v->co)};
int v_index = 0; /* global vert index */
- for (unsigned int g_index = 0; g_index < group_arr_len; g_index++) {
+ for (uint g_index = 0; g_index < group_arr_len; g_index++) {
LinkNode *edge_links = group_arr[g_index]->edge_links.link;
do {
BMEdge *e = edge_links->link;
@@ -1436,7 +1451,7 @@ bool BM_face_split_edgenet_connect_islands(
/* Now create bvh tree*/
BVHTree *bvhtree = BLI_bvhtree_new(edge_arr_len, 0.0f, 8, 8);
- for (unsigned int i = 0; i < edge_arr_len; i++) {
+ for (uint i = 0; i < edge_arr_len; i++) {
const float e_cos[2][3] = {
{UNPACK2(edge_arr[i]->v1->co), 0.0f},
{UNPACK2(edge_arr[i]->v2->co), 0.0f},
@@ -1465,15 +1480,15 @@ bool BM_face_split_edgenet_connect_islands(
/* Create connections between groups */
/* may be an over-alloc, but not by much */
- unsigned int edge_net_new_len = (unsigned int)edge_net_init_len + ((group_arr_len - 1) * 2);
+ uint edge_net_new_len = (uint)edge_net_init_len + ((group_arr_len - 1) * 2);
BMEdge **edge_net_new = BLI_memarena_alloc(mem_arena, sizeof(*edge_net_new) * edge_net_new_len);
memcpy(edge_net_new, edge_net_init, sizeof(*edge_net_new) * (size_t)edge_net_init_len);
{
- unsigned int edge_net_new_index = edge_net_init_len;
+ uint edge_net_new_index = edge_net_init_len;
/* start-end of the verts in the current group */
- unsigned int vert_range[2];
+ uint vert_range[2];
vert_range[0] = 0;
vert_range[1] = group_arr[0]->vert_len;
@@ -1492,7 +1507,7 @@ bool BM_face_split_edgenet_connect_islands(
.vert_range = vert_range,
};
- for (unsigned int g_index = 1; g_index < group_arr_len; g_index++) {
+ for (uint g_index = 1; g_index < group_arr_len; g_index++) {
struct EdgeGroupIsland *g = group_arr[g_index];
/* the range of verts this group uses in 'verts_arr' (not uncluding the last index) */
@@ -1551,7 +1566,7 @@ bool BM_face_split_edgenet_connect_islands(
}
/* tell the 'next' group it doesn't need to create its own back-link */
- unsigned int g_index_other = verts_group_table[index_other];
+ uint g_index_other = verts_group_table[index_other];
group_arr[g_index_other]->has_prev_edge = true;
}
}
@@ -1567,7 +1582,7 @@ bool BM_face_split_edgenet_connect_islands(
*r_edge_net_new_len = edge_net_new_len;
ok = true;
- for (unsigned int i = 0; i < vert_arr_len; i++) {
+ for (uint i = 0; i < vert_arr_len; i++) {
copy_v3_v3(vert_arr[i]->co, vert_coords_backup[i]);
}
@@ -1600,7 +1615,7 @@ finally:
/* Remove edges which have become doubles since splicing vertices together,
* its less trouble then detecting future-doubles on edge-creation. */
- for (unsigned int i = edge_net_init_len; i < edge_net_new_len; i++) {
+ for (uint i = edge_net_init_len; i < edge_net_new_len; i++) {
while (BM_edge_find_double(edge_net_new[i])) {
BM_edge_kill(bm, edge_net_new[i]);
edge_net_new_len--;
@@ -1616,7 +1631,7 @@ finally:
#endif
- for (unsigned int i = 0; i < edge_arr_len; i++) {
+ for (uint i = 0; i < edge_arr_len; i++) {
BM_elem_flag_disable(edge_arr[i], EDGE_NOT_IN_STACK);
BM_elem_flag_disable(edge_arr[i]->v1, VERT_NOT_IN_STACK);
BM_elem_flag_disable(edge_arr[i]->v2, VERT_NOT_IN_STACK);
diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.h b/source/blender/bmesh/intern/bmesh_polygon_edgenet.h
index 72ae7695f0f..bf5cea59e30 100644
--- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.h
+++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.h
@@ -32,10 +32,10 @@ bool BM_face_split_edgenet(
bool BM_face_split_edgenet_connect_islands(
BMesh *bm,
- BMFace *f, BMEdge **edge_net_init, const unsigned int edge_net_init_len,
+ BMFace *f, BMEdge **edge_net_init, const uint edge_net_init_len,
bool use_partial_connect,
struct MemArena *arena,
- BMEdge ***r_edge_net_new, unsigned int *r_edge_net_new_len)
+ BMEdge ***r_edge_net_new, uint *r_edge_net_new_len)
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3, 6, 7, 8);
#endif /* __BMESH_POLYGON_EDGENET_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h
index d8d297c9298..4161fbe90fb 100644
--- a/source/blender/bmesh/intern/bmesh_private.h
+++ b/source/blender/bmesh/intern/bmesh_private.h
@@ -73,7 +73,7 @@ enum {
};
#define BM_ELEM_API_FLAG_ENABLE(element, f) { ((element)->head.api_flag |= (f)); } (void)0
-#define BM_ELEM_API_FLAG_DISABLE(element, f) { ((element)->head.api_flag &= (unsigned char)~(f)); } (void)0
+#define BM_ELEM_API_FLAG_DISABLE(element, f) { ((element)->head.api_flag &= (uchar)~(f)); } (void)0
#define BM_ELEM_API_FLAG_TEST(element, f) ((element)->head.api_flag & (f))
#define BM_ELEM_API_FLAG_CLEAR(element) { ((element)->head.api_flag = 0); } (void)0
diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c
index b5f9575aff5..668fb998254 100644
--- a/source/blender/bmesh/intern/bmesh_queries.c
+++ b/source/blender/bmesh/intern/bmesh_queries.c
@@ -102,17 +102,10 @@ BMLoop *BM_loop_other_edge_loop(BMLoop *l, BMVert *v)
*/
BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v)
{
- BMIter liter;
- BMLoop *l_iter;
+ BMLoop *l_iter = BM_face_vert_share_loop(f, v);
BLI_assert(BM_edge_exists(v_prev, v) != NULL);
- BM_ITER_ELEM (l_iter, &liter, v, BM_LOOPS_OF_VERT) {
- if (l_iter->f == f) {
- break;
- }
- }
-
if (l_iter) {
if (l_iter->prev->v == v_prev) {
return l_iter->next;
@@ -149,7 +142,6 @@ BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v)
* The faces loop direction is ignored.
* </pre>
*/
-
BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v)
{
#if 0 /* works but slow */
@@ -178,9 +170,6 @@ BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v)
return l->next->next;
}
}
-
-
-
#endif
}
@@ -392,17 +381,7 @@ BMFace *BM_vert_pair_share_face_by_angle(
*/
BMLoop *BM_vert_find_first_loop(BMVert *v)
{
- BMEdge *e;
-
- if (!v->e)
- return NULL;
-
- e = bmesh_disk_faceedge_find_first(v->e, v);
-
- if (!e)
- return NULL;
-
- return bmesh_radial_faceloop_find_first(e->l, v);
+ return v->e ? bmesh_disk_faceloop_find_first(v->e, v) : NULL;
}
/**
@@ -878,9 +857,18 @@ int BM_vert_face_count_ex(const BMVert *v, int count_max)
*
* same as ``BM_vert_face_count(v) != 0`` or ``BM_vert_find_first_loop(v) == NULL``
*/
-bool BM_vert_face_check(BMVert *v)
+bool BM_vert_face_check(const BMVert *v)
{
- return v->e && (bmesh_disk_faceedge_find_first(v->e, v) != NULL);
+ if (v->e != NULL) {
+ const BMEdge *e_iter, *e_first;
+ e_first = e_iter = v->e;
+ do {
+ if (e_iter->l != NULL) {
+ return true;
+ }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
+ }
+ return false;
}
/**
@@ -910,7 +898,7 @@ bool BM_vert_is_wire(const BMVert *v)
* A vertex is non-manifold if it meets the following conditions:
* 1: Loose - (has no edges/faces incident upon it).
* 2: Joins two distinct regions - (two pyramids joined at the tip).
- * 3: Is part of a an edge with more than 2 faces.
+ * 3: Is part of an edge with more than 2 faces.
* 4: Is part of a wire edge.
*/
bool BM_vert_is_manifold(const BMVert *v)
@@ -926,7 +914,8 @@ bool BM_vert_is_manifold(const BMVert *v)
/* count edges while looking for non-manifold edges */
e_first = e_iter = v->e;
- l_first = e_iter->l ? e_iter->l : NULL;
+ /* may be null */
+ l_first = e_iter->l;
do {
/* loose edge or edge shared by more than two faces,
* edges with 1 face user are OK, otherwise we could
@@ -1522,20 +1511,68 @@ float BM_loop_calc_face_angle(const BMLoop *l)
* Calculate the normal at this loop corner or fallback to the face normal on straight lines.
*
* \param l The loop to calculate the normal at
+ * \param epsilon: Value to avoid numeric errors (1e-5f works well).
* \param r_normal Resulting normal
*/
-void BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3])
+float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon_sq, float r_normal[3])
{
- if (normal_tri_v3(r_normal,
- l->prev->v->co,
- l->v->co,
- l->next->v->co) != 0.0f)
- {
- /* pass */
+ /* Note: we cannot use result of normal_tri_v3 here to detect colinear vectors (vertex on a straight line)
+ * from zero value, because it does not normalize both vectors before making crossproduct.
+ * Instead of adding two costly normalize computations, just check ourselves for colinear case. */
+ /* Note: FEPSILON might need some finer tweaking at some point? Seems to be working OK for now though. */
+ float v1[3], v2[3], v_tmp[3];
+ sub_v3_v3v3(v1, l->prev->v->co, l->v->co);
+ sub_v3_v3v3(v2, l->next->v->co, l->v->co);
+
+ const float fac =
+ ((v2[0] == 0.0f) ?
+ ((v2[1] == 0.0f) ?
+ ((v2[2] == 0.0f) ? 0.0f : v1[2] / v2[2]) : v1[1] / v2[1]) : v1[0] / v2[0]);
+
+ mul_v3_v3fl(v_tmp, v2, fac);
+ sub_v3_v3(v_tmp, v1);
+ if (fac != 0.0f && !is_zero_v3(v1) && len_squared_v3(v_tmp) > epsilon_sq) {
+ /* Not co-linear, we can compute crossproduct and normalize it into normal. */
+ cross_v3_v3v3(r_normal, v1, v2);
+ return normalize_v3(r_normal);
}
else {
copy_v3_v3(r_normal, l->f->no);
+ return 0.0f;
+ }
+}
+
+/**
+ * #BM_loop_calc_face_normal_safe_ex with pre-defined sane epsilon.
+ *
+ * Since this doesn't scale baed on triangle size, fixed value works well.
+ */
+float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3])
+{
+ return BM_loop_calc_face_normal_safe_ex(l, 1e-5f, r_normal);
+}
+
+/**
+ * \brief BM_loop_calc_face_normal
+ *
+ * Calculate the normal at this loop corner or fallback to the face normal on straight lines.
+ *
+ * \param l The loop to calculate the normal at
+ * \param r_normal Resulting normal
+ * \return The length of the cross product (double the area).
+ */
+float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3])
+{
+ float v1[3], v2[3];
+ sub_v3_v3v3(v1, l->prev->v->co, l->v->co);
+ sub_v3_v3v3(v2, l->next->v->co, l->v->co);
+
+ cross_v3_v3v3(r_normal, v1, v2);
+ const float len = normalize_v3(r_normal);
+ if (UNLIKELY(len == 0.0f)) {
+ copy_v3_v3(r_normal, l->f->no);
}
+ return len;
}
/**
@@ -1924,7 +1961,7 @@ BMEdge *BM_edge_find_double(BMEdge *e)
*
* \note there used to be a BM_face_exists_overlap function that checks for partial overlap.
*/
-bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface)
+BMFace *BM_face_exists(BMVert **varr, int len)
{
if (varr[0]->e) {
BMEdge *e_iter, *e_first;
@@ -1963,10 +2000,7 @@ bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface)
}
if (i_walk == len) {
- if (r_existface) {
- *r_existface = l_iter_radial->f;
- }
- return true;
+ return l_iter_radial->f;
}
}
} while ((l_iter_radial = l_iter_radial->radial_next) != l_first_radial);
@@ -1975,10 +2009,7 @@ bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface)
} while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, varr[0])) != e_first);
}
- if (r_existface) {
- *r_existface = NULL;
- }
- return false;
+ return NULL;
}
@@ -2121,26 +2152,21 @@ bool BM_face_exists_multi_edge(BMEdge **earr, int len)
* \note The face may contain other verts \b not in \a varr.
*
* \note Its possible there are more than one overlapping faces,
- * in this case the first one found will be assigned to \a r_f_overlap.
+ * in this case the first one found will be returned.
*
* \param varr Array of unordered verts.
* \param len \a varr array length.
- * \param r_f_overlap The overlapping face to return.
- * \return Success
+ * \return The face or NULL.
*/
-bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap)
+BMFace *BM_face_exists_overlap(BMVert **varr, const int len)
{
BMIter viter;
BMFace *f;
int i;
- bool is_overlap = false;
+ BMFace *f_overlap = NULL;
LinkNode *f_lnk = NULL;
- if (r_f_overlap) {
- *r_f_overlap = NULL;
- }
-
#ifdef DEBUG
/* check flag isn't already set */
for (i = 0; i < len; i++) {
@@ -2154,10 +2180,7 @@ bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap)
BM_ITER_ELEM (f, &viter, varr[i], BM_FACES_OF_VERT) {
if (BM_ELEM_API_FLAG_TEST(f, _FLAG_OVERLAP) == 0) {
if (len <= BM_verts_in_face_count(varr, len, f)) {
- if (r_f_overlap)
- *r_f_overlap = f;
-
- is_overlap = true;
+ f_overlap = f;
break;
}
@@ -2171,7 +2194,7 @@ bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap)
BM_ELEM_API_FLAG_DISABLE((BMFace *)f_lnk->link, _FLAG_OVERLAP);
}
- return is_overlap;
+ return f_overlap;
}
/**
@@ -2351,7 +2374,7 @@ static void bm_mesh_calc_volume_face(const BMFace *f, float *r_vol)
{
const int tottri = f->len - 2;
BMLoop **loops = BLI_array_alloca(loops, f->len);
- unsigned int (*index)[3] = BLI_array_alloca(index, tottri);
+ uint (*index)[3] = BLI_array_alloca(index, tottri);
int j;
BM_face_calc_tessellation(f, false, loops, index);
@@ -2420,8 +2443,8 @@ int BM_mesh_calc_face_groups(
int group_curr = 0;
- unsigned int tot_faces = 0;
- unsigned int tot_touch = 0;
+ uint tot_faces = 0;
+ uint tot_touch = 0;
BMFace **stack;
STACK_DECLARE(stack);
@@ -2578,8 +2601,8 @@ int BM_mesh_calc_edge_groups(
int group_curr = 0;
- unsigned int tot_edges = 0;
- unsigned int tot_touch = 0;
+ uint tot_edges = 0;
+ uint tot_touch = 0;
BMEdge **stack;
STACK_DECLARE(stack);
diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h
index 10e4b9a15aa..83977fa8be0 100644
--- a/source/blender/bmesh/intern/bmesh_queries.h
+++ b/source/blender/bmesh/intern/bmesh_queries.h
@@ -86,7 +86,7 @@ BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e) ATTR_WARN_UNUSED_RESULT AT
bool BM_vert_is_edge_pair(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b);
-bool BM_vert_face_check(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_vert_face_check(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_is_wire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -113,7 +113,9 @@ BMLoop *BM_loop_find_prev_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq
BMLoop *BM_loop_find_next_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq);
float BM_loop_calc_face_angle(const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-void BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3]) ATTR_NONNULL();
+float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3]) ATTR_NONNULL();
+float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3]) ATTR_NONNULL();
+float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon, float r_normal[3]) ATTR_NONNULL();
void BM_loop_calc_face_direction(const BMLoop *l, float r_normal[3]);
void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3]);
@@ -135,12 +137,12 @@ BMLoop *BM_face_find_longest_loop(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNUL
BMEdge *BM_edge_exists(BMVert *v1, BMVert *v2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMEdge *BM_edge_find_double(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface) ATTR_NONNULL(1);
+BMFace *BM_face_exists(BMVert **varr, int len) ATTR_NONNULL(1);
bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_face_exists_multi_edge(BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+BMFace *BM_face_exists_overlap(BMVert **varr, const int len) ATTR_WARN_UNUSED_RESULT;
bool BM_face_exists_overlap_subset(BMVert **varr, const int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BM_face_share_face_count(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
diff --git a/source/blender/bmesh/intern/bmesh_strands_conv.c b/source/blender/bmesh/intern/bmesh_strands_conv.c
index d74ceac4d32..6cd39798126 100644
--- a/source/blender/bmesh/intern/bmesh_strands_conv.c
+++ b/source/blender/bmesh/intern/bmesh_strands_conv.c
@@ -159,12 +159,12 @@ static KeyBlock *bm_set_shapekey_from_psys(BMesh *bm, ParticleSystem *psys, int
#endif
/* create vertex and edge data for BMesh based on particle hair keys */
-static void bm_make_particles(BMesh *bm, Object *ob, ParticleSystem *psys, struct DerivedMesh *emitter_dm, float (*keyco)[3], int cd_shape_keyindex_offset)
+static void bm_make_particles(BMesh *bm, Object *ob, ParticleSystem *psys, struct DerivedMesh *emitter_dm, float (*keyco)[3], int UNUSED(cd_shape_keyindex_offset))
{
// KeyBlock *block;
ParticleData *pa;
HairKey *hkey;
- int p, k, j;
+ int p, k;
int vindex, eindex;
BMVert *v = NULL, *v_prev;
@@ -265,9 +265,9 @@ static void bm_make_particles(BMesh *bm, Object *ob, ParticleSystem *psys, struc
* \brief ParticleSystem -> BMesh
*/
void BM_strands_bm_from_psys(BMesh *bm, Object *ob, ParticleSystem *psys, struct DerivedMesh *emitter_dm,
- const bool set_key, int act_key_nr)
+ const bool set_key, int UNUSED(act_key_nr))
{
- KeyBlock *actkey;
+ /*KeyBlock *actkey;*/
float (*keyco)[3] = NULL;
int totvert, totedge;
@@ -507,7 +507,7 @@ static void make_particle_hair(BMesh *bm, BMVert *root, Object *ob, ParticleSyst
void BM_strands_bm_to_psys(BMesh *bm, Object *ob, ParticleSystem *psys, struct DerivedMesh *emitter_dm, struct BVHTreeFromMesh *emitter_bvhtree)
{
ParticleData *particles, *oldparticles;
- int ototpart, ototkey, ntotpart;
+ int ototpart, ntotpart;
BMVert *root;
BMIter iter;
@@ -515,7 +515,6 @@ void BM_strands_bm_to_psys(BMesh *bm, Object *ob, ParticleSystem *psys, struct D
int p;
ototpart = psys->totpart;
- ototkey = BM_strands_count_psys_keys(psys);
ntotpart = BM_strands_count(bm);
@@ -711,11 +710,11 @@ void BM_strands_bm_to_psys(BMesh *bm, Object *ob, ParticleSystem *psys, struct D
#endif
if (oldparticles) {
- ParticleData *pa;
- int p;
- for (p = 0, pa = oldparticles; p < ototpart; ++p, ++pa)
- if (pa->hair)
- MEM_freeN(pa->hair);
+ ParticleData *opa;
+ int op;
+ for (op = 0, opa = oldparticles; op < ototpart; ++op, ++opa)
+ if (opa->hair)
+ MEM_freeN(opa->hair);
MEM_freeN(oldparticles);
}
}
diff --git a/source/blender/bmesh/intern/bmesh_structure.c b/source/blender/bmesh/intern/bmesh_structure.c
index cb302139a4c..8e484841568 100644
--- a/source/blender/bmesh/intern/bmesh_structure.c
+++ b/source/blender/bmesh/intern/bmesh_structure.c
@@ -143,7 +143,7 @@ void bmesh_disk_vert_replace(BMEdge *e, BMVert *v_dst, BMVert *v_src)
* to store non-manifold conditions since BM does not keep track of region/shell information.
*
* Functions relating to this cycle:
- * - #bmesh_radial_append
+ * - #bmesh_radial_loop_append
* - #bmesh_radial_loop_remove
* - #bmesh_radial_facevert_count
* - #bmesh_radial_facevert_check
@@ -264,10 +264,12 @@ bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v)
{
BMEdge *e_iter;
- if (!BM_vert_in_edge(e, v))
+ if (!BM_vert_in_edge(e, v)) {
return false;
- if (bmesh_disk_count_ex(v, len + 1) != len || len == 0)
+ }
+ if (len == 0 || bmesh_disk_count_ex(v, len + 1) != len) {
return false;
+ }
e_iter = e;
do {
@@ -336,13 +338,28 @@ int bmesh_disk_facevert_count_ex(const BMVert *v, const int count_max)
*/
BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v)
{
- const BMEdge *e_find = e;
+ const BMEdge *e_iter = e;
do {
- if (e_find->l && bmesh_radial_facevert_check(e_find->l, v)) {
- return (BMEdge *)e_find;
+ if (e_iter->l != NULL) {
+ return (BMEdge *)((e_iter->l->v == v) ? e_iter : e_iter->l->next->e);
}
- } while ((e_find = bmesh_disk_edge_next(e_find, v)) != e);
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e);
+ return NULL;
+}
+/**
+ * Special case for BM_LOOPS_OF_VERT & BM_FACES_OF_VERT, avoids 2x calls.
+ *
+ * The returned BMLoop.e matches the result of #bmesh_disk_faceedge_find_first
+ */
+BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v)
+{
+ const BMEdge *e_iter = e;
+ do {
+ if (e_iter->l != NULL) {
+ return (e_iter->l->v == v) ? e_iter->l : e_iter->l->next;
+ }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e);
return NULL;
}
@@ -389,6 +406,30 @@ bool bmesh_radial_validate(int radlen, BMLoop *l)
return true;
}
+void bmesh_radial_loop_append(BMEdge *e, BMLoop *l)
+{
+ if (e->l == NULL) {
+ e->l = l;
+ l->radial_next = l->radial_prev = l;
+ }
+ else {
+ l->radial_prev = e->l;
+ l->radial_next = e->l->radial_next;
+
+ e->l->radial_next->radial_prev = l;
+ e->l->radial_next = l;
+
+ e->l = l;
+ }
+
+ if (UNLIKELY(l->e && l->e != e)) {
+ /* l is already in a radial cycle for a different edge */
+ BMESH_ASSERT(0);
+ }
+
+ l->e = e;
+}
+
/**
* \brief BMESH RADIAL REMOVE LOOP
*
@@ -397,28 +438,27 @@ bool bmesh_radial_validate(int radlen, BMLoop *l)
* updated (in the case that the edge's link into the radial
* cycle was the loop which is being removed from the cycle).
*/
-void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e)
+void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l)
{
/* if e is non-NULL, l must be in the radial cycle of e */
- if (UNLIKELY(e && e != l->e)) {
+ if (UNLIKELY(e != l->e)) {
BMESH_ASSERT(0);
}
if (l->radial_next != l) {
- if (e && l == e->l)
+ if (l == e->l) {
e->l = l->radial_next;
+ }
l->radial_next->radial_prev = l->radial_prev;
l->radial_prev->radial_next = l->radial_next;
}
else {
- if (e) {
- if (l == e->l) {
- e->l = NULL;
- }
- else {
- BMESH_ASSERT(0);
- }
+ if (l == e->l) {
+ e->l = NULL;
+ }
+ else {
+ BMESH_ASSERT(0);
}
}
@@ -428,6 +468,22 @@ void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e)
l->e = NULL;
}
+/**
+ * A version of #bmesh_radial_loop_remove which only performs the radial unlink,
+ * leaving the edge untouched.
+ */
+void bmesh_radial_loop_unlink(BMLoop *l)
+{
+ if (l->radial_next != l) {
+ l->radial_next->radial_prev = l->radial_prev;
+ l->radial_prev->radial_next = l->radial_next;
+ }
+
+ /* l is no longer in a radial cycle; empty the links
+ * to the cycle and the link back to an edge */
+ l->radial_next = l->radial_prev = NULL;
+ l->e = NULL;
+}
/**
* \brief BME RADIAL FIND FIRST FACE VERT
@@ -484,30 +540,6 @@ int bmesh_radial_length(const BMLoop *l)
return i;
}
-void bmesh_radial_append(BMEdge *e, BMLoop *l)
-{
- if (e->l == NULL) {
- e->l = l;
- l->radial_next = l->radial_prev = l;
- }
- else {
- l->radial_prev = e->l;
- l->radial_next = e->l->radial_next;
-
- e->l->radial_next->radial_prev = l;
- e->l->radial_next = l;
-
- e->l = l;
- }
-
- if (UNLIKELY(l->e && l->e != e)) {
- /* l is already in a radial cycle for a different edge */
- BMESH_ASSERT(0);
- }
-
- l->e = e;
-}
-
/**
* \brief RADIAL COUNT FACE VERT
*
diff --git a/source/blender/bmesh/intern/bmesh_structure.h b/source/blender/bmesh/intern/bmesh_structure.h
index 07f94796bb2..0efb25da37c 100644
--- a/source/blender/bmesh/intern/bmesh_structure.h
+++ b/source/blender/bmesh/intern/bmesh_structure.h
@@ -52,11 +52,13 @@ BLI_INLINE BMEdge *bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v) ATTR_W
int bmesh_disk_facevert_count_ex(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int bmesh_disk_facevert_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMEdge *bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/* RADIAL CYCLE MANAGMENT */
-void bmesh_radial_append(BMEdge *e, BMLoop *l) ATTR_NONNULL();
-void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e) ATTR_NONNULL(1);
+void bmesh_radial_loop_append(BMEdge *e, BMLoop *l) ATTR_NONNULL();
+void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l) ATTR_NONNULL();
+void bmesh_radial_loop_unlink(BMLoop *l) ATTR_NONNULL();
/* note:
* bmesh_radial_loop_next(BMLoop *l) / prev.
* just use member access l->radial_next, l->radial_prev now */
diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c
index d5afb39d7b7..2ae87b64286 100644
--- a/source/blender/bmesh/operators/bmo_bevel.c
+++ b/source/blender/bmesh/operators/bmo_bevel.c
@@ -66,5 +66,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op)
BM_mesh_bevel(bm, offset, offset_type, seg, profile, vonly, false, clamp_overlap, NULL, -1, material, loop_slide);
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);
+ BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "verts.out", BM_VERT, BM_ELEM_TAG);
}
}
diff --git a/source/blender/bmesh/operators/bmo_bisect_plane.c b/source/blender/bmesh/operators/bmo_bisect_plane.c
index bed1ea5cb94..2c80ff651b8 100644
--- a/source/blender/bmesh/operators/bmo_bisect_plane.c
+++ b/source/blender/bmesh/operators/bmo_bisect_plane.c
@@ -38,7 +38,8 @@
#include "intern/bmesh_operators_private.h" /* own include */
#define ELE_NEW 1
-#define ELE_INPUT 2
+#define ELE_CUT 2
+#define ELE_INPUT 4
void bmo_bisect_plane_exec(BMesh *bm, BMOperator *op)
{
@@ -69,7 +70,7 @@ void bmo_bisect_plane_exec(BMesh *bm, BMOperator *op)
BM_mesh_bisect_plane(bm, plane, use_snap_center, true,
- ELE_NEW, dist);
+ ELE_CUT, ELE_NEW, dist);
if (clear_outer || clear_inner) {
@@ -108,5 +109,5 @@ void bmo_bisect_plane_exec(BMesh *bm, BMOperator *op)
}
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, ELE_NEW | ELE_INPUT);
- BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom_cut.out", BM_VERT | BM_EDGE, ELE_NEW);
+ BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom_cut.out", BM_VERT | BM_EDGE, ELE_CUT);
}
diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c
index 6ef0fd6b084..61179d7be70 100644
--- a/source/blender/bmesh/operators/bmo_bridge.c
+++ b/source/blender/bmesh/operators/bmo_bridge.c
@@ -398,7 +398,8 @@ static void bridge_loop_pair(
if (v_b != v_b_next) {
BMVert *v_arr[4] = {v_a, v_b, v_b_next, v_a_next};
- if (BM_face_exists(v_arr, 4, &f) == false) {
+ f = BM_face_exists(v_arr, 4);
+ if (f == NULL) {
/* copy if loop data if its is missing on one ring */
f = BM_face_create_verts(bm, v_arr, 4, NULL, BM_CREATE_NOP, true);
@@ -411,7 +412,8 @@ static void bridge_loop_pair(
}
else {
BMVert *v_arr[3] = {v_a, v_b, v_a_next};
- if (BM_face_exists(v_arr, 3, &f) == false) {
+ f = BM_face_exists(v_arr, 3);
+ if (f == NULL) {
/* fan-fill a triangle */
f = BM_face_create_verts(bm, v_arr, 3, NULL, BM_CREATE_NOP, true);
diff --git a/source/blender/bmesh/operators/bmo_connect.c b/source/blender/bmesh/operators/bmo_connect.c
index 5c9cd8dc3fa..c5c4ac959a9 100644
--- a/source/blender/bmesh/operators/bmo_connect.c
+++ b/source/blender/bmesh/operators/bmo_connect.c
@@ -55,7 +55,7 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenera
BMLoop *l_tag_prev = NULL, *l_tag_first = NULL;
BMLoop *l_iter, *l_first;
- unsigned int i;
+ uint i;
STACK_INIT(loops_split, pair_split_max);
STACK_INIT(verts_pair, pair_split_max);
diff --git a/source/blender/bmesh/operators/bmo_connect_nonplanar.c b/source/blender/bmesh/operators/bmo_connect_nonplanar.c
index b8acc9d09b8..67590fe8ef9 100644
--- a/source/blender/bmesh/operators/bmo_connect_nonplanar.c
+++ b/source/blender/bmesh/operators/bmo_connect_nonplanar.c
@@ -67,8 +67,8 @@ static bool bm_face_split_find(BMesh *bm, BMFace *f, BMLoop *l_pair[2], float *r
{
BMLoop *l_iter, *l_first;
BMLoop **l_arr = BLI_array_alloca(l_arr, f->len);
- const unsigned int f_len = f->len;
- unsigned int i_a, i_b;
+ const uint f_len = f->len;
+ uint i_a, i_b;
bool found = false;
/* angle finding */
diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c
index 05322a570a7..b474ad9fc7b 100644
--- a/source/blender/bmesh/operators/bmo_connect_pair.c
+++ b/source/blender/bmesh/operators/bmo_connect_pair.c
@@ -48,7 +48,7 @@
* - store a heap of paths which are being scanned (#PathContext.states).
* - continuously search the shortest path in the heap.
* - never step over the same element twice (tag elements as #ELE_TOUCHED).
- * this avoids going into an eternal loop of there are many possible branches (see T45582).
+ * this avoids going into an eternal loop if there are many possible branches (see T45582).
* - when running into a branch, create a new #PathLinkState state and add to the heap.
* - when the target is reached, finish - since none of the other paths can be shorter then the one just found.
* - if the connection can't be found - fail.
@@ -82,13 +82,13 @@
#define ELE_TOUCH_TEST_VERT(v) BMO_vert_flag_test(pc->bm_bmoflag, v, ELE_TOUCHED)
-// #define ELE_TOUCH_MARK_VERT(v) BMO_vert_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED)
+// #define ELE_TOUCH_MARK_VERT(v) BMO_vert_flag_enable(pc->bm_bmoflag, (BMElemF *)v, ELE_TOUCHED)
-// #define ELE_TOUCH_TEST_EDGE(v) BMO_edge_flag_test(pc->bm_bmoflag, v, ELE_TOUCHED)
-// #define ELE_TOUCH_MARK_EDGE(v) BMO_edge_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED)
+#define ELE_TOUCH_TEST_EDGE(e) BMO_edge_flag_test(pc->bm_bmoflag, e, ELE_TOUCHED)
+// #define ELE_TOUCH_MARK_EDGE(e) BMO_edge_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED)
-// #define ELE_TOUCH_TEST_FACE(v) BMO_face_flag_test(pc->bm_bmoflag, v, ELE_TOUCHED)
-// #define ELE_TOUCH_MARK_FACE(v) BMO_face_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED)
+// #define ELE_TOUCH_TEST_FACE(f) BMO_face_flag_test(pc->bm_bmoflag, f, ELE_TOUCHED)
+// #define ELE_TOUCH_MARK_FACE(f) BMO_face_flag_enable(pc->bm_bmoflag, (BMElemF *)f, ELE_TOUCHED)
// #define DEBUG_PRINT
@@ -363,7 +363,7 @@ static PathLinkState *state_step__face_edges(
BMElem *ele_next_from = (BMElem *)l_iter->f;
if (FACE_WALK_TEST((BMFace *)ele_next_from) &&
- (ELE_TOUCH_TEST_VERT((BMVert *)ele_next) == false))
+ (ELE_TOUCH_TEST_EDGE((BMEdge *)ele_next) == false))
{
min_dist_dir_update(mddir, dist_dir);
mddir->dist_min[index] = dist_test;
@@ -530,8 +530,8 @@ static void bm_vert_pair_to_matrix(BMVert *v_pair[2], float r_unit_mat[3][3])
float basis_nor_b[3];
/* align normal to direction */
- project_plane_v3_v3v3(basis_nor_a, v_pair[0]->no, basis_dir);
- project_plane_v3_v3v3(basis_nor_b, v_pair[1]->no, basis_dir);
+ project_plane_normalized_v3_v3v3(basis_nor_a, v_pair[0]->no, basis_dir);
+ project_plane_normalized_v3_v3v3(basis_nor_b, v_pair[1]->no, basis_dir);
/* don't normalize before combining so as normals approach the direction, they have less effect (T46784). */
@@ -569,7 +569,7 @@ static void bm_vert_pair_to_matrix(BMVert *v_pair[2], float r_unit_mat[3][3])
float angle_cos_test;
/* project basis dir onto the normal to find its closest angle */
- project_plane_v3_v3v3(basis_dir_proj, basis_dir, l->f->no);
+ project_plane_normalized_v3_v3v3(basis_dir_proj, basis_dir, l->f->no);
if (normalize_v3(basis_dir_proj) > eps) {
angle_cos_test = dot_v3v3(basis_dir_proj, basis_dir);
@@ -586,7 +586,7 @@ static void bm_vert_pair_to_matrix(BMVert *v_pair[2], float r_unit_mat[3][3])
* note: we could add the directions,
* but this more often gives 45d rotated matrix, so just use the best one. */
copy_v3_v3(basis_nor, axis_pair[axis_pair[0].angle_cos < axis_pair[1].angle_cos].nor);
- project_plane_v3_v3v3(basis_nor, basis_nor, basis_dir);
+ project_plane_normalized_v3_v3v3(basis_nor, basis_nor, basis_dir);
cross_v3_v3v3(basis_tmp, basis_dir, basis_nor);
@@ -661,7 +661,7 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op)
while (!BLI_heap_is_empty(pc.states)) {
#ifdef DEBUG_PRINT
- printf("\n%s: stepping %d\n", __func__, BLI_heap_size(pc.states));
+ printf("\n%s: stepping %u\n", __func__, BLI_heap_size(pc.states));
#endif
while (!BLI_heap_is_empty(pc.states)) {
diff --git a/source/blender/bmesh/operators/bmo_create.c b/source/blender/bmesh/operators/bmo_create.c
index 7b8cb36ab59..fa08d009d40 100644
--- a/source/blender/bmesh/operators/bmo_create.c
+++ b/source/blender/bmesh/operators/bmo_create.c
@@ -74,13 +74,13 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
BMVert *verts[2];
BMEdge *e;
- BMO_iter_as_array(op->slots_in, "geom", BM_VERT, (void **)verts, 2);
-
- /* create edge */
- e = BM_edge_create(bm, verts[0], verts[1], NULL, BM_CREATE_NO_DOUBLE);
- BMO_edge_flag_enable(bm, e, ELE_OUT);
- tote += 1;
- BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, ELE_OUT);
+ if (BMO_iter_as_array(op->slots_in, "geom", BM_VERT, (void **)verts, 2) == 2) {
+ /* create edge */
+ e = BM_edge_create(bm, verts[0], verts[1], NULL, BM_CREATE_NO_DOUBLE);
+ BMO_edge_flag_enable(bm, e, ELE_OUT);
+ tote += 1;
+ BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, ELE_OUT);
+ }
return;
}
@@ -283,14 +283,18 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
*/
if (totv > 2) {
/* TODO, some of these vertes may be connected by edges,
- * this connectivity could be used rather then treating
+ * this connectivity could be used rather than treating
* them as a bunch of isolated verts. */
BMVert **vert_arr = MEM_mallocN(sizeof(BMVert *) * totv, __func__);
BMFace *f;
- BMO_iter_as_array(op->slots_in, "geom", BM_VERT, (void **)vert_arr, totv);
- f = BM_face_create_ngon_vcloud(bm, vert_arr, totv, NULL, BM_CREATE_NO_DOUBLE);
+ totv = BMO_iter_as_array(op->slots_in, "geom", BM_VERT, (void **)vert_arr, totv);
+
+ BM_verts_sort_radial_plane(vert_arr, totv);
+
+ /* create edges and find the winding (if faces are attached to any existing edges) */
+ f = BM_face_create_ngon_verts(bm, vert_arr, totv, NULL, BM_CREATE_NO_DOUBLE, true, true);
if (f) {
BMO_face_flag_enable(bm, f, ELE_OUT);
diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c
index 05efb14a699..2df8e73c2b8 100644
--- a/source/blender/bmesh/operators/bmo_dissolve.c
+++ b/source/blender/bmesh/operators/bmo_dissolve.c
@@ -309,7 +309,7 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op)
BMO_ITER (e, &eiter, op->slots_in, "edges", BM_EDGE) {
BMFace *f_pair[2];
if (BM_edge_face_pair(e, &f_pair[0], &f_pair[1])) {
- unsigned int j;
+ uint j;
for (j = 0; j < 2; j++) {
BMLoop *l_first, *l_iter;
l_iter = l_first = BM_FACE_FIRST_LOOP(f_pair[j]);
@@ -322,12 +322,12 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op)
}
BMO_ITER (e, &eiter, op->slots_in, "edges", BM_EDGE) {
- BMFace *fa, *fb;
- if (BM_edge_face_pair(e, &fa, &fb)) {
+ BMLoop *l_a, *l_b;
+ if (BM_edge_loop_pair(e, &l_a, &l_b)) {
BMFace *f_new;
/* join faces */
- f_new = BM_faces_join_pair(bm, fa, fb, e, false);
+ f_new = BM_faces_join_pair(bm, l_a, l_b, false);
if (f_new) {
/* maintain active face */
@@ -437,12 +437,12 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op)
if (!BMO_vert_flag_test(bm, v, VERT_MARK_PAIR)) {
BM_ITER_ELEM (e, &itersub, v, BM_EDGES_OF_VERT) {
- BMFace *fa, *fb;
- if (BM_edge_face_pair(e, &fa, &fb)) {
+ BMLoop *l_a, *l_b;
+ if (BM_edge_loop_pair(e, &l_a, &l_b)) {
BMFace *f_new;
/* join faces */
- f_new = BM_faces_join_pair(bm, fa, fb, e, false);
+ f_new = BM_faces_join_pair(bm, l_a, l_b, false);
/* maintain active face */
if (act_face && bm->act_face == NULL) {
diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c
index 56639a097b6..e35c1f3b66c 100644
--- a/source/blender/bmesh/operators/bmo_dupe.c
+++ b/source/blender/bmesh/operators/bmo_dupe.c
@@ -83,7 +83,7 @@ static BMEdge *bmo_edge_copy(
{
BMEdge *e_dst;
BMVert *e_dst_v1, *e_dst_v2;
- unsigned int rlen;
+ uint rlen;
/* see if any of the neighboring faces are
* not being duplicated. in that case,
@@ -378,6 +378,10 @@ void BMO_dupe_from_flag(BMesh *bm, int htype, const char hflag)
* BMOP_DUPE_VOUTPUT: Buffer containing pointers to the split mesh vertices
* BMOP_DUPE_EOUTPUT: Buffer containing pointers to the split mesh edges
* BMOP_DUPE_FOUTPUT: Buffer containing pointers to the split mesh faces
+ *
+ * \note Lower level uses of this operator may want to use #BM_mesh_separate_faces
+ * Since it's faster for the 'use_only_faces' case.
+ *
*/
void bmo_split_exec(BMesh *bm, BMOperator *op)
{
diff --git a/source/blender/bmesh/operators/bmo_fill_attribute.c b/source/blender/bmesh/operators/bmo_fill_attribute.c
index 233ed746ed4..dcf2570dff4 100644
--- a/source/blender/bmesh/operators/bmo_fill_attribute.c
+++ b/source/blender/bmesh/operators/bmo_fill_attribute.c
@@ -91,7 +91,7 @@ static void bm_face_copy_shared_all(
/**
* Flood fill attributes.
*/
-static unsigned int bmesh_face_attribute_fill(
+static uint bmesh_face_attribute_fill(
BMesh *bm,
const bool use_normals, const bool use_data)
{
@@ -102,7 +102,7 @@ static unsigned int bmesh_face_attribute_fill(
BMIter iter;
BMLoop *l;
- unsigned int face_tot = 0;
+ uint face_tot = 0;
BLI_LINKSTACK_INIT(loop_queue_prev);
diff --git a/source/blender/bmesh/operators/bmo_fill_edgeloop.c b/source/blender/bmesh/operators/bmo_fill_edgeloop.c
index c68130bc11d..f33a60ccc5c 100644
--- a/source/blender/bmesh/operators/bmo_fill_edgeloop.c
+++ b/source/blender/bmesh/operators/bmo_fill_edgeloop.c
@@ -136,7 +136,7 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op)
i++;
} while ((v != f_verts[0]));
- if (BM_face_exists(f_verts, i, NULL) == false) {
+ if (!BM_face_exists(f_verts, i)) {
BMFace *f;
/* don't use calc_edges option because we already have the edges */
diff --git a/source/blender/bmesh/operators/bmo_fill_grid.c b/source/blender/bmesh/operators/bmo_fill_grid.c
index 04ae915b707..dc4ebf50754 100644
--- a/source/blender/bmesh/operators/bmo_fill_grid.c
+++ b/source/blender/bmesh/operators/bmo_fill_grid.c
@@ -187,15 +187,15 @@ static void bm_loop_interp_from_grid_boundary_2(BMesh *bm, BMLoop *l, BMLoop *l_
* Avoids calling #barycentric_weights_v2_quad often by caching weights into an array.
*/
static void barycentric_weights_v2_grid_cache(
- const unsigned int xtot, const unsigned int ytot,
+ const uint xtot, const uint ytot,
float (*weight_table)[4])
{
float x_step = 1.0f / (float)(xtot - 1);
float y_step = 1.0f / (float)(ytot - 1);
- unsigned int i = 0;
+ uint i = 0;
float xy_fl[2];
- unsigned int x, y;
+ uint x, y;
for (y = 0; y < ytot; y++) {
xy_fl[1] = y_step * (float)y;
for (x = 0; x < xtot; x++) {
@@ -219,13 +219,13 @@ static void barycentric_weights_v2_grid_cache(
* \param v_grid 2d array of verts, all boundary verts must be set, we fill in the middle.
*/
static void bm_grid_fill_array(
- BMesh *bm, BMVert **v_grid, const unsigned int xtot, unsigned const int ytot,
+ BMesh *bm, BMVert **v_grid, const uint xtot, unsigned const int ytot,
const short mat_nr, const bool use_smooth,
const bool use_flip, const bool use_interp_simple)
{
const bool use_vert_interp = CustomData_has_interp(&bm->vdata);
const bool use_loop_interp = CustomData_has_interp(&bm->ldata);
- unsigned int x, y;
+ uint x, y;
/* for use_loop_interp */
BMLoop *((*larr_x_a)[2]), *((*larr_x_b)[2]), *((*larr_y_a)[2]), *((*larr_y_b)[2]);
@@ -393,7 +393,7 @@ static void bm_grid_fill_array(
BMLoop *l_quad[4];
BMLoop *l_bound[4];
BMLoop *l_tmp;
- unsigned int x_side, y_side, i;
+ uint x_side, y_side, i;
char interp_from;
@@ -496,12 +496,12 @@ static void bm_grid_fill(
{
#define USE_FLIP_DETECT
- const unsigned int xtot = (unsigned int)BM_edgeloop_length_get(estore_a);
- const unsigned int ytot = (unsigned int)BM_edgeloop_length_get(estore_rail_a);
+ const uint xtot = (uint)BM_edgeloop_length_get(estore_a);
+ const uint ytot = (uint)BM_edgeloop_length_get(estore_rail_a);
//BMVert *v;
- unsigned int i;
+ uint i;
#ifdef DEBUG
- unsigned int x, y;
+ uint x, y;
#endif
LinkData *el;
bool use_flip = false;
diff --git a/source/blender/bmesh/operators/bmo_fill_holes.c b/source/blender/bmesh/operators/bmo_fill_holes.c
index eadfbdb1aa8..869994a98b9 100644
--- a/source/blender/bmesh/operators/bmo_fill_holes.c
+++ b/source/blender/bmesh/operators/bmo_fill_holes.c
@@ -36,7 +36,7 @@
void bmo_holes_fill_exec(BMesh *bm, BMOperator *op)
{
BMOperator op_attr;
- const unsigned int sides = BMO_slot_int_get(op->slots_in, "sides");
+ const uint sides = BMO_slot_int_get(op->slots_in, "sides");
BM_mesh_elem_hflag_disable_all(bm, BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
diff --git a/source/blender/bmesh/operators/bmo_hull.c b/source/blender/bmesh/operators/bmo_hull.c
index 9c41e4f2115..81ec2860cf7 100644
--- a/source/blender/bmesh/operators/bmo_hull.c
+++ b/source/blender/bmesh/operators/bmo_hull.c
@@ -119,7 +119,8 @@ static void hull_output_triangles(BMesh *bm, GSet *hull_triangles)
};
BMFace *f, *example = NULL;
- if (BM_face_exists(t->v, 3, &f)) {
+ f = BM_face_exists(t->v, 3);
+ if (f != NULL) {
/* If the operator is run with "use_existing_faces"
* disabled, but an output face in the hull is the
* same as a face in the existing mesh, it should not
diff --git a/source/blender/bmesh/operators/bmo_inset.c b/source/blender/bmesh/operators/bmo_inset.c
index c52c608e671..a64c6d74a93 100644
--- a/source/blender/bmesh/operators/bmo_inset.c
+++ b/source/blender/bmesh/operators/bmo_inset.c
@@ -275,7 +275,7 @@ static void bmo_face_inset_individual(
BMLoop *l_iter, *l_first;
BMLoop *l_other;
- unsigned int i;
+ uint i;
float e_length_prev;
l_first = BM_FACE_FIRST_LOOP(f);
@@ -647,6 +647,10 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
} (void)0
#define VERT_ORIG_GET(_v) \
(const float *)BLI_ghash_lookup_default(vert_coords, (_v), (_v)->co)
+ /* memory for the coords isn't given back to the arena,
+ * acceptable in this case since it runs a fixed number of times. */
+#define VERT_ORIG_REMOVE(_v) \
+ BLI_ghash_remove(vert_coords, (_v), NULL, NULL)
for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
@@ -659,7 +663,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
/* run the separate arg */
if (!BM_edge_is_boundary(es->e_old)) {
- bmesh_edge_separate(bm, es->e_old, es->l, false);
+ bmesh_kernel_edge_separate(bm, es->e_old, es->l, false);
}
/* calc edge-split info */
@@ -738,7 +742,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
/* disable touching twice, this _will_ happen if the flags not disabled */
BM_elem_flag_disable(v, BM_ELEM_TAG);
- bmesh_vert_separate(bm, v, &vout, &r_vout_len, false);
+ bmesh_kernel_vert_separate(bm, v, &vout, &r_vout_len, false);
v = NULL; /* don't use again */
/* in some cases the edge doesn't split off */
@@ -972,7 +976,11 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
v_glue = v_split;
}
else {
- BM_vert_splice(bm, v_glue, v_split);
+ if (BM_vert_splice(bm, v_glue, v_split)) {
+ if (use_vert_coords_orig) {
+ VERT_ORIG_REMOVE(v_split);
+ }
+ }
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_join_triangles.c b/source/blender/bmesh/operators/bmo_join_triangles.c
index bc620e4a020..69198ff35ab 100644
--- a/source/blender/bmesh/operators/bmo_join_triangles.c
+++ b/source/blender/bmesh/operators/bmo_join_triangles.c
@@ -132,11 +132,11 @@ struct DelimitData_CD {
};
struct DelimitData {
- unsigned int do_seam : 1;
- unsigned int do_sharp : 1;
- unsigned int do_mat : 1;
- unsigned int do_angle_face : 1;
- unsigned int do_angle_shape : 1;
+ uint do_seam : 1;
+ uint do_sharp : 1;
+ uint do_mat : 1;
+ uint do_angle_face : 1;
+ uint do_angle_shape : 1;
float angle_face;
float angle_face__cos;
@@ -272,7 +272,7 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
/* data: edge-to-join, sort_value: error weight */
struct SortPointerByFloat *jedges;
unsigned i, totedge;
- unsigned int totedge_tag = 0;
+ uint totedge_tag = 0;
struct DelimitData delimit_data = {0};
@@ -361,16 +361,16 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
qsort(jedges, totedge, sizeof(*jedges), BLI_sortutil_cmp_float);
for (i = 0; i < totedge; i++) {
- BMFace *f_a, *f_b;
+ BMLoop *l_a, *l_b;
e = jedges[i].data;
- f_a = e->l->f;
- f_b = e->l->radial_next->f;
+ l_a = e->l;
+ l_b = e->l->radial_next;
/* check if another edge already claimed this face */
- if ((f_a->len == 3) && (f_b->len == 3)) {
+ if ((l_a->f->len == 3) && (l_b->f->len == 3)) {
BMFace *f_new;
- f_new = BM_faces_join_pair(bm, f_a, f_b, e, true);
+ f_new = BM_faces_join_pair(bm, l_a, l_b, true);
if (f_new) {
BMO_face_flag_enable(bm, f_new, FACE_OUT);
}
diff --git a/source/blender/bmesh/operators/bmo_offset_edgeloops.c b/source/blender/bmesh/operators/bmo_offset_edgeloops.c
index 7a6f779b34f..a9840a72fc9 100644
--- a/source/blender/bmesh/operators/bmo_offset_edgeloops.c
+++ b/source/blender/bmesh/operators/bmo_offset_edgeloops.c
@@ -270,7 +270,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op)
v_other = BM_edge_other_vert(e, v);
if (BM_elem_index_get(v_other) == -1) {
if (BM_vert_is_edge_pair(v_other)) {
- /* defer bmesh_jekv to avoid looping over data we're removing */
+ /* defer bmesh_kernel_join_edge_kill_vert to avoid looping over data we're removing */
v_other->e = e;
STACK_PUSH(varr, v_other);
}
@@ -278,7 +278,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op)
}
while ((v = STACK_POP(varr))) {
- bmesh_jekv(bm, v->e, v, true, false, false);
+ bmesh_kernel_join_edge_kill_vert(bm, v->e, v, true, false, false);
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c
index d2b9fa9efa3..cca0f7387cd 100644
--- a/source/blender/bmesh/operators/bmo_primitive.c
+++ b/source/blender/bmesh/operators/bmo_primitive.c
@@ -78,6 +78,31 @@ static const short icoface[20][3] = {
{10, 9, 11}
};
+static const float icouvs[60][2] =
+{
+ {0.818181f, 0.000000f}, {0.727272f, 0.157461f}, {0.909090f, 0.157461f},
+ {0.727272f, 0.157461f}, {0.636363f, 0.000000f}, {0.545454f, 0.157461f},
+ {0.090909f, 0.000000f}, {0.000000f, 0.157461f}, {0.181818f, 0.157461f},
+ {0.272727f, 0.000000f}, {0.181818f, 0.157461f}, {0.363636f, 0.157461f},
+ {0.454545f, 0.000000f}, {0.363636f, 0.157461f}, {0.545454f, 0.157461f},
+ {0.727272f, 0.157461f}, {0.545454f, 0.157461f}, {0.636363f, 0.314921f},
+ {0.909090f, 0.157461f}, {0.727272f, 0.157461f}, {0.818181f, 0.314921f},
+ {0.181818f, 0.157461f}, {0.000000f, 0.157461f}, {0.090909f, 0.314921f},
+ {0.363636f, 0.157461f}, {0.181818f, 0.157461f}, {0.272727f, 0.314921f},
+ {0.545454f, 0.157461f}, {0.363636f, 0.157461f}, {0.454545f, 0.314921f},
+ {0.727272f, 0.157461f}, {0.636363f, 0.314921f}, {0.818181f, 0.314921f},
+ {0.909090f, 0.157461f}, {0.818181f, 0.314921f}, {1.000000f, 0.314921f},
+ {0.181818f, 0.157461f}, {0.090909f, 0.314921f}, {0.272727f, 0.314921f},
+ {0.363636f, 0.157461f}, {0.272727f, 0.314921f}, {0.454545f, 0.314921f},
+ {0.545454f, 0.157461f}, {0.454545f, 0.314921f}, {0.636363f, 0.314921f},
+ {0.818181f, 0.314921f}, {0.636363f, 0.314921f}, {0.727272f, 0.472382f},
+ {1.000000f, 0.314921f}, {0.818181f, 0.314921f}, {0.909090f, 0.472382f},
+ {0.272727f, 0.314921f}, {0.090909f, 0.314921f}, {0.181818f, 0.472382f},
+ {0.454545f, 0.314921f}, {0.272727f, 0.314921f}, {0.363636f, 0.472382f},
+ {0.636363f, 0.314921f}, {0.454545f, 0.314921f}, {0.545454f, 0.472382f}
+};
+
+
static const int monkeyo = 4;
static const int monkeynv = 271;
static const int monkeynf = 250;
@@ -218,6 +243,510 @@ static signed char monkeyf[250][4] = {
{-68, -67, 24, -33},
};
+static const float monkeyuvs[] =
+{
+ 0.890955f, 0.590063f, 0.870622f, 0.589649f, 0.860081f, 0.560115f, 0.904571f, 0.559404f,
+ 0.856226f, 0.850547f, 0.868067f, 0.821510f, 0.888398f, 0.821999f, 0.900640f, 0.853232f,
+ 0.904571f, 0.559404f, 0.860081f, 0.560115f, 0.853018f, 0.521562f, 0.920166f, 0.524546f,
+ 0.847458f, 0.888748f, 0.856226f, 0.850547f, 0.900640f, 0.853232f, 0.914672f, 0.888748f,
+ 0.860081f, 0.560115f, 0.828900f, 0.590771f, 0.798481f, 0.569535f, 0.853018f, 0.521562f,
+ 0.795104f, 0.838402f, 0.826436f, 0.818537f, 0.856226f, 0.850547f, 0.847458f, 0.888748f,
+ 0.870622f, 0.589649f, 0.854402f, 0.604754f, 0.828900f, 0.590771f, 0.860081f, 0.560115f,
+ 0.826436f, 0.818537f, 0.852534f, 0.805700f, 0.868067f, 0.821510f, 0.856226f, 0.850547f,
+ 0.854402f, 0.604754f, 0.854107f, 0.625459f, 0.828171f, 0.633354f, 0.828900f, 0.590771f,
+ 0.827598f, 0.775964f, 0.853157f, 0.785002f, 0.852534f, 0.805700f, 0.826436f, 0.818537f,
+ 0.828900f, 0.590771f, 0.828171f, 0.633354f, 0.791018f, 0.645443f, 0.798481f, 0.569535f,
+ 0.791018f, 0.762238f, 0.827598f, 0.775964f, 0.826436f, 0.818537f, 0.795104f, 0.838402f,
+ 0.828171f, 0.633354f, 0.855181f, 0.668527f, 0.842358f, 0.702491f, 0.791018f, 0.645443f,
+ 0.844839f, 0.707525f, 0.856142f, 0.742025f, 0.827598f, 0.775964f, 0.791018f, 0.762238f,
+ 0.854107f, 0.625459f, 0.867508f, 0.642291f, 0.855181f, 0.668527f, 0.828171f, 0.633354f,
+ 0.856142f, 0.742025f, 0.867293f, 0.768782f, 0.853157f, 0.785002f, 0.827598f, 0.775964f,
+ 0.867508f, 0.642291f, 0.890474f, 0.641909f, 0.900375f, 0.666964f, 0.855181f, 0.668527f,
+ 0.901223f, 0.745592f, 0.890219f, 0.770183f, 0.867293f, 0.768782f, 0.856142f, 0.742025f,
+ 0.855181f, 0.668527f, 0.900375f, 0.666964f, 0.918898f, 0.699697f, 0.842358f, 0.702491f,
+ 0.921180f, 0.713713f, 0.901223f, 0.745592f, 0.856142f, 0.742025f, 0.844839f, 0.707525f,
+ 0.900375f, 0.666964f, 0.931889f, 0.636832f, 0.968392f, 0.645333f, 0.918898f, 0.699697f,
+ 0.968213f, 0.770220f, 0.931368f, 0.777093f, 0.901223f, 0.745592f, 0.921180f, 0.713713f,
+ 0.890474f, 0.641909f, 0.905882f, 0.627902f, 0.931889f, 0.636832f, 0.900375f, 0.666964f,
+ 0.931368f, 0.777093f, 0.904990f, 0.784860f, 0.890219f, 0.770183f, 0.901223f, 0.745592f,
+ 0.905882f, 0.627902f, 0.906232f, 0.605742f, 0.933717f, 0.593037f, 0.931889f, 0.636832f,
+ 0.931250f, 0.820926f, 0.904357f, 0.807013f, 0.904990f, 0.784860f, 0.931368f, 0.777093f,
+ 0.931889f, 0.636832f, 0.933717f, 0.593037f, 0.968392f, 0.573812f, 0.968392f, 0.645333f,
+ 0.965038f, 0.841671f, 0.931250f, 0.820926f, 0.931368f, 0.777093f, 0.968213f, 0.770220f,
+ 0.933717f, 0.593037f, 0.904571f, 0.559404f, 0.920166f, 0.524546f, 0.968392f, 0.573812f,
+ 0.914672f, 0.888748f, 0.900640f, 0.853232f, 0.931250f, 0.820926f, 0.965038f, 0.841671f,
+ 0.906232f, 0.605742f, 0.890955f, 0.590063f, 0.904571f, 0.559404f, 0.933717f, 0.593037f,
+ 0.900640f, 0.853232f, 0.888398f, 0.821999f, 0.904357f, 0.807013f, 0.931250f, 0.820926f,
+ 0.890955f, 0.590063f, 0.906232f, 0.605742f, 0.902359f, 0.607909f, 0.889591f, 0.593275f,
+ 0.900583f, 0.804677f, 0.904357f, 0.807013f, 0.888398f, 0.821999f, 0.887178f, 0.818729f,
+ 0.906232f, 0.605742f, 0.905882f, 0.627902f, 0.899781f, 0.626257f, 0.902359f, 0.607909f,
+ 0.898822f, 0.786233f, 0.904990f, 0.784860f, 0.904357f, 0.807013f, 0.900583f, 0.804677f,
+ 0.905882f, 0.627902f, 0.890474f, 0.641909f, 0.887842f, 0.636527f, 0.899781f, 0.626257f,
+ 0.887351f, 0.775442f, 0.890219f, 0.770183f, 0.904990f, 0.784860f, 0.898822f, 0.786233f,
+ 0.890474f, 0.641909f, 0.867508f, 0.642291f, 0.870908f, 0.635245f, 0.887842f, 0.636527f,
+ 0.870376f, 0.775972f, 0.867293f, 0.768782f, 0.890219f, 0.770183f, 0.887351f, 0.775442f,
+ 0.867508f, 0.642291f, 0.854107f, 0.625459f, 0.859881f, 0.623942f, 0.870908f, 0.635245f,
+ 0.858859f, 0.786774f, 0.853157f, 0.785002f, 0.867293f, 0.768782f, 0.870376f, 0.775972f,
+ 0.854107f, 0.625459f, 0.854402f, 0.604754f, 0.859664f, 0.608186f, 0.859881f, 0.623942f,
+ 0.857942f, 0.802505f, 0.852534f, 0.805700f, 0.853157f, 0.785002f, 0.858859f, 0.786774f,
+ 0.854402f, 0.604754f, 0.870622f, 0.589649f, 0.871664f, 0.593961f, 0.859664f, 0.608186f,
+ 0.869299f, 0.817249f, 0.868067f, 0.821510f, 0.852534f, 0.805700f, 0.857942f, 0.802505f,
+ 0.870622f, 0.589649f, 0.890955f, 0.590063f, 0.889591f, 0.593275f, 0.871664f, 0.593961f,
+ 0.887178f, 0.818729f, 0.888398f, 0.821999f, 0.868067f, 0.821510f, 0.869299f, 0.817249f,
+ 0.879400f, 0.616512f, 0.871664f, 0.593961f, 0.889591f, 0.593275f,
+ 0.887178f, 0.818729f, 0.869299f, 0.817249f, 0.878029f, 0.795063f,
+ 0.859664f, 0.608186f, 0.871664f, 0.593961f, 0.879400f, 0.616512f,
+ 0.878029f, 0.795063f, 0.869299f, 0.817249f, 0.857942f, 0.802505f,
+ 0.879400f, 0.616512f, 0.859881f, 0.623942f, 0.859664f, 0.608186f,
+ 0.857942f, 0.802505f, 0.858859f, 0.786774f, 0.878029f, 0.795063f,
+ 0.879400f, 0.616512f, 0.870908f, 0.635245f, 0.859881f, 0.623942f,
+ 0.858859f, 0.786774f, 0.870376f, 0.775972f, 0.878029f, 0.795063f,
+ 0.879400f, 0.616512f, 0.887842f, 0.636527f, 0.870908f, 0.635245f,
+ 0.870376f, 0.775972f, 0.887351f, 0.775442f, 0.878029f, 0.795063f,
+ 0.879400f, 0.616512f, 0.899781f, 0.626257f, 0.887842f, 0.636527f,
+ 0.887351f, 0.775442f, 0.898822f, 0.786233f, 0.878029f, 0.795063f,
+ 0.879400f, 0.616512f, 0.902359f, 0.607909f, 0.899781f, 0.626257f,
+ 0.898822f, 0.786233f, 0.900583f, 0.804677f, 0.878029f, 0.795063f,
+ 0.879400f, 0.616512f, 0.889591f, 0.593275f, 0.902359f, 0.607909f,
+ 0.900583f, 0.804677f, 0.887178f, 0.818729f, 0.878029f, 0.795063f,
+ 0.540260f, 0.053805f, 0.536419f, 0.062072f, 0.518925f, 0.059681f, 0.518916f, 0.050294f,
+ 0.518925f, 0.059681f, 0.501452f, 0.062043f, 0.497626f, 0.053770f, 0.518916f, 0.050294f,
+ 0.551930f, 0.058338f, 0.542788f, 0.064089f, 0.536419f, 0.062072f, 0.540260f, 0.053805f,
+ 0.501452f, 0.062043f, 0.495083f, 0.064047f, 0.485955f, 0.058273f, 0.497626f, 0.053770f,
+ 0.555073f, 0.061900f, 0.546290f, 0.072669f, 0.542788f, 0.064089f, 0.551930f, 0.058338f,
+ 0.495083f, 0.064047f, 0.491565f, 0.072625f, 0.482805f, 0.061829f, 0.485955f, 0.058273f,
+ 0.563812f, 0.076586f, 0.548333f, 0.084893f, 0.546290f, 0.072669f, 0.555073f, 0.061900f,
+ 0.491565f, 0.072625f, 0.489507f, 0.084858f, 0.474014f, 0.076511f, 0.482805f, 0.061829f,
+ 0.583135f, 0.108495f, 0.555621f, 0.121749f, 0.548333f, 0.084893f, 0.563812f, 0.076586f,
+ 0.489507f, 0.084858f, 0.482177f, 0.121781f, 0.454527f, 0.108481f, 0.474014f, 0.076511f,
+ 0.605512f, 0.165134f, 0.647395f, 0.200502f, 0.621513f, 0.227818f, 0.553118f, 0.209599f,
+ 0.416514f, 0.229490f, 0.389677f, 0.201890f, 0.432024f, 0.165644f, 0.485339f, 0.210053f,
+ 0.647395f, 0.200502f, 0.676379f, 0.233241f, 0.664761f, 0.253225f, 0.621513f, 0.227818f,
+ 0.372747f, 0.256357f, 0.360308f, 0.235899f, 0.389677f, 0.201890f, 0.416514f, 0.229490f,
+ 0.676379f, 0.233241f, 0.715342f, 0.265392f, 0.683908f, 0.279995f, 0.664761f, 0.253225f,
+ 0.353696f, 0.284606f, 0.320452f, 0.270303f, 0.360308f, 0.235899f, 0.372747f, 0.256357f,
+ 0.715342f, 0.265392f, 0.707254f, 0.310054f, 0.687515f, 0.311539f, 0.683908f, 0.279995f,
+ 0.351187f, 0.317440f, 0.330721f, 0.316853f, 0.320452f, 0.270303f, 0.353696f, 0.284606f,
+ 0.707254f, 0.310054f, 0.697446f, 0.332673f, 0.676824f, 0.323937f, 0.687515f, 0.311539f,
+ 0.362723f, 0.329722f, 0.341964f, 0.339667f, 0.330721f, 0.316853f, 0.351187f, 0.317440f,
+ 0.697446f, 0.332673f, 0.662817f, 0.372521f, 0.639050f, 0.357330f, 0.676824f, 0.323937f,
+ 0.402772f, 0.362131f, 0.379297f, 0.378686f, 0.341964f, 0.339667f, 0.362723f, 0.329722f,
+ 0.662817f, 0.372521f, 0.626842f, 0.395792f, 0.618316f, 0.375151f, 0.639050f, 0.357330f,
+ 0.424583f, 0.379267f, 0.416915f, 0.400552f, 0.379297f, 0.378686f, 0.402772f, 0.362131f,
+ 0.626842f, 0.395792f, 0.604826f, 0.397804f, 0.600808f, 0.377857f, 0.618316f, 0.375151f,
+ 0.442396f, 0.381222f, 0.439252f, 0.401540f, 0.416915f, 0.400552f, 0.424583f, 0.379267f,
+ 0.604826f, 0.397804f, 0.553095f, 0.390512f, 0.559674f, 0.357011f, 0.600808f, 0.377857f,
+ 0.482938f, 0.358497f, 0.490934f, 0.391862f, 0.439252f, 0.401540f, 0.442396f, 0.381222f,
+ 0.553095f, 0.390512f, 0.521923f, 0.386009f, 0.521086f, 0.343868f, 0.559674f, 0.357011f,
+ 0.521086f, 0.343868f, 0.521923f, 0.386009f, 0.490934f, 0.391862f, 0.482938f, 0.358497f,
+ 0.577279f, 0.340156f, 0.599845f, 0.344815f, 0.600808f, 0.377857f, 0.559674f, 0.357011f,
+ 0.442396f, 0.381222f, 0.441977f, 0.347815f, 0.464579f, 0.342230f, 0.482938f, 0.358497f,
+ 0.599845f, 0.344815f, 0.615546f, 0.342005f, 0.618316f, 0.375151f, 0.600808f, 0.377857f,
+ 0.424583f, 0.379267f, 0.425972f, 0.345582f, 0.441977f, 0.347815f, 0.442396f, 0.381222f,
+ 0.634472f, 0.332311f, 0.639050f, 0.357330f, 0.618316f, 0.375151f, 0.615546f, 0.342005f,
+ 0.424583f, 0.379267f, 0.402772f, 0.362131f, 0.406362f, 0.336480f, 0.425972f, 0.345582f,
+ 0.662406f, 0.312804f, 0.676824f, 0.323937f, 0.639050f, 0.357330f, 0.634472f, 0.332311f,
+ 0.402772f, 0.362131f, 0.362723f, 0.329722f, 0.377061f, 0.317685f, 0.406362f, 0.336480f,
+ 0.668440f, 0.297958f, 0.687515f, 0.311539f, 0.676824f, 0.323937f, 0.662406f, 0.312804f,
+ 0.362723f, 0.329722f, 0.351187f, 0.317440f, 0.370304f, 0.302644f, 0.377061f, 0.317685f,
+ 0.664101f, 0.277872f, 0.683908f, 0.279995f, 0.687515f, 0.311539f, 0.668440f, 0.297958f,
+ 0.351187f, 0.317440f, 0.353696f, 0.284606f, 0.374100f, 0.281778f, 0.370304f, 0.302644f,
+ 0.639236f, 0.253047f, 0.664761f, 0.253225f, 0.683908f, 0.279995f, 0.664101f, 0.277872f,
+ 0.353696f, 0.284606f, 0.372747f, 0.256357f, 0.398938f, 0.255633f, 0.374100f, 0.281778f,
+ 0.613992f, 0.242662f, 0.621513f, 0.227818f, 0.664761f, 0.253225f, 0.639236f, 0.253047f,
+ 0.372747f, 0.256357f, 0.416514f, 0.229490f, 0.424464f, 0.244473f, 0.398938f, 0.255633f,
+ 0.572941f, 0.258564f, 0.553118f, 0.209599f, 0.621513f, 0.227818f, 0.613992f, 0.242662f,
+ 0.416514f, 0.229490f, 0.485339f, 0.210053f, 0.466409f, 0.259709f, 0.424464f, 0.244473f,
+ 0.572941f, 0.258564f, 0.563905f, 0.272007f, 0.519760f, 0.248864f, 0.553118f, 0.209599f,
+ 0.519760f, 0.248864f, 0.475886f, 0.273078f, 0.466409f, 0.259709f, 0.485339f, 0.210053f,
+ 0.577279f, 0.340156f, 0.559674f, 0.357011f, 0.521086f, 0.343868f, 0.558527f, 0.316594f,
+ 0.521086f, 0.343868f, 0.482938f, 0.358497f, 0.464579f, 0.342230f, 0.482619f, 0.317843f,
+ 0.558527f, 0.316594f, 0.521086f, 0.343868f, 0.520277f, 0.294764f, 0.556923f, 0.291214f,
+ 0.520277f, 0.294764f, 0.521086f, 0.343868f, 0.482619f, 0.317843f, 0.483433f, 0.292249f,
+ 0.519760f, 0.248864f, 0.563905f, 0.272007f, 0.556923f, 0.291214f, 0.520277f, 0.294764f,
+ 0.483433f, 0.292249f, 0.475886f, 0.273078f, 0.519760f, 0.248864f, 0.520277f, 0.294764f,
+ 0.525483f, 0.068967f, 0.518928f, 0.067899f, 0.518925f, 0.059681f, 0.536419f, 0.062072f,
+ 0.518925f, 0.059681f, 0.518928f, 0.067899f, 0.512375f, 0.068956f, 0.501452f, 0.062043f,
+ 0.531231f, 0.073829f, 0.525483f, 0.068967f, 0.536419f, 0.062072f, 0.542788f, 0.064089f,
+ 0.501452f, 0.062043f, 0.512375f, 0.068956f, 0.506626f, 0.073811f, 0.495083f, 0.064047f,
+ 0.531019f, 0.087431f, 0.531231f, 0.073829f, 0.542788f, 0.064089f, 0.546290f, 0.072669f,
+ 0.495083f, 0.064047f, 0.506626f, 0.073811f, 0.506827f, 0.087416f, 0.491565f, 0.072625f,
+ 0.555621f, 0.121749f, 0.532042f, 0.127713f, 0.532669f, 0.090920f, 0.548333f, 0.084893f,
+ 0.505177f, 0.090908f, 0.505828f, 0.127728f, 0.482177f, 0.121781f, 0.489507f, 0.084858f,
+ 0.531019f, 0.087431f, 0.546290f, 0.072669f, 0.548333f, 0.084893f, 0.532669f, 0.090920f,
+ 0.489507f, 0.084858f, 0.491565f, 0.072625f, 0.506827f, 0.087416f, 0.505177f, 0.090908f,
+ 0.538112f, 0.158382f, 0.518981f, 0.151749f, 0.518941f, 0.128358f, 0.532042f, 0.127713f,
+ 0.518941f, 0.128358f, 0.518981f, 0.151749f, 0.499851f, 0.158434f, 0.505828f, 0.127728f,
+ 0.532669f, 0.090920f, 0.532042f, 0.127713f, 0.518941f, 0.128358f, 0.518925f, 0.093952f,
+ 0.518941f, 0.128358f, 0.505828f, 0.127728f, 0.505177f, 0.090908f, 0.518925f, 0.093952f,
+ 0.518927f, 0.085180f, 0.531019f, 0.087431f, 0.532669f, 0.090920f, 0.518925f, 0.093952f,
+ 0.505177f, 0.090908f, 0.506827f, 0.087416f, 0.518927f, 0.085180f, 0.518925f, 0.093952f,
+ 0.548362f, 0.173560f, 0.537959f, 0.175966f, 0.535214f, 0.166808f, 0.538112f, 0.158382f,
+ 0.502799f, 0.166857f, 0.500100f, 0.176033f, 0.489683f, 0.173693f, 0.499851f, 0.158434f,
+ 0.544281f, 0.193366f, 0.537248f, 0.187577f, 0.537959f, 0.175966f, 0.548362f, 0.173560f,
+ 0.500100f, 0.176033f, 0.500890f, 0.187571f, 0.493996f, 0.193428f, 0.489683f, 0.173693f,
+ 0.519841f, 0.200843f, 0.528757f, 0.191785f, 0.537248f, 0.187577f, 0.544281f, 0.193366f,
+ 0.500890f, 0.187571f, 0.509219f, 0.191626f, 0.519841f, 0.200843f, 0.493996f, 0.193428f,
+ 0.517577f, 0.190607f, 0.519132f, 0.185382f, 0.528757f, 0.191785f, 0.519841f, 0.200843f,
+ 0.509219f, 0.191626f, 0.519132f, 0.185382f, 0.517577f, 0.190607f, 0.519841f, 0.200843f,
+ 0.518981f, 0.151749f, 0.538112f, 0.158382f, 0.535214f, 0.166808f, 0.518998f, 0.159028f,
+ 0.502799f, 0.166857f, 0.499851f, 0.158434f, 0.518981f, 0.151749f, 0.518998f, 0.159028f,
+ 0.518998f, 0.159028f, 0.535214f, 0.166808f, 0.531131f, 0.171631f, 0.519016f, 0.165599f,
+ 0.506910f, 0.171667f, 0.502799f, 0.166857f, 0.518998f, 0.159028f, 0.519016f, 0.165599f,
+ 0.519132f, 0.185382f, 0.519099f, 0.179457f, 0.528222f, 0.186316f, 0.528757f, 0.191785f,
+ 0.509787f, 0.186260f, 0.519099f, 0.179457f, 0.519132f, 0.185382f, 0.509219f, 0.191626f,
+ 0.528757f, 0.191785f, 0.528222f, 0.186316f, 0.533528f, 0.184215f, 0.537248f, 0.187577f,
+ 0.504547f, 0.184206f, 0.509787f, 0.186260f, 0.509219f, 0.191626f, 0.500890f, 0.187571f,
+ 0.537248f, 0.187577f, 0.533528f, 0.184215f, 0.533449f, 0.176739f, 0.537959f, 0.175966f,
+ 0.504604f, 0.176791f, 0.504547f, 0.184206f, 0.500890f, 0.187571f, 0.500100f, 0.176033f,
+ 0.537959f, 0.175966f, 0.533449f, 0.176739f, 0.531131f, 0.171631f, 0.535214f, 0.166808f,
+ 0.506910f, 0.171667f, 0.504604f, 0.176791f, 0.500100f, 0.176033f, 0.502799f, 0.166857f,
+ 0.519099f, 0.179457f, 0.533449f, 0.176739f, 0.533528f, 0.184215f, 0.528222f, 0.186316f,
+ 0.504547f, 0.184206f, 0.504604f, 0.176791f, 0.519099f, 0.179457f, 0.509787f, 0.186260f,
+ 0.519099f, 0.179457f, 0.519016f, 0.165599f, 0.531131f, 0.171631f, 0.533449f, 0.176739f,
+ 0.506910f, 0.171667f, 0.519016f, 0.165599f, 0.519099f, 0.179457f, 0.504604f, 0.176791f,
+ 0.519841f, 0.200843f, 0.544281f, 0.193366f, 0.553118f, 0.209599f, 0.519760f, 0.248864f,
+ 0.485339f, 0.210053f, 0.493996f, 0.193428f, 0.519841f, 0.200843f, 0.519760f, 0.248864f,
+ 0.544281f, 0.193366f, 0.548362f, 0.173560f, 0.561572f, 0.167779f, 0.553118f, 0.209599f,
+ 0.476363f, 0.167996f, 0.489683f, 0.173693f, 0.493996f, 0.193428f, 0.485339f, 0.210053f,
+ 0.548362f, 0.173560f, 0.538112f, 0.158382f, 0.559475f, 0.149319f, 0.561572f, 0.167779f,
+ 0.478371f, 0.149447f, 0.499851f, 0.158434f, 0.489683f, 0.173693f, 0.476363f, 0.167996f,
+ 0.538112f, 0.158382f, 0.532042f, 0.127713f, 0.555621f, 0.121749f, 0.559475f, 0.149319f,
+ 0.482177f, 0.121781f, 0.505828f, 0.127728f, 0.499851f, 0.158434f, 0.478371f, 0.149447f,
+ 0.583135f, 0.108495f, 0.596138f, 0.133426f, 0.559475f, 0.149319f, 0.555621f, 0.121749f,
+ 0.478371f, 0.149447f, 0.441395f, 0.133592f, 0.454527f, 0.108481f, 0.482177f, 0.121781f,
+ 0.596138f, 0.133426f, 0.601169f, 0.147885f, 0.561572f, 0.167779f, 0.559475f, 0.149319f,
+ 0.476363f, 0.167996f, 0.436337f, 0.148194f, 0.441395f, 0.133592f, 0.478371f, 0.149447f,
+ 0.605512f, 0.165134f, 0.553118f, 0.209599f, 0.561572f, 0.167779f, 0.601169f, 0.147885f,
+ 0.476363f, 0.167996f, 0.485339f, 0.210053f, 0.432024f, 0.165644f, 0.436337f, 0.148194f,
+ 0.531019f, 0.087431f, 0.518927f, 0.085180f, 0.518925f, 0.083865f, 0.528933f, 0.084957f,
+ 0.518925f, 0.083865f, 0.518927f, 0.085180f, 0.506827f, 0.087416f, 0.508915f, 0.084945f,
+ 0.531231f, 0.073829f, 0.531019f, 0.087431f, 0.528933f, 0.084957f, 0.529036f, 0.075429f,
+ 0.508915f, 0.084945f, 0.506827f, 0.087416f, 0.506626f, 0.073811f, 0.508820f, 0.075415f,
+ 0.525483f, 0.068967f, 0.531231f, 0.073829f, 0.529036f, 0.075429f, 0.523751f, 0.070508f,
+ 0.508820f, 0.075415f, 0.506626f, 0.073811f, 0.512375f, 0.068956f, 0.514106f, 0.070501f,
+ 0.518928f, 0.067899f, 0.525483f, 0.068967f, 0.523751f, 0.070508f, 0.518929f, 0.069468f,
+ 0.514106f, 0.070501f, 0.512375f, 0.068956f, 0.518928f, 0.067899f, 0.518929f, 0.069468f,
+ 0.518929f, 0.069468f, 0.523751f, 0.070508f, 0.521560f, 0.074970f, 0.518928f, 0.074259f,
+ 0.516297f, 0.074966f, 0.514106f, 0.070501f, 0.518929f, 0.069468f, 0.518928f, 0.074259f,
+ 0.523751f, 0.070508f, 0.529036f, 0.075429f, 0.524236f, 0.076691f, 0.521560f, 0.074970f,
+ 0.513619f, 0.076684f, 0.508820f, 0.075415f, 0.514106f, 0.070501f, 0.516297f, 0.074966f,
+ 0.529036f, 0.075429f, 0.528933f, 0.084957f, 0.524601f, 0.079886f, 0.524236f, 0.076691f,
+ 0.513252f, 0.079879f, 0.508915f, 0.084945f, 0.508820f, 0.075415f, 0.513619f, 0.076684f,
+ 0.528933f, 0.084957f, 0.518925f, 0.083865f, 0.518926f, 0.079331f, 0.524601f, 0.079886f,
+ 0.518926f, 0.079331f, 0.518925f, 0.083865f, 0.508915f, 0.084945f, 0.513252f, 0.079879f,
+ 0.518926f, 0.079331f, 0.518928f, 0.074259f, 0.521560f, 0.074970f, 0.524601f, 0.079886f,
+ 0.516297f, 0.074966f, 0.518928f, 0.074259f, 0.518926f, 0.079331f, 0.513252f, 0.079879f,
+ 0.524601f, 0.079886f, 0.521560f, 0.074970f, 0.524236f, 0.076691f,
+ 0.513619f, 0.076684f, 0.516297f, 0.074966f, 0.513252f, 0.079879f,
+ 0.556923f, 0.291214f, 0.563905f, 0.272007f, 0.571787f, 0.277295f, 0.568351f, 0.292904f,
+ 0.468070f, 0.278617f, 0.475886f, 0.273078f, 0.483433f, 0.292249f, 0.471978f, 0.294282f,
+ 0.558527f, 0.316594f, 0.556923f, 0.291214f, 0.568351f, 0.292904f, 0.573085f, 0.311386f,
+ 0.471978f, 0.294282f, 0.483433f, 0.292249f, 0.482619f, 0.317843f, 0.467790f, 0.313081f,
+ 0.577279f, 0.340156f, 0.558527f, 0.316594f, 0.573085f, 0.311386f, 0.584855f, 0.327708f,
+ 0.467790f, 0.313081f, 0.482619f, 0.317843f, 0.464579f, 0.342230f, 0.456477f, 0.329961f,
+ 0.563905f, 0.272007f, 0.572941f, 0.258564f, 0.580734f, 0.266620f, 0.571787f, 0.277295f,
+ 0.458737f, 0.268049f, 0.466409f, 0.259709f, 0.475886f, 0.273078f, 0.468070f, 0.278617f,
+ 0.572941f, 0.258564f, 0.613992f, 0.242662f, 0.611720f, 0.255725f, 0.580734f, 0.266620f,
+ 0.427062f, 0.257728f, 0.424464f, 0.244473f, 0.466409f, 0.259709f, 0.458737f, 0.268049f,
+ 0.613992f, 0.242662f, 0.639236f, 0.253047f, 0.632494f, 0.262853f, 0.611720f, 0.255725f,
+ 0.406068f, 0.265508f, 0.398938f, 0.255633f, 0.424464f, 0.244473f, 0.427062f, 0.257728f,
+ 0.639236f, 0.253047f, 0.664101f, 0.277872f, 0.653658f, 0.279971f, 0.632494f, 0.262853f,
+ 0.384904f, 0.283634f, 0.374100f, 0.281778f, 0.398938f, 0.255633f, 0.406068f, 0.265508f,
+ 0.664101f, 0.277872f, 0.668440f, 0.297958f, 0.656064f, 0.297636f, 0.653658f, 0.279971f,
+ 0.383015f, 0.301864f, 0.370304f, 0.302644f, 0.374100f, 0.281778f, 0.384904f, 0.283634f,
+ 0.668440f, 0.297958f, 0.662406f, 0.312804f, 0.652752f, 0.310186f, 0.656064f, 0.297636f,
+ 0.386858f, 0.314615f, 0.377061f, 0.317685f, 0.370304f, 0.302644f, 0.383015f, 0.301864f,
+ 0.662406f, 0.312804f, 0.634472f, 0.332311f, 0.629040f, 0.323864f, 0.652752f, 0.310186f,
+ 0.411556f, 0.327673f, 0.406362f, 0.336480f, 0.377061f, 0.317685f, 0.386858f, 0.314615f,
+ 0.634472f, 0.332311f, 0.615546f, 0.342005f, 0.614408f, 0.331972f, 0.629040f, 0.323864f,
+ 0.426727f, 0.335361f, 0.425972f, 0.345582f, 0.406362f, 0.336480f, 0.411556f, 0.327673f,
+ 0.615546f, 0.342005f, 0.599845f, 0.344815f, 0.601033f, 0.333624f, 0.614408f, 0.331972f,
+ 0.440344f, 0.336537f, 0.441977f, 0.347815f, 0.425972f, 0.345582f, 0.426727f, 0.335361f,
+ 0.599845f, 0.344815f, 0.577279f, 0.340156f, 0.584855f, 0.327708f, 0.601033f, 0.333624f,
+ 0.456477f, 0.329961f, 0.464579f, 0.342230f, 0.441977f, 0.347815f, 0.440344f, 0.336537f,
+ 0.601033f, 0.333624f, 0.584855f, 0.327708f, 0.590644f, 0.321516f, 0.601799f, 0.328453f,
+ 0.450408f, 0.323919f, 0.456477f, 0.329961f, 0.440344f, 0.336537f, 0.439372f, 0.331331f,
+ 0.614408f, 0.331972f, 0.601033f, 0.333624f, 0.601799f, 0.328453f, 0.613335f, 0.327083f,
+ 0.439372f, 0.331331f, 0.440344f, 0.336537f, 0.426727f, 0.335361f, 0.427623f, 0.330358f,
+ 0.629040f, 0.323864f, 0.614408f, 0.331972f, 0.613335f, 0.327083f, 0.626851f, 0.320513f,
+ 0.427623f, 0.330358f, 0.426727f, 0.335361f, 0.411556f, 0.327673f, 0.413648f, 0.324175f,
+ 0.652752f, 0.310186f, 0.629040f, 0.323864f, 0.626851f, 0.320513f, 0.646248f, 0.306421f,
+ 0.413648f, 0.324175f, 0.411556f, 0.327673f, 0.386858f, 0.314615f, 0.393381f, 0.310510f,
+ 0.656064f, 0.297636f, 0.652752f, 0.310186f, 0.646248f, 0.306421f, 0.649541f, 0.296225f,
+ 0.393381f, 0.310510f, 0.386858f, 0.314615f, 0.383015f, 0.301864f, 0.389662f, 0.300183f,
+ 0.653658f, 0.279971f, 0.656064f, 0.297636f, 0.649541f, 0.296225f, 0.647785f, 0.283486f,
+ 0.389662f, 0.300183f, 0.383015f, 0.301864f, 0.384904f, 0.283634f, 0.391040f, 0.287071f,
+ 0.632494f, 0.262853f, 0.653658f, 0.279971f, 0.647785f, 0.283486f, 0.629829f, 0.267263f,
+ 0.391040f, 0.287071f, 0.384904f, 0.283634f, 0.406068f, 0.265508f, 0.408893f, 0.269959f,
+ 0.611720f, 0.255725f, 0.632494f, 0.262853f, 0.629829f, 0.267263f, 0.612641f, 0.261560f,
+ 0.408893f, 0.269959f, 0.406068f, 0.265508f, 0.427062f, 0.257728f, 0.426254f, 0.263693f,
+ 0.580734f, 0.266620f, 0.611720f, 0.255725f, 0.612641f, 0.261560f, 0.585166f, 0.270991f,
+ 0.426254f, 0.263693f, 0.427062f, 0.257728f, 0.458737f, 0.268049f, 0.454369f, 0.272583f,
+ 0.571787f, 0.277295f, 0.580734f, 0.266620f, 0.585166f, 0.270991f, 0.578124f, 0.281900f,
+ 0.454369f, 0.272583f, 0.458737f, 0.268049f, 0.468070f, 0.278617f, 0.461798f, 0.283441f,
+ 0.584855f, 0.327708f, 0.573085f, 0.311386f, 0.579548f, 0.309340f, 0.590644f, 0.321516f,
+ 0.461204f, 0.311233f, 0.467790f, 0.313081f, 0.456477f, 0.329961f, 0.450408f, 0.323919f,
+ 0.573085f, 0.311386f, 0.568351f, 0.292904f, 0.577524f, 0.293776f, 0.579548f, 0.309340f,
+ 0.462754f, 0.295432f, 0.471978f, 0.294282f, 0.467790f, 0.313081f, 0.461204f, 0.311233f,
+ 0.568351f, 0.292904f, 0.571787f, 0.277295f, 0.578124f, 0.281900f, 0.577524f, 0.293776f,
+ 0.461798f, 0.283441f, 0.468070f, 0.278617f, 0.471978f, 0.294282f, 0.462754f, 0.295432f,
+ 0.521923f, 0.386009f, 0.553095f, 0.390512f, 0.553209f, 0.433063f, 0.523031f, 0.433628f,
+ 0.492809f, 0.434538f, 0.490934f, 0.391862f, 0.521923f, 0.386009f, 0.523031f, 0.433628f,
+ 0.553095f, 0.390512f, 0.604826f, 0.397804f, 0.609819f, 0.431516f, 0.553209f, 0.433063f,
+ 0.435860f, 0.435740f, 0.439252f, 0.401540f, 0.490934f, 0.391862f, 0.492809f, 0.434538f,
+ 0.604826f, 0.397804f, 0.626842f, 0.395792f, 0.648174f, 0.419316f, 0.609819f, 0.431516f,
+ 0.396518f, 0.425416f, 0.416915f, 0.400552f, 0.439252f, 0.401540f, 0.435860f, 0.435740f,
+ 0.626842f, 0.395792f, 0.662817f, 0.372521f, 0.692106f, 0.388274f, 0.648174f, 0.419316f,
+ 0.350292f, 0.396229f, 0.379297f, 0.378686f, 0.416915f, 0.400552f, 0.396518f, 0.425416f,
+ 0.662817f, 0.372521f, 0.697446f, 0.332673f, 0.726332f, 0.341754f, 0.692106f, 0.388274f,
+ 0.312756f, 0.350588f, 0.341964f, 0.339667f, 0.379297f, 0.378686f, 0.350292f, 0.396229f,
+ 0.697446f, 0.332673f, 0.707254f, 0.310054f, 0.735879f, 0.312112f, 0.726332f, 0.341754f,
+ 0.301067f, 0.320593f, 0.330721f, 0.316853f, 0.341964f, 0.339667f, 0.312756f, 0.350588f,
+ 0.707254f, 0.310054f, 0.715342f, 0.265392f, 0.729900f, 0.256393f, 0.735879f, 0.312112f,
+ 0.304876f, 0.261087f, 0.320452f, 0.270303f, 0.330721f, 0.316853f, 0.301067f, 0.320593f,
+ 0.715342f, 0.265392f, 0.676379f, 0.233241f, 0.698172f, 0.216906f, 0.729900f, 0.256393f,
+ 0.337414f, 0.219179f, 0.360308f, 0.235899f, 0.320452f, 0.270303f, 0.304876f, 0.261087f,
+ 0.676379f, 0.233241f, 0.647395f, 0.200502f, 0.663103f, 0.190671f, 0.698172f, 0.216906f,
+ 0.373474f, 0.191872f, 0.389677f, 0.201890f, 0.360308f, 0.235899f, 0.337414f, 0.219179f,
+ 0.626908f, 0.015608f, 0.649444f, 0.022378f, 0.660451f, 0.076084f, 0.621440f, 0.048089f,
+ 0.376796f, 0.075296f, 0.388827f, 0.021586f, 0.411318f, 0.015131f, 0.416419f, 0.047631f,
+ 0.567460f, 0.000144f, 0.626908f, 0.015608f, 0.621440f, 0.048089f, 0.577206f, 0.032801f,
+ 0.416419f, 0.047631f, 0.411318f, 0.015131f, 0.470636f, 0.000144f, 0.460782f, 0.032656f,
+ 0.518922f, 0.024886f, 0.567460f, 0.000144f, 0.577206f, 0.032801f, 0.547413f, 0.041724f,
+ 0.460782f, 0.032656f, 0.470636f, 0.000144f, 0.518922f, 0.024886f, 0.490511f, 0.041669f,
+ 0.540260f, 0.053805f, 0.518916f, 0.050294f, 0.518922f, 0.024886f, 0.547413f, 0.041724f,
+ 0.518922f, 0.024886f, 0.518916f, 0.050294f, 0.497626f, 0.053770f, 0.490511f, 0.041669f,
+ 0.551930f, 0.058338f, 0.540260f, 0.053805f, 0.547413f, 0.041724f, 0.558059f, 0.053871f,
+ 0.490511f, 0.041669f, 0.497626f, 0.053770f, 0.485955f, 0.058273f, 0.479842f, 0.053785f,
+ 0.555073f, 0.061900f, 0.551930f, 0.058338f, 0.558059f, 0.053871f, 0.576951f, 0.057998f,
+ 0.479842f, 0.053785f, 0.485955f, 0.058273f, 0.482805f, 0.061829f, 0.460920f, 0.057845f,
+ 0.563812f, 0.076586f, 0.555073f, 0.061900f, 0.576951f, 0.057998f, 0.611687f, 0.078268f,
+ 0.460920f, 0.057845f, 0.482805f, 0.061829f, 0.474014f, 0.076511f, 0.425932f, 0.077985f,
+ 0.576951f, 0.057998f, 0.577206f, 0.032801f, 0.621440f, 0.048089f, 0.611687f, 0.078268f,
+ 0.416419f, 0.047631f, 0.460782f, 0.032656f, 0.460920f, 0.057845f, 0.425932f, 0.077985f,
+ 0.576951f, 0.057998f, 0.558059f, 0.053871f, 0.547413f, 0.041724f, 0.577206f, 0.032801f,
+ 0.490511f, 0.041669f, 0.479842f, 0.053785f, 0.460920f, 0.057845f, 0.460782f, 0.032656f,
+ 0.626663f, 0.111357f, 0.611687f, 0.078268f, 0.621440f, 0.048089f, 0.660451f, 0.076084f,
+ 0.416419f, 0.047631f, 0.425932f, 0.077985f, 0.410618f, 0.111244f, 0.376796f, 0.075296f,
+ 0.583135f, 0.108495f, 0.563812f, 0.076586f, 0.611687f, 0.078268f, 0.626663f, 0.111357f,
+ 0.425932f, 0.077985f, 0.474014f, 0.076511f, 0.454527f, 0.108481f, 0.410618f, 0.111244f,
+ 0.596138f, 0.133426f, 0.629482f, 0.130456f, 0.623495f, 0.146796f, 0.601169f, 0.147885f,
+ 0.413741f, 0.147158f, 0.407648f, 0.130594f, 0.441395f, 0.133592f, 0.436337f, 0.148194f,
+ 0.583135f, 0.108495f, 0.626663f, 0.111357f, 0.629482f, 0.130456f, 0.596138f, 0.133426f,
+ 0.407648f, 0.130594f, 0.410618f, 0.111244f, 0.454527f, 0.108481f, 0.441395f, 0.133592f,
+ 0.605512f, 0.165134f, 0.601169f, 0.147885f, 0.623495f, 0.146796f, 0.619303f, 0.159841f,
+ 0.413741f, 0.147158f, 0.436337f, 0.148194f, 0.432024f, 0.165644f, 0.418035f, 0.160361f,
+ 0.605512f, 0.165134f, 0.619303f, 0.159841f, 0.663103f, 0.190671f, 0.647395f, 0.200502f,
+ 0.373474f, 0.191872f, 0.418035f, 0.160361f, 0.432024f, 0.165644f, 0.389677f, 0.201890f,
+ 0.945900f, 0.079569f, 0.886245f, 0.121777f, 0.849114f, 0.099732f, 0.891780f, 0.036916f,
+ 0.183115f, 0.092127f, 0.141314f, 0.112482f, 0.078961f, 0.060719f, 0.142277f, 0.021467f,
+ 0.891780f, 0.036916f, 0.849114f, 0.099732f, 0.788458f, 0.080826f, 0.805584f, 0.010786f,
+ 0.246353f, 0.076510f, 0.183115f, 0.092127f, 0.142277f, 0.021467f, 0.232648f, 0.003484f,
+ 0.805584f, 0.010786f, 0.788458f, 0.080826f, 0.687018f, 0.077204f, 0.672384f, 0.022201f,
+ 0.349875f, 0.075955f, 0.246353f, 0.076510f, 0.232648f, 0.003484f, 0.365979f, 0.020991f,
+ 0.672384f, 0.022201f, 0.687018f, 0.077204f, 0.660451f, 0.076084f, 0.649444f, 0.022378f,
+ 0.376796f, 0.075296f, 0.349875f, 0.075955f, 0.365979f, 0.020991f, 0.388827f, 0.021586f,
+ 0.626663f, 0.111357f, 0.660451f, 0.076084f, 0.687018f, 0.077204f, 0.629482f, 0.130456f,
+ 0.349875f, 0.075955f, 0.376796f, 0.075296f, 0.410618f, 0.111244f, 0.407648f, 0.130594f,
+ 0.729900f, 0.256393f, 0.698172f, 0.216906f, 0.760215f, 0.193244f, 0.789046f, 0.233323f,
+ 0.271553f, 0.193871f, 0.337414f, 0.219179f, 0.304876f, 0.261087f, 0.241255f, 0.236977f,
+ 0.994525f, 0.167705f, 0.909112f, 0.183261f, 0.886245f, 0.121777f, 0.945900f, 0.079569f,
+ 0.141314f, 0.112482f, 0.107928f, 0.179083f, 0.011829f, 0.155367f, 0.078961f, 0.060719f,
+ 0.911671f, 0.402429f, 0.862868f, 0.338556f, 0.894128f, 0.301884f, 0.962901f, 0.344752f,
+ 0.123776f, 0.315519f, 0.160557f, 0.356821f, 0.106400f, 0.432652f, 0.043968f, 0.367038f,
+ 0.962901f, 0.344752f, 0.894128f, 0.301884f, 0.915360f, 0.259804f, 0.999856f, 0.254640f,
+ 0.098965f, 0.266968f, 0.123776f, 0.315519f, 0.043968f, 0.367038f, 0.000144f, 0.259113f,
+ 0.999856f, 0.254640f, 0.915360f, 0.259804f, 0.909112f, 0.183261f, 0.994525f, 0.167705f,
+ 0.107928f, 0.179083f, 0.098965f, 0.266968f, 0.000144f, 0.259113f, 0.011829f, 0.155367f,
+ 0.749542f, 0.334683f, 0.735879f, 0.312112f, 0.766337f, 0.300809f, 0.789162f, 0.313727f,
+ 0.267408f, 0.310142f, 0.301067f, 0.320593f, 0.288183f, 0.346496f, 0.242992f, 0.325552f,
+ 0.789162f, 0.313727f, 0.766337f, 0.300809f, 0.815314f, 0.276388f, 0.846174f, 0.293397f,
+ 0.213065f, 0.285164f, 0.267408f, 0.310142f, 0.242992f, 0.325552f, 0.178537f, 0.304983f,
+ 0.846174f, 0.293397f, 0.815314f, 0.276388f, 0.845007f, 0.256352f, 0.873517f, 0.265922f,
+ 0.179662f, 0.263312f, 0.213065f, 0.285164f, 0.178537f, 0.304983f, 0.147089f, 0.274284f,
+ 0.873517f, 0.265922f, 0.845007f, 0.256352f, 0.859075f, 0.228168f, 0.886999f, 0.233769f,
+ 0.162803f, 0.231720f, 0.179662f, 0.263312f, 0.147089f, 0.274284f, 0.131514f, 0.237587f,
+ 0.842355f, 0.195160f, 0.875030f, 0.184705f, 0.886999f, 0.233769f, 0.859075f, 0.228168f,
+ 0.131514f, 0.237587f, 0.145224f, 0.182749f, 0.176788f, 0.196179f, 0.162803f, 0.231720f,
+ 0.909112f, 0.183261f, 0.915360f, 0.259804f, 0.886999f, 0.233769f, 0.875030f, 0.184705f,
+ 0.131514f, 0.237587f, 0.098965f, 0.266968f, 0.107928f, 0.179083f, 0.145224f, 0.182749f,
+ 0.915360f, 0.259804f, 0.894128f, 0.301884f, 0.873517f, 0.265922f, 0.886999f, 0.233769f,
+ 0.147089f, 0.274284f, 0.123776f, 0.315519f, 0.098965f, 0.266968f, 0.131514f, 0.237587f,
+ 0.894128f, 0.301884f, 0.862868f, 0.338556f, 0.846174f, 0.293397f, 0.873517f, 0.265922f,
+ 0.178537f, 0.304983f, 0.160557f, 0.356821f, 0.123776f, 0.315519f, 0.147089f, 0.274284f,
+ 0.862868f, 0.338556f, 0.794286f, 0.364062f, 0.789162f, 0.313727f, 0.846174f, 0.293397f,
+ 0.242992f, 0.325552f, 0.239776f, 0.382592f, 0.160557f, 0.356821f, 0.178537f, 0.304983f,
+ 0.770185f, 0.379538f, 0.749542f, 0.334683f, 0.789162f, 0.313727f, 0.794286f, 0.364062f,
+ 0.242992f, 0.325552f, 0.288183f, 0.346496f, 0.268122f, 0.398737f, 0.239776f, 0.382592f,
+ 0.845499f, 0.449967f, 0.794286f, 0.364062f, 0.862868f, 0.338556f, 0.911671f, 0.402429f,
+ 0.160557f, 0.356821f, 0.239776f, 0.382592f, 0.185281f, 0.484099f, 0.106400f, 0.432652f,
+ 0.815858f, 0.445381f, 0.770572f, 0.444261f, 0.755700f, 0.418603f, 0.770185f, 0.379538f,
+ 0.287033f, 0.442912f, 0.271364f, 0.473316f, 0.219260f, 0.477186f, 0.268122f, 0.398737f,
+ 0.815858f, 0.445381f, 0.770185f, 0.379538f, 0.794286f, 0.364062f, 0.845499f, 0.449967f,
+ 0.239776f, 0.382592f, 0.268122f, 0.398737f, 0.219260f, 0.477186f, 0.185281f, 0.484099f,
+ 0.819845f, 0.468071f, 0.815858f, 0.445381f, 0.845499f, 0.449967f,
+ 0.185281f, 0.484099f, 0.219260f, 0.477186f, 0.215894f, 0.503605f,
+ 0.735879f, 0.312112f, 0.729900f, 0.256393f, 0.789046f, 0.233323f, 0.766337f, 0.300809f,
+ 0.241255f, 0.236977f, 0.304876f, 0.261087f, 0.301067f, 0.320593f, 0.267408f, 0.310142f,
+ 0.789046f, 0.233323f, 0.809631f, 0.233887f, 0.815314f, 0.276388f, 0.766337f, 0.300809f,
+ 0.213065f, 0.285164f, 0.219168f, 0.237388f, 0.241255f, 0.236977f, 0.267408f, 0.310142f,
+ 0.809631f, 0.233887f, 0.829287f, 0.219562f, 0.845007f, 0.256352f, 0.815314f, 0.276388f,
+ 0.179662f, 0.263312f, 0.199067f, 0.222464f, 0.219168f, 0.237388f, 0.213065f, 0.285164f,
+ 0.842355f, 0.195160f, 0.859075f, 0.228168f, 0.845007f, 0.256352f, 0.829287f, 0.219562f,
+ 0.179662f, 0.263312f, 0.162803f, 0.231720f, 0.176788f, 0.196179f, 0.199067f, 0.222464f,
+ 0.687018f, 0.077204f, 0.788458f, 0.080826f, 0.786480f, 0.117591f, 0.715482f, 0.139727f,
+ 0.246666f, 0.114850f, 0.246353f, 0.076510f, 0.349875f, 0.075955f, 0.319538f, 0.139409f,
+ 0.760215f, 0.193244f, 0.715482f, 0.139727f, 0.786480f, 0.117591f, 0.785486f, 0.152330f,
+ 0.246666f, 0.114850f, 0.319538f, 0.139409f, 0.271553f, 0.193871f, 0.245969f, 0.151002f,
+ 0.698172f, 0.216906f, 0.663103f, 0.190671f, 0.715482f, 0.139727f, 0.760215f, 0.193244f,
+ 0.319538f, 0.139409f, 0.373474f, 0.191872f, 0.337414f, 0.219179f, 0.271553f, 0.193871f,
+ 0.663103f, 0.190671f, 0.623495f, 0.146796f, 0.629482f, 0.130456f, 0.715482f, 0.139727f,
+ 0.407648f, 0.130594f, 0.413741f, 0.147158f, 0.373474f, 0.191872f, 0.319538f, 0.139409f,
+ 0.629482f, 0.130456f, 0.687018f, 0.077204f, 0.715482f, 0.139727f,
+ 0.319538f, 0.139409f, 0.349875f, 0.075955f, 0.407648f, 0.130594f,
+ 0.663103f, 0.190671f, 0.619303f, 0.159841f, 0.623495f, 0.146796f,
+ 0.413741f, 0.147158f, 0.418035f, 0.160361f, 0.373474f, 0.191872f,
+ 0.842355f, 0.195160f, 0.837382f, 0.156361f, 0.858171f, 0.137775f, 0.875030f, 0.184705f,
+ 0.171653f, 0.132294f, 0.196622f, 0.155241f, 0.176788f, 0.196179f, 0.145224f, 0.182749f,
+ 0.909112f, 0.183261f, 0.875030f, 0.184705f, 0.858171f, 0.137775f, 0.886245f, 0.121777f,
+ 0.171653f, 0.132294f, 0.145224f, 0.182749f, 0.107928f, 0.179083f, 0.141314f, 0.112482f,
+ 0.785486f, 0.152330f, 0.786480f, 0.117591f, 0.858171f, 0.137775f, 0.837382f, 0.156361f,
+ 0.171653f, 0.132294f, 0.246666f, 0.114850f, 0.245969f, 0.151002f, 0.196622f, 0.155241f,
+ 0.788458f, 0.080826f, 0.849114f, 0.099732f, 0.858171f, 0.137775f, 0.786480f, 0.117591f,
+ 0.171653f, 0.132294f, 0.183115f, 0.092127f, 0.246353f, 0.076510f, 0.246666f, 0.114850f,
+ 0.886245f, 0.121777f, 0.858171f, 0.137775f, 0.849114f, 0.099732f,
+ 0.183115f, 0.092127f, 0.171653f, 0.132294f, 0.141314f, 0.112482f,
+ 0.506166f, 0.904851f, 0.432388f, 0.894943f, 0.438797f, 0.870229f, 0.491058f, 0.881714f,
+ 0.315867f, 0.868209f, 0.321637f, 0.893225f, 0.247207f, 0.901159f, 0.263032f, 0.878321f,
+ 0.506166f, 0.904851f, 0.491058f, 0.881714f, 0.572792f, 0.860484f, 0.604825f, 0.879946f,
+ 0.181486f, 0.854693f, 0.263032f, 0.878321f, 0.247207f, 0.901159f, 0.148729f, 0.873349f,
+ 0.604825f, 0.879946f, 0.572792f, 0.860484f, 0.586396f, 0.793977f, 0.619962f, 0.791615f,
+ 0.169745f, 0.787474f, 0.181486f, 0.854693f, 0.148729f, 0.873349f, 0.136063f, 0.784093f,
+ 0.619962f, 0.791615f, 0.586396f, 0.793977f, 0.549027f, 0.746412f, 0.563786f, 0.739211f,
+ 0.208656f, 0.740879f, 0.169745f, 0.787474f, 0.136063f, 0.784093f, 0.194086f, 0.733241f,
+ 0.563786f, 0.739211f, 0.549027f, 0.746412f, 0.500314f, 0.711729f, 0.508270f, 0.697693f,
+ 0.258399f, 0.707497f, 0.208656f, 0.740879f, 0.194086f, 0.733241f, 0.250811f, 0.693249f,
+ 0.508270f, 0.697693f, 0.500314f, 0.711729f, 0.438641f, 0.680683f, 0.434803f, 0.658882f,
+ 0.320962f, 0.677959f, 0.258399f, 0.707497f, 0.250811f, 0.693249f, 0.325318f, 0.656224f,
+ 0.500314f, 0.711729f, 0.505666f, 0.730944f, 0.452955f, 0.700023f, 0.438641f, 0.680683f,
+ 0.306136f, 0.696976f, 0.252524f, 0.726592f, 0.258399f, 0.707497f, 0.320962f, 0.677959f,
+ 0.549027f, 0.746412f, 0.542850f, 0.755753f, 0.505666f, 0.730944f, 0.500314f, 0.711729f,
+ 0.252524f, 0.726592f, 0.214575f, 0.750414f, 0.208656f, 0.740879f, 0.258399f, 0.707497f,
+ 0.586396f, 0.793977f, 0.568148f, 0.787367f, 0.542850f, 0.755753f, 0.549027f, 0.746412f,
+ 0.214575f, 0.750414f, 0.188269f, 0.781375f, 0.169745f, 0.787474f, 0.208656f, 0.740879f,
+ 0.572792f, 0.860484f, 0.555495f, 0.826352f, 0.568148f, 0.787367f, 0.586396f, 0.793977f,
+ 0.188269f, 0.781375f, 0.199850f, 0.820889f, 0.181486f, 0.854693f, 0.169745f, 0.787474f,
+ 0.491058f, 0.881714f, 0.501231f, 0.844356f, 0.555495f, 0.826352f, 0.572792f, 0.860484f,
+ 0.199850f, 0.820889f, 0.253846f, 0.840502f, 0.263032f, 0.878321f, 0.181486f, 0.854693f,
+ 0.491058f, 0.881714f, 0.438797f, 0.870229f, 0.457832f, 0.840040f, 0.501231f, 0.844356f,
+ 0.297562f, 0.837358f, 0.315867f, 0.868209f, 0.263032f, 0.878321f, 0.253846f, 0.840502f,
+ 0.760215f, 0.193244f, 0.785486f, 0.152330f, 0.796021f, 0.176969f, 0.783193f, 0.187449f,
+ 0.233625f, 0.175620f, 0.245969f, 0.151002f, 0.271553f, 0.193871f, 0.246955f, 0.187075f,
+ 0.391039f, 0.611891f, 0.434803f, 0.658882f, 0.438641f, 0.680683f, 0.394766f, 0.686125f,
+ 0.320962f, 0.677959f, 0.325318f, 0.656224f, 0.369913f, 0.610196f, 0.364838f, 0.684445f,
+ 0.789046f, 0.233323f, 0.760215f, 0.193244f, 0.783193f, 0.187449f, 0.809631f, 0.233887f,
+ 0.246955f, 0.187075f, 0.271553f, 0.193871f, 0.241255f, 0.236977f, 0.219168f, 0.237388f,
+ 0.391747f, 0.862097f, 0.401605f, 0.841460f, 0.438797f, 0.870229f, 0.432388f, 0.894943f,
+ 0.315867f, 0.868209f, 0.354026f, 0.840297f, 0.363377f, 0.861308f, 0.321637f, 0.893225f,
+ 0.438641f, 0.680683f, 0.452955f, 0.700023f, 0.435018f, 0.718280f, 0.394766f, 0.686125f,
+ 0.323658f, 0.715731f, 0.306136f, 0.696976f, 0.320962f, 0.677959f, 0.364838f, 0.684445f,
+ 0.433669f, 0.729661f, 0.384658f, 0.710299f, 0.394766f, 0.686125f, 0.435018f, 0.718280f,
+ 0.364838f, 0.684445f, 0.374400f, 0.708969f, 0.324726f, 0.727177f, 0.323658f, 0.715731f,
+ 0.410995f, 0.747662f, 0.384658f, 0.710299f, 0.433669f, 0.729661f, 0.427812f, 0.742828f,
+ 0.324726f, 0.727177f, 0.374400f, 0.708969f, 0.347028f, 0.745816f, 0.330270f, 0.740536f,
+ 0.418086f, 0.784946f, 0.384657f, 0.795423f, 0.384658f, 0.710299f, 0.410995f, 0.747662f,
+ 0.374400f, 0.708969f, 0.372270f, 0.794472f, 0.338952f, 0.783073f, 0.347028f, 0.745816f,
+ 0.401605f, 0.841460f, 0.384657f, 0.795423f, 0.418086f, 0.784946f, 0.431333f, 0.817535f,
+ 0.338952f, 0.783073f, 0.372270f, 0.794472f, 0.354026f, 0.840297f, 0.324790f, 0.815460f,
+ 0.438797f, 0.870229f, 0.401605f, 0.841460f, 0.431333f, 0.817535f, 0.457832f, 0.840040f,
+ 0.324790f, 0.815460f, 0.354026f, 0.840297f, 0.315867f, 0.868209f, 0.297562f, 0.837358f,
+ 0.809631f, 0.233887f, 0.816266f, 0.203086f, 0.825107f, 0.209762f, 0.829287f, 0.219562f,
+ 0.199767f, 0.214827f, 0.209828f, 0.206161f, 0.219168f, 0.237388f, 0.199067f, 0.222464f,
+ 0.809631f, 0.233887f, 0.783193f, 0.187449f, 0.802192f, 0.184609f, 0.816266f, 0.203086f,
+ 0.226485f, 0.183086f, 0.246955f, 0.187075f, 0.219168f, 0.237388f, 0.209828f, 0.206161f,
+ 0.783193f, 0.187449f, 0.796021f, 0.176969f, 0.802192f, 0.184609f,
+ 0.226485f, 0.183086f, 0.233625f, 0.175620f, 0.246955f, 0.187075f,
+ 0.457832f, 0.840040f, 0.431333f, 0.817535f, 0.448505f, 0.804621f, 0.473386f, 0.824700f,
+ 0.307886f, 0.802031f, 0.324790f, 0.815460f, 0.297562f, 0.837358f, 0.282357f, 0.821525f,
+ 0.431333f, 0.817535f, 0.418086f, 0.784946f, 0.435868f, 0.779569f, 0.448505f, 0.804621f,
+ 0.321237f, 0.777208f, 0.338952f, 0.783073f, 0.324790f, 0.815460f, 0.307886f, 0.802031f,
+ 0.418086f, 0.784946f, 0.410995f, 0.747662f, 0.423718f, 0.754191f, 0.435868f, 0.779569f,
+ 0.334089f, 0.752045f, 0.347028f, 0.745816f, 0.338952f, 0.783073f, 0.321237f, 0.777208f,
+ 0.410995f, 0.747662f, 0.427812f, 0.742828f, 0.437950f, 0.749777f, 0.423718f, 0.754191f,
+ 0.319919f, 0.747250f, 0.330270f, 0.740536f, 0.347028f, 0.745816f, 0.334089f, 0.752045f,
+ 0.427812f, 0.742828f, 0.433669f, 0.729661f, 0.445392f, 0.731997f, 0.437950f, 0.749777f,
+ 0.312907f, 0.729222f, 0.324726f, 0.727177f, 0.330270f, 0.740536f, 0.319919f, 0.747250f,
+ 0.433669f, 0.729661f, 0.435018f, 0.718280f, 0.440995f, 0.724383f, 0.445392f, 0.731997f,
+ 0.317510f, 0.721697f, 0.323658f, 0.715731f, 0.324726f, 0.727177f, 0.312907f, 0.729222f,
+ 0.435018f, 0.718280f, 0.452955f, 0.700023f, 0.455277f, 0.713731f, 0.440995f, 0.724383f,
+ 0.303460f, 0.710657f, 0.306136f, 0.696976f, 0.323658f, 0.715731f, 0.317510f, 0.721697f,
+ 0.501231f, 0.844356f, 0.457832f, 0.840040f, 0.473386f, 0.824700f, 0.512485f, 0.828811f,
+ 0.282357f, 0.821525f, 0.297562f, 0.837358f, 0.253846f, 0.840502f, 0.242975f, 0.824574f,
+ 0.555495f, 0.826352f, 0.501231f, 0.844356f, 0.512485f, 0.828811f, 0.550942f, 0.811814f,
+ 0.242975f, 0.824574f, 0.253846f, 0.840502f, 0.199850f, 0.820889f, 0.204839f, 0.806417f,
+ 0.568148f, 0.787367f, 0.555495f, 0.826352f, 0.550942f, 0.811814f, 0.552139f, 0.787682f,
+ 0.204839f, 0.806417f, 0.199850f, 0.820889f, 0.188269f, 0.781375f, 0.204331f, 0.782156f,
+ 0.542850f, 0.755753f, 0.568148f, 0.787367f, 0.552139f, 0.787682f, 0.539407f, 0.764539f,
+ 0.204331f, 0.782156f, 0.188269f, 0.781375f, 0.214575f, 0.750414f, 0.217774f, 0.759319f,
+ 0.505666f, 0.730944f, 0.542850f, 0.755753f, 0.539407f, 0.764539f, 0.508439f, 0.743135f,
+ 0.217774f, 0.759319f, 0.214575f, 0.750414f, 0.252524f, 0.726592f, 0.249419f, 0.738732f,
+ 0.452955f, 0.700023f, 0.505666f, 0.730944f, 0.508439f, 0.743135f, 0.455277f, 0.713731f,
+ 0.249419f, 0.738732f, 0.252524f, 0.726592f, 0.306136f, 0.696976f, 0.303460f, 0.710657f,
+ 0.437950f, 0.749777f, 0.445392f, 0.731997f, 0.470841f, 0.748408f, 0.454776f, 0.761665f,
+ 0.286960f, 0.745020f, 0.312907f, 0.729222f, 0.319919f, 0.747250f, 0.302729f, 0.758742f,
+ 0.454776f, 0.761665f, 0.470841f, 0.748408f, 0.488870f, 0.770464f, 0.475403f, 0.783904f,
+ 0.268291f, 0.766661f, 0.286960f, 0.745020f, 0.302729f, 0.758742f, 0.281439f, 0.780511f,
+ 0.475403f, 0.783904f, 0.488870f, 0.770464f, 0.503673f, 0.787562f, 0.494476f, 0.802470f,
+ 0.252972f, 0.783410f, 0.268291f, 0.766661f, 0.281439f, 0.780511f, 0.261790f, 0.798626f,
+ 0.494476f, 0.802470f, 0.503673f, 0.787562f, 0.518562f, 0.791602f, 0.516802f, 0.807339f,
+ 0.237920f, 0.787045f, 0.252972f, 0.783410f, 0.261790f, 0.798626f, 0.239243f, 0.802891f,
+ 0.512485f, 0.828811f, 0.473386f, 0.824700f, 0.494476f, 0.802470f, 0.516802f, 0.807339f,
+ 0.261790f, 0.798626f, 0.282357f, 0.821525f, 0.242975f, 0.824574f, 0.239243f, 0.802891f,
+ 0.448505f, 0.804621f, 0.475403f, 0.783904f, 0.494476f, 0.802470f, 0.473386f, 0.824700f,
+ 0.261790f, 0.798626f, 0.281439f, 0.780511f, 0.307886f, 0.802031f, 0.282357f, 0.821525f,
+ 0.448505f, 0.804621f, 0.435868f, 0.779569f, 0.454776f, 0.761665f, 0.475403f, 0.783904f,
+ 0.302729f, 0.758742f, 0.321237f, 0.777208f, 0.307886f, 0.802031f, 0.281439f, 0.780511f,
+ 0.437950f, 0.749777f, 0.454776f, 0.761665f, 0.435868f, 0.779569f, 0.423718f, 0.754191f,
+ 0.321237f, 0.777208f, 0.302729f, 0.758742f, 0.319919f, 0.747250f, 0.334089f, 0.752045f,
+ 0.440995f, 0.724383f, 0.455277f, 0.713731f, 0.470841f, 0.748408f, 0.445392f, 0.731997f,
+ 0.286960f, 0.745020f, 0.303460f, 0.710657f, 0.317510f, 0.721697f, 0.312907f, 0.729222f,
+ 0.508439f, 0.743135f, 0.488870f, 0.770464f, 0.470841f, 0.748408f, 0.455277f, 0.713731f,
+ 0.286960f, 0.745020f, 0.268291f, 0.766661f, 0.249419f, 0.738732f, 0.303460f, 0.710657f,
+ 0.539407f, 0.764539f, 0.503673f, 0.787562f, 0.488870f, 0.770464f, 0.508439f, 0.743135f,
+ 0.268291f, 0.766661f, 0.252972f, 0.783410f, 0.217774f, 0.759319f, 0.249419f, 0.738732f,
+ 0.552139f, 0.787682f, 0.518562f, 0.791602f, 0.503673f, 0.787562f, 0.539407f, 0.764539f,
+ 0.252972f, 0.783410f, 0.237920f, 0.787045f, 0.204331f, 0.782156f, 0.217774f, 0.759319f,
+ 0.550942f, 0.811814f, 0.516802f, 0.807339f, 0.518562f, 0.791602f, 0.552139f, 0.787682f,
+ 0.237920f, 0.787045f, 0.239243f, 0.802891f, 0.204839f, 0.806417f, 0.204331f, 0.782156f,
+ 0.512485f, 0.828811f, 0.516802f, 0.807339f, 0.550942f, 0.811814f,
+ 0.204839f, 0.806417f, 0.239243f, 0.802891f, 0.242975f, 0.824574f,
+ 0.508270f, 0.697693f, 0.434803f, 0.658882f, 0.484068f, 0.628776f, 0.543385f, 0.683538f,
+ 0.276936f, 0.625067f, 0.325318f, 0.656224f, 0.250811f, 0.693249f, 0.216123f, 0.678120f,
+ 0.563786f, 0.739211f, 0.508270f, 0.697693f, 0.543385f, 0.683538f, 0.581052f, 0.726933f,
+ 0.216123f, 0.678120f, 0.250811f, 0.693249f, 0.194086f, 0.733241f, 0.177176f, 0.720426f,
+ 0.619962f, 0.791615f, 0.563786f, 0.739211f, 0.581052f, 0.726933f, 0.616701f, 0.759965f,
+ 0.177176f, 0.720426f, 0.194086f, 0.733241f, 0.136063f, 0.784093f, 0.140379f, 0.752377f,
+ 0.707492f, 0.759884f, 0.619962f, 0.791615f, 0.616701f, 0.759965f, 0.660647f, 0.741167f,
+ 0.140379f, 0.752377f, 0.136063f, 0.784093f, 0.049526f, 0.748824f, 0.097038f, 0.732052f,
+ 0.745511f, 0.652100f, 0.707492f, 0.759884f, 0.660647f, 0.741167f, 0.677256f, 0.670436f,
+ 0.097038f, 0.732052f, 0.049526f, 0.748824f, 0.019409f, 0.639749f, 0.083564f, 0.662038f,
+ 0.740843f, 0.572428f, 0.745511f, 0.652100f, 0.677256f, 0.670436f, 0.671403f, 0.592656f,
+ 0.083564f, 0.662038f, 0.019409f, 0.639749f, 0.033664f, 0.564403f, 0.092820f, 0.589862f,
+ 0.677256f, 0.670436f, 0.543385f, 0.683538f, 0.484068f, 0.628776f, 0.671403f, 0.592656f,
+ 0.276936f, 0.625067f, 0.216123f, 0.678120f, 0.083564f, 0.662038f, 0.092820f, 0.589862f,
+ 0.677256f, 0.670436f, 0.660647f, 0.741167f, 0.581052f, 0.726933f, 0.543385f, 0.683538f,
+ 0.177176f, 0.720426f, 0.097038f, 0.732052f, 0.083564f, 0.662038f, 0.216123f, 0.678120f,
+ 0.660647f, 0.741167f, 0.616701f, 0.759965f, 0.581052f, 0.726933f,
+ 0.177176f, 0.720426f, 0.140379f, 0.752377f, 0.097038f, 0.732052f,
+ 0.842355f, 0.195160f, 0.829287f, 0.219562f, 0.834578f, 0.206879f, 0.834705f, 0.206959f,
+ 0.033664f, 0.564403f, 0.051216f, 0.522659f, 0.145041f, 0.562595f, 0.092820f, 0.589862f,
+ 0.620420f, 0.565675f, 0.671403f, 0.592656f, 0.484068f, 0.628776f, 0.498072f, 0.552315f,
+ 0.276936f, 0.625067f, 0.092820f, 0.589862f, 0.145041f, 0.562595f, 0.264218f, 0.550140f,
+ 0.391039f, 0.611891f, 0.498072f, 0.552315f, 0.484068f, 0.628776f, 0.434803f, 0.658882f,
+ 0.276936f, 0.625067f, 0.264218f, 0.550140f, 0.369913f, 0.610196f, 0.325318f, 0.656224f
+};
+
#define VERT_MARK 1
#define EDGE_ORIG 1
@@ -231,11 +760,13 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op)
BMOpSlot *slot_verts_out = BMO_slot_get(op->slots_out, "verts.out");
const float dia = BMO_slot_float_get(op->slots_in, "size");
- const unsigned int xtot = max_ii(2, BMO_slot_int_get(op->slots_in, "x_segments"));
- const unsigned int ytot = max_ii(2, BMO_slot_int_get(op->slots_in, "y_segments"));
+ const uint xtot = max_ii(2, BMO_slot_int_get(op->slots_in, "x_segments"));
+ const uint ytot = max_ii(2, BMO_slot_int_get(op->slots_in, "y_segments"));
const float xtot_inv2 = 2.0f / (xtot - 1);
const float ytot_inv2 = 2.0f / (ytot - 1);
- const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs");
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs");
BMVert **varr;
BMVert *vquad[4];
@@ -243,7 +774,7 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op)
float mat[4][4];
float vec[3], tvec[3];
- unsigned int x, y, i;
+ uint x, y, i;
BMO_slot_mat4_get(op->slots_in, "matrix", mat);
@@ -285,7 +816,7 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op)
#undef XY
if (calc_uvs) {
- BM_mesh_calc_uvs_grid(bm, xtot, ytot, FACE_MARK);
+ BM_mesh_calc_uvs_grid(bm, xtot, ytot, FACE_MARK, cd_loop_uv_offset);
}
}
@@ -297,7 +828,9 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op)
* \param y_segments The y-resolution of the grid
* \param oflag The flag to check faces with.
*/
-void BM_mesh_calc_uvs_grid(BMesh *bm, const unsigned int x_segments, const unsigned int y_segments, const short oflag)
+void BM_mesh_calc_uvs_grid(
+ BMesh *bm, const uint x_segments, const uint y_segments,
+ const short oflag, const int cd_loop_uv_offset)
{
BMFace *f;
BMLoop *l;
@@ -308,8 +841,6 @@ void BM_mesh_calc_uvs_grid(BMesh *bm, const unsigned int x_segments, const unsig
float x = 0.0f;
float y = 0.0f;
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
int loop_index;
BLI_assert(cd_loop_uv_offset != -1);
@@ -355,7 +886,9 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op)
const float dia = BMO_slot_float_get(op->slots_in, "diameter");
const int seg = BMO_slot_int_get(op->slots_in, "u_segments");
const int tot = BMO_slot_int_get(op->slots_in, "v_segments");
- const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs");
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs");
BMOperator bmop, prevop;
BMVert *eve, *preveve;
@@ -453,7 +986,7 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op)
}
}
- BM_mesh_calc_uvs_sphere(bm, FACE_MARK);
+ BM_mesh_calc_uvs_sphere(bm, FACE_MARK, cd_loop_uv_offset);
}
/* and now do imat */
@@ -471,7 +1004,9 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op)
const float dia = BMO_slot_float_get(op->slots_in, "diameter");
const float dia_div = dia / 200.0f;
const int subdiv = BMO_slot_int_get(op->slots_in, "subdivisions");
- const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs");
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs");
BMVert *eva[12];
BMVert *v;
@@ -496,21 +1031,32 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op)
BMO_vert_flag_enable(bm, eva[a], VERT_MARK);
}
+ int uvi = 0;
for (a = 0; a < 20; a++) {
- BMFace *eftemp;
+ BMFace *f;
BMVert *v1, *v2, *v3;
v1 = eva[icoface[a][0]];
v2 = eva[icoface[a][1]];
v3 = eva[icoface[a][2]];
- eftemp = BM_face_create_quad_tri(bm, v1, v2, v3, NULL, NULL, BM_CREATE_NOP);
+ f = BM_face_create_quad_tri(bm, v1, v2, v3, NULL, NULL, BM_CREATE_NOP);
- BM_ITER_ELEM (l, &liter, eftemp, BM_LOOPS_OF_FACE) {
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
BMO_edge_flag_enable(bm, l->e, EDGE_MARK);
}
- BMO_face_flag_enable(bm, eftemp, FACE_MARK);
+ /* Set the UVs here, the iteration order of the faces is not guaranteed,
+ * so it's best to set the UVs right after the face is created. */
+ if (calc_uvs) {
+ int loop_index;
+ BM_ITER_ELEM_INDEX (l, &liter, f, BM_LOOPS_OF_FACE, loop_index) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->uv[0] = icouvs[uvi][0];
+ luv->uv[1] = icouvs[uvi][1];
+ uvi++;
+ }
+ }
}
if (subdiv > 1) {
@@ -530,29 +1076,7 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op)
BMO_op_finish(bm, &bmop);
}
- if (calc_uvs) {
- BMFace *f;
- BMIter fiter;
-
- /* We cannot tag faces for UVs computing above, so we have to do it now, based on all its vertices
- * being tagged. */
- BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- bool valid = true;
- BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- if (!BMO_vert_flag_test(bm, l->v, VERT_MARK)) {
- valid = false;
- break;
- }
- }
-
- if (valid) {
- BMO_face_flag_enable(bm, f, FACE_MARK);
- }
- }
-
- BM_mesh_calc_uvs_sphere(bm, FACE_MARK);
- }
/* must transform after because of sphere subdivision */
BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
@@ -564,7 +1088,7 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op)
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
}
-static void bm_mesh_calc_uvs_sphere_face(BMFace *f, float mat_rot[3][3], const int cd_loop_uv_offset)
+static void bm_mesh_calc_uvs_sphere_face(BMFace *f, const int cd_loop_uv_offset)
{
float *uvs[4];
BMLoop *l;
@@ -574,12 +1098,42 @@ static void bm_mesh_calc_uvs_sphere_face(BMFace *f, float mat_rot[3][3], const i
BLI_assert(f->len <= 4);
+ /* If face has 3 vertices, it's a polar face, in which case we need to
+ * compute a nearbye to determine its latitude. */
+ float avgx = 0.0f, avgy = 0.0f;
+ BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, loop_index) {
+ if (f->len == 3) {
+ avgx += l->v->co[0];
+ avgy += l->v->co[1];
+ }
+ }
+ avgx /= 3.0f;
+ avgy /= 3.0f;
+
BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, loop_index) {
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- float vco[3];
+ float x = l->v->co[0];
+ float y = l->v->co[1];
+ float z = l->v->co[2];
+ float len = len_v3(l->v->co);
+
+ /* Use neigboring point to compute angle for poles. */
+ float theta;
+ if (f->len == 3 && fabsf(x) < 0.0001f && fabsf(y) < 0.0001f) {
+ theta = atan2f(avgy, avgx);
+ }
+ else {
+ theta = atan2f(y, x);
+ }
- mul_v3_m3v3(vco, mat_rot, l->v->co);
- map_to_sphere(&luv->uv[0], &luv->uv[1], vco[0], vco[1], vco[2]);
+ /* Shift borderline coordinates to the left. */
+ if (fabsf(theta - (float)M_PI) < 0.0001f) {
+ theta = -M_PI;
+ }
+
+ float phi = saacos(z / len);
+ luv->uv[0] = 0.5f + theta / ((float)M_PI * 2);
+ luv->uv[1] = 1.0f - phi / (float)M_PI;
uvs[loop_index] = luv->uv;
}
@@ -608,28 +1162,45 @@ static void bm_mesh_calc_uvs_sphere_face(BMFace *f, float mat_rot[3][3], const i
* \param bm The BMesh to operate on
* \param oflag The flag to check faces with.
*/
-void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag)
+void BM_mesh_calc_uvs_sphere(
+ BMesh *bm,
+ const short oflag, const int cd_loop_uv_offset)
{
BMFace *f;
BMIter iter;
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ BLI_assert(cd_loop_uv_offset != -1); /* caller is responsible for giving us UVs */
- /* We apply a 'magic' rotationto vcos before mapping them to sphere,
- * those values seem to give best results for both ico and uv sphere projections. */
- float mat_rot[3][3];
- const float axis[3] = {0.806f, 0.329f, 0.491f};
- const float angle = DEG2RADF(120.0f);
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (!BMO_face_flag_test(bm, f, oflag))
+ continue;
- axis_angle_to_mat3(mat_rot, axis, angle);
+ bm_mesh_calc_uvs_sphere_face(f, cd_loop_uv_offset);
+ }
- BLI_assert(cd_loop_uv_offset != -1); /* caller is responsible for giving us UVs */
+ BMIter iter2;
+ BMLoop *l;
+ int loop_index;
+ float minx = 1.0f;
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
if (!BMO_face_flag_test(bm, f, oflag))
continue;
+ BM_ITER_ELEM_INDEX (l, &iter2, f, BM_LOOPS_OF_FACE, loop_index) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (luv->uv[0] < minx) {
+ minx = luv->uv[0];
+ }
+ }
+ }
- bm_mesh_calc_uvs_sphere_face(f, mat_rot, cd_loop_uv_offset);
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (!BMO_face_flag_test(bm, f, oflag))
+ continue;
+ BM_ITER_ELEM_INDEX (l, &iter2, f, BM_LOOPS_OF_FACE, loop_index) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->uv[0] -= minx;
+ }
}
}
@@ -641,6 +1212,9 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op)
BMO_slot_mat4_get(op->slots_in, "matrix", mat);
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs");
+
for (i = 0; i < monkeynv; i++) {
float v[3];
@@ -666,20 +1240,41 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op)
mul_m4_v3(mat, tv[i]->co);
}
+ int uvi = 0;
for (i = 0; i < monkeynf; i++) {
- BM_face_create_quad_tri(bm,
+ BMFace *f_new_a = BM_face_create_quad_tri(bm,
tv[monkeyf[i][0] + i - monkeyo],
tv[monkeyf[i][1] + i - monkeyo],
tv[monkeyf[i][2] + i - monkeyo],
(monkeyf[i][3] != monkeyf[i][2]) ? tv[monkeyf[i][3] + i - monkeyo] : NULL,
NULL, BM_CREATE_NOP);
- BM_face_create_quad_tri(bm,
+ BMFace *f_new_b = BM_face_create_quad_tri(bm,
tv[monkeynv + monkeyf[i][2] + i - monkeyo],
tv[monkeynv + monkeyf[i][1] + i - monkeyo],
tv[monkeynv + monkeyf[i][0] + i - monkeyo],
(monkeyf[i][3] != monkeyf[i][2]) ? tv[monkeynv + monkeyf[i][3] + i - monkeyo] : NULL,
NULL, BM_CREATE_NOP);
+
+ /* Set the UVs here, the iteration order of the faces is not guaranteed,
+ * so it's best to set the UVs right after the face is created. */
+ if (calc_uvs) {
+ BMLoop *l;
+ BMIter liter;
+ BM_ITER_ELEM (l, &liter, f_new_a, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->uv[0] = monkeyuvs[uvi * 2 + 0];
+ luv->uv[1] = monkeyuvs[uvi * 2 + 1];
+ uvi++;
+ }
+ BM_ITER_ELEM (l, &liter, f_new_b, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->uv[0] = monkeyuvs[uvi * 2 + 0];
+ luv->uv[1] = monkeyuvs[uvi * 2 + 1];
+ uvi++;
+ }
+
+ }
}
MEM_freeN(tv);
@@ -694,7 +1289,9 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
const int segs = BMO_slot_int_get(op->slots_in, "segments");
const bool cap_ends = BMO_slot_bool_get(op->slots_in, "cap_ends");
const bool cap_tris = BMO_slot_bool_get(op->slots_in, "cap_tris");
- const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs");
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs");
BMVert *v1, *lastv1 = NULL, *cent1, *firstv1 = NULL;
float vec[3], mat[4][4], phi, phid;
@@ -754,7 +1351,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
BMO_face_flag_enable(bm, f, FACE_NEW);
if (calc_uvs) {
- BM_mesh_calc_uvs_circle(bm, mat, dia, FACE_NEW);
+ BM_mesh_calc_uvs_circle(bm, mat, dia, FACE_NEW, cd_loop_uv_offset);
}
}
@@ -773,14 +1370,14 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
* \param radius The size of the circle.
* \param oflag The flag to check faces with.
*/
-void BM_mesh_calc_uvs_circle(BMesh *bm, float mat[4][4], const float radius, const short oflag)
+void BM_mesh_calc_uvs_circle(
+ BMesh *bm, float mat[4][4], const float radius,
+ const short oflag, const int cd_loop_uv_offset)
{
BMFace *f;
BMLoop *l;
BMIter fiter, liter;
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
const float uv_scale = 0.5f / radius;
const float uv_center = 0.5f;
@@ -820,7 +1417,9 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
int segs = BMO_slot_int_get(op->slots_in, "segments");
const bool cap_ends = BMO_slot_bool_get(op->slots_in, "cap_ends");
const bool cap_tris = BMO_slot_bool_get(op->slots_in, "cap_tris");
- const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs");
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs");
int a;
if (!segs)
@@ -917,7 +1516,7 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
}
if (calc_uvs) {
- BM_mesh_calc_uvs_cone(bm, mat, dia2, dia1, segs, cap_ends, FACE_MARK);
+ BM_mesh_calc_uvs_cone(bm, mat, dia2, dia1, segs, cap_ends, FACE_MARK, cd_loop_uv_offset);
}
if (!cap_tris) {
@@ -941,12 +1540,12 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
*/
void BM_mesh_calc_uvs_cone(
BMesh *bm, float mat[4][4],
- const float radius_top, const float radius_bottom, const int segments, const bool cap_ends, const short oflag)
+ const float radius_top, const float radius_bottom, const int segments, const bool cap_ends,
+ const short oflag, const int cd_loop_uv_offset)
{
BMFace *f;
BMLoop *l;
BMIter fiter, liter;
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
const float uv_width = 1.0f / (float)segments;
const float uv_height = cap_ends ? 0.5f : 1.0f;
@@ -977,7 +1576,7 @@ void BM_mesh_calc_uvs_cone(
BLI_assert(cd_loop_uv_offset != -1); /* caller is responsible for ensuring the mesh has UVs */
- x = 0.0f;
+ x = 1.0f;
y = 1.0f - uv_height;
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
@@ -991,7 +1590,7 @@ void BM_mesh_calc_uvs_cone(
switch (loop_index) {
case 0:
- x += uv_width;
+ /* Continue in the last position */
break;
case 1:
y += uv_height;
@@ -1009,8 +1608,6 @@ void BM_mesh_calc_uvs_cone(
luv->uv[0] = x;
luv->uv[1] = y;
}
-
- x += uv_width;
}
else {
/* top or bottom face - so unwrap it by transforming back to a circle and using the X/Y coords */
@@ -1040,8 +1637,10 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op)
BMVert *verts[8];
float mat[4][4];
float off = BMO_slot_float_get(op->slots_in, "size") / 2.0f;
- const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs");
- int i, x, y, z;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs");
+
/* rotation order set to match 'BM_mesh_calc_uvs_cube' */
const char faces[6][4] = {
{0, 1, 3, 2},
@@ -1055,11 +1654,11 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op)
BMO_slot_mat4_get(op->slots_in, "matrix", mat);
if (!off) off = 0.5f;
- i = 0;
+ int i = 0;
- for (x = -1; x < 2; x += 2) {
- for (y = -1; y < 2; y += 2) {
- for (z = -1; z < 2; z += 2) {
+ for (int x = -1; x < 2; x += 2) {
+ for (int y = -1; y < 2; y += 2) {
+ for (int z = -1; z < 2; z += 2) {
float vec[3] = {(float)x * off, (float)y * off, (float)z * off};
mul_m4_v3(mat, vec);
verts[i] = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c
index 6da591b23a0..7d19d90807a 100644
--- a/source/blender/bmesh/operators/bmo_removedoubles.c
+++ b/source/blender/bmesh/operators/bmo_removedoubles.c
@@ -153,19 +153,19 @@ static BMFace *remdoubles_createface(BMesh *bm, BMFace *f, BMOpSlot *slot_target
finally:
{
- unsigned int i;
+ uint i;
for (i = 0; i < STACK_SIZE(verts); i++) {
BMO_vert_flag_disable(bm, verts[i], VERT_IN_FACE);
}
}
if (STACK_SIZE(edges) >= 3) {
- if (!BM_face_exists(verts, STACK_SIZE(edges), NULL)) {
+ if (!BM_face_exists(verts, STACK_SIZE(edges))) {
BMFace *f_new = BM_face_create(bm, verts, edges, STACK_SIZE(edges), f, BM_CREATE_NOP);
BLI_assert(f_new != f);
if (f_new) {
- unsigned int i = 0;
+ uint i = 0;
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
do {
@@ -440,20 +440,24 @@ void bmo_collapse_exec(BMesh *bm, BMOperator *op)
edge_stack = BLI_stack_new(sizeof(BMEdge *), __func__);
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- float min[3], max[3], center[3];
+ float center[3];
+ int count = 0;
BMVert *v_tar;
+ zero_v3(center);
+
if (!BMO_edge_flag_test(bm, e, EDGE_MARK))
continue;
BLI_assert(BLI_stack_is_empty(edge_stack));
- INIT_MINMAX(min, max);
for (e = BMW_begin(&walker, e->v1); e; e = BMW_step(&walker)) {
BLI_stack_push(edge_stack, &e);
- minmax_v3v3_v3(min, max, e->v1->co);
- minmax_v3v3_v3(min, max, e->v2->co);
+ add_v3_v3(center, e->v1->co);
+ add_v3_v3(center, e->v2->co);
+
+ count += 2;
/* prevent adding to slot_targetmap multiple times */
BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
@@ -461,15 +465,14 @@ void bmo_collapse_exec(BMesh *bm, BMOperator *op)
}
if (!BLI_stack_is_empty(edge_stack)) {
-
- mid_v3_v3v3(center, min, max);
+ mul_v3_fl(center, 1.0f / count);
/* snap edges to a point. for initial testing purposes anyway */
e = *(BMEdge **)BLI_stack_peek(edge_stack);
v_tar = e->v1;
while (!BLI_stack_is_empty(edge_stack)) {
- unsigned int j;
+ uint j;
BLI_stack_pop(edge_stack, &e);
for (j = 0; j < 2; j++) {
diff --git a/source/blender/bmesh/operators/bmo_similar.c b/source/blender/bmesh/operators/bmo_similar.c
index 454d6d8c6c8..0cd17258834 100644
--- a/source/blender/bmesh/operators/bmo_similar.c
+++ b/source/blender/bmesh/operators/bmo_similar.c
@@ -106,11 +106,28 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
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");
+ /* for comparison types that use custom-data */
+ int cd_offset = -1;
/* initial_elem - other_elem */
float delta_fl;
int delta_i;
+ if (type == SIMFACE_FACEMAP) {
+ cd_offset = CustomData_get_offset(&bm->pdata, CD_FACEMAP);
+ if (cd_offset == -1) {
+ return;
+ }
+ }
+#ifdef WITH_FREESTYLE
+ else if (type == SIMFACE_FREESTYLE) {
+ cd_offset = CustomData_get_offset(&bm->pdata, CD_FREESTYLE_FACE);
+ if (cd_offset == -1) {
+ return;
+ }
+ }
+#endif
+
num_total = BM_mesh_elem_count(bm, BM_FACE);
/*
@@ -145,7 +162,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
* 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) {
+ if (type == SIMFACE_PERIMETER || type == SIMFACE_AREA || type == SIMFACE_COPLANAR) {
for (i = 0; i < num_total; i++) {
switch (type) {
case SIMFACE_PERIMETER:
@@ -164,14 +181,6 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
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;
}
}
}
@@ -190,14 +199,6 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
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) {
@@ -254,20 +255,29 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
cont = false;
}
break;
+ case SIMFACE_FACEMAP:
+ {
+ BLI_assert(cd_offset != -1);
+ const int *fmap1 = BM_ELEM_CD_GET_VOID_P(fs, cd_offset);
+ const int *fmap2 = BM_ELEM_CD_GET_VOID_P(fm, cd_offset);
+ if (*fmap1 == *fmap2) {
+ 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;
- }
+ {
+ BLI_assert(cd_offset != -1);
+ const FreestyleEdge *ffa1 = BM_ELEM_CD_GET_VOID_P(fs, cd_offset);
+ const FreestyleEdge *ffa2 = BM_ELEM_CD_GET_VOID_P(fm, cd_offset);
+ if ((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);
diff --git a/source/blender/bmesh/operators/bmo_smooth_laplacian.c b/source/blender/bmesh/operators/bmo_smooth_laplacian.c
index 1a83bafc074..2a7b85ac8fd 100644
--- a/source/blender/bmesh/operators/bmo_smooth_laplacian.c
+++ b/source/blender/bmesh/operators/bmo_smooth_laplacian.c
@@ -172,7 +172,7 @@ static void init_laplacian_matrix(LaplacianSystem *sys)
float w1, w2, w3, w4;
int i, j;
bool has_4_vert;
- unsigned int idv1, idv2, idv3, idv4, idv[4];
+ uint idv1, idv2, idv3, idv4, idv[4];
BMEdge *e;
BMFace *f;
BMIter eiter;
@@ -289,7 +289,7 @@ static void fill_laplacian_matrix(LaplacianSystem *sys)
float w2, w3, w4;
int i, j;
bool has_4_vert;
- unsigned int idv1, idv2, idv3, idv4, idv[4];
+ uint idv1, idv2, idv3, idv4, idv[4];
BMEdge *e;
BMFace *f;
@@ -420,7 +420,7 @@ static void validate_solution(LaplacianSystem *sys, int usex, int usey, int usez
float leni, lene;
float vini, vend;
float *vi1, *vi2, ve1[3], ve2[3];
- unsigned int idv1, idv2;
+ uint idv1, idv2;
BMOIter siter;
BMVert *v;
BMEdge *e;
diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
index ce031e1c230..94b60a51f68 100644
--- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c
+++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
@@ -66,7 +66,7 @@
/* Specialized Utility Funcs */
#ifndef NDEBUG
-static unsigned int bm_verts_tag_count(BMesh *bm)
+static uint bm_verts_tag_count(BMesh *bm)
{
int count = 0;
BMIter iter;
@@ -390,9 +390,9 @@ static void bm_vert_calc_surface_tangent(BMesh *bm, BMVert *v, float r_no[3])
* Tag faces connected to an edge loop as FACE_SHARED
* if all vertices are VERT_SHARED.
*/
-static void bm_faces_share_tag_flush(BMesh *bm, BMEdge **e_arr, const unsigned int e_arr_len)
+static void bm_faces_share_tag_flush(BMesh *bm, BMEdge **e_arr, const uint e_arr_len)
{
- unsigned int i;
+ uint i;
for (i = 0; i < e_arr_len; i++) {
BMEdge *e = e_arr[i];
@@ -412,9 +412,9 @@ static void bm_faces_share_tag_flush(BMesh *bm, BMEdge **e_arr, const unsigned i
/**
* Un-Tag faces connected to an edge loop, clearing FACE_SHARED
*/
-static void bm_faces_share_tag_clear(BMesh *bm, BMEdge **e_arr_iter, const unsigned int e_arr_len_iter)
+static void bm_faces_share_tag_clear(BMesh *bm, BMEdge **e_arr_iter, const uint e_arr_len_iter)
{
- unsigned int i;
+ uint i;
for (i = 0; i < e_arr_len_iter; i++) {
BMEdge *e = e_arr_iter[i];
@@ -454,16 +454,16 @@ static LoopPairStore *bm_edgering_pair_store_create(
LoopPairStore *lpair = MEM_mallocN(sizeof(*lpair), __func__);
if (interp_mode == SUBD_RING_INTERP_SURF) {
- const unsigned int len_a = BM_edgeloop_length_get(el_store_a);
- const unsigned int len_b = BM_edgeloop_length_get(el_store_b);
- const unsigned int e_arr_a_len = len_a - (BM_edgeloop_is_closed(el_store_a) ? 0 : 1);
- const unsigned int e_arr_b_len = len_b - (BM_edgeloop_is_closed(el_store_b) ? 0 : 1);
+ const uint len_a = BM_edgeloop_length_get(el_store_a);
+ const uint len_b = BM_edgeloop_length_get(el_store_b);
+ const uint e_arr_a_len = len_a - (BM_edgeloop_is_closed(el_store_a) ? 0 : 1);
+ const uint e_arr_b_len = len_b - (BM_edgeloop_is_closed(el_store_b) ? 0 : 1);
BMEdge **e_arr_a = BLI_array_alloca(e_arr_a, e_arr_a_len);
BMEdge **e_arr_b = BLI_array_alloca(e_arr_b, e_arr_b_len);
- unsigned int i;
+ uint i;
struct BMEdgeLoopStore *el_store_pair[2] = {el_store_a, el_store_b};
- unsigned int side_index;
+ uint side_index;
float (*nors_pair[2])[3];
GHash *nors_gh_pair[2];
@@ -768,8 +768,8 @@ static void bm_edgering_pair_interpolate(
bm_vert_calc_surface_tangent(bm, v_b, no_b);
#else
{
- const unsigned int index_a = GET_UINT_FROM_POINTER(BLI_ghash_lookup(lpair->nors_gh_a, v_a));
- const unsigned int index_b = GET_UINT_FROM_POINTER(BLI_ghash_lookup(lpair->nors_gh_b, v_b));
+ const uint index_a = GET_UINT_FROM_POINTER(BLI_ghash_lookup(lpair->nors_gh_a, v_a));
+ const uint index_b = GET_UINT_FROM_POINTER(BLI_ghash_lookup(lpair->nors_gh_b, v_b));
BLI_assert(BLI_ghash_haskey(lpair->nors_gh_a, v_a));
BLI_assert(BLI_ghash_haskey(lpair->nors_gh_b, v_b));
diff --git a/source/blender/bmesh/operators/bmo_triangulate.c b/source/blender/bmesh/operators/bmo_triangulate.c
index 8938d086c1a..4e8bace59e0 100644
--- a/source/blender/bmesh/operators/bmo_triangulate.c
+++ b/source/blender/bmesh/operators/bmo_triangulate.c
@@ -77,7 +77,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
GHash *sf_vert_map;
float normal[3];
const int scanfill_flag = BLI_SCANFILL_CALC_HOLES | BLI_SCANFILL_CALC_POLYS | BLI_SCANFILL_CALC_LOOSE;
- unsigned int nors_tot;
+ uint nors_tot;
bool calc_winding = false;
sf_vert_map = BLI_ghash_ptr_new_ex(__func__, BMO_slot_buffer_count(op->slots_in, "edges"));
@@ -89,7 +89,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) {
ScanFillVert *sf_verts[2];
BMVert **e_verts = &e->v1;
- unsigned int i;
+ uint i;
BMO_edge_flag_enable(bm, e, EDGE_MARK);
@@ -115,7 +115,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
* Since we don't know winding, just accumulate */
ScanFillVert *sf_vert;
struct SortNormal *nors;
- unsigned int i;
+ uint i;
bool is_degenerate = true;
nors = MEM_mallocN(sizeof(*nors) * nors_tot, __func__);
@@ -124,7 +124,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
BMVert *v = sf_vert->tmp.p;
BMIter eiter;
BMEdge *e_pair[2];
- unsigned int e_index = 0;
+ uint e_index = 0;
nors[i].value = -1.0f;
@@ -199,7 +199,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
int winding_votes = 0;
for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) {
BMVert *v_tri[3] = {sf_tri->v1->tmp.p, sf_tri->v2->tmp.p, sf_tri->v3->tmp.p};
- unsigned int i, i_prev;
+ uint i, i_prev;
for (i = 0, i_prev = 2; i < 3; i_prev = i++) {
e = BM_edge_exists(v_tri[i], v_tri[i_prev]);
@@ -253,10 +253,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
if (BMO_edge_flag_test(bm, e, ELE_NEW)) {
/* in rare cases the edges face will have already been removed from the edge */
if (LIKELY(e->l)) {
- BMFace *f_new = BM_faces_join_pair(
- bm, e->l->f,
- e->l->radial_next->f, e,
- false); /* join faces */
+ BMFace *f_new = BM_faces_join_pair(bm, e->l, e->l->radial_next, false);
if (f_new) {
BMO_face_flag_enable(bm, f_new, ELE_NEW);
BM_edge_kill(bm, e);
diff --git a/source/blender/bmesh/tools/bmesh_beautify.c b/source/blender/bmesh/tools/bmesh_beautify.c
index 3e3a6547b75..f08f21a2c88 100644
--- a/source/blender/bmesh/tools/bmesh_beautify.c
+++ b/source/blender/bmesh/tools/bmesh_beautify.c
@@ -62,7 +62,7 @@ typedef struct EdRotState {
#if 0
/* use BLI_ghashutil_inthash_v4 direct */
-static unsigned int erot_gsetutil_hash(const void *ptr)
+static uint erot_gsetutil_hash(const void *ptr)
{
const EdRotState *e_state = (const EdRotState *)ptr;
return BLI_ghashutil_inthash_v4(&e_state->v1);
@@ -368,7 +368,7 @@ void BM_mesh_beautify_fill(
TIMEIT_START(beautify_fill);
#endif
- eheap = BLI_heap_new_ex((unsigned int)edge_array_len);
+ eheap = BLI_heap_new_ex((uint)edge_array_len);
eheap_table = MEM_mallocN(sizeof(HeapNode *) * (size_t)edge_array_len, __func__);
/* build heap */
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index b647f5a667d..6673c5d25cf 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -57,6 +57,7 @@
#define BEVEL_EPSILON_ANG DEG2RADF(2.0f)
#define BEVEL_SMALL_ANG DEG2RADF(10.0f)
#define BEVEL_MAX_ADJUST_PCT 10.0f
+#define BEVEL_MAX_AUTO_ADJUST_PCT 300.0f
/* happens far too often, uncomment for development */
// #define BEVEL_ASSERT_PROJECT
@@ -204,6 +205,38 @@ static int bev_debug_flags = 0;
#define DEBUG_OLD_PROJ_TO_PERP_PLANE (bev_debug_flags & 2)
#define DEBUG_OLD_FLAT_MID (bev_debug_flags & 4)
+/* this flag values will get set on geom we want to return in 'out' slots for edges and verts */
+#define EDGE_OUT 4
+#define VERT_OUT 8
+
+/* If we're called from the modifier, tool flags aren't available, but don't need output geometry */
+static void flag_out_edge(BMesh *bm, BMEdge *bme)
+{
+ if (bm->use_toolflags)
+ BMO_edge_flag_enable(bm, bme, EDGE_OUT);
+}
+
+static void flag_out_vert(BMesh *bm, BMVert *bmv)
+{
+ if (bm->use_toolflags)
+ BMO_vert_flag_enable(bm, bmv, VERT_OUT);
+}
+
+static void disable_flag_out_edge(BMesh *bm, BMEdge *bme)
+{
+ if (bm->use_toolflags)
+ BMO_edge_flag_disable(bm, bme, EDGE_OUT);
+}
+
+/* Are d1 and d2 parallel or nearly so? */
+static bool nearly_parallel(const float d1[3], const float d2[3])
+{
+ float ang;
+
+ ang = angle_v3v3(d1, d2);
+ return (fabsf(ang) < BEVEL_EPSILON_ANG) || (fabsf(ang - M_PI) < BEVEL_EPSILON_ANG);
+}
+
/* Make a new BoundVert of the given kind, insert it at the end of the circular linked
* list with entry point bv->boundstart, and return it. */
static BoundVert *add_new_bound_vert(MemArena *mem_arena, VMesh *vm, const float co[3])
@@ -252,6 +285,7 @@ static void create_mesh_bmvert(BMesh *bm, VMesh *vm, int i, int j, int k, BMVert
NewVert *nv = mesh_vert(vm, i, j, k);
nv->v = BM_vert_create(bm, nv->co, eg, BM_CREATE_NOP);
BM_elem_flag_disable(nv->v, BM_ELEM_TAG);
+ flag_out_vert(bm, nv->v);
}
static void copy_mesh_vert(
@@ -323,15 +357,33 @@ static bool edge_half_offset_changed(EdgeHalf *e)
e->offset_r != e->offset_r_spec;
}
-static bool any_edge_half_offset_changed(BevVert *bv)
+static float adjusted_rel_change(float val, float spec)
+{
+ float relchg;
+
+ relchg = 0.0f;
+ if (val != spec) {
+ if (spec == 0)
+ relchg = 1000.0f; /* arbitrary large value */
+ else
+ relchg = fabsf((val - spec) / spec);
+ }
+ return relchg;
+}
+
+static float max_edge_half_offset_rel_change(BevVert *bv)
{
int i;
+ float max_rel_change;
+ EdgeHalf *e;
+ max_rel_change = 0.0f;
for (i = 0; i < bv->edgecount; i++) {
- if (edge_half_offset_changed(&bv->edges[i]))
- return true;
+ e = &bv->edges[i];
+ max_rel_change = max_ff(max_rel_change, adjusted_rel_change(e->offset_l, e->offset_l_spec));
+ max_rel_change = max_ff(max_rel_change, adjusted_rel_change(e->offset_r, e->offset_r_spec));
}
- return false;
+ return max_rel_change;
}
/* Return the next EdgeHalf after from_e that is beveled.
@@ -476,9 +528,12 @@ static BMFace *bev_create_ngon(
}
/* not essential for bevels own internal logic,
- * this is done so the operator can select newly created faces */
+ * this is done so the operator can select newly created geometry */
if (f) {
BM_elem_flag_enable(f, BM_ELEM_TAG);
+ BM_ITER_ELEM(bme, &iter, f, BM_EDGES_OF_FACE) {
+ flag_out_edge(bm, bme);
+ }
}
if (mat_nr >= 0)
@@ -897,8 +952,12 @@ static bool offset_meet_edge(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, float meetc
return false;
}
cross_v3_v3v3(fno, dir1, dir2);
- if (dot_v3v3(fno, v->no) < 0.0f)
+ if (dot_v3v3(fno, v->no) < 0.0f) {
ang = 2.0f * (float)M_PI - ang; /* angle is reflex */
+ if (r_angle)
+ *r_angle = ang;
+ return false;
+ }
if (r_angle)
*r_angle = ang;
@@ -1036,7 +1095,7 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv)
{
EdgeHalf *e;
Profile *pro;
- float co1[3], co2[3], co3[3], d1[3], d2[3], l;
+ float co1[3], co2[3], co3[3], d1[3], d2[3];
bool do_linear_interp;
copy_v3_v3(co1, bndv->nv.co);
@@ -1074,8 +1133,8 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv)
normalize_v3(d1);
normalize_v3(d2);
cross_v3_v3v3(pro->plane_no, d1, d2);
- l = normalize_v3(pro->plane_no);
- if (l <= BEVEL_EPSILON_BIG) {
+ normalize_v3(pro->plane_no);
+ if (nearly_parallel(d1, d2)) {
/* co1 - midco -co2 are collinear.
* Should be case that beveled edge is coplanar with two boundary verts.
* We want to move the profile to that common plane, if possible.
@@ -1107,17 +1166,24 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv)
sub_v3_v3v3(d4, e->next->e->v1->co, e->next->e->v2->co);
normalize_v3(d3);
normalize_v3(d4);
- add_v3_v3v3(co3, co1, d3);
- add_v3_v3v3(co4, co2, d4);
- isect_kind = isect_line_line_v3(co1, co3, co2, co4, meetco, isect2);
- if (isect_kind != 0) {
- copy_v3_v3(pro->midco, meetco);
- }
- else {
+ if (nearly_parallel(d3, d4)) {
/* offset lines are collinear - want linear interpolation */
mid_v3_v3v3(pro->midco, co1, co2);
do_linear_interp = true;
}
+ else {
+ add_v3_v3v3(co3, co1, d3);
+ add_v3_v3v3(co4, co2, d4);
+ isect_kind = isect_line_line_v3(co1, co3, co2, co4, meetco, isect2);
+ if (isect_kind != 0) {
+ copy_v3_v3(pro->midco, meetco);
+ }
+ else {
+ /* offset lines don't intersect - want linear interpolation */
+ mid_v3_v3v3(pro->midco, co1, co2);
+ do_linear_interp = true;
+ }
+ }
}
}
copy_v3_v3(pro->cob, co2);
@@ -1126,8 +1192,8 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv)
sub_v3_v3v3(d2, pro->midco, co2);
normalize_v3(d2);
cross_v3_v3v3(pro->plane_no, d1, d2);
- l = normalize_v3(pro->plane_no);
- if (l <= BEVEL_EPSILON_BIG) {
+ normalize_v3(pro->plane_no);
+ if (nearly_parallel(d1, d2)) {
/* whole profile is collinear with edge: just interpolate */
do_linear_interp = true;
}
@@ -1951,6 +2017,7 @@ static void adjust_offsets(BevelParams *bp)
GHashIterator giter;
EdgeHalf *e, *efirst, *eother;
GSQueue *q;
+ float max_rel_adj;
BLI_assert(!bp->vertex_only);
GHASH_ITER(giter, bp->vert_hash) {
@@ -1966,7 +2033,7 @@ static void adjust_offsets(BevelParams *bp)
searchi = -1;
GHASH_ITER(giter, bp->vert_hash) {
bv = BLI_ghashIterator_getValue(&giter);
- if (!bv->visited && any_edge_half_offset_changed(bv)) {
+ if (!bv->visited && max_edge_half_offset_rel_change(bv) > 0.0f) {
i = BM_elem_index_get(bv->v);
if (!searchbv || i < searchi) {
searchbv = bv;
@@ -1996,6 +2063,24 @@ static void adjust_offsets(BevelParams *bp)
}
}
BLI_gsqueue_free(q);
+
+ /* Should we auto-limit the error accumulation? Typically, spirals can lead to 100x relative adjustments,
+ * and somewhat hacky mechanism of using bp->limit_offset to indicate "clamp the adjustments" is not
+ * obvious to users, who almost certainaly want clamping in this situation.
+ * The reason not to clamp always is that some models work better without it (e.g., Bent_test in regression
+ * suite, where relative adjust maximum is about .6). */
+ if (!bp->limit_offset) {
+ max_rel_adj = 0.0f;
+ GHASH_ITER(giter, bp->vert_hash) {
+ bv = BLI_ghashIterator_getValue(&giter);
+ max_rel_adj = max_ff(max_rel_adj, max_edge_half_offset_rel_change(bv));
+ }
+ if (max_rel_adj > BEVEL_MAX_AUTO_ADJUST_PCT / 100.0f) {
+ bp->limit_offset = true;
+ adjust_offsets(bp);
+ bp->limit_offset = false;
+ }
+ }
}
/* Do the edges at bv form a "pipe"?
@@ -2194,10 +2279,13 @@ static void fill_vmesh_fracs(VMesh *vm, float *frac, int i)
total += len_v3v3(mesh_vert(vm, i, 0, k)->co, mesh_vert(vm, i, 0, k + 1)->co);
frac[k + 1] = total;
}
- if (total > BEVEL_EPSILON) {
+ if (total > 0.0f) {
for (k = 1; k <= ns; k++)
frac[k] /= total;
}
+ else {
+ frac[ns] = 1.0f;
+ }
}
/* Like fill_vmesh_fracs but want fractions for profile points of bndv, with ns segments */
@@ -2215,11 +2303,14 @@ static void fill_profile_fracs(BevelParams *bp, BoundVert *bndv, float *frac, in
frac[k + 1] = total;
copy_v3_v3(co, nextco);
}
- if (total > BEVEL_EPSILON) {
+ if (total > 0.0f) {
for (k = 1; k <= ns; k++) {
frac[k] /= total;
}
}
+ else {
+ frac[ns] = 1.0f;
+ }
}
/* Return i such that frac[i] <= f <= frac[i + 1], where frac[n] == 1.0
@@ -2251,7 +2342,7 @@ static int interp_range(const float *frac, int n, const float f, float *r_rest)
/* Interpolate given vmesh to make one with target nseg border vertices on the profiles */
static VMesh *interp_vmesh(BevelParams *bp, VMesh *vm0, int nseg)
{
- int n, ns0, nseg2, odd, i, j, k, j0, k0, k0prev;
+ int n, ns0, nseg2, odd, i, j, k, j0, k0, k0prev, j0inc, k0inc;
float *prev_frac, *frac, *new_frac, *prev_new_frac;
float f, restj, restk, restkprev;
float quad[4][3], co[3], center[3];
@@ -2295,10 +2386,12 @@ static VMesh *interp_vmesh(BevelParams *bp, VMesh *vm0, int nseg)
copy_v3_v3(co, mesh_vert_canon(vm0, i, j0, k0)->co);
}
else {
+ j0inc = (restj < BEVEL_EPSILON || j0 == ns0) ? 0 : 1;
+ k0inc = (restk < BEVEL_EPSILON || k0 == ns0) ? 0 : 1;
copy_v3_v3(quad[0], mesh_vert_canon(vm0, i, j0, k0)->co);
- copy_v3_v3(quad[1], mesh_vert_canon(vm0, i, j0, k0 + 1)->co);
- copy_v3_v3(quad[2], mesh_vert_canon(vm0, i, j0 + 1, k0 + 1)->co);
- copy_v3_v3(quad[3], mesh_vert_canon(vm0, i, j0 + 1, k0)->co);
+ copy_v3_v3(quad[1], mesh_vert_canon(vm0, i, j0, k0 + k0inc)->co);
+ copy_v3_v3(quad[2], mesh_vert_canon(vm0, i, j0 + j0inc, k0 + k0inc)->co);
+ copy_v3_v3(quad[3], mesh_vert_canon(vm0, i, j0 + j0inc, k0)->co);
interp_bilinear_quad_v3(quad, restk, restj, co);
}
copy_v3_v3(mesh_vert(vm1, i, j, k)->co, co);
@@ -3147,6 +3240,7 @@ static void bevel_build_trifan(BevelParams *bp, BMesh *bm, BevVert *bv)
BMFace *f_new;
BLI_assert(v_fan == l_fan->v);
f_new = BM_face_split(bm, f, l_fan, l_fan->next->next, &l_new, NULL, false);
+ flag_out_edge(bm, l_new->e);
if (f_new->len > f->len) {
f = f_new;
@@ -3193,6 +3287,7 @@ static void bevel_build_quadstrip(BevelParams *bp, BMesh *bm, BevVert *bv)
else {
BM_face_split(bm, f, l_a, l_b, &l_new, NULL, false);
f = l_new->f;
+ flag_out_edge(bm, l_new->e);
/* walk around the new face to get the next verts to split */
l_a = l_new->prev;
@@ -3212,7 +3307,7 @@ static void bevel_vert_two_edges(BevelParams *bp, BMesh *bm, BevVert *bv)
{
VMesh *vm = bv->vmesh;
BMVert *v1, *v2;
- BMEdge *e_eg;
+ BMEdge *e_eg, *bme;
Profile *pro;
float co[3];
BoundVert *bndv;
@@ -3254,7 +3349,9 @@ static void bevel_vert_two_edges(BevelParams *bp, BMesh *bm, BevVert *bv)
v1 = mesh_vert(vm, 0, 0, k)->v;
v2 = mesh_vert(vm, 0, 0, k + 1)->v;
BLI_assert(v1 != NULL && v2 != NULL);
- BM_edge_create(bm, v1, v2, e_eg, BM_CREATE_NO_DOUBLE);
+ bme = BM_edge_create(bm, v1, v2, e_eg, BM_CREATE_NO_DOUBLE);
+ if (bme)
+ flag_out_edge(bm, bme);
}
}
}
@@ -3551,7 +3648,7 @@ static void find_bevel_edge_order(BMesh *bm, BevVert *bv, BMEdge *first_bme)
{
BMEdge *bme, *bme2;
BMIter iter;
- BMFace *f;
+ BMFace *f, *bestf;
EdgeHalf *e;
EdgeHalf *e2;
BMLoop *l;
@@ -3563,7 +3660,7 @@ static void find_bevel_edge_order(BMesh *bm, BevVert *bv, BMEdge *first_bme)
BLI_assert(first_bme != NULL);
bv->edges[i].e = first_bme;
BM_BEVEL_EDGE_TAG_ENABLE(first_bme);
- if (fast_bevel_edge_order(bv))
+ if (i == 0 && fast_bevel_edge_order(bv))
break;
i = bevel_edge_order_extend(bm, bv, i);
i++;
@@ -3588,10 +3685,22 @@ static void find_bevel_edge_order(BMesh *bm, BevVert *bv, BMEdge *first_bme)
e2 = (i == bv->edgecount - 1) ? &bv->edges[0] : &bv->edges[i + 1];
bme = e->e;
bme2 = e2->e;
+ BLI_assert(bme != NULL);
+ if (e->fnext != NULL || e2->fprev != NULL)
+ continue;
+ /* Which faces have successive loops that are for bme and bme2?
+ * There could be more than one. E.g., in manifold ntot==2 case.
+ * Prefer one that has loop in same direction as e. */
+ bestf = NULL;
BM_ITER_ELEM(l, &iter, bme, BM_LOOPS_OF_EDGE) {
f = l->f;
- if ((l->prev->e == bme2 || l->next->e == bme2) && !e->fnext && !e2->fprev)
- e->fnext = e2->fprev = f;
+ if ((l->prev->e == bme2 || l->next->e == bme2)) {
+ if (!bestf || l->v == bv->v)
+ bestf = f;
+ }
+ if (bestf) {
+ e->fnext = e2->fprev = bestf;
+ }
}
}
}
@@ -3823,7 +3932,7 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
/* Face f has at least one beveled vertex. Rebuild f */
static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
{
- BMIter liter;
+ BMIter liter, eiter, fiter;
BMLoop *l, *lprev;
BevVert *bv;
BoundVert *v, *vstart, *vend;
@@ -3831,10 +3940,10 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
VMesh *vm;
int i, k, n;
bool do_rebuild = false;
- bool go_ccw, corner3special;
+ bool go_ccw, corner3special, keep;
BMVert *bmv;
BMEdge *bme, *bme_new, *bme_prev;
- BMFace *f_new;
+ BMFace *f_new, *f_other;
BMVert **vv = NULL;
BMVert **vv_fix = NULL;
BMEdge **ee = NULL;
@@ -3848,9 +3957,10 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
bv = find_bevvert(bp, l->v);
vm = bv->vmesh;
e = find_edge_half(bv, l->e);
+ BLI_assert(e != NULL);
bme = e->e;
eprev = find_edge_half(bv, lprev->e);
- BLI_assert(e != NULL && eprev != NULL);
+ BLI_assert(eprev != NULL);
/* which direction around our vertex do we travel to match orientation of f? */
if (e->prev == eprev) {
@@ -3971,9 +4081,21 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
}
}
- /* don't select newly created boundary faces... */
+ /* don't select newly or return created boundary faces... */
if (f_new) {
BM_elem_flag_disable(f_new, BM_ELEM_TAG);
+ /* Also don't want new edges that aren't part of a new bevel face */
+ BM_ITER_ELEM(bme, &eiter, f_new, BM_EDGES_OF_FACE) {
+ keep = false;
+ BM_ITER_ELEM(f_other, &fiter, bme, BM_FACES_OF_EDGE) {
+ if (BM_elem_flag_test(f_other, BM_ELEM_TAG)) {
+ keep = true;
+ break;
+ }
+ }
+ if (!keep)
+ disable_flag_out_edge(bm, bme);
+ }
}
}
@@ -4055,8 +4177,9 @@ static void bevel_reattach_wires(BMesh *bm, BevelParams *bp, BMVert *v)
}
}
} while ((bndv = bndv->next) != bv->vmesh->boundstart);
- if (vclosest)
+ if (vclosest) {
BM_edge_create(bm, vclosest, votherclosest, e, BM_CREATE_NO_DOUBLE);
+ }
}
}
@@ -4460,9 +4583,9 @@ static float bevel_limit_offset(BMesh *bm, BevelParams *bp)
/**
* - Currently only bevels BM_ELEM_TAG'd verts and edges.
*
- * - Newly created faces are BM_ELEM_TAG'd too,
- * the caller needs to ensure this is cleared before calling
- * if its going to use this face tag.
+ * - Newly created faces, edges, and verts are BM_ELEM_TAG'd too,
+ * the caller needs to ensure these are cleared before calling
+ * if its going to use this tag.
*
* - If limit_offset is set, adjusts offset down if necessary
* to avoid geometry collisions.
@@ -4554,6 +4677,20 @@ void BM_mesh_bevel(
}
}
+ /* When called from operator (as opposed to modifier), bm->use_toolflags
+ * will be set, and we to transfer the oflags to BM_ELEM_TAGs */
+ if (bm->use_toolflags) {
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BMO_vert_flag_test(bm, v, VERT_OUT))
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ }
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BMO_edge_flag_test(bm, e, EDGE_OUT)) {
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ }
+ }
+ }
+
/* primary free */
BLI_ghash_free(bp.vert_hash, NULL, NULL);
BLI_memarena_free(bp.mem_arena);
diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.c b/source/blender/bmesh/tools/bmesh_bisect_plane.c
index 51b92a3c45e..676a8de94c8 100644
--- a/source/blender/bmesh/tools/bmesh_bisect_plane.c
+++ b/source/blender/bmesh/tools/bmesh_bisect_plane.c
@@ -74,7 +74,7 @@ static short plane_point_test_v3(const float plane[4], const float co[3], const
#define BM_VERT_DIST(v) ((v)->no[0]) /* Distance from the plane. */
#define BM_VERT_SORTVAL(v) ((v)->no[1]) /* Temp value for sorting. */
#define BM_VERT_LOOPINDEX(v) /* The verts index within a face (temp var) */ \
- (*((unsigned int *)(&(v)->no[2])))
+ (*((uint *)(&(v)->no[2])))
/**
* Hide flag access
@@ -110,10 +110,10 @@ static int bm_vert_sortval_cb(const void *v_a_v, const void *v_b_v)
}
-static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], const short oflag_center)
+static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], const short oflag_center, const short oflag_new)
{
/* unlikely more than 2 verts are needed */
- const unsigned int f_len_orig = (unsigned int)f->len;
+ const uint f_len_orig = (uint)f->len;
BMVert **vert_split_arr = BLI_array_alloca(vert_split_arr, f_len_orig);
STACK_DECLARE(vert_split_arr);
BMLoop *l_iter, *l_first;
@@ -154,10 +154,11 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con
/* common case, just cut the face once */
BM_face_split(bm, f, l_a, l_b, &l_new, NULL, true);
if (l_new) {
- if (oflag_center) {
- BMO_edge_flag_enable(bm, l_new->e, oflag_center);
- BMO_face_flag_enable(bm, l_new->f, oflag_center);
- BMO_face_flag_enable(bm, f, oflag_center);
+ if (oflag_center | oflag_new) {
+ BMO_edge_flag_enable(bm, l_new->e, oflag_center | oflag_new);
+ }
+ if (oflag_new) {
+ BMO_face_flag_enable(bm, l_new->f, oflag_new);
}
}
}
@@ -170,7 +171,7 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con
STACK_DECLARE(face_split_arr);
float sort_dir[3];
- unsigned int i;
+ uint i;
/* ---- */
@@ -245,7 +246,7 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con
if (is_inside) {
BMLoop *l_a, *l_b;
bool found = false;
- unsigned int j;
+ uint j;
for (j = 0; j < STACK_SIZE(face_split_arr); j++) {
/* would be nice to avoid loop lookup here,
@@ -269,10 +270,11 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con
f_tmp = BM_face_split(bm, face_split_arr[j], l_a, l_b, &l_new, NULL, true);
if (l_new) {
- if (oflag_center) {
- BMO_edge_flag_enable(bm, l_new->e, oflag_center);
- BMO_face_flag_enable(bm, l_new->f, oflag_center);
- BMO_face_flag_enable(bm, face_split_arr[j], oflag_center);
+ if (oflag_center | oflag_new) {
+ BMO_edge_flag_enable(bm, l_new->e, oflag_center | oflag_new);
+ }
+ if (oflag_new) {
+ BMO_face_flag_enable(bm, l_new->f, oflag_new);
}
}
@@ -307,10 +309,10 @@ finally:
void BM_mesh_bisect_plane(
BMesh *bm, const float plane[4],
const bool use_snap_center, const bool use_tag,
- const short oflag_center, const float eps)
+ const short oflag_center, const short oflag_new, const float eps)
{
- unsigned int einput_len;
- unsigned int i;
+ uint einput_len;
+ uint i;
BMEdge **edges_arr = MEM_mallocN(sizeof(*edges_arr) * (size_t)bm->totedge, __func__);
BLI_LINKSTACK_DECLARE(face_stack, BMFace *);
@@ -343,7 +345,7 @@ void BM_mesh_bisect_plane(
}
else {
BMEdge *e;
- einput_len = (unsigned int)bm->totedge;
+ einput_len = (uint)bm->totedge;
BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
edge_is_cut_enable(e);
edges_arr[i] = e;
@@ -390,7 +392,7 @@ void BM_mesh_bisect_plane(
const float dist[2] = {BM_VERT_DIST(e->v1), BM_VERT_DIST(e->v2)};
if (side[0] && side[1] && (side[0] != side[1])) {
- const float e_fac = fabsf(dist[0]) / fabsf(dist[0] - dist[1]);
+ const float e_fac = dist[0] / (dist[0] - dist[1]);
BMVert *v_new;
if (e->l) {
@@ -404,10 +406,17 @@ void BM_mesh_bisect_plane(
} while ((l_iter = l_iter->radial_next) != l_first);
}
- v_new = BM_edge_split(bm, e, e->v1, NULL, e_fac);
+ {
+ BMEdge *e_new;
+ v_new = BM_edge_split(bm, e, e->v1, &e_new, e_fac);
+ if (oflag_new) {
+ BMO_edge_flag_enable(bm, e_new, oflag_new);
+ }
+ }
+
vert_is_center_enable(v_new);
- if (oflag_center) {
- BMO_vert_flag_enable(bm, v_new, oflag_center);
+ if (oflag_new | oflag_center) {
+ BMO_vert_flag_enable(bm, v_new, oflag_new | oflag_center);
}
BM_VERT_DIR(v_new) = 0;
@@ -416,7 +425,7 @@ void BM_mesh_bisect_plane(
else if (side[0] == 0 || side[1] == 0) {
/* check if either edge verts are aligned,
* if so - tag and push all faces that use it into the stack */
- unsigned int j;
+ uint j;
BM_ITER_ELEM_INDEX (v, &iter, e, BM_VERTS_OF_EDGE, j) {
if (side[j] == 0) {
if (vert_is_center_test(v) == 0) {
@@ -448,7 +457,7 @@ void BM_mesh_bisect_plane(
MEM_freeN(edges_arr);
while ((f = BLI_LINKSTACK_POP(face_stack))) {
- bm_face_bisect_verts(bm, f, plane, oflag_center);
+ bm_face_bisect_verts(bm, f, plane, oflag_center, oflag_new);
}
/* now we have all faces to split in the stack */
diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.h b/source/blender/bmesh/tools/bmesh_bisect_plane.h
index 7f3a97c4c79..fb99a1c8214 100644
--- a/source/blender/bmesh/tools/bmesh_bisect_plane.h
+++ b/source/blender/bmesh/tools/bmesh_bisect_plane.h
@@ -30,6 +30,6 @@
void BM_mesh_bisect_plane(
BMesh *bm, const float plane[4],
const bool use_snap_center, const bool use_tag,
- const short oflag_center, const float eps);
+ const short oflag_center, const short oflag_new, const float eps);
#endif /* __BMESH_BISECT_PLANE_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
index 52a0df5b9d1..c417131d588 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
@@ -180,7 +180,7 @@ static bool bm_edge_collapse_is_degenerate_flip(BMEdge *e, const float optimize_
{
BMIter liter;
BMLoop *l;
- unsigned int i;
+ uint i;
for (i = 0; i < 2; i++) {
/* loop over both verts */
@@ -367,7 +367,7 @@ static void bm_decim_build_edge_cost(
{
BMIter iter;
BMEdge *e;
- unsigned int i;
+ uint i;
BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
eheap_table[i] = NULL; /* keep sanity check happy */
@@ -418,19 +418,19 @@ static bool bm_edge_symmetry_check_cb(void *user_data, int index, const float UN
return false;
}
-static int *bm_edge_symmetry_map(BMesh *bm, unsigned int symmetry_axis, float limit)
+static int *bm_edge_symmetry_map(BMesh *bm, uint symmetry_axis, float limit)
{
struct KD_Symmetry_Data sym_data;
BMIter iter;
BMEdge *e, **etable;
- unsigned int i;
+ uint i;
int *edge_symmetry_map;
const float limit_sq = SQUARE(limit);
KDTree *tree;
tree = BLI_kdtree_new(bm->totedge);
- etable = MEM_mallocN(sizeof(BMEdge **) * bm->totedge, __func__);
+ etable = MEM_mallocN(sizeof(*etable) * bm->totedge, __func__);
edge_symmetry_map = MEM_mallocN(sizeof(*edge_symmetry_map) * bm->totedge, __func__);
BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
diff --git a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
index 978cceee37c..e2c36299ddf 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
@@ -322,9 +322,7 @@ void BM_mesh_decimate_dissolve_ex(
i = BM_elem_index_get(e);
if (BM_edge_is_manifold(e)) {
- f_new = BM_faces_join_pair(bm, e->l->f,
- e->l->radial_next->f, e,
- false); /* join faces */
+ f_new = BM_faces_join_pair(bm, e->l, e->l->radial_next, false);
if (f_new) {
BMLoop *l_first, *l_iter;
diff --git a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
index 0fc571bc0a8..f0ac6c673c9 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
@@ -43,10 +43,10 @@ static bool bm_vert_dissolve_fan_test(BMVert *v)
BMVert *varr[4];
- unsigned int tot_edge = 0;
- unsigned int tot_edge_boundary = 0;
- unsigned int tot_edge_manifold = 0;
- unsigned int tot_edge_wire = 0;
+ uint tot_edge = 0;
+ uint tot_edge_boundary = 0;
+ uint tot_edge_manifold = 0;
+ uint tot_edge_wire = 0;
BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
if (BM_edge_is_boundary(e)) {
@@ -74,7 +74,7 @@ static bool bm_vert_dissolve_fan_test(BMVert *v)
((tot_edge == 3) && (tot_edge_boundary == 0) && (tot_edge_manifold == 3)) ||
((tot_edge == 3) && (tot_edge_boundary == 2) && (tot_edge_manifold == 1)))
{
- if (!BM_face_exists(varr, tot_edge, NULL)) {
+ if (!BM_face_exists(varr, tot_edge)) {
return true;
}
}
@@ -97,11 +97,11 @@ static bool bm_vert_dissolve_fan(BMesh *bm, BMVert *v)
BMIter iter;
BMEdge *e;
- unsigned int tot_loop = 0;
- unsigned int tot_edge = 0;
- unsigned int tot_edge_boundary = 0;
- unsigned int tot_edge_manifold = 0;
- unsigned int tot_edge_wire = 0;
+ uint tot_loop = 0;
+ uint tot_edge = 0;
+ uint tot_edge_boundary = 0;
+ uint tot_edge_manifold = 0;
+ uint tot_edge_wire = 0;
BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
if (BM_edge_is_boundary(e)) {
@@ -143,7 +143,7 @@ static bool bm_vert_dissolve_fan(BMesh *bm, BMVert *v)
if (tot_loop) {
BMLoop *f_loop[4];
- unsigned int i;
+ uint i;
/* ensure there are exactly tot_loop loops */
BLI_assert(BM_iter_at_index(bm, BM_LOOPS_OF_VERT, v, tot_loop) == NULL);
@@ -192,8 +192,8 @@ void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool
BMIter iter;
- const unsigned int offset = 0;
- const unsigned int nth = 2;
+ const uint offset = 0;
+ const uint nth = 2;
int iter_step;
@@ -229,8 +229,8 @@ void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool
#ifdef USE_WALKER
BMWalker walker;
#else
- unsigned int depth = 1;
- unsigned int i;
+ uint depth = 1;
+ uint i;
#endif
BMVert *v_first = NULL;
diff --git a/source/blender/bmesh/tools/bmesh_edgenet.c b/source/blender/bmesh/tools/bmesh_edgenet.c
index 2a1946df7ae..193a032b46e 100644
--- a/source/blender/bmesh/tools/bmesh_edgenet.c
+++ b/source/blender/bmesh/tools/bmesh_edgenet.c
@@ -100,13 +100,13 @@ static BMEdge *bm_edgenet_edge_get_next(
*
* This function returns half a loop, the caller needs to run twice to get both sides.
*/
-static unsigned int bm_edgenet_path_from_pass(
+static uint bm_edgenet_path_from_pass(
BMVert *v, LinkNode **v_ls,
VertNetInfo *vnet_info, BLI_mempool *path_pool)
{
VertNetInfo *vn = &vnet_info[BM_elem_index_get(v)];
const int pass = vn->pass;
- unsigned int v_ls_tot = 0;
+ uint v_ls_tot = 0;
do {
BLI_linklist_prepend_pool(v_ls, v, path_pool);
@@ -127,10 +127,10 @@ static bool bm_edgenet_path_check_overlap(
VertNetInfo *vnet_info)
{
/* vert order doesn't matter */
- unsigned int v_ls_tot = 0;
+ uint v_ls_tot = 0;
LinkNode *v_ls = NULL;
BMVert *v_pair[2] = {v1, v2};
- unsigned int i;
+ uint i;
for (i = 0; i < 2; i++) {
BMVert *v = v_pair[i];
@@ -162,7 +162,7 @@ static bool bm_edgenet_path_check_overlap(
* Create a face from the path.
*/
static BMFace *bm_edgenet_face_from_path(
- BMesh *bm, LinkNode *path, const unsigned int path_len)
+ BMesh *bm, LinkNode *path, const uint path_len)
{
BMFace *f;
LinkNode *v_lnk;
@@ -205,8 +205,8 @@ static BMEdge *bm_edgenet_path_step(
BMEdge *e;
BMIter iter;
- unsigned int tot;
- unsigned int v_ls_tot;
+ uint tot;
+ uint v_ls_tot;
begin:
@@ -277,8 +277,8 @@ begin:
* \return A linked list of verts.
*/
static LinkNode *bm_edgenet_path_calc(
- BMEdge *e, const int pass_nr, const unsigned int path_cost_max,
- unsigned int *r_path_len, unsigned int *r_path_cost,
+ BMEdge *e, const int pass_nr, const uint path_cost_max,
+ uint *r_path_len, uint *r_path_cost,
VertNetInfo *vnet_info, BLI_mempool *path_pool)
{
VertNetInfo *vn_1, *vn_2;
@@ -288,7 +288,7 @@ static LinkNode *bm_edgenet_path_calc(
LinkNode *v_ls_prev = NULL;
LinkNode *v_ls_next = NULL;
- unsigned int path_cost_accum = 0;
+ uint path_cost_accum = 0;
BLI_assert(bm_edge_step_ok(e));
@@ -331,7 +331,7 @@ static LinkNode *bm_edgenet_path_calc(
if (e_found) {
LinkNode *path = NULL;
- unsigned int path_len;
+ uint path_len;
BLI_linklist_free_pool(v_ls_next, NULL, path_pool);
BLI_linklist_free_pool(v_ls_prev, NULL, path_pool);
@@ -376,12 +376,12 @@ static LinkNode *bm_edgenet_path_calc(
* _don't_ have a better option.
*/
static LinkNode *bm_edgenet_path_calc_best(
- BMEdge *e, int *pass_nr, unsigned int path_cost_max,
- unsigned int *r_path_len, unsigned int *r_path_cost,
+ BMEdge *e, int *pass_nr, uint path_cost_max,
+ uint *r_path_len, uint *r_path_cost,
VertNetInfo *vnet_info, BLI_mempool *path_pool)
{
LinkNode *path;
- unsigned int path_cost;
+ uint path_cost;
path = bm_edgenet_path_calc(e, *pass_nr, path_cost_max,
r_path_len, &path_cost,
@@ -399,8 +399,8 @@ static LinkNode *bm_edgenet_path_calc_best(
/* Check every edge to see if any can give a better path.
* This avoids very strange/long paths from being created. */
- const unsigned int path_len = *r_path_len;
- unsigned int i, i_prev;
+ const uint path_len = *r_path_len;
+ uint i, i_prev;
BMVert **vert_arr = BLI_array_alloca(vert_arr, path_len);
LinkNode *v_lnk;
@@ -413,8 +413,8 @@ static LinkNode *bm_edgenet_path_calc_best(
BMEdge *e_other = BM_edge_exists(vert_arr[i], vert_arr[i_prev]);
if (e_other != e) {
LinkNode *path_test;
- unsigned int path_len_test;
- unsigned int path_cost_test;
+ uint path_len_test;
+ uint path_cost_test;
path_test = bm_edgenet_path_calc(e_other, *pass_nr, path_cost,
&path_len_test, &path_cost_test,
@@ -471,8 +471,8 @@ void BM_mesh_edgenet(
while (true) {
LinkNode *path = NULL;
- unsigned int path_len;
- unsigned int path_cost;
+ uint path_len;
+ uint path_cost;
e = bm_edgenet_edge_get_next(bm, &edge_queue, edge_queue_pool);
if (e == NULL) {
diff --git a/source/blender/bmesh/tools/bmesh_edgesplit.c b/source/blender/bmesh/tools/bmesh_edgesplit.c
index a59a5c43c82..3a844a0b8d9 100644
--- a/source/blender/bmesh/tools/bmesh_edgesplit.c
+++ b/source/blender/bmesh/tools/bmesh_edgesplit.c
@@ -96,7 +96,7 @@ void BM_mesh_edgesplit(
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- unsigned int i;
+ uint i;
for (i = 0; i < 2; i++) {
BMVert *v = ((&e->v1)[i]);
if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c
index 58234ddf3bd..cfb43181703 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(
@@ -152,7 +146,7 @@ struct ISectState {
*/
struct LinkBase {
LinkNode *list;
- unsigned int list_len;
+ uint list_len;
};
static bool ghash_insert_link(
@@ -193,7 +187,7 @@ struct vert_sort_t {
static void edge_verts_sort(const float co[3], struct LinkBase *v_ls_base)
{
/* not optimal but list will be typically < 5 */
- unsigned int i;
+ uint i;
struct vert_sort_t *vert_sort = BLI_array_alloca(vert_sort, v_ls_base->list_len);
LinkNode *node;
@@ -246,8 +240,8 @@ static void face_edges_split(
bool use_island_connect,
MemArena *mem_arena_edgenet)
{
- unsigned int i;
- unsigned int edge_arr_len = e_ls_base->list_len;
+ uint i;
+ uint edge_arr_len = e_ls_base->list_len;
BMEdge **edge_arr = BLI_array_alloca(edge_arr, edge_arr_len);
LinkNode *node;
BLI_assert(f->head.htype == BM_FACE);
@@ -263,7 +257,7 @@ static void face_edges_split(
#ifdef USE_NET_ISLAND_CONNECT
if (use_island_connect) {
- unsigned int edge_arr_holes_len;
+ uint edge_arr_holes_len;
BMEdge **edge_arr_holes;
if (BM_face_split_edgenet_connect_islands(
bm, f,
@@ -305,14 +299,14 @@ static enum ISectType intersect_line_tri(
const struct ISectEpsilon *e)
{
float p_dir[3];
- unsigned int i_t0;
+ uint i_t0;
float fac;
sub_v3_v3v3(p_dir, p0, p1);
normalize_v3(p_dir);
for (i_t0 = 0; i_t0 < 3; i_t0++) {
- const unsigned int i_t1 = (i_t0 + 1) % 3;
+ const uint i_t1 = (i_t0 + 1) % 3;
float te_dir[3];
sub_v3_v3v3(te_dir, t_cos[i_t0], t_cos[i_t1]);
@@ -375,7 +369,7 @@ static BMVert *bm_isect_edge_tri(
{
BMesh *bm = s->bm;
int k_arr[IX_TOT][4];
- unsigned int i;
+ uint i;
const int ti[3] = {UNPACK3_EX(BM_elem_index_get, t, )};
float ix[3];
@@ -470,7 +464,7 @@ static BMVert *bm_isect_edge_tri(
}
if ((*r_side >= IX_EDGE_TRI_EDGE0) && (*r_side <= IX_EDGE_TRI_EDGE2)) {
- i = (unsigned int)(*r_side - IX_EDGE_TRI_EDGE0);
+ i = (uint)(*r_side - IX_EDGE_TRI_EDGE0);
e = BM_edge_exists(t[i], t[(i + 1) % 3]);
if (e) {
edge_verts_add(s, e, iv, false);
@@ -537,7 +531,7 @@ static void bm_isect_tri_tri(
const float *f_b_cos[3] = {UNPACK3_EX(, fv_b, ->co)};
float f_a_nor[3];
float f_b_nor[3];
- unsigned int i;
+ uint i;
/* should be enough but may need to bump */
@@ -578,9 +572,9 @@ static void bm_isect_tri_tri(
/* first check in any verts are touching
* (any case where we wont create new verts)
*/
- unsigned int i_a;
+ uint i_a;
for (i_a = 0; i_a < 3; i_a++) {
- unsigned int i_b;
+ uint i_b;
for (i_b = 0; i_b < 3; i_b++) {
if (len_squared_v3v3(fv_a[i_a]->co, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
#ifdef USE_DUMP
@@ -603,12 +597,12 @@ static void bm_isect_tri_tri(
/* vert-edge
* --------- */
{
- unsigned int i_a;
+ uint i_a;
for (i_a = 0; i_a < 3; i_a++) {
if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT_A) == 0) {
- unsigned int i_b_e0;
+ uint i_b_e0;
for (i_b_e0 = 0; i_b_e0 < 3; i_b_e0++) {
- unsigned int i_b_e1 = (i_b_e0 + 1) % 3;
+ uint i_b_e1 = (i_b_e0 + 1) % 3;
if (BM_ELEM_API_FLAG_TEST(fv_b[i_b_e0], VERT_VISIT_B) ||
BM_ELEM_API_FLAG_TEST(fv_b[i_b_e1], VERT_VISIT_B))
@@ -644,12 +638,12 @@ static void bm_isect_tri_tri(
}
{
- unsigned int i_b;
+ uint i_b;
for (i_b = 0; i_b < 3; i_b++) {
if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT_B) == 0) {
- unsigned int i_a_e0;
+ uint i_a_e0;
for (i_a_e0 = 0; i_a_e0 < 3; i_a_e0++) {
- unsigned int i_a_e1 = (i_a_e0 + 1) % 3;
+ uint i_a_e1 = (i_a_e0 + 1) % 3;
if (BM_ELEM_API_FLAG_TEST(fv_a[i_a_e0], VERT_VISIT_A) ||
BM_ELEM_API_FLAG_TEST(fv_a[i_a_e1], VERT_VISIT_A))
@@ -689,7 +683,7 @@ static void bm_isect_tri_tri(
{
float t_scale[3][3];
- unsigned int i_a;
+ uint i_a;
copy_v3_v3(t_scale[0], fv_b[0]->co);
copy_v3_v3(t_scale[1], fv_b[1]->co);
@@ -717,7 +711,7 @@ static void bm_isect_tri_tri(
{
float t_scale[3][3];
- unsigned int i_b;
+ uint i_b;
copy_v3_v3(t_scale[0], fv_a[0]->co);
copy_v3_v3(t_scale[1], fv_a[1]->co);
@@ -757,8 +751,8 @@ static void bm_isect_tri_tri(
/* edge-tri & edge-edge
* -------------------- */
{
- for (unsigned int i_a_e0 = 0; i_a_e0 < 3; i_a_e0++) {
- unsigned int i_a_e1 = (i_a_e0 + 1) % 3;
+ for (uint i_a_e0 = 0; i_a_e0 < 3; i_a_e0++) {
+ uint i_a_e1 = (i_a_e0 + 1) % 3;
enum ISectType side;
BMVert *iv;
@@ -778,8 +772,8 @@ static void bm_isect_tri_tri(
}
}
- for (unsigned int i_b_e0 = 0; i_b_e0 < 3; i_b_e0++) {
- unsigned int i_b_e1 = (i_b_e0 + 1) % 3;
+ for (uint i_b_e0 = 0; i_b_e0 < 3; i_b_e0++) {
+ uint i_b_e1 = (i_b_e0 + 1) % 3;
enum ISectType side;
BMVert *iv;
@@ -956,7 +950,7 @@ static int isect_bvhtree_point_v3(
const float *depth_arr = z_buffer.data;
float depth_last = depth_arr[0];
- for (unsigned int i = 1; i < z_buffer.count; i++) {
+ for (uint i = 1; i < z_buffer.count; i++) {
if (depth_arr[i] - depth_last > eps) {
depth_last = depth_arr[i];
num_isect++;
@@ -986,7 +980,7 @@ bool BM_mesh_intersect(
struct BMLoop *(*looptris)[3], const int looptris_tot,
int (*test_fn)(BMFace *f, void *user_data), void *user_data,
const bool use_self, const bool use_separate, const bool use_dissolve, const bool use_island_connect,
- const int boolean_mode,
+ const bool use_edge_tag, const int boolean_mode,
const float eps)
{
struct ISectState s;
@@ -1000,16 +994,12 @@ bool BM_mesh_intersect(
#ifdef USE_BVH
BVHTree *tree_a, *tree_b;
- unsigned int tree_overlap_tot;
+ uint tree_overlap_tot;
BVHTreeOverlap *overlap;
#else
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__);
@@ -1117,7 +1107,7 @@ bool BM_mesh_intersect(
overlap = BLI_bvhtree_overlap(tree_b, tree_a, &tree_overlap_tot, NULL, NULL);
if (overlap) {
- unsigned int i;
+ uint i;
for (i = 0; i < tree_overlap_tot; i++) {
#ifdef USE_DUMP
@@ -1390,7 +1380,7 @@ bool BM_mesh_intersect(
GHASH_ITER (gh_iter, s.face_edges) {
struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter);
LinkNode **node_prev_p;
- unsigned int i;
+ uint i;
node_prev_p = &e_ls_base->list;
for (i = 0, node = e_ls_base->list; node; i++, node = node->next) {
@@ -1455,7 +1445,7 @@ bool BM_mesh_intersect(
}
{
- unsigned int i;
+ uint i;
for (i = 0; i < STACK_SIZE(splice_ls); i++) {
if (!BLI_gset_haskey(verts_invalid, splice_ls[i][0]) &&
!BLI_gset_haskey(verts_invalid, splice_ls[i][1]))
@@ -1526,7 +1516,7 @@ bool BM_mesh_intersect(
BM_mesh_edgesplit(bm, false, true, false);
}
- else if (boolean_mode != BMESH_ISECT_BOOLEAN_NONE) {
+ else if (boolean_mode != BMESH_ISECT_BOOLEAN_NONE || use_edge_tag) {
GSetIterator gs_iter;
/* no need to clear for boolean */
@@ -1607,17 +1597,6 @@ bool BM_mesh_intersect(
do_flip = (side == 0);
break;
}
-
-#ifdef USE_BOOLEAN_RAYCAST_DRAW
- {
- unsigned int 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_intersect.h b/source/blender/bmesh/tools/bmesh_intersect.h
index d0cc41654eb..51926a01710 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.h
+++ b/source/blender/bmesh/tools/bmesh_intersect.h
@@ -30,7 +30,7 @@ bool BM_mesh_intersect(
struct BMLoop *(*looptris)[3], const int looptris_tot,
int (*test_fn)(BMFace *f, void *user_data), void *user_data,
const bool use_self, const bool use_separate, const bool use_dissolve, const bool use_island_connect,
- const int boolean_mode,
+ const bool use_edge_tag, const int boolean_mode,
const float eps);
enum {
diff --git a/source/blender/bmesh/tools/bmesh_path.h b/source/blender/bmesh/tools/bmesh_path.h
index b6de5e0e4e0..fbdd2296121 100644
--- a/source/blender/bmesh/tools/bmesh_path.h
+++ b/source/blender/bmesh/tools/bmesh_path.h
@@ -28,8 +28,8 @@
*/
struct BMCalcPathParams {
- unsigned int use_topology_distance : 1;
- unsigned int use_step_face : 1;
+ uint use_topology_distance : 1;
+ uint use_step_face : 1;
};
struct LinkNode *BM_mesh_calc_path_vert(
diff --git a/source/blender/bmesh/tools/bmesh_region_match.c b/source/blender/bmesh/tools/bmesh_region_match.c
index a6860a6614a..2abf8f2c46e 100644
--- a/source/blender/bmesh/tools/bmesh_region_match.c
+++ b/source/blender/bmesh/tools/bmesh_region_match.c
@@ -114,7 +114,7 @@ typedef struct UUIDWalk {
GHash *faces_from_uuid; /* UUID -> UUIDFaceStepItem */
UUID_Int *rehash_store;
- unsigned int rehash_store_len;
+ uint rehash_store_len;
} cache;
} UUIDWalk;
@@ -136,7 +136,7 @@ typedef struct UUIDFaceStepItem {
uintptr_t uuid;
LinkNode *list;
- unsigned int list_len;
+ uint list_len;
} UUIDFaceStepItem;
BLI_INLINE bool bm_uuidwalk_face_test(
@@ -178,10 +178,10 @@ BLI_INLINE bool bm_uuidwalk_face_lookup(
}
}
-static unsigned int ghashutil_bmelem_indexhash(const void *key)
+static uint ghashutil_bmelem_indexhash(const void *key)
{
const BMElem *ele = key;
- return (unsigned int)BM_elem_index_get(ele);
+ return (uint)BM_elem_index_get(ele);
}
static bool ghashutil_bmelem_indexcmp(const void *a, const void *b)
@@ -192,14 +192,14 @@ static bool ghashutil_bmelem_indexcmp(const void *a, const void *b)
static GHash *ghash_bmelem_new_ex(
const char *info,
- const unsigned int nentries_reserve)
+ const uint nentries_reserve)
{
return BLI_ghash_new_ex(ghashutil_bmelem_indexhash, ghashutil_bmelem_indexcmp, info, nentries_reserve);
}
static GSet *gset_bmelem_new_ex(
const char *info,
- const unsigned int nentries_reserve)
+ const uint nentries_reserve)
{
return BLI_gset_new_ex(ghashutil_bmelem_indexhash, ghashutil_bmelem_indexcmp, info, nentries_reserve);
}
@@ -218,8 +218,8 @@ static GSet *gset_bmelem_new(const char *info)
static void bm_uuidwalk_init(
UUIDWalk *uuidwalk,
- const unsigned int faces_src_region_len,
- const unsigned int verts_src_region_len)
+ const uint faces_src_region_len,
+ const uint verts_src_region_len)
{
BLI_listbase_clear(&uuidwalk->faces_step);
@@ -307,7 +307,7 @@ static UUID_Int bm_uuidwalk_calc_vert_uuid(
/* vert -> other */
{
- unsigned int tot = 0;
+ uint tot = 0;
BMIter eiter;
BMEdge *e;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
@@ -323,7 +323,7 @@ static UUID_Int bm_uuidwalk_calc_vert_uuid(
/* faces */
{
- unsigned int tot = 0;
+ uint tot = 0;
BMIter iter;
BMFace *f;
@@ -357,7 +357,7 @@ static UUID_Int bm_uuidwalk_calc_face_uuid(
UUID_Int uuid;
- uuid = uuidwalk->pass * (unsigned int)f->len * PRIME_FACE_LARGE;
+ uuid = uuidwalk->pass * (uint)f->len * PRIME_FACE_LARGE;
/* face-verts */
{
@@ -399,7 +399,7 @@ static UUID_Int bm_uuidwalk_calc_face_uuid(
}
static void bm_uuidwalk_rehash_reserve(
- UUIDWalk *uuidwalk, unsigned int rehash_store_len_new)
+ UUIDWalk *uuidwalk, uint rehash_store_len_new)
{
if (UNLIKELY(rehash_store_len_new > uuidwalk->cache.rehash_store_len)) {
/* avoid re-allocs */
@@ -419,9 +419,9 @@ static void bm_uuidwalk_rehash(
{
GHashIterator gh_iter;
UUID_Int *uuid_store;
- unsigned int i;
+ uint i;
- unsigned int rehash_store_len_new = MAX2(BLI_ghash_size(uuidwalk->verts_uuid),
+ uint rehash_store_len_new = MAX2(BLI_ghash_size(uuidwalk->verts_uuid),
BLI_ghash_size(uuidwalk->faces_uuid));
bm_uuidwalk_rehash_reserve(uuidwalk, rehash_store_len_new);
@@ -454,12 +454,12 @@ static void bm_uuidwalk_rehash(
static void bm_uuidwalk_rehash_facelinks(
UUIDWalk *uuidwalk,
- LinkNode *faces, const unsigned int faces_len,
+ LinkNode *faces, const uint faces_len,
const bool is_init)
{
UUID_Int *uuid_store;
LinkNode *f_link;
- unsigned int i;
+ uint i;
bm_uuidwalk_rehash_reserve(uuidwalk, faces_len);
uuid_store = uuidwalk->cache.rehash_store;
@@ -502,7 +502,7 @@ static bool bm_vert_is_uuid_connect(
}
static void bm_uuidwalk_pass_add(
- UUIDWalk *uuidwalk, LinkNode *faces_pass, const unsigned int faces_pass_len)
+ UUIDWalk *uuidwalk, LinkNode *faces_pass, const uint faces_pass_len)
{
GHashIterator gh_iter;
GHash *verts_uuid_pass;
@@ -511,7 +511,7 @@ static void bm_uuidwalk_pass_add(
UUIDFaceStep *fstep;
- BLI_assert(faces_pass_len == (unsigned int)BLI_linklist_count(faces_pass));
+ BLI_assert(faces_pass_len == (uint)BLI_linklist_count(faces_pass));
/* rehash faces now all their verts have been added */
bm_uuidwalk_rehash_facelinks(uuidwalk, faces_pass, faces_pass_len, true);
@@ -588,13 +588,13 @@ static int bm_face_len_cmp(const void *v1, const void *v2)
else return 0;
}
-static unsigned int bm_uuidwalk_init_from_edge(
+static uint bm_uuidwalk_init_from_edge(
UUIDWalk *uuidwalk, BMEdge *e)
{
BMLoop *l_iter = e->l;
- unsigned int f_arr_len = (unsigned int)BM_edge_face_count(e);
+ uint f_arr_len = (uint)BM_edge_face_count(e);
BMFace **f_arr = BLI_array_alloca(f_arr, f_arr_len);
- unsigned int fstep_num = 0, i = 0;
+ uint fstep_num = 0, i = 0;
do {
BMFace *f = l_iter->f;
@@ -619,7 +619,7 @@ static unsigned int bm_uuidwalk_init_from_edge(
* elsewhere using LinkNode's makes more sense */
for (i = 0; i < f_arr_len; ) {
LinkNode *faces_pass = NULL;
- const unsigned int i_init = i;
+ const uint i_init = i;
const int f_len = f_arr[i]->len;
do {
@@ -750,9 +750,9 @@ static BMFace **bm_mesh_region_match_pair(
UUIDWalk *w_src, UUIDWalk *w_dst,
#endif
BMEdge *e_src, BMEdge *e_dst,
- const unsigned int faces_src_region_len,
- const unsigned int verts_src_region_len,
- unsigned int *r_faces_result_len)
+ const uint faces_src_region_len,
+ const uint verts_src_region_len,
+ uint *r_faces_result_len)
{
#ifndef USE_WALKER_REUSE
UUIDWalk w_src_, w_dst_;
@@ -877,8 +877,8 @@ static BMFace **bm_mesh_region_match_pair(
if (found) {
GHashIterator gh_iter;
- const unsigned int faces_result_len = BLI_ghash_size(w_dst->faces_uuid);
- unsigned int i;
+ const uint faces_result_len = BLI_ghash_size(w_dst->faces_uuid);
+ uint i;
faces_result = MEM_mallocN(sizeof(*faces_result) * (faces_result_len + 1), __func__);
GHASH_ITER_INDEX (gh_iter, w_dst->faces_uuid, i) {
@@ -909,12 +909,12 @@ finally:
* Tag as visited, avoid re-use.
*/
static void bm_face_array_visit(
- BMFace **faces, const unsigned int faces_len,
- unsigned int *r_verts_len,
+ BMFace **faces, const uint faces_len,
+ uint *r_verts_len,
bool visit_faces)
{
- unsigned int verts_len = 0;
- unsigned int i;
+ uint verts_len = 0;
+ uint i;
for (i = 0; i < faces_len; i++) {
BMFace *f = faces[i];
BMLoop *l_iter, *l_first;
@@ -1081,9 +1081,9 @@ static SUID_Int bm_face_region_vert_pass_id(GHash *gh, BMVert *v)
* This is only called once on the source region (no need to be highly optimized).
*/
static BMEdge *bm_face_region_pivot_edge_find(
- BMFace **faces_region, unsigned int faces_region_len,
- unsigned int verts_region_len,
- unsigned int *r_depth)
+ BMFace **faces_region, uint faces_region_len,
+ uint verts_region_len,
+ uint *r_depth)
{
/* note, keep deterministic where possible (geometry order independent)
* this function assumed all visit faces & edges are tagged */
@@ -1092,7 +1092,7 @@ static BMEdge *bm_face_region_pivot_edge_find(
BLI_LINKSTACK_DECLARE(vert_queue_next, BMVert *);
GHash *gh = BLI_ghash_ptr_new(__func__);
- unsigned int i;
+ uint i;
BMEdge *e_pivot = NULL;
/* pick any non-boundary edge (not ideal) */
@@ -1101,7 +1101,7 @@ static BMEdge *bm_face_region_pivot_edge_find(
SUID_Int pass = 0;
/* total verts in 'gs' we have visited - aka - not v_init_none */
- unsigned int vert_queue_used = 0;
+ uint vert_queue_used = 0;
BLI_LINKSTACK_INIT(vert_queue_prev);
BLI_LINKSTACK_INIT(vert_queue_next);
@@ -1115,7 +1115,7 @@ static BMEdge *bm_face_region_pivot_edge_find(
do {
BMEdge *e = l_iter->e;
if (bm_edge_is_region_boundary(e)) {
- unsigned int j;
+ uint j;
for (j = 0; j < 2; j++) {
void **val_p;
if (!BLI_ghash_ensure_p(gh, (&e->v1)[j], &val_p)) {
@@ -1251,7 +1251,7 @@ static BMEdge *bm_face_region_pivot_edge_find(
pass = 0;
}
- *r_depth = (unsigned int)pass;
+ *r_depth = (uint)pass;
return e_pivot;
}
@@ -1286,7 +1286,7 @@ static UUIDFashMatch bm_vert_fasthash_single(BMVert *v)
e_num += 1;
do {
f_num += 1;
- l_num += (unsigned int)l_iter->f->len;
+ l_num += (uint)l_iter->f->len;
} while ((l_iter = l_iter->radial_next) != e->l);
}
}
@@ -1301,16 +1301,16 @@ static UUIDFashMatch bm_vert_fasthash_single(BMVert *v)
}
static UUIDFashMatch *bm_vert_fasthash_create(
- BMesh *bm, const unsigned int depth)
+ BMesh *bm, const uint depth)
{
UUIDFashMatch *id_prev;
UUIDFashMatch *id_curr;
- unsigned int pass, i;
+ uint pass, i;
BMVert *v;
BMIter iter;
- id_prev = MEM_mallocN(sizeof(*id_prev) * (unsigned int)bm->totvert, __func__);
- id_curr = MEM_mallocN(sizeof(*id_curr) * (unsigned int)bm->totvert, __func__);
+ id_prev = MEM_mallocN(sizeof(*id_prev) * (uint)bm->totvert, __func__);
+ id_curr = MEM_mallocN(sizeof(*id_curr) * (uint)bm->totvert, __func__);
BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
id_prev[i] = bm_vert_fasthash_single(v);
@@ -1319,7 +1319,7 @@ static UUIDFashMatch *bm_vert_fasthash_create(
for (pass = 0; pass < depth; pass++) {
BMEdge *e;
- memcpy(id_curr, id_prev, sizeof(*id_prev) * (unsigned int)bm->totvert);
+ memcpy(id_curr, id_prev, sizeof(*id_prev) * (uint)bm->totvert);
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_edge_is_wire(e) == false) {
@@ -1379,16 +1379,16 @@ static void bm_vert_fasthash_destroy(
*/
int BM_mesh_region_match(
BMesh *bm,
- BMFace **faces_region, unsigned int faces_region_len,
+ BMFace **faces_region, uint faces_region_len,
ListBase *r_face_regions)
{
BMEdge *e_src;
BMEdge *e_dst;
BMIter iter;
- unsigned int verts_region_len = 0;
- unsigned int faces_result_len = 0;
+ uint verts_region_len = 0;
+ uint faces_result_len = 0;
/* number of steps from e_src to a boundary vert */
- unsigned int depth;
+ uint depth;
#ifdef USE_WALKER_REUSE
@@ -1457,7 +1457,7 @@ int BM_mesh_region_match(
BM_ITER_MESH (e_dst, &iter, bm, BM_EDGES_OF_MESH) {
BMFace **faces_result;
- unsigned int faces_result_len_out;
+ uint faces_result_len_out;
if (BM_elem_flag_test(e_dst, BM_ELEM_TAG) || BM_edge_is_wire(e_dst)) {
continue;
diff --git a/source/blender/bmesh/tools/bmesh_region_match.h b/source/blender/bmesh/tools/bmesh_region_match.h
index edf8369b070..8ef138629b8 100644
--- a/source/blender/bmesh/tools/bmesh_region_match.h
+++ b/source/blender/bmesh/tools/bmesh_region_match.h
@@ -27,7 +27,7 @@
int BM_mesh_region_match(
BMesh *bm,
- BMFace **faces_region, unsigned int faces_region_len,
+ BMFace **faces_region, uint faces_region_len,
ListBase *r_face_regions);
#endif /* __BMESH_REGION_MATCH_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_separate.c b/source/blender/bmesh/tools/bmesh_separate.c
new file mode 100644
index 00000000000..287b4125330
--- /dev/null
+++ b/source/blender/bmesh/tools/bmesh_separate.c
@@ -0,0 +1,133 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/bmesh/tools/bmesh_separate.c
+ * \ingroup bmesh
+ *
+ * BMesh separate, disconnects a set of faces from all others,
+ * so they don't share any vertices/edges with other faces.
+ */
+
+#include <limits.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_buffer.h"
+
+#include "bmesh.h"
+#include "intern/bmesh_private.h"
+#include "bmesh_separate.h" /* own include */
+
+/**
+ * Split all faces that match `filter_fn`.
+ * \note
+ */
+void BM_mesh_separate_faces(
+ BMesh *bm,
+ BMFaceFilterFunc filter_fn, void *user_data)
+{
+ BMFace **faces_array_all = MEM_mallocN(bm->totface * sizeof(BMFace *), __func__);
+ /*
+ * - Create an array of faces based on 'filter_fn'.
+ * First part of array for match, for non-match.
+ *
+ * - Enable all vertex tags, then clear all tagged vertices from 'faces_b'.
+ *
+ * - Loop over 'faces_a', checking each vertex,
+ * splitting out any which aren't tagged (and therefor shared), disabling tags as we go.
+ */
+
+ BMFace *f;
+ BMIter iter;
+
+ uint faces_a_len = 0;
+ uint faces_b_len = 0;
+ {
+ int i_a = 0;
+ int i_b = bm->totface;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ faces_array_all[filter_fn(f, user_data) ? i_a++ : --i_b] = f;
+ }
+ faces_a_len = i_a;
+ faces_b_len = bm->totface - i_a;
+ }
+
+ BMFace **faces_a = faces_array_all;
+ BMFace **faces_b = faces_array_all + faces_a_len;
+
+ /* Enable for all */
+ BM_mesh_elem_hflag_enable_all(bm, BM_VERT, BM_ELEM_TAG, false);
+
+ /* Disable vert tag on faces_b */
+ for (uint i = 0; i < faces_b_len; i++) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(faces_b[i]);
+ do {
+ BM_elem_flag_disable(l_iter->v, BM_ELEM_TAG);
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+
+ BLI_buffer_declare_static(BMLoop **, loop_split, 0, 128);
+
+ /* Check shared verts ('faces_a' tag and disable) */
+ for (uint i = 0; i < faces_a_len; i++) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(faces_a[i]);
+ do {
+ if (!BM_elem_flag_test(l_iter->v, BM_ELEM_TAG)) {
+ BMVert *v = l_iter->v;
+ /* Enable, since we may visit this vertex again on other faces */
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+
+ /* We know the vertex is shared, collect all vertices and split them off. */
+
+ /* Fill 'loop_split' */
+ {
+ BMEdge *e_first, *e_iter;
+ e_iter = e_first = l_iter->e;
+ do {
+ if (e_iter->l != NULL) {
+ BMLoop *l_radial_first, *l_radial_iter;
+ l_radial_first = l_radial_iter = e_iter->l;
+ do {
+ if (l_radial_iter->v == v) {
+ if (filter_fn(l_radial_iter->f, user_data)) {
+ BLI_buffer_append(&loop_split, BMLoop *, l_radial_iter);
+ }
+ }
+ } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
+ }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
+ }
+
+ /* Perform the split */
+ BM_face_loop_separate_multi(bm, loop_split.data, loop_split.count);
+
+ BLI_buffer_empty(&loop_split);
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ BLI_buffer_free(&loop_split);
+
+ MEM_freeN(faces_array_all);
+}
diff --git a/source/blender/bmesh/tools/bmesh_separate.h b/source/blender/bmesh/tools/bmesh_separate.h
new file mode 100644
index 00000000000..91b2b71c872
--- /dev/null
+++ b/source/blender/bmesh/tools/bmesh_separate.h
@@ -0,0 +1,32 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 __BMESH_SEPARATE_H__
+#define __BMESH_SEPARATE_H__
+
+/** \file blender/bmesh/tools/bmesh_separate.h
+ * \ingroup bmesh
+ */
+
+void BM_mesh_separate_faces(
+ BMesh *bm,
+ BMFaceFilterFunc filter_fn, void *user_data);
+
+#endif /* __BMESH_SEPARATE_H__ */
diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp
index 3bff20e846b..707aaea0b65 100644
--- a/source/blender/collada/AnimationExporter.cpp
+++ b/source/blender/collada/AnimationExporter.cpp
@@ -938,7 +938,7 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Obj
float ctime = BKE_scene_frame_get_from_ctime(scene, *it);
CFRA = BKE_scene_frame_get_from_ctime(scene, *it);
- //BKE_scene_update_for_newframe(G.main->eval_ctx, G.main,scene,scene->lay);
+ //BKE_scene_update_for_newframe(G.main->eval_ctx, G.main,scene);
BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL);
if (bone) {
diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp
index 5cd01eff263..5e6fe84d3a9 100644
--- a/source/blender/collada/AnimationImporter.cpp
+++ b/source/blender/collada/AnimationImporter.cpp
@@ -35,8 +35,8 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
-#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -1918,7 +1918,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);
@@ -1934,19 +1934,19 @@ Object *AnimationImporter::get_joint_object(COLLADAFW::Node *root, COLLADAFW::No
mul_m4_m4m4(mat, ipar, temp);
}
- TransformBase::decompose(mat, job->loc, NULL, job->quat, job->size);
+ bc_decompose(mat, job->loc, NULL, job->quat, job->size);
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/ArmatureExporter.cpp b/source/blender/collada/ArmatureExporter.cpp
index 4f5cf83f5ca..9348f3b3285 100644
--- a/source/blender/collada/ArmatureExporter.cpp
+++ b/source/blender/collada/ArmatureExporter.cpp
@@ -69,17 +69,21 @@ void ArmatureExporter::add_armature_bones(Object *ob_arm, Scene *sce,
// write bone nodes
bArmature * armature = (bArmature *)ob_arm->data;
- ED_armature_to_edit(armature);
+ bool is_edited = armature->edbo != NULL;
- bArmature *arm = (bArmature *)ob_arm->data;
- for (Bone *bone = (Bone *)arm->bonebase.first; bone; bone = bone->next) {
+ 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(bone, ob_arm, sce, se, child_objects);
}
- ED_armature_from_edit(armature);
- ED_armature_edit_free(armature);
+ if (!is_edited) {
+ ED_armature_from_edit(armature);
+ ED_armature_edit_free(armature);
+ }
}
void ArmatureExporter::write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone)
@@ -152,11 +156,6 @@ void ArmatureExporter::find_objects_using_armature(Object *ob_arm, std::vector<O
}
#endif
-std::string ArmatureExporter::get_joint_sid(Bone *bone, Object *ob_arm)
-{
- return get_joint_id(bone, ob_arm);
-}
-
// parent_mat is armature-space
void ArmatureExporter::add_bone_node(Bone *bone, Object *ob_arm, Scene *sce,
SceneExporter *se,
@@ -257,47 +256,59 @@ void ArmatureExporter::add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW:
//bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name);
float mat[4][4];
+ float bone_rest_mat[4][4]; /* derived from bone->arm_mat */
+ float parent_rest_mat[4][4]; /* derived from bone->parent->arm_mat */
- if (bone->parent) {
- // get bone-space matrix from parent pose
- /*bPoseChannel *parchan = BKE_pose_channel_find_name(ob_arm->pose, bone->parent->name);
- float invpar[4][4];
- invert_m4_m4(invpar, parchan->pose_mat);
- mul_m4_m4m4(mat, invpar, pchan->pose_mat);*/
-
- float invpar[4][4];
- invert_m4_m4(invpar, bone->parent->arm_mat);
- mul_m4_m4m4(mat, invpar, bone->arm_mat);
+ bool has_restmat = bc_get_property_matrix(bone, "rest_mat", mat);
- }
- else {
+ if (!has_restmat) {
+
+ /* Have no restpose matrix stored, try old style <= Blender 2.78 */
- //copy_m4_m4(mat, pchan->pose_mat);
- //pose mat is object space
- //New change: export bone->arm_mat
- copy_m4_m4(mat, bone->arm_mat);
- }
+ bc_create_restpose_mat(this->export_settings, bone, bone_rest_mat, bone->arm_mat, true);
- // OPEN_SIM_COMPATIBILITY
- if (export_settings->open_sim) {
- // Remove rotations vs armature from transform
- // parent_rest_rot * mat * irest_rot
- 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);
+ if (bone->parent) {
+ // get bone-space matrix from parent pose
+ /*bPoseChannel *parchan = BKE_pose_channel_find_name(ob_arm->pose, bone->parent->name);
+ float invpar[4][4];
+ invert_m4_m4(invpar, parchan->pose_mat);
+ mul_m4_m4m4(mat, invpar, pchan->pose_mat);*/
+ float invpar[4][4];
+ bc_create_restpose_mat(this->export_settings, bone->parent, parent_rest_mat, bone->parent->arm_mat, true);
- mul_m4_m4m4(mat, mat, temp);
+ invert_m4_m4(invpar, parent_rest_mat);
+ mul_m4_m4m4(mat, invpar, bone_rest_mat);
- if (bone->parent) {
- copy_m4_m4(temp, bone->parent->arm_mat);
+ }
+ else {
+ copy_m4_m4(mat, bone_rest_mat);
+ }
+
+ // OPEN_SIM_COMPATIBILITY
+ if (export_settings->open_sim) {
+ // Remove rotations vs armature from transform
+ // parent_rest_rot * mat * irest_rot
+ float temp[4][4];
+ copy_m4_m4(temp, bone_rest_mat);
temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
+ invert_m4(temp);
+
+ mul_m4_m4m4(mat, mat, temp);
- mul_m4_m4m4(mat, temp, mat);
+ if (bone->parent) {
+ copy_m4_m4(temp, parent_rest_mat);
+ temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
+
+ mul_m4_m4m4(mat, temp, mat);
+ }
}
}
+ if (this->export_settings->limit_precision)
+ bc_sanitize_mat(mat, 6);
+
TransformWriter::add_node_transform(node, mat, NULL);
+
}
std::string ArmatureExporter::get_controller_id(Object *ob_arm, Object *ob)
diff --git a/source/blender/collada/ArmatureExporter.h b/source/blender/collada/ArmatureExporter.h
index 883a6aca847..d271b505aa9 100644
--- a/source/blender/collada/ArmatureExporter.h
+++ b/source/blender/collada/ArmatureExporter.h
@@ -83,8 +83,6 @@ private:
void find_objects_using_armature(Object *ob_arm, std::vector<Object *>& objects, Scene *sce);
#endif
- std::string get_joint_sid(Bone *bone, Object *ob_arm);
-
// Scene, SceneExporter and the list of child_objects
// are required for writing bone parented objects
void add_bone_node(Bone *bone, Object *ob_arm, Scene *sce, SceneExporter *se,
diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp
index 1bc2bff74e3..9c8b8fc25d6 100644
--- a/source/blender/collada/ArmatureImporter.cpp
+++ b/source/blender/collada/ArmatureImporter.cpp
@@ -32,14 +32,18 @@
#include "COLLADAFWUniqueId.h"
+extern "C" {
#include "BKE_action.h"
-#include "BKE_depsgraph.h"
#include "BKE_object.h"
#include "BKE_armature.h"
#include "BLI_string.h"
#include "BLI_listbase.h"
#include "ED_armature.h"
+}
+
+#include "DEG_depsgraph.h"
+#include "collada_utils.h"
#include "ArmatureImporter.h"
// use node name, or fall back to original id if not present (name is optional)
@@ -52,23 +56,14 @@ static const char *bc_get_joint_name(T *node)
ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce, const ImportSettings *import_settings) :
- import_settings(import_settings),
+ TransformReader(conv),
+ scene(sce),
unit_converter(conv),
- TransformReader(conv),
- scene(sce),
+ import_settings(import_settings),
empty(NULL),
mesh_importer(mesh) {
}
-void ArmatureImporter::clear_extended_boneset()
-{
- for (std::map<std::string, BoneExtended *>::iterator it = extended_bones.begin(); it != extended_bones.end(); ++it) {
- if (it->second != NULL)
- delete it->second;
- }
- extended_bones.clear();
-}
-
ArmatureImporter::~ArmatureImporter()
{
// free skin controller data if we forget to do this earlier
@@ -76,7 +71,6 @@ ArmatureImporter::~ArmatureImporter()
for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) {
it->second.free();
}
- clear_extended_boneset();
}
#if 0
@@ -101,6 +95,7 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
{
float mat[4][4];
float joint_inv_bind_mat[4][4];
+ float joint_bind_mat[4][4];
int chain_length = 0;
//Checking if bone is already made.
@@ -116,7 +111,7 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
*/
std::map<COLLADAFW::UniqueId, SkinInfo>::iterator skin_it;
- bool bone_is_not_skinned = true;
+ bool bone_is_skinned = false;
for (skin_it = skin_by_data_uid.begin(); skin_it != skin_by_data_uid.end(); skin_it++) {
SkinInfo *b = &skin_it->second;
@@ -124,7 +119,7 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
// get original world-space matrix
invert_m4_m4(mat, joint_inv_bind_mat);
-
+ copy_m4_m4(joint_bind_mat, mat);
// And make local to armature
Object *ob_arm = skin->BKE_armature_from_object();
if (ob_arm) {
@@ -133,31 +128,21 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
mul_m4_m4m4(mat, invmat, mat);
}
- bone_is_not_skinned = false;
+ bone_is_skinned = true;
break;
}
}
// create a bone even if there's no joint data for it (i.e. it has no influence)
- if (bone_is_not_skinned) {
- float obmat[4][4];
- // bone-space
- get_node_mat(obmat, node, NULL, NULL);
-
- // get world-space
- if (parent) {
- mul_m4_m4m4(mat, parent_mat, obmat);
- }
- else {
- copy_m4_m4(mat, obmat);
- }
+ if (!bone_is_skinned) {
+ get_node_mat(mat, node, NULL, NULL, parent_mat);
}
if (parent) bone->parent = parent;
float loc[3], size[3], rot[3][3];
-
- BoneExtended &be = add_bone_extended(bone, node, totchild, layer_labels);
+ BoneExtensionMap &extended_bones = bone_extension_manager.getExtensionMap(arm);
+ BoneExtended &be = add_bone_extended(bone, node, totchild, layer_labels, extended_bones);
int layer = be.get_bone_layers();
if (layer) bone->layer = layer;
arm->layer |= layer; // ensure that all populated bone layers are visible after import
@@ -166,10 +151,11 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
int use_connect = be.get_use_connect();
switch (use_connect) {
- case 1: bone->flag |= BONE_CONNECTED;
- break;
- case 0: bone->flag &= ~BONE_CONNECTED;
- case -1: break; // not defined
+ case 1: bone->flag |= BONE_CONNECTED;
+ break;
+ case -1:/* Connect type not specified */
+ case 0: bone->flag &= ~BONE_CONNECTED;
+ break;
}
if (be.has_roll()) {
@@ -179,8 +165,18 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
float angle;
mat4_to_loc_rot_size(loc, rot, size, mat);
mat3_to_vec_roll(rot, NULL, &angle);
+ bone->roll = angle;
}
copy_v3_v3(bone->head, mat[3]);
+
+ if (bone_is_skinned)
+ {
+ float rest_mat[4][4];
+ get_node_mat(rest_mat, node, NULL, NULL, NULL);
+ bc_set_IDPropertyMatrix(bone, "bind_mat", joint_bind_mat);
+ bc_set_IDPropertyMatrix(bone, "rest_mat", rest_mat);
+ }
+
add_v3_v3v3(bone->tail, bone->head, tail); //tail must be non zero
/* find smallest bone length in armature (used later for leaf bone length) */
@@ -205,7 +201,6 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
chain_length = cl;
}
-
bone->length = len_v3v3(bone->head, bone->tail);
joint_by_uid[node->getUniqueId()] = node;
finished_joints.push_back(node);
@@ -221,43 +216,49 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
* tail locations for the affected bones (nodes which don't have any connected child)
* Hint: The extended_bones set gets populated in ArmatureImporter::create_bone
**/
-void ArmatureImporter::fix_leaf_bones(bArmature *armature, Bone *bone)
+void ArmatureImporter::fix_leaf_bone_hierarchy(bArmature *armature, Bone *bone, bool fix_orientation)
{
if (bone == NULL)
return;
if (bc_is_leaf_bone(bone)) {
-
+ BoneExtensionMap &extended_bones = bone_extension_manager.getExtensionMap(armature);
BoneExtended *be = extended_bones[bone->name];
- if (be == NULL || !be->has_tail()) {
+ EditBone *ebone = bc_get_edit_bone(armature, bone->name);
+ fix_leaf_bone(armature, ebone, be, fix_orientation);
+ }
+
+ for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
+ fix_leaf_bone_hierarchy(armature, child, fix_orientation);
+ }
+}
- /* Collada only knows Joints, Here we guess a reasonable leaf bone length */
- float leaf_length = (leaf_bone_length == FLT_MAX) ? 1.0 : leaf_bone_length;
+void ArmatureImporter::fix_leaf_bone(bArmature *armature, EditBone *ebone, BoneExtended *be , bool fix_orientation)
+{
+ if (be == NULL || !be->has_tail()) {
- EditBone *ebone = bc_get_edit_bone(armature, bone->name);
- float vec[3];
+ /* Collada only knows Joints, Here we guess a reasonable leaf bone length */
+ float leaf_length = (leaf_bone_length == FLT_MAX) ? 1.0 : leaf_bone_length;
- if (ebone->parent != NULL) {
- EditBone *parent = ebone->parent;
- sub_v3_v3v3(vec, ebone->head, parent->head);
- if (len_squared_v3(vec) < MINIMUM_BONE_LENGTH)
- {
- sub_v3_v3v3(vec, parent->tail, parent->head);
- }
- }
- else {
- vec[2] = 0.1f;
- sub_v3_v3v3(vec, ebone->tail, ebone->head);
- }
- normalize_v3_v3(vec, vec);
- mul_v3_fl(vec, leaf_length);
- add_v3_v3v3(ebone->tail, ebone->head, vec);
+ float vec[3];
+
+ if (fix_orientation && ebone->parent != NULL) {
+ EditBone *parent = ebone->parent;
+ sub_v3_v3v3(vec, ebone->head, parent->head);
+ if (len_squared_v3(vec) < MINIMUM_BONE_LENGTH)
+ {
+ sub_v3_v3v3(vec, parent->tail, parent->head);
+ }
+ }
+ else {
+ vec[2] = 0.1f;
+ sub_v3_v3v3(vec, ebone->tail, ebone->head);
}
- }
- for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
- fix_leaf_bones(armature, child);
+ normalize_v3_v3(vec, vec);
+ mul_v3_fl(vec, leaf_length);
+ add_v3_v3v3(ebone->tail, ebone->head, vec);
}
}
@@ -277,9 +278,9 @@ void ArmatureImporter::fix_parent_connect(bArmature *armature, Bone *bone)
}
-
void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone, int clip)
{
+ BoneExtensionMap &extended_bones = bone_extension_manager.getExtensionMap(armature);
BoneExtended *dominant_child = NULL;
int maxlen = 0;
Bone *child;
@@ -292,12 +293,13 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone
for (; child; child = child->next) {
BoneExtended *be = extended_bones[child->name];
if (be != NULL) {
- if (be->get_chain_length() <= clip) {
- if (be->get_chain_length() > maxlen) {
+ int chain_len = be->get_chain_length();
+ if (chain_len <= clip) {
+ if (chain_len > maxlen) {
dominant_child = be;
- maxlen = be->get_chain_length();
+ maxlen = chain_len;
}
- else if (be->get_chain_length() == maxlen) {
+ else if (chain_len == maxlen) {
dominant_child = NULL;
}
}
@@ -311,7 +313,6 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone
EditBone *pebone = bc_get_edit_bone(armature, parentbone->name);
EditBone *cebone = bc_get_edit_bone(armature, dominant_child->get_name());
if (pebone && !(cebone->flag & BONE_CONNECTED)) {
-
float vec[3];
sub_v3_v3v3(vec, cebone->head, pebone->head);
@@ -324,14 +325,16 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone
if (len_squared_v3(vec) > MINIMUM_BONE_LENGTH)
{
- pebone->tail[0] = cebone->head[0];
- pebone->tail[1] = cebone->head[1];
- pebone->tail[2] = cebone->head[2];
-
+ copy_v3_v3(pebone->tail, cebone->head);
+ pbe->set_tail(pebone->tail); /* to make fix_leafbone happy ...*/
if (pbe && pbe->get_chain_length() >= this->import_settings->min_chain_length) {
+
+ BoneExtended *cbe = extended_bones[cebone->name];
+ cbe->set_use_connect(true);
+
cebone->flag |= BONE_CONNECTED;
- printf("Connecting chain: parent %s --> %s (child)\n", pebone->name, cebone->name);
pbe->set_leaf_bone(false);
+ printf("Connect Bone chain: parent (%s --> %s) child)\n", pebone->name, cebone->name);
}
}
}
@@ -445,11 +448,10 @@ ArmatureJoints& ArmatureImporter::get_armature_joints(Object *ob_arm)
return armature_joints.back();
}
#endif
-Object *ArmatureImporter::create_armature_bones(std::vector<Object *> &ob_arms)
+void ArmatureImporter::create_armature_bones(std::vector<Object *> &ob_arms)
{
std::vector<COLLADAFW::Node *>::iterator ri;
std::vector<std::string> layer_labels;
- Object *ob_arm = NULL;
//if there is an armature created for root_joint next root_joint
for (ri = root_joints.begin(); ri != root_joints.end(); ri++) {
@@ -470,15 +472,23 @@ Object *ArmatureImporter::create_armature_bones(std::vector<Object *> &ob_arms)
continue;
}
- clear_extended_boneset();
-
ED_armature_to_edit(armature);
armature->layer = 0; // layer is set according to imported bone set in create_bone()
create_bone(NULL, *ri , NULL, (*ri)->getChildNodes().getCount(), NULL, armature, layer_labels);
+ if (this->import_settings->find_chains) {
+ connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX);
+ }
/* exit armature edit mode to populate the Armature object */
+ ED_armature_from_edit(armature);
+ ED_armature_edit_free(armature);
+
+ ED_armature_to_edit(armature);
+
+ fix_leaf_bone_hierarchy(armature, (Bone *)armature->bonebase.first, this->import_settings->fix_orientation);
unskinned_armature_map[(*ri)->getUniqueId()] = ob_arm;
+
ED_armature_from_edit(armature);
ED_armature_edit_free(armature);
@@ -487,9 +497,8 @@ Object *ArmatureImporter::create_armature_bones(std::vector<Object *> &ob_arms)
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);
}
- return ob_arm;
}
Object *ArmatureImporter::create_armature_bones(SkinInfo& skin)
@@ -584,8 +593,6 @@ Object *ArmatureImporter::create_armature_bones(SkinInfo& skin)
bArmature * armature = (bArmature *)ob_arm->data;
ED_armature_to_edit(armature);
- clear_extended_boneset();
-
totbone = 0;
// bone_direction_row = 1; // TODO: don't default to Y but use asset and based on it decide on default row
@@ -615,7 +622,15 @@ Object *ArmatureImporter::create_armature_bones(SkinInfo& skin)
ED_armature_from_edit(armature);
ED_armature_edit_free(armature);
- DAG_id_tag_update(&ob_arm->id, OB_RECALC_OB | OB_RECALC_DATA);
+ ED_armature_to_edit(armature);
+ if (this->import_settings->find_chains) {
+ connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX);
+ }
+ fix_leaf_bone_hierarchy(armature, (Bone *)armature->bonebase.first, this->import_settings->fix_orientation);
+ ED_armature_from_edit(armature);
+ ED_armature_edit_free(armature);
+
+ DEG_id_tag_update(&ob_arm->id, OB_RECALC_OB | OB_RECALC_DATA);
return ob_arm;
}
@@ -756,18 +771,6 @@ void ArmatureImporter::make_armatures(bContext *C, std::vector<Object *> &object
/* and step back to edit mode to fix the leaf nodes */
ED_armature_to_edit(armature);
- if (this->import_settings->fix_orientation || this->import_settings->find_chains) {
-
- if (this->import_settings->find_chains)
- connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX);
-
- if (this->import_settings->fix_orientation)
- fix_leaf_bones(armature, (Bone *)armature->bonebase.first);
-
- // exit armature edit mode
-
- }
-
fix_parent_connect(armature, (Bone *)armature->bonebase.first);
ED_armature_from_edit(armature);
@@ -959,7 +962,7 @@ bool ArmatureImporter::get_joint_bind_mat(float m[4][4], COLLADAFW::Node *joint)
return found;
}
-BoneExtended &ArmatureImporter::add_bone_extended(EditBone *bone, COLLADAFW::Node *node, int sibcount, std::vector<std::string> &layer_labels)
+BoneExtended &ArmatureImporter::add_bone_extended(EditBone *bone, COLLADAFW::Node *node, int sibcount, std::vector<std::string> &layer_labels, BoneExtensionMap &extended_bones)
{
BoneExtended *be = new BoneExtended(bone);
extended_bones[bone->name] = be;
diff --git a/source/blender/collada/ArmatureImporter.h b/source/blender/collada/ArmatureImporter.h
index e006ccbc94a..17173f157e5 100644
--- a/source/blender/collada/ArmatureImporter.h
+++ b/source/blender/collada/ArmatureImporter.h
@@ -68,8 +68,7 @@ private:
// std::map<int, JointData> joint_index_to_joint_info_map;
// std::map<COLLADAFW::UniqueId, int> joint_id_to_joint_index_map;
-
- std::map<std::string, BoneExtended *> extended_bones;
+ BoneExtensionManager bone_extension_manager;
// int bone_direction_row; // XXX not used
float leaf_bone_length;
int totbone;
@@ -108,16 +107,15 @@ private:
int create_bone(SkinInfo* skin, COLLADAFW::Node *node, EditBone *parent, int totchild,
float parent_mat[4][4], bArmature *arm, std::vector<std::string> &layer_labels);
- BoneExtended &add_bone_extended(EditBone *bone, COLLADAFW::Node * node, int sibcount, std::vector<std::string> &layer_labels);
- void clear_extended_boneset();
+ BoneExtended &add_bone_extended(EditBone *bone, COLLADAFW::Node * node, int sibcount, std::vector<std::string> &layer_labels, BoneExtensionMap &extended_bones);
- void fix_leaf_bones(bArmature *armature, Bone *bone);
+ void fix_leaf_bone_hierarchy(bArmature *armature, Bone *bone, bool fix_orientation);
+ void fix_leaf_bone(bArmature *armature, EditBone *ebone, BoneExtended *be, bool fix_orientation);
void fix_parent_connect(bArmature *armature, Bone *bone);
void connect_bone_chains(bArmature *armature, Bone *bone, const int max_chain_length);
void set_pose( Object *ob_arm, COLLADAFW::Node *root_node, const char *parentname, float parent_mat[4][4]);
-
#if 0
void set_leaf_bone_shapes(Object *ob_arm);
void set_euler_rotmode();
@@ -132,7 +130,7 @@ private:
#endif
Object *create_armature_bones(SkinInfo& skin);
- Object *create_armature_bones(std::vector<Object *> &arm_objs);
+ void create_armature_bones(std::vector<Object *> &arm_objs);
/** TagsMap typedef for uid_tags_map. */
typedef std::map<std::string, ExtraTags*> TagsMap;
diff --git a/source/blender/collada/CMakeLists.txt b/source/blender/collada/CMakeLists.txt
index 293049a1a05..8642bbee698 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
diff --git a/source/blender/collada/ControllerExporter.cpp b/source/blender/collada/ControllerExporter.cpp
index 06e151c363b..1c2642e8313 100644
--- a/source/blender/collada/ControllerExporter.cpp
+++ b/source/blender/collada/ControllerExporter.cpp
@@ -157,11 +157,6 @@ void ArmatureExporter::find_objects_using_armature(Object *ob_arm, std::vector<O
}
#endif
-std::string ControllerExporter::get_joint_sid(Bone *bone, Object *ob_arm)
-{
- return get_joint_id(bone, ob_arm);
-}
-
std::string ControllerExporter::get_controller_id(Object *ob_arm, Object *ob)
{
return translate_id(id_name(ob_arm)) + "_" + translate_id(id_name(ob)) + SKIN_CONTROLLER_ID_SUFFIX;
@@ -468,81 +463,6 @@ std::string ControllerExporter::add_joints_source(Object *ob_arm, ListBase *defb
return source_id;
}
-static float get_property(Bone *bone, const char *key, float def)
-{
- float result = def;
- if (bone->prop) {
- IDProperty *property = IDP_GetPropertyFromGroup(bone->prop, key);
- if (property) {
- switch (property->type) {
- case IDP_INT:
- result = (float)(IDP_Int(property));
- break;
- case IDP_FLOAT:
- result = (float)(IDP_Float(property));
- break;
- case IDP_DOUBLE:
- result = (float)(IDP_Double(property));
- break;
- default:
- result = def;
- }
- }
- }
- return result;
-}
-
-/**
- * This function creates an arbitrary rest pose matrix from
- * data provided as custom properties. This is a workaround
- * for support of maya's restpose matrix which can be arbitrary
- * in opposition to Blender where the Rest pose Matrix is always
- * the Identity matrix.
- *
- * The custom properties are:
- *
- * restpose_scale_x
- * restpose_scale_y
- * restpose_scale_z
- *
- * restpose_rot_x
- * restpose_rot_y
- * restpose_rot_z
- *
- * restpose_loc_x
- * restpose_loc_y
- * restpose_loc_z
- *
- * The matrix is only setup if the scale AND the rot properties are defined.
- * The presence of the loc properties is optional.
- *
- * This feature has been implemented to support Second Life "Fitted Mesh"
- * TODO: Check if an arbitrary rest pose matrix makes sense within Blender.
- * Eventually leverage the custom property data into an "official"
- * Edit_bone Property
- */
-static void create_restpose_mat(Bone *bone, float mat[4][4])
-{
- float loc[3] = {
- get_property(bone, "restpose_loc_x", 0.0),
- get_property(bone, "restpose_loc_y", 0.0),
- get_property(bone, "restpose_loc_z", 0.0)
- };
-
- float rot[3] = {
- DEG2RADF(get_property(bone, "restpose_rot_x", 0.0)),
- DEG2RADF(get_property(bone, "restpose_rot_y", 0.0)),
- DEG2RADF(get_property(bone, "restpose_rot_z", 0.0))
- };
-
- float scale[3] = {
- get_property(bone, "restpose_scale_x", 1.0),
- get_property(bone, "restpose_scale_y", 1.0),
- get_property(bone, "restpose_scale_z", 1.0)
- };
-
- loc_eulO_size_to_mat4(mat, loc, rot, scale, 6);
-}
std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id)
{
@@ -585,30 +505,36 @@ std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, ListBas
float world[4][4];
float inv_bind_mat[4][4];
+ float bind_mat[4][4]; /* derived from bone->arm_mat */
+
+ bool has_bindmat = bc_get_property_matrix(pchan->bone, "bind_mat", bind_mat);
- // SL/OPEN_SIM COMPATIBILITY
- if (export_settings->open_sim) {
- // Only translations, no rotation vs armature
- float temp[4][4];
- unit_m4(temp);
- copy_v3_v3(temp[3], pchan->bone->arm_mat[3]);
- mul_m4_m4m4(world, ob_arm->obmat, temp);
-
- // Add Maya restpose matrix (if defined as properties)
- float restpose_mat[4][4];
- create_restpose_mat(pchan->bone, restpose_mat);
- mul_m4_m4m4(world, world, restpose_mat);
+ if (!has_bindmat) {
- }
- else {
- // make world-space matrix, arm_mat is armature-space
- mul_m4_m4m4(world, ob_arm->obmat, pchan->bone->arm_mat);
+ /* Have no bind matrix stored, try old style <= Blender 2.78 */
+
+ bc_create_restpose_mat(this->export_settings, pchan->bone, bind_mat, pchan->bone->arm_mat, true);
+
+ // SL/OPEN_SIM COMPATIBILITY
+ if (export_settings->open_sim) {
+
+ float loc[3];
+ float rot[3] = { 0, 0, 0 };
+ float scale[3];
+ bc_decompose(bind_mat, loc, NULL, NULL, scale);
+
+ // Only translations, no rotation vs armature
+ loc_eulO_size_to_mat4(bind_mat, loc, rot, scale, 6);
+ }
}
+ // make world-space matrix (bind_mat is armature-space)
+ mul_m4_m4m4(world, ob_arm->obmat, bind_mat);
invert_m4_m4(mat, world);
converter.mat4_to_dae(inv_bind_mat, mat);
-
+ if (this->export_settings->limit_precision)
+ bc_sanitize_mat(inv_bind_mat, 6);
source.appendValues(inv_bind_mat);
}
}
diff --git a/source/blender/collada/ControllerExporter.h b/source/blender/collada/ControllerExporter.h
index 0be51187f6f..80b858ca6dd 100644
--- a/source/blender/collada/ControllerExporter.h
+++ b/source/blender/collada/ControllerExporter.h
@@ -84,8 +84,6 @@ private:
void find_objects_using_armature(Object *ob_arm, std::vector<Object *>& objects, Scene *sce);
#endif
- std::string get_joint_sid(Bone *bone, Object *ob_arm);
-
std::string get_controller_id(Object *ob_arm, Object *ob);
std::string get_controller_id(Key *key, Object *ob);
diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp
index 226f319cefd..2d428d6fe5d 100644
--- a/source/blender/collada/DocumentImporter.cpp
+++ b/source/blender/collada/DocumentImporter.cpp
@@ -57,12 +57,12 @@ extern "C" {
#include "BLI_fileops.h"
#include "BKE_camera.h"
+#include "BKE_collection.h"
#include "BKE_main.h"
#include "BKE_lamp.h"
#include "BKE_library.h"
#include "BKE_texture.h"
#include "BKE_fcurve.h"
-#include "BKE_depsgraph.h"
#include "BKE_scene.h"
#include "BKE_global.h"
#include "BKE_material.h"
@@ -82,6 +82,9 @@ extern "C" {
}
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "ExtraHandler.h"
#include "ErrorHandler.h"
#include "DocumentImporter.h"
@@ -230,7 +233,7 @@ void DocumentImporter::finish()
}
// update scene
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(mContext, NC_OBJECT | ND_TRANSFORM, NULL);
}
@@ -241,7 +244,7 @@ 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();
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
#if 0
armature_importer.fix_animation();
@@ -264,7 +267,7 @@ void DocumentImporter::finish()
for (it = libnode_ob.begin(); it != libnode_ob.end(); it++) {
Object *ob = *it;
- Base *base = BKE_scene_base_find(sce, ob);
+ BaseLegacy *base = (BaseLegacy *)BKE_scene_base_find(sce, ob);
if (base) {
BLI_remlink(&sce->base, base);
BKE_libblock_free_us(G.main, base->object);
@@ -275,7 +278,7 @@ void DocumentImporter::finish()
}
libnode_ob.clear();
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
}
bc_match_scale(objects_to_scale, unit_converter, !this->import_settings->import_units);
@@ -388,9 +391,7 @@ Object *DocumentImporter::create_camera_object(COLLADAFW::InstanceCamera *camera
Camera *cam = uid_camera_map[cam_uid];
Camera *old_cam = (Camera *)ob->data;
ob->data = cam;
- id_us_min(&old_cam->id);
- if (old_cam->id.us == 0)
- BKE_libblock_free(G.main, old_cam);
+ BKE_libblock_free_us(G.main, old_cam);
return ob;
}
@@ -406,9 +407,7 @@ Object *DocumentImporter::create_lamp_object(COLLADAFW::InstanceLight *lamp, Sce
Lamp *la = uid_lamp_map[lamp_uid];
Lamp *old_lamp = (Lamp *)ob->data;
ob->data = la;
- id_us_min(&old_lamp->id);
- if (old_lamp->id.us == 0)
- BKE_libblock_free(G.main, old_lamp);
+ BKE_libblock_free_us(G.main, old_lamp);
return ob;
}
@@ -417,8 +416,8 @@ Object *DocumentImporter::create_instance_node(Object *source_ob, COLLADAFW::Nod
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);
Object *obn = BKE_object_copy(G.main, 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(sce, source_ob, obn);
if (instance_node) {
anim_importer.read_node_transform(instance_node, obn);
diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp
index 76b51148509..978d79077fe 100644
--- a/source/blender/collada/EffectExporter.cpp
+++ b/source/blender/collada/EffectExporter.cpp
@@ -66,7 +66,7 @@ EffectsExporter::EffectsExporter(COLLADASW::StreamWriter *sw, const ExportSettin
bool EffectsExporter::hasEffects(Scene *sce)
{
- Base *base = (Base *)sce->base.first;
+ BaseLegacy *base = (BaseLegacy *)sce->base.first;
while (base) {
Object *ob = base->object;
@@ -311,58 +311,6 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
}
}
- int active_uv_layer = -1;
- std::set<Image *> uv_textures;
- if (ob->type == OB_MESH && ob->totcol && this->export_settings->include_uv_textures) {
- bool active_uv_only = this->export_settings->active_uv_only;
- Mesh *me = (Mesh *) ob->data;
- active_uv_layer = CustomData_get_active_layer_index(&me->pdata, CD_MTEXPOLY);
-
- BKE_mesh_tessface_ensure(me);
- for (int i = 0; i < me->pdata.totlayer; i++) {
- if (!active_uv_only || 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++) {
-
- Material *mat = give_current_material(ob, mpoly->mat_nr + 1);
- if (mat != ma)
- continue;
-
- Image *ima = txface->tpage;
- if (ima == NULL)
- continue;
-
-
- bool not_in_list = uv_textures.find(ima)==uv_textures.end();
- if (not_in_list) {
- std::string name = id_name(ima);
- std::string key(name);
- key = translate_id(key);
-
- // create only one <sampler>/<surface> pair for each unique image
- if (im_samp_map.find(key) == im_samp_map.end()) {
- //<newparam> <sampler> <source>
- COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D,
- key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
- key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
- sampler.setImageId(key);
- samplers[a] = sampler;
- samp_surf[b] = &samplers[a];
- im_samp_map[key] = b;
- b++;
- a++;
- uv_textures.insert(ima);
- }
- }
- }
- }
- }
- }
- }
-
// 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(getActiveUVLayerName(ob));
@@ -385,19 +333,6 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
writeTextures(ep, key, sampler, t, ima, uvname);
}
- std::set<Image *>::iterator uv_t_iter;
- int idx;
- for (idx = 0, uv_t_iter = uv_textures.begin(); uv_t_iter != uv_textures.end(); uv_t_iter++, idx++ ) {
- if (active_uv_layer>-1 && idx==active_uv_layer) {
- Image *ima = *uv_t_iter;
- std::string key(id_name(ima));
- key = translate_id(key);
- int i = im_samp_map[key];
- COLLADASW::Sampler *sampler = (COLLADASW::Sampler *)samp_surf[i];
- ep.setDiffuse(createTexture(ima, active_uv, sampler), false, "diffuse");
- }
- }
-
// performs the actual writing
ep.addProfileElements();
bool twoSided = false;
diff --git a/source/blender/collada/ErrorHandler.cpp b/source/blender/collada/ErrorHandler.cpp
index 98aa85f8a9b..32aa5636e08 100644
--- a/source/blender/collada/ErrorHandler.cpp
+++ b/source/blender/collada/ErrorHandler.cpp
@@ -49,7 +49,7 @@ ErrorHandler::~ErrorHandler()
//--------------------------------------------------------------------
bool ErrorHandler::handleError(const COLLADASaxFWL::IError *error)
{
- bool isError = true;
+ bool isError = false;
if (error->getErrorClass() == COLLADASaxFWL::IError::ERROR_SAXPARSER) {
COLLADASaxFWL::SaxParserError *saxParserError = (COLLADASaxFWL::SaxParserError *) error;
@@ -81,10 +81,7 @@ bool ErrorHandler::handleError(const COLLADASaxFWL::IError *error)
* Accept non critical errors as warnings (i.e. texture not found)
* This makes the importer more graceful, so it now imports what makes sense.
*/
- if (saxFWLError->getSeverity() == COLLADASaxFWL::IError::SEVERITY_ERROR_NONCRITICAL) {
- isError = false;
- }
-
+ isError = (saxFWLError->getSeverity() != COLLADASaxFWL::IError::SEVERITY_ERROR_NONCRITICAL);
std::cout << "Sax FWL Error: " << saxFWLError->getErrorMessage() << std::endl;
}
else {
@@ -93,5 +90,5 @@ bool ErrorHandler::handleError(const COLLADASaxFWL::IError *error)
mError |= isError;
- return false; // let OpenCollada decide when to abort
+ return isError; // let OpenCollada decide when to abort
}
diff --git a/source/blender/collada/ExportSettings.h b/source/blender/collada/ExportSettings.h
index 9451cac9dae..33a7527f383 100644
--- a/source/blender/collada/ExportSettings.h
+++ b/source/blender/collada/ExportSettings.h
@@ -42,7 +42,6 @@ public:
bool deform_bones_only;
bool active_uv_only;
- bool include_uv_textures;
bool include_material_textures;
bool use_texture_copies;
@@ -51,7 +50,10 @@ public:
bool use_blender_profile;
bool sort_by_name;
BC_export_transformation_type export_transformation_type;
+
bool open_sim;
+ bool limit_precision;
+ bool keep_bind_info;
char *filepath;
LinkNode *export_set;
diff --git a/source/blender/collada/ImageExporter.cpp b/source/blender/collada/ImageExporter.cpp
index aac41e2e93c..a2ab3ce520b 100644
--- a/source/blender/collada/ImageExporter.cpp
+++ b/source/blender/collada/ImageExporter.cpp
@@ -152,44 +152,6 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies)
}
}
-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 && ob->totcol) {
- 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);
- }
- }
- }
- }
- }
- }
- }
-}
-
-
bool ImagesExporter::hasImages(Scene *sce)
{
LinkNode *node;
@@ -209,20 +171,6 @@ bool ImagesExporter::hasImages(Scene *sce)
}
}
- 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;
}
@@ -236,10 +184,6 @@ void ImagesExporter::exportImages(Scene *sce)
mf.forEachMaterialInExportSet<ImagesExporter>(sce, *this, this->export_settings->export_set);
}
- if (this->export_settings->include_uv_textures) {
- export_UV_Images();
- }
-
closeLibrary();
}
diff --git a/source/blender/collada/ImageExporter.h b/source/blender/collada/ImageExporter.h
index 0eaebdd5cdd..f3dd2b336e4 100644
--- a/source/blender/collada/ImageExporter.h
+++ b/source/blender/collada/ImageExporter.h
@@ -51,7 +51,6 @@ public:
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);
const ExportSettings *export_settings;
diff --git a/source/blender/collada/ImportSettings.h b/source/blender/collada/ImportSettings.h
index 2c52d73e756..4a2d4e8046a 100644
--- a/source/blender/collada/ImportSettings.h
+++ b/source/blender/collada/ImportSettings.h
@@ -37,6 +37,7 @@ public:
bool fix_orientation;
int min_chain_length;
char *filepath;
+ bool keep_bind_info;
};
#endif
diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp
index 6ff6de33d56..9c95d4de695 100644
--- a/source/blender/collada/MeshImporter.cpp
+++ b/source/blender/collada/MeshImporter.cpp
@@ -27,7 +27,7 @@
#include <algorithm>
-#if !defined(WIN32) || defined(FREE_WINDOWS)
+#if !defined(WIN32)
#include <iostream>
#endif
@@ -317,11 +317,6 @@ bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh) // checks if mesh has su
}
}
- if (mesh->getPositions().empty()) {
- fprintf(stderr, "ERROR: Mesh %s has no vertices.\n", name.c_str());
- return false;
- }
-
return true;
}
@@ -329,11 +324,15 @@ void MeshImporter::read_vertices(COLLADAFW::Mesh *mesh, Mesh *me)
{
// vertices
COLLADAFW::MeshVertexData& pos = mesh->getPositions();
+ if (pos.empty()) {
+ return;
+ }
+
int stride = pos.getStride(0);
if (stride == 0) stride = 3;
-
- me->totvert = mesh->getPositions().getFloatValues()->getCount() / stride;
- me->mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert);
+
+ me->totvert = pos.getFloatValues()->getCount() / stride;
+ me->mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert);
MVert *mvert;
int i;
@@ -473,11 +472,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);
}
@@ -1052,11 +1049,11 @@ 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,
+ std::map<Material *, TexIndexTextureArrayMap>& material_texture_mapping_map, short mat_index)
{
MTex *color_texture = NULL;
Mesh *me = (Mesh *)ob->data;
@@ -1066,7 +1063,7 @@ MTFace *MeshImporter::assign_material_to_geom(COLLADAFW::MaterialBinding cmateri
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.
@@ -1090,15 +1087,6 @@ MTFace *MeshImporter::assign_material_to_geom(COLLADAFW::MaterialBinding cmateri
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();
@@ -1115,15 +1103,9 @@ MTFace *MeshImporter::assign_material_to_geom(COLLADAFW::MaterialBinding cmateri
for (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,
@@ -1174,12 +1156,9 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta
BKE_mesh_assign_object(ob, new_mesh);
BKE_mesh_calc_normals(new_mesh);
- if (old_mesh->id.us == 0) BKE_libblock_free(G.main, old_mesh);
-
- char layername[100];
- layername[0] = '\0';
- MTFace *texture_face = NULL;
-
+ id_us_plus(&old_mesh->id); /* Because BKE_mesh_assign_object would have already decreased it... */
+ BKE_libblock_free_us(G.main, old_mesh);
+
COLLADAFW::MaterialBindingArray& mat_array =
geom->getMaterialBindings();
@@ -1187,9 +1166,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,
+ material_texture_mapping_map, 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 d6426fbaf56..e8ae934a393 100644
--- a/source/blender/collada/MeshImporter.h
+++ b/source/blender/collada/MeshImporter.h
@@ -171,11 +171,11 @@ public:
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,
+ std::map<Material*, TexIndexTextureArrayMap>& material_texture_mapping_map, short mat_index);
Object *create_mesh_object(COLLADAFW::Node *node, COLLADAFW::InstanceGeometry *geom,
diff --git a/source/blender/collada/SkinInfo.cpp b/source/blender/collada/SkinInfo.cpp
index 7242a24523c..c29f1748efc 100644
--- a/source/blender/collada/SkinInfo.cpp
+++ b/source/blender/collada/SkinInfo.cpp
@@ -27,7 +27,7 @@
#include <algorithm>
-#if !defined(WIN32) || defined(FREE_WINDOWS)
+#if !defined(WIN32)
#include <stdint.h>
#endif
@@ -230,7 +230,6 @@ void SkinInfo::link_armature(bContext *C, Object *ob, std::map<COLLADAFW::Unique
ModifierData *md = ED_object_modifier_add(NULL, bmain, scene, ob, NULL, eModifierType_Armature);
ArmatureModifierData *amd = (ArmatureModifierData *)md;
amd->object = ob_arm;
- struct bArmature *armature = (bArmature *)ob_arm->data;
#if 1
bc_set_parent(ob, ob_arm, C);
@@ -242,9 +241,9 @@ 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);
+ DEG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA);
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
#endif
copy_m4_m4(ob->obmat, bind_shape_matrix);
diff --git a/source/blender/collada/TransformReader.cpp b/source/blender/collada/TransformReader.cpp
index f8f31304d28..7f742be7e30 100644
--- a/source/blender/collada/TransformReader.cpp
+++ b/source/blender/collada/TransformReader.cpp
@@ -34,7 +34,21 @@ TransformReader::TransformReader(UnitConverter *conv) : unit_converter(conv)
/* pass */
}
-void TransformReader::get_node_mat(float mat[4][4], COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, Animation> *animation_map, Object *ob)
+void TransformReader::get_node_mat(
+ float mat[4][4],
+ COLLADAFW::Node *node,
+ std::map<COLLADAFW::UniqueId, Animation> *animation_map,
+ Object *ob)
+{
+ get_node_mat(mat, node, animation_map, ob, NULL);
+}
+
+void TransformReader::get_node_mat(
+ float mat[4][4],
+ COLLADAFW::Node *node,
+ std::map<COLLADAFW::UniqueId, Animation> *animation_map,
+ Object *ob,
+ float parent_mat[4][4])
{
float cur[4][4];
float copy[4][4];
@@ -52,6 +66,9 @@ void TransformReader::get_node_mat(float mat[4][4], COLLADAFW::Node *node, std::
// then this is considered as redundant information.
// So if we find a Matrix we use that and return.
dae_matrix_to_mat4(tm, mat);
+ if (parent_mat) {
+ mul_m4_m4m4(mat, parent_mat, mat);
+ }
return;
case COLLADAFW::Transformation::TRANSLATE:
dae_translate_to_mat4(tm, cur);
@@ -80,6 +97,10 @@ void TransformReader::get_node_mat(float mat[4][4], COLLADAFW::Node *node, std::
(*animation_map)[anim_list_id] = anim;
}
}
+
+ if (parent_mat) {
+ mul_m4_m4m4(mat, parent_mat, mat);
+ }
}
void TransformReader::dae_rotate_to_mat4(COLLADAFW::Transformation *tm, float m[4][4])
diff --git a/source/blender/collada/TransformReader.h b/source/blender/collada/TransformReader.h
index ab974b9ba85..08bb17ccac1 100644
--- a/source/blender/collada/TransformReader.h
+++ b/source/blender/collada/TransformReader.h
@@ -43,7 +43,7 @@
//struct Object;
-class TransformReader : public TransformBase
+class TransformReader
{
protected:
@@ -59,7 +59,8 @@ public:
TransformReader(UnitConverter *conv);
void get_node_mat(float mat[4][4], COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, Animation> *animation_map, Object *ob);
-
+ void get_node_mat(float mat[4][4], COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, Animation> *animation_map, Object *ob, float parent_mat[4][4]);
+
void dae_rotate_to_mat4(COLLADAFW::Transformation *tm, float m[4][4]);
void dae_translate_to_mat4(COLLADAFW::Transformation *tm, float m[4][4]);
void dae_scale_to_mat4(COLLADAFW::Transformation *tm, float m[4][4]);
diff --git a/source/blender/collada/TransformWriter.cpp b/source/blender/collada/TransformWriter.cpp
index e205608a365..b7eeff3b074 100644
--- a/source/blender/collada/TransformWriter.cpp
+++ b/source/blender/collada/TransformWriter.cpp
@@ -27,11 +27,10 @@
#include "BKE_object.h"
+#include "BLI_math.h"
#include "TransformWriter.h"
-#include "BLI_math.h"
-
void TransformWriter::add_node_transform(COLLADASW::Node& node, float mat[4][4], float parent_mat[4][4])
{
float loc[3], rot[3], scale[3];
@@ -49,8 +48,9 @@ void TransformWriter::add_node_transform(COLLADASW::Node& node, float mat[4][4],
double dmat[4][4];
UnitConverter *converter = new UnitConverter();
converter->mat4_to_dae_double(dmat, local);
+ delete converter;
- TransformBase::decompose(local, loc, rot, NULL, scale);
+ bc_decompose(local, loc, rot, NULL, scale);
if (node.getType() == COLLADASW::Node::JOINT) {
// XXX Why are joints handled differently ?
@@ -112,15 +112,10 @@ void TransformWriter::add_node_transform_ob(COLLADASW::Node& node, Object *ob, B
node.addMatrix("transform",d_obmat);
break;
}
- case BC_TRANSFORMATION_TYPE_BOTH:
- {
- node.addMatrix("transform",d_obmat);
- /* fall-through */
- }
case BC_TRANSFORMATION_TYPE_TRANSROTLOC:
{
float loc[3], rot[3], scale[3];
- TransformBase::decompose(f_obmat, loc, rot, NULL, scale);
+ bc_decompose(f_obmat, loc, rot, NULL, scale);
add_transform(node, loc, rot, scale);
break;
}
diff --git a/source/blender/collada/TransformWriter.h b/source/blender/collada/TransformWriter.h
index 7f69a4b9c95..5bb13d4aac9 100644
--- a/source/blender/collada/TransformWriter.h
+++ b/source/blender/collada/TransformWriter.h
@@ -33,9 +33,10 @@
#include "DNA_object_types.h"
#include "collada_internal.h"
+#include "collada_utils.h"
#include "collada.h"
-class TransformWriter : protected TransformBase
+class TransformWriter
{
protected:
void add_node_transform(COLLADASW::Node& node, float mat[4][4], float parent_mat[4][4]);
diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp
index fe8b1d2320a..9cb0b414721 100644
--- a/source/blender/collada/collada.cpp
+++ b/source/blender/collada/collada.cpp
@@ -48,7 +48,8 @@ int collada_import(bContext *C,
int find_chains,
int auto_connect,
int fix_orientation,
- int min_chain_length)
+ int min_chain_length,
+ int keep_bind_info)
{
ImportSettings import_settings;
@@ -58,6 +59,7 @@ int collada_import(bContext *C,
import_settings.find_chains = find_chains != 0;
import_settings.fix_orientation = fix_orientation != 0;
import_settings.min_chain_length = min_chain_length;
+ import_settings.keep_bind_info = keep_bind_info !=0;
DocumentImporter imp(C, &import_settings);
if (imp.import()) return 1;
@@ -66,6 +68,7 @@ int collada_import(bContext *C,
}
int collada_export(Scene *sce,
+ SceneLayer *scene_layer,
const char *filepath,
int apply_modifiers,
@@ -78,7 +81,6 @@ int collada_export(Scene *sce,
int deform_bones_only,
int active_uv_only,
- int include_uv_textures,
int include_material_textures,
int use_texture_copies,
@@ -87,7 +89,9 @@ int collada_export(Scene *sce,
int use_blender_profile,
int sort_by_name,
BC_export_transformation_type export_transformation_type,
- int open_sim)
+ int open_sim,
+ int limit_precision,
+ int keep_bind_info)
{
ExportSettings export_settings;
@@ -102,7 +106,6 @@ int collada_export(Scene *sce,
export_settings.deform_bones_only = deform_bones_only != 0;
export_settings.active_uv_only = active_uv_only != 0;
- export_settings.include_uv_textures = include_uv_textures != 0;
export_settings.include_material_textures= include_material_textures != 0;
export_settings.use_texture_copies = use_texture_copies != 0;
@@ -112,14 +115,15 @@ int collada_export(Scene *sce,
export_settings.sort_by_name = sort_by_name != 0;
export_settings.export_transformation_type = export_transformation_type;
export_settings.open_sim = open_sim != 0;
-
+ export_settings.limit_precision = limit_precision != 0;
+ export_settings.keep_bind_info = keep_bind_info !=0;
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;
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(scene_layer, objectSet, (eObRelationTypes)includeFilter);
int export_count = BLI_linklist_count(export_settings.export_set);
if (export_count == 0) {
diff --git a/source/blender/collada/collada.h b/source/blender/collada/collada.h
index 0017c66836a..9aba51ef18a 100644
--- a/source/blender/collada/collada.h
+++ b/source/blender/collada/collada.h
@@ -43,12 +43,12 @@ typedef enum BC_export_mesh_type {
typedef enum BC_export_transformation_type {
BC_TRANSFORMATION_TYPE_MATRIX,
- BC_TRANSFORMATION_TYPE_TRANSROTLOC,
- BC_TRANSFORMATION_TYPE_BOTH
+ BC_TRANSFORMATION_TYPE_TRANSROTLOC
} BC_export_transformation_type;
struct bContext;
struct Scene;
+struct SceneLayer;
/*
* both return 1 on success, 0 on error
@@ -59,9 +59,12 @@ int collada_import(struct bContext *C,
int find_chains,
int auto_connect,
int fix_orientation,
- int min_chain_length);
+ int min_chain_length,
+
+ int keep_bind_info);
int collada_export(struct Scene *sce,
+ struct SceneLayer *scene_layer,
const char *filepath,
int apply_modifiers,
BC_export_mesh_type export_mesh_type,
@@ -73,7 +76,6 @@ int collada_export(struct Scene *sce,
int deform_bones_only,
int active_uv_only,
- int include_uv_textures,
int include_material_textures,
int use_texture_copies,
@@ -82,9 +84,10 @@ int collada_export(struct Scene *sce,
int use_blender_profile,
int sort_by_name,
BC_export_transformation_type export_transformation_type,
- int open_sim);
-
+ int open_sim,
+ int limit_precision,
+ int keep_bind_info);
#ifdef __cplusplus
}
diff --git a/source/blender/collada/collada_internal.cpp b/source/blender/collada/collada_internal.cpp
index 38855013ee1..6ebde6bd773 100644
--- a/source/blender/collada/collada_internal.cpp
+++ b/source/blender/collada/collada_internal.cpp
@@ -33,11 +33,8 @@
UnitConverter::UnitConverter() : unit(), up_axis(COLLADAFW::FileInfo::Z_UP)
{
- unit_m4(x_up_mat4);
- rotate_m4(x_up_mat4, 'Y', -0.5 * M_PI);
-
- unit_m4(y_up_mat4);
- rotate_m4(y_up_mat4, 'X', 0.5 * M_PI);
+ axis_angle_to_mat4_single(x_up_mat4, 'Y', -0.5 * M_PI);
+ axis_angle_to_mat4_single(y_up_mat4, 'X', 0.5 * M_PI);
unit_m4(z_up_mat4);
unit_m4(scale_mat4);
@@ -165,18 +162,6 @@ void UnitConverter::calculate_scale(Scene &sce)
size_to_mat4(scale_mat4, rescale);
}
-void TransformBase::decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size)
-{
- mat4_to_size(size, mat);
- if (eul) {
- mat4_to_eul(eul, mat);
- }
- if (quat) {
- mat4_to_quat(quat, mat);
- }
- copy_v3_v3(loc, mat[3]);
-}
-
/**
* Translation map.
* Used to translate every COLLADA id to a valid id, no matter what "wrong" letters may be
@@ -344,7 +329,12 @@ std::string get_light_id(Object *ob)
std::string get_joint_id(Bone *bone, Object *ob_arm)
{
- return translate_id(/*id_name(ob_arm) + "_" +*/ bone->name);
+ return translate_id(id_name(ob_arm) + "_" + bone->name);
+}
+
+std::string get_joint_sid(Bone *bone, Object *ob_arm)
+{
+ return translate_id(bone->name);
}
std::string get_camera_id(Object *ob)
diff --git a/source/blender/collada/collada_internal.h b/source/blender/collada/collada_internal.h
index 4aa637a6876..1c7aa160f57 100644
--- a/source/blender/collada/collada_internal.h
+++ b/source/blender/collada/collada_internal.h
@@ -85,12 +85,6 @@ public:
};
-class TransformBase
-{
-public:
- void decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size);
-};
-
extern void clear_global_id_map();
/** Look at documentation of translate_map */
extern std::string translate_id(const std::string &id);
@@ -104,6 +98,7 @@ 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(Bone *bone, Object *ob_arm);
+extern std::string get_joint_sid(Bone *bone, Object *ob_arm);
extern std::string get_camera_id(Object *ob);
diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp
index abe5130b9c1..0f39b27316c 100644
--- a/source/blender/collada/collada_utils.cpp
+++ b/source/blender/collada/collada_utils.cpp
@@ -32,8 +32,6 @@
#include "COLLADAFWMeshPrimitive.h"
#include "COLLADAFWMeshVertexData.h"
-#include "collada_utils.h"
-
extern "C" {
#include "DNA_modifier_types.h"
#include "DNA_customdata_types.h"
@@ -47,7 +45,6 @@ extern "C" {
#include "BKE_context.h"
#include "BKE_customdata.h"
-#include "BKE_depsgraph.h"
#include "BKE_object.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
@@ -63,6 +60,11 @@ extern "C" {
#include "bmesh_tools.h"
}
+#include "DEG_depsgraph.h"
+
+#include "collada_utils.h"
+#include "ExportSettings.h"
+
float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned int index)
{
if (index >= array.getValuesCount())
@@ -117,12 +119,12 @@ int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space)
BKE_object_workob_calc_parent(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);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_id_tag_update(&par->id, OB_RECALC_OB);
/** done once after import */
#if 0
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
#endif
@@ -135,7 +137,7 @@ Object *bc_add_object(Scene *scene, int type, const char *name)
ob->data = BKE_object_obdata_add_from_type(G.main, 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));
@@ -352,6 +354,28 @@ void bc_match_scale(std::vector<Object *> *objects_done,
}
}
+/*
+ Convenience function to get only the needed components of a matrix
+*/
+void bc_decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size)
+{
+ if (size) {
+ mat4_to_size(size, mat);
+ }
+
+ if (eul) {
+ mat4_to_eul(eul, mat);
+ }
+
+ if (quat) {
+ mat4_to_quat(quat, mat);
+ }
+
+ if (loc) {
+ copy_v3_v3(loc, mat[3]);
+ }
+}
+
void bc_triangulate_mesh(Mesh *me)
{
bool use_beauty = false;
@@ -412,6 +436,38 @@ int bc_set_layer(int bitfield, int layer, bool enable)
return bitfield;
}
+/*
+ | This method creates a new extension map when needed.
+ | Note: The ~BoneExtensionManager destructor takes care
+ | to delete the created maps when the manager is removed.
+*/
+BoneExtensionMap &BoneExtensionManager::getExtensionMap(bArmature *armature)
+{
+ std::string key = armature->id.name;
+ BoneExtensionMap *result = extended_bone_maps[key];
+ if (result == NULL)
+ {
+ result = new BoneExtensionMap();
+ extended_bone_maps[key] = result;
+ }
+ return *result;
+}
+
+BoneExtensionManager::~BoneExtensionManager()
+{
+ std::map<std::string, BoneExtensionMap *>::iterator map_it;
+ for (map_it = extended_bone_maps.begin(); map_it != extended_bone_maps.end(); ++map_it)
+ {
+ BoneExtensionMap *extended_bones = map_it->second;
+ for (BoneExtensionMap::iterator ext_it = extended_bones->begin(); ext_it != extended_bones->end(); ++ext_it) {
+ if (ext_it->second != NULL)
+ delete ext_it->second;
+ }
+ extended_bones->clear();
+ delete extended_bones;
+ }
+}
+
/**
* BoneExtended is a helper class needed for the Bone chain finder
* See ArmatureImporter::fix_leaf_bones()
@@ -580,3 +636,200 @@ int BoneExtended::get_use_connect()
{
return this->use_connect;
}
+
+/**
+* Stores a 4*4 matrix as a custom bone property array of size 16
+*/
+void bc_set_IDPropertyMatrix(EditBone *ebone, const char *key, float mat[4][4])
+{
+ IDProperty *idgroup = (IDProperty *)ebone->prop;
+ if (idgroup == NULL)
+ {
+ IDPropertyTemplate val = { 0 };
+ idgroup = IDP_New(IDP_GROUP, &val, "RNA_EditBone ID properties");
+ ebone->prop = idgroup;
+ }
+
+ IDPropertyTemplate val = { 0 };
+ val.array.len = 16;
+ val.array.type = IDP_FLOAT;
+
+ IDProperty *data = IDP_New(IDP_ARRAY, &val, key);
+ float *array = (float *)IDP_Array(data);
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ array[4 * i + j] = mat[i][j];
+
+ IDP_AddToGroup(idgroup, data);
+}
+
+#if 0
+/**
+* Stores a Float value as a custom bone property
+*
+* Note: This function is currently not needed. Keep for future usage
+*/
+static void bc_set_IDProperty(EditBone *ebone, const char *key, float value)
+{
+ if (ebone->prop == NULL)
+ {
+ IDPropertyTemplate val = { 0 };
+ ebone->prop = IDP_New(IDP_GROUP, &val, "RNA_EditBone ID properties");
+ }
+
+ IDProperty *pgroup = (IDProperty *)ebone->prop;
+ IDPropertyTemplate val = { 0 };
+ IDProperty *prop = IDP_New(IDP_FLOAT, &val, key);
+ IDP_Float(prop) = value;
+ IDP_AddToGroup(pgroup, prop);
+
+}
+#endif
+
+/*
+* Get a custom property when it exists.
+* This function is also used to check if a property exists.
+*/
+IDProperty *bc_get_IDProperty(Bone *bone, std::string key)
+{
+ return (bone->prop == NULL) ? NULL : IDP_GetPropertyFromGroup(bone->prop, key.c_str());
+}
+
+/**
+* Read a custom bone property and convert to float
+* Return def if the property does not exist.
+*/
+float bc_get_property(Bone *bone, std::string key, float def)
+{
+ float result = def;
+ IDProperty *property = bc_get_IDProperty(bone, key);
+ if (property) {
+ switch (property->type) {
+ case IDP_INT:
+ result = (float)(IDP_Int(property));
+ break;
+ case IDP_FLOAT:
+ result = (float)(IDP_Float(property));
+ break;
+ case IDP_DOUBLE:
+ result = (float)(IDP_Double(property));
+ break;
+ default:
+ result = def;
+ }
+ }
+ return result;
+}
+
+/**
+* Read a custom bone property and convert to matrix
+* Return true if conversion was succesfull
+*
+* Return false if:
+* - the property does not exist
+* - is not an array of size 16
+*/
+bool bc_get_property_matrix(Bone *bone, std::string key, float mat[4][4])
+{
+ IDProperty *property = bc_get_IDProperty(bone, key);
+ if (property && property->type == IDP_ARRAY && property->len == 16) {
+ float *array = (float *)IDP_Array(property);
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ mat[i][j] = array[4 * i + j];
+ return true;
+ }
+ return false;
+}
+
+/**
+* get a vector that is stored in 3 custom properties (used in Blender <= 2.78)
+*/
+void bc_get_property_vector(Bone *bone, std::string key, float val[3], const float def[3])
+{
+ val[0] = bc_get_property(bone, key + "_x", def[0]);
+ val[1] = bc_get_property(bone, key + "_y", def[1]);
+ val[2] = bc_get_property(bone, key + "_z", def[2]);
+}
+
+/**
+* Check if vector exist stored in 3 custom properties (used in Blender <= 2.78)
+*/
+static bool has_custom_props(Bone *bone, bool enabled, std::string key)
+{
+ if (!enabled)
+ return false;
+
+ return (bc_get_IDProperty(bone, key + "_x")
+ || bc_get_IDProperty(bone, key + "_y")
+ || bc_get_IDProperty(bone, key + "_z"));
+
+}
+
+/**
+* Check if custom information about bind matrix exists and modify the from_mat
+* accordingly.
+*
+* Note: This is old style for Blender <= 2.78 only kept for compatibility
+*/
+void bc_create_restpose_mat(const ExportSettings *export_settings, Bone *bone, float to_mat[4][4], float from_mat[4][4], bool use_local_space)
+{
+ float loc[3];
+ float rot[3];
+ float scale[3];
+ static const float V0[3] = { 0, 0, 0 };
+
+ if (!has_custom_props(bone, export_settings->keep_bind_info, "restpose_loc") &&
+ !has_custom_props(bone, export_settings->keep_bind_info, "restpose_rot") &&
+ !has_custom_props(bone, export_settings->keep_bind_info, "restpose_scale"))
+ {
+ /* No need */
+ copy_m4_m4(to_mat, from_mat);
+ return;
+ }
+
+ bc_decompose(from_mat, loc, rot, NULL, scale);
+ loc_eulO_size_to_mat4(to_mat, loc, rot, scale, 6);
+
+ if (export_settings->keep_bind_info) {
+ bc_get_property_vector(bone, "restpose_loc", loc, loc);
+
+ if (use_local_space && bone->parent) {
+ Bone *b = bone;
+ while (b->parent) {
+ b = b->parent;
+ float ploc[3];
+ bc_get_property_vector(b, "restpose_loc", ploc, V0);
+ loc[0] += ploc[0];
+ loc[1] += ploc[1];
+ loc[2] += ploc[2];
+ }
+ }
+ }
+
+ if (export_settings->keep_bind_info) {
+ if (bc_get_IDProperty(bone, "restpose_rot_x"))
+ rot[0] = DEG2RADF(bc_get_property(bone, "restpose_rot_x", 0));
+ if (bc_get_IDProperty(bone, "restpose_rot_y"))
+ rot[1] = DEG2RADF(bc_get_property(bone, "restpose_rot_y", 0));
+ if (bc_get_IDProperty(bone, "restpose_rot_z"))
+ rot[2] = DEG2RADF(bc_get_property(bone, "restpose_rot_z", 0));
+ }
+
+ if (export_settings->keep_bind_info) {
+ bc_get_property_vector(bone, "restpose_scale", scale, scale);
+ }
+
+ loc_eulO_size_to_mat4(to_mat, loc, rot, scale, 6);
+
+}
+
+/*
+ Make 4*4 matrices better readable
+*/
+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);
+}
diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h
index ee371f7959e..38c0bd5096a 100644
--- a/source/blender/collada/collada_utils.h
+++ b/source/blender/collada/collada_utils.h
@@ -53,8 +53,10 @@ extern "C" {
#include "BKE_object.h"
#include "BKE_DerivedMesh.h"
#include "BKE_scene.h"
+#include "BKE_idprop.h"
}
+#include "ImportSettings.h"
#include "ExportSettings.h"
#include "collada_internal.h"
@@ -88,11 +90,24 @@ extern std::string bc_url_encode(std::string data);
extern void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_scene);
extern void bc_match_scale(std::vector<Object *> *objects_done, UnitConverter &unit_converter, bool scale_to_scene);
+extern void bc_decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size);
+
extern void bc_triangulate_mesh(Mesh *me);
extern bool bc_is_leaf_bone(Bone *bone);
extern EditBone *bc_get_edit_bone(bArmature * armature, char *name);
extern int bc_set_layer(int bitfield, int layer, bool enable);
extern int bc_set_layer(int bitfield, int layer);
+extern void bc_sanitize_mat(float mat[4][4], int precision);
+
+extern IDProperty *bc_get_IDProperty(Bone *bone, std::string key);
+extern void bc_set_IDProperty(EditBone *ebone, const char *key, float value);
+extern void bc_set_IDPropertyMatrix(EditBone *ebone, const char *key, float mat[4][4]);
+
+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);
class BCPolygonNormalsIndices
{
@@ -153,5 +168,24 @@ public:
int get_use_connect();
};
+/* a map to store bone extension maps
+| std:string : an armature name
+| BoneExtended * : a map that contains extra data for bones
+*/
+typedef std::map<std::string, BoneExtended *> BoneExtensionMap;
+
+/*
+| A class to organise bone extendion data for multiple Armatures.
+| this is needed for the case where a Collada file contains 2 or more
+| separate armatures.
+*/
+class BoneExtensionManager {
+private:
+ std::map<std::string, BoneExtensionMap *> extended_bone_maps;
+
+public:
+ BoneExtensionMap &getExtensionMap(bArmature *armature);
+ ~BoneExtensionManager();
+};
#endif
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index 3180e7e4154..3e1dd83112a 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -551,8 +551,4 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
-if(WITH_CYCLES AND WITH_CYCLES_DEBUG)
- add_definitions(-DWITH_CYCLES_DEBUG)
-endif()
-
blender_add_lib(bf_compositor "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/compositor/COM_compositor.h b/source/blender/compositor/COM_compositor.h
index a5d7704a708..3b24f9c69a2 100644
--- a/source/blender/compositor/COM_compositor.h
+++ b/source/blender/compositor/COM_compositor.h
@@ -331,19 +331,6 @@ void COM_deinitialize(void);
*/
// void COM_clearCaches(void); // NOT YET WRITTEN
-/**
- * @brief Return a list of highlighted bnodes pointers.
- * @return
- */
-void COM_startReadHighlights(void);
-
-/**
- * @brief check if a bnode is highlighted
- * @param bnode
- * @return
- */
-int COM_isHighlightedbNode(bNode *bnode);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cpp b/source/blender/compositor/intern/COM_ExecutionGroup.cpp
index e5c2b8ace4e..9a47c6b2438 100644
--- a/source/blender/compositor/intern/COM_ExecutionGroup.cpp
+++ b/source/blender/compositor/intern/COM_ExecutionGroup.cpp
@@ -383,7 +383,7 @@ void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memo
if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_SCHEDULED)
this->m_chunkExecutionStates[chunkNumber] = COM_ES_EXECUTED;
- atomic_add_u(&this->m_chunksFinished, 1);
+ atomic_add_and_fetch_u(&this->m_chunksFinished, 1);
if (memoryBuffers) {
for (unsigned int index = 0; index < this->m_cachedMaxReadBufferOffset; index++) {
MemoryBuffer *buffer = memoryBuffers[index];
diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cpp b/source/blender/compositor/intern/COM_WorkScheduler.cpp
index 39147f3ab84..68f934008a4 100644
--- a/source/blender/compositor/intern/COM_WorkScheduler.cpp
+++ b/source/blender/compositor/intern/COM_WorkScheduler.cpp
@@ -75,82 +75,6 @@ static bool g_openclInitialized = false;
#endif
#endif
-#define MAX_HIGHLIGHT 8
-static bool g_highlightInitialized = false;
-extern "C" {
-static int g_highlightIndex;
-static void **g_highlightedNodes;
-static void **g_highlightedNodesRead;
-
-/* XXX highlighting disabled for now
- * This requires pointers back to DNA data (bNodeTree/bNode) in operations, which is bad!
- * Instead IF we want to keep this feature it should use a weak reference such as bNodeInstanceKey
- */
-#if 0
-#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
-#define HIGHLIGHT(wp) \
-{ \
- ExecutionGroup *group = wp->getExecutionGroup(); \
- if (group->isComplex()) { \
- NodeOperation *operation = group->getOutputOperation(); \
- if (operation->isWriteBufferOperation()) { \
- WriteBufferOperation *writeOperation = (WriteBufferOperation *)operation; \
- NodeOperation *complexOperation = writeOperation->getInput(); \
- bNode *node = complexOperation->getbNode(); \
- if (node) { \
- if (node->original) { \
- node = node->original; \
- } \
- if (g_highlightInitialized && g_highlightedNodes) { \
- if (g_highlightIndex < MAX_HIGHLIGHT) { \
- g_highlightedNodes[g_highlightIndex++] = node; \
- } \
- } \
- } \
- } \
- } \
-}
-#endif /* COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE */
-#else
-# if COM_CURRENT_THREADING_MODEL != COM_TM_NOTHREAD
-#define HIGHLIGHT(wp) {}
-# endif
-#endif
-
-void COM_startReadHighlights()
-{
- if (!g_highlightInitialized) {
- return;
- }
-
- if (g_highlightedNodesRead) {
- MEM_freeN(g_highlightedNodesRead);
- }
-
- g_highlightedNodesRead = g_highlightedNodes;
- g_highlightedNodes = (void **)MEM_callocN(sizeof(void *) * MAX_HIGHLIGHT, __func__);
- g_highlightIndex = 0;
-}
-
-int COM_isHighlightedbNode(bNode *bnode)
-{
- if (!g_highlightInitialized) {
- return false;
- }
-
- if (!g_highlightedNodesRead) {
- return false;
- }
-
- for (int i = 0; i < MAX_HIGHLIGHT; i++) {
- void *p = g_highlightedNodesRead[i];
- if (!p) return false;
- if (p == bnode) return true;
- }
- return false;
-}
-} // end extern "C"
-
#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
void *WorkScheduler::thread_execute_cpu(void *data)
{
@@ -158,7 +82,6 @@ void *WorkScheduler::thread_execute_cpu(void *data)
WorkPackage *work;
BLI_thread_local_set(g_thread_device, device);
while ((work = (WorkPackage *)BLI_thread_queue_pop(g_cpuqueue))) {
- HIGHLIGHT(work);
device->execute(work);
delete work;
}
@@ -172,7 +95,6 @@ void *WorkScheduler::thread_execute_gpu(void *data)
WorkPackage *work;
while ((work = (WorkPackage *)BLI_thread_queue_pop(g_gpuqueue))) {
- HIGHLIGHT(work);
device->execute(work);
delete work;
}
@@ -289,19 +211,6 @@ static void CL_CALLBACK clContextError(const char *errinfo,
void WorkScheduler::initialize(bool use_opencl, int num_cpu_threads)
{
- /* initialize highlighting */
- if (!g_highlightInitialized) {
- if (g_highlightedNodesRead) MEM_freeN(g_highlightedNodesRead);
- if (g_highlightedNodes) MEM_freeN(g_highlightedNodes);
-
- g_highlightedNodesRead = NULL;
- g_highlightedNodes = NULL;
-
- COM_startReadHighlights();
-
- g_highlightInitialized = true;
- }
-
#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
/* deinitialize if number of threads doesn't match */
if (g_cpudevices.size() != num_cpu_threads) {
@@ -439,20 +348,6 @@ void WorkScheduler::deinitialize()
}
#endif
#endif
-
- /* deinitialize highlighting */
- if (g_highlightInitialized) {
- g_highlightInitialized = false;
- if (g_highlightedNodes) {
- MEM_freeN(g_highlightedNodes);
- g_highlightedNodes = NULL;
- }
-
- if (g_highlightedNodesRead) {
- MEM_freeN(g_highlightedNodesRead);
- g_highlightedNodesRead = NULL;
- }
- }
}
int WorkScheduler::current_thread_id()
diff --git a/source/blender/compositor/nodes/COM_BrightnessNode.cpp b/source/blender/compositor/nodes/COM_BrightnessNode.cpp
index 053f286c66e..6729571fac0 100644
--- a/source/blender/compositor/nodes/COM_BrightnessNode.cpp
+++ b/source/blender/compositor/nodes/COM_BrightnessNode.cpp
@@ -31,7 +31,9 @@ BrightnessNode::BrightnessNode(bNode *editorNode) : Node(editorNode)
void BrightnessNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
+ bNode *bnode = this->getbNode();
BrightnessOperation *operation = new BrightnessOperation();
+ operation->setUsePremultiply((bnode->custom1 & 1) != 0);
converter.addOperation(operation);
converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp
index e159886bb46..851d43fc062 100644
--- a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp
+++ b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp
@@ -27,7 +27,6 @@
#include "COM_MixOperation.h"
#include "COM_SetColorOperation.h"
#include "COM_SetValueOperation.h"
-#include "COM_ChangeHSVOperation.h"
#include "DNA_node_types.h"
#include "COM_HueSaturationValueCorrectOperation.h"
diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp
index 29c296a896d..36bc176b1a6 100644
--- a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp
+++ b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp
@@ -37,11 +37,12 @@ HueSaturationValueNode::HueSaturationValueNode(bNode *editorNode) : Node(editorN
void HueSaturationValueNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
- NodeInput *valueSocket = this->getInputSocket(0);
- NodeInput *colorSocket = this->getInputSocket(1);
+ NodeInput *colorSocket = this->getInputSocket(0);
+ NodeInput *hueSocket = this->getInputSocket(1);
+ NodeInput *saturationSocket = this->getInputSocket(2);
+ NodeInput *valueSocket = this->getInputSocket(3);
+ NodeInput *facSocket = this->getInputSocket(4);
NodeOutput *outputSocket = this->getOutputSocket(0);
- bNode *editorsnode = getbNode();
- NodeHueSat *storage = (NodeHueSat *)editorsnode->storage;
ConvertRGBToHSVOperation *rgbToHSV = new ConvertRGBToHSVOperation();
converter.addOperation(rgbToHSV);
@@ -50,9 +51,9 @@ void HueSaturationValueNode::convertToOperations(NodeConverter &converter, const
converter.addOperation(hsvToRGB);
ChangeHSVOperation *changeHSV = new ChangeHSVOperation();
- changeHSV->setHue(storage->hue);
- changeHSV->setSaturation(storage->sat);
- changeHSV->setValue(storage->val);
+ converter.mapInputSocket(hueSocket, changeHSV->getInputSocket(1));
+ converter.mapInputSocket(saturationSocket, changeHSV->getInputSocket(2));
+ converter.mapInputSocket(valueSocket, changeHSV->getInputSocket(3));
converter.addOperation(changeHSV);
MixBlendOperation *blend = new MixBlendOperation();
@@ -64,6 +65,6 @@ void HueSaturationValueNode::convertToOperations(NodeConverter &converter, const
converter.addLink(changeHSV->getOutputSocket(), hsvToRGB->getInputSocket(0));
converter.addLink(hsvToRGB->getOutputSocket(), blend->getInputSocket(2));
converter.mapInputSocket(colorSocket, blend->getInputSocket(1));
- converter.mapInputSocket(valueSocket, blend->getInputSocket(0));
+ converter.mapInputSocket(facSocket, blend->getInputSocket(0));
converter.mapOutputSocket(outputSocket, blend->getOutputSocket());
}
diff --git a/source/blender/compositor/nodes/COM_ImageNode.cpp b/source/blender/compositor/nodes/COM_ImageNode.cpp
index facd422c217..81891d853d2 100644
--- a/source/blender/compositor/nodes/COM_ImageNode.cpp
+++ b/source/blender/compositor/nodes/COM_ImageNode.cpp
@@ -95,17 +95,14 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
NodeOperation *operation = NULL;
socket = this->getOutputSocket(index);
bNodeSocket *bnodeSocket = socket->getbNodeSocket();
- RenderPass *rpass = (RenderPass *)BLI_findstring(&rl->passes, bnodeSocket->identifier, offsetof(RenderPass, internal_name));
+ NodeImageLayer *storage = (NodeImageLayer *)bnodeSocket->storage;
+ RenderPass *rpass = (RenderPass *)BLI_findstring(&rl->passes, storage->pass_name, offsetof(RenderPass, name));
int view = 0;
- /* Passes in the file can differ from passes stored in sockets (#36755).
- * Look up the correct file pass using the socket identifier instead.
- */
-#if 0
- NodeImageLayer *storage = (NodeImageLayer *)bnodeSocket->storage;*/
- int passindex = storage->pass_index;*/
- RenderPass *rpass = (RenderPass *)BLI_findlink(&rl->passes, passindex);
-#endif
+ if (STREQ(storage->pass_name, RE_PASSNAME_COMBINED) && STREQ(bnodeSocket->name, "Alpha")) {
+ /* Alpha output is already handled with the associated combined output. */
+ continue;
+ }
/* returns the image view to use for the current active view */
if (BLI_listbase_count_ex(&image->rr->views, 2) > 1) {
@@ -147,17 +144,25 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
if (index == 0 && operation) {
converter.addPreview(operation->getOutputSocket());
}
- if (rpass->passtype == SCE_PASS_COMBINED) {
- BLI_assert(operation != NULL);
- BLI_assert(index < numberOfOutputs - 1);
- NodeOutput *outputSocket = this->getOutputSocket(index + 1);
- SeparateChannelOperation *separate_operation;
- separate_operation = new SeparateChannelOperation();
- separate_operation->setChannel(3);
- converter.addOperation(separate_operation);
- converter.addLink(operation->getOutputSocket(), separate_operation->getInputSocket(0));
- converter.mapOutputSocket(outputSocket, separate_operation->getOutputSocket());
- index++;
+ if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) {
+ for (int alphaIndex = 0; alphaIndex < numberOfOutputs; alphaIndex++) {
+ NodeOutput *alphaSocket = this->getOutputSocket(alphaIndex);
+ bNodeSocket *bnodeAlphaSocket = alphaSocket->getbNodeSocket();
+ if (!STREQ(bnodeAlphaSocket->name, "Alpha")) {
+ continue;
+ }
+ NodeImageLayer *alphaStorage = (NodeImageLayer *)bnodeSocket->storage;
+ if (!STREQ(alphaStorage->pass_name, RE_PASSNAME_COMBINED)) {
+ continue;
+ }
+ SeparateChannelOperation *separate_operation;
+ separate_operation = new SeparateChannelOperation();
+ separate_operation->setChannel(3);
+ converter.addOperation(separate_operation);
+ converter.addLink(operation->getOutputSocket(), separate_operation->getInputSocket(0));
+ converter.mapOutputSocket(alphaSocket, separate_operation->getOutputSocket());
+ break;
+ }
}
}
diff --git a/source/blender/compositor/nodes/COM_MovieClipNode.cpp b/source/blender/compositor/nodes/COM_MovieClipNode.cpp
index 933223dacac..b3f1b5a4458 100644
--- a/source/blender/compositor/nodes/COM_MovieClipNode.cpp
+++ b/source/blender/compositor/nodes/COM_MovieClipNode.cpp
@@ -91,7 +91,7 @@ void MovieClipNode::convertToOperations(NodeConverter &converter, const Composit
if (stab->flag & TRACKING_2D_STABILIZATION) {
int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(movieClip, context.getFramenumber());
- BKE_tracking_stabilization_data_get(&movieClip->tracking, clip_framenr, ibuf->x, ibuf->y, loc, &scale, &angle);
+ BKE_tracking_stabilization_data_get(movieClip, clip_framenr, ibuf->x, ibuf->y, loc, &scale, &angle);
}
}
diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp b/source/blender/compositor/nodes/COM_RenderLayersNode.cpp
index 842edcf35c9..75128de2d84 100644
--- a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp
+++ b/source/blender/compositor/nodes/COM_RenderLayersNode.cpp
@@ -27,76 +27,61 @@
#include "COM_ScaleOperation.h"
#include "COM_SetValueOperation.h"
-#ifdef WITH_CYCLES_DEBUG
-# include "RE_pipeline.h"
-#endif
-
RenderLayersNode::RenderLayersNode(bNode *editorNode) : Node(editorNode)
{
/* pass */
}
void RenderLayersNode::testSocketLink(NodeConverter &converter, const CompositorContext &context,
- int outputSocketNumber, RenderLayersBaseProg *operation) const
+ NodeOutput *output, RenderLayersProg *operation,
+ Scene *scene, int layerId, bool is_preview) const
{
- NodeOutput *outputSocket = this->getOutputSocket(outputSocketNumber);
- Scene *scene = (Scene *)this->getbNode()->id;
- short layerId = this->getbNode()->custom1;
-
operation->setScene(scene);
operation->setLayerId(layerId);
operation->setRenderData(context.getRenderData());
operation->setViewName(context.getViewName());
- converter.mapOutputSocket(outputSocket, operation->getOutputSocket());
+ converter.mapOutputSocket(output, operation->getOutputSocket());
converter.addOperation(operation);
- if (outputSocketNumber == 0) /* only for image socket */
+ if (is_preview) /* only for image socket */
converter.addPreview(operation->getOutputSocket());
}
void RenderLayersNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
{
- testSocketLink(converter, context, 0, new RenderLayersColorProg());
- testSocketLink(converter, context, 1, new RenderLayersAlphaProg());
- testSocketLink(converter, context, 2, new RenderLayersDepthProg());
- testSocketLink(converter, context, 3, new RenderLayersNormalOperation());
- testSocketLink(converter, context, 4, new RenderLayersUVOperation());
- testSocketLink(converter, context, 5, new RenderLayersSpeedOperation());
- testSocketLink(converter, context, 6, new RenderLayersColorOperation());
- testSocketLink(converter, context, 7, new RenderLayersDiffuseOperation());
- testSocketLink(converter, context, 8, new RenderLayersSpecularOperation());
- testSocketLink(converter, context, 9, new RenderLayersShadowOperation());
- testSocketLink(converter, context, 10, new RenderLayersAOOperation());
- testSocketLink(converter, context, 11, new RenderLayersReflectionOperation());
- testSocketLink(converter, context, 12, new RenderLayersRefractionOperation());
- testSocketLink(converter, context, 13, new RenderLayersIndirectOperation());
- testSocketLink(converter, context, 14, new RenderLayersObjectIndexOperation());
- testSocketLink(converter, context, 15, new RenderLayersMaterialIndexOperation());
- testSocketLink(converter, context, 16, new RenderLayersMistOperation());
- testSocketLink(converter, context, 17, new RenderLayersEmitOperation());
- testSocketLink(converter, context, 18, new RenderLayersEnvironmentOperation());
+ Scene *scene = (Scene *)this->getbNode()->id;
+ short layerId = this->getbNode()->custom1;
+ Render *re = (scene) ? RE_GetRender(scene->id.name) : NULL;
+ int numberOfOutputs = this->getNumberOfOutputSockets();
- // cycles passes
- testSocketLink(converter, context, 19, new RenderLayersCyclesOperation(SCE_PASS_DIFFUSE_DIRECT));
- testSocketLink(converter, context, 20, new RenderLayersCyclesOperation(SCE_PASS_DIFFUSE_INDIRECT));
- testSocketLink(converter, context, 21, new RenderLayersCyclesOperation(SCE_PASS_DIFFUSE_COLOR));
- testSocketLink(converter, context, 22, new RenderLayersCyclesOperation(SCE_PASS_GLOSSY_DIRECT));
- testSocketLink(converter, context, 23, new RenderLayersCyclesOperation(SCE_PASS_GLOSSY_INDIRECT));
- testSocketLink(converter, context, 24, new RenderLayersCyclesOperation(SCE_PASS_GLOSSY_COLOR));
- testSocketLink(converter, context, 25, new RenderLayersCyclesOperation(SCE_PASS_TRANSM_DIRECT));
- testSocketLink(converter, context, 26, new RenderLayersCyclesOperation(SCE_PASS_TRANSM_INDIRECT));
- testSocketLink(converter, context, 27, new RenderLayersCyclesOperation(SCE_PASS_TRANSM_COLOR));
- testSocketLink(converter, context, 28, new RenderLayersCyclesOperation(SCE_PASS_SUBSURFACE_DIRECT));
- testSocketLink(converter, context, 29, new RenderLayersCyclesOperation(SCE_PASS_SUBSURFACE_INDIRECT));
- testSocketLink(converter, context, 30, new RenderLayersCyclesOperation(SCE_PASS_SUBSURFACE_COLOR));
-
-#ifdef WITH_CYCLES_DEBUG
- {
- Scene *scene = (Scene *)this->getbNode()->id;
- Render *re = RE_GetRender(scene->id.name);
- int debug_pass_type = ((re != NULL) ? RE_debug_pass_type_get(re) : scene->r.debug_pass_type);
- testSocketLink(converter, context, 31, new RenderLayersCyclesDebugOperation(SCE_PASS_DEBUG, debug_pass_type));
+ if (re) {
+ RenderResult *rr = RE_AcquireResultRead(re);
+ if (rr) {
+ SceneRenderLayer *srl = (SceneRenderLayer *)BLI_findlink(&scene->r.layers, layerId);
+ if (srl) {
+ RenderLayer *rl = RE_GetRenderLayer(rr, srl->name);
+ if (rl) {
+ for (int i = 0; i < numberOfOutputs; i++) {
+ NodeOutput *output = this->getOutputSocket(i);
+ NodeImageLayer *storage = (NodeImageLayer*) output->getbNodeSocket()->storage;
+ RenderPass *rpass = (RenderPass*) BLI_findstring(&rl->passes, storage->pass_name, offsetof(RenderPass, name));
+ if (rpass) {
+ if (STREQ(rpass->name, RE_PASSNAME_COMBINED) && STREQ(output->getbNodeSocket()->name, "Alpha")) {
+ testSocketLink(converter, context, output, new RenderLayersAlphaProg(rpass->name, COM_DT_VALUE, rpass->channels), scene, layerId, false);
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_Z)) {
+ testSocketLink(converter, context, output, new RenderLayersDepthProg(rpass->name, COM_DT_VALUE, rpass->channels), scene, layerId, false);
+ }
+ else {
+ DataType type = ((rpass->channels == 4)? COM_DT_COLOR : ((rpass->channels == 3)? COM_DT_VECTOR : COM_DT_VALUE));
+ testSocketLink(converter, context, output, new RenderLayersProg(rpass->name, type, rpass->channels), scene, layerId, STREQ(output->getbNodeSocket()->name, "Image"));
+ }
+ }
+ }
+ }
+ }
+ }
+ RE_ReleaseResult(re);
}
-#endif
}
diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.h b/source/blender/compositor/nodes/COM_RenderLayersNode.h
index 5863cbb390c..1f733a9f4bb 100644
--- a/source/blender/compositor/nodes/COM_RenderLayersNode.h
+++ b/source/blender/compositor/nodes/COM_RenderLayersNode.h
@@ -33,5 +33,11 @@ public:
RenderLayersNode(bNode *editorNode);
void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
private:
- void testSocketLink(NodeConverter &converter, const CompositorContext &context, int outputSocketNumber, RenderLayersBaseProg *operation) const;
+ void testSocketLink(NodeConverter &converter,
+ const CompositorContext &context,
+ NodeOutput *output,
+ RenderLayersProg *operation,
+ Scene *scene,
+ int layerId,
+ bool is_preview) const;
};
diff --git a/source/blender/compositor/operations/COM_BrightnessOperation.cpp b/source/blender/compositor/operations/COM_BrightnessOperation.cpp
index 33e35c3fe3b..c7ba86b66bc 100644
--- a/source/blender/compositor/operations/COM_BrightnessOperation.cpp
+++ b/source/blender/compositor/operations/COM_BrightnessOperation.cpp
@@ -29,7 +29,14 @@ BrightnessOperation::BrightnessOperation() : NodeOperation()
this->addInputSocket(COM_DT_VALUE);
this->addOutputSocket(COM_DT_COLOR);
this->m_inputProgram = NULL;
+ this->m_use_premultiply = false;
}
+
+void BrightnessOperation::setUsePremultiply(bool use_premultiply)
+{
+ this->m_use_premultiply = use_premultiply;
+}
+
void BrightnessOperation::initExecution()
{
this->m_inputProgram = this->getInputSocketReader(0);
@@ -64,11 +71,16 @@ void BrightnessOperation::executePixelSampled(float output[4], float x, float y,
delta *= -1;
b = a * (brightness + delta);
}
-
+ if (this->m_use_premultiply) {
+ premul_to_straight_v4(inputValue);
+ }
output[0] = a * inputValue[0] + b;
output[1] = a * inputValue[1] + b;
output[2] = a * inputValue[2] + b;
output[3] = inputValue[3];
+ if (this->m_use_premultiply) {
+ straight_to_premul_v4(output);
+ }
}
void BrightnessOperation::deinitExecution()
diff --git a/source/blender/compositor/operations/COM_BrightnessOperation.h b/source/blender/compositor/operations/COM_BrightnessOperation.h
index 22086ae11e8..ff492f2b102 100644
--- a/source/blender/compositor/operations/COM_BrightnessOperation.h
+++ b/source/blender/compositor/operations/COM_BrightnessOperation.h
@@ -34,6 +34,8 @@ private:
SocketReader *m_inputBrightnessProgram;
SocketReader *m_inputContrastProgram;
+ bool m_use_premultiply;
+
public:
BrightnessOperation();
@@ -52,5 +54,6 @@ public:
*/
void deinitExecution();
+ void setUsePremultiply(bool use_premultiply);
};
#endif
diff --git a/source/blender/compositor/operations/COM_ChangeHSVOperation.cpp b/source/blender/compositor/operations/COM_ChangeHSVOperation.cpp
index 964f1d64667..7ea974a41dc 100644
--- a/source/blender/compositor/operations/COM_ChangeHSVOperation.cpp
+++ b/source/blender/compositor/operations/COM_ChangeHSVOperation.cpp
@@ -25,6 +25,9 @@
ChangeHSVOperation::ChangeHSVOperation() : NodeOperation()
{
this->addInputSocket(COM_DT_COLOR);
+ this->addInputSocket(COM_DT_VALUE);
+ this->addInputSocket(COM_DT_VALUE);
+ this->addInputSocket(COM_DT_VALUE);
this->addOutputSocket(COM_DT_COLOR);
this->m_inputOperation = NULL;
}
@@ -32,24 +35,34 @@ ChangeHSVOperation::ChangeHSVOperation() : NodeOperation()
void ChangeHSVOperation::initExecution()
{
this->m_inputOperation = getInputSocketReader(0);
+ this->m_hueOperation = getInputSocketReader(1);
+ this->m_saturationOperation = getInputSocketReader(2);
+ this->m_valueOperation = getInputSocketReader(3);
}
void ChangeHSVOperation::deinitExecution()
{
this->m_inputOperation = NULL;
+ this->m_hueOperation = NULL;
+ this->m_saturationOperation = NULL;
+ this->m_valueOperation = NULL;
}
void ChangeHSVOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
float inputColor1[4];
+ float hue[4], saturation[4], value[4];
this->m_inputOperation->readSampled(inputColor1, x, y, sampler);
+ this->m_hueOperation->readSampled(hue, x, y, sampler);
+ this->m_saturationOperation->readSampled(saturation, x, y, sampler);
+ this->m_valueOperation->readSampled(value, x, y, sampler);
- output[0] = inputColor1[0] + (this->m_hue - 0.5f);
+ output[0] = inputColor1[0] + (hue[0] - 0.5f);
if (output[0] > 1.0f) output[0] -= 1.0f;
else if (output[0] < 0.0f) output[0] += 1.0f;
- output[1] = inputColor1[1] * this->m_saturation;
- output[2] = inputColor1[2] * this->m_value;
+ output[1] = inputColor1[1] * saturation[0];
+ output[2] = inputColor1[2] * value[0];
output[3] = inputColor1[3];
}
diff --git a/source/blender/compositor/operations/COM_ChangeHSVOperation.h b/source/blender/compositor/operations/COM_ChangeHSVOperation.h
index 76025e86b7a..800c09c05ff 100644
--- a/source/blender/compositor/operations/COM_ChangeHSVOperation.h
+++ b/source/blender/compositor/operations/COM_ChangeHSVOperation.h
@@ -32,10 +32,9 @@
class ChangeHSVOperation : public NodeOperation {
private:
SocketReader *m_inputOperation;
-
- float m_hue;
- float m_saturation;
- float m_value;
+ SocketReader *m_hueOperation;
+ SocketReader *m_saturationOperation;
+ SocketReader *m_valueOperation;
public:
/**
@@ -51,9 +50,5 @@ public:
*/
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
- void setHue(float hue) { this->m_hue = hue; }
- void setSaturation(float saturation) { this->m_saturation = saturation; }
- void setValue(float value) { this->m_value = value; }
-
};
#endif
diff --git a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp
index e1ada9a8c39..5f78067220a 100644
--- a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp
@@ -94,4 +94,10 @@ void ConvolutionEdgeFilterOperation::executePixel(float output[4], int x, int y,
output[2] = output[2] * value[0] + in2[2] * mval;
output[3] = in2[3];
+
+ /* Make sure we don't return negative color. */
+ output[0] = max(output[0], 0.0f);
+ output[1] = max(output[1], 0.0f);
+ output[2] = max(output[2], 0.0f);
+ output[3] = max(output[3], 0.0f);
}
diff --git a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp
index 68ec2be5ebd..6ac1ff9a1eb 100644
--- a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp
@@ -107,6 +107,12 @@ void ConvolutionFilterOperation::executePixel(float output[4], int x, int y, voi
output[1] = output[1] * value[0] + in2[1] * mval;
output[2] = output[2] * value[0] + in2[2] * mval;
output[3] = output[3] * value[0] + in2[3] * mval;
+
+ /* Make sure we don't return negative color. */
+ output[0] = max(output[0], 0.0f);
+ output[1] = max(output[1], 0.0f);
+ output[2] = max(output[2], 0.0f);
+ output[3] = max(output[3], 0.0f);
}
bool ConvolutionFilterOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
diff --git a/source/blender/compositor/operations/COM_DifferenceMatteOperation.cpp b/source/blender/compositor/operations/COM_DifferenceMatteOperation.cpp
index 325ef83a529..aa58c0571cf 100644
--- a/source/blender/compositor/operations/COM_DifferenceMatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_DifferenceMatteOperation.cpp
@@ -65,11 +65,11 @@ void DifferenceMatteOperation::executePixelSampled(float output[4], float x, flo
difference = difference / 3.0f;
/* make 100% transparent */
- if (difference < tolerance) {
+ if (difference <= tolerance) {
output[0] = 0.0f;
}
/*in the falloff region, make partially transparent */
- else if (difference < falloff + tolerance) {
+ else if (difference <= falloff + tolerance) {
difference = difference - tolerance;
alpha = difference / falloff;
/*only change if more transparent than before */
diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
index 76afedf4b2a..ca3c5f7b069 100644
--- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
@@ -20,6 +20,8 @@
* Monique Dewanchand
*/
+#include <stdlib.h>
+
#include "COM_DoubleEdgeMaskOperation.h"
#include "BLI_math.h"
#include "DNA_node_types.h"
@@ -1151,12 +1153,13 @@ void DoubleEdgeMaskOperation::doDoubleEdgeMask(float *imask, float *omask, float
if (true) { // if both input sockets have some data coming in...
- t = (this->getWidth() * this->getHeight()) - 1; // determine size of the frame
+ rw = this->getWidth(); // width of a row of pixels
+ t = (rw * this->getHeight()) - 1; // determine size of the frame
+ memset(res, 0, sizeof(float) * (t + 1)); // clear output buffer (not all pixels will be written later)
lres = (unsigned int *)res; // unsigned int pointer to output buffer (for bit level ops)
limask = (unsigned int *)imask; // unsigned int pointer to input mask (for bit level ops)
lomask = (unsigned int *)omask; // unsigned int pointer to output mask (for bit level ops)
- rw = this->getWidth(); // width of a row of pixels
/*
diff --git a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp
index 957ac5af748..57aa3a1bac2 100644
--- a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp
@@ -44,18 +44,18 @@ void GlareSimpleStarOperation::generateGlare(float *data, MemoryBuffer *inputTil
xp = x + i;
tbuf1->read(c, x, y);
mul_v3_fl(c, f1);
- tbuf1->read(tc, (settings->angle ? xm : x), ym);
+ tbuf1->read(tc, (settings->star_45 ? xm : x), ym);
madd_v3_v3fl(c, tc, f2);
- tbuf1->read(tc, (settings->angle ? xp : x), yp);
+ tbuf1->read(tc, (settings->star_45 ? xp : x), yp);
madd_v3_v3fl(c, tc, f2);
c[3] = 1.0f;
tbuf1->writePixel(x, y, c);
tbuf2->read(c, x, y);
mul_v3_fl(c, f1);
- tbuf2->read(tc, xm, (settings->angle ? yp : y));
+ tbuf2->read(tc, xm, (settings->star_45 ? yp : y));
madd_v3_v3fl(c, tc, f2);
- tbuf2->read(tc, xp, (settings->angle ? ym : y));
+ tbuf2->read(tc, xp, (settings->star_45 ? ym : y));
madd_v3_v3fl(c, tc, f2);
c[3] = 1.0f;
tbuf2->writePixel(x, y, c);
@@ -73,18 +73,18 @@ void GlareSimpleStarOperation::generateGlare(float *data, MemoryBuffer *inputTil
xp = x + i;
tbuf1->read(c, x, y);
mul_v3_fl(c, f1);
- tbuf1->read(tc, (settings->angle ? xm : x), ym);
+ tbuf1->read(tc, (settings->star_45 ? xm : x), ym);
madd_v3_v3fl(c, tc, f2);
- tbuf1->read(tc, (settings->angle ? xp : x), yp);
+ tbuf1->read(tc, (settings->star_45 ? xp : x), yp);
madd_v3_v3fl(c, tc, f2);
c[3] = 1.0f;
tbuf1->writePixel(x, y, c);
tbuf2->read(c, x, y);
mul_v3_fl(c, f1);
- tbuf2->read(tc, xm, (settings->angle ? yp : y));
+ tbuf2->read(tc, xm, (settings->star_45 ? yp : y));
madd_v3_v3fl(c, tc, f2);
- tbuf2->read(tc, xp, (settings->angle ? ym : y));
+ tbuf2->read(tc, xp, (settings->star_45 ? ym : y));
madd_v3_v3fl(c, tc, f2);
c[3] = 1.0f;
tbuf2->writePixel(x, y, c);
diff --git a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp b/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp
index da6076337b4..535f2952e5d 100644
--- a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp
@@ -28,7 +28,7 @@ void GlareStreaksOperation::generateGlare(float *data, MemoryBuffer *inputTile,
int x, y, n;
unsigned int nump = 0;
float c1[4], c2[4], c3[4], c4[4];
- float a, ang = DEG2RADF(360.0f) / (float)settings->angle;
+ float a, ang = DEG2RADF(360.0f) / (float)settings->streaks;
int size = inputTile->getWidth() * inputTile->getHeight();
int size4 = size * 4;
diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
index 5ddf15f7684..41f7da7c49f 100644
--- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
@@ -47,7 +47,7 @@ void MovieClipAttributeOperation::executePixelSampled(float output[4],
angle = 0.0f;
if (this->m_clip) {
int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_clip, this->m_framenumber);
- BKE_tracking_stabilization_data_get(&this->m_clip->tracking, clip_framenr, getWidth(), getHeight(), loc, &scale, &angle);
+ BKE_tracking_stabilization_data_get(this->m_clip, clip_framenr, getWidth(), getHeight(), loc, &scale, &angle);
}
switch (this->m_attribute) {
case MCA_SCALE:
diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp
index fb8730c9fa0..d6affa6eee9 100644
--- a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp
@@ -29,8 +29,6 @@
#include "BLI_math_color.h"
extern "C" {
-# include "BLI_jitter.h"
-
# include "BKE_node.h"
}
diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp b/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
index a56aa0cbaa6..070b7562b2d 100644
--- a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
@@ -29,8 +29,6 @@
#include "BLI_math_color.h"
extern "C" {
-# include "BLI_jitter.h"
-
# include "BKE_movieclip.h"
# include "BKE_node.h"
# include "BKE_tracking.h"
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cpp b/source/blender/compositor/operations/COM_RenderLayersProg.cpp
index 099208ce600..f2f1b211a97 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.cpp
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.cpp
@@ -34,17 +34,18 @@ extern "C" {
/* ******** Render Layers Base Prog ******** */
-RenderLayersBaseProg::RenderLayersBaseProg(int renderpass, int elementsize) : NodeOperation()
+RenderLayersProg::RenderLayersProg(const char *passName, DataType type, int elementsize) : NodeOperation(), m_passName(passName)
{
- this->m_renderpass = renderpass;
this->setScene(NULL);
this->m_inputBuffer = NULL;
this->m_elementsize = elementsize;
this->m_rd = NULL;
+
+ this->addOutputSocket(type);
}
-void RenderLayersBaseProg::initExecution()
+void RenderLayersProg::initExecution()
{
Scene *scene = this->getScene();
Render *re = (scene) ? RE_GetRender(scene->id.name) : NULL;
@@ -59,10 +60,7 @@ void RenderLayersBaseProg::initExecution()
RenderLayer *rl = RE_GetRenderLayer(rr, srl->name);
if (rl) {
- this->m_inputBuffer = RE_RenderLayerGetPass(rl, this->m_renderpass, this->m_viewName);
- if (this->m_inputBuffer == NULL && this->m_renderpass == SCE_PASS_COMBINED) {
- this->m_inputBuffer = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, this->m_viewName);
- }
+ this->m_inputBuffer = RE_RenderLayerGetPass(rl, this->m_passName.c_str(), this->m_viewName);
}
}
}
@@ -72,7 +70,7 @@ void RenderLayersBaseProg::initExecution()
}
}
-void RenderLayersBaseProg::doInterpolation(float output[4], float x, float y, PixelSampler sampler)
+void RenderLayersProg::doInterpolation(float output[4], float x, float y, PixelSampler sampler)
{
unsigned int offset;
int width = this->getWidth(), height = this->getHeight();
@@ -111,7 +109,7 @@ void RenderLayersBaseProg::doInterpolation(float output[4], float x, float y, Pi
}
}
-void RenderLayersBaseProg::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void RenderLayersProg::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
#if 0
const RenderData *rd = this->m_rd;
@@ -173,12 +171,12 @@ void RenderLayersBaseProg::executePixelSampled(float output[4], float x, float y
}
}
-void RenderLayersBaseProg::deinitExecution()
+void RenderLayersProg::deinitExecution()
{
this->m_inputBuffer = NULL;
}
-void RenderLayersBaseProg::determineResolution(unsigned int resolution[2], unsigned int /*preferredResolution*/[2])
+void RenderLayersProg::determineResolution(unsigned int resolution[2], unsigned int /*preferredResolution*/[2])
{
Scene *sce = this->getScene();
Render *re = (sce) ? RE_GetRender(sce->id.name) : NULL;
@@ -207,13 +205,6 @@ void RenderLayersBaseProg::determineResolution(unsigned int resolution[2], unsig
}
/* ******** Render Layers AO Operation ******** */
-
-RenderLayersAOOperation::RenderLayersAOOperation() : RenderLayersBaseProg(SCE_PASS_AO, 3)
-{
- this->addOutputSocket(COM_DT_COLOR);
-}
-
-
void RenderLayersAOOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
float *inputBuffer = this->getInputBuffer();
@@ -227,12 +218,6 @@ void RenderLayersAOOperation::executePixelSampled(float output[4], float x, floa
}
/* ******** Render Layers Alpha Operation ******** */
-
-RenderLayersAlphaProg::RenderLayersAlphaProg() : RenderLayersBaseProg(SCE_PASS_COMBINED, 4)
-{
- this->addOutputSocket(COM_DT_VALUE);
-}
-
void RenderLayersAlphaProg::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
float *inputBuffer = this->getInputBuffer();
@@ -247,27 +232,7 @@ void RenderLayersAlphaProg::executePixelSampled(float output[4], float x, float
}
}
-/* ******** Render Layers Color Operation ******** */
-
-RenderLayersColorOperation::RenderLayersColorOperation() : RenderLayersBaseProg(SCE_PASS_RGBA, 4)
-{
- this->addOutputSocket(COM_DT_COLOR);
-}
-
-/* ******** Render Layers Cycles Operation ******** */
-
-RenderLayersCyclesOperation::RenderLayersCyclesOperation(int pass) : RenderLayersBaseProg(pass, 3)
-{
- this->addOutputSocket(COM_DT_VECTOR);
-}
-
/* ******** Render Layers Depth Operation ******** */
-
-RenderLayersDepthProg::RenderLayersDepthProg() : RenderLayersBaseProg(SCE_PASS_Z, 1)
-{
- this->addOutputSocket(COM_DT_VALUE);
-}
-
void RenderLayersDepthProg::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
int ix = x;
@@ -281,135 +246,4 @@ void RenderLayersDepthProg::executePixelSampled(float output[4], float x, float
unsigned int offset = (iy * this->getWidth() + ix);
output[0] = inputBuffer[offset];
}
-}
-
-/* ******** Render Layers Diffuse Operation ******** */
-
-RenderLayersDiffuseOperation::RenderLayersDiffuseOperation() : RenderLayersBaseProg(SCE_PASS_DIFFUSE, 3)
-{
- this->addOutputSocket(COM_DT_VECTOR);
-}
-
-/* ******** Render Layers Emit Operation ******** */
-
-RenderLayersEmitOperation::RenderLayersEmitOperation() : RenderLayersBaseProg(SCE_PASS_EMIT, 3)
-{
- this->addOutputSocket(COM_DT_VECTOR);
-}
-
-/* ******** Render Layers Environment Operation ******** */
-
-RenderLayersEnvironmentOperation::RenderLayersEnvironmentOperation() : RenderLayersBaseProg(SCE_PASS_ENVIRONMENT, 3)
-{
- this->addOutputSocket(COM_DT_VECTOR);
-}
-
-/* ******** Render Layers Image Operation ******** */
-
-RenderLayersColorProg::RenderLayersColorProg() : RenderLayersBaseProg(SCE_PASS_COMBINED, 4)
-{
- this->addOutputSocket(COM_DT_COLOR);
-}
-
-/* ******** Render Layers Indirect Operation ******** */
-
-RenderLayersIndirectOperation::RenderLayersIndirectOperation() : RenderLayersBaseProg(SCE_PASS_INDIRECT, 3)
-{
- this->addOutputSocket(COM_DT_VECTOR);
-}
-
-/* ******** Render Layers Material Index Operation ******** */
-
-RenderLayersMaterialIndexOperation::RenderLayersMaterialIndexOperation() : RenderLayersBaseProg(SCE_PASS_INDEXMA, 1)
-{
- this->addOutputSocket(COM_DT_VALUE);
-}
-
-/* ******** Render Layers Mist Operation ******** */
-
-RenderLayersMistOperation::RenderLayersMistOperation() : RenderLayersBaseProg(SCE_PASS_MIST, 1)
-{
- this->addOutputSocket(COM_DT_VALUE);
-}
-
-/* ******** Render Layers Normal Operation ******** */
-
-RenderLayersNormalOperation::RenderLayersNormalOperation() : RenderLayersBaseProg(SCE_PASS_NORMAL, 3)
-{
- this->addOutputSocket(COM_DT_VECTOR);
-}
-
-/* ******** Render Layers Object Index Operation ******** */
-
-RenderLayersObjectIndexOperation::RenderLayersObjectIndexOperation() : RenderLayersBaseProg(SCE_PASS_INDEXOB, 1)
-{
- this->addOutputSocket(COM_DT_VALUE);
-}
-
-/* ******** Render Layers Reflection Operation ******** */
-
-RenderLayersReflectionOperation::RenderLayersReflectionOperation() : RenderLayersBaseProg(SCE_PASS_REFLECT, 3)
-{
- this->addOutputSocket(COM_DT_VECTOR);
-}
-
-/* ******** Render Layers Refraction Operation ******** */
-
-RenderLayersRefractionOperation::RenderLayersRefractionOperation() : RenderLayersBaseProg(SCE_PASS_REFRACT, 3)
-{
- this->addOutputSocket(COM_DT_VECTOR);
-}
-
-/* ******** Render Layers Shadow Operation ******** */
-
-RenderLayersShadowOperation::RenderLayersShadowOperation() : RenderLayersBaseProg(SCE_PASS_SHADOW, 3)
-{
- this->addOutputSocket(COM_DT_VECTOR);
-}
-
-/* ******** Render Layers Specular Operation ******** */
-
-RenderLayersSpecularOperation::RenderLayersSpecularOperation() : RenderLayersBaseProg(SCE_PASS_SPEC, 3)
-{
- this->addOutputSocket(COM_DT_VECTOR);
-}
-
-/* ******** Render Layers Speed Operation ******** */
-
-RenderLayersSpeedOperation::RenderLayersSpeedOperation() : RenderLayersBaseProg(SCE_PASS_VECTOR, 4)
-{
- this->addOutputSocket(COM_DT_COLOR);
-}
-
-/* ******** Render Layers UV Operation ******** */
-
-RenderLayersUVOperation::RenderLayersUVOperation() : RenderLayersBaseProg(SCE_PASS_UV, 3)
-{
- this->addOutputSocket(COM_DT_VECTOR);
-}
-
-/* ******** Debug Render Layers Cycles Operation ******** */
-
-#ifdef WITH_CYCLES_DEBUG
-
-RenderLayersCyclesDebugOperation::RenderLayersCyclesDebugOperation(
- int pass,
- int debug_pass_type)
- : RenderLayersBaseProg(pass, RE_debug_pass_num_channels_get(debug_pass_type))
-{
- switch (m_elementsize) {
- case 1:
- this->addOutputSocket(COM_DT_VALUE);
- break;
- case 3:
- this->addOutputSocket(COM_DT_VECTOR);
- break;
- case 4:
- this->addOutputSocket(COM_DT_COLOR);
- break;
- default:
- BLI_assert(!"Unkown debug pass type element size.");
- }
-}
-
-#endif
+} \ No newline at end of file
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.h b/source/blender/compositor/operations/COM_RenderLayersProg.h
index 89eb2a6954d..1be15906770 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.h
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.h
@@ -40,7 +40,7 @@ extern "C" {
*
* @todo: rename to operation.
*/
-class RenderLayersBaseProg : public NodeOperation {
+class RenderLayersProg : public NodeOperation {
protected:
/**
* Reference to the scene object.
@@ -65,7 +65,7 @@ protected:
/**
* renderpass where this operation needs to get its data from
*/
- int m_renderpass;
+ std::string m_passName;
int m_elementsize;
@@ -73,11 +73,6 @@ protected:
* @brief render data used for active rendering
*/
const RenderData *m_rd;
-
- /**
- * Constructor
- */
- RenderLayersBaseProg(int renderpass, int elementsize);
/**
* Determine the output resolution. The resolution is retrieved from the Renderer
@@ -92,6 +87,10 @@ protected:
void doInterpolation(float output[4], float x, float y, PixelSampler sampler);
public:
/**
+ * Constructor
+ */
+ RenderLayersProg(const char *passName, DataType type, int elementsize);
+ /**
* setter for the scene field. Will be called from
* @see RenderLayerNode to set the actual scene where
* the data will be retrieved from.
@@ -108,116 +107,25 @@ public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
};
-class RenderLayersAOOperation : public RenderLayersBaseProg {
+class RenderLayersAOOperation : public RenderLayersProg {
public:
- RenderLayersAOOperation();
+ RenderLayersAOOperation(const char *passName, DataType type, int elementsize)
+ : RenderLayersProg(passName, type, elementsize) {}
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
};
-class RenderLayersAlphaProg : public RenderLayersBaseProg {
+class RenderLayersAlphaProg : public RenderLayersProg {
public:
- RenderLayersAlphaProg();
+ RenderLayersAlphaProg(const char *passName, DataType type, int elementsize)
+ : RenderLayersProg(passName, type, elementsize) {}
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
};
-class RenderLayersColorOperation : public RenderLayersBaseProg {
-public:
- RenderLayersColorOperation();
-};
-
-class RenderLayersCyclesOperation : public RenderLayersBaseProg {
-public:
- RenderLayersCyclesOperation(int pass);
-};
-
-class RenderLayersDepthProg : public RenderLayersBaseProg {
+class RenderLayersDepthProg : public RenderLayersProg {
public:
- RenderLayersDepthProg();
+ RenderLayersDepthProg(const char *passName, DataType type, int elementsize)
+ : RenderLayersProg(passName, type, elementsize) {}
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
};
-class RenderLayersDiffuseOperation : public RenderLayersBaseProg {
-public:
- RenderLayersDiffuseOperation();
-};
-
-class RenderLayersEmitOperation : public RenderLayersBaseProg {
-public:
- RenderLayersEmitOperation();
-};
-
-class RenderLayersEnvironmentOperation : public RenderLayersBaseProg {
-public:
- RenderLayersEnvironmentOperation();
-};
-
-/// @todo rename to image operation
-class RenderLayersColorProg : public RenderLayersBaseProg {
-public:
- RenderLayersColorProg();
-};
-
-class RenderLayersIndirectOperation : public RenderLayersBaseProg {
-public:
- RenderLayersIndirectOperation();
-};
-
-class RenderLayersMaterialIndexOperation : public RenderLayersBaseProg {
-public:
- RenderLayersMaterialIndexOperation();
-};
-
-class RenderLayersMistOperation : public RenderLayersBaseProg {
-public:
- RenderLayersMistOperation();
-};
-
-class RenderLayersNormalOperation : public RenderLayersBaseProg {
-public:
- RenderLayersNormalOperation();
-};
-
-class RenderLayersObjectIndexOperation : public RenderLayersBaseProg {
-public:
- RenderLayersObjectIndexOperation();
-};
-
-class RenderLayersReflectionOperation : public RenderLayersBaseProg {
-public:
- RenderLayersReflectionOperation();
-};
-
-class RenderLayersRefractionOperation : public RenderLayersBaseProg {
-public:
- RenderLayersRefractionOperation();
-};
-
-class RenderLayersShadowOperation : public RenderLayersBaseProg {
-public:
- RenderLayersShadowOperation();
-};
-
-class RenderLayersSpecularOperation : public RenderLayersBaseProg {
-public:
- RenderLayersSpecularOperation();
-};
-
-class RenderLayersSpeedOperation : public RenderLayersBaseProg {
-public:
- RenderLayersSpeedOperation();
-};
-
-class RenderLayersUVOperation : public RenderLayersBaseProg {
-public:
- RenderLayersUVOperation();
-};
-
-#ifdef WITH_CYCLES_DEBUG
-class RenderLayersCyclesDebugOperation : public RenderLayersBaseProg {
-public:
- RenderLayersCyclesDebugOperation(int pass,
- int debug_pass_type);
-};
-#endif
-
#endif
diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp
index a681583809c..70e0b2cfb57 100644
--- a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp
+++ b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp
@@ -186,8 +186,8 @@ struct BufferLineAccumulator {
}
/* TODO implement proper filtering here, see
- * http://en.wikipedia.org/wiki/Lanczos_resampling
- * http://en.wikipedia.org/wiki/Sinc_function
+ * https://en.wikipedia.org/wiki/Lanczos_resampling
+ * https://en.wikipedia.org/wiki/Sinc_function
*
* using lanczos with x = distance from the line segment,
* normalized to a == 0.5f, could give a good result
diff --git a/source/blender/compositor/operations/COM_TextureOperation.cpp b/source/blender/compositor/operations/COM_TextureOperation.cpp
index 665bffc2c1c..d0c72935b16 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.cpp
+++ b/source/blender/compositor/operations/COM_TextureOperation.cpp
@@ -41,6 +41,7 @@ TextureBaseOperation::TextureBaseOperation() : NodeOperation()
this->m_rd = NULL;
this->m_pool = NULL;
this->m_sceneColorManage = false;
+ setComplex(true);
}
TextureOperation::TextureOperation() : TextureBaseOperation()
{
@@ -110,8 +111,18 @@ void TextureBaseOperation::executePixelSampled(float output[4], float x, float y
int retval;
const float cx = this->getWidth() / 2;
const float cy = this->getHeight() / 2;
- const float u = (x - cx) / this->getWidth() * 2;
- const float v = (y - cy) / this->getHeight() * 2;
+ float u = (x - cx) / this->getWidth() * 2;
+ float v = (y - cy) / this->getHeight() * 2;
+
+ /* When no interpolation/filtering happens in multitex() foce nearest interpolation.
+ * We do it here because (a) we can't easily say multitex() that we want nearest
+ * interpolaiton and (b) in such configuration multitex() sinply floor's the value
+ * which often produces artifacts.
+ */
+ if (m_texture != NULL && (m_texture->imaflag & TEX_INTERPOL) == 0) {
+ u += 0.5f / cx;
+ v += 0.5f / cy;
+ }
this->m_inputSize->readSampled(textureSize, x, y, sampler);
this->m_inputOffset->readSampled(textureOffset, x, y, sampler);
@@ -145,31 +156,3 @@ void TextureBaseOperation::executePixelSampled(float output[4], float x, float y
output[0] = output[1] = output[2] = output[3];
}
}
-
-MemoryBuffer *TextureBaseOperation::createMemoryBuffer(rcti * /*rect2*/)
-{
- int height = getHeight();
- int width = getWidth();
- DataType datatype = this->getOutputSocket()->getDataType();
- int add = 4;
- if (datatype == COM_DT_VALUE) {
- add = 1;
- }
-
- rcti rect;
- rect.xmin = 0;
- rect.ymin = 0;
- rect.xmax = width;
- rect.ymax = height;
- MemoryBuffer *result = new MemoryBuffer(datatype, &rect);
-
- float *data = result->getBuffer();
-
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++, data += add) {
- this->executePixelSampled(data, x, y, COM_PS_NEAREST);
- }
- }
-
- return result;
-}
diff --git a/source/blender/compositor/operations/COM_TextureOperation.h b/source/blender/compositor/operations/COM_TextureOperation.h
index 4cc203b54a2..59ff58a7289 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.h
+++ b/source/blender/compositor/operations/COM_TextureOperation.h
@@ -59,8 +59,6 @@ protected:
* Constructor
*/
TextureBaseOperation();
-
- MemoryBuffer *createMemoryBuffer(rcti *rect2);
public:
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp
index 1ec52571be8..9ff0bf9ce12 100644
--- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp
@@ -286,9 +286,9 @@ void InverseSearchRadiusOperation::initExecution()
this->m_inputRadius = this->getInputSocketReader(0);
}
-voi *InverseSearchRadiusOperation::initializeTileData(rcti *rect)
+void *InverseSearchRadiusOperation::initializeTileData(rcti *rect)
{
- MemoryBuffer * data = new MemoryBuffer(NULL, rect);
+ MemoryBuffer * data = new MemoryBuffer(COM_DT_COLOR, rect);
float *buffer = data->getBuffer();
int x, y;
int width = this->m_inputRadius->getWidth();
@@ -343,7 +343,7 @@ voi *InverseSearchRadiusOperation::initializeTileData(rcti *rect)
void InverseSearchRadiusOperation::executePixelChunk(float output[4], int x, int y, void *data)
{
MemoryBuffer *buffer = (MemoryBuffer *)data;
- buffer->readNoCheck(color, x, y);
+ buffer->readNoCheck(output, x, y);
}
void InverseSearchRadiusOperation::deinitializeTileData(rcti *rect, void *data)
diff --git a/source/blender/datatoc/CMakeLists.txt b/source/blender/datatoc/CMakeLists.txt
index 0f123fbf9f0..af7f954cad1 100644
--- a/source/blender/datatoc/CMakeLists.txt
+++ b/source/blender/datatoc/CMakeLists.txt
@@ -62,4 +62,9 @@ if(NOT WITH_HEADLESS)
add_executable(datatoc_icon ${SRC})
target_link_libraries(datatoc_icon ${PNG_LIBRARIES} ${ZLIB_LIBRARIES})
+ # PNG library uses pow() and floow(), so seems -lm is required for proper
+ # workign binary.
+ if(UNIX AND NOT APPLE)
+ target_link_libraries(datatoc_icon m)
+ endif()
endif()
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt
index fd2a521bec5..17a13b66aaa 100644
--- a/source/blender/depsgraph/CMakeLists.txt
+++ b/source/blender/depsgraph/CMakeLists.txt
@@ -43,11 +43,19 @@ set(SRC
intern/builder/deg_builder.cc
intern/builder/deg_builder_cycle.cc
intern/builder/deg_builder_nodes.cc
+ intern/builder/deg_builder_nodes_layer.cc
+ intern/builder/deg_builder_nodes_rig.cc
+ intern/builder/deg_builder_nodes_scene.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_layer.cc
+ intern/builder/deg_builder_relations_rig.cc
+ intern/builder/deg_builder_relations_scene.cc
intern/builder/deg_builder_transitive.cc
intern/debug/deg_debug_graphviz.cc
intern/eval/deg_eval.cc
+ intern/eval/deg_eval_copy_on_write.cc
intern/eval/deg_eval_debug.cc
intern/eval/deg_eval_flush.cc
intern/nodes/deg_node.cc
@@ -73,6 +81,7 @@ set(SRC
intern/builder/deg_builder_relations.h
intern/builder/deg_builder_transitive.h
intern/eval/deg_eval.h
+ intern/eval/deg_eval_copy_on_write.h
intern/eval/deg_eval_debug.h
intern/eval/deg_eval_flush.h
intern/nodes/deg_node.h
@@ -82,8 +91,8 @@ set(SRC
intern/depsgraph_intern.h
intern/depsgraph_types.h
+ util/deg_util_foreach.h
util/deg_util_function.h
- util/deg_util_hash.h
)
if(WITH_CXX11)
@@ -108,10 +117,6 @@ else()
endif()
endif()
-if(WITH_LEGACY_DEPSGRAPH)
- add_definitions(-DWITH_LEGACY_DEPSGRAPH)
-endif()
-
if(WITH_BOOST)
list(APPEND INC_SYS
${BOOST_INCLUDE_DIR}
@@ -123,4 +128,8 @@ if(WITH_OPENSUBDIV)
add_definitions(-DWITH_OPENSUBDIV)
endif()
+if(WITH_DEPSGRAPH_COPY_ON_WRITE)
+ add_definitions(-DWITH_COPY_ON_WRITE)
+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 945a4785b9c..9347a29b14a 100644
--- a/source/blender/depsgraph/DEG_depsgraph.h
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -66,6 +66,35 @@ struct Main;
struct PointerRNA;
struct PropertyRNA;
+/* 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;
+ float ctime;
+} 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,
+};
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -115,10 +144,31 @@ void DEG_graph_data_tag_update(Depsgraph *graph, const struct PointerRNA *ptr);
void DEG_graph_property_tag_update(Depsgraph *graph, const struct PointerRNA *ptr, const struct PropertyRNA *prop);
/* Tag given ID for an update in all the dependency graphs. */
-void DEG_id_tag_update(struct ID *id, short flag);
+enum {
+ /* Object transformation changed, corresponds to OB_RECALC_OB. */
+ DEG_TAG_TRANSFORM = (1 << 0),
+
+ /* Object geoemtry 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. */
+ DEG_TAG_PSYSC_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 = ((1 << 3) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7)),
+
+ /* Update copy on write component without flushing down the road. */
+ DEG_TAG_COPY_ON_WRITE = (1 << 8),
+};
+void DEG_id_tag_update(struct ID *id, int flag);
void DEG_id_tag_update_ex(struct Main *bmain,
struct ID *id,
- short flag);
+ int flag);
/* Tag given ID type for update.
*
@@ -132,7 +182,7 @@ void DEG_ids_clear_recalc(struct Main *bmain);
/* Update Flushing ------------------------------- */
/* Flush updates for all IDs */
-void DEG_ids_flush_tagged(struct Main *bmain);
+void DEG_ids_flush_tagged(struct Main *bmain, struct Scene *scene);
/* Check if something was changed in the database and inform
* editors about this.
@@ -167,16 +217,13 @@ void DEG_evaluation_context_free(struct EvaluationContext *eval_ctx);
void DEG_evaluate_on_framechange(struct EvaluationContext *eval_ctx,
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);
+ Depsgraph *graph);
/* Data changed recalculation entry point.
* < context_type: context to perform evaluation for
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
index 0209e94debe..8c3ddec40a4 100644
--- a/source/blender/depsgraph/DEG_depsgraph_build.h
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -40,7 +40,12 @@ struct Depsgraph;
/* ------------------------------------------------ */
+struct CacheFile;
+struct EffectorWeights;
+struct Group;
struct Main;
+struct ModifierData;
+struct Object;
struct Scene;
#ifdef __cplusplus
@@ -49,8 +54,12 @@ extern "C" {
/* 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);
+/* 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);
/* Tag relations from the given graph for update. */
void DEG_graph_tag_relations_update(struct Depsgraph *graph);
@@ -79,39 +88,94 @@ void DEG_scene_graph_free(struct Scene *scene);
*/
struct DepsNodeHandle;
-struct CacheFile;
-struct Object;
-
typedef enum eDepsSceneComponentType {
- DEG_SCENE_COMP_PARAMETERS, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */
- DEG_SCENE_COMP_ANIMATION, /* Animation Component */ // XXX: merge in with parameters?
- DEG_SCENE_COMP_SEQUENCER, /* Sequencer Component (Scene Only) */
+ /* Parameters Component - Default when nothing else fits
+ * (i.e. just SDNA property setting).
+ */
+ DEG_SCENE_COMP_PARAMETERS,
+ /* Animation Component
+ * TODO(sergey): merge in with parameters?
+ */
+ DEG_SCENE_COMP_ANIMATION,
+ /* Sequencer Component (Scene Only). */
+ DEG_SCENE_COMP_SEQUENCER,
} eDepsSceneComponentType;
typedef enum eDepsObjectComponentType {
- DEG_OB_COMP_PARAMETERS, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */
- DEG_OB_COMP_PROXY, /* Generic "Proxy-Inherit" Component */ // XXX: Also for instancing of subgraphs?
- DEG_OB_COMP_ANIMATION, /* Animation Component */ // XXX: merge in with parameters?
- DEG_OB_COMP_TRANSFORM, /* Transform Component (Parenting/Constraints) */
- DEG_OB_COMP_GEOMETRY, /* Geometry Component (DerivedMesh/Displist) */
-
+ /* Parameters Component - Default when nothing else fits
+ * (i.e. just SDNA property setting).
+ */
+ DEG_OB_COMP_PARAMETERS,
+ /* Generic "Proxy-Inherit" Component.
+ * TODO(sergey): Also for instancing of subgraphs?
+ */
+ DEG_OB_COMP_PROXY,
+ /* Animation Component.
+ *
+ * TODO(sergey): merge in with parameters?
+ */
+ DEG_OB_COMP_ANIMATION,
+ /* Transform Component (Parenting/Constraints) */
+ DEG_OB_COMP_TRANSFORM,
+ /* Geometry Component (DerivedMesh/Displist) */
+ DEG_OB_COMP_GEOMETRY,
+
/* Evaluation-Related Outer Types (with Subdata) */
- DEG_OB_COMP_EVAL_POSE, /* Pose Component - Owner/Container of Bones Eval */
- DEG_OB_COMP_BONE, /* Bone Component - Child/Subcomponent of Pose */
-
- DEG_OB_COMP_EVAL_PARTICLES, /* Particle Systems Component */
- DEG_OB_COMP_SHADING, /* Material Shading Component */
- DEG_OB_COMP_CACHE, /* Cache Component */
-} eDepsObjectComponentType;
-void DEG_add_scene_relation(struct DepsNodeHandle *node, struct Scene *scene, eDepsSceneComponentType component, const char *description);
-void DEG_add_object_relation(struct DepsNodeHandle *node, struct Object *ob, eDepsObjectComponentType component, const char *description);
-void DEG_add_bone_relation(struct DepsNodeHandle *handle, struct Object *ob, const char *bone_name, eDepsObjectComponentType component, const char *description);
-void DEG_add_object_cache_relation(struct DepsNodeHandle *handle, struct CacheFile *cache_file, eDepsObjectComponentType component, const char *description);
+ /* Pose Component - Owner/Container of Bones Eval */
+ DEG_OB_COMP_EVAL_POSE,
+ /* 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;
-/* TODO(sergey): Remove once all geometry update is granular. */
+void DEG_add_scene_relation(struct DepsNodeHandle *node,
+ struct Scene *scene,
+ eDepsSceneComponentType component,
+ const char *description);
+void DEG_add_object_relation(struct DepsNodeHandle *node, struct
+ Object *ob,
+ eDepsObjectComponentType component,
+ const char *description);
+void DEG_add_bone_relation(struct DepsNodeHandle *handle,
+ struct Object *ob,
+ const char *bone_name,
+ eDepsObjectComponentType component,
+ const char *description);
+void DEG_add_object_cache_relation(struct DepsNodeHandle *handle,
+ struct CacheFile *cache_file,
+ eDepsObjectComponentType component,
+ const char *description);
+
+
+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 *ob,
+ struct Group *group,
+ 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 *ob,
+ struct EffectorWeights *eff,
+ bool add_absorption,
+ int skip_forcefield,
+ const char *name);
+
/* ************************************************ */
#ifdef __cplusplus
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
index ccd204a2083..04584c07d4b 100644
--- a/source/blender/depsgraph/DEG_depsgraph_query.h
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -33,9 +33,17 @@
#ifndef __DEG_DEPSGRAPH_QUERY_H__
#define __DEG_DEPSGRAPH_QUERY_H__
+#include "DEG_depsgraph.h"
+
struct ID;
+struct Base;
+struct BLI_Iterator;
struct Depsgraph;
+struct DupliObject;
+struct ListBase;
+struct Scene;
+struct SceneLayer;
#ifdef __cplusplus
extern "C" {
@@ -47,6 +55,76 @@ bool DEG_id_type_tagged(struct Main *bmain, short idtype);
/* Get additional evaluation flags for the given ID. */
short DEG_get_eval_flags_for_id(struct Depsgraph *graph, struct ID *id);
+/* Get scene the despgraph is created for. */
+struct Scene *DEG_get_evaluated_scene(struct Depsgraph *graph);
+
+/* Get scene layer the despgraph is created for. */
+struct SceneLayer *DEG_get_evaluated_scene_layer(struct Depsgraph *graph);
+
+/* Get evaluated version of object for given original one. */
+struct Object *DEG_get_evaluated_object(struct Depsgraph *depsgraph, struct Object *object);
+
+/* Get evaluated version of given ID datablock. */
+struct ID *DEG_get_evaluated_id(struct Depsgraph *depsgraph, struct ID *id);
+
+/* ************************ DAG iterators ********************* */
+
+enum {
+ DEG_OBJECT_ITER_FLAG_SET = (1 << 0),
+ DEG_OBJECT_ITER_FLAG_DUPLI = (1 << 1),
+};
+
+#define DEG_OBJECT_ITER_FLAG_ALL (DEG_OBJECT_ITER_FLAG_SET | DEG_OBJECT_ITER_FLAG_DUPLI)
+
+typedef struct DEGObjectsIteratorData {
+ struct Depsgraph *graph;
+ struct Scene *scene;
+ struct EvaluationContext eval_ctx;
+
+ /* TODO(sergey): Base should never be a thing coming FROM depsgraph. */
+ struct Base *base;
+ int base_flag;
+ int flag;
+
+ /* **** 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;
+} DEGObjectsIteratorData;
+
+void DEG_objects_iterator_begin(struct BLI_Iterator *iter, DEGObjectsIteratorData *data);
+void DEG_objects_iterator_next(struct BLI_Iterator *iter);
+void DEG_objects_iterator_end(struct BLI_Iterator *iter);
+
+/* Temporary hacky solution waiting for cow depsgraph implementation. */
+#define DEG_OBJECT_ITER(graph_, instance_, flag_) \
+ { \
+ DEGObjectsIteratorData data_ = { \
+ .graph = (graph_), \
+ .flag = (flag_), \
+ }; \
+ \
+ ITER_BEGIN(DEG_objects_iterator_begin, \
+ DEG_objects_iterator_next, \
+ DEG_objects_iterator_end, \
+ &data_, Object *, instance_)
+
+#define DEG_OBJECT_ITER_END \
+ ITER_END \
+ }
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
index 6169100d574..92c79388657 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -30,10 +30,9 @@
#include "intern/builder/deg_builder.h"
-// TODO(sergey): Use own wrapper over STD.
-#include <stack>
-
#include "DNA_anim_types.h"
+#include "DNA_object_types.h"
+#include "DNA_ID.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -41,87 +40,32 @@
#include "intern/depsgraph.h"
#include "intern/depsgraph_types.h"
#include "intern/nodes/deg_node.h"
-#include "intern/nodes/deg_node_component.h"
-#include "intern/nodes/deg_node_operation.h"
-
-#include "util/deg_util_foreach.h"
namespace DEG {
-string deg_fcurve_id_name(const FCurve *fcu)
-{
- char index_buf[32];
- // TODO(sergey): Use int-to-string utility or so.
- BLI_snprintf(index_buf, sizeof(index_buf), "[%d]", fcu->array_index);
- return string(fcu->rna_path) + index_buf;
-}
-
void deg_graph_build_finalize(Depsgraph *graph)
{
- std::stack<OperationDepsNode *> 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) {
- if ((rel->from->type == DEPSNODE_TYPE_OPERATION) &&
- (rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
- {
- ++node->num_links_pending;
- }
- }
- if (node->num_links_pending == 0) {
- stack.push(node);
- node->done = 1;
- }
- node->owner->layers = id_node->layers;
- id_node->id->tag |= LIB_TAG_DOIT;
- }
-
- while (!stack.empty()) {
- OperationDepsNode *node = stack.top();
- stack.pop();
- /* Flush layers to parents. */
- foreach (DepsRelation *rel, node->inlinks) {
- if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
- OperationDepsNode *from = (OperationDepsNode *)rel->from;
- from->owner->layers |= node->owner->layers;
- }
- }
- /* Schedule parent nodes. */
- foreach (DepsRelation *rel, node->inlinks) {
- if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
- OperationDepsNode *from = (OperationDepsNode *)rel->from;
- if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
- BLI_assert(from->num_links_pending > 0);
- --from->num_links_pending;
- }
- if (from->num_links_pending == 0 && from->done == 0) {
- stack.push(from);
- from->done = 1;
- }
- }
- }
- }
-
- /* Re-tag IDs for update if it was tagged before the relations update tag. */
+ /* Re-tag IDs for update if it was tagged before the relations
+ * update tag.
+ */
GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash)
{
- GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp, id_node->components)
- {
- id_node->layers |= comp->layers;
- }
- GHASH_FOREACH_END();
-
- ID *id = id_node->id;
- if (id->tag & LIB_TAG_ID_RECALC_ALL &&
- id->tag & LIB_TAG_DOIT)
- {
+ ID *id = id_node->id_orig;
+ id_node->finalize_build(graph);
+ if ((id->tag & LIB_TAG_ID_RECALC_ALL)) {
id_node->tag_update(graph);
- id->tag &= ~LIB_TAG_DOIT;
}
- id_node->finalize_build();
+ else if (GS(id->name) == ID_OB) {
+ Object *object = (Object *)id;
+ if (object->recalc & OB_RECALC_ALL) {
+ id_node->tag_update(graph);
+ }
+ }
+ /* XXX: This is only so we've got proper COW IDs after rebuild. */
+ /* TODO(sergey): Ideally we'll need to copy evaluated CoW from previous
+ * depsgraph, so we don't need to re-tag anything what we already have.
+ */
+ id_node->tag_update(graph);
}
GHASH_FOREACH_END();
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h
index bdc030e3810..c0731eeac20 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder.h
@@ -30,17 +30,10 @@
#pragma once
-#include "intern/depsgraph_types.h"
-
-struct FCurve;
-
namespace DEG {
struct Depsgraph;
-/* Get unique identifier for FCurves and Drivers */
-string deg_fcurve_id_name(const FCurve *fcu);
-
void deg_graph_build_finalize(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 225cc64ae4d..3eed0697b5e 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
@@ -32,11 +32,9 @@
// TOO(sergey): Use some wrappers over those?
#include <cstdio>
#include <cstdlib>
-#include <stack>
-extern "C" {
#include "BLI_utildefines.h"
-}
+#include "BLI_stack.h"
#include "util/deg_util_foreach.h"
@@ -48,26 +46,30 @@ extern "C" {
namespace DEG {
-struct StackEntry {
- OperationDepsNode *node;
- StackEntry *from;
- DepsRelation *via_relation;
-};
-
void deg_graph_detect_cycles(Depsgraph *graph)
{
- /* Not is not visited at all during traversal. */
- const int NODE_NOT_VISITED = 0;
- /* Node has been visited during traversal and not in current stack. */
- const int NODE_VISITED = 1;
- /* Node has been visited during traversal and is in current stack. */
- const int NODE_IN_STACK = 2;
-
- std::stack<StackEntry> traversal_stack;
+ enum {
+ /* Not is not visited at all during traversal. */
+ NODE_NOT_VISITED = 0,
+ /* Node has been visited during traversal and not in current stack. */
+ NODE_VISITED = 1,
+ /* Node has been visited during traversal and is in current stack. */
+ NODE_IN_STACK = 2,
+ };
+
+ struct StackEntry {
+ OperationDepsNode *node;
+ StackEntry *from;
+ DepsRelation *via_relation;
+ };
+
+ BLI_Stack *traversal_stack = BLI_stack_new(sizeof(StackEntry),
+ "DEG detect cycles stack");
+
foreach (OperationDepsNode *node, graph->operations) {
bool has_inlinks = false;
foreach (DepsRelation *rel, node->inlinks) {
- if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
+ if (rel->from->type == DEG_NODE_TYPE_OPERATION) {
has_inlinks = true;
}
}
@@ -76,29 +78,31 @@ void deg_graph_detect_cycles(Depsgraph *graph)
entry.node = node;
entry.from = NULL;
entry.via_relation = NULL;
- traversal_stack.push(entry);
- node->done = NODE_IN_STACK;
+ BLI_stack_push(traversal_stack, &entry);
+ node->tag = NODE_IN_STACK;
}
else {
- node->done = NODE_NOT_VISITED;
+ node->tag = NODE_NOT_VISITED;
}
+ node->done = 0;
}
- while (!traversal_stack.empty()) {
- StackEntry &entry = traversal_stack.top();
- OperationDepsNode *node = entry.node;
+ while (!BLI_stack_is_empty(traversal_stack)) {
+ StackEntry *entry = (StackEntry *)BLI_stack_peek(traversal_stack);
+ OperationDepsNode *node = entry->node;
bool all_child_traversed = true;
- foreach (DepsRelation *rel, node->outlinks) {
- if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
+ for (int i = node->done; i < node->outlinks.size(); ++i) {
+ DepsRelation *rel = node->outlinks[i];
+ if (rel->to->type == DEG_NODE_TYPE_OPERATION) {
OperationDepsNode *to = (OperationDepsNode *)rel->to;
- if (to->done == NODE_IN_STACK) {
+ if (to->tag == NODE_IN_STACK) {
printf("Dependency cycle detected:\n");
printf(" '%s' depends on '%s' through '%s'\n",
to->full_identifier().c_str(),
node->full_identifier().c_str(),
rel->name);
- StackEntry *current = &entry;
+ StackEntry *current = entry;
while (current->node != to) {
BLI_assert(current != NULL);
printf(" '%s' depends on '%s' through '%s'\n",
@@ -107,26 +111,29 @@ void deg_graph_detect_cycles(Depsgraph *graph)
current->via_relation->name);
current = current->from;
}
- /* TODO(sergey): So called roussian rlette cycle solver. */
+ /* TODO(sergey): So called russian roulette cycle solver. */
rel->flag |= DEPSREL_FLAG_CYCLIC;
}
- else if (to->done == NODE_NOT_VISITED) {
+ else if (to->tag == NODE_NOT_VISITED) {
StackEntry new_entry;
new_entry.node = to;
- new_entry.from = &entry;
+ new_entry.from = entry;
new_entry.via_relation = rel;
- traversal_stack.push(new_entry);
- to->done = NODE_IN_STACK;
+ BLI_stack_push(traversal_stack, &new_entry);
+ to->tag = NODE_IN_STACK;
all_child_traversed = false;
+ node->done = i;
break;
}
}
}
if (all_child_traversed) {
- node->done = NODE_VISITED;
- traversal_stack.pop();
+ node->tag = NODE_VISITED;
+ BLI_stack_discard(traversal_stack);
}
}
+
+ BLI_stack_free(traversal_stack);
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index 1812384440f..935b8c543ec 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -34,15 +34,14 @@
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include "MEM_guardedalloc.h"
-extern "C" {
#include "BLI_blenlib.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
+extern "C" {
#include "DNA_action_types.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
@@ -56,11 +55,14 @@ extern "C" {
#include "DNA_key_types.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
+#include "DNA_mask_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
+#include "DNA_movieclip_types.h"
#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_texture_types.h"
@@ -71,7 +73,6 @@ extern "C" {
#include "BKE_animsys.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_effect.h"
#include "BKE_fcurve.h"
#include "BKE_idcode.h"
@@ -93,22 +94,58 @@ extern "C" {
#include "BKE_tracking.h"
#include "BKE_world.h"
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_build.h"
-
#include "RNA_access.h"
#include "RNA_types.h"
} /* extern "C" */
+#include "DEG_depsgraph.h"
+#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"
#include "intern/depsgraph_types.h"
#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
namespace DEG {
+namespace {
+
+struct BuilderWalkUserData {
+ DepsgraphNodeBuilder *builder;
+ Scene *scene;
+};
+
+static void modifier_walk(void *user_data,
+ struct Object * /*ob*/,
+ struct Object **obpoin,
+ int /*cb_flag*/)
+{
+ BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
+ if (*obpoin) {
+ data->builder->build_object(data->scene, *obpoin);
+ }
+}
+
+void constraint_walk(bConstraint * /*con*/,
+ ID **idpoin,
+ bool /*is_reference*/,
+ void *user_data)
+{
+ BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
+ if (*idpoin) {
+ ID *id = *idpoin;
+ if (GS(id->name) == ID_OB) {
+ data->builder->build_object(data->scene, (Object *)id);
+ }
+ }
+}
+
+} /* namespace */
+
/* ************ */
/* Node Builder */
@@ -124,62 +161,36 @@ DepsgraphNodeBuilder::~DepsgraphNodeBuilder()
{
}
-RootDepsNode *DepsgraphNodeBuilder::add_root_node()
-{
- return m_graph->add_root_node();
-}
-
IDDepsNode *DepsgraphNodeBuilder::add_id_node(ID *id)
{
- const char *idtype_name = BKE_idcode_to_name(GS(id->name));
- return m_graph->add_id_node(id, string(id->name + 2) + "[" + idtype_name + "]");
+ IDDepsNode *id_node = m_graph->add_id_node(id, id->name);
+#ifdef WITH_COPY_ON_WRITE
+ /* 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_size(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, m_graph, id_node),
+ DEG_OPCODE_COPY_ON_WRITE,
+ "", -1);
+ m_graph->operations.push_back(op_cow);
+ }
+#endif
+ return id_node;
}
-TimeSourceDepsNode *DepsgraphNodeBuilder::add_time_source(ID *id)
+TimeSourceDepsNode *DepsgraphNodeBuilder::add_time_source()
{
- /* determine which node to attach timesource to */
- if (id) {
-#if 0 /* XXX TODO */
- /* get ID node */
- IDDepsNode id_node = m_graph->find_id_node(id);
-
- /* depends on what this is... */
- switch (GS(id->name)) {
- case ID_SCE: /* Scene - Usually sequencer strip causing time remapping... */
- {
- // TODO...
- }
- break;
-
- case ID_GR: /* Group */
- {
- // TODO...
- }
- break;
-
- // XXX: time source...
-
- default: /* Unhandled */
- printf("%s(): Unhandled ID - %s \n", __func__, id->name);
- break;
- }
-#endif
- }
- else {
- /* root-node */
- RootDepsNode *root_node = m_graph->root_node;
- if (root_node) {
- return root_node->add_time_source("Time Source");
- }
- }
-
- return NULL;
+ return m_graph->add_time_source();
}
ComponentDepsNode *DepsgraphNodeBuilder::add_component_node(
ID *id,
eDepsNode_Type comp_type,
- const string &comp_name)
+ const char *comp_name)
{
IDDepsNode *id_node = add_id_node(id);
ComponentDepsNode *comp_node = id_node->add_component(comp_type, comp_name);
@@ -189,18 +200,21 @@ ComponentDepsNode *DepsgraphNodeBuilder::add_component_node(
OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
ComponentDepsNode *comp_node,
- eDepsOperation_Type optype,
- DepsEvalOperationCb op,
+ const DepsEvalOperationCb& op,
eDepsOperation_Code opcode,
- const string &description)
+ const char *name,
+ int name_tag)
{
- OperationDepsNode *op_node = comp_node->has_operation(opcode, description);
+ OperationDepsNode *op_node = comp_node->has_operation(opcode,
+ name,
+ name_tag);
if (op_node == NULL) {
- op_node = comp_node->add_operation(optype, op, opcode, description);
+ op_node = comp_node->add_operation(op, opcode, name, name_tag);
m_graph->operations.push_back(op_node);
}
else {
- fprintf(stderr, "add_operation: Operation already exists - %s has %s at %p\n",
+ fprintf(stderr,
+ "add_operation: Operation already exists - %s has %s at %p\n",
comp_node->identifier().c_str(),
op_node->identifier().c_str(),
op_node);
@@ -212,60 +226,78 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
ID *id,
eDepsNode_Type comp_type,
- const string &comp_name,
- eDepsOperation_Type optype,
- DepsEvalOperationCb op,
+ const char *comp_name,
+ const DepsEvalOperationCb& op,
eDepsOperation_Code opcode,
- const string &description)
+ const char *name,
+ int name_tag)
{
ComponentDepsNode *comp_node = add_component_node(id, comp_type, comp_name);
- return add_operation_node(comp_node, optype, op, opcode, description);
+ return add_operation_node(comp_node, op, opcode, name, name_tag);
}
OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
ID *id,
eDepsNode_Type comp_type,
- eDepsOperation_Type optype,
- DepsEvalOperationCb op,
+ const DepsEvalOperationCb& op,
eDepsOperation_Code opcode,
- const string& description)
+ const char *name,
+ int name_tag)
{
- return add_operation_node(id, comp_type, "", optype, op, opcode, description);
+ return add_operation_node(id,
+ comp_type,
+ "",
+ op,
+ opcode,
+ name,
+ name_tag);
}
bool DepsgraphNodeBuilder::has_operation_node(ID *id,
eDepsNode_Type comp_type,
- const string &comp_name,
+ const char *comp_name,
eDepsOperation_Code opcode,
- const string &description)
+ const char *name,
+ int name_tag)
{
- return find_operation_node(id, comp_type, comp_name, opcode, description) != NULL;
+ return find_operation_node(id,
+ comp_type,
+ comp_name,
+ opcode,
+ name,
+ name_tag) != NULL;
}
OperationDepsNode *DepsgraphNodeBuilder::find_operation_node(
ID *id,
eDepsNode_Type comp_type,
- const string &comp_name,
+ const char *comp_name,
eDepsOperation_Code opcode,
- const string &description)
+ const char *name,
+ int name_tag)
{
ComponentDepsNode *comp_node = add_component_node(id, comp_type, comp_name);
- return comp_node->has_operation(opcode, description);
+ return comp_node->has_operation(opcode, name, name_tag);
}
OperationDepsNode *DepsgraphNodeBuilder::find_operation_node(
ID *id,
eDepsNode_Type comp_type,
eDepsOperation_Code opcode,
- const string& description)
+ const char *name,
+ int name_tag)
{
- return find_operation_node(id, comp_type, "", opcode, description);
+ return find_operation_node(id, comp_type, "", opcode, name, name_tag);
+}
+
+ID *DepsgraphNodeBuilder::get_cow_id(const ID *id_orig) const
+{
+ return m_graph->get_cow_id(id_orig);
}
/* **** Build functions for entity nodes **** */
-void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene)
-{
+void DepsgraphNodeBuilder::begin_build(Main *bmain) {
/* LIB_TAG_DOIT is used to indicate whether node for given ID was already
* created or not. This flag is being set in add_id_node(), so functions
* shouldn't bother with setting it, they only might query this flag when
@@ -276,83 +308,13 @@ void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene)
* so we need to do this manually.
*/
FOREACH_NODETREE(bmain, nodetree, id) {
- if (id != (ID *)nodetree)
+ if (id != (ID *)nodetree) {
nodetree->id.tag &= ~LIB_TAG_DOIT;
- } FOREACH_NODETREE_END
-
- /* scene ID block */
- add_id_node(&scene->id);
-
- /* timesource */
- add_time_source(NULL);
-
- /* 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) {
- build_scene(bmain, scene->set);
- }
-
- /* scene objects */
- for (Base *base = (Base *)scene->base.first; base; base = base->next) {
- Object *ob = base->object;
-
- /* object itself */
- build_object(scene, base, ob);
-
- /* object that this is a proxy for */
- // XXX: the way that proxies work needs to be completely reviewed!
- if (ob->proxy) {
- ob->proxy->proxy_from = ob;
- build_object(scene, base, ob->proxy);
- }
-
- /* Object dupligroup. */
- if (ob->dup_group) {
- build_group(scene, base, ob->dup_group);
}
- }
-
- /* rigidbody */
- if (scene->rigidbody_world) {
- build_rigidbody(scene);
- }
-
- /* scene's animation and drivers */
- if (scene->adt) {
- build_animdata(&scene->id);
- }
-
- /* world */
- if (scene->world) {
- build_world(scene->world);
- }
-
- /* compo nodes */
- if (scene->nodetree) {
- build_compositor(scene);
- }
-
- /* sequencer */
- // XXX...
-
- /* grease pencil */
- if (scene->gpd) {
- build_gpencil(scene->gpd);
- }
-
- /* cache files */
- for (CacheFile *cachefile = static_cast<CacheFile *>(bmain->cachefiles.first);
- cachefile;
- cachefile = static_cast<CacheFile *>(cachefile->id.next))
- {
- build_cachefile(cachefile);
- }
+ } FOREACH_NODETREE_END
}
-void DepsgraphNodeBuilder::build_group(Scene *scene,
- Base *base,
- Group *group)
+void DepsgraphNodeBuilder::build_group(Scene *scene, Group *group)
{
ID *group_id = &group->id;
if (group_id->tag & LIB_TAG_DOIT) {
@@ -360,66 +322,44 @@ void DepsgraphNodeBuilder::build_group(Scene *scene,
}
group_id->tag |= LIB_TAG_DOIT;
- for (GroupObject *go = (GroupObject *)group->gobject.first;
- go != NULL;
- go = go->next)
- {
- build_object(scene, base, go->ob);
+ LINKLIST_FOREACH (GroupObject *, go, &group->gobject) {
+ build_object(scene, go->ob);
}
}
-SubgraphDepsNode *DepsgraphNodeBuilder::build_subgraph(Group *group)
-{
- /* sanity checks */
- if (!group)
- return NULL;
-
- /* create new subgraph's data */
- Depsgraph *subgraph = reinterpret_cast<Depsgraph *>(DEG_graph_new());
-
- DepsgraphNodeBuilder subgraph_builder(m_bmain, subgraph);
-
- /* add group objects */
- for (GroupObject *go = (GroupObject *)group->gobject.first;
- go != NULL;
- go = go->next)
- {
- /*Object *ob = go->ob;*/
-
- /* Each "group object" is effectively a separate instance of the underlying
- * object data. When the group is evaluated, the transform results and/or
- * some other attributes end up getting overridden by the group
- */
- }
-
- /* create a node for representing subgraph */
- SubgraphDepsNode *subgraph_node = m_graph->add_subgraph_node(&group->id);
- subgraph_node->graph = subgraph;
-
- /* make a copy of the data this node will need? */
- // XXX: do we do this now, or later?
- // TODO: need API function which queries graph's ID's hash, and duplicates those blocks thoroughly with all outside links removed...
-
- return subgraph_node;
-}
-
-void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
+void DepsgraphNodeBuilder::build_object(Scene *scene, Object *ob)
{
+ /* Skip rest of components if the ID node was already there. */
if (ob->id.tag & LIB_TAG_DOIT) {
- IDDepsNode *id_node = m_graph->find_id_node(&ob->id);
- id_node->layers |= base->lay;
return;
}
+ ob->id.tag |= LIB_TAG_DOIT;
+ /* Create ID node for obejct and begin init. */
IDDepsNode *id_node = add_id_node(&ob->id);
- id_node->layers |= base->lay;
ob->customdata_mask = 0;
- /* standard components */
+ /* Standard components. */
build_object_transform(scene, ob);
- /* object data */
- if (ob->data) {
+ if (ob->parent != NULL) {
+ build_object(scene, ob->parent);
+ }
+ if (ob->modifiers.first != NULL) {
+ BuilderWalkUserData data;
+ data.builder = this;
+ data.scene = scene;
+ modifiers_foreachObjectLink(ob, modifier_walk, &data);
+ }
+ if (ob->constraints.first != NULL) {
+ BuilderWalkUserData data;
+ data.builder = this;
+ data.scene = scene;
+ BKE_constraints_id_loop(&ob->constraints, constraint_walk, &data);
+ }
+
+ /* Object data. */
+ if (ob->data != NULL) {
/* type-specific data... */
switch (ob->type) {
case OB_MESH: /* Geometry */
@@ -428,15 +368,6 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
case OB_SURF:
case OB_MBALL:
case OB_LATTICE:
- {
- /* TODO(sergey): This way using this object's
- * properties as driver target works fine.
- *
- * Does this depend on other nodes?
- */
- add_operation_node(&ob->id, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_POST, NULL,
- DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
-
build_obdata_geom(scene, ob);
/* TODO(sergey): Only for until we support granular
* update of curves.
@@ -448,7 +379,6 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
}
}
break;
- }
case OB_ARMATURE: /* Pose */
if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from != NULL) {
@@ -467,6 +397,10 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
build_camera(ob);
break;
+ case OB_LIGHTPROBE:
+ build_lightprobe(ob);
+ break;
+
default:
{
ID *obdata = (ID *)ob->data;
@@ -487,50 +421,67 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
build_animdata(&ob->id);
/* particle systems */
- if (ob->particlesystem.first) {
+ if (ob->particlesystem.first != NULL) {
build_particles(scene, ob);
}
- /* grease pencil */
- if (ob->gpd) {
+ /* Grease pencil. */
+ if (ob->gpd != NULL) {
build_gpencil(ob->gpd);
}
+
+ /* Object that this is a proxy for. */
+ if (ob->proxy) {
+ ob->proxy->proxy_from = ob;
+ build_object(scene, ob->proxy);
+ }
+
+ /* Object dupligroup. */
+ if (ob->dup_group != NULL) {
+ build_group(scene, ob->dup_group);
+ }
}
void DepsgraphNodeBuilder::build_object_transform(Scene *scene, Object *ob)
{
+ OperationDepsNode *op_node;
+ Scene *scene_cow = get_cow_datablock(scene);
+ Object *ob_cow = get_cow_datablock(ob);
+
/* local transforms (from transform channels - loc/rot/scale + deltas) */
- add_operation_node(&ob->id, DEPSNODE_TYPE_TRANSFORM,
- DEPSOP_TYPE_INIT, function_bind(BKE_object_eval_local_transform, _1, scene, ob),
- DEG_OPCODE_TRANSFORM_LOCAL);
+ op_node = add_operation_node(&ob->id, DEG_NODE_TYPE_TRANSFORM,
+ function_bind(BKE_object_eval_local_transform,
+ _1,
+ scene_cow, ob_cow),
+ DEG_OPCODE_TRANSFORM_LOCAL);
+ op_node->set_as_entry();
/* object parent */
- if (ob->parent) {
- add_operation_node(&ob->id, DEPSNODE_TYPE_TRANSFORM,
- DEPSOP_TYPE_EXEC, function_bind(BKE_object_eval_parent, _1, scene, ob),
+ if (ob->parent != NULL) {
+ add_operation_node(&ob->id, DEG_NODE_TYPE_TRANSFORM,
+ function_bind(BKE_object_eval_parent,
+ _1,
+ scene_cow, ob_cow),
DEG_OPCODE_TRANSFORM_PARENT);
}
/* object constraints */
- if (ob->constraints.first) {
+ if (ob->constraints.first != NULL) {
build_object_constraints(scene, ob);
}
- /* 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.
- */
- add_operation_node(&ob->id, DEPSNODE_TYPE_TRANSFORM,
- DEPSOP_TYPE_EXEC, function_bind(BKE_object_eval_uber_transform, _1, scene, ob),
+ /* Rest of transformation update. */
+ add_operation_node(&ob->id, DEG_NODE_TYPE_TRANSFORM,
+ function_bind(BKE_object_eval_uber_transform,
+ _1,
+ scene_cow, ob_cow),
DEG_OPCODE_OBJECT_UBEREVAL);
/* object transform is done */
- add_operation_node(&ob->id, DEPSNODE_TYPE_TRANSFORM,
- DEPSOP_TYPE_POST, function_bind(BKE_object_eval_done, _1, ob),
- DEG_OPCODE_TRANSFORM_FINAL);
+ op_node = add_operation_node(&ob->id, DEG_NODE_TYPE_TRANSFORM,
+ function_bind(BKE_object_eval_done, _1, ob_cow),
+ DEG_OPCODE_TRANSFORM_FINAL);
+ op_node->set_as_exit();
}
/**
@@ -553,19 +504,13 @@ void DepsgraphNodeBuilder::build_object_transform(Scene *scene, Object *ob)
void DepsgraphNodeBuilder::build_object_constraints(Scene *scene, Object *ob)
{
/* create node for constraint stack */
- add_operation_node(&ob->id, DEPSNODE_TYPE_TRANSFORM,
- DEPSOP_TYPE_EXEC, function_bind(BKE_object_eval_constraints, _1, scene, ob),
+ add_operation_node(&ob->id, DEG_NODE_TYPE_TRANSFORM,
+ function_bind(BKE_object_eval_constraints, _1,
+ get_cow_datablock(scene),
+ get_cow_datablock(ob)),
DEG_OPCODE_TRANSFORM_CONSTRAINTS);
}
-void DepsgraphNodeBuilder::build_pose_constraints(Object *ob, bPoseChannel *pchan)
-{
- /* create node for constraint stack */
- add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
- DEPSOP_TYPE_EXEC, function_bind(BKE_pose_constraints_evaluate, _1, ob, pchan),
- DEG_OPCODE_BONE_CONSTRAINTS);
-}
-
/**
* Build graph nodes for AnimData block
* \param id: ID-Block which hosts the AnimData
@@ -573,27 +518,33 @@ void DepsgraphNodeBuilder::build_pose_constraints(Object *ob, bPoseChannel *pcha
void DepsgraphNodeBuilder::build_animdata(ID *id)
{
AnimData *adt = BKE_animdata_from_id(id);
-
- if (adt == NULL)
+ if (adt == NULL) {
return;
+ }
+ ID *id_cow = get_cow_id(id);
/* animation */
if (adt->action || adt->nla_tracks.first || adt->drivers.first) {
- // XXX: Hook up specific update callbacks for special properties which may need it...
+ // 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, DEPSNODE_TYPE_ANIMATION,
- DEPSOP_TYPE_EXEC, function_bind(BKE_animsys_eval_animdata, _1, id),
+ add_operation_node(id, DEG_NODE_TYPE_ANIMATION,
+ 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)
+ */
}
/* drivers */
- for (FCurve *fcu = (FCurve *)adt->drivers.first; fcu; fcu = fcu->next) {
+ LINKLIST_FOREACH (FCurve *, fcu, &adt->drivers) {
/* create driver */
build_driver(id, fcu);
}
@@ -608,6 +559,7 @@ void DepsgraphNodeBuilder::build_animdata(ID *id)
OperationDepsNode *DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcu)
{
ChannelDriver *driver = fcu->driver;
+ ID *id_cow = get_cow_id(id);
/* Create data node for this driver */
/* TODO(sergey): Avoid creating same operation multiple times,
@@ -615,14 +567,19 @@ OperationDepsNode *DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcu)
* and use some tagging magic instead.
*/
OperationDepsNode *driver_op = find_operation_node(id,
- DEPSNODE_TYPE_PARAMETERS,
+ DEG_NODE_TYPE_PARAMETERS,
DEG_OPCODE_DRIVER,
- deg_fcurve_id_name(fcu));
+ fcu->rna_path ? fcu->rna_path : "",
+ fcu->array_index);
if (driver_op == NULL) {
- driver_op = add_operation_node(id, DEPSNODE_TYPE_PARAMETERS,
- DEPSOP_TYPE_EXEC, function_bind(BKE_animsys_eval_driver, _1, id, fcu),
- DEG_OPCODE_DRIVER, deg_fcurve_id_name(fcu));
+ /* TODO(sergey): Shall we use COW of fcu itself here? */
+ driver_op = add_operation_node(id,
+ DEG_NODE_TYPE_PARAMETERS,
+ function_bind(BKE_animsys_eval_driver, _1, id_cow, fcu),
+ DEG_OPCODE_DRIVER,
+ fcu->rna_path ? fcu->rna_path : "",
+ fcu->array_index);
}
/* tag "scripted expression" drivers as needing Python (due to GIL issues, etc.) */
@@ -642,19 +599,20 @@ void DepsgraphNodeBuilder::build_world(World *world)
return;
}
- /* world itself */
- IDDepsNode *world_node = add_id_node(world_id); /* world shading/params? */
-
build_animdata(world_id);
- /* TODO: other settings? */
+ /* world itself */
+ add_component_node(world_id, DEG_NODE_TYPE_PARAMETERS);
+
+ add_operation_node(world_id, DEG_NODE_TYPE_PARAMETERS, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
/* textures */
- build_texture_stack(world_node, world->mtex);
+ build_texture_stack(world->mtex);
/* world's nodetree */
if (world->nodetree) {
- build_nodetree(world_node, world->nodetree);
+ build_nodetree(world->nodetree);
}
}
@@ -662,55 +620,65 @@ void DepsgraphNodeBuilder::build_world(World *world)
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, DEPSNODE_TYPE_TRANSFORM,
- DEPSOP_TYPE_REBUILD, 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, DEPSNODE_TYPE_TRANSFORM,
- DEPSOP_TYPE_SIM, 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) {
- for (GroupObject *go = (GroupObject *)rbw->group->gobject.first; go; go = go->next) {
+ LINKLIST_FOREACH (GroupObject *, go, &rbw->group->gobject) {
Object *ob = go->ob;
if (!ob || (ob->type != OB_MESH))
continue;
/* 2) create operation for flushing results */
- /* object's transform component - where the rigidbody operation lives */
- add_operation_node(&ob->id, DEPSNODE_TYPE_TRANSFORM,
- DEPSOP_TYPE_EXEC, function_bind(BKE_rigidbody_object_sync_transforms, _1, scene, ob),
+ /* object's transform component - where the rigidbody operation
+ * lives. */
+ add_operation_node(&ob->id, DEG_NODE_TYPE_TRANSFORM,
+ function_bind(BKE_rigidbody_object_sync_transforms,
+ _1,
+ scene_cow,
+ get_cow_datablock(ob)),
DEG_OPCODE_TRANSFORM_RIGIDBODY);
}
}
@@ -734,10 +702,15 @@ void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob)
*/
/* component for all particle systems */
- ComponentDepsNode *psys_comp = add_component_node(&ob->id, DEPSNODE_TYPE_EVAL_PARTICLES);
+ ComponentDepsNode *psys_comp =
+ add_component_node(&ob->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(ob);
/* particle systems */
- for (ParticleSystem *psys = (ParticleSystem *)ob->particlesystem.first; psys; psys = psys->next) {
+ LINKLIST_FOREACH (ParticleSystem *, psys, &ob->particlesystem) {
ParticleSettings *part = psys->part;
/* particle settings */
@@ -747,7 +720,11 @@ void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob)
/* this particle system */
// TODO: for now, this will just be a placeholder "ubereval" node
add_operation_node(psys_comp,
- DEPSOP_TYPE_EXEC, function_bind(BKE_particle_system_eval, _1, scene, ob, psys),
+ function_bind(BKE_particle_system_eval,
+ _1,
+ scene_cow,
+ ob_cow,
+ psys),
DEG_OPCODE_PSYS_EVAL,
psys->name);
}
@@ -756,205 +733,20 @@ void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob)
// TODO...
}
-/* IK Solver Eval Steps */
-void DepsgraphNodeBuilder::build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con)
-{
- bKinematicConstraint *data = (bKinematicConstraint *)con->data;
-
- /* Find the chain's root. */
- bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
-
- if (has_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
- DEG_OPCODE_POSE_IK_SOLVER))
- {
- return;
- }
-
- /* Operation node for evaluating/running IK Solver. */
- add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
- DEPSOP_TYPE_SIM, function_bind(BKE_pose_iktree_evaluate, _1, scene, ob, rootchan),
- DEG_OPCODE_POSE_IK_SOLVER);
-}
-
-/* Spline IK Eval Steps */
-void DepsgraphNodeBuilder::build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con)
+void DepsgraphNodeBuilder::build_cloth(Scene *scene, Object *object)
{
- bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
-
- /* Find the chain's root. */
- 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.
- */
- add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
- DEPSOP_TYPE_SIM, function_bind(BKE_pose_splineik_evaluate, _1, scene, ob, rootchan),
- DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
-}
-
-/* Pose/Armature Bones Graph */
-void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
-{
- bArmature *arm = (bArmature *)ob->data;
-
- /* 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...
- */
- build_animdata(&arm->id);
-
- /* Rebuild pose if not up to date. */
- if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
- BKE_pose_rebuild(ob, arm);
- /* XXX: Without this animation gets lost in certain circumstances
- * after loading file. Need to investigate further since it does
- * not happen with simple scenes..
- */
- if (ob->adt) {
- ob->adt->recalc |= ADT_RECALC_ANIM;
- }
- }
-
- /* speed optimization for animation lookups */
- if (ob->pose) {
- BKE_pose_channels_hash_make(ob->pose);
- if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
- BKE_pose_update_constraint_flags(ob->pose);
- }
- }
-
- /* Make sure pose is up-to-date with armature updates. */
- add_operation_node(&arm->id,
- DEPSNODE_TYPE_PARAMETERS,
- DEPSOP_TYPE_EXEC,
- NULL,
+ Scene *scene_cow = get_cow_datablock(scene);
+ Object *object_cow = get_cow_datablock(object);
+
+ ComponentDepsNode *cache_comp = add_component_node(&object->id,
+ DEG_NODE_TYPE_CACHE);
+ add_operation_node(cache_comp,
+ function_bind(BKE_object_eval_cloth,
+ _1,
+ scene_cow,
+ object_cow),
DEG_OPCODE_PLACEHOLDER,
- "Armature Eval");
-
- /**
- * Pose Rig Graph
- * ==============
- *
- * Pose Component:
- * - Mainly used for referencing Bone components.
- * - This is where the evaluation operations for init/exec/cleanup
- * (ik) solvers live, and are later hooked up (so that they can be
- * interleaved during runtime) with bone-operations they depend on/affect.
- * - init_pose_eval() and cleanup_pose_eval() are absolute first and last
- * steps of pose eval process. ALL bone operations must be performed
- * between these two...
- *
- * Bone Component:
- * - 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/
- * post-constraint/post-matrix steps, as needed.
- */
-
- /* pose eval context */
- add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE,
- DEPSOP_TYPE_INIT, function_bind(BKE_pose_eval_init, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_INIT);
-
- add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE,
- DEPSOP_TYPE_POST, function_bind(BKE_pose_eval_flush, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_DONE);
-
- /* bones */
- for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- /* node for bone eval */
- add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
- DEPSOP_TYPE_INIT, NULL, // XXX: BKE_pose_eval_bone_local
- DEG_OPCODE_BONE_LOCAL);
-
- add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
- DEPSOP_TYPE_EXEC, function_bind(BKE_pose_eval_bone, _1, scene, ob, pchan), // XXX: BKE_pose_eval_bone_pose
- DEG_OPCODE_BONE_POSE_PARENT);
-
- add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
- DEPSOP_TYPE_OUT, NULL, /* NOTE: dedicated noop for easier relationship construction */
- DEG_OPCODE_BONE_READY);
-
- add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
- DEPSOP_TYPE_POST, function_bind(BKE_pose_bone_done, _1, pchan),
- DEG_OPCODE_BONE_DONE);
-
- /* constraints */
- if (pchan->constraints.first != NULL) {
- build_pose_constraints(ob, pchan);
- }
-
- /**
- * 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)
- *
- * 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...
- */
- for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) {
- switch (con->type) {
- case CONSTRAINT_TYPE_KINEMATIC:
- build_ik_pose(scene, ob, pchan, con);
- break;
-
- case CONSTRAINT_TYPE_SPLINEIK:
- build_splineik_pose(scene, ob, pchan, con);
- break;
-
- default:
- break;
- }
- }
- }
-}
-
-void DepsgraphNodeBuilder::build_proxy_rig(Object *ob)
-{
- ID *obdata = (ID *)ob->data;
- build_animdata(obdata);
-
- BLI_assert(ob->pose != NULL);
-
- /* speed optimization for animation lookups */
- BKE_pose_channels_hash_make(ob->pose);
- if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
- BKE_pose_update_constraint_flags(ob->pose);
- }
-
- add_operation_node(&ob->id,
- DEPSNODE_TYPE_EVAL_POSE,
- DEPSOP_TYPE_INIT,
- function_bind(BKE_pose_eval_proxy_copy, _1, ob),
- DEG_OPCODE_POSE_INIT);
-
- for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first;
- pchan != NULL;
- pchan = pchan->next)
- {
- add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
- DEPSOP_TYPE_INIT, NULL,
- DEG_OPCODE_BONE_LOCAL);
-
- add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
- DEPSOP_TYPE_EXEC, NULL,
- DEG_OPCODE_BONE_READY);
-
- add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
- DEPSOP_TYPE_POST, NULL,
- DEG_OPCODE_BONE_DONE);
- }
-
- add_operation_node(&ob->id,
- DEPSNODE_TYPE_EVAL_POSE,
- DEPSOP_TYPE_POST,
- NULL,
- DEG_OPCODE_POSE_DONE);
+ "Cloth Modifier");
}
/* Shapekeys */
@@ -962,7 +754,7 @@ void DepsgraphNodeBuilder::build_shapekeys(Key *key)
{
build_animdata(&key->id);
- add_operation_node(&key->id, DEPSNODE_TYPE_GEOMETRY, DEPSOP_TYPE_EXEC, NULL,
+ add_operation_node(&key->id, DEG_NODE_TYPE_GEOMETRY, NULL,
DEG_OPCODE_PLACEHOLDER, "Shapekey Eval");
}
@@ -971,6 +763,22 @@ void DepsgraphNodeBuilder::build_shapekeys(Key *key)
void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
{
ID *obdata = (ID *)ob->data;
+ ID *obdata_cow = get_cow_id(obdata);
+ OperationDepsNode *op_node;
+ Scene *scene_cow = get_cow_datablock(scene);
+ Object *object_cow = get_cow_datablock(ob);
+
+ /* TODO(sergey): This way using this object's properties as driver target
+ * works fine.
+ *
+ * Does this depend on other nodes?
+ */
+ op_node = add_operation_node(&ob->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ NULL,
+ DEG_OPCODE_PLACEHOLDER,
+ "Parameters Eval");
+ op_node->set_as_exit();
/* Temporary uber-update node, which does everything.
* It is for the being we're porting old dependencies into the new system.
@@ -979,38 +787,45 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
*
* TODO(sergey): Get rid of this node.
*/
- add_operation_node(&ob->id, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_POST, function_bind(BKE_object_eval_uber_data, _1, scene, ob),
- DEG_OPCODE_GEOMETRY_UBEREVAL);
-
- add_operation_node(&ob->id, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_INIT, NULL,
- DEG_OPCODE_PLACEHOLDER, "Eval Init");
+ op_node = add_operation_node(&ob->id,
+ DEG_NODE_TYPE_GEOMETRY,
+ function_bind(BKE_object_eval_uber_data,
+ _1,
+ scene_cow,
+ object_cow),
+ DEG_OPCODE_GEOMETRY_UBEREVAL);
+ op_node->set_as_exit();
+
+ op_node = add_operation_node(&ob->id,
+ DEG_NODE_TYPE_GEOMETRY,
+ NULL,
+ DEG_OPCODE_PLACEHOLDER,
+ "Eval Init");
+ op_node->set_as_entry();
// TODO: "Done" operation
- /* Modifiers */
- if (ob->modifiers.first) {
- ModifierData *md;
-
- for (md = (ModifierData *)ob->modifiers.first; md; md = md->next) {
- add_operation_node(&ob->id, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_EXEC, function_bind(BKE_object_eval_modifier, _1, scene, ob, md),
- DEG_OPCODE_GEOMETRY_MODIFIER, md->name);
+ /* Cloyth modifier. */
+ LINKLIST_FOREACH (ModifierData *, md, &ob->modifiers) {
+ if (md->type == eModifierType_Cloth) {
+ build_cloth(scene, ob);
}
}
/* materials */
- if (ob->totcol) {
- int a;
+ if (ob->totcol != 0) {
+ if (ob->type == OB_MESH) {
+ add_operation_node(&ob->id,
+ DEG_NODE_TYPE_SHADING,
+ function_bind(BKE_object_eval_update_shading, _1,
+ object_cow),
+ DEG_OPCODE_SHADING);
+ }
- for (a = 1; a <= ob->totcol; a++) {
+ for (int a = 1; a <= ob->totcol; a++) {
Material *ma = give_current_material(ob, a);
-
- if (ma) {
- // XXX?!
- ComponentDepsNode *geom_node = add_component_node(&ob->id, DEPSNODE_TYPE_GEOMETRY);
- build_material(geom_node, ma);
+ if (ma != NULL) {
+ build_material(ma);
}
}
}
@@ -1032,16 +847,23 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
build_animdata(obdata);
- /* nodes for result of obdata's evaluation, and geometry evaluation on object */
+ /* Nodes for result of obdata's evaluation, and geometry
+ * evaluation on object.
+ */
switch (ob->type) {
case OB_MESH:
{
//Mesh *me = (Mesh *)ob->data;
/* evaluation operations */
- add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_INIT, function_bind(BKE_mesh_eval_geometry, _1, (Mesh *)obdata),
- DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+ op_node = add_operation_node(obdata,
+ DEG_NODE_TYPE_GEOMETRY,
+ function_bind(BKE_mesh_eval_geometry,
+ _1,
+ (Mesh *)obdata_cow),
+ DEG_OPCODE_PLACEHOLDER,
+ "Geometry Eval");
+ op_node->set_as_entry();
break;
}
@@ -1049,58 +871,85 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
{
Object *mom = BKE_mball_basis_find(scene, ob);
- /* motherball - mom depends on children! */
+ /* Motherball - mom depends on children! */
if (mom == ob) {
/* metaball evaluation operations */
/* NOTE: only the motherball gets evaluated! */
- add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_INIT, function_bind(BKE_mball_eval_geometry, _1, (MetaBall *)obdata),
- DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+ op_node = add_operation_node(obdata,
+ DEG_NODE_TYPE_GEOMETRY,
+ function_bind(BKE_mball_eval_geometry,
+ _1,
+ (MetaBall *)obdata_cow),
+ DEG_OPCODE_PLACEHOLDER,
+ "Geometry Eval");
+ op_node->set_as_entry();
}
break;
}
case OB_CURVE:
+ case OB_SURF:
case OB_FONT:
{
- /* curve evaluation operations */
+ /* Curve/nurms evaluation operations. */
/* - calculate curve geometry (including path) */
- add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_INIT, function_bind(BKE_curve_eval_geometry, _1, (Curve *)obdata),
- DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
-
- /* - calculate curve path - this is used by constraints, etc. */
- add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_EXEC, function_bind(BKE_curve_eval_path, _1, (Curve *)obdata),
- DEG_OPCODE_GEOMETRY_PATH, "Path");
- break;
- }
+ op_node = add_operation_node(obdata,
+ DEG_NODE_TYPE_GEOMETRY,
+ function_bind(BKE_curve_eval_geometry,
+ _1,
+ (Curve *)obdata_cow),
+ DEG_OPCODE_PLACEHOLDER,
+ "Geometry Eval");
+ op_node->set_as_entry();
+
+ /* Calculate curve path - this is used by constraints, etc. */
+ if (ELEM(ob->type, OB_CURVE, OB_FONT)) {
+ add_operation_node(obdata,
+ DEG_NODE_TYPE_GEOMETRY,
+ function_bind(BKE_curve_eval_path,
+ _1,
+ (Curve *)obdata_cow),
+ DEG_OPCODE_GEOMETRY_PATH,
+ "Path");
+ }
- case OB_SURF: /* Nurbs Surface */
- {
- /* nurbs evaluation operations */
- add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_INIT, function_bind(BKE_curve_eval_geometry, _1, (Curve *)obdata),
- DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+ /* 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(scene, cu->bevobj);
+ }
+ if (cu->taperobj != NULL) {
+ build_object(scene, cu->taperobj);
+ }
+ if (ob->type == OB_FONT && cu->textoncurve != NULL) {
+ build_object(scene, cu->textoncurve);
+ }
break;
}
- case OB_LATTICE: /* Lattice */
+ case OB_LATTICE:
{
- /* lattice evaluation operations */
- add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_INIT, function_bind(BKE_lattice_eval_geometry, _1, (Lattice *)obdata),
- DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+ /* Lattice evaluation operations. */
+ op_node = add_operation_node(obdata,
+ DEG_NODE_TYPE_GEOMETRY,
+ function_bind(BKE_lattice_eval_geometry,
+ _1,
+ (Lattice *)obdata_cow),
+ DEG_OPCODE_PLACEHOLDER,
+ "Geometry Eval");
+ op_node->set_as_entry();
break;
}
}
- add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
- DEPSOP_TYPE_POST, NULL,
- DEG_OPCODE_PLACEHOLDER, "Eval Done");
+ 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, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_EXEC, NULL,
+ add_operation_node(obdata, DEG_NODE_TYPE_PARAMETERS, NULL,
DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
}
@@ -1116,15 +965,13 @@ void DepsgraphNodeBuilder::build_camera(Object *ob)
build_animdata(&cam->id);
- add_operation_node(camera_id, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_EXEC, NULL,
+ add_operation_node(camera_id, DEG_NODE_TYPE_PARAMETERS, NULL,
DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
if (cam->dof_ob != NULL) {
/* TODO(sergey): For now parametrs are on object level. */
- add_operation_node(&ob->id, DEPSNODE_TYPE_PARAMETERS,
- DEPSOP_TYPE_EXEC, NULL,
- DEG_OPCODE_PLACEHOLDER,
- "Camera DOF");
+ add_operation_node(&ob->id, DEG_NODE_TYPE_PARAMETERS, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Camera DOF");
}
}
@@ -1140,48 +987,55 @@ void DepsgraphNodeBuilder::build_lamp(Object *ob)
build_animdata(&la->id);
/* node for obdata */
- ComponentDepsNode *param_node = add_component_node(lamp_id, DEPSNODE_TYPE_PARAMETERS);
+ add_component_node(lamp_id, DEG_NODE_TYPE_PARAMETERS);
/* TODO(sergey): Is it really how we're supposed to work with drivers? */
- add_operation_node(lamp_id, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_EXEC, NULL,
+ add_operation_node(lamp_id, DEG_NODE_TYPE_PARAMETERS, NULL,
DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
/* lamp's nodetree */
if (la->nodetree) {
- build_nodetree(param_node, la->nodetree);
+ build_nodetree(la->nodetree);
}
/* textures */
- build_texture_stack(param_node, la->mtex);
+ build_texture_stack(la->mtex);
}
-void DepsgraphNodeBuilder::build_nodetree(DepsNode *owner_node, bNodeTree *ntree)
+void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
{
if (!ntree)
return;
/* nodetree itself */
ID *ntree_id = &ntree->id;
+ OperationDepsNode *op_node;
build_animdata(ntree_id);
/* Parameters for drivers. */
- add_operation_node(ntree_id, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_POST, NULL,
- DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
+ op_node = add_operation_node(ntree_id, DEG_NODE_TYPE_PARAMETERS, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
+ op_node->set_as_exit();
/* nodetree's nodes... */
- for (bNode *bnode = (bNode *)ntree->nodes.first; bnode; bnode = bnode->next) {
- if (bnode->id) {
- if (GS(bnode->id->name) == ID_MA) {
- build_material(owner_node, (Material *)bnode->id);
+ LINKLIST_FOREACH (bNode *, bnode, &ntree->nodes) {
+ ID *id = bnode->id;
+ if (id != NULL) {
+ short id_type = GS(id->name);
+ if (id_type == ID_MA) {
+ build_material((Material *)id);
}
- else if (bnode->type == ID_TE) {
- build_texture(owner_node, (Tex *)bnode->id);
+ else if (id_type == ID_TE) {
+ build_texture((Tex *)id);
+ }
+ else if (id_type == ID_IM) {
+ build_image((Image *)id);
}
else if (bnode->type == NODE_GROUP) {
- bNodeTree *group_ntree = (bNodeTree *)bnode->id;
+ bNodeTree *group_ntree = (bNodeTree *)id;
if ((group_ntree->id.tag & LIB_TAG_DOIT) == 0) {
- build_nodetree(owner_node, group_ntree);
+ build_nodetree(group_ntree);
}
}
}
@@ -1191,7 +1045,7 @@ void DepsgraphNodeBuilder::build_nodetree(DepsNode *owner_node, bNodeTree *ntree
}
/* Recursively build graph for material */
-void DepsgraphNodeBuilder::build_material(DepsNode *owner_node, Material *ma)
+void DepsgraphNodeBuilder::build_material(Material *ma)
{
ID *ma_id = &ma->id;
if (ma_id->tag & LIB_TAG_DOIT) {
@@ -1201,22 +1055,21 @@ void DepsgraphNodeBuilder::build_material(DepsNode *owner_node, Material *ma)
/* material itself */
add_id_node(ma_id);
- add_operation_node(ma_id, DEPSNODE_TYPE_SHADING,
- DEPSOP_TYPE_EXEC, NULL,
+ add_operation_node(ma_id, DEG_NODE_TYPE_SHADING, NULL,
DEG_OPCODE_PLACEHOLDER, "Material Update");
/* material animation */
build_animdata(ma_id);
/* textures */
- build_texture_stack(owner_node, ma->mtex);
+ build_texture_stack(ma->mtex);
/* material's nodetree */
- build_nodetree(owner_node, ma->nodetree);
+ build_nodetree(ma->nodetree);
}
/* Texture-stack attached to some shading datablock */
-void DepsgraphNodeBuilder::build_texture_stack(DepsNode *owner_node, MTex **texture_stack)
+void DepsgraphNodeBuilder::build_texture_stack(MTex **texture_stack)
{
int i;
@@ -1224,22 +1077,44 @@ void DepsgraphNodeBuilder::build_texture_stack(DepsNode *owner_node, MTex **text
for (i = 0; i < MAX_MTEX; i++) {
MTex *mtex = texture_stack[i];
if (mtex && mtex->tex)
- build_texture(owner_node, mtex->tex);
+ build_texture(mtex->tex);
}
}
/* Recursively build graph for texture */
-void DepsgraphNodeBuilder::build_texture(DepsNode *owner_node, Tex *tex)
+void DepsgraphNodeBuilder::build_texture(Tex *tex)
{
ID *tex_id = &tex->id;
if (tex_id->tag & LIB_TAG_DOIT) {
return;
}
tex_id->tag |= LIB_TAG_DOIT;
- /* texture itself */
+ /* Texture itself. */
build_animdata(tex_id);
- /* texture's nodetree */
- build_nodetree(owner_node, tex->nodetree);
+ /* Texture's nodetree. */
+ build_nodetree(tex->nodetree);
+ /* Special cases for different IDs which texture uses. */
+ if (tex->type == TEX_IMAGE) {
+ if (tex->ima != NULL) {
+ build_image(tex->ima);
+ }
+ }
+}
+
+void DepsgraphNodeBuilder::build_image(Image *image) {
+ ID *image_id = &image->id;
+ if (image_id->tag & LIB_TAG_DOIT) {
+ return;
+ }
+ image_id->tag |= LIB_TAG_DOIT;
+ /* Image ID node itself. */
+ add_id_node(image_id);
+ /* Placeholder so we can add relations and tag ID node for update. */
+ add_operation_node(image_id,
+ DEG_NODE_TYPE_PARAMETERS,
+ NULL,
+ DEG_OPCODE_PLACEHOLDER,
+ "Image Eval");
}
void DepsgraphNodeBuilder::build_compositor(Scene *scene)
@@ -1247,11 +1122,11 @@ void DepsgraphNodeBuilder::build_compositor(Scene *scene)
/* For now, just a plain wrapper? */
// TODO: create compositing component?
// XXX: component type undefined!
- //graph->get_node(&scene->id, NULL, DEPSNODE_TYPE_COMPOSITING, NULL);
+ //graph->get_node(&scene->id, NULL, DEG_NODE_TYPE_COMPOSITING, NULL);
/* for now, nodetrees are just parameters; compositing occurs in internals of renderer... */
- ComponentDepsNode *owner_node = add_component_node(&scene->id, DEPSNODE_TYPE_PARAMETERS);
- build_nodetree(owner_node, scene->nodetree);
+ add_component_node(&scene->id, DEG_NODE_TYPE_PARAMETERS);
+ build_nodetree(scene->nodetree);
}
void DepsgraphNodeBuilder::build_gpencil(bGPdata *gpd)
@@ -1272,14 +1147,50 @@ void DepsgraphNodeBuilder::build_cachefile(CacheFile *cache_file)
{
ID *cache_file_id = &cache_file->id;
- add_component_node(cache_file_id, DEPSNODE_TYPE_CACHE);
-
- add_operation_node(cache_file_id, DEPSNODE_TYPE_CACHE,
- DEPSOP_TYPE_EXEC, NULL,
+ add_component_node(cache_file_id, DEG_NODE_TYPE_CACHE);
+ add_operation_node(cache_file_id, DEG_NODE_TYPE_CACHE, NULL,
DEG_OPCODE_PLACEHOLDER, "Cache File Update");
add_id_node(cache_file_id);
build_animdata(cache_file_id);
}
+void DepsgraphNodeBuilder::build_mask(Mask *mask)
+{
+ ID *mask_id = &mask->id;
+ add_id_node(mask_id);
+ build_animdata(mask_id);
+}
+
+void DepsgraphNodeBuilder::build_movieclip(MovieClip *clip)
+{
+ ID *clip_id = &clip->id;
+ add_id_node(clip_id);
+ build_animdata(clip_id);
+}
+
+void DepsgraphNodeBuilder::build_lightprobe(Object *object)
+{
+ LightProbe *probe = (LightProbe *)object->data;
+ ID *probe_id = &probe->id;
+ if (probe_id->tag & LIB_TAG_DOIT) {
+ return;
+ }
+ probe_id->tag |= LIB_TAG_DOIT;
+ /* Placeholder so we can add relations and tag ID node for update. */
+ add_operation_node(probe_id,
+ DEG_NODE_TYPE_PARAMETERS,
+ NULL,
+ DEG_OPCODE_PLACEHOLDER,
+ "LightProbe Eval");
+
+ add_operation_node(&object->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ NULL,
+ DEG_OPCODE_PLACEHOLDER,
+ "LightProbe Eval");
+
+ build_animdata(probe_id);
+}
+
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index f378f076804..81fbbb07bc8 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -32,20 +32,24 @@
#include "intern/depsgraph_types.h"
-struct Base;
struct CacheFile;
struct bGPdata;
struct ListBase;
struct GHash;
struct ID;
+struct Image;
struct FCurve;
struct Group;
struct Key;
+struct LayerCollection;
struct Main;
struct Material;
+struct Mask;
struct MTex;
+struct MovieClip;
struct bNodeTree;
struct Object;
+struct Probe;
struct bPoseChannel;
struct bConstraint;
struct Scene;
@@ -58,8 +62,6 @@ namespace DEG {
struct Depsgraph;
struct DepsNode;
-struct RootDepsNode;
-struct SubgraphDepsNode;
struct IDDepsNode;
struct TimeSourceDepsNode;
struct ComponentDepsNode;
@@ -69,59 +71,70 @@ struct DepsgraphNodeBuilder {
DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph);
~DepsgraphNodeBuilder();
- RootDepsNode *add_root_node();
+ void begin_build(Main *bmain);
+
+ ID *get_cow_id(const ID *id_orig) const;
+
+ template<typename T>
+ T *get_cow_datablock(const T *orig) const {
+ return (T *)get_cow_id(&orig->id);
+ }
+
IDDepsNode *add_id_node(ID *id);
- TimeSourceDepsNode *add_time_source(ID *id);
+ TimeSourceDepsNode *add_time_source();
ComponentDepsNode *add_component_node(ID *id,
eDepsNode_Type comp_type,
- const string& comp_name = "");
+ const char *comp_name = "");
OperationDepsNode *add_operation_node(ComponentDepsNode *comp_node,
- eDepsOperation_Type optype,
- DepsEvalOperationCb op,
+ const DepsEvalOperationCb& op,
eDepsOperation_Code opcode,
- const string& description = "");
+ const char *name = "",
+ int name_tag = -1);
OperationDepsNode *add_operation_node(ID *id,
eDepsNode_Type comp_type,
- const string& comp_name,
- eDepsOperation_Type optype,
- DepsEvalOperationCb op,
+ const char *comp_name,
+ const DepsEvalOperationCb& op,
eDepsOperation_Code opcode,
- const string& description = "");
+ const char *name = "",
+ int name_tag = -1);
OperationDepsNode *add_operation_node(ID *id,
eDepsNode_Type comp_type,
- eDepsOperation_Type optype,
- DepsEvalOperationCb op,
+ const DepsEvalOperationCb& op,
eDepsOperation_Code opcode,
- const string& description = "");
+ const char *name = "",
+ int name_tag = -1);
bool has_operation_node(ID *id,
eDepsNode_Type comp_type,
- const string& comp_name,
+ const char *comp_name,
eDepsOperation_Code opcode,
- const string& description = "");
+ const char *name = "",
+ int name_tag = -1);
OperationDepsNode *find_operation_node(ID *id,
eDepsNode_Type comp_type,
- const string &comp_name,
+ const char *comp_name,
eDepsOperation_Code opcode,
- const string &description = "");
+ const char *name = "",
+ int name_tag = -1);
OperationDepsNode *find_operation_node(ID *id,
eDepsNode_Type comp_type,
eDepsOperation_Code opcode,
- const string &description = "");
+ const char *name = "",
+ int name_tag = -1);
void build_scene(Main *bmain, Scene *scene);
- SubgraphDepsNode *build_subgraph(Group *group);
- void build_group(Scene *scene, Base *base, Group *group);
- void build_object(Scene *scene, Base *base, Object *ob);
+ void build_group(Scene *scene, Group *group);
+ void build_object(Scene *scene, Object *ob);
void build_object_transform(Scene *scene, Object *ob);
void build_object_constraints(Scene *scene, Object *ob);
- void build_pose_constraints(Object *ob, bPoseChannel *pchan);
+ void build_pose_constraints(Scene *scene, Object *ob, bPoseChannel *pchan);
void build_rigidbody(Scene *scene);
void build_particles(Scene *scene, Object *ob);
+ void build_cloth(Scene *scene, Object *object);
void build_animdata(ID *id);
OperationDepsNode *build_driver(ID *id, FCurve *fcurve);
void build_ik_pose(Scene *scene,
@@ -138,15 +151,30 @@ struct DepsgraphNodeBuilder {
void build_obdata_geom(Scene *scene, Object *ob);
void build_camera(Object *ob);
void build_lamp(Object *ob);
- void build_nodetree(DepsNode *owner_node, bNodeTree *ntree);
- void build_material(DepsNode *owner_node, Material *ma);
- void build_texture(DepsNode *owner_node, Tex *tex);
- void build_texture_stack(DepsNode *owner_node, MTex **texture_stack);
+ 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);
void build_gpencil(bGPdata *gpd);
void build_cachefile(CacheFile *cache_file);
-
+ void build_mask(Mask *mask);
+ void build_movieclip(MovieClip *clip);
+ void build_lightprobe(Object *object);
+
+ struct LayerCollectionState {
+ int index;
+ LayerCollection *parent;
+ };
+ void build_layer_collection(Scene *scene,
+ LayerCollection *layer_collection,
+ LayerCollectionState *state);
+ void build_layer_collections(Scene *scene,
+ ListBase *layer_collections,
+ LayerCollectionState *state);
+ void build_scene_layer_collections(Scene *scene);
protected:
Main *m_bmain;
Depsgraph *m_graph;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_layer.cc
new file mode 100644
index 00000000000..b6df176545e
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_layer.cc
@@ -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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc
+ * \ingroup depsgraph
+ *
+ * Methods for constructing depsgraph's nodes
+ */
+
+#include "intern/builder/deg_builder_nodes.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_utildefines.h"
+
+#include "BKE_layer.h"
+
+#include "DNA_scene_types.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+} /* extern "C" */
+
+#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"
+#include "intern/depsgraph_types.h"
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
+
+namespace DEG {
+
+void DepsgraphNodeBuilder::build_layer_collection(Scene *scene,
+ LayerCollection *layer_collection,
+ LayerCollectionState *state)
+{
+ /* TODO(sergey): This will attempt to create component for each collection.
+ * Harmless but could be optimized.
+ */
+ ComponentDepsNode *comp = add_component_node(&scene->id, DEG_NODE_TYPE_LAYER_COLLECTIONS);
+
+ add_operation_node(comp,
+ function_bind(BKE_layer_eval_layer_collection,
+ _1,
+ layer_collection,
+ state->parent),
+ DEG_OPCODE_SCENE_LAYER_EVAL,
+ layer_collection->scene_collection->name,
+ state->index);
+ ++state->index;
+
+ /* Recurs into nested layer collections. */
+ LayerCollection *parent = state->parent;
+ state->parent = layer_collection;
+ build_layer_collections(scene, &layer_collection->layer_collections, state);
+ state->parent = parent;
+}
+
+void DepsgraphNodeBuilder::build_layer_collections(Scene *scene,
+ ListBase *layer_collections,
+ LayerCollectionState *state)
+{
+ LINKLIST_FOREACH (LayerCollection *, layer_collection, layer_collections) {
+ build_layer_collection(scene, layer_collection, state);
+ }
+}
+
+void DepsgraphNodeBuilder::build_scene_layer_collections(Scene *scene)
+{
+#ifdef WITH_COPY_ON_WRITE
+ /* Make sure we've got ID node, so we can get pointer to CoW datablock. */
+ IDDepsNode *id_node = add_id_node(&scene->id);
+ Scene *scene_cow = (Scene *)deg_expand_copy_on_write_datablock(m_graph,
+ id_node);
+#else
+ Scene *scene_cow = scene;
+#endif
+
+ LayerCollectionState state;
+ state.index = 0;
+ LINKLIST_FOREACH (SceneLayer *, scene_layer, &scene_cow->render_layers) {
+ ComponentDepsNode *comp = add_component_node(&scene->id, DEG_NODE_TYPE_LAYER_COLLECTIONS);
+
+ add_operation_node(comp,
+ function_bind(BKE_layer_eval_layer_collection_pre, _1, scene_cow, scene_layer),
+ DEG_OPCODE_SCENE_LAYER_INIT,
+ scene_layer->name);
+ add_operation_node(comp,
+ function_bind(BKE_layer_eval_layer_collection_post, _1, scene_layer),
+ DEG_OPCODE_SCENE_LAYER_DONE,
+ scene_layer->name);
+
+ state.parent = NULL;
+ build_layer_collections(scene, &scene_layer->layer_collections, &state);
+ }
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
new file mode 100644
index 00000000000..69f02603f40
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
@@ -0,0 +1,336 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
+ * \ingroup depsgraph
+ *
+ * Methods for constructing depsgraph's nodes
+ */
+
+#include "intern/builder/deg_builder_nodes.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_blenlib.h"
+#include "BLI_string.h"
+
+extern "C" {
+#include "DNA_anim_types.h"
+#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"
+} /* extern "C" */
+
+#include "DEG_depsgraph.h"
+#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"
+#include "intern/depsgraph_types.h"
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
+
+namespace DEG {
+
+void DepsgraphNodeBuilder::build_pose_constraints(Scene *scene,
+ Object *ob,
+ bPoseChannel *pchan)
+{
+ /* create node for constraint stack */
+ add_operation_node(&ob->id, DEG_NODE_TYPE_BONE, pchan->name,
+ function_bind(BKE_pose_constraints_evaluate,
+ _1,
+ get_cow_datablock(scene),
+ get_cow_datablock(ob),
+ pchan),
+ DEG_OPCODE_BONE_CONSTRAINTS);
+}
+
+/* IK Solver Eval Steps */
+void DepsgraphNodeBuilder::build_ik_pose(Scene *scene,
+ Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *con)
+{
+ bKinematicConstraint *data = (bKinematicConstraint *)con->data;
+
+ /* Find the chain's root. */
+ bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
+
+ if (has_operation_node(&ob->id, DEG_NODE_TYPE_EVAL_POSE, rootchan->name,
+ DEG_OPCODE_POSE_IK_SOLVER))
+ {
+ return;
+ }
+
+ /* Operation node for evaluating/running IK Solver. */
+ add_operation_node(&ob->id, DEG_NODE_TYPE_EVAL_POSE, rootchan->name,
+ function_bind(BKE_pose_iktree_evaluate, _1,
+ get_cow_datablock(scene),
+ get_cow_datablock(ob),
+ rootchan),
+ DEG_OPCODE_POSE_IK_SOLVER);
+}
+
+/* Spline IK Eval Steps */
+void DepsgraphNodeBuilder::build_splineik_pose(Scene *scene,
+ Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *con)
+{
+ bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
+
+ /* Find the chain's root. */
+ 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.
+ */
+ add_operation_node(&ob->id, DEG_NODE_TYPE_EVAL_POSE, rootchan->name,
+ function_bind(BKE_pose_splineik_evaluate,
+ _1,
+ get_cow_datablock(scene),
+ get_cow_datablock(ob),
+ rootchan),
+ DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
+}
+
+/* Pose/Armature Bones Graph */
+void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *object)
+{
+ bArmature *armature = (bArmature *)object->data;
+ const bool armature_tag = armature->id.tag;
+#ifdef WITH_COPY_ON_WRITE
+ /* NOTE: We need to expand both object and armature, so this way we can
+ * safely create object level pose.
+ */
+ Scene *scene_cow = get_cow_datablock(scene);
+ IDDepsNode *object_id_node = add_id_node(&object->id);
+ Object *object_cow = (Object *)deg_expand_copy_on_write_datablock(
+ m_graph, object_id_node);
+ IDDepsNode *armature_id_node = add_id_node(&armature->id);
+ bArmature *armature_cow = (bArmature *)deg_expand_copy_on_write_datablock(
+ m_graph, armature_id_node);
+#else
+ Scene *scene_cow = scene;
+ Object *object_cow = object;
+ bArmature *armature_cow = armature;
+#endif
+ OperationDepsNode *op_node;
+
+ /* 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.
+ */
+ if ((armature_tag & LIB_TAG_DOIT) == 0) {
+ 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_PLACEHOLDER,
+ "Armature Eval");
+ }
+
+ /* Rebuild pose if not up to date. */
+ if (object_cow->pose == NULL || (object->pose->flag & POSE_RECALC)) {
+ BKE_pose_rebuild(object_cow, armature_cow);
+ /* XXX: Without this animation gets lost in certain circumstances
+ * after loading file. Need to investigate further since it does
+ * not happen with simple scenes..
+ */
+ if (object_cow->adt) {
+ object_cow->adt->recalc |= ADT_RECALC_ANIM;
+ }
+ }
+
+ /* speed optimization for animation lookups */
+ if (object_cow->pose != NULL) {
+ BKE_pose_channels_hash_make(object_cow->pose);
+ if (object_cow->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
+ BKE_pose_update_constraint_flags(object_cow->pose);
+ }
+ }
+
+ /**
+ * Pose Rig Graph
+ * ==============
+ *
+ * Pose Component:
+ * - Mainly used for referencing Bone components.
+ * - This is where the evaluation operations for init/exec/cleanup
+ * (ik) solvers live, and are later hooked up (so that they can be
+ * interleaved during runtime) with bone-operations they depend on/affect.
+ * - init_pose_eval() and cleanup_pose_eval() are absolute first and last
+ * steps of pose eval process. ALL bone operations must be performed
+ * between these two...
+ *
+ * Bone Component:
+ * - 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/
+ * post-constraint/post-matrix steps, as needed.
+ */
+
+ /* pose eval context */
+ op_node = add_operation_node(&object->id,
+ DEG_NODE_TYPE_EVAL_POSE,
+ function_bind(BKE_pose_eval_init,
+ _1,
+ scene_cow,
+ object_cow,
+ object_cow->pose),
+ DEG_OPCODE_POSE_INIT);
+ op_node->set_as_entry();
+
+ op_node = add_operation_node(&object->id,
+ DEG_NODE_TYPE_EVAL_POSE,
+ function_bind(BKE_pose_eval_flush,
+ _1,
+ scene_cow,
+ object_cow,
+ object_cow->pose),
+ DEG_OPCODE_POSE_DONE);
+ op_node->set_as_exit();
+
+ /* bones */
+ LINKLIST_FOREACH (bPoseChannel *, pchan, &object_cow->pose->chanbase) {
+ /* node for bone eval */
+ 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,
+ function_bind(BKE_pose_eval_bone, _1,
+ scene_cow,
+ object_cow,
+ pchan),
+ DEG_OPCODE_BONE_POSE_PARENT);
+
+ /* NOTE: Dedicated noop for easier relationship construction. */
+ 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,
+ function_bind(BKE_pose_bone_done, _1, pchan),
+ DEG_OPCODE_BONE_DONE);
+ op_node->set_as_exit();
+
+ /* constraints */
+ if (pchan->constraints.first != NULL) {
+ build_pose_constraints(scene, object, pchan);
+ }
+
+ /**
+ * 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)
+ *
+ * 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.
+ */
+ LINKLIST_FOREACH (bConstraint *, con, &pchan->constraints) {
+ switch (con->type) {
+ case CONSTRAINT_TYPE_KINEMATIC:
+ build_ik_pose(scene, object, pchan, con);
+ break;
+
+ case CONSTRAINT_TYPE_SPLINEIK:
+ build_splineik_pose(scene, object, pchan, con);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+}
+
+void DepsgraphNodeBuilder::build_proxy_rig(Object *ob)
+{
+ ID *obdata = (ID *)ob->data;
+ OperationDepsNode *op_node;
+
+ build_animdata(obdata);
+
+ BLI_assert(ob->pose != NULL);
+
+ /* speed optimization for animation lookups */
+ BKE_pose_channels_hash_make(ob->pose);
+ if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
+ BKE_pose_update_constraint_flags(ob->pose);
+ }
+
+ op_node = add_operation_node(&ob->id,
+ DEG_NODE_TYPE_EVAL_POSE,
+ function_bind(BKE_pose_eval_proxy_copy, _1, ob),
+ DEG_OPCODE_POSE_INIT);
+ op_node->set_as_entry();
+
+ LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
+ op_node = add_operation_node(&ob->id, DEG_NODE_TYPE_BONE, pchan->name,
+ NULL, DEG_OPCODE_BONE_LOCAL);
+ op_node->set_as_entry();
+
+ add_operation_node(&ob->id, DEG_NODE_TYPE_BONE, pchan->name,
+ NULL, DEG_OPCODE_BONE_READY);
+
+ op_node = add_operation_node(&ob->id, DEG_NODE_TYPE_BONE, pchan->name,
+ NULL, DEG_OPCODE_BONE_DONE);
+ op_node->set_as_exit();
+ }
+
+ op_node = add_operation_node(&ob->id, DEG_NODE_TYPE_EVAL_POSE,
+ NULL, DEG_OPCODE_POSE_DONE);
+ op_node->set_as_exit();
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc
new file mode 100644
index 00000000000..f24d4e8d3f2
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc
@@ -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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc
+ * \ingroup depsgraph
+ *
+ * Methods for constructing depsgraph's nodes
+ */
+
+#include "intern/builder/deg_builder_nodes.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_blenlib.h"
+#include "BLI_string.h"
+
+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" */
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "intern/builder/deg_builder.h"
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+#include "intern/depsgraph_types.h"
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
+
+namespace DEG {
+
+void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene)
+{
+ /* scene ID block */
+ add_id_node(&scene->id);
+
+ /* timesource */
+ 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) {
+ build_scene(bmain, scene->set);
+ }
+
+ /* scene objects */
+ int select_color = 1;
+ for (SceneLayer *sl = (SceneLayer *)scene->render_layers.first; sl; sl = sl->next) {
+ for (Base *base = (Base *)sl->object_bases.first; base; base = base->next) {
+ /* object itself */
+ build_object(scene, base->object);
+ base->object->select_color = select_color++;
+ }
+ }
+
+ /* rigidbody */
+ if (scene->rigidbody_world) {
+ build_rigidbody(scene);
+ }
+
+ /* scene's animation and drivers */
+ if (scene->adt) {
+ build_animdata(&scene->id);
+ }
+
+ /* world */
+ if (scene->world) {
+ build_world(scene->world);
+ }
+
+ /* compo nodes */
+ if (scene->nodetree) {
+ build_compositor(scene);
+ }
+
+ /* sequencer */
+ // XXX...
+
+ /* grease pencil */
+ if (scene->gpd) {
+ build_gpencil(scene->gpd);
+ }
+
+ /* Cache file. */
+ LINKLIST_FOREACH (CacheFile *, cachefile, &bmain->cachefiles) {
+ build_cachefile(cachefile);
+ }
+
+ /* Masks. */
+ LINKLIST_FOREACH (Mask *, mask, &bmain->mask) {
+ build_mask(mask);
+ }
+
+ /* Movie clips. */
+ LINKLIST_FOREACH (MovieClip *, clip, &bmain->movieclip) {
+ build_movieclip(clip);
+ }
+
+ /* Collections. */
+ build_scene_layer_collections(scene);
+
+ /* Parameters evaluation for scene relations mainly. */
+ add_operation_node(&scene->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ NULL,
+ DEG_OPCODE_PLACEHOLDER,
+ "Scene Eval");
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
index f870a33fb68..59eb7ed8cf1 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
@@ -33,10 +33,8 @@
#include <stdio.h>
#include <string.h>
-extern "C" {
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
-}
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 9ab28331249..2665f28ee94 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -34,15 +34,14 @@
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
+#include <cstring> /* required for STREQ later on. */
#include "MEM_guardedalloc.h"
-extern "C" {
-#include "BLI_blenlib.h"
-#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BLI_blenlib.h"
+extern "C" {
#include "DNA_action_types.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
@@ -56,15 +55,19 @@ extern "C" {
#include "DNA_key_types.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
+#include "DNA_mask_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
+#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_texture_types.h"
#include "DNA_world_types.h"
+#include "DNA_object_force.h"
#include "BKE_action.h"
#include "BKE_armature.h"
@@ -72,6 +75,7 @@ extern "C" {
#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"
@@ -89,13 +93,13 @@ extern "C" {
#include "BKE_tracking.h"
#include "BKE_world.h"
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_build.h"
-
#include "RNA_access.h"
#include "RNA_types.h"
} /* extern "C" */
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "intern/builder/deg_builder.h"
#include "intern/builder/deg_builder_pchanmap.h"
@@ -110,9 +114,70 @@ extern "C" {
namespace DEG {
+namespace {
+
+struct BuilderWalkUserData {
+ DepsgraphRelationBuilder *builder;
+ Main *bmain;
+ Scene *scene;
+};
+
+static void modifier_walk(void *user_data,
+ struct Object * /*ob*/,
+ struct Object **obpoin,
+ int /*cb_flag*/)
+{
+ BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
+ if (*obpoin) {
+ data->builder->build_object(data->bmain, data->scene, *obpoin);
+ }
+}
+
+void constraint_walk(bConstraint * /*con*/,
+ ID **idpoin,
+ bool /*is_reference*/,
+ void *user_data)
+{
+ BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
+ if (*idpoin) {
+ ID *id = *idpoin;
+ if (GS(id->name) == ID_OB) {
+ data->builder->build_object(data->bmain, data->scene, (Object *)id);
+ }
+ }
+}
+
+} /* namespace */
+
/* ***************** */
/* Relations Builder */
+/* TODO(sergey): This is somewhat weak, but we don't want neither false-positive
+ * time dependencies nor special exceptions in the depsgraph evaluation.
+ */
+static bool python_driver_depends_on_time(ChannelDriver *driver)
+{
+ if (driver->expression[0] == '\0') {
+ /* Empty expression depends on nothing. */
+ return false;
+ }
+ if (strchr(driver->expression, '(') != NULL) {
+ /* Function calls are considered dependent on a time. */
+ return true;
+ }
+ if (strstr(driver->expression, "frame") != NULL) {
+ /* Variable `frame` depends on time. */
+ /* TODO(sergey): This is a bit weak, but not sure about better way of
+ * handling this.
+ */
+ return true;
+ }
+ /* Possible indirect time relation s should be handled via variable
+ * targets.
+ */
+ return false;
+}
+
/* **** General purpose functions **** */
RNAPathKey::RNAPathKey(ID *id, const char *path) :
@@ -134,13 +199,6 @@ DepsgraphRelationBuilder::DepsgraphRelationBuilder(Depsgraph *graph) :
{
}
-RootDepsNode *DepsgraphRelationBuilder::find_node(const RootKey &key) const
-{
- (void)key;
- BLI_assert(!"Doesn't seem to be correct");
- return m_graph->root_node;
-}
-
TimeSourceDepsNode *DepsgraphRelationBuilder::find_node(
const TimeSourceKey &key) const
{
@@ -149,7 +207,7 @@ TimeSourceDepsNode *DepsgraphRelationBuilder::find_node(
return NULL;
}
else {
- return m_graph->root_node->time_source;
+ return m_graph->time_source;
}
}
@@ -183,10 +241,12 @@ OperationDepsNode *DepsgraphRelationBuilder::find_node(
return NULL;
}
- OperationDepsNode *op_node = comp_node->find_operation(key.opcode, key.name);
+ OperationDepsNode *op_node = comp_node->find_operation(key.opcode,
+ key.name,
+ key.name_tag);
if (!op_node) {
fprintf(stderr, "find_node_operation: Failed for (%s, '%s')\n",
- DEG_OPNAMES[key.opcode], key.name.c_str());
+ DEG_OPNAMES[key.opcode], key.name);
}
return op_node;
}
@@ -208,7 +268,7 @@ OperationDepsNode *DepsgraphRelationBuilder::has_node(
if (!comp_node) {
return NULL;
}
- return comp_node->has_operation(key.opcode, key.name);
+ return comp_node->has_operation(key.opcode, key.name, key.name_tag);
}
void DepsgraphRelationBuilder::add_time_relation(TimeSourceDepsNode *timesrc,
@@ -216,7 +276,7 @@ void DepsgraphRelationBuilder::add_time_relation(TimeSourceDepsNode *timesrc,
const char *description)
{
if (timesrc && node_to) {
- m_graph->add_new_relation(timesrc, node_to, DEPSREL_TYPE_TIME, description);
+ m_graph->add_new_relation(timesrc, node_to, description);
}
else {
DEG_DEBUG_PRINTF("add_time_relation(%p = %s, %p = %s, %s) Failed\n",
@@ -229,102 +289,103 @@ void DepsgraphRelationBuilder::add_time_relation(TimeSourceDepsNode *timesrc,
void DepsgraphRelationBuilder::add_operation_relation(
OperationDepsNode *node_from,
OperationDepsNode *node_to,
- eDepsRelation_Type type,
const char *description)
{
if (node_from && node_to) {
- m_graph->add_new_relation(node_from, node_to, type, description);
+ m_graph->add_new_relation(node_from, node_to, description);
}
else {
- DEG_DEBUG_PRINTF("add_operation_relation(%p = %s, %p = %s, %d, %s) Failed\n",
+ DEG_DEBUG_PRINTF("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>",
- type, description);
+ description);
}
}
-/* **** Functions to build relations between entities **** */
-
-void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene)
+void DepsgraphRelationBuilder::add_collision_relations(const OperationKey &key, Scene *scene, Object *ob, Group *group, bool dupli, const char *name)
{
- /* LIB_TAG_DOIT is used to indicate whether node for given ID was already
- * created or not.
- */
- BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
- /* XXX nested node trees are not included in tag-clearing above,
- * so we need to do this manually.
- */
- FOREACH_NODETREE(bmain, nodetree, id) {
- if (id != (ID *)nodetree)
- nodetree->id.tag &= ~LIB_TAG_DOIT;
- } FOREACH_NODETREE_END
+ unsigned int numcollobj;
+ Object **collobjs = get_collisionobjects_ext(scene, ob, group, &numcollobj, eModifierType_Collision, dupli);
+
+ for (unsigned int i = 0; i < numcollobj; i++)
+ {
+ Object *ob1 = collobjs[i];
- if (scene->set) {
- // TODO: link set to scene, especially our timesource...
+ ComponentKey trf_key(&ob1->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);
}
- /* scene objects */
- for (Base *base = (Base *)scene->base.first; base; base = base->next) {
- Object *ob = base->object;
+ if (collobjs)
+ MEM_freeN(collobjs);
+}
- /* object itself */
- build_object(bmain, scene, ob);
+void DepsgraphRelationBuilder::add_forcefield_relations(const OperationKey &key, Scene *scene, Object *ob, ParticleSystem *psys, EffectorWeights *eff, bool add_absorption, const char *name)
+{
+ ListBase *effectors = pdInitEffectors(scene, ob, psys, eff, false);
- /* object that this is a proxy for */
- if (ob->proxy) {
- ob->proxy->proxy_from = ob;
- build_object(bmain, scene, ob->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(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
- ComponentKey proxy_pose_key(&ob->proxy->id, DEPSNODE_TYPE_EVAL_POSE);
- add_relation(ob_pose_key, proxy_pose_key, DEPSREL_TYPE_TRANSFORM, "Proxy");
- }
+ if (effectors) {
+ for (EffectorCache *eff = (EffectorCache *)effectors->first; eff; eff = eff->next) {
+ if (eff->ob != ob) {
+ ComponentKey eff_key(&eff->ob->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(eff_key, key, name);
+ }
- /* Object dupligroup. */
- if (ob->dup_group) {
- build_group(bmain, scene, ob, ob->dup_group);
- }
- }
+ if (eff->psys) {
+ if (eff->ob != ob) {
+ ComponentKey eff_key(&eff->ob->id, DEG_NODE_TYPE_EVAL_PARTICLES);
+ add_relation(eff_key, key, name);
- /* rigidbody */
- if (scene->rigidbody_world) {
- build_rigidbody(scene);
- }
+ /* 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_PSYS_EVAL, eff->psys->name);
+ add_relation(eff_key, key, name);
+ }
+ }
- /* scene's animation and drivers */
- if (scene->adt) {
- build_animdata(&scene->id);
- }
+ if (eff->pd->forcefield == PFIELD_SMOKEFLOW && eff->pd->f_source) {
+ ComponentKey trf_key(&eff->pd->f_source->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(trf_key, key, "Smoke Force Domain");
- /* world */
- if (scene->world) {
- build_world(scene->world);
- }
+ ComponentKey eff_key(&eff->pd->f_source->id, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(eff_key, key, "Smoke Force Domain");
+ }
- /* compo nodes */
- if (scene->nodetree) {
- build_compositor(scene);
+ if (add_absorption && (eff->pd->flag & PFIELD_VISIBILITY)) {
+ add_collision_relations(key, scene, ob, NULL, true, "Force Absorption");
+ }
+ }
}
- /* grease pencil */
- if (scene->gpd) {
- build_gpencil(&scene->id, scene->gpd);
- }
+ pdEndEffectors(&effectors);
+}
- for (Depsgraph::OperationNodes::const_iterator it_op = m_graph->operations.begin();
- it_op != m_graph->operations.end();
- ++it_op)
- {
- OperationDepsNode *node = *it_op;
- IDDepsNode *id_node = node->owner->owner;
- ID *id = id_node->id;
- if (GS(id->name) == ID_OB) {
- Object *object = (Object *)id;
- object->customdata_mask |= node->customdata_mask;
+Depsgraph *DepsgraphRelationBuilder::getGraph()
+{
+ return m_graph;
+}
+
+/* **** Functions to build relations between entities **** */
+
+void DepsgraphRelationBuilder::begin_build(Main *bmain)
+{
+ /* LIB_TAG_DOIT is used to indicate whether node for given ID was already
+ * created or not.
+ */
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ /* XXX nested node trees are notr included in tag-clearing above,
+ * so we need to do this manually.
+ */
+ FOREACH_NODETREE(bmain, nodetree, id) {
+ if (id != (ID *)nodetree) {
+ nodetree->id.tag &= ~LIB_TAG_DOIT;
}
- }
+ } FOREACH_NODETREE_END
}
void DepsgraphRelationBuilder::build_group(Main *bmain,
@@ -335,20 +396,14 @@ void DepsgraphRelationBuilder::build_group(Main *bmain,
ID *group_id = &group->id;
bool group_done = (group_id->tag & LIB_TAG_DOIT) != 0;
OperationKey object_local_transform_key(&object->id,
- DEPSNODE_TYPE_TRANSFORM,
+ DEG_NODE_TYPE_TRANSFORM,
DEG_OPCODE_TRANSFORM_LOCAL);
- for (GroupObject *go = (GroupObject *)group->gobject.first;
- go != NULL;
- go = go->next)
- {
+ LINKLIST_FOREACH (GroupObject *, go, &group->gobject) {
if (!group_done) {
build_object(bmain, scene, go->ob);
}
- ComponentKey dupli_transform_key(&go->ob->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(dupli_transform_key,
- object_local_transform_key,
- DEPSREL_TYPE_TRANSFORM,
- "Dupligroup");
+ ComponentKey dupli_transform_key(&go->ob->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(dupli_transform_key, object_local_transform_key, "Dupligroup");
}
group_id->tag |= LIB_TAG_DOIT;
}
@@ -358,63 +413,89 @@ void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *o
if (ob->id.tag & LIB_TAG_DOIT) {
return;
}
+ ob->id.tag |= LIB_TAG_DOIT;
/* Object Transforms */
eDepsOperation_Code base_op = (ob->parent) ? DEG_OPCODE_TRANSFORM_PARENT : DEG_OPCODE_TRANSFORM_LOCAL;
- OperationKey base_op_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, base_op);
+ OperationKey base_op_key(&ob->id, DEG_NODE_TYPE_TRANSFORM, base_op);
- OperationKey local_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_LOCAL);
- OperationKey parent_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_PARENT);
- OperationKey final_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
+ OperationKey local_transform_key(&ob->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_LOCAL);
+ OperationKey parent_transform_key(&ob->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_PARENT);
+ OperationKey final_transform_key(&ob->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
- OperationKey ob_ubereval_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_OBJECT_UBEREVAL);
+ OperationKey ob_ubereval_key(&ob->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_OBJECT_UBEREVAL);
/* parenting */
- if (ob->parent) {
+ if (ob->parent != NULL) {
/* parent relationship */
build_object_parent(ob);
/* local -> parent */
- add_relation(local_transform_key, parent_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, "[ObLocal -> ObParent]");
+ add_relation(local_transform_key, parent_transform_key, "[ObLocal -> ObParent]");
+ }
+
+ if (ob->modifiers.first != NULL) {
+ BuilderWalkUserData data;
+ data.builder = this;
+ data.bmain = bmain;
+ data.scene = scene;
+ modifiers_foreachObjectLink(ob, modifier_walk, &data);
+ }
+ if (ob->constraints.first != NULL) {
+ BuilderWalkUserData data;
+ data.builder = this;
+ data.bmain = bmain;
+ data.scene = scene;
+ BKE_constraints_id_loop(&ob->constraints, constraint_walk, &data);
}
/* object constraints */
- if (ob->constraints.first) {
- OperationKey constraint_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_CONSTRAINTS);
+ if (ob->constraints.first != NULL) {
+ OperationKey constraint_key(&ob->id,
+ DEG_NODE_TYPE_TRANSFORM,
+ DEG_OPCODE_TRANSFORM_CONSTRAINTS);
/* constraint relations */
// TODO: provide base op
// XXX: this is broken
- build_constraints(scene, &ob->id, DEPSNODE_TYPE_TRANSFORM, "", &ob->constraints, NULL);
+ build_constraints(scene,
+ &ob->id,
+ DEG_NODE_TYPE_TRANSFORM,
+ "",
+ &ob->constraints,
+ NULL);
/* operation order */
- add_relation(base_op_key, constraint_key, DEPSREL_TYPE_COMPONENT_ORDER, "[ObBase-> Constraint Stack]");
- add_relation(constraint_key, final_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, "[ObConstraints -> Done]");
+ add_relation(base_op_key, constraint_key, "[ObBase-> Constraint Stack]");
+ add_relation(constraint_key, final_transform_key, "[ObConstraints -> Done]");
// XXX
- add_relation(constraint_key, ob_ubereval_key, DEPSREL_TYPE_COMPONENT_ORDER, "Temp Ubereval");
- add_relation(ob_ubereval_key, final_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, "Temp Ubereval");
+ add_relation(constraint_key, ob_ubereval_key, "Temp Ubereval");
+ add_relation(ob_ubereval_key, final_transform_key, "Temp Ubereval");
}
else {
- /* operation order */
- add_relation(base_op_key, final_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, "Object Transform");
-
- // XXX
- add_relation(base_op_key, ob_ubereval_key, DEPSREL_TYPE_COMPONENT_ORDER, "Temp Ubereval");
- add_relation(ob_ubereval_key, final_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, "Temp Ubereval");
+ /* NOTE: Keep an eye here, we skip some relations here to "streamline"
+ * dependencies and avoid transitive relations which causes overhead.
+ * But once we get rid of uber eval node this will need reconsideration.
+ */
+ if (ob->rigidbody_object == NULL) {
+ /* Rigid body will hook up another node inbetween, so skip
+ * relation here to avoid transitive relation.
+ */
+ add_relation(base_op_key, ob_ubereval_key, "Temp Ubereval");
+ }
+ add_relation(ob_ubereval_key, final_transform_key, "Temp Ubereval");
}
-
/* AnimData */
build_animdata(&ob->id);
// XXX: This should be hooked up by the build_animdata code
- if (ob->adt && (ob->adt->action || ob->adt->nla_tracks.first)) {
- ComponentKey adt_key(&ob->id, DEPSNODE_TYPE_ANIMATION);
- add_relation(adt_key, local_transform_key, DEPSREL_TYPE_OPERATION, "Object Animation");
+ if (needs_animdata_node(&ob->id)) {
+ ComponentKey adt_key(&ob->id, DEG_NODE_TYPE_ANIMATION);
+ add_relation(adt_key, local_transform_key, "Object Animation");
}
-
/* object data */
if (ob->data) {
ID *obdata_id = (ID *)ob->data;
@@ -451,48 +532,72 @@ void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *o
case OB_CAMERA: /* Camera */
build_camera(ob);
break;
+
+ case OB_LIGHTPROBE:
+ build_lightprobe(ob);
+ break;
}
Key *key = BKE_key_from_object(ob);
if (key != NULL) {
- ComponentKey geometry_key((ID *)ob->data, DEPSNODE_TYPE_GEOMETRY);
- ComponentKey key_key(&key->id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(key_key, geometry_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Shapekeys");
+ ComponentKey geometry_key((ID *)ob->data, DEG_NODE_TYPE_GEOMETRY);
+ ComponentKey key_key(&key->id, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(key_key, geometry_key, "Shapekeys");
}
}
- /* particle systems */
- if (ob->particlesystem.first) {
+ /* Particle systems. */
+ if (ob->particlesystem.first != NULL) {
build_particles(scene, ob);
}
- /* grease pencil */
- if (ob->gpd) {
- build_gpencil(&ob->id, ob->gpd);
+ /* Grease pencil. */
+ if (ob->gpd != NULL) {
+ build_gpencil(ob->gpd);
+ }
+
+ /* Object that this is a proxy for. */
+ if (ob->proxy != NULL) {
+ ob->proxy->proxy_from = ob;
+ build_object(bmain, scene, ob->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(&ob->id, DEG_NODE_TYPE_EVAL_POSE);
+ ComponentKey proxy_pose_key(&ob->proxy->id, DEG_NODE_TYPE_EVAL_POSE);
+ add_relation(ob_pose_key, proxy_pose_key, "Proxy");
+ }
+
+ /* Object dupligroup. */
+ if (ob->dup_group != NULL) {
+ build_group(bmain, scene, ob, ob->dup_group);
}
}
void DepsgraphRelationBuilder::build_object_parent(Object *ob)
{
- /* XXX: for now, need to use the component key (not just direct to the parent op), or else the matrix doesn't get reset */
- // XXX: @sergey - it would be good if we got that backwards flushing working when tagging for updates
- //OperationKey ob_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_PARENT);
- ComponentKey ob_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
+ /* XXX: for now, need to use the component key (not just direct to the parent op),
+ * or else the matrix doesn't get reset/
+ */
+ // XXX: @sergey - it would be good if we got that backwards flushing working
+ // when tagging for updates.
+ //OperationKey ob_key(&ob->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_PARENT);
+ ComponentKey ob_key(&ob->id, DEG_NODE_TYPE_TRANSFORM);
/* type-specific links */
switch (ob->partype) {
case PARSKEL: /* Armature Deform (Virtual Modifier) */
{
- ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(parent_key, ob_key, DEPSREL_TYPE_STANDARD, "Armature Deform Parent");
+ ComponentKey parent_key(&ob->parent->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(parent_key, ob_key, "Armature Deform Parent");
break;
}
case PARVERT1: /* Vertex Parent */
case PARVERT3:
{
- ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(parent_key, ob_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Vertex Parent");
+ ComponentKey parent_key(&ob->parent->id, DEG_NODE_TYPE_GEOMETRY);
+ 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);
@@ -500,15 +605,21 @@ void DepsgraphRelationBuilder::build_object_parent(Object *ob)
parent_node->customdata_mask |= CD_MASK_ORIGINDEX;
}
- ComponentKey transform_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(transform_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Vertex Parent TFM");
+ ComponentKey transform_key(&ob->parent->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(transform_key, ob_key, "Vertex Parent TFM");
break;
}
case PARBONE: /* Bone Parent */
{
- ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_BONE, ob->parsubstr);
- add_relation(parent_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Bone Parent");
+ ComponentKey parent_bone_key(&ob->parent->id,
+ DEG_NODE_TYPE_BONE,
+ ob->parsubstr);
+ OperationKey parent_transform_key(&ob->parent->id,
+ DEG_NODE_TYPE_TRANSFORM,
+ DEG_OPCODE_TRANSFORM_FINAL);
+ add_relation(parent_bone_key, ob_key, "Bone Parent");
+ add_relation(parent_transform_key, ob_key, "Armature Parent");
break;
}
@@ -517,33 +628,33 @@ void DepsgraphRelationBuilder::build_object_parent(Object *ob)
if (ob->parent->type == OB_LATTICE) {
/* Lattice Deform Parent - Virtual Modifier */
// XXX: no virtual modifiers should be left!
- ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
- ComponentKey geom_key(&ob->parent->id, DEPSNODE_TYPE_GEOMETRY);
+ ComponentKey parent_key(&ob->parent->id, DEG_NODE_TYPE_TRANSFORM);
+ ComponentKey geom_key(&ob->parent->id, DEG_NODE_TYPE_GEOMETRY);
- add_relation(parent_key, ob_key, DEPSREL_TYPE_STANDARD, "Lattice Deform Parent");
- add_relation(geom_key, ob_key, DEPSREL_TYPE_STANDARD, "Lattice Deform Parent Geom");
+ add_relation(parent_key, ob_key, "Lattice Deform Parent");
+ add_relation(geom_key, ob_key, "Lattice Deform Parent Geom");
}
else if (ob->parent->type == OB_CURVE) {
Curve *cu = (Curve *)ob->parent->data;
if (cu->flag & CU_PATH) {
/* Follow Path */
- ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(parent_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Curve Follow Parent");
+ ComponentKey parent_key(&ob->parent->id, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(parent_key, ob_key, "Curve Follow Parent");
- ComponentKey transform_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(transform_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Curve Follow TFM");
+ ComponentKey transform_key(&ob->parent->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(transform_key, ob_key, "Curve Follow TFM");
}
else {
/* Standard Parent */
- ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(parent_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Curve Parent");
+ ComponentKey parent_key(&ob->parent->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(parent_key, ob_key, "Curve Parent");
}
}
else {
/* Standard Parent */
- ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(parent_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Parent");
+ ComponentKey parent_key(&ob->parent->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(parent_key, ob_key, "Parent");
}
break;
}
@@ -559,7 +670,7 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode
ListBase *constraints, RootPChanMap *root_map)
{
OperationKey constraint_op_key(id, component_type, component_subdata,
- (component_type == DEPSNODE_TYPE_BONE) ? DEG_OPCODE_BONE_CONSTRAINTS : DEG_OPCODE_TRANSFORM_CONSTRAINTS);
+ (component_type == DEG_NODE_TYPE_BONE) ? DEG_OPCODE_BONE_CONSTRAINTS : DEG_OPCODE_TRANSFORM_CONSTRAINTS);
/* add dependencies for each constraint in turn */
for (bConstraint *con = (bConstraint *)constraints->first; con; con = con->next) {
@@ -582,8 +693,8 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode
if (data->depth_ob) {
// DAG_RL_DATA_OB | DAG_RL_OB_OB
- ComponentKey depth_key(&data->depth_ob->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(depth_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ ComponentKey depth_key(&data->depth_ob->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(depth_key, constraint_op_key, cti->name);
}
}
else if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
@@ -592,41 +703,42 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode
if (depends_on_camera && scene->camera) {
// DAG_RL_DATA_OB | DAG_RL_OB_OB
- ComponentKey camera_key(&scene->camera->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(camera_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ ComponentKey camera_key(&scene->camera->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(camera_key, constraint_op_key, cti->name);
}
/* TODO(sergey): This is more a TimeSource -> MovieClip -> Constraint dependency chain. */
TimeSourceKey time_src_key;
- add_relation(time_src_key, constraint_op_key, DEPSREL_TYPE_TIME, "[TimeSrc -> Animation]");
+ add_relation(time_src_key, constraint_op_key, "[TimeSrc -> Animation]");
}
else if (cti->type == CONSTRAINT_TYPE_TRANSFORM_CACHE) {
/* TODO(kevin): This is more a TimeSource -> CacheFile -> Constraint dependency chain. */
TimeSourceKey time_src_key;
- add_relation(time_src_key, constraint_op_key, DEPSREL_TYPE_TIME, "[TimeSrc -> Animation]");
+ add_relation(time_src_key, constraint_op_key, "[TimeSrc -> Animation]");
bTransformCacheConstraint *data = (bTransformCacheConstraint *)con->data;
if (data->cache_file) {
- ComponentKey cache_key(&data->cache_file->id, DEPSNODE_TYPE_CACHE);
- add_relation(cache_key, constraint_op_key, DEPSREL_TYPE_CACHE, cti->name);
+ ComponentKey cache_key(&data->cache_file->id, DEG_NODE_TYPE_CACHE);
+ add_relation(cache_key, constraint_op_key, cti->name);
}
}
else if (cti->get_constraint_targets) {
ListBase targets = {NULL, NULL};
cti->get_constraint_targets(con, &targets);
- for (bConstraintTarget *ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
- if (!ct->tar)
+ LINKLIST_FOREACH (bConstraintTarget *, ct, &targets) {
+ if (ct->tar == NULL) {
continue;
+ }
if (ELEM(con->type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK)) {
/* ignore IK constraints - these are handled separately (on pose level) */
}
else if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO)) {
/* these constraints require path geometry data... */
- ComponentKey target_key(&ct->tar->id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(target_key, constraint_op_key, DEPSREL_TYPE_GEOMETRY_EVAL, cti->name); // XXX: type = geom_transform
+ ComponentKey target_key(&ct->tar->id, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(target_key, constraint_op_key, cti->name); // XXX: type = geom_transform
// TODO: path dependency
}
else if ((ct->tar->type == OB_ARMATURE) && (ct->subtarget[0])) {
@@ -645,20 +757,20 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode
target_key_opcode = DEG_OPCODE_BONE_DONE;
}
- OperationKey target_key(&ct->tar->id, DEPSNODE_TYPE_BONE, ct->subtarget, target_key_opcode);
- add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ OperationKey target_key(&ct->tar->id, DEG_NODE_TYPE_BONE, ct->subtarget, target_key_opcode);
+ add_relation(target_key, constraint_op_key, cti->name);
}
else {
/* different armature - we can safely use the result of that */
- OperationKey target_key(&ct->tar->id, DEPSNODE_TYPE_BONE, ct->subtarget, DEG_OPCODE_BONE_DONE);
- add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ 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);
}
}
else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) {
/* vertex group */
/* NOTE: for now, we don't need to represent vertex groups separately... */
- ComponentKey target_key(&ct->tar->id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(target_key, constraint_op_key, DEPSREL_TYPE_GEOMETRY_EVAL, cti->name);
+ 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);
@@ -669,12 +781,12 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode
}
else if (con->type == CONSTRAINT_TYPE_SHRINKWRAP) {
/* Constraints which requires the target object surface. */
- ComponentKey target_key(&ct->tar->id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ ComponentKey target_key(&ct->tar->id, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(target_key, constraint_op_key, cti->name);
/* NOTE: obdata eval now doesn't necessarily depend on the object's transform... */
- ComponentKey target_transform_key(&ct->tar->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(target_transform_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ ComponentKey target_transform_key(&ct->tar->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(target_transform_key, constraint_op_key, cti->name);
}
else {
/* standard object relation */
@@ -686,19 +798,19 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode
* - If however it is a real self targetting case, just make it depend on the
* previous constraint (or the pre-constraint state)...
*/
- if ((ct->tar->type == OB_ARMATURE) && (component_type == DEPSNODE_TYPE_BONE)) {
- OperationKey target_key(&ct->tar->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
- add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ if ((ct->tar->type == OB_ARMATURE) && (component_type == DEG_NODE_TYPE_BONE)) {
+ OperationKey target_key(&ct->tar->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
+ add_relation(target_key, constraint_op_key, cti->name);
}
else {
- OperationKey target_key(&ct->tar->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_LOCAL);
- add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ OperationKey target_key(&ct->tar->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_LOCAL);
+ add_relation(target_key, constraint_op_key, cti->name);
}
}
else {
/* normal object dependency */
- OperationKey target_key(&ct->tar->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
- add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ OperationKey target_key(&ct->tar->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
+ add_relation(target_key, constraint_op_key, cti->name);
}
}
@@ -712,8 +824,8 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode
CONSTRAINT_TYPE_TRANSLIKE))
{
/* TODO(sergey): Add used space check. */
- ComponentKey target_transform_key(&ct->tar->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(target_transform_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ ComponentKey target_transform_key(&ct->tar->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(target_transform_key, constraint_op_key, cti->name);
}
}
@@ -731,13 +843,13 @@ void DepsgraphRelationBuilder::build_animdata(ID *id)
if (adt == NULL)
return;
- ComponentKey adt_key(id, DEPSNODE_TYPE_ANIMATION);
+ ComponentKey adt_key(id, DEG_NODE_TYPE_ANIMATION);
/* animation */
if (adt->action || adt->nla_tracks.first) {
/* wire up dependency to time source */
TimeSourceKey time_src_key;
- add_relation(time_src_key, adt_key, DEPSREL_TYPE_TIME, "[TimeSrc -> Animation]");
+ add_relation(time_src_key, adt_key, "[TimeSrc -> Animation]");
// XXX: Hook up specific update callbacks for special properties which may need it...
@@ -745,16 +857,65 @@ void DepsgraphRelationBuilder::build_animdata(ID *id)
}
/* drivers */
- for (FCurve *fcu = (FCurve *)adt->drivers.first; fcu; fcu = fcu->next) {
- OperationKey driver_key(id, DEPSNODE_TYPE_PARAMETERS, DEG_OPCODE_DRIVER, deg_fcurve_id_name(fcu));
+ LINKLIST_FOREACH (FCurve *, fcu, &adt->drivers) {
+ OperationKey driver_key(id,
+ DEG_NODE_TYPE_PARAMETERS,
+ DEG_OPCODE_DRIVER,
+ fcu->rna_path ? fcu->rna_path : "",
+ fcu->array_index);
/* 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.
+ *
+ * Some tricky things here:
+ * - array_index is -1 for single channel drivers, meaning we only have
+ * to do some magic when array_index is not -1.
+ * - We do relation from next array index to a previous one, so we don't
+ * have to deal with array index 0.
+ *
+ * TODO(sergey): Avoid liner lookup somehow.
+ */
+ if (fcu->array_index > 0) {
+ FCurve *fcu_prev = NULL;
+ LINKLIST_FOREACH (FCurve *, fcu_candidate, &adt->drivers) {
+ /* Writing to different RNA paths is */
+ const char *rna_path = fcu->rna_path ? fcu->rna_path : "";
+ if (!STREQ(fcu_candidate->rna_path, rna_path)) {
+ continue;
+ }
+ /* We only do relation from previous fcurve to previous one. */
+ if (fcu_candidate->array_index >= fcu->array_index) {
+ continue;
+ }
+ /* Choose fcurve with highest possible array index. */
+ if (fcu_prev == NULL ||
+ fcu_candidate->array_index > fcu_prev->array_index)
+ {
+ fcu_prev = fcu_candidate;
+ }
+ }
+ if (fcu_prev != NULL) {
+ OperationKey prev_driver_key(id,
+ DEG_NODE_TYPE_PARAMETERS,
+ DEG_OPCODE_DRIVER,
+ fcu_prev->rna_path ? fcu_prev->rna_path : "",
+ fcu_prev->array_index);
+ OperationKey driver_key(id,
+ DEG_NODE_TYPE_PARAMETERS,
+ DEG_OPCODE_DRIVER,
+ fcu->rna_path ? fcu->rna_path : "",
+ fcu->array_index);
+ add_relation(prev_driver_key, driver_key, "[Driver Order]");
+ }
+ }
+
/* prevent driver from occurring before own animation... */
if (adt->action || adt->nla_tracks.first) {
- add_relation(adt_key, driver_key, DEPSREL_TYPE_OPERATION,
- "[AnimData Before Drivers]");
+ add_relation(adt_key, driver_key, "[AnimData Before Drivers]");
}
}
}
@@ -762,23 +923,29 @@ void DepsgraphRelationBuilder::build_animdata(ID *id)
void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
{
ChannelDriver *driver = fcu->driver;
- OperationKey driver_key(id, DEPSNODE_TYPE_PARAMETERS, DEG_OPCODE_DRIVER, deg_fcurve_id_name(fcu));
+ OperationKey driver_key(id,
+ DEG_NODE_TYPE_PARAMETERS,
+ DEG_OPCODE_DRIVER,
+ fcu->rna_path ? fcu->rna_path : "",
+ fcu->array_index);
bPoseChannel *pchan = NULL;
+ const char *rna_path = fcu->rna_path ? fcu->rna_path : "";
+
/* create dependency between driver and data affected by it */
/* - direct property relationship... */
//RNAPathKey affected_key(id, fcu->rna_path);
- //add_relation(driver_key, affected_key, DEPSREL_TYPE_DRIVER, "[Driver -> Data] DepsRel");
+ //add_relation(driver_key, affected_key, "[Driver -> Data] DepsRel");
/* driver -> data components (for interleaved evaluation - bones/constraints/modifiers) */
// XXX: this probably should probably be moved out into a separate function
- if (strstr(fcu->rna_path, "pose.bones[") != NULL) {
+ if (strstr(rna_path, "pose.bones[") != NULL) {
/* interleaved drivers during bone eval */
// TODO: ideally, if this is for a constraint, it goes to said constraint
Object *ob = (Object *)id;
char *bone_name;
- bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
+ bone_name = BLI_str_quoted_substrN(rna_path, "pose.bones[");
pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
if (bone_name) {
@@ -787,21 +954,21 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
}
if (pchan) {
- OperationKey bone_key(id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
- add_relation(driver_key, bone_key, DEPSREL_TYPE_DRIVER, "[Driver -> Bone]");
+ OperationKey bone_key(id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
+ add_relation(driver_key, bone_key, "[Driver -> Bone]");
}
else {
fprintf(stderr,
"Couldn't find bone name for driver path - '%s'\n",
- fcu->rna_path);
+ rna_path);
}
}
- else if (GS(id->name) == ID_AR && strstr(fcu->rna_path, "bones[")) {
+ else if (GS(id->name) == ID_AR && strstr(rna_path, "bones[")) {
/* drivers on armature-level bone settings (i.e. bbone stuff),
* which will affect the evaluation of corresponding pose bones
*/
IDDepsNode *arm_node = m_graph->find_id_node(id);
- char *bone_name = BLI_str_quoted_substrN(fcu->rna_path, "bones[");
+ char *bone_name = BLI_str_quoted_substrN(rna_path, "bones[");
if (arm_node && bone_name) {
/* find objects which use this, and make their eval callbacks depend on this */
@@ -809,13 +976,13 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
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 *ob = (Object *)to_node->id;
+ if (GS(to_node->id_orig->name) == ID_OB) {
+ Object *ob = (Object *)to_node->id_orig;
bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bone_name); // NOTE: ob->pose may be NULL
if (pchan) {
- OperationKey bone_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
- add_relation(driver_key, bone_key, DEPSREL_TYPE_DRIVER, "[Arm Bone -> Driver -> Bone]");
+ OperationKey bone_key(&ob->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
+ add_relation(driver_key, bone_key, "[Arm Bone -> Driver -> Bone]");
}
}
}
@@ -827,48 +994,39 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
else {
fprintf(stderr,
"Couldn't find armature bone name for driver path - '%s'\n",
- fcu->rna_path);
+ rna_path);
}
}
- else if (GS(id->name) == ID_OB && strstr(fcu->rna_path, "modifiers[")) {
- /* modifier driver - connect directly to the modifier */
- char *modifier_name = BLI_str_quoted_substrN(fcu->rna_path, "modifiers[");
- if (modifier_name) {
- OperationKey modifier_key(id,
- DEPSNODE_TYPE_GEOMETRY,
- DEG_OPCODE_GEOMETRY_MODIFIER,
- modifier_name);
- if (has_node(modifier_key)) {
- add_relation(driver_key, modifier_key, DEPSREL_TYPE_DRIVER, "[Driver -> Modifier]");
- }
- else {
- printf("Unexisting driver RNA path: %s\n", fcu->rna_path);
- }
-
- MEM_freeN(modifier_name);
+ else if (GS(id->name) == ID_OB && strstr(rna_path, "modifiers[")) {
+ OperationKey modifier_key(id, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_UBEREVAL);
+ if (has_node(modifier_key)) {
+ add_relation(driver_key, modifier_key, "[Driver -> Modifier]");
+ }
+ else {
+ printf("Unexisting driver RNA path: %s\n", rna_path);
}
}
- else if (GS(id->name) == ID_KE && strstr(fcu->rna_path, "key_blocks[")) {
+ else if (GS(id->name) == ID_KE && strstr(rna_path, "key_blocks[")) {
/* shape key driver - hook into the base geometry operation */
// XXX: double check where this points
Key *shape_key = (Key *)id;
- ComponentKey geometry_key(shape_key->from, DEPSNODE_TYPE_GEOMETRY);
- add_relation(driver_key, geometry_key, DEPSREL_TYPE_DRIVER, "[Driver -> ShapeKey Geom]");
+ ComponentKey geometry_key(shape_key->from, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(driver_key, geometry_key, "[Driver -> ShapeKey Geom]");
}
- else if (strstr(fcu->rna_path, "key_blocks[")) {
- ComponentKey geometry_key(id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(driver_key, geometry_key, DEPSREL_TYPE_DRIVER, "[Driver -> ShapeKey Geom]");
+ else if (strstr(rna_path, "key_blocks[")) {
+ ComponentKey geometry_key(id, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(driver_key, geometry_key, "[Driver -> ShapeKey Geom]");
}
else {
if (GS(id->name) == ID_OB) {
/* assume that driver affects a transform... */
- OperationKey local_transform_key(id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_LOCAL);
- add_relation(driver_key, local_transform_key, DEPSREL_TYPE_OPERATION, "[Driver -> Transform]");
+ OperationKey local_transform_key(id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_LOCAL);
+ add_relation(driver_key, local_transform_key, "[Driver -> Transform]");
}
else if (GS(id->name) == ID_KE) {
- ComponentKey geometry_key(id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(driver_key, geometry_key, DEPSREL_TYPE_GEOMETRY_EVAL, "[Driver -> Shapekey Geometry]");
+ ComponentKey geometry_key(id, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(driver_key, geometry_key, "[Driver -> Shapekey Geometry]");
}
}
@@ -877,7 +1035,7 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
// XXX: the data itself could also set this, if it were to be truly initialised later?
/* loop over variables to get the target relationships */
- for (DriverVar *dvar = (DriverVar *)driver->variables.first; dvar; dvar = dvar->next) {
+ LINKLIST_FOREACH (DriverVar *, dvar, &driver->variables) {
/* only used targets */
DRIVER_TARGETS_USED_LOOPER(dvar)
{
@@ -901,14 +1059,14 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
{
continue;
}
- OperationKey target_key(dtar->id, DEPSNODE_TYPE_BONE, target_pchan->name, DEG_OPCODE_BONE_DONE);
- add_relation(target_key, driver_key, DEPSREL_TYPE_DRIVER_TARGET, "[Bone Target -> Driver]");
+ OperationKey target_key(dtar->id, DEG_NODE_TYPE_BONE, target_pchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(target_key, driver_key, "[Bone Target -> Driver]");
}
}
else if (dtar->flag & DTAR_FLAG_STRUCT_REF) {
/* get node associated with the object's transforms */
- OperationKey target_key(dtar->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
- add_relation(target_key, driver_key, DEPSREL_TYPE_DRIVER_TARGET, "[Target -> Driver]");
+ OperationKey target_key(dtar->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
+ add_relation(target_key, driver_key, "[Target -> Driver]");
}
else if (dtar->rna_path && strstr(dtar->rna_path, "pose.bones[")) {
/* workaround for ensuring that local bone transforms don't end up
@@ -928,8 +1086,8 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
{
continue;
}
- OperationKey bone_key(dtar->id, DEPSNODE_TYPE_BONE, target_pchan->name, DEG_OPCODE_BONE_LOCAL);
- add_relation(bone_key, driver_key, DEPSREL_TYPE_DRIVER, "[RNA Bone -> Driver]");
+ OperationKey bone_key(dtar->id, DEG_NODE_TYPE_BONE, target_pchan->name, DEG_OPCODE_BONE_LOCAL);
+ add_relation(bone_key, driver_key, "[RNA Bone -> Driver]");
}
}
else {
@@ -941,7 +1099,7 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
}
/* resolve path to get node */
RNAPathKey target_key(dtar->id, dtar->rna_path ? dtar->rna_path : "");
- add_relation(target_key, driver_key, DEPSREL_TYPE_DRIVER_TARGET, "[RNA Target -> Driver]");
+ add_relation(target_key, driver_key, "[RNA Target -> Driver]");
}
}
DRIVER_TARGETS_LOOPER_END
@@ -951,9 +1109,11 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
* so for now we'll be quite conservative here about optimization and consider
* all python drivers to be depending on time.
*/
- if (driver->type == DRIVER_TYPE_PYTHON) {
+ if ((driver->type == DRIVER_TYPE_PYTHON) &&
+ python_driver_depends_on_time(driver))
+ {
TimeSourceKey time_src_key;
- add_relation(time_src_key, driver_key, DEPSREL_TYPE_TIME, "[TimeSrc -> Driver]");
+ add_relation(time_src_key, driver_key, "[TimeSrc -> Driver]");
}
}
@@ -970,35 +1130,40 @@ void DepsgraphRelationBuilder::build_world(World *world)
/* TODO: other settings? */
/* textures */
- build_texture_stack(world_id, world->mtex);
+ build_texture_stack(world->mtex);
/* world's nodetree */
- build_nodetree(world_id, world->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");
+ }
}
void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
- OperationKey init_key(&scene->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_RIGIDBODY_REBUILD);
- OperationKey sim_key(&scene->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_RIGIDBODY_SIM);
+ OperationKey init_key(&scene->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_RIGIDBODY_REBUILD);
+ OperationKey sim_key(&scene->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_RIGIDBODY_SIM);
/* rel between the two sim-nodes */
- add_relation(init_key, sim_key, DEPSREL_TYPE_OPERATION, "Rigidbody [Init -> SimStep]");
+ add_relation(init_key, sim_key, "Rigidbody [Init -> SimStep]");
/* set up dependencies between these operations and other builtin nodes --------------- */
/* time dependency */
TimeSourceKey time_src_key;
- add_relation(time_src_key, init_key, DEPSREL_TYPE_TIME, "TimeSrc -> Rigidbody Reset/Rebuild (Optional)");
- add_relation(time_src_key, sim_key, DEPSREL_TYPE_TIME, "TimeSrc -> Rigidbody Sim Step");
+ add_relation(time_src_key, init_key, "TimeSrc -> Rigidbody Reset/Rebuild (Optional)");
/* objects - simulation participants */
if (rbw->group) {
- for (GroupObject *go = (GroupObject *)rbw->group->gobject.first; go; go = go->next) {
+ LINKLIST_FOREACH (GroupObject *, go, &rbw->group->gobject) {
Object *ob = go->ob;
- if (!ob || ob->type != OB_MESH)
+ if (ob == NULL || ob->type != OB_MESH) {
continue;
+ }
/* hook up evaluation order...
* 1) flushing rigidbody results follows base transforms being applied
@@ -1008,13 +1173,12 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
* XXX: there's probably a difference between passive and active
* - passive don't change, so may need to know full transform...
*/
- OperationKey rbo_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_RIGIDBODY);
+ OperationKey rbo_key(&ob->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_RIGIDBODY);
eDepsOperation_Code trans_opcode = ob->parent ? DEG_OPCODE_TRANSFORM_PARENT : DEG_OPCODE_TRANSFORM_LOCAL;
- OperationKey trans_op(&ob->id, DEPSNODE_TYPE_TRANSFORM, trans_opcode);
+ OperationKey trans_op(&ob->id, DEG_NODE_TYPE_TRANSFORM, trans_opcode);
- add_relation(trans_op, rbo_key, DEPSREL_TYPE_OPERATION, "Base Ob Transform -> RBO Sync");
- add_relation(sim_key, rbo_key, DEPSREL_TYPE_COMPONENT_ORDER, "Rigidbody Sim Eval -> RBO Sync");
+ add_relation(sim_key, rbo_key, "Rigidbody Sim Eval -> RBO Sync");
/* 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)
@@ -1025,47 +1189,51 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
* to control whether rigidbody eval gets interleaved into the constraint stack
*/
if (ob->constraints.first) {
- OperationKey constraint_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_CONSTRAINTS);
- add_relation(rbo_key, constraint_key, DEPSREL_TYPE_COMPONENT_ORDER, "RBO Sync -> Ob Constraints");
+ OperationKey constraint_key(&ob->id,
+ DEG_NODE_TYPE_TRANSFORM,
+ DEG_OPCODE_TRANSFORM_CONSTRAINTS);
+ add_relation(rbo_key, constraint_key, "RBO Sync -> Ob Constraints");
}
else {
- /* final object transform depends on rigidbody */
- OperationKey done_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
- add_relation(rbo_key, done_key, DEPSREL_TYPE_COMPONENT_ORDER, "RBO Sync -> Done");
-
- // XXX: ubereval will be removed eventually, but we still need it in the meantime
- OperationKey uber_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_OBJECT_UBEREVAL);
- add_relation(rbo_key, uber_key, DEPSREL_TYPE_COMPONENT_ORDER, "RBO Sync -> Uber (Temp)");
+ /* Final object transform depends on rigidbody.
+ *
+ * NOTE: Currently we consider final here an ubereval node.
+ * If it is gone we'll need to reconsider relation here.
+ */
+ OperationKey uber_key(&ob->id,
+ DEG_NODE_TYPE_TRANSFORM,
+ DEG_OPCODE_OBJECT_UBEREVAL);
+ add_relation(rbo_key, uber_key, "RBO Sync -> Uber (Temp)");
}
-
- /* needed to get correct base values */
- add_relation(trans_op, sim_key, DEPSREL_TYPE_OPERATION, "Base Ob Transform -> Rigidbody Sim Eval");
+ /* Needed to get correct base values. */
+ add_relation(trans_op, sim_key, "Base Ob Transform -> Rigidbody Sim Eval");
}
}
/* constraints */
if (rbw->constraints) {
- for (GroupObject *go = (GroupObject *)rbw->constraints->gobject.first; go; go = go->next) {
+ LINKLIST_FOREACH (GroupObject *, go, &rbw->constraints->gobject) {
Object *ob = go->ob;
- if (!ob || !ob->rigidbody_constraint)
+ if (ob == NULL || !ob->rigidbody_constraint) {
continue;
+ }
RigidBodyCon *rbc = ob->rigidbody_constraint;
/* final result of the constraint object's transform controls how the
* constraint affects the physics sim for these objects
*/
- ComponentKey trans_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
- OperationKey ob1_key(&rbc->ob1->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_RIGIDBODY);
- OperationKey ob2_key(&rbc->ob2->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_RIGIDBODY);
+ ComponentKey trans_key(&ob->id, DEG_NODE_TYPE_TRANSFORM);
+ OperationKey ob1_key(&rbc->ob1->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_RIGIDBODY);
+ OperationKey ob2_key(&rbc->ob2->id, DEG_NODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_RIGIDBODY);
/* - constrained-objects sync depends on the constraint-holder */
- add_relation(trans_key, ob1_key, DEPSREL_TYPE_TRANSFORM, "RigidBodyConstraint -> RBC.Object_1");
- add_relation(trans_key, ob2_key, DEPSREL_TYPE_TRANSFORM, "RigidBodyConstraint -> RBC.Object_2");
+ add_relation(trans_key, ob1_key, "RigidBodyConstraint -> RBC.Object_1");
+ add_relation(trans_key, ob2_key, "RigidBodyConstraint -> RBC.Object_2");
/* - ensure that sim depends on this constraint's transform */
- add_relation(trans_key, sim_key, DEPSREL_TYPE_TRANSFORM, "RigidBodyConstraint Transform -> RB Simulation");
+ add_relation(trans_key, sim_key, "RigidBodyConstraint Transform -> RB Simulation");
}
}
}
@@ -1074,18 +1242,18 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob)
{
TimeSourceKey time_src_key;
OperationKey obdata_ubereval_key(&ob->id,
- DEPSNODE_TYPE_GEOMETRY,
+ DEG_NODE_TYPE_GEOMETRY,
DEG_OPCODE_GEOMETRY_UBEREVAL);
/* particle systems */
- for (ParticleSystem *psys = (ParticleSystem *)ob->particlesystem.first; psys; psys = psys->next) {
+ LINKLIST_FOREACH (ParticleSystem *, psys, &ob->particlesystem) {
ParticleSettings *part = psys->part;
/* particle settings */
build_animdata(&part->id);
/* this particle system */
- OperationKey psys_key(&ob->id, DEPSNODE_TYPE_EVAL_PARTICLES, DEG_OPCODE_PSYS_EVAL, psys->name);
+ OperationKey psys_key(&ob->id, DEG_NODE_TYPE_EVAL_PARTICLES, DEG_OPCODE_PSYS_EVAL, psys->name);
/* XXX: if particle system is later re-enabled, we must do full rebuild? */
if (!psys_check_enabled(ob, psys, G.is_rendering))
@@ -1094,71 +1262,29 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob)
/* TODO(sergey): Are all particle systems depends on time?
* Hair without dynamics i.e.
*/
- add_relation(time_src_key, psys_key,
- DEPSREL_TYPE_TIME,
- "TimeSrc -> PSys");
+ add_relation(time_src_key, psys_key, "TimeSrc -> PSys");
/* TODO(sergey): Currently particle update is just a placeholder,
* hook it to the ubereval node so particle system is getting updated
* on playback.
*/
- add_relation(psys_key,
- obdata_ubereval_key,
- DEPSREL_TYPE_OPERATION,
- "PSys -> UberEval");
-
-#if 0
- if (ELEM(part->phystype, PART_PHYS_KEYED, PART_PHYS_BOIDS)) {
- ParticleTarget *pt;
-
- for (pt = psys->targets.first; pt; pt = pt->next) {
- if (pt->ob && BLI_findlink(&pt->ob->particlesystem, pt->psys - 1)) {
- node2 = dag_get_node(dag, pt->ob);
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Particle Targets");
- }
- }
- }
+ add_relation(psys_key, obdata_ubereval_key, "PSys -> UberEval");
- if (part->ren_as == PART_DRAW_OB && part->dup_ob) {
- node2 = dag_get_node(dag, part->dup_ob);
- /* note that this relation actually runs in the wrong direction, the problem
- * is that dupli system all have this (due to parenting), and the render
- * engine instancing assumes particular ordering of objects in list */
- dag_add_relation(dag, node, node2, DAG_RL_OB_OB, "Particle Object Visualization");
- if (part->dup_ob->type == OB_MBALL)
- dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA, "Particle Object Visualization");
+ /* collisions */
+ if (part->type != PART_HAIR) {
+ add_collision_relations(psys_key, scene, ob, part->collision_group, true, "Particle Collision");
}
-
- if (part->ren_as == PART_DRAW_GR && part->dup_group) {
- for (go = part->dup_group->gobject.first; go; go = go->next) {
- node2 = dag_get_node(dag, go->ob);
- dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Particle Group Visualization");
- }
+ else if ((psys->flag & PSYS_HAIR_DYNAMICS) && psys->clmd && psys->clmd->coll_parms) {
+ add_collision_relations(psys_key, scene, ob, psys->clmd->coll_parms->group, true, "Hair Collision");
}
-#endif
/* effectors */
- ListBase *effectors = pdInitEffectors(scene, ob, psys, part->effector_weights, false);
-
- if (effectors) {
- for (EffectorCache *eff = (EffectorCache *)effectors->first; eff; eff = eff->next) {
- if (eff->psys) {
- // XXX: DAG_RL_DATA_DATA | DAG_RL_OB_DATA
- ComponentKey eff_key(&eff->ob->id, DEPSNODE_TYPE_GEOMETRY); // xxx: particles instead?
- add_relation(eff_key, psys_key, DEPSREL_TYPE_STANDARD, "Particle Field");
- }
- }
- }
-
- pdEndEffectors(&effectors);
+ add_forcefield_relations(psys_key, scene, ob, psys, part->effector_weights, part->type == PART_HAIR, "Particle Field");
/* boids */
if (part->boids) {
- BoidRule *rule = NULL;
- BoidState *state = NULL;
-
- for (state = (BoidState *)part->boids->states.first; state; state = state->next) {
- for (rule = (BoidRule *)state->rules.first; rule; rule = rule->next) {
+ LINKLIST_FOREACH (BoidState *, state, &part->boids->states) {
+ LINKLIST_FOREACH (BoidRule *, rule, &state->rules) {
Object *ruleob = NULL;
if (rule->type == eBoidRuleType_Avoid)
ruleob = ((BoidRuleGoalAvoid *)rule)->ob;
@@ -1166,19 +1292,16 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob)
ruleob = ((BoidRuleFollowLeader *)rule)->ob;
if (ruleob) {
- ComponentKey ruleob_key(&ruleob->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(ruleob_key, psys_key, DEPSREL_TYPE_TRANSFORM, "Boid Rule");
+ ComponentKey ruleob_key(&ruleob->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(ruleob_key, psys_key, "Boid Rule");
}
}
}
}
if (part->ren_as == PART_DRAW_OB && part->dup_ob) {
- ComponentKey dup_ob_key(&part->dup_ob->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(dup_ob_key,
- psys_key,
- DEPSREL_TYPE_TRANSFORM,
- "Particle Object Visualization");
+ ComponentKey dup_ob_key(&part->dup_ob->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(dup_ob_key, psys_key, "Particle Object Visualization");
}
}
@@ -1188,405 +1311,32 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob)
* TODO(sergey): This relation should be altered once real granular update
* is implemented.
*/
- ComponentKey transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(transform_key,
- obdata_ubereval_key,
- DEPSREL_TYPE_GEOMETRY_EVAL,
- "Partcile Eval");
+ ComponentKey transform_key(&ob->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(transform_key, obdata_ubereval_key, "Partcile Eval");
/* pointcache */
// TODO...
}
-/* IK Solver Eval Steps */
-void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
- bPoseChannel *pchan,
- bConstraint *con,
- 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...
- */
- bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
- OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_IK_SOLVER);
-
- /* IK target */
- // XXX: 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.
- *
- * 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...
- ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
- if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) {
- /* TODO(sergey): This is only for until granular update stores intermediate result. */
- if (data->tar != ob) {
- /* different armature - can just read the results */
- ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget);
- add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, 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, DEPSNODE_TYPE_BONE, data->subtarget, DEG_OPCODE_BONE_DONE);
- add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, 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... */
- ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
-
- if (data->tar->type == OB_MESH) {
- OperationDepsNode *node2 = find_operation_node(target_key);
- if (node2 != NULL) {
- node2->customdata_mask |= CD_MASK_MDEFORMVERT;
- }
- }
- }
- else {
- /* Standard Object Target */
- ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name);
- }
-
- if ((data->tar == ob) && (data->subtarget[0])) {
- /* Prevent target's constraints from linking to anything from same
- * 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
- 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, DEPSNODE_TYPE_BONE, data->subtarget);
- add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
- }
- else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->subtarget[0])) {
- /* vertex group target */
- /* NOTE: for now, we don't need to represent vertex groups separately... */
- ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
-
- if (data->poletar->type == OB_MESH) {
- OperationDepsNode *node2 = find_operation_node(target_key);
- if (node2 != NULL) {
- node2->customdata_mask |= CD_MASK_MDEFORMVERT;
- }
- }
- }
- else {
- ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
- }
- }
-
- DEG_DEBUG_PRINTF("\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? */
- if (!(data->flag & CONSTRAINT_IK_TIP)) {
- OperationKey tip_transforms_key(&ob->id, DEPSNODE_TYPE_BONE,
- parchan->name, DEG_OPCODE_BONE_LOCAL);
- add_relation(solver_key, tip_transforms_key,
- DEPSREL_TYPE_TRANSFORM, "IK Solver Result");
- parchan = pchan->parent;
- }
-
- root_map->add_bone(parchan->name, rootchan->name);
-
- OperationKey parchan_transforms_key(&ob->id, DEPSNODE_TYPE_BONE,
- parchan->name, DEG_OPCODE_BONE_READY);
- add_relation(parchan_transforms_key, solver_key,
- DEPSREL_TYPE_TRANSFORM, "IK Solver Owner");
-
- /* Walk to the chain's root */
- //size_t segcount = 0;
- 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...
- */
- if (parchan != pchan) {
- OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY);
- add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Parent");
-
- OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
- add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result");
- }
- else {
- OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
- add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "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(" %d = %s\n", segcount, parchan->name);
- segcount++;
- if ((segcount == data->rootbone) || (segcount > 255)) break; /* 255 is weak */
-
- parchan = parchan->parent;
- }
-
- OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
- add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
-}
-
-/* Spline IK Eval Steps */
-void DepsgraphRelationBuilder::build_splineik_pose(Object *ob,
- bPoseChannel *pchan,
- bConstraint *con,
- RootPChanMap *root_map)
-{
- bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
- bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data);
- OperationKey transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
- OperationKey solver_key(&ob->id, DEPSNODE_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, DEPSREL_TYPE_TRANSFORM, "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.
- */
- // TODO: the bigggest point here is that we need the curve PATH and not just the general geometry...
- ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY);
- ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
- add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, "[Curve.Path -> Spline IK] DepsRel");
- }
-
- pchan->flag |= POSE_DONE;
- OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
- add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Result");
-
- root_map->add_bone(pchan->name, rootchan->name);
-
- /* Walk to the chain's root */
- //size_t segcount = 0;
- 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...
- */
- if (parchan != pchan) {
- OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY);
- add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Update");
-
- OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
- add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result");
- }
- parchan->flag |= POSE_DONE;
-
- OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
- add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Result");
-
- root_map->add_bone(parchan->name, rootchan->name);
-
- /* continue up chain, until we reach target number of items... */
- segcount++;
- if ((segcount == data->chainlen) || (segcount > 255)) break; /* 255 is weak */
- }
-
- OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
- add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
-}
-
-/* Pose/Armature Bones Graph */
-void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob)
-{
- /* Armature-Data */
- bArmature *arm = (bArmature *)ob->data;
-
- // TODO: selection status?
-
- /* attach links between pose operations */
- OperationKey init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
- OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
-
- add_relation(init_key, flush_key, DEPSREL_TYPE_COMPONENT_ORDER, "[Pose Init -> Pose Cleanup]");
-
- /* Make sure pose is up-to-date with armature updates. */
- OperationKey armature_key(&arm->id,
- DEPSNODE_TYPE_PARAMETERS,
- DEG_OPCODE_PLACEHOLDER,
- "Armature Eval");
- add_relation(armature_key, init_key, DEPSREL_TYPE_COMPONENT_ORDER, "Data dependency");
-
- if (ob->adt && (ob->adt->action || ob->adt->nla_tracks.first)) {
- ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION);
- add_relation(animation_key, init_key, DEPSREL_TYPE_OPERATION, "Rig Animation");
- }
-
- /* 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)
- *
- * - 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)
- *
- * 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...
- */
- RootPChanMap root_map;
- bool pose_depends_on_local_transform = false;
- for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) {
- switch (con->type) {
- case CONSTRAINT_TYPE_KINEMATIC:
- build_ik_pose(ob, pchan, con, &root_map);
- pose_depends_on_local_transform = true;
- break;
-
- case CONSTRAINT_TYPE_SPLINEIK:
- build_splineik_pose(ob, pchan, con, &root_map);
- pose_depends_on_local_transform = true;
- break;
-
- /* Constraints which needs world's matrix for transform.
- * TODO(sergey): More constraints here?
- */
- case CONSTRAINT_TYPE_ROTLIKE:
- case CONSTRAINT_TYPE_SIZELIKE:
- case CONSTRAINT_TYPE_LOCLIKE:
- case CONSTRAINT_TYPE_TRANSLIKE:
- /* TODO(sergey): Add used space check. */
- pose_depends_on_local_transform = true;
- break;
-
- default:
- break;
- }
- }
- }
- //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.
- */
- ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
- ComponentKey local_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(local_transform_key, pose_key, DEPSREL_TYPE_TRANSFORM, "Local Transforms");
- }
-
-
- /* links between operations for each bone */
- for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
- OperationKey bone_pose_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_POSE_PARENT);
- OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
- OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
-
- pchan->flag &= ~POSE_DONE;
-
- /* pose init to bone local */
- add_relation(init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "PoseEval Source-Bone Link");
-
- /* local to pose parenting operation */
- add_relation(bone_local_key, bone_pose_key, DEPSREL_TYPE_OPERATION, "Bone Local - PoseSpace Link");
-
- /* 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 */
- if (root_map.has_common_root(pchan->name, pchan->parent->name)) {
- parent_key_opcode = DEG_OPCODE_BONE_READY;
- }
- else {
- parent_key_opcode = DEG_OPCODE_BONE_DONE;
- }
-
- OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->parent->name, parent_key_opcode);
- add_relation(parent_key, bone_pose_key, DEPSREL_TYPE_TRANSFORM, "[Parent Bone -> Child Bone]");
- }
-
- /* constraints */
- if (pchan->constraints.first != NULL) {
- /* constraints stack and constraint dependencies */
- build_constraints(scene, &ob->id, DEPSNODE_TYPE_BONE, pchan->name, &pchan->constraints, &root_map);
-
- /* pose -> constraints */
- OperationKey constraints_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_CONSTRAINTS);
- add_relation(bone_pose_key, constraints_key, DEPSREL_TYPE_OPERATION, "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, DEPSREL_TYPE_OPERATION, "Constraints -> Ready");
- }
- else {
- /* pose -> ready */
- add_relation(bone_pose_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Pose -> Ready");
- }
-
- /* bone ready -> 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...
- */
- add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done");
-
- /* assume that all bones must be done for the pose to be ready (for deformers) */
- add_relation(bone_done_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
- }
-}
-
-void DepsgraphRelationBuilder::build_proxy_rig(Object *ob)
+void DepsgraphRelationBuilder::build_cloth(Scene * /*scene*/,
+ Object *object,
+ ModifierData * /*md*/)
{
- OperationKey pose_init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
- OperationKey pose_done_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
- for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first;
- pchan != NULL;
- pchan = pchan->next)
- {
- OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
- OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
- OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
- add_relation(pose_init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "Pose Init -> Bone Local");
- add_relation(bone_local_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Local -> Ready");
- add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done");
- add_relation(bone_done_key, pose_done_key, DEPSREL_TYPE_OPERATION, "Bone Done -> Pose Done");
- }
+ OperationKey cache_key(&object->id,
+ DEG_NODE_TYPE_CACHE,
+ DEG_OPCODE_PLACEHOLDER,
+ "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)
{
- ComponentKey obdata_key(obdata, DEPSNODE_TYPE_GEOMETRY);
+ ComponentKey obdata_key(obdata, DEG_NODE_TYPE_GEOMETRY);
/* attach animdata to geometry */
build_animdata(&key->id);
@@ -1594,8 +1344,8 @@ void DepsgraphRelationBuilder::build_shapekeys(ID *obdata, Key *key)
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, DEPSNODE_TYPE_ANIMATION);
- add_relation(adt_key, obdata_key, DEPSREL_TYPE_OPERATION, "Animation");
+ ComponentKey adt_key(&key->id, DEG_NODE_TYPE_ANIMATION);
+ add_relation(adt_key, obdata_key, "Animation");
}
/* NOTE: individual shapekey drivers are handled above already */
@@ -1603,8 +1353,8 @@ void DepsgraphRelationBuilder::build_shapekeys(ID *obdata, Key *key)
/* attach to geometry */
// XXX: aren't shapekeys now done as a pseudo-modifier on object?
- //ComponentKey key_key(&key->id, DEPSNODE_TYPE_GEOMETRY); // FIXME: this doesn't exist
- //add_relation(key_key, obdata_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Shapekeys");
+ //ComponentKey key_key(&key->id, DEG_NODE_TYPE_GEOMETRY); // FIXME: this doesn't exist
+ //add_relation(key_key, obdata_key, "Shapekeys");
}
/**
@@ -1632,35 +1382,36 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
ID *obdata = (ID *)ob->data;
/* Init operation of object-level geometry evaluation. */
- OperationKey geom_init_key(&ob->id, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Eval Init");
+ OperationKey geom_init_key(&ob->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, DEPSNODE_TYPE_GEOMETRY);
- ComponentKey geom_key(&ob->id, DEPSNODE_TYPE_GEOMETRY);
+ ComponentKey obdata_geom_key(obdata, DEG_NODE_TYPE_GEOMETRY);
+ ComponentKey geom_key(&ob->id, DEG_NODE_TYPE_GEOMETRY);
/* link components to each other */
- add_relation(obdata_geom_key, geom_key, DEPSREL_TYPE_DATABLOCK, "Object Geometry Base Data");
+ add_relation(obdata_geom_key, geom_key, "Object Geometry Base Data");
- /* Modifiers */
- if (ob->modifiers.first) {
- ModifierData *md;
- OperationKey prev_mod_key;
+ OperationKey obdata_ubereval_key(&ob->id,
+ DEG_NODE_TYPE_GEOMETRY,
+ DEG_OPCODE_GEOMETRY_UBEREVAL);
- for (md = (ModifierData *)ob->modifiers.first; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo((ModifierType)md->type);
- OperationKey mod_key(&ob->id, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_MODIFIER, md->name);
+ /* Special case: modifiers and DerivedMesh creation 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_PARAMETERS,
+ DEG_OPCODE_PLACEHOLDER,
+ "Scene Eval");
+ add_relation(scene_key, obdata_ubereval_key, "CoW Relation");
- if (md->prev) {
- /* Stack relation: modifier depends on previous modifier in the stack */
- add_relation(prev_mod_key, mod_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Modifier Stack");
- }
- else {
- /* Stack relation: first modifier depends on the geometry. */
- add_relation(geom_init_key, mod_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Modifier Stack");
- }
+ /* Modifiers */
+ if (ob->modifiers.first != NULL) {
+ LINKLIST_FOREACH (ModifierData *, md, &ob->modifiers) {
+ const ModifierTypeInfo *mti = modifierType_getInfo((ModifierType)md->type);
if (mti->updateDepsgraph) {
- DepsNodeHandle handle = create_node_handle(mod_key);
+ DepsNodeHandle handle = create_node_handle(obdata_ubereval_key);
mti->updateDepsgraph(
md,
bmain,
@@ -1671,7 +1422,7 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
if (BKE_object_modifier_use_time(ob, md)) {
TimeSourceKey time_src_key;
- add_relation(time_src_key, mod_key, DEPSREL_TYPE_TIME, "Time Source");
+ add_relation(time_src_key, obdata_ubereval_key, "Time Source");
/* Hacky fix for T45633 (Animated modifiers aren't updated)
*
@@ -1679,25 +1430,34 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
* for either the modifier needing time, or that it is animated.
*/
/* XXX: Remove this hack when these links are added as part of build_animdata() instead */
- if (modifier_dependsOnTime(md) == false) {
- ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION);
- add_relation(animation_key, mod_key, DEPSREL_TYPE_OPERATION, "Modifier Animation");
+ if (modifier_dependsOnTime(md) == false && needs_animdata_node(&ob->id)) {
+ ComponentKey animation_key(&ob->id, DEG_NODE_TYPE_ANIMATION);
+ add_relation(animation_key, obdata_ubereval_key, "Modifier Animation");
}
}
- prev_mod_key = mod_key;
+ if (md->type == eModifierType_Cloth) {
+ build_cloth(scene, ob, md);
+ }
}
}
/* materials */
if (ob->totcol) {
- int a;
-
- for (a = 1; a <= ob->totcol; a++) {
+ for (int a = 1; a <= ob->totcol; a++) {
Material *ma = give_current_material(ob, a);
-
- if (ma)
- build_material(&ob->id, ma);
+ if (ma != NULL) {
+ build_material(ma);
+
+ if (ob->type == OB_MESH) {
+ OperationKey material_key(&ma->id,
+ DEG_NODE_TYPE_SHADING,
+ DEG_OPCODE_PLACEHOLDER,
+ "Material Update");
+ OperationKey shading_key(&ob->id, DEG_NODE_TYPE_SHADING, DEG_OPCODE_SHADING);
+ add_relation(material_key, shading_key, "Material Update");
+ }
+ }
}
}
@@ -1712,15 +1472,8 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
*/
if (ob->type != OB_ARMATURE) {
/* Armatures does no longer require uber node. */
- OperationKey obdata_ubereval_key(&ob->id, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_UBEREVAL);
- if (ob->modifiers.last) {
- ModifierData *md = (ModifierData *)ob->modifiers.last;
- OperationKey mod_key(&ob->id, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_MODIFIER, md->name);
- add_relation(mod_key, obdata_ubereval_key, DEPSREL_TYPE_OPERATION, "Object Geometry UberEval");
- }
- else {
- add_relation(geom_init_key, obdata_ubereval_key, DEPSREL_TYPE_OPERATION, "Object Geometry UberEval");
- }
+ OperationKey obdata_ubereval_key(&ob->id, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_UBEREVAL);
+ add_relation(geom_init_key, obdata_ubereval_key, "Object Geometry UberEval");
}
if (obdata->tag & LIB_TAG_DOIT) {
@@ -1729,13 +1482,26 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
obdata->tag |= LIB_TAG_DOIT;
/* Link object data evaluation node to exit operation. */
- OperationKey obdata_geom_eval_key(obdata, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
- OperationKey obdata_geom_done_key(obdata, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Eval Done");
- add_relation(obdata_geom_eval_key, obdata_geom_done_key, DEPSREL_TYPE_DATABLOCK, "ObData Geom Eval Done");
+ 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 (ob->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 (ob->particlesystem.first != NULL) {
+ TimeSourceKey time_key;
+ OperationKey obdata_ubereval_key(&ob->id, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_UBEREVAL);
+ add_relation(time_key, obdata_ubereval_key, "Legacy particle time");
+ }
break;
case OB_MBALL:
@@ -1745,10 +1511,10 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
/* motherball - mom depends on children! */
if (mom != ob) {
/* non-motherball -> cannot be directly evaluated! */
- ComponentKey mom_key(&mom->id, DEPSNODE_TYPE_GEOMETRY);
- ComponentKey transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(geom_key, mom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Metaball Motherball");
- add_relation(transform_key, mom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Metaball Motherball");
+ ComponentKey mom_key(&mom->id, DEG_NODE_TYPE_GEOMETRY);
+ ComponentKey transform_key(&ob->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(geom_key, mom_key, "Metaball Motherball");
+ add_relation(transform_key, mom_key, "Metaball Motherball");
}
break;
}
@@ -1761,17 +1527,20 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
/* curve's dependencies */
// XXX: these needs geom data, but where is geom stored?
if (cu->bevobj) {
- ComponentKey bevob_key(&cu->bevobj->id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(bevob_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Curve Bevel");
+ ComponentKey bevob_key(&cu->bevobj->id, DEG_NODE_TYPE_GEOMETRY);
+ build_object(bmain, scene, cu->bevobj);
+ add_relation(bevob_key, geom_key, "Curve Bevel");
}
if (cu->taperobj) {
- ComponentKey taperob_key(&cu->taperobj->id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(taperob_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Curve Taper");
+ ComponentKey taperob_key(&cu->taperobj->id, DEG_NODE_TYPE_GEOMETRY);
+ build_object(bmain, scene, cu->taperobj);
+ add_relation(taperob_key, geom_key, "Curve Taper");
}
if (ob->type == OB_FONT) {
if (cu->textoncurve) {
- ComponentKey textoncurve_key(&cu->taperobj->id, DEPSNODE_TYPE_GEOMETRY);
- add_relation(textoncurve_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Text on Curve");
+ ComponentKey textoncurve_key(&cu->textoncurve->id, DEG_NODE_TYPE_GEOMETRY);
+ build_object(bmain, scene, cu->textoncurve);
+ add_relation(textoncurve_key, geom_key, "Text on Curve");
}
}
break;
@@ -1795,14 +1564,13 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
}
if (needs_animdata_node(obdata)) {
- ComponentKey animation_key(obdata, DEPSNODE_TYPE_ANIMATION);
- ComponentKey parameters_key(obdata, DEPSNODE_TYPE_PARAMETERS);
- add_relation(animation_key, parameters_key,
- DEPSREL_TYPE_COMPONENT_ORDER, "Geom Parameters");
+ ComponentKey animation_key(obdata, DEG_NODE_TYPE_ANIMATION);
+ ComponentKey parameters_key(obdata, DEG_NODE_TYPE_PARAMETERS);
+ add_relation(animation_key, parameters_key, "Geom Parameters");
/* Evaluation usually depends on animation.
* TODO(sergey): Need to re-hook it after granular update is implemented..
*/
- add_relation(animation_key, obdata_geom_eval_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Animation");
+ add_relation(animation_key, obdata_geom_eval_key, "Animation");
}
}
@@ -1817,19 +1585,18 @@ void DepsgraphRelationBuilder::build_camera(Object *ob)
}
camera_id->tag |= LIB_TAG_DOIT;
- ComponentKey parameters_key(camera_id, DEPSNODE_TYPE_PARAMETERS);
+ ComponentKey parameters_key(camera_id, DEG_NODE_TYPE_PARAMETERS);
if (needs_animdata_node(camera_id)) {
- ComponentKey animation_key(camera_id, DEPSNODE_TYPE_ANIMATION);
- add_relation(animation_key, parameters_key,
- DEPSREL_TYPE_COMPONENT_ORDER, "Camera Parameters");
+ ComponentKey animation_key(camera_id, DEG_NODE_TYPE_ANIMATION);
+ add_relation(animation_key, parameters_key, "Camera Parameters");
}
/* DOF */
if (cam->dof_ob) {
- ComponentKey ob_param_key(&ob->id, DEPSNODE_TYPE_PARAMETERS);
- ComponentKey dof_ob_key(&cam->dof_ob->id, DEPSNODE_TYPE_TRANSFORM);
- add_relation(dof_ob_key, ob_param_key, DEPSREL_TYPE_TRANSFORM, "Camera DOF");
+ ComponentKey ob_param_key(&ob->id, DEG_NODE_TYPE_PARAMETERS);
+ ComponentKey dof_ob_key(&cam->dof_ob->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(dof_ob_key, ob_param_key, "Camera DOF");
}
}
@@ -1843,27 +1610,25 @@ void DepsgraphRelationBuilder::build_lamp(Object *ob)
}
lamp_id->tag |= LIB_TAG_DOIT;
- ComponentKey parameters_key(lamp_id, DEPSNODE_TYPE_PARAMETERS);
+ ComponentKey parameters_key(lamp_id, DEG_NODE_TYPE_PARAMETERS);
if (needs_animdata_node(lamp_id)) {
- ComponentKey animation_key(lamp_id, DEPSNODE_TYPE_ANIMATION);
- add_relation(animation_key, parameters_key,
- DEPSREL_TYPE_COMPONENT_ORDER, "Lamp Parameters");
+ ComponentKey animation_key(lamp_id, DEG_NODE_TYPE_ANIMATION);
+ add_relation(animation_key, parameters_key, "Lamp Parameters");
}
/* lamp's nodetree */
if (la->nodetree) {
- build_nodetree(lamp_id, la->nodetree);
- ComponentKey nodetree_key(&la->nodetree->id, DEPSNODE_TYPE_PARAMETERS);
- add_relation(nodetree_key, parameters_key,
- DEPSREL_TYPE_COMPONENT_ORDER, "NTree->Lamp Parameters");
+ build_nodetree(la->nodetree);
+ ComponentKey nodetree_key(&la->nodetree->id, DEG_NODE_TYPE_PARAMETERS);
+ add_relation(nodetree_key, parameters_key, "NTree->Lamp Parameters");
}
/* textures */
- build_texture_stack(lamp_id, la->mtex);
+ build_texture_stack(la->mtex);
}
-void DepsgraphRelationBuilder::build_nodetree(ID *owner, bNodeTree *ntree)
+void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
{
if (!ntree)
return;
@@ -1873,46 +1638,42 @@ void DepsgraphRelationBuilder::build_nodetree(ID *owner, bNodeTree *ntree)
build_animdata(ntree_id);
OperationKey parameters_key(ntree_id,
- DEPSNODE_TYPE_PARAMETERS,
+ DEG_NODE_TYPE_PARAMETERS,
DEG_OPCODE_PLACEHOLDER,
"Parameters Eval");
/* nodetree's nodes... */
- for (bNode *bnode = (bNode *)ntree->nodes.first; bnode; bnode = bnode->next) {
+ LINKLIST_FOREACH (bNode *, bnode, &ntree->nodes) {
if (bnode->id) {
if (GS(bnode->id->name) == ID_MA) {
- build_material(owner, (Material *)bnode->id);
+ build_material((Material *)bnode->id);
}
else if (bnode->type == ID_TE) {
- build_texture(owner, (Tex *)bnode->id);
+ build_texture((Tex *)bnode->id);
}
else if (bnode->type == NODE_GROUP) {
bNodeTree *group_ntree = (bNodeTree *)bnode->id;
if ((group_ntree->id.tag & LIB_TAG_DOIT) == 0) {
- build_nodetree(owner, group_ntree);
+ build_nodetree(group_ntree);
group_ntree->id.tag |= LIB_TAG_DOIT;
}
OperationKey group_parameters_key(&group_ntree->id,
- DEPSNODE_TYPE_PARAMETERS,
+ DEG_NODE_TYPE_PARAMETERS,
DEG_OPCODE_PLACEHOLDER,
"Parameters Eval");
- add_relation(group_parameters_key, parameters_key,
- DEPSREL_TYPE_COMPONENT_ORDER, "Group Node");
+ add_relation(group_parameters_key, parameters_key, "Group Node");
}
}
}
if (needs_animdata_node(ntree_id)) {
- ComponentKey animation_key(ntree_id, DEPSNODE_TYPE_ANIMATION);
- add_relation(animation_key, parameters_key,
- DEPSREL_TYPE_COMPONENT_ORDER, "NTree Parameters");
+ ComponentKey animation_key(ntree_id, DEG_NODE_TYPE_ANIMATION);
+ add_relation(animation_key, parameters_key, "NTree Parameters");
}
-
- // TODO: link from nodetree to owner_component?
}
/* Recursively build graph for material */
-void DepsgraphRelationBuilder::build_material(ID *owner, Material *ma)
+void DepsgraphRelationBuilder::build_material(Material *ma)
{
ID *ma_id = &ma->id;
if (ma_id->tag & LIB_TAG_DOIT) {
@@ -1924,14 +1685,25 @@ void DepsgraphRelationBuilder::build_material(ID *owner, Material *ma)
build_animdata(ma_id);
/* textures */
- build_texture_stack(owner, ma->mtex);
+ build_texture_stack(ma->mtex);
/* material's nodetree */
- build_nodetree(owner, ma->nodetree);
+ if (ma->nodetree != NULL) {
+ build_nodetree(ma->nodetree);
+ OperationKey ntree_key(&ma->nodetree->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ DEG_OPCODE_PLACEHOLDER,
+ "Parameters Eval");
+ OperationKey material_key(&ma->id,
+ DEG_NODE_TYPE_SHADING,
+ DEG_OPCODE_PLACEHOLDER,
+ "Material Update");
+ add_relation(ntree_key, material_key, "Material's NTree");
+ }
}
/* Recursively build graph for texture */
-void DepsgraphRelationBuilder::build_texture(ID *owner, Tex *tex)
+void DepsgraphRelationBuilder::build_texture(Tex *tex)
{
ID *tex_id = &tex->id;
if (tex_id->tag & LIB_TAG_DOIT) {
@@ -1943,11 +1715,11 @@ void DepsgraphRelationBuilder::build_texture(ID *owner, Tex *tex)
build_animdata(tex_id);
/* texture's nodetree */
- build_nodetree(owner, tex->nodetree);
+ build_nodetree(tex->nodetree);
}
/* Texture-stack attached to some shading datablock */
-void DepsgraphRelationBuilder::build_texture_stack(ID *owner, MTex **texture_stack)
+void DepsgraphRelationBuilder::build_texture_stack(MTex **texture_stack)
{
int i;
@@ -1955,17 +1727,17 @@ void DepsgraphRelationBuilder::build_texture_stack(ID *owner, MTex **texture_sta
for (i = 0; i < MAX_MTEX; i++) {
MTex *mtex = texture_stack[i];
if (mtex && mtex->tex)
- build_texture(owner, mtex->tex);
+ build_texture(mtex->tex);
}
}
void DepsgraphRelationBuilder::build_compositor(Scene *scene)
{
/* For now, just a plain wrapper? */
- build_nodetree(&scene->id, scene->nodetree);
+ build_nodetree(scene->nodetree);
}
-void DepsgraphRelationBuilder::build_gpencil(ID *UNUSED(owner), bGPdata *gpd)
+void DepsgraphRelationBuilder::build_gpencil(bGPdata *gpd)
{
/* animation */
build_animdata(&gpd->id);
@@ -1977,9 +1749,105 @@ bool DepsgraphRelationBuilder::needs_animdata_node(ID *id)
{
AnimData *adt = BKE_animdata_from_id(id);
if (adt != NULL) {
- return adt->action != NULL;
+ return (adt->action != NULL) || (adt->nla_tracks.first != NULL);
}
return false;
}
+void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file) {
+ /* Animation. */
+ build_animdata(&cache_file->id);
+}
+
+void DepsgraphRelationBuilder::build_mask(Mask *mask)
+{
+ /* Animation. */
+ build_animdata(&mask->id);
+}
+
+void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip)
+{
+ /* Animation. */
+ build_animdata(&clip->id);
+}
+
+void DepsgraphRelationBuilder::build_lightprobe(Object *object)
+{
+ LightProbe *probe = (LightProbe *)object->data;
+ ID *probe_id = &probe->id;
+ if (probe_id->tag & LIB_TAG_DOIT) {
+ return;
+ }
+ probe_id->tag |= LIB_TAG_DOIT;
+ build_animdata(&probe->id);
+
+ OperationKey probe_key(probe_id,
+ DEG_NODE_TYPE_PARAMETERS,
+ DEG_OPCODE_PLACEHOLDER,
+ "LightProbe Eval");
+ OperationKey object_key(&object->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ DEG_OPCODE_PLACEHOLDER,
+ "LightProbe Eval");
+ add_relation(probe_key, object_key, "LightProbe Update");
+}
+
+void DepsgraphRelationBuilder::build_copy_on_write_relations()
+{
+ GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, m_graph->id_hash)
+ {
+ build_copy_on_write_relations(id_node);
+ }
+ GHASH_FOREACH_END();
+}
+
+void DepsgraphRelationBuilder::build_copy_on_write_relations(IDDepsNode *id_node)
+{
+ ID *id_orig = id_node->id_orig;
+
+ 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;
+ }
+ /* 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) {
+ m_graph->add_new_relation(op_cow, op_entry, "CoW Dependency");
+ }
+ /* All dangling operations should also be executed after copy-on-write. */
+ GHASH_FOREACH_BEGIN(OperationDepsNode *, op_node, comp_node->operations_map)
+ {
+ if (op_node->inlinks.size() == 0) {
+ m_graph->add_new_relation(op_cow, op_node, "CoW Dependency");
+ }
+ }
+ 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();
+}
+
} // 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 ce6d2c961fd..8a53bf4a6bf 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -45,17 +45,22 @@
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_operation.h"
-struct Base;
+struct BaseLegacy;
struct bGPdata;
+struct CacheFile;
struct ListBase;
struct GHash;
struct ID;
struct FCurve;
struct Group;
struct Key;
+struct LayerCollection;
struct Main;
+struct Mask;
struct Material;
struct MTex;
+struct ModifierData;
+struct MovieClip;
struct bNodeTree;
struct Object;
struct bPoseChannel;
@@ -63,6 +68,8 @@ struct bConstraint;
struct Scene;
struct Tex;
struct World;
+struct EffectorWeights;
+struct ParticleSystem;
struct PropertyRNA;
@@ -72,115 +79,85 @@ struct Depsgraph;
struct DepsNode;
struct DepsNodeHandle;
struct RootDepsNode;
-struct SubgraphDepsNode;
struct IDDepsNode;
struct TimeSourceDepsNode;
struct ComponentDepsNode;
struct OperationDepsNode;
struct RootPChanMap;
-struct RootKey
-{
- RootKey() {}
-};
-
struct TimeSourceKey
{
- TimeSourceKey() : id(NULL) {}
- TimeSourceKey(ID *id) : id(id) {}
+ TimeSourceKey();
+ TimeSourceKey(ID *id);
- string identifier() const
- {
- return string("TimeSourceKey");
- }
+ string identifier() const;
ID *id;
};
struct ComponentKey
{
- ComponentKey() :
- id(NULL), type(DEPSNODE_TYPE_UNDEFINED), name("")
- {}
- ComponentKey(ID *id, eDepsNode_Type type, const string &name = "") :
- id(id), type(type), name(name)
- {}
-
- string identifier() const
- {
- const char *idname = (id) ? id->name : "<None>";
-
- char typebuf[5];
- BLI_snprintf(typebuf, sizeof(typebuf), "%d", type);
+ ComponentKey();
+ ComponentKey(ID *id, eDepsNode_Type type, const char *name = "");
- return string("ComponentKey(") + idname + ", " + typebuf + ", '" + name + "')";
- }
+ string identifier() const;
ID *id;
eDepsNode_Type type;
- string name;
+ const char *name;
};
struct OperationKey
{
- OperationKey() :
- id(NULL), component_type(DEPSNODE_TYPE_UNDEFINED), component_name(""), opcode(DEG_OPCODE_OPERATION), name("")
- {}
-
- OperationKey(ID *id, eDepsNode_Type component_type, const string &name) :
- id(id), component_type(component_type), component_name(""), opcode(DEG_OPCODE_OPERATION), name(name)
- {}
- OperationKey(ID *id, eDepsNode_Type component_type, const string &component_name, const string &name) :
- id(id), component_type(component_type), component_name(component_name), opcode(DEG_OPCODE_OPERATION), name(name)
- {}
-
- OperationKey(ID *id, eDepsNode_Type component_type, eDepsOperation_Code opcode) :
- id(id), component_type(component_type), component_name(""), opcode(opcode), name("")
- {}
- OperationKey(ID *id, eDepsNode_Type component_type, const string &component_name, eDepsOperation_Code opcode) :
- id(id), component_type(component_type), component_name(component_name), opcode(opcode), name("")
- {}
-
- OperationKey(ID *id, eDepsNode_Type component_type, eDepsOperation_Code opcode, const string &name) :
- id(id), component_type(component_type), component_name(""), opcode(opcode), name(name)
- {}
- OperationKey(ID *id, eDepsNode_Type component_type, const string &component_name, eDepsOperation_Code opcode, const string &name) :
- id(id), component_type(component_type), component_name(component_name), opcode(opcode), name(name)
- {}
-
- string 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 + "')";
- }
-
+ OperationKey();
+ OperationKey(ID *id,
+ eDepsNode_Type component_type,
+ const char *name,
+ int name_tag = -1);
+ OperationKey(ID *id,
+ eDepsNode_Type component_type,
+ const char *component_name,
+ const char *name,
+ int name_tag);
+
+ OperationKey(ID *id,
+ eDepsNode_Type component_type,
+ eDepsOperation_Code opcode);
+ OperationKey(ID *id,
+ eDepsNode_Type component_type,
+ const char *component_name,
+ eDepsOperation_Code opcode);
+
+ OperationKey(ID *id,
+ eDepsNode_Type component_type,
+ eDepsOperation_Code opcode,
+ const char *name,
+ int name_tag = -1);
+ OperationKey(ID *id,
+ eDepsNode_Type component_type,
+ const char *component_name,
+ eDepsOperation_Code opcode,
+ const char *name,
+ int name_tag = -1);
+
+ string identifier() const;
ID *id;
eDepsNode_Type component_type;
- string component_name;
+ const char *component_name;
eDepsOperation_Code opcode;
- string name;
+ const char *name;
+ int name_tag;
};
struct RNAPathKey
{
- // Note: see depsgraph_build.cpp for implementation
+ /* NOTE: see depsgraph_build.cpp for implementation */
RNAPathKey(ID *id, const char *path);
- RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop) :
- id(id), ptr(ptr), prop(prop)
- {}
-
- string 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 + "')";
- }
+ RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop);
+ string identifier() const;
ID *id;
PointerRNA ptr;
@@ -191,22 +168,21 @@ struct DepsgraphRelationBuilder
{
DepsgraphRelationBuilder(Depsgraph *graph);
+ void begin_build(Main *bmain);
+
template <typename KeyFrom, typename KeyTo>
void add_relation(const KeyFrom& key_from,
const KeyTo& key_to,
- eDepsRelation_Type type,
const char *description);
template <typename KeyTo>
void add_relation(const TimeSourceKey& key_from,
const KeyTo& key_to,
- eDepsRelation_Type type,
const char *description);
template <typename KeyType>
void add_node_handle_relation(const KeyType& key_from,
const DepsNodeHandle *handle,
- eDepsRelation_Type type,
const char *description);
void build_scene(Main *bmain, Scene *scene);
@@ -223,6 +199,7 @@ struct DepsgraphRelationBuilder
void build_world(World *world);
void build_rigidbody(Scene *scene);
void build_particles(Scene *scene, Object *ob);
+ void build_cloth(Scene *scene, Object *object, ModifierData *md);
void build_ik_pose(Object *ob,
bPoseChannel *pchan,
bConstraint *con,
@@ -237,18 +214,48 @@ struct DepsgraphRelationBuilder
void build_obdata_geom(Main *bmain, Scene *scene, Object *ob);
void build_camera(Object *ob);
void build_lamp(Object *ob);
- void build_nodetree(ID *owner, bNodeTree *ntree);
- void build_material(ID *owner, Material *ma);
- void build_texture(ID *owner, Tex *tex);
- void build_texture_stack(ID *owner, MTex **texture_stack);
+ 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(ID *owner, bGPdata *gpd);
+ void build_gpencil(bGPdata *gpd);
+ void build_cachefile(CacheFile *cache_file);
+ void build_mask(Mask *mask);
+ void build_movieclip(MovieClip *clip);
+ void build_lightprobe(Object *object);
+
+ void add_collision_relations(const OperationKey &key,
+ Scene *scene, Object *ob, Group *group,
+ bool dupli, const char *name);
+ void add_forcefield_relations(const OperationKey &key,
+ Scene *scene, Object *ob, ParticleSystem *psys,
+ EffectorWeights *eff,
+ bool add_absorption, const char *name);
+
+ struct LayerCollectionState {
+ int index;
+ OperationKey init_key;
+ OperationKey done_key;
+ OperationKey prev_key;
+ };
+ void build_layer_collection(Scene *scene,
+ LayerCollection *layer_collection,
+ LayerCollectionState *state);
+ void build_layer_collections(Scene *scene,
+ ListBase *layer_collections,
+ LayerCollectionState *state);
+ void build_scene_layer_collections(Scene *scene);
+
+ 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);
+ Depsgraph *getGraph();
+
protected:
- RootDepsNode *find_node(const RootKey &key) const;
TimeSourceDepsNode *find_node(const TimeSourceKey &key) const;
ComponentDepsNode *find_node(const ComponentKey &key) const;
OperationDepsNode *find_node(const OperationKey &key) const;
@@ -260,12 +267,11 @@ protected:
const char *description);
void add_operation_relation(OperationDepsNode *node_from,
OperationDepsNode *node_to,
- eDepsRelation_Type type,
const char *description);
template <typename KeyType>
DepsNodeHandle create_node_handle(const KeyType& key,
- const string& default_name = "");
+ const char *default_name = "");
bool needs_animdata_node(ID *id);
@@ -275,7 +281,7 @@ private:
struct DepsNodeHandle
{
- DepsNodeHandle(DepsgraphRelationBuilder *builder, OperationDepsNode *node, const string &default_name = "") :
+ DepsNodeHandle(DepsgraphRelationBuilder *builder, OperationDepsNode *node, const char *default_name = "") :
builder(builder),
node(node),
default_name(default_name)
@@ -285,7 +291,7 @@ struct DepsNodeHandle
DepsgraphRelationBuilder *builder;
OperationDepsNode *node;
- const string &default_name;
+ const char *default_name;
};
/* Utilities for Builders ----------------------------------------------------- */
@@ -300,7 +306,6 @@ OperationDepsNode *DepsgraphRelationBuilder::find_operation_node(const KeyType&
template <typename KeyFrom, typename KeyTo>
void DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from,
const KeyTo &key_to,
- eDepsRelation_Type type,
const char *description)
{
DepsNode *node_from = find_node(key_from);
@@ -308,26 +313,27 @@ void DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from,
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) {
- add_operation_relation(op_from, op_to, type, description);
+ add_operation_relation(op_from, op_to, description);
}
else {
if (!op_from) {
/* XXX TODO handle as error or report if needed */
- fprintf(stderr, "add_relation(%d, %s) - Could not find op_from (%s)\n",
- type, description, key_from.identifier().c_str());
+ node_from = find_node(key_from);
+ fprintf(stderr, "add_relation(%s) - Could not find op_from (%s)\n",
+ description, key_from.identifier().c_str());
}
else {
- fprintf(stderr, "add_relation(%d, %s) - Failed, but op_from (%s) was ok\n",
- type, description, key_from.identifier().c_str());
+ fprintf(stderr, "add_relation(%s) - Failed, but op_from (%s) was ok\n",
+ description, key_from.identifier().c_str());
}
if (!op_to) {
/* XXX TODO handle as error or report if needed */
- fprintf(stderr, "add_relation(%d, %s) - Could not find op_to (%s)\n",
- type, description, key_to.identifier().c_str());
+ fprintf(stderr, "add_relation(%s) - Could not find op_to (%s)\n",
+ description, key_to.identifier().c_str());
}
else {
- fprintf(stderr, "add_relation(%d, %s) - Failed, but op_to (%s) was ok\n",
- type, description, key_to.identifier().c_str());
+ fprintf(stderr, "add_relation(%s) - Failed, but op_to (%s) was ok\n",
+ description, key_to.identifier().c_str());
}
}
}
@@ -335,11 +341,8 @@ void DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from,
template <typename KeyTo>
void DepsgraphRelationBuilder::add_relation(const TimeSourceKey &key_from,
const KeyTo &key_to,
- eDepsRelation_Type type,
const char *description)
{
- (void)type; /* Ignored in release builds. */
- BLI_assert(type == DEPSREL_TYPE_TIME);
TimeSourceDepsNode *time_from = find_node(key_from);
DepsNode *node_to = find_node(key_to);
OperationDepsNode *op_to = node_to ? node_to->get_entry_operation() : NULL;
@@ -354,21 +357,22 @@ template <typename KeyType>
void DepsgraphRelationBuilder::add_node_handle_relation(
const KeyType &key_from,
const DepsNodeHandle *handle,
- eDepsRelation_Type type,
const char *description)
{
DepsNode *node_from = find_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 && op_to) {
- add_operation_relation(op_from, op_to, type, description);
+ add_operation_relation(op_from, op_to, description);
}
else {
if (!op_from) {
- /* XXX TODO handle as error or report if needed */
+ fprintf(stderr, "add_node_handle_relation(%s) - Could not find op_from (%s)\n",
+ description, key_from.identifier().c_str());
}
if (!op_to) {
- /* XXX TODO handle as error or report if needed */
+ fprintf(stderr, "add_node_handle_relation(%s) - Could not find op_to (%s)\n",
+ description, key_from.identifier().c_str());
}
}
}
@@ -376,7 +380,7 @@ void DepsgraphRelationBuilder::add_node_handle_relation(
template <typename KeyType>
DepsNodeHandle DepsgraphRelationBuilder::create_node_handle(
const KeyType &key,
- const string &default_name)
+ const char *default_name)
{
return DepsNodeHandle(this, find_node(key), default_name);
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc
new file mode 100644
index 00000000000..9d6ab3358a7
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc
@@ -0,0 +1,204 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/builder/deg_builder_relations_keys.cc
+ * \ingroup depsgraph
+ *
+ * Methods for constructing depsgraph
+ */
+
+#include "intern/builder/deg_builder_relations.h"
+
+namespace DEG {
+
+/////////////////////////////////////////
+// Time source.
+
+TimeSourceKey::TimeSourceKey()
+ : id(NULL)
+{
+}
+
+TimeSourceKey::TimeSourceKey(ID *id)
+ : id(id)
+{
+}
+
+string TimeSourceKey::identifier() const
+{
+ return string("TimeSourceKey");
+}
+
+/////////////////////////////////////////
+// Component.
+
+ComponentKey::ComponentKey()
+ : id(NULL),
+ type(DEG_NODE_TYPE_UNDEFINED),
+ name("")
+{
+}
+
+ComponentKey::ComponentKey(ID *id, eDepsNode_Type type, const char *name)
+ : id(id),
+ type(type),
+ name(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 + "')";
+}
+
+/////////////////////////////////////////
+// Operation.
+
+OperationKey::OperationKey()
+ : id(NULL),
+ component_type(DEG_NODE_TYPE_UNDEFINED),
+ component_name(""),
+ opcode(DEG_OPCODE_OPERATION),
+ name(""),
+ name_tag(-1)
+{
+}
+
+OperationKey::OperationKey(ID *id,
+ eDepsNode_Type component_type,
+ const char *name,
+ int name_tag)
+ : id(id),
+ component_type(component_type),
+ component_name(""),
+ opcode(DEG_OPCODE_OPERATION),
+ name(name),
+ name_tag(name_tag)
+{
+}
+
+OperationKey::OperationKey(ID *id,
+ eDepsNode_Type component_type,
+ const char *component_name,
+ const char *name,
+ int name_tag)
+ : id(id),
+ component_type(component_type),
+ component_name(component_name),
+ opcode(DEG_OPCODE_OPERATION),
+ name(name),
+ name_tag(name_tag)
+{
+}
+
+OperationKey::OperationKey(ID *id,
+ eDepsNode_Type component_type,
+ eDepsOperation_Code opcode)
+ : id(id),
+ component_type(component_type),
+ component_name(""),
+ opcode(opcode),
+ name(""),
+ name_tag(-1)
+{
+}
+
+OperationKey::OperationKey(ID *id,
+ eDepsNode_Type component_type,
+ const char *component_name,
+ eDepsOperation_Code opcode)
+ : id(id),
+ component_type(component_type),
+ component_name(component_name),
+ opcode(opcode),
+ name(""),
+ name_tag(-1)
+{
+}
+
+OperationKey::OperationKey(ID *id,
+ eDepsNode_Type component_type,
+ eDepsOperation_Code opcode,
+ const char *name,
+ int name_tag)
+ : id(id),
+ component_type(component_type),
+ component_name(""),
+ opcode(opcode),
+ name(name),
+ name_tag(name_tag)
+{
+}
+
+OperationKey::OperationKey(ID *id,
+ eDepsNode_Type component_type,
+ const char *component_name,
+ eDepsOperation_Code opcode,
+ const char *name,
+ int name_tag)
+ : id(id),
+ component_type(component_type),
+ component_name(component_name),
+ opcode(opcode),
+ name(name),
+ name_tag(name_tag)
+{
+}
+
+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 + "')";
+}
+
+/////////////////////////////////////////
+// RNA path.
+
+RNAPathKey::RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop)
+ : id(id),
+ ptr(ptr),
+ prop(prop)
+{
+}
+
+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 + "')";
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_layer.cc
new file mode 100644
index 00000000000..a6c9fdfc6bc
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_layer.cc
@@ -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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
+ * \ingroup depsgraph
+ *
+ * Methods for constructing depsgraph
+ */
+
+#include "intern/builder/deg_builder_relations.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <cstring> /* required for STREQ later on. */
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_layer.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+} /* extern "C" */
+
+#include "intern/builder/deg_builder.h"
+#include "intern/builder/deg_builder_pchanmap.h"
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "intern/depsgraph_intern.h"
+#include "intern/depsgraph_types.h"
+
+#include "util/deg_util_foreach.h"
+
+namespace DEG {
+
+void DepsgraphRelationBuilder::build_layer_collection(Scene *scene,
+ LayerCollection *layer_collection,
+ LayerCollectionState *state)
+{
+ OperationKey layer_key(&scene->id,
+ DEG_NODE_TYPE_LAYER_COLLECTIONS,
+ DEG_OPCODE_SCENE_LAYER_EVAL,
+ layer_collection->scene_collection->name,
+ state->index);
+ add_relation(state->prev_key, layer_key, "Layer collection order");
+
+ ++state->index;
+ state->prev_key = layer_key;
+
+ /* Recurs into nested layer collections. */
+ build_layer_collections(scene,
+ &layer_collection->layer_collections,
+ state);
+}
+
+void DepsgraphRelationBuilder::build_layer_collections(Scene *scene,
+ ListBase *layer_collections,
+ LayerCollectionState *state)
+{
+ LINKLIST_FOREACH (LayerCollection *, layer_collection, layer_collections) {
+ /* Recurs into the layer. */
+ build_layer_collection(scene, layer_collection, state);
+ }
+}
+
+void DepsgraphRelationBuilder::build_scene_layer_collections(Scene *scene)
+{
+ LayerCollectionState state;
+ state.index = 0;
+ LINKLIST_FOREACH (SceneLayer *, scene_layer, &scene->render_layers) {
+ OperationKey init_key(&scene->id,
+ DEG_NODE_TYPE_LAYER_COLLECTIONS,
+ DEG_OPCODE_SCENE_LAYER_INIT,
+ scene_layer->name);
+ OperationKey done_key(&scene->id,
+ DEG_NODE_TYPE_LAYER_COLLECTIONS,
+ DEG_OPCODE_SCENE_LAYER_DONE,
+ scene_layer->name);
+
+ state.init_key = init_key;
+ state.done_key = done_key;
+ state.prev_key = init_key;
+
+ build_layer_collections(scene,
+ &scene_layer->layer_collections,
+ &state);
+
+ add_relation(state.prev_key, done_key, "Layer collection order");
+ }
+}
+
+} // 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
new file mode 100644
index 00000000000..be666165a0b
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
@@ -0,0 +1,452 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
+ * \ingroup depsgraph
+ *
+ * Methods for constructing depsgraph
+ */
+
+#include "intern/builder/deg_builder_relations.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <cstring> /* required for STREQ later on. */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_blenlib.h"
+
+extern "C" {
+#include "DNA_action_types.h"
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+} /* extern "C" */
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "intern/builder/deg_builder.h"
+#include "intern/builder/deg_builder_pchanmap.h"
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "intern/depsgraph_intern.h"
+#include "intern/depsgraph_types.h"
+
+#include "util/deg_util_foreach.h"
+
+namespace DEG {
+
+/* IK Solver Eval Steps */
+void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *con,
+ 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...
+ */
+ bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
+ OperationKey solver_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_IK_SOLVER);
+
+ /* IK target */
+ // XXX: 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.
+ *
+ * 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...
+ ComponentKey pose_key(&ob->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. */
+ if (data->tar != ob) {
+ /* 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);
+ 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... */
+ 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;
+ }
+ }
+ }
+ else {
+ /* Standard Object Target */
+ ComponentKey target_key(&data->tar->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(target_key, pose_key, con->name);
+ }
+
+ if ((data->tar == ob) && (data->subtarget[0])) {
+ /* Prevent target's constraints from linking to anything from same
+ * 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
+ 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);
+ 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... */
+ 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;
+ }
+ }
+ }
+ else {
+ ComponentKey target_key(&data->poletar->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(target_key, solver_key, con->name);
+ }
+ }
+
+ DEG_DEBUG_PRINTF("\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? */
+ if (!(data->flag & CONSTRAINT_IK_TIP)) {
+ OperationKey tip_transforms_key(&ob->id, DEG_NODE_TYPE_BONE,
+ parchan->name, DEG_OPCODE_BONE_LOCAL);
+ add_relation(solver_key, tip_transforms_key, "IK Solver Result");
+ parchan = pchan->parent;
+ }
+
+ root_map->add_bone(parchan->name, rootchan->name);
+
+ OperationKey parchan_transforms_key(&ob->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;
+ 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...
+ */
+ if (parchan != pchan) {
+ OperationKey parent_key(&ob->id, DEG_NODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY);
+ add_relation(parent_key, solver_key, "IK Chain Parent");
+
+ OperationKey done_key(&ob->id, DEG_NODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(solver_key, done_key, "IK Chain Result");
+ }
+ else {
+ OperationKey final_transforms_key(&ob->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(" %d = %s\n", segcount, parchan->name);
+ segcount++;
+ if ((segcount == data->rootbone) || (segcount > 255)) break; /* 255 is weak */
+
+ parchan = parchan->parent;
+ }
+
+ OperationKey flush_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
+ add_relation(solver_key, flush_key, "PoseEval Result-Bone Link");
+}
+
+/* Spline IK Eval Steps */
+void DepsgraphRelationBuilder::build_splineik_pose(Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *con,
+ RootPChanMap *root_map)
+{
+ bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
+ bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data);
+ OperationKey transforms_key(&ob->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
+ OperationKey solver_key(&ob->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.
+ */
+ // 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(&ob->id, DEG_NODE_TYPE_EVAL_POSE);
+ add_relation(target_key, pose_key, "[Curve.Path -> Spline IK] DepsRel");
+ }
+
+ pchan->flag |= POSE_DONE;
+ OperationKey final_transforms_key(&ob->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;
+ 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...
+ */
+ if (parchan != pchan) {
+ OperationKey parent_key(&ob->id, DEG_NODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY);
+ add_relation(parent_key, solver_key, "Spline IK Solver Update");
+
+ OperationKey done_key(&ob->id, DEG_NODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(solver_key, done_key, "IK Chain Result");
+ }
+ parchan->flag |= POSE_DONE;
+
+ OperationKey final_transforms_key(&ob->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... */
+ segcount++;
+ if ((segcount == data->chainlen) || (segcount > 255)) break; /* 255 is weak */
+ }
+
+ OperationKey flush_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
+ add_relation(solver_key, flush_key, "PoseEval Result-Bone Link");
+}
+
+/* Pose/Armature Bones Graph */
+void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob)
+{
+ /* Armature-Data */
+ bArmature *arm = (bArmature *)ob->data;
+
+ // TODO: selection status?
+
+ /* attach links between pose operations */
+ OperationKey init_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
+ OperationKey flush_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
+
+ add_relation(init_key, flush_key, "[Pose Init -> Pose Cleanup]");
+
+ /* Make sure pose is up-to-date with armature updates. */
+ OperationKey armature_key(&arm->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ DEG_OPCODE_PLACEHOLDER,
+ "Armature Eval");
+ add_relation(armature_key, init_key, "Data dependency");
+
+ if (needs_animdata_node(&ob->id)) {
+ ComponentKey animation_key(&ob->id, DEG_NODE_TYPE_ANIMATION);
+ add_relation(animation_key, init_key, "Rig Animation");
+ }
+
+ /* 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)
+ *
+ * - 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)
+ *
+ * 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...
+ */
+ RootPChanMap root_map;
+ bool pose_depends_on_local_transform = false;
+ LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
+ LINKLIST_FOREACH (bConstraint *, con, &pchan->constraints) {
+ switch (con->type) {
+ case CONSTRAINT_TYPE_KINEMATIC:
+ build_ik_pose(ob, pchan, con, &root_map);
+ pose_depends_on_local_transform = true;
+ break;
+
+ case CONSTRAINT_TYPE_SPLINEIK:
+ build_splineik_pose(ob, pchan, con, &root_map);
+ pose_depends_on_local_transform = true;
+ break;
+
+ /* Constraints which needs world's matrix for transform.
+ * TODO(sergey): More constraints here?
+ */
+ case CONSTRAINT_TYPE_ROTLIKE:
+ case CONSTRAINT_TYPE_SIZELIKE:
+ case CONSTRAINT_TYPE_LOCLIKE:
+ case CONSTRAINT_TYPE_TRANSLIKE:
+ /* TODO(sergey): Add used space check. */
+ pose_depends_on_local_transform = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ //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.
+ */
+ ComponentKey pose_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE);
+ ComponentKey local_transform_key(&ob->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(local_transform_key, pose_key, "Local Transforms");
+ }
+
+ /* links between operations for each bone */
+ LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
+ OperationKey bone_local_key(&ob->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
+ OperationKey bone_pose_key(&ob->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_POSE_PARENT);
+ OperationKey bone_ready_key(&ob->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
+ OperationKey bone_done_key(&ob->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 */
+ 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 */
+ if (root_map.has_common_root(pchan->name, pchan->parent->name)) {
+ parent_key_opcode = DEG_OPCODE_BONE_READY;
+ }
+ else {
+ parent_key_opcode = DEG_OPCODE_BONE_DONE;
+ }
+
+ OperationKey parent_key(&ob->id, DEG_NODE_TYPE_BONE, pchan->parent->name, parent_key_opcode);
+ add_relation(parent_key, bone_pose_key, "[Parent Bone -> Child Bone]");
+ }
+
+ /* constraints */
+ if (pchan->constraints.first != NULL) {
+ /* constraints stack and constraint dependencies */
+ build_constraints(scene, &ob->id, DEG_NODE_TYPE_BONE, pchan->name, &pchan->constraints, &root_map);
+
+ /* pose -> constraints */
+ OperationKey constraints_key(&ob->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");
+ }
+ else {
+ /* pose -> ready */
+ add_relation(bone_pose_key, bone_ready_key, "Pose -> Ready");
+ }
+
+ /* bone ready -> 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...
+ */
+ 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");
+ }
+}
+
+void DepsgraphRelationBuilder::build_proxy_rig(Object *ob)
+{
+ OperationKey pose_init_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
+ OperationKey pose_done_key(&ob->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
+ LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
+ OperationKey bone_local_key(&ob->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
+ OperationKey bone_ready_key(&ob->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
+ OperationKey bone_done_key(&ob->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_done_key, "Bone Done -> Pose Done");
+ }
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
new file mode 100644
index 00000000000..4b8d5119cf6
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
@@ -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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
+ * \ingroup depsgraph
+ *
+ * Methods for constructing depsgraph
+ */
+
+#include "intern/builder/deg_builder_relations.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <cstring> /* required for STREQ later on. */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_blenlib.h"
+
+extern "C" {
+#include "DNA_node_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" */
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "intern/builder/deg_builder.h"
+#include "intern/builder/deg_builder_pchanmap.h"
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "intern/depsgraph_intern.h"
+#include "intern/depsgraph_types.h"
+
+#include "util/deg_util_foreach.h"
+
+namespace DEG {
+
+void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene)
+{
+ if (scene->set) {
+ build_scene(bmain, scene->set);
+ }
+
+ /* XXX store scene to access from DAG_get_scene */
+ m_graph->bmain = bmain;
+ m_graph->scene = scene;
+
+ /* scene objects */
+ for (SceneLayer *sl = (SceneLayer *)scene->render_layers.first; sl; sl = sl->next) {
+ for (Base *base = (Base *)sl->object_bases.first; base; base = base->next) {
+ build_object(bmain, scene, base->object);
+ }
+ }
+
+ /* rigidbody */
+ if (scene->rigidbody_world) {
+ build_rigidbody(scene);
+ }
+
+ /* scene's animation and drivers */
+ if (scene->adt) {
+ build_animdata(&scene->id);
+ }
+
+ /* world */
+ if (scene->world) {
+ build_world(scene->world);
+ }
+
+ /* compo nodes */
+ if (scene->nodetree) {
+ build_compositor(scene);
+ }
+
+ /* grease pencil */
+ if (scene->gpd) {
+ build_gpencil(scene->gpd);
+ }
+
+ /* Masks. */
+ LINKLIST_FOREACH (Mask *, mask, &bmain->mask) {
+ build_mask(mask);
+ }
+
+ /* Movie clips. */
+ LINKLIST_FOREACH (MovieClip *, clip, &bmain->movieclip) {
+ build_movieclip(clip);
+ }
+
+ /* Collections. */
+ build_scene_layer_collections(scene);
+
+ /* TODO(sergey): Do this flush on CoW object? */
+ for (Depsgraph::OperationNodes::const_iterator it_op = m_graph->operations.begin();
+ it_op != m_graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ IDDepsNode *id_node = node->owner->owner;
+ ID *id = id_node->id_orig;
+ if (GS(id->name) == ID_OB) {
+ Object *object = (Object *)id;
+ object->customdata_mask |= node->customdata_mask;
+ }
+ }
+}
+
+} // 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 76cd81f1b8f..b12af21fc8d 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
@@ -30,9 +30,7 @@
#include "intern/builder/deg_builder_transitive.h"
-extern "C" {
#include "MEM_guardedalloc.h"
-}
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
@@ -47,7 +45,7 @@ namespace DEG {
/* -------------------------------------------------- */
/* Performs a transitive reduction to remove redundant relations.
- * http://en.wikipedia.org/wiki/Transitive_reduction
+ * https://en.wikipedia.org/wiki/Transitive_reduction
*
* XXX The current implementation is somewhat naive and has O(V*E) worst case
* runtime.
@@ -105,7 +103,7 @@ void deg_graph_transitive_reduction(Depsgraph *graph)
/* Increment in advance, so we can safely remove the relation. */
++it_rel;
- if (rel->from->type == DEPSNODE_TYPE_TIMESOURCE) {
+ if (rel->from->type == DEG_NODE_TYPE_TIMESOURCE) {
/* HACK: time source nodes don't get "done" flag set/cleared. */
/* TODO: there will be other types in future, so iterators above
* need modifying.
diff --git a/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc
index 70cd5f11a47..66b63f861ee 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc
+++ b/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc
@@ -35,10 +35,10 @@
extern "C" {
#include "DNA_listBase.h"
+} /* extern "C" */
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_debug.h"
-} /* extern "C" */
#include "intern/depsgraph_intern.h"
#include "util/deg_util_foreach.h"
@@ -77,21 +77,21 @@ static const char *deg_debug_colors_light[] = {
#ifdef COLOR_SCHEME_NODE_TYPE
static const int deg_debug_node_type_color_map[][2] = {
- {DEPSNODE_TYPE_ROOT, 0},
- {DEPSNODE_TYPE_TIMESOURCE, 1},
- {DEPSNODE_TYPE_ID_REF, 2},
- {DEPSNODE_TYPE_SUBGRAPH, 3},
+ {DEG_NODE_TYPE_TIMESOURCE, 0},
+ {DEG_NODE_TYPE_ID_REF, 1},
/* Outer Types */
- {DEPSNODE_TYPE_PARAMETERS, 4},
- {DEPSNODE_TYPE_PROXY, 5},
- {DEPSNODE_TYPE_ANIMATION, 6},
- {DEPSNODE_TYPE_TRANSFORM, 7},
- {DEPSNODE_TYPE_GEOMETRY, 8},
- {DEPSNODE_TYPE_SEQUENCER, 9},
- {DEPSNODE_TYPE_SHADING, 10},
- {DEPSNODE_TYPE_CACHE, 11},
- {-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_CACHE, 9},
+ {DEG_NODE_TYPE_LAYER_COLLECTIONS, 10},
+ {DEG_NODE_TYPE_COPY_ON_WRITE, 11},
+ {-1, 0}
};
#endif
@@ -100,9 +100,9 @@ static int deg_debug_node_color_index(const DepsNode *node)
#ifdef COLOR_SCHEME_NODE_CLASS
/* Some special types. */
switch (node->type) {
- case DEPSNODE_TYPE_ID_REF:
+ case DEG_NODE_TYPE_ID_REF:
return 5;
- case DEPSNODE_TYPE_OPERATION:
+ case DEG_NODE_TYPE_OPERATION:
{
OperationDepsNode *op_node = (OperationDepsNode *)node;
if (op_node->is_noop())
@@ -115,9 +115,9 @@ static int deg_debug_node_color_index(const DepsNode *node)
}
/* Do others based on class. */
switch (node->tclass) {
- case DEPSNODE_CLASS_OPERATION:
+ case DEG_NODE_CLASS_OPERATION:
return 4;
- case DEPSNODE_CLASS_COMPONENT:
+ case DEG_NODE_CLASS_COMPONENT:
return 1;
default:
return 9;
@@ -179,7 +179,7 @@ static void deg_debug_graphviz_legend(const DebugContext &ctx)
#ifdef COLOR_SCHEME_NODE_TYPE
const int (*pair)[2];
for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) {
- DepsNodeFactory *nti = DEG_get_node_factory((eDepsNode_Type)(*pair)[0]);
+ DepsNodeFactory *nti = DEG_get_node_factory((eDEG_NODE_TYPE)(*pair)[0]);
deg_debug_graphviz_legend_color(ctx,
nti->tname().c_str(),
deg_debug_colors_light[(*pair)[1] % deg_debug_max_colors]);
@@ -201,7 +201,7 @@ static void deg_debug_graphviz_node_color(const DebugContext &ctx,
const char *color_update = "dodgerblue3";
const char *color = color_default;
if (ctx.show_tags) {
- if (node->tclass == DEPSNODE_CLASS_OPERATION) {
+ if (node->tclass == DEG_NODE_CLASS_OPERATION) {
OperationDepsNode *op_node = (OperationDepsNode *)node;
if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
color = color_modified;
@@ -222,7 +222,7 @@ static void deg_debug_graphviz_node_penwidth(const DebugContext &ctx,
float penwidth_update = 4.0f;
float penwidth = penwidth_default;
if (ctx.show_tags) {
- if (node->tclass == DEPSNODE_CLASS_OPERATION) {
+ if (node->tclass == DEG_NODE_CLASS_OPERATION) {
OperationDepsNode *op_node = (OperationDepsNode *)node;
if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
penwidth = penwidth_modified;
@@ -260,7 +260,7 @@ static void deg_debug_graphviz_node_style(const DebugContext &ctx, const DepsNod
{
const char *base_style = "filled"; /* default style */
if (ctx.show_tags) {
- if (node->tclass == DEPSNODE_CLASS_OPERATION) {
+ if (node->tclass == DEG_NODE_CLASS_OPERATION) {
OperationDepsNode *op_node = (OperationDepsNode *)node;
if (op_node->flag & (DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE)) {
base_style = "striped";
@@ -268,13 +268,13 @@ static void deg_debug_graphviz_node_style(const DebugContext &ctx, const DepsNod
}
}
switch (node->tclass) {
- case DEPSNODE_CLASS_GENERIC:
+ case DEG_NODE_CLASS_GENERIC:
deg_debug_fprintf(ctx, "\"%s\"", base_style);
break;
- case DEPSNODE_CLASS_COMPONENT:
+ case DEG_NODE_CLASS_COMPONENT:
deg_debug_fprintf(ctx, "\"%s\"", base_style);
break;
- case DEPSNODE_CLASS_OPERATION:
+ case DEG_NODE_CLASS_OPERATION:
deg_debug_fprintf(ctx, "\"%s,rounded\"", base_style);
break;
}
@@ -286,13 +286,7 @@ static void deg_debug_graphviz_node_single(const DebugContext &ctx,
const char *shape = "box";
string name = node->identifier();
float priority = -1.0f;
- if (node->type == DEPSNODE_TYPE_ID_REF) {
- IDDepsNode *id_node = (IDDepsNode *)node;
- char buf[256];
- BLI_snprintf(buf, sizeof(buf), " (Layers: %u)", id_node->layers);
- name += buf;
- }
- if (ctx.show_eval_priority && node->tclass == DEPSNODE_CLASS_OPERATION) {
+ if (ctx.show_eval_priority && node->tclass == DEG_NODE_CLASS_OPERATION) {
priority = ((OperationDepsNode *)node)->eval_priority;
}
deg_debug_fprintf(ctx, "// %s\n", name.c_str());
@@ -321,13 +315,7 @@ static void deg_debug_graphviz_node_single(const DebugContext &ctx,
static void deg_debug_graphviz_node_cluster_begin(const DebugContext &ctx,
const DepsNode *node)
{
- string name = node->identifier().c_str();
- if (node->type == DEPSNODE_TYPE_ID_REF) {
- IDDepsNode *id_node = (IDDepsNode *)node;
- char buf[256];
- BLI_snprintf(buf, sizeof(buf), " (Layers: %u)", id_node->layers);
- name += buf;
- }
+ string name = node->identifier();
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);
@@ -363,7 +351,7 @@ static void deg_debug_graphviz_node(const DebugContext &ctx,
const DepsNode *node)
{
switch (node->type) {
- case DEPSNODE_TYPE_ID_REF:
+ case DEG_NODE_TYPE_ID_REF:
{
const IDDepsNode *id_node = (const IDDepsNode *)node;
if (BLI_ghash_size(id_node->components) == 0) {
@@ -380,30 +368,19 @@ static void deg_debug_graphviz_node(const DebugContext &ctx,
}
break;
}
- case DEPSNODE_TYPE_SUBGRAPH:
- {
- SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
- if (sub_node->graph) {
- deg_debug_graphviz_node_cluster_begin(ctx, node);
- deg_debug_graphviz_graph_nodes(ctx, sub_node->graph);
- deg_debug_graphviz_node_cluster_end(ctx);
- }
- else {
- deg_debug_graphviz_node_single(ctx, node);
- }
- break;
- }
- case DEPSNODE_TYPE_PARAMETERS:
- case DEPSNODE_TYPE_ANIMATION:
- case DEPSNODE_TYPE_TRANSFORM:
- case DEPSNODE_TYPE_PROXY:
- case DEPSNODE_TYPE_GEOMETRY:
- case DEPSNODE_TYPE_SEQUENCER:
- case DEPSNODE_TYPE_EVAL_POSE:
- case DEPSNODE_TYPE_BONE:
- case DEPSNODE_TYPE_SHADING:
- case DEPSNODE_TYPE_CACHE:
- case DEPSNODE_TYPE_EVAL_PARTICLES:
+ case DEG_NODE_TYPE_PARAMETERS:
+ case DEG_NODE_TYPE_ANIMATION:
+ case DEG_NODE_TYPE_TRANSFORM:
+ case DEG_NODE_TYPE_PROXY:
+ case DEG_NODE_TYPE_GEOMETRY:
+ case DEG_NODE_TYPE_SEQUENCER:
+ case DEG_NODE_TYPE_EVAL_POSE:
+ case DEG_NODE_TYPE_BONE:
+ case DEG_NODE_TYPE_SHADING:
+ case DEG_NODE_TYPE_CACHE:
+ case DEG_NODE_TYPE_LAYER_COLLECTIONS:
+ case DEG_NODE_TYPE_EVAL_PARTICLES:
+ case DEG_NODE_TYPE_COPY_ON_WRITE:
{
ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
if (!comp_node->operations.empty()) {
@@ -427,24 +404,19 @@ static void deg_debug_graphviz_node(const DebugContext &ctx,
static bool deg_debug_graphviz_is_cluster(const DepsNode *node)
{
switch (node->type) {
- case DEPSNODE_TYPE_ID_REF:
+ case DEG_NODE_TYPE_ID_REF:
{
const IDDepsNode *id_node = (const IDDepsNode *)node;
return BLI_ghash_size(id_node->components) > 0;
}
- case DEPSNODE_TYPE_SUBGRAPH:
- {
- SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
- return sub_node->graph != NULL;
- }
- case DEPSNODE_TYPE_PARAMETERS:
- case DEPSNODE_TYPE_ANIMATION:
- case DEPSNODE_TYPE_TRANSFORM:
- case DEPSNODE_TYPE_PROXY:
- case DEPSNODE_TYPE_GEOMETRY:
- case DEPSNODE_TYPE_SEQUENCER:
- case DEPSNODE_TYPE_EVAL_POSE:
- case DEPSNODE_TYPE_BONE:
+ case DEG_NODE_TYPE_PARAMETERS:
+ case DEG_NODE_TYPE_ANIMATION:
+ case DEG_NODE_TYPE_TRANSFORM:
+ case DEG_NODE_TYPE_PROXY:
+ case DEG_NODE_TYPE_GEOMETRY:
+ case DEG_NODE_TYPE_SEQUENCER:
+ case DEG_NODE_TYPE_EVAL_POSE:
+ case DEG_NODE_TYPE_BONE:
{
ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
return !comp_node->operations.empty();
@@ -458,14 +430,14 @@ static bool deg_debug_graphviz_is_owner(const DepsNode *node,
const DepsNode *other)
{
switch (node->tclass) {
- case DEPSNODE_CLASS_COMPONENT:
+ case DEG_NODE_CLASS_COMPONENT:
{
ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
if (comp_node->owner == other)
return true;
break;
}
- case DEPSNODE_CLASS_OPERATION:
+ case DEG_NODE_CLASS_OPERATION:
{
OperationDepsNode *op_node = (OperationDepsNode *)node;
if (op_node->owner == other)
@@ -517,15 +489,12 @@ static void deg_debug_graphviz_node_relations(const DebugContext &ctx,
static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx,
const Depsgraph *graph)
{
- if (graph->root_node) {
- deg_debug_graphviz_node(ctx, graph->root_node);
- }
GHASH_FOREACH_BEGIN (DepsNode *, node, graph->id_hash)
{
deg_debug_graphviz_node(ctx, node);
}
GHASH_FOREACH_END();
- TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
+ TimeSourceDepsNode *time_source = graph->find_time_source();
if (time_source != NULL) {
deg_debug_graphviz_node(ctx, time_source);
}
@@ -546,7 +515,7 @@ static void deg_debug_graphviz_graph_relations(const DebugContext &ctx,
}
GHASH_FOREACH_END();
- TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
+ TimeSourceDepsNode *time_source = graph->find_time_source();
if (time_source != NULL) {
deg_debug_graphviz_node_relations(ctx, time_source);
}
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index 2b7c63767ab..dc3174751bd 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -32,8 +32,6 @@
#include "intern/depsgraph.h" /* own include */
-#include <string.h>
-
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
@@ -48,11 +46,11 @@ extern "C" {
#include "DNA_object_types.h"
#include "DNA_sequence_types.h"
-#include "BKE_depsgraph.h"
-
#include "RNA_access.h"
}
+#include <cstring>
+
#include "DEG_depsgraph.h"
#include "intern/nodes/deg_node.h"
@@ -69,26 +67,21 @@ static DEG_EditorUpdateSceneCb deg_editor_update_scene_cb = NULL;
static DEG_EditorUpdateScenePreCb deg_editor_update_scene_pre_cb = NULL;
Depsgraph::Depsgraph()
- : root_node(NULL),
- need_update(false),
- layers(0)
+ : time_source(NULL),
+ need_update(false)
{
BLI_spin_init(&lock);
id_hash = BLI_ghash_ptr_new("Depsgraph id hash");
- subgraphs = BLI_gset_ptr_new("Depsgraph subgraphs");
entry_tags = BLI_gset_ptr_new("Depsgraph entry_tags");
}
Depsgraph::~Depsgraph()
{
- /* Free root node - it won't have been freed yet... */
clear_id_nodes();
- clear_subgraph_nodes();
BLI_ghash_free(id_hash, NULL, NULL);
- BLI_gset_free(subgraphs, NULL);
BLI_gset_free(entry_tags, NULL);
- if (this->root_node != NULL) {
- OBJECT_GUARDED_DELETE(this->root_node, RootDepsNode);
+ if (time_source != NULL) {
+ OBJECT_GUARDED_DELETE(time_source, TimeSourceDepsNode);
}
BLI_spin_end(&lock);
}
@@ -116,7 +109,7 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
const PropertyRNA *prop,
ID **id,
eDepsNode_Type *type,
- string *subdata)
+ const char **subdata)
{
if (!ptr->type)
return false;
@@ -131,7 +124,7 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
bPoseChannel *pchan = (bPoseChannel *)ptr->data;
/* Bone - generally, we just want the bone component... */
- *type = DEPSNODE_TYPE_BONE;
+ *type = DEG_NODE_TYPE_BONE;
*subdata = pchan->name;
return true;
@@ -141,7 +134,7 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
/* armature-level bone, but it ends up going to bone component anyway */
// TODO: the ID in thise case will end up being bArmature, not Object as needed!
- *type = DEPSNODE_TYPE_BONE;
+ *type = DEG_NODE_TYPE_BONE;
*subdata = bone->name;
//*id = ...
@@ -155,7 +148,7 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
if (BLI_findindex(&ob->constraints, con) != -1) {
/* object transform */
// XXX: for now, we can't address the specific constraint or the constraint stack...
- *type = DEPSNODE_TYPE_TRANSFORM;
+ *type = DEG_NODE_TYPE_TRANSFORM;
return true;
}
else if (ob->pose) {
@@ -163,7 +156,7 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
for (pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
if (BLI_findindex(&pchan->constraints, con) != -1) {
/* bone transforms */
- *type = DEPSNODE_TYPE_BONE;
+ *type = DEG_NODE_TYPE_BONE;
*subdata = pchan->name;
return true;
}
@@ -178,7 +171,7 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
* so although we have unique ops for modifiers,
* we can't lump them together
*/
- *type = DEPSNODE_TYPE_BONE;
+ *type = DEG_NODE_TYPE_BONE;
//*subdata = md->name;
return true;
@@ -189,37 +182,44 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
/* Transforms props? */
if (prop) {
const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop);
-
+ /* TODO(sergey): How to optimize this? */
if (strstr(prop_identifier, "location") ||
strstr(prop_identifier, "rotation") ||
- strstr(prop_identifier, "scale"))
+ strstr(prop_identifier, "scale") ||
+ strstr(prop_identifier, "matrix_"))
{
- *type = DEPSNODE_TYPE_TRANSFORM;
+ *type = DEG_NODE_TYPE_TRANSFORM;
+ return true;
+ }
+ else if (strstr(prop_identifier, "data")) {
+ /* We access object.data, most likely a geometry.
+ * Might be a bone tho..
+ */
+ *type = DEG_NODE_TYPE_GEOMETRY;
return true;
}
}
- // ...
}
else if (ptr->type == &RNA_ShapeKey) {
Key *key = (Key *)ptr->id.data;
/* ShapeKeys are currently handled as geometry on the geometry that owns it */
*id = key->from; // XXX
- *type = DEPSNODE_TYPE_PARAMETERS;
+ *type = DEG_NODE_TYPE_PARAMETERS;
return true;
}
else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) {
Sequence *seq = (Sequence *)ptr->data;
/* Sequencer strip */
- *type = DEPSNODE_TYPE_SEQUENCER;
+ *type = DEG_NODE_TYPE_SEQUENCER;
*subdata = seq->name; // xxx?
return true;
}
if (prop) {
/* All unknown data effectively falls under "parameter evaluation" */
- *type = DEPSNODE_TYPE_PARAMETERS;
+ *type = DEG_NODE_TYPE_PARAMETERS;
return true;
}
@@ -232,7 +232,7 @@ DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr,
{
ID *id;
eDepsNode_Type type;
- string name;
+ const char *name;
/* Get querying conditions. */
if (pointer_to_id_node_criteria(ptr, prop, &id)) {
@@ -240,8 +240,9 @@ DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr,
}
else if (pointer_to_component_node_criteria(ptr, prop, &id, &type, &name)) {
IDDepsNode *id_node = find_id_node(id);
- if (id_node)
+ if (id_node != NULL) {
return id_node->find_component(type, name);
+ }
}
return NULL;
@@ -255,72 +256,18 @@ static void id_node_deleter(void *value)
OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
}
-RootDepsNode *Depsgraph::add_root_node()
+TimeSourceDepsNode *Depsgraph::add_time_source()
{
- if (!root_node) {
- DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_ROOT);
- root_node = (RootDepsNode *)factory->create_node(NULL, "", "Root (Scene)");
+ if (time_source == NULL) {
+ DepsNodeFactory *factory = deg_get_node_factory(DEG_NODE_TYPE_TIMESOURCE);
+ time_source = (TimeSourceDepsNode *)factory->create_node(NULL, "", "Time Source");
}
- return root_node;
+ return time_source;
}
-TimeSourceDepsNode *Depsgraph::find_time_source(const ID *id) const
+TimeSourceDepsNode *Depsgraph::find_time_source() const
{
- /* Search for one attached to a particular ID? */
- if (id) {
- /* Check if it was added as a component
- * (as may be done for subgraphs needing timeoffset).
- */
- IDDepsNode *id_node = find_id_node(id);
- if (id_node) {
- // XXX: review this
-// return id_node->find_component(DEPSNODE_TYPE_TIMESOURCE);
- }
- BLI_assert(!"Not implemented yet");
- }
- else {
- /* Use "official" timesource. */
- return root_node->time_source;
- }
- return NULL;
-}
-
-SubgraphDepsNode *Depsgraph::add_subgraph_node(const ID *id)
-{
- DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_SUBGRAPH);
- SubgraphDepsNode *subgraph_node =
- (SubgraphDepsNode *)factory->create_node(id, "", id->name + 2);
-
- /* Add to subnodes list. */
- BLI_gset_insert(subgraphs, subgraph_node);
-
- /* if there's an ID associated, add to ID-nodes lookup too */
- if (id) {
-#if 0
- /* XXX subgraph node is NOT a true IDDepsNode - what is this supposed to do? */
- // TODO: what to do if subgraph's ID has already been added?
- BLI_assert(!graph->find_id_node(id));
- graph->id_hash[id] = this;
-#endif
- }
-
- return subgraph_node;
-}
-
-void Depsgraph::remove_subgraph_node(SubgraphDepsNode *subgraph_node)
-{
- BLI_gset_remove(subgraphs, subgraph_node, NULL);
- OBJECT_GUARDED_DELETE(subgraph_node, SubgraphDepsNode);
-}
-
-void Depsgraph::clear_subgraph_nodes()
-{
- GSET_FOREACH_BEGIN(SubgraphDepsNode *, subgraph_node, subgraphs)
- {
- OBJECT_GUARDED_DELETE(subgraph_node, SubgraphDepsNode);
- }
- GSET_FOREACH_END();
- BLI_gset_clear(subgraphs, NULL);
+ return time_source;
}
IDDepsNode *Depsgraph::find_id_node(const ID *id) const
@@ -328,29 +275,23 @@ 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 string &name)
+IDDepsNode *Depsgraph::add_id_node(ID *id, const char *name)
{
IDDepsNode *id_node = find_id_node(id);
if (!id_node) {
- DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_ID_REF);
+ DepsNodeFactory *factory = deg_get_node_factory(DEG_NODE_TYPE_ID_REF);
id_node = (IDDepsNode *)factory->create_node(id, "", name);
id->tag |= LIB_TAG_DOIT;
- /* register */
+ /* 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);
}
return id_node;
}
-void Depsgraph::remove_id_node(const ID *id)
-{
- IDDepsNode *id_node = find_id_node(id);
- if (id_node) {
- /* unregister */
- BLI_ghash_remove(id_hash, id, NULL, NULL);
- OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
- }
-}
-
void Depsgraph::clear_id_nodes()
{
BLI_ghash_clear(id_hash, NULL, id_node_deleter);
@@ -359,19 +300,17 @@ void Depsgraph::clear_id_nodes()
/* Add new relationship between two nodes. */
DepsRelation *Depsgraph::add_new_relation(OperationDepsNode *from,
OperationDepsNode *to,
- eDepsRelation_Type type,
const char *description)
{
/* Create new relation, and add it to the graph. */
- DepsRelation *rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, type, description);
+ DepsRelation *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 == DEPSNODE_TYPE_GEOMETRY) {
+ if (comp_node->type == DEG_NODE_TYPE_GEOMETRY) {
IDDepsNode *id_to = to->owner->owner;
IDDepsNode *id_from = from->owner->owner;
- Object *object_to = (Object *)id_to->id;
- if (id_to != id_from && (object_to->recalc & OB_RECALC_ALL)) {
+ if (id_to != id_from && (id_to->id_orig->tag & LIB_TAG_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;
@@ -384,11 +323,10 @@ DepsRelation *Depsgraph::add_new_relation(OperationDepsNode *from,
/* Add new relation between two nodes */
DepsRelation *Depsgraph::add_new_relation(DepsNode *from, DepsNode *to,
- eDepsRelation_Type type,
const char *description)
{
/* Create new relation, and add it to the graph. */
- DepsRelation *rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, type, description);
+ DepsRelation *rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, description);
return rel;
}
@@ -397,12 +335,10 @@ DepsRelation *Depsgraph::add_new_relation(DepsNode *from, DepsNode *to,
DepsRelation::DepsRelation(DepsNode *from,
DepsNode *to,
- eDepsRelation_Type type,
const char *description)
: from(from),
to(to),
name(description),
- type(type),
flag(0)
{
#ifndef NDEBUG
@@ -465,12 +401,20 @@ void Depsgraph::add_entry_tag(OperationDepsNode *node)
void Depsgraph::clear_all_nodes()
{
clear_id_nodes();
- clear_subgraph_nodes();
BLI_ghash_clear(id_hash, NULL, NULL);
- if (this->root_node) {
- OBJECT_GUARDED_DELETE(this->root_node, RootDepsNode);
- root_node = NULL;
+ if (time_source != NULL) {
+ OBJECT_GUARDED_DELETE(time_source, TimeSourceDepsNode);
+ time_source = NULL;
+ }
+}
+
+ID *Depsgraph::get_cow_id(const ID *id_orig) const
+{
+ IDDepsNode *id_node = find_id_node(id_orig);
+ if (id_node == NULL) {
+ return (ID *)id_orig;
}
+ return id_node->id_cow;
}
void deg_editors_id_update(Main *bmain, ID *id)
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index 08b264f8497..50c55bc0cf9 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -42,17 +42,17 @@
struct ID;
struct GHash;
+struct Main;
struct GSet;
struct PointerRNA;
struct PropertyRNA;
+struct Scene;
namespace DEG {
struct DepsNode;
-struct RootDepsNode;
struct TimeSourceDepsNode;
struct IDDepsNode;
-struct SubgraphDepsNode;
struct ComponentDepsNode;
struct OperationDepsNode;
@@ -79,12 +79,10 @@ struct DepsRelation {
/* relationship attributes */
const char *name; /* label for debugging */
- eDepsRelation_Type type; /* type */
int flag; /* (eDepsRelation_Flag) */
DepsRelation(DepsNode *from,
DepsNode *to,
- eDepsRelation_Type type,
const char *description);
~DepsRelation();
@@ -101,22 +99,6 @@ struct Depsgraph {
~Depsgraph();
/**
- * Find node which matches the specified description.
- *
- * \param id: ID block that is associated with this
- * \param subdata: identifier used for sub-ID data (e.g. bone)
- * \param type: type of node we're dealing with
- * \param name: custom identifier assigned to node
- *
- * \return A node matching the required characteristics if it exists
- * or NULL if no such node exists in the graph.
- */
- DepsNode *find_node(const ID *id,
- eDepsNode_Type type,
- const string &subdata,
- const string &name);
-
- /**
* Convenience wrapper to find node given just pointer + property.
*
* \param ptr: pointer to the data that node will represent
@@ -127,28 +109,20 @@ struct Depsgraph {
*/
DepsNode *find_node_from_pointer(const PointerRNA *ptr, const PropertyRNA *prop) const;
- RootDepsNode *add_root_node();
-
- TimeSourceDepsNode *find_time_source(const ID *id = NULL) const;
-
- SubgraphDepsNode *add_subgraph_node(const ID *id);
- void remove_subgraph_node(SubgraphDepsNode *subgraph_node);
- void clear_subgraph_nodes();
+ TimeSourceDepsNode *add_time_source();
+ TimeSourceDepsNode *find_time_source() const;
IDDepsNode *find_id_node(const ID *id) const;
- IDDepsNode *add_id_node(ID *id, const string &name = "");
- void remove_id_node(const ID *id);
+ IDDepsNode *add_id_node(ID *id, const char *name = "");
void clear_id_nodes();
/* Add new relationship between two nodes. */
DepsRelation *add_new_relation(OperationDepsNode *from,
OperationDepsNode *to,
- eDepsRelation_Type type,
const char *description);
DepsRelation *add_new_relation(DepsNode *from,
DepsNode *to,
- eDepsRelation_Type type,
const char *description);
/* Tag a specific node as needing updates. */
@@ -157,17 +131,19 @@ 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 blocks
* (for quick lookups). */
GHash *id_hash;
- /* "root" node - the one where all evaluation enters from. */
- RootDepsNode *root_node;
-
- /* Subgraphs referenced in tree. */
- GSet *subgraphs;
+ /* Top-level time source node. */
+ TimeSourceDepsNode *time_source;
/* Indicates whether relations needs to be updated. */
bool need_update;
@@ -188,12 +164,9 @@ struct Depsgraph {
*/
SpinLock lock;
- /* Layers Visibility .................. */
-
- /* Visible layers bitfield, used for skipping invisible objects updates. */
- unsigned int layers;
-
// XXX: additional stuff like eval contexts, mempools for allocating nodes from, etc.
+ Main *bmain; /* XXX: For until depsgraph has proper ownership. */
+ Scene *scene; /* XXX: We really shouldn't do that, but it's required for shader preview. */
};
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index ae830da1252..41934e3e4e6 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -32,22 +32,32 @@
#include "MEM_guardedalloc.h"
+// #define DEBUG_TIME
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+
+#ifdef DEBUG_TIME
+# include "PIL_time.h"
+# include "PIL_time_utildefines.h"
+#endif
+
extern "C" {
#include "DNA_cachefile_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-
-#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
+#include "DNA_object_force.h"
#include "BKE_main.h"
+#include "BKE_collision.h"
+#include "BKE_effect.h"
+#include "BKE_modifier.h"
+} /* extern "C" */
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_debug.h"
#include "DEG_depsgraph_build.h"
-} /* extern "C" */
-
#include "builder/deg_builder.h"
#include "builder/deg_builder_cycle.h"
#include "builder/deg_builder_nodes.h"
@@ -70,29 +80,29 @@ static DEG::eDepsNode_Type deg_build_scene_component_type(
eDepsSceneComponentType component)
{
switch (component) {
- case DEG_SCENE_COMP_PARAMETERS: return DEG::DEPSNODE_TYPE_PARAMETERS;
- case DEG_SCENE_COMP_ANIMATION: return DEG::DEPSNODE_TYPE_ANIMATION;
- case DEG_SCENE_COMP_SEQUENCER: return DEG::DEPSNODE_TYPE_SEQUENCER;
+ case DEG_SCENE_COMP_PARAMETERS: return DEG::DEG_NODE_TYPE_PARAMETERS;
+ case DEG_SCENE_COMP_ANIMATION: return DEG::DEG_NODE_TYPE_ANIMATION;
+ case DEG_SCENE_COMP_SEQUENCER: return DEG::DEG_NODE_TYPE_SEQUENCER;
}
- return DEG::DEPSNODE_TYPE_UNDEFINED;
+ return DEG::DEG_NODE_TYPE_UNDEFINED;
}
static DEG::eDepsNode_Type deg_build_object_component_type(
eDepsObjectComponentType component)
{
switch (component) {
- case DEG_OB_COMP_PARAMETERS: return DEG::DEPSNODE_TYPE_PARAMETERS;
- case DEG_OB_COMP_PROXY: return DEG::DEPSNODE_TYPE_PROXY;
- case DEG_OB_COMP_ANIMATION: return DEG::DEPSNODE_TYPE_ANIMATION;
- case DEG_OB_COMP_TRANSFORM: return DEG::DEPSNODE_TYPE_TRANSFORM;
- case DEG_OB_COMP_GEOMETRY: return DEG::DEPSNODE_TYPE_GEOMETRY;
- case DEG_OB_COMP_EVAL_POSE: return DEG::DEPSNODE_TYPE_EVAL_POSE;
- case DEG_OB_COMP_BONE: return DEG::DEPSNODE_TYPE_BONE;
- case DEG_OB_COMP_EVAL_PARTICLES: return DEG::DEPSNODE_TYPE_EVAL_PARTICLES;
- case DEG_OB_COMP_SHADING: return DEG::DEPSNODE_TYPE_SHADING;
- case DEG_OB_COMP_CACHE: return DEG::DEPSNODE_TYPE_CACHE;
+ case DEG_OB_COMP_PARAMETERS: return DEG::DEG_NODE_TYPE_PARAMETERS;
+ case DEG_OB_COMP_PROXY: return DEG::DEG_NODE_TYPE_PROXY;
+ case DEG_OB_COMP_ANIMATION: return DEG::DEG_NODE_TYPE_ANIMATION;
+ case DEG_OB_COMP_TRANSFORM: return DEG::DEG_NODE_TYPE_TRANSFORM;
+ 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::DEPSNODE_TYPE_UNDEFINED;
+ return DEG::DEG_NODE_TYPE_UNDEFINED;
}
static DEG::DepsNodeHandle *get_handle(DepsNodeHandle *handle)
@@ -110,7 +120,6 @@ void DEG_add_scene_relation(DepsNodeHandle *handle,
DEG::DepsNodeHandle *deg_handle = get_handle(handle);
deg_handle->builder->add_node_handle_relation(comp_key,
deg_handle,
- DEG::DEPSREL_TYPE_GEOMETRY_EVAL,
description);
}
@@ -124,7 +133,6 @@ void DEG_add_object_relation(DepsNodeHandle *handle,
DEG::DepsNodeHandle *deg_handle = get_handle(handle);
deg_handle->builder->add_node_handle_relation(comp_key,
deg_handle,
- DEG::DEPSREL_TYPE_GEOMETRY_EVAL,
description);
}
@@ -138,7 +146,6 @@ void DEG_add_object_cache_relation(DepsNodeHandle *handle,
DEG::DepsNodeHandle *deg_handle = get_handle(handle);
deg_handle->builder->add_node_handle_relation(comp_key,
deg_handle,
- DEG::DEPSREL_TYPE_CACHE,
description);
}
@@ -156,10 +163,16 @@ void DEG_add_bone_relation(DepsNodeHandle *handle,
*/
deg_handle->builder->add_node_handle_relation(comp_key,
deg_handle,
- DEG::DEPSREL_TYPE_GEOMETRY_EVAL,
description);
}
+struct Depsgraph *DEG_get_graph_from_handle(struct DepsNodeHandle *handle)
+{
+ DEG::DepsNodeHandle *deg_handle = get_handle(handle);
+ DEG::DepsgraphRelationBuilder *relation_builder = deg_handle->builder;
+ return reinterpret_cast<Depsgraph *>(relation_builder->getGraph());
+}
+
void DEG_add_special_eval_flag(Depsgraph *graph, ID *id, short flag)
{
DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
@@ -186,33 +199,26 @@ void DEG_add_special_eval_flag(Depsgraph *graph, ID *id, short flag)
*/
void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene)
{
+#ifdef DEBUG_TIME
+ TIMEIT_START(DEG_graph_build_from_scene);
+#endif
+
DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
/* 1) Generate all the nodes in the graph first */
DEG::DepsgraphNodeBuilder node_builder(bmain, deg_graph);
- /* create root node for scene first
- * - this way it should be the first in the graph,
- * reflecting its role as the entrypoint
- */
- node_builder.add_root_node();
+ node_builder.begin_build(bmain);
node_builder.build_scene(bmain, scene);
/* 2) Hook up relationships between operations - to determine evaluation
* order.
*/
DEG::DepsgraphRelationBuilder relation_builder(deg_graph);
- /* Hook scene up to the root node as entrypoint to graph. */
- /* XXX what does this relation actually mean?
- * it doesnt add any operations anyway and is not clear what part of the
- * scene is to be connected.
- */
-#if 0
- relation_builder.add_relation(RootKey(),
- IDKey(scene),
- DEPSREL_TYPE_ROOT_TO_ACTIVE,
- "Root to Active Scene");
-#endif
+ relation_builder.begin_build(bmain);
relation_builder.build_scene(bmain, scene);
+#ifdef WITH_COPY_ON_WRITE
+ relation_builder.build_copy_on_write_relations();
+#endif
/* Detect and solve cycles. */
DEG::deg_graph_detect_cycles(deg_graph);
@@ -235,6 +241,10 @@ void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene)
abort();
}
#endif
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(DEG_graph_build_from_scene);
+#endif
}
/* Tag graph relations for update. */
@@ -251,8 +261,8 @@ void DEG_relations_tag_update(Main *bmain)
scene != NULL;
scene = (Scene *)scene->id.next)
{
- if (scene->depsgraph != NULL) {
- DEG_graph_tag_relations_update(scene->depsgraph);
+ if (scene->depsgraph_legacy != NULL) {
+ DEG_graph_tag_relations_update(scene->depsgraph_legacy);
}
}
}
@@ -262,14 +272,14 @@ void DEG_relations_tag_update(Main *bmain)
*/
void DEG_scene_relations_update(Main *bmain, Scene *scene)
{
- if (scene->depsgraph == NULL) {
+ if (scene->depsgraph_legacy == NULL) {
/* Rebuild graph from scratch and exit. */
- scene->depsgraph = DEG_graph_new();
- DEG_graph_build_from_scene(scene->depsgraph, bmain, scene);
+ scene->depsgraph_legacy = DEG_graph_new();
+ DEG_graph_build_from_scene(scene->depsgraph_legacy, bmain, scene);
return;
}
- DEG::Depsgraph *graph = reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph);
+ DEG::Depsgraph *graph = reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph_legacy);
if (!graph->need_update) {
/* Graph is up to date, nothing to do. */
return;
@@ -291,16 +301,93 @@ void DEG_scene_relations_update(Main *bmain, Scene *scene)
/* 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);
+ if (scene->depsgraph_legacy != NULL) {
+ DEG_graph_tag_relations_update(scene->depsgraph_legacy);
}
DEG_scene_relations_update(bmain, scene);
}
void DEG_scene_graph_free(Scene *scene)
{
- if (scene->depsgraph) {
- DEG_graph_free(scene->depsgraph);
- scene->depsgraph = NULL;
+ if (scene->depsgraph_legacy) {
+ DEG_graph_free(scene->depsgraph_legacy);
+ scene->depsgraph_legacy = NULL;
}
}
+
+void DEG_add_collision_relations(DepsNodeHandle *handle,
+ Scene *scene,
+ Object *ob,
+ Group *group,
+ unsigned int modifier_type,
+ DEG_CollobjFilterFunction fn,
+ bool dupli,
+ const char *name)
+{
+ unsigned int numcollobj;
+ Object **collobjs = get_collisionobjects_ext(scene, ob, group, &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 *ob,
+ EffectorWeights *effector_weights,
+ bool add_absorption,
+ int skip_forcefield,
+ const char *name)
+{
+ ListBase *effectors = pdInitEffectors(scene, ob, NULL, effector_weights, false);
+
+ if (effectors) {
+ for (EffectorCache *eff = (EffectorCache*)effectors->first; eff; eff = eff->next) {
+ if (eff->ob != ob && 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,
+ ob,
+ NULL,
+ eModifierType_Collision,
+ NULL,
+ true,
+ "Force Absorption");
+ }
+ }
+ }
+ }
+
+ pdEndEffectors(&effectors);
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc
index d3b48930779..453bd2aa75f 100644
--- a/source/blender/depsgraph/intern/depsgraph_debug.cc
+++ b/source/blender/depsgraph/intern/depsgraph_debug.cc
@@ -35,11 +35,11 @@
extern "C" {
#include "DNA_scene_types.h"
+} /* extern "C" */
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_debug.h"
#include "DEG_depsgraph_build.h"
-} /* extern "C" */
#include "intern/eval/deg_eval_debug.h"
#include "intern/depsgraph_intern.h"
@@ -91,7 +91,7 @@ bool DEG_debug_scene_relations_validate(Main *bmain,
Depsgraph *depsgraph = DEG_graph_new();
bool valid = true;
DEG_graph_build_from_scene(depsgraph, bmain, scene);
- if (!DEG_debug_compare(depsgraph, scene->depsgraph)) {
+ if (!DEG_debug_compare(depsgraph, scene->depsgraph_legacy)) {
fprintf(stderr, "ERROR! Depsgraph wasn't tagged for update when it should have!\n");
BLI_assert(!"This should not happen!");
valid = false;
@@ -165,7 +165,7 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
return false;
}
foreach (DEG::DepsRelation *rel, node->outlinks) {
- if (rel->to->type == DEG::DEPSNODE_TYPE_OPERATION) {
+ if (rel->to->type == DEG::DEG_NODE_TYPE_OPERATION) {
DEG::OperationDepsNode *to = (DEG::OperationDepsNode *)rel->to;
BLI_assert(to->num_links_pending < to->inlinks.size());
++to->num_links_pending;
@@ -177,7 +177,7 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
foreach (DEG::OperationDepsNode *node, deg_graph->operations) {
int num_links_pending = 0;
foreach (DEG::DepsRelation *rel, node->inlinks) {
- if (rel->from->type == DEG::DEPSNODE_TYPE_OPERATION) {
+ if (rel->from->type == DEG::DEG_NODE_TYPE_OPERATION) {
++num_links_pending;
}
}
@@ -232,7 +232,7 @@ void DEG_stats_simple(const Depsgraph *graph, size_t *r_outer,
}
GHASH_FOREACH_END();
- DEG::TimeSourceDepsNode *time_source = deg_graph->find_time_source(NULL);
+ DEG::TimeSourceDepsNode *time_source = deg_graph->find_time_source();
if (time_source != NULL) {
tot_rels += time_source->inlinks.size();
}
diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc
index a0435c318f0..73a0428c264 100644
--- a/source/blender/depsgraph/intern/depsgraph_eval.cc
+++ b/source/blender/depsgraph/intern/depsgraph_eval.cc
@@ -32,15 +32,14 @@
#include "MEM_guardedalloc.h"
-extern "C" {
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
-#include "BKE_depsgraph.h"
+extern "C" {
#include "BKE_scene.h"
+} /* extern "C" */
#include "DEG_depsgraph.h"
-} /* extern "C" */
#include "intern/eval/deg_eval.h"
#include "intern/eval/deg_eval_flush.h"
@@ -50,43 +49,9 @@ extern "C" {
#include "intern/depsgraph.h"
-#ifdef WITH_LEGACY_DEPSGRAPH
-static bool use_legacy_depsgraph = true;
-#endif
-
/* Unfinished and unused, and takes quite some pre-processing time. */
#undef USE_EVAL_PRIORITY
-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 */
@@ -96,7 +61,7 @@ EvaluationContext *DEG_evaluation_context_new(int mode)
EvaluationContext *eval_ctx =
(EvaluationContext *)MEM_callocN(sizeof(EvaluationContext),
"EvaluationContext");
- eval_ctx->mode = mode;
+ DEG_evaluation_context_init(eval_ctx, mode);
return eval_ctx;
}
@@ -125,15 +90,14 @@ void DEG_evaluate_on_refresh(EvaluationContext *eval_ctx,
/* Update time on primary timesource. */
DEG::TimeSourceDepsNode *tsrc = deg_graph->find_time_source();
tsrc->cfra = BKE_scene_frame_get(scene);
- DEG::deg_evaluate_on_refresh(eval_ctx, deg_graph, deg_graph->layers);
+ DEG::deg_evaluate_on_refresh(eval_ctx, deg_graph);
}
/* Frame-change happened for root scene that graph belongs to. */
void DEG_evaluate_on_framechange(EvaluationContext *eval_ctx,
Main *bmain,
Depsgraph *graph,
- float ctime,
- const unsigned int layers)
+ float ctime)
{
DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
/* Update time on primary timesource. */
@@ -142,7 +106,7 @@ void DEG_evaluate_on_framechange(EvaluationContext *eval_ctx,
tsrc->tag_update(deg_graph);
DEG::deg_graph_flush_updates(bmain, deg_graph);
/* Perform recalculation updates. */
- DEG::deg_evaluate_on_refresh(eval_ctx, deg_graph, layers);
+ DEG::deg_evaluate_on_refresh(eval_ctx, 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 e5d3d1f5861..2d8e7dc841c 100644
--- a/source/blender/depsgraph/intern/depsgraph_intern.h
+++ b/source/blender/depsgraph/intern/depsgraph_intern.h
@@ -63,8 +63,8 @@ struct DepsNodeFactory {
virtual const char *tname() const = 0;
virtual DepsNode *create_node(const ID *id,
- const string &subdata,
- const string &name) const = 0;
+ const char *subdata,
+ const char *name) const = 0;
};
template <class NodeType>
@@ -73,7 +73,7 @@ struct DepsNodeFactoryImpl : public DepsNodeFactory {
eDepsNode_Class tclass() const { return NodeType::typeinfo.tclass; }
const char *tname() const { return NodeType::typeinfo.tname; }
- DepsNode *create_node(const ID *id, const string &subdata, const string &name) const
+ DepsNode *create_node(const ID *id, const char *subdata, const char *name) const
{
DepsNode *node = OBJECT_GUARDED_NEW(NodeType);
@@ -81,12 +81,14 @@ struct DepsNodeFactoryImpl : public DepsNodeFactory {
node->type = type();
node->tclass = tclass();
- if (!name.empty())
+ if (name[0] != '\0') {
/* set name if provided ... */
node->name = name;
- else
+ }
+ else {
/* ... otherwise use default type name */
node->name = tname();
+ }
node->init(id, subdata);
diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc
index 7f2f6a65f5e..c0e50643102 100644
--- a/source/blender/depsgraph/intern/depsgraph_query.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query.cc
@@ -33,13 +33,25 @@
#include "MEM_guardedalloc.h"
extern "C" {
+#include "BLI_math.h"
+#include "BKE_anim.h"
#include "BKE_idcode.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
+} /* extern "C" */
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
-} /* extern "C" */
#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
+
+#ifndef NDEBUG
+# include "intern/eval/deg_eval_copy_on_write.h"
+#endif
bool DEG_id_type_tagged(Main *bmain, short idtype)
{
@@ -68,3 +80,186 @@ short DEG_get_eval_flags_for_id(Depsgraph *graph, ID *id)
return id_node->eval_flags;
}
+
+Scene *DEG_get_evaluated_scene(Depsgraph *graph)
+{
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ Scene *scene_orig = deg_graph->scene;
+ return reinterpret_cast<Scene *>(deg_graph->get_cow_id(&scene_orig->id));
+}
+
+SceneLayer *DEG_get_evaluated_scene_layer(Depsgraph *graph)
+{
+ Scene *scene = DEG_get_evaluated_scene(graph);
+ if (scene != NULL) {
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ return BKE_scene_layer_context_active_ex_PLACEHOLDER(deg_graph->bmain, scene);
+ }
+ return NULL;
+}
+
+Object *DEG_get_evaluated_object(Depsgraph *depsgraph, Object *object)
+{
+ return (Object *)DEG_get_evaluated_id(depsgraph, &object->id);
+}
+
+ID *DEG_get_evaluated_id(struct Depsgraph *depsgraph, ID *id)
+{
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
+ return deg_graph->get_cow_id(id);
+}
+
+/* ************************ DAG ITERATORS ********************* */
+
+#define BASE_FLUSH_FLAGS (BASE_FROM_SET | BASE_FROMDUPLI)
+
+void DEG_objects_iterator_begin(BLI_Iterator *iter, DEGObjectsIteratorData *data)
+{
+ Depsgraph *graph = data->graph;
+ SceneLayer *scene_layer = DEG_get_evaluated_scene_layer(graph);
+
+ iter->data = data;
+ iter->valid = true;
+
+ data->scene = DEG_get_evaluated_scene(graph);
+ DEG_evaluation_context_init(&data->eval_ctx, DAG_EVAL_RENDER);
+
+ /* TODO(sergey): It's really confusing to store pointer to a local data. */
+ Base base = {(Base *)scene_layer->object_bases.first, NULL};
+ data->base = &base;
+
+ data->base_flag = ~(BASE_FLUSH_FLAGS);
+
+ data->dupli_parent = NULL;
+ data->dupli_list = NULL;
+ data->dupli_object_next = NULL;
+ data->dupli_object_current = NULL;
+
+ DEG_objects_iterator_next(iter);
+}
+
+/**
+ * Temporary function to flush depsgraph until we get copy on write (CoW)
+ */
+static void deg_flush_base_flags_and_settings(Object *ob, Base *base, const int flag)
+{
+ ob->base_flag = (base->flag | BASE_FLUSH_FLAGS) & flag;
+ ob->base_collection_properties = base->collection_properties;
+}
+
+static bool deg_objects_dupli_iterator_next(BLI_Iterator *iter)
+{
+ DEGObjectsIteratorData *data = (DEGObjectsIteratorData *)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;
+ }
+
+ data->dupli_object_current = dob;
+
+ /* Temporary object to evaluate. */
+ data->temp_dupli_object = *dob->ob;
+ data->temp_dupli_object.select_color = data->dupli_parent->select_color;
+ copy_m4_m4(data->temp_dupli_object.obmat, dob->mat);
+
+ deg_flush_base_flags_and_settings(&data->temp_dupli_object,
+ data->base,
+ data->base_flag | BASE_FROMDUPLI);
+ 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_objects_iterator_next(BLI_Iterator *iter)
+{
+ DEGObjectsIteratorData *data = (DEGObjectsIteratorData *)iter->data;
+ Base *base;
+
+ if (data->dupli_list) {
+ if (deg_objects_dupli_iterator_next(iter)) {
+ return;
+ }
+ else {
+ free_object_duplilist(data->dupli_list);
+ data->dupli_parent = NULL;
+ data->dupli_list = NULL;
+ data->dupli_object_next = NULL;
+ data->dupli_object_current = NULL;
+ }
+ }
+
+ base = data->base->next;
+ while (base != NULL) {
+ if ((base->flag & BASE_VISIBLED) != 0) {
+ // Object *ob = DEG_get_evaluated_object(data->graph, base->object);
+ Object *ob = base->object;
+ iter->current = ob;
+ data->base = base;
+
+ BLI_assert(DEG::deg_validate_copy_on_write_datablock(&ob->id));
+
+ /* Make sure we have the base collection settings is already populated.
+ * This will fail when BKE_layer_eval_layer_collection_pre hasn't run yet
+ * Which usually means a missing call to DAG_id_tag_update(). */
+ BLI_assert(!BLI_listbase_is_empty(&base->collection_properties->data.group));
+
+ /* Flushing depsgraph data. */
+ deg_flush_base_flags_and_settings(ob,
+ base,
+ data->base_flag);
+
+ if ((data->flag & DEG_OBJECT_ITER_FLAG_DUPLI) && (ob->transflag & OB_DUPLI)) {
+ data->dupli_parent = ob;
+ data->dupli_list = object_duplilist(&data->eval_ctx, data->scene, ob);
+ data->dupli_object_next = (DupliObject *)data->dupli_list->first;
+ }
+ return;
+ }
+ base = base->next;
+ }
+
+ /* Look for an object in the next set. */
+ if ((data->flag & DEG_OBJECT_ITER_FLAG_SET) && data->scene->set) {
+ SceneLayer *scene_layer;
+ data->scene = data->scene->set;
+ data->base_flag = ~(BASE_SELECTED | BASE_SELECTABLED);
+
+ /* For the sets we use the layer used for rendering. */
+ scene_layer = BKE_scene_layer_from_scene_get(data->scene);
+
+ /* TODO(sergey): It's really confusing to store pointer to a local data. */
+ Base base = {(Base *)scene_layer->object_bases.first, NULL};
+ data->base = &base;
+ DEG_objects_iterator_next(iter);
+ return;
+ }
+
+ iter->current = NULL;
+ iter->valid = false;
+}
+
+void DEG_objects_iterator_end(BLI_Iterator *iter)
+{
+#ifndef NDEBUG
+ DEGObjectsIteratorData *data = (DEGObjectsIteratorData *)iter->data;
+ /* Force crash in case the iterator data is referenced and accessed down the line. (T51718) */
+ memset(&data->temp_dupli_object, 0xff, sizeof(data->temp_dupli_object));
+#else
+ (void) iter;
+#endif
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index b7b62bd59f9..abf4cba2617 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -31,33 +31,35 @@
*/
#include <stdio.h>
-#include <cstring>
+#include <cstring> /* required for memset */
#include <queue>
-extern "C" {
#include "BLI_utildefines.h"
+#include "BLI_task.h"
+#include "BLI_listbase.h"
+extern "C" {
#include "DNA_object_types.h"
#include "DNA_particle_types.h"
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
-#include "BLI_task.h"
#include "BKE_idcode.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_workspace.h"
#define new new_
#include "BKE_screen.h"
#undef new
+} /* extern "C" */
#include "DEG_depsgraph.h"
-} /* extern "C" */
+#include "intern/builder/deg_builder.h"
#include "intern/eval/deg_eval_flush.h"
-
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
#include "intern/nodes/deg_node_operation.h"
@@ -125,7 +127,7 @@ void lib_id_recalc_tag_flag(Main *bmain, ID *id, int flag)
}
#ifdef DEPSGRAPH_USE_LEGACY_TAGGING
-void depsgraph_legacy_handle_update_tag(Main *bmain, ID *id, short flag)
+void depsgraph_legacy_handle_update_tag(Main *bmain, ID *id, int flag)
{
if (flag) {
Object *object;
@@ -151,6 +153,20 @@ void depsgraph_legacy_handle_update_tag(Main *bmain, ID *id, short flag)
}
#endif
+#ifdef WITH_COPY_ON_WRITE
+void id_tag_copy_on_write_update(Main *bmain, Depsgraph *graph, ID *id)
+{
+ lib_id_recalc_tag(bmain, id);
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ DEG::IDDepsNode *id_node = deg_graph->find_id_node(id);
+ DEG::ComponentDepsNode *cow_comp =
+ id_node->find_component(DEG::DEG_NODE_TYPE_COPY_ON_WRITE);
+ DEG::OperationDepsNode *cow_node = cow_comp->get_entry_operation();
+ cow_node->tag_update(deg_graph);
+ cow_node->flag |= DEG::DEPSOP_FLAG_SKIP_FLUSH;
+}
+#endif
+
} /* namespace */
/* Tag all nodes in ID-block for update.
@@ -197,12 +213,12 @@ void DEG_graph_property_tag_update(Depsgraph *graph,
}
/* Tag given ID for an update in all the dependency graphs. */
-void DEG_id_tag_update(ID *id, short flag)
+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, short 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. */
@@ -214,8 +230,8 @@ void DEG_id_tag_update_ex(Main *bmain, ID *id, short flag)
scene != NULL;
scene = (Scene *)scene->id.next)
{
- if (scene->depsgraph) {
- Depsgraph *graph = scene->depsgraph;
+ if (scene->depsgraph_legacy) {
+ Depsgraph *graph = scene->depsgraph_legacy;
if (flag == 0) {
/* TODO(sergey): Currently blender is still tagging IDs
* for recalc just using flag=0. This isn't totally correct
@@ -235,6 +251,14 @@ void DEG_id_tag_update_ex(Main *bmain, ID *id, short flag)
if (flag & (OB_RECALC_OB | OB_RECALC_DATA)) {
DEG_graph_id_tag_update(bmain, graph, id);
}
+ else if (flag & OB_RECALC_TIME) {
+ DEG_graph_id_tag_update(bmain, graph, id);
+ }
+ else if (flag & DEG_TAG_COPY_ON_WRITE) {
+#ifdef WITH_COPY_ON_WRITE
+ id_tag_copy_on_write_update(bmain, graph, id);
+#endif
+ }
}
}
@@ -267,82 +291,26 @@ void DEG_id_type_tag(Main *bmain, short idtype)
/* Recursively push updates out to all nodes dependent on this,
* until all affected are tagged and/or scheduled up for eval
*/
-void DEG_ids_flush_tagged(Main *bmain)
+void DEG_ids_flush_tagged(Main *bmain, Scene *scene)
{
- for (Scene *scene = (Scene *)bmain->scene.first;
- scene != NULL;
- scene = (Scene *)scene->id.next)
- {
- /* TODO(sergey): Only visible scenes? */
- if (scene->depsgraph != NULL) {
- DEG::deg_graph_flush_updates(
- bmain,
- reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph));
- }
+ /* TODO(sergey): Only visible scenes? */
+ if (scene->depsgraph_legacy != NULL) {
+ DEG::deg_graph_flush_updates(
+ bmain,
+ reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph_legacy));
}
}
/* Update dependency graph when visible scenes/layers changes. */
void DEG_graph_on_visible_update(Main *bmain, Scene *scene)
{
- 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;
- }
- }
- }
- 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.
- *
- * This is mainly needed on file load only, after that updates of invisible objects
- * will be stored in the pending list.
- */
- GHASH_FOREACH_BEGIN(DEG::IDDepsNode *, id_node, graph->id_hash)
- {
- ID *id = id_node->id;
- if ((id->tag & LIB_TAG_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->tag & LIB_TAG_ID_RECALC_ALL) == 0 &&
- (object->recalc & OB_RECALC_ALL) != 0)
- {
- id_node->tag_update(graph);
- DEG::ComponentDepsNode *anim_comp =
- id_node->find_component(DEG::DEPSNODE_TYPE_ANIMATION);
- if (anim_comp != NULL && object->recalc & OB_RECALC_TIME) {
- anim_comp->tag_update(graph);
- }
- }
- }
- }
- GHASH_FOREACH_END();
+ (void) bmain;
+ DEG::Depsgraph *graph = reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph_legacy);
+ GHASH_FOREACH_BEGIN(DEG::IDDepsNode *, id_node, graph->id_hash)
+ {
+ id_node->tag_update(graph);
}
- scene->lay_updated |= graph->layers;
+ GHASH_FOREACH_END();
}
void DEG_on_visible_update(Main *bmain, const bool UNUSED(do_time))
@@ -351,7 +319,7 @@ void DEG_on_visible_update(Main *bmain, const bool UNUSED(do_time))
scene != NULL;
scene = (Scene *)scene->id.next)
{
- if (scene->depsgraph != NULL) {
+ if (scene->depsgraph_legacy != NULL) {
DEG_graph_on_visible_update(bmain, scene);
}
}
diff --git a/source/blender/depsgraph/intern/depsgraph_type_defines.cc b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
index 4ce91516c84..eab1913727d 100644
--- a/source/blender/depsgraph/intern/depsgraph_type_defines.cc
+++ b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
@@ -32,12 +32,11 @@
#include <cstdlib> // for BLI_assert()
-extern "C" {
+
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "DEG_depsgraph.h"
-} /* extern "C" */
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
@@ -67,7 +66,9 @@ static GHash *_depsnode_typeinfo_registry = NULL;
void deg_register_node_typeinfo(DepsNodeFactory *factory)
{
BLI_assert(factory != NULL);
- BLI_ghash_insert(_depsnode_typeinfo_registry, SET_INT_IN_POINTER(factory->type()), factory);
+ BLI_ghash_insert(_depsnode_typeinfo_registry,
+ SET_INT_IN_POINTER(factory->type()),
+ factory);
}
/* Getters ------------------------------------------------- */
@@ -76,7 +77,8 @@ void deg_register_node_typeinfo(DepsNodeFactory *factory)
DepsNodeFactory *deg_get_node_factory(const eDepsNode_Type type)
{
/* look up type - at worst, it doesn't exist in table yet, and we fail */
- return (DepsNodeFactory *)BLI_ghash_lookup(_depsnode_typeinfo_registry, SET_INT_IN_POINTER(type));
+ return (DepsNodeFactory *)BLI_ghash_lookup(_depsnode_typeinfo_registry,
+ SET_INT_IN_POINTER(type));
}
/* Get typeinfo for provided node */
@@ -98,23 +100,17 @@ static const char *stringify_opcode(eDepsOperation_Code opcode)
#define STRINGIFY_OPCODE(name) case DEG_OPCODE_##name: return #name
STRINGIFY_OPCODE(OPERATION);
STRINGIFY_OPCODE(PLACEHOLDER);
- STRINGIFY_OPCODE(NOOP);
STRINGIFY_OPCODE(ANIMATION);
STRINGIFY_OPCODE(DRIVER);
- //STRINGIFY_OPCODE(PROXY);
STRINGIFY_OPCODE(TRANSFORM_LOCAL);
STRINGIFY_OPCODE(TRANSFORM_PARENT);
STRINGIFY_OPCODE(TRANSFORM_CONSTRAINTS);
- //STRINGIFY_OPCODE(TRANSFORM_CONSTRAINTS_INIT);
- //STRINGIFY_OPCODE(TRANSFORM_CONSTRAINT);
- //STRINGIFY_OPCODE(TRANSFORM_CONSTRAINTS_DONE);
STRINGIFY_OPCODE(RIGIDBODY_REBUILD);
STRINGIFY_OPCODE(RIGIDBODY_SIM);
STRINGIFY_OPCODE(TRANSFORM_RIGIDBODY);
STRINGIFY_OPCODE(TRANSFORM_FINAL);
STRINGIFY_OPCODE(OBJECT_UBEREVAL);
STRINGIFY_OPCODE(GEOMETRY_UBEREVAL);
- STRINGIFY_OPCODE(GEOMETRY_MODIFIER);
STRINGIFY_OPCODE(GEOMETRY_PATH);
STRINGIFY_OPCODE(POSE_INIT);
STRINGIFY_OPCODE(POSE_DONE);
@@ -123,13 +119,18 @@ static const char *stringify_opcode(eDepsOperation_Code opcode)
STRINGIFY_OPCODE(BONE_LOCAL);
STRINGIFY_OPCODE(BONE_POSE_PARENT);
STRINGIFY_OPCODE(BONE_CONSTRAINTS);
- //STRINGIFY_OPCODE(BONE_CONSTRAINTS_INIT);
- //STRINGIFY_OPCODE(BONE_CONSTRAINT);
- //STRINGIFY_OPCODE(BONE_CONSTRAINTS_DONE);
STRINGIFY_OPCODE(BONE_READY);
STRINGIFY_OPCODE(BONE_DONE);
STRINGIFY_OPCODE(PSYS_EVAL);
+ STRINGIFY_OPCODE(SCENE_LAYER_INIT);
+ STRINGIFY_OPCODE(SCENE_LAYER_EVAL);
+ STRINGIFY_OPCODE(SCENE_LAYER_DONE);
+
+ STRINGIFY_OPCODE(COPY_ON_WRITE);
+
+ STRINGIFY_OPCODE(SHADING);
+
case DEG_NUM_OPCODES: return "SpecialCase";
#undef STRINGIFY_OPCODE
}
@@ -145,7 +146,7 @@ DepsOperationStringifier::DepsOperationStringifier()
const char *DepsOperationStringifier::operator[](eDepsOperation_Code opcode)
{
- BLI_assert((opcode > 0) && (opcode < DEG_NUM_OPCODES));
+ BLI_assert((opcode >= 0) && (opcode < DEG_NUM_OPCODES));
if (opcode >= 0 && opcode < DEG_NUM_OPCODES) {
return names_[opcode];
}
diff --git a/source/blender/depsgraph/intern/depsgraph_types.h b/source/blender/depsgraph/intern/depsgraph_types.h
index effd34a0eb9..15b6f9bd00e 100644
--- a/source/blender/depsgraph/intern/depsgraph_types.h
+++ b/source/blender/depsgraph/intern/depsgraph_types.h
@@ -44,9 +44,6 @@
#include <string>
#include <vector>
-using std::string;
-using std::vector;
-
struct bAction;
struct ChannelDriver;
struct ModifierData;
@@ -56,6 +53,9 @@ struct FCurve;
namespace DEG {
+using std::string;
+using std::vector;
+
/* Evaluation Operation for atomic operation */
// XXX: move this to another header that can be exposed?
typedef function<void(struct EvaluationContext *)> DepsEvalOperationCb;
@@ -67,74 +67,71 @@ typedef enum eDepsNode_Class {
/* Types generally unassociated with user-visible entities,
* but needed for graph functioning.
*/
- DEPSNODE_CLASS_GENERIC = 0,
+ DEG_NODE_CLASS_GENERIC = 0,
/* [Outer Node] An "aspect" of evaluating/updating an ID-Block, requiring
* certain types of evaluation behavior.
*/
- DEPSNODE_CLASS_COMPONENT = 1,
+ DEG_NODE_CLASS_COMPONENT = 1,
/* [Inner Node] A glorified function-pointer/callback for scheduling up
* evaluation operations for components, subject to relationship
* requirements.
*/
- DEPSNODE_CLASS_OPERATION = 2,
+ DEG_NODE_CLASS_OPERATION = 2,
} eDepsNode_Class;
/* Types of Nodes */
typedef enum eDepsNode_Type {
/* Fallback type for invalid return value */
- DEPSNODE_TYPE_UNDEFINED = -1,
+ DEG_NODE_TYPE_UNDEFINED = -1,
/* Inner Node (Operation) */
- DEPSNODE_TYPE_OPERATION = 0,
+ DEG_NODE_TYPE_OPERATION = 0,
/* **** Generic Types **** */
- /* "Current Scene" - basically whatever kicks off the evaluation process. */
- DEPSNODE_TYPE_ROOT = 1,
/* Time-Source */
- DEPSNODE_TYPE_TIMESOURCE = 2,
+ DEG_NODE_TYPE_TIMESOURCE,
/* ID-Block reference - used as landmarks/collection point for components,
* but not usually part of main graph.
*/
- DEPSNODE_TYPE_ID_REF = 3,
- /* Isolated sub-graph - used for keeping instanced data separate from
- * instances using them.
- */
- DEPSNODE_TYPE_SUBGRAPH = 4,
+ DEG_NODE_TYPE_ID_REF,
/* **** Outer Types **** */
/* Parameters Component - Default when nothing else fits
* (i.e. just SDNA property setting).
*/
- DEPSNODE_TYPE_PARAMETERS = 11,
- /* Generic "Proxy-Inherit" Component
- * XXX: Also for instancing of subgraphs?
- */
- DEPSNODE_TYPE_PROXY = 12,
- /* Animation Component
- *
- * XXX: merge in with parameters?
- */
- DEPSNODE_TYPE_ANIMATION = 13,
+ DEG_NODE_TYPE_PARAMETERS,
+ /* Generic "Proxy-Inherit" Component. */
+ DEG_NODE_TYPE_PROXY,
+ /* Animation Component */
+ DEG_NODE_TYPE_ANIMATION,
/* Transform Component (Parenting/Constraints) */
- DEPSNODE_TYPE_TRANSFORM = 14,
+ DEG_NODE_TYPE_TRANSFORM,
/* Geometry Component (DerivedMesh/Displist) */
- DEPSNODE_TYPE_GEOMETRY = 15,
+ DEG_NODE_TYPE_GEOMETRY,
/* Sequencer Component (Scene Only) */
- DEPSNODE_TYPE_SEQUENCER = 16,
+ 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,
/* **** Evaluation-Related Outer Types (with Subdata) **** */
/* Pose Component - Owner/Container of Bones Eval */
- DEPSNODE_TYPE_EVAL_POSE = 21,
+ DEG_NODE_TYPE_EVAL_POSE,
/* Bone Component - Child/Subcomponent of Pose */
- DEPSNODE_TYPE_BONE = 22,
+ DEG_NODE_TYPE_BONE,
/* Particle Systems Component */
- DEPSNODE_TYPE_EVAL_PARTICLES = 23,
+ DEG_NODE_TYPE_EVAL_PARTICLES,
/* Material Shading Component */
- DEPSNODE_TYPE_SHADING = 24,
+ DEG_NODE_TYPE_SHADING,
/* Cache Component */
- DEPSNODE_TYPE_CACHE = 25,
+ DEG_NODE_TYPE_CACHE,
} eDepsNode_Type;
/* Identifiers for common operations (as an enum). */
@@ -147,83 +144,53 @@ typedef enum eDepsOperation_Code {
// XXX: Placeholder while porting depsgraph code
DEG_OPCODE_PLACEHOLDER,
- DEG_OPCODE_NOOP,
-
/* Animation, Drivers, etc. ------------------------ */
-
/* NLA + Action */
DEG_OPCODE_ANIMATION,
-
/* Driver */
DEG_OPCODE_DRIVER,
- /* Proxy Inherit? */
- //DEG_OPCODE_PROXY,
-
/* Transform --------------------------------------- */
-
/* Transform entry point - local transforms only */
DEG_OPCODE_TRANSFORM_LOCAL,
-
/* Parenting */
DEG_OPCODE_TRANSFORM_PARENT,
-
/* Constraints */
DEG_OPCODE_TRANSFORM_CONSTRAINTS,
- //DEG_OPCODE_TRANSFORM_CONSTRAINTS_INIT,
- //DEG_OPCODE_TRANSFORM_CONSTRAINT,
- //DEG_OPCODE_TRANSFORM_CONSTRAINTS_DONE,
+ /* Transform exit point */
+ DEG_OPCODE_TRANSFORM_FINAL,
+ /* Handle object-level updates, mainly proxies hacks and recalc flags. */
+ DEG_OPCODE_OBJECT_UBEREVAL,
- /* Rigidbody Sim - Perform Sim */
+ /* Rigid body -------------------------------------- */
+ /* Perform Simulation */
DEG_OPCODE_RIGIDBODY_REBUILD,
DEG_OPCODE_RIGIDBODY_SIM,
-
- /* Rigidbody Sim - Copy Results to Object */
+ /* Copy results to object */
DEG_OPCODE_TRANSFORM_RIGIDBODY,
- /* Transform exitpoint */
- DEG_OPCODE_TRANSFORM_FINAL,
-
- /* XXX: ubereval is for temporary porting purposes only */
- DEG_OPCODE_OBJECT_UBEREVAL,
-
/* Geometry ---------------------------------------- */
-
- /* XXX: Placeholder - UberEval */
+ /* Evaluate the whole geometry, including modifiers. */
DEG_OPCODE_GEOMETRY_UBEREVAL,
-
- /* Modifier */
- DEG_OPCODE_GEOMETRY_MODIFIER,
-
/* Curve Objects - Path Calculation (used for path-following tools, */
DEG_OPCODE_GEOMETRY_PATH,
/* Pose -------------------------------------------- */
-
/* Init IK Trees, etc. */
DEG_OPCODE_POSE_INIT,
-
/* Free IK Trees + Compute Deform Matrices */
DEG_OPCODE_POSE_DONE,
-
/* IK/Spline Solvers */
DEG_OPCODE_POSE_IK_SOLVER,
DEG_OPCODE_POSE_SPLINE_IK_SOLVER,
/* Bone -------------------------------------------- */
-
- /* Bone local transforms - Entrypoint */
+ /* Bone local transforms - entry point */
DEG_OPCODE_BONE_LOCAL,
-
/* Pose-space conversion (includes parent + restpose, */
DEG_OPCODE_BONE_POSE_PARENT,
-
/* Constraints */
DEG_OPCODE_BONE_CONSTRAINTS,
- //DEG_OPCODE_BONE_CONSTRAINTS_INIT,
- //DEG_OPCODE_BONE_CONSTRAINT,
- //DEG_OPCODE_BONE_CONSTRAINTS_DONE,
-
/* Bone transforms are ready
*
* - "READY" This (internal, noop is used to signal that all pre-IK
@@ -239,10 +206,20 @@ typedef enum eDepsOperation_Code {
DEG_OPCODE_BONE_DONE,
/* Particles --------------------------------------- */
-
- /* XXX: placeholder - Particle System eval */
+ /* Particle System evaluation. */
DEG_OPCODE_PSYS_EVAL,
+ /* Collections ------------------------------------- */
+ DEG_OPCODE_SCENE_LAYER_INIT,
+ DEG_OPCODE_SCENE_LAYER_EVAL,
+ DEG_OPCODE_SCENE_LAYER_DONE,
+
+ /* Copy on Write ------------------------- */
+ DEG_OPCODE_COPY_ON_WRITE,
+
+ /* Shading operations ------------------------- */
+ DEG_OPCODE_SHADING,
+
DEG_NUM_OPCODES,
} eDepsOperation_Code;
@@ -258,83 +235,4 @@ protected:
/* String defines for these opcodes, defined in depsgraph_type_defines.cpp */
extern DepsOperationStringifier DEG_OPNAMES;
-/* Type of operation */
-typedef enum eDepsOperation_Type {
- /* **** Primary operation types **** */
-
- /* Initialise evaluation data */
- DEPSOP_TYPE_INIT = 0,
- /* Standard evaluation step */
- DEPSOP_TYPE_EXEC = 1,
- /* Cleanup evaluation data + flush results */
- DEPSOP_TYPE_POST = 2,
-
- /* **** Additional operation types **** */
- /* Indicator for outputting a temporary result that other components
- * can use. // XXX?
- */
- DEPSOP_TYPE_OUT = 3,
- /* Indicator for things like IK Solvers and Rigidbody Sim steps which
- * modify final results of separate entities at once.
- */
- DEPSOP_TYPE_SIM = 4,
- /* Rebuild internal evaluation data - used for Rigidbody Reset and
- * Armature Rebuild-On-Load.
- */
- DEPSOP_TYPE_REBUILD = 5,
-} eDepsOperation_Type;
-
-/* Types of relationships between nodes
- *
- * This is used to provide additional hints to use when filtering
- * the graph, so that we can go without doing more extensive
- * data-level checks...
- */
-typedef enum eDepsRelation_Type {
- /* relationship type unknown/irrelevant */
- DEPSREL_TYPE_STANDARD = 0,
-
- /* root -> active scene or entity (screen, image, etc.) */
- DEPSREL_TYPE_ROOT_TO_ACTIVE,
-
- /* general datablock dependency */
- DEPSREL_TYPE_DATABLOCK,
-
- /* time dependency */
- DEPSREL_TYPE_TIME,
-
- /* component depends on results of another */
- DEPSREL_TYPE_COMPONENT_ORDER,
-
- /* relationship is just used to enforce ordering of operations
- * (e.g. "init()" callback done before "exec() and "cleanup()")
- */
- DEPSREL_TYPE_OPERATION,
-
- /* relationship results from a property driver affecting property */
- DEPSREL_TYPE_DRIVER,
-
- /* relationship is something driver depends on */
- DEPSREL_TYPE_DRIVER_TARGET,
-
- /* relationship is used for transform stack
- * (e.g. parenting, user transforms, constraints)
- */
- DEPSREL_TYPE_TRANSFORM,
-
- /* relationship is used for geometry evaluation
- * (e.g. metaball "motherball" or modifiers)
- */
- DEPSREL_TYPE_GEOMETRY_EVAL,
-
- /* relationship is used to trigger a post-change validity updates */
- DEPSREL_TYPE_UPDATE,
-
- /* relationship is used to trigger editor/screen updates */
- DEPSREL_TYPE_UPDATE_UI,
-
- /* cache dependency */
- DEPSREL_TYPE_CACHE,
-} eDepsRelation_Type;
-
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index c3fd202d832..15ad6b8054d 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -34,16 +34,11 @@
#include "PIL_time.h"
-extern "C" {
#include "BLI_utildefines.h"
#include "BLI_task.h"
#include "BLI_ghash.h"
-#include "BKE_depsgraph.h"
-#include "BKE_global.h"
-
#include "DEG_depsgraph.h"
-} /* extern "C" */
#include "atomic_ops.h"
@@ -53,6 +48,7 @@ extern "C" {
#include "intern/nodes/deg_node_component.h"
#include "intern/nodes/deg_node_operation.h"
#include "intern/depsgraph.h"
+#include "intern/depsgraph_intern.h"
#include "util/deg_util_foreach.h"
/* Unfinished and unused, and takes quite some pre-processing time. */
@@ -72,13 +68,11 @@ 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;
};
static void deg_task_run_func(TaskPool *pool,
@@ -94,136 +88,63 @@ static void deg_task_run_func(TaskPool *pool,
/* Should only be the case for NOOPs, which never get to this point. */
BLI_assert(node->evaluate);
- while (true) {
- /* Get context. */
- /* TODO: Who initialises this? "Init" operations aren't able to
- * initialise it!!!
- */
- /* TODO(sergey): We don't use component contexts at this moment. */
- /* ComponentDepsNode *comp = node->owner; */
- BLI_assert(node->owner != NULL);
-
- /* Since we're not leaving the thread for until the graph branches it is
- * possible to have NO-OP on the way. for which evaluate() will be NULL.
- * but that's all fine, we'll just scheduler it's children.
- */
- if (node->evaluate) {
+ /* Get context. */
+ /* TODO: Who initialises this? "Init" operations aren't able to
+ * initialise it!!!
+ */
+ /* TODO(sergey): We don't use component contexts at this moment. */
+ /* ComponentDepsNode *comp = node->owner; */
+ BLI_assert(node->owner != NULL);
+
+ /* Since we're not leaving the thread for until the graph branches it is
+ * possible to have NO-OP on the way. for which evaluate() will be NULL.
+ * but that's all fine, we'll just scheduler it's children.
+ */
+ if (node->evaluate) {
/* Take note of current time. */
#ifdef USE_DEBUGGER
- double start_time = PIL_check_seconds_timer();
- DepsgraphDebug::task_started(state->graph, node);
+ double start_time = PIL_check_seconds_timer();
+ DepsgraphDebug::task_started(state->graph, node);
#endif
- /* Perform operation. */
- node->evaluate(state->eval_ctx);
+ /* Perform operation. */
+ node->evaluate(state->eval_ctx);
/* Note how long this took. */
#ifdef USE_DEBUGGER
- double end_time = PIL_check_seconds_timer();
- DepsgraphDebug::task_completed(state->graph,
- node,
- end_time - start_time);
+ double end_time = PIL_check_seconds_timer();
+ DepsgraphDebug::task_completed(state->graph,
+ node,
+ end_time - start_time);
#endif
- }
-
- /* If there's only one outgoing link we try to immediately switch to
- * that node evaluation, without leaving the thread.
- *
- * It's only doable if the child don't have extra relations or all they
- * are satisfied.
- *
- * TODO(sergey): Checks here can be de-duplicated with the ones from
- * schedule_node(), however, how to do it nicely?
- */
- if (node->outlinks.size() == 1) {
- DepsRelation *rel = node->outlinks[0];
- OperationDepsNode *child = (OperationDepsNode *)rel->to;
- BLI_assert(child->type == DEPSNODE_TYPE_OPERATION);
- if (!child->scheduled) {
- unsigned int id_layers = child->owner->owner->layers;
- if (!((child->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 &&
- (id_layers & state->layers) != 0))
- {
- /* Node does not need an update, so can;t continue with the
- * chain and need to switch to another one by leaving the
- * thread.
- */
- break;
- }
- if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
- BLI_assert(child->num_links_pending > 0);
- atomic_sub_uint32(&child->num_links_pending, 1);
- }
- if (child->num_links_pending == 0) {
- bool is_scheduled = atomic_fetch_and_or_uint8(
- (uint8_t *)&child->scheduled, (uint8_t)true);
- if (!is_scheduled) {
- /* Node was not scheduled, switch to it! */
- node = child;
- }
- else {
- /* Someone else scheduled the node, leaving us
- * unemployed in this thread, we're leaving.
- */
- break;
- }
- }
- else {
- /* There are other dependencies on the child, can't do
- * anything in the current thread.
- */
- break;
- }
- }
- else {
- /* Happens when having cyclic dependencies.
- *
- * Nothing to do here, single child was already scheduled, we
- * can leave the thread now.
- */
- break;
- }
- }
- else {
- /* TODO(sergey): It's possible to use one of the outgoing relations
- * as a chain which we'll try to keep alive, but it's a bit more
- * involved change.
- */
- schedule_children(pool, state->graph, node, state->layers, thread_id);
- break;
- }
}
+
+ BLI_task_pool_delayed_push_begin(pool, thread_id);
+ schedule_children(pool, state->graph, node, thread_id);
+ BLI_task_pool_delayed_push_end(pool, thread_id);
}
typedef struct CalculatePengindData {
Depsgraph *graph;
- unsigned int layers;
} CalculatePengindData;
static void calculate_pending_func(void *data_v, int i)
{
CalculatePengindData *data = (CalculatePengindData *)data_v;
Depsgraph *graph = data->graph;
- unsigned int layers = data->layers;
OperationDepsNode *node = graph->operations[i];
- IDDepsNode *id_node = node->owner->owner;
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)
- {
+ if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0) {
foreach (DepsRelation *rel, node->inlinks) {
- if (rel->from->type == DEPSNODE_TYPE_OPERATION &&
+ 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)
- {
+ if ((from->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0) {
++node->num_links_pending;
}
}
@@ -231,13 +152,12 @@ static void calculate_pending_func(void *data_v, int i)
}
}
-static void calculate_pending_parents(Depsgraph *graph, unsigned int layers)
+static void calculate_pending_parents(Depsgraph *graph)
{
const int num_operations = graph->operations.size();
const bool do_threads = num_operations > 256;
CalculatePengindData data;
data.graph = graph;
- data.layers = layers;
BLI_task_parallel_range(0,
num_operations,
&data,
@@ -261,7 +181,7 @@ static void calculate_eval_priority(OperationDepsNode *node)
foreach (DepsRelation *rel, node->outlinks) {
OperationDepsNode *to = (OperationDepsNode *)rel->to;
- BLI_assert(to->type == DEPSNODE_TYPE_OPERATION);
+ BLI_assert(to->type == DEG_NODE_TYPE_OPERATION);
calculate_eval_priority(to);
node->eval_priority += to->eval_priority;
}
@@ -276,18 +196,14 @@ static void calculate_eval_priority(OperationDepsNode *node)
* dec_parents: Decrement pending parents count, true when child nodes are
* scheduled after a task has been completed.
*/
-static void schedule_node(TaskPool *pool, Depsgraph *graph, 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 ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0) {
if (dec_parents) {
BLI_assert(node->num_links_pending > 0);
- atomic_sub_uint32(&node->num_links_pending, 1);
+ atomic_sub_and_fetch_uint32(&node->num_links_pending, 1);
}
if (node->num_links_pending == 0) {
@@ -296,7 +212,7 @@ static void schedule_node(TaskPool *pool, Depsgraph *graph, unsigned int layers,
if (!is_scheduled) {
if (node->is_noop()) {
/* skip NOOP node, schedule children right away */
- schedule_children(pool, graph, node, layers, thread_id);
+ schedule_children(pool, graph, node, thread_id);
}
else {
/* children are scheduled once this task is completed */
@@ -304,7 +220,7 @@ static void schedule_node(TaskPool *pool, Depsgraph *graph, unsigned int layers,
deg_task_run_func,
node,
false,
- TASK_PRIORITY_LOW,
+ TASK_PRIORITY_HIGH,
thread_id);
}
}
@@ -312,31 +228,27 @@ static void schedule_node(TaskPool *pool, Depsgraph *graph, unsigned int layers,
}
}
-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) {
OperationDepsNode *child = (OperationDepsNode *)rel->to;
- BLI_assert(child->type == DEPSNODE_TYPE_OPERATION);
+ BLI_assert(child->type == DEG_NODE_TYPE_OPERATION);
if (child->scheduled) {
/* Happens when having cyclic dependencies. */
continue;
}
schedule_node(pool,
graph,
- layers,
child,
(rel->flag & DEPSREL_FLAG_CYCLIC) == 0,
thread_id);
@@ -351,8 +263,7 @@ 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)
+ Depsgraph *graph)
{
/* Generate base evaluation context, upon which all the others are derived. */
// TODO: this needs both main and scene access...
@@ -370,16 +281,22 @@ void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
DepsgraphEvalState state;
state.eval_ctx = eval_ctx;
state.graph = graph;
- state.layers = layers;
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
- TaskPool *task_pool = BLI_task_pool_create(task_scheduler, &state);
+ TaskScheduler *task_scheduler;
+ bool need_free_scheduler;
if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
- BLI_pool_set_num_threads(task_pool, 1);
+ task_scheduler = BLI_task_scheduler_create(1);
+ need_free_scheduler = true;
}
+ else {
+ task_scheduler = BLI_task_scheduler_get();
+ need_free_scheduler = false;
+ }
+
+ TaskPool *task_pool = BLI_task_pool_create_suspended(task_scheduler, &state);
- calculate_pending_parents(graph, layers);
+ calculate_pending_parents(graph);
/* Clear tags. */
foreach (OperationDepsNode *node, graph->operations) {
@@ -395,7 +312,7 @@ void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
DepsgraphDebug::eval_begin(eval_ctx);
- 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);
@@ -404,6 +321,10 @@ void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
/* Clear any uncleared tags - just in case. */
deg_graph_clear_tags(graph);
+
+ if (need_free_scheduler) {
+ BLI_task_scheduler_free(task_scheduler);
+ }
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.h b/source/blender/depsgraph/intern/eval/deg_eval.h
index 49c0379939e..576ab89dec1 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval.h
@@ -46,7 +46,6 @@ struct Depsgraph;
* \note Time sources should be all valid!
*/
void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
- Depsgraph *graph,
- const unsigned int layers);
+ 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..663caf5d716
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
@@ -0,0 +1,664 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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
+ */
+
+/* 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
+
+#include "intern/eval/deg_eval_copy_on_write.h"
+
+#include <cstring>
+
+#include "BLI_utildefines.h"
+#include "BLI_threads.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 "MEM_guardedalloc.h"
+
+extern "C" {
+#include "DNA_ID.h"
+#include "DNA_mesh_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+
+#ifdef NESTED_ID_NASTY_WORKAROUND
+# include "DNA_key_types.h"
+# include "DNA_lamp_types.h"
+# include "DNA_linestyle_types.h"
+# include "DNA_material_types.h"
+# include "DNA_mesh_types.h"
+# include "DNA_node_types.h"
+# include "DNA_scene_types.h"
+# include "DNA_texture_types.h"
+# include "DNA_world_types.h"
+#endif
+
+#include "BKE_editmesh.h"
+#include "BKE_library_query.h"
+}
+
+#include "intern/depsgraph.h"
+#include "intern/nodes/deg_node.h"
+
+namespace DEG {
+
+#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
+
+namespace {
+
+#ifdef NESTED_ID_NASTY_WORKAROUND
+union NestedIDHackTempStorage {
+ FreestyleLineStyle linestyle;
+ Lamp lamp;
+ 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_SCE, Scene, nodetree)
+ SPECIAL_CASE(ID_TE, Tex, nodetree)
+ SPECIAL_CASE(ID_WO, World, nodetree)
+
+ SPECIAL_CASE(ID_ME, Mesh, key)
+
+# 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_SCE, Scene, nodetree, scene)
+ SPECIAL_CASE(ID_TE, Tex, nodetree, tex)
+ SPECIAL_CASE(ID_WO, World, nodetree, world)
+
+ SPECIAL_CASE(ID_ME, Mesh, key, mesh)
+
+# 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_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_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.
+ *
+ * TODO(sergey): Get rid of this once T51804 is handled.
+ */
+bool id_copy_no_main(const ID *id, ID **newid)
+{
+ const ID *id_for_copy = id;
+ Main temp_bmain = {0};
+ SpinLock lock;
+ temp_bmain.lock = (MainLock *)&lock;
+ BLI_spin_init(&lock);
+
+#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 = id_copy(&temp_bmain, (ID *)id_for_copy, newid, false);
+
+#ifdef NESTED_ID_NASTY_WORKAROUND
+ if (result) {
+ nested_id_hack_restore_pointers(id, *newid);
+ }
+#endif
+
+ BLI_spin_end(&lock);
+ return result;
+}
+
+/* Similar to BKE_scene_copy() but does not require main.
+ *
+ * TODO(sergey): Get rid of this once T51804 is handled.
+ */
+Scene *scene_copy_no_main(Scene *scene)
+{
+ const ID *id_for_copy = &scene->id;
+ Main temp_bmain = {0};
+ SpinLock lock;
+ temp_bmain.lock = (MainLock *)&lock;
+ BLI_spin_init(&lock);
+
+#ifdef NESTED_ID_NASTY_WORKAROUND
+ NestedIDHackTempStorage id_hack_storage;
+ id_for_copy = nested_id_hack_get_discarded_pointers(&id_hack_storage,
+ &scene->id);
+#endif
+
+ Scene *new_scene = BKE_scene_copy(&temp_bmain,
+ (Scene *)id_for_copy,
+ SCE_COPY_LINK_OB);
+
+#ifdef NESTED_ID_NASTY_WORKAROUND
+ nested_id_hack_restore_pointers(&scene->id, &new_scene->id);
+#endif
+
+ BLI_spin_end(&lock);
+ return new_scene;
+}
+
+/* Callback for BKE_library_foreach_ID_link which remaps original ID pointer
+ * with the one created by CoW system.
+ */
+int foreach_libblock_remap_callback(void *user_data,
+ ID * /*id_self*/,
+ ID **id_p,
+ int /*cb_flag*/)
+{
+ Depsgraph *depsgraph = (Depsgraph *)user_data;
+ if (*id_p != NULL) {
+ const ID *id_orig = *id_p;
+ ID *id_cow = depsgraph->get_cow_id(id_orig);
+ if (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;
+}
+
+/* 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');
+}
+
+/* Check whether datablock was already expanded during depsgraph
+ * construction.
+ */
+static bool check_datablock_expanded_at_construction(const ID *id_orig)
+{
+ const short id_type = GS(id_orig->name);
+ return (id_type == ID_SCE) ||
+ (id_type == ID_OB && ((Object *)id_orig)->type == OB_ARMATURE) ||
+ (id_type == ID_AR);
+}
+
+/* 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 short 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;
+ (void) object_cow; /* Ignored for release builds. */
+ BLI_assert(object_cow->derivedFinal == NULL);
+ BLI_assert(object_cow->derivedDeform == NULL);
+ break;
+ }
+ case ID_ME:
+ {
+ /* For meshes we need to update edit_brtmesh 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) {
+ 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->derivedFinal = NULL;
+ mesh_cow->edit_btmesh->derivedCage = NULL;
+ }
+ break;
+ }
+ case ID_SCE:
+ {
+ const Scene *scene_orig = (const Scene *)id_orig;
+ Scene *scene_cow = (Scene *)id_cow;
+ if (scene_orig->obedit != NULL) {
+ scene_cow->obedit = (Object *)depsgraph->get_cow_id(&scene_orig->obedit->id);
+ }
+ else {
+ scene_cow->obedit = NULL;
+ }
+ break;
+ }
+ }
+}
+
+/* Update copy-on-write version of datablock from it's original ID without re-building
+ * the whole datablock from scratch.
+ *
+ * Used for such special cases as scene collections and armatures, which can not use full
+ * re-alloc due to pointers used as function bindings.
+ */
+void update_copy_on_write_datablock(const Depsgraph *depsgraph,
+ const ID *id_orig, ID *id_cow)
+{
+ if (GS(id_orig->name) == ID_SCE) {
+ const Scene *scene_orig = (const Scene *)id_orig;
+ Scene *scene_cow = (Scene *)id_cow;
+ // Some non-pointer data sync, current frame for now.
+ // TODO(sergey): Are we missing something here?
+ scene_cow->r.cfra = scene_orig->r.cfra;
+ scene_cow->r.subframe = scene_orig->r.subframe;
+ // Update bases.
+ const SceneLayer *sl_orig = (SceneLayer *)scene_orig->render_layers.first;
+ SceneLayer *sl_cow = (SceneLayer *)scene_cow->render_layers.first;
+ while (sl_orig != NULL) {
+ // Update pointers to active base.
+ if (sl_orig->basact == NULL) {
+ sl_cow->basact = NULL;
+ }
+ else {
+ const Object *obact_orig = sl_orig->basact->object;
+ Object *obact_cow = (Object *)depsgraph->get_cow_id(&obact_orig->id);
+ sl_cow->basact = BKE_scene_layer_base_find(sl_cow, obact_cow);
+ }
+ // Update base flags.
+ //
+ // TODO(sergey): We should probably check visibled/selectabled
+ // flag here?
+ const Base *base_orig = (Base *)sl_orig->object_bases.first;
+ Base *base_cow = (Base *)sl_cow->object_bases.first;;
+ while (base_orig != NULL) {
+ base_cow->flag = base_orig->flag;
+ base_orig = base_orig->next;
+ base_cow = base_cow->next;
+ }
+ sl_orig = sl_orig->next;
+ sl_cow = sl_cow->next;
+ }
+ // Update edit object pointer.
+ if (scene_orig->obedit != NULL) {
+ scene_cow->obedit = (Object *)depsgraph->get_cow_id(&scene_orig->obedit->id);
+ }
+ else {
+ scene_cow->obedit = NULL;
+ }
+ // TODO(sergey): Things which are still missing here:
+ // - Active render engine.
+ // - Something else?
+ }
+ // TODO(sergey): Other ID types here.
+}
+
+/* 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)
+{
+ const ID *id_orig = id_node->id_orig;
+ ID *id_cow = id_node->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. */
+ 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 short type = GS(id_orig->name);
+ switch (type) {
+ case ID_SCE:
+ {
+ Scene *new_scene = scene_copy_no_main((Scene *)id_orig);
+ *(Scene *)id_cow = *new_scene;
+ MEM_freeN(new_scene);
+ done = true;
+ 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;
+ }
+ }
+ if (!done) {
+ ID *newid;
+ if (id_copy_no_main(id_orig, &newid)) {
+ /* We copy contents of new ID to our CoW placeholder and free ID memory
+ * returned by id_copy().
+ *
+ * TODO(sergey): We can avoid having extra ID allocation here if we'll
+ * have some smarter id_copy() which can use externally allocated memory.
+ */
+ const size_t size = BKE_libblock_get_alloc_info(GS(newid->name), NULL);
+ memcpy(id_cow, newid, size);
+ MEM_freeN(newid);
+ done = true;
+ }
+ }
+ 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
+
+ BKE_library_foreach_ID_link(NULL,
+ id_cow,
+ foreach_libblock_remap_callback,
+ (void *)depsgraph,
+ IDWALK_NOP);
+ /* Correct or tweak some pointers which are not taken care by foreach
+ * from above.
+ */
+ update_special_pointers(depsgraph, id_orig, id_cow);
+ 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)
+{
+ 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);
+}
+
+ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph,
+ const IDDepsNode *id_node)
+{
+ const ID *id_orig = id_node->id_orig;
+ ID *id_cow = id_node->id_cow;
+ /* Special case for datablocks which are expanded at the dependency graph
+ * construction time. This datablocks must never change pointers of their
+ * nested data since it is used for function bindings.
+ */
+ if (check_datablock_expanded_at_construction(id_orig)) {
+ BLI_assert(check_datablock_expanded(id_cow) == true);
+ update_copy_on_write_datablock(depsgraph, id_orig, id_cow);
+ return id_cow;
+ }
+ /* For the rest if datablock types we use simple logic:
+ * - Free previously expanded data, if any.
+ * - Perform full datablock copy.
+ */
+ deg_free_copy_on_write_datablock(id_cow);
+ deg_expand_copy_on_write_datablock(depsgraph, id_node);
+ 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);
+}
+
+/* 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 short type = GS(id_cow->name);
+ 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;
+ break;
+ }
+ case ID_ME:
+ {
+ Mesh *mesh_cow = (Mesh *)id_cow;
+ if (mesh_cow->edit_btmesh != NULL) {
+ BKE_editmesh_free_derivedmesh(mesh_cow->edit_btmesh);
+ MEM_freeN(mesh_cow->edit_btmesh);
+ mesh_cow->edit_btmesh = NULL;
+ }
+ break;
+ }
+ case ID_SCE:
+ {
+ /* Special case for scene: we use explicit function call which
+ * ensures no access to other datablocks is done.
+ */
+ BKE_scene_free_ex((Scene *)id_cow, false);
+ BKE_libblock_free_data(id_cow, false);
+ id_cow->name[0] = '\0';
+ return;
+ }
+ }
+#ifdef NESTED_ID_NASTY_WORKAROUND
+ nested_id_hack_discard_pointers(id_cow);
+#endif
+ BKE_libblock_free_datablock(id_cow);
+ BKE_libblock_free_data(id_cow, false);
+ /* Signal datablock as not being expanded. */
+ id_cow->name[0] = '\0';
+}
+
+void deg_evaluate_copy_on_write(EvaluationContext * /*eval_ctx*/,
+ const Depsgraph *depsgraph,
+ const IDDepsNode *id_node)
+{
+ DEBUG_PRINT("%s on %s\n", __func__, id_node->id_orig->name);
+ 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;
+}
+
+} // 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..0e1b6642002
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h
@@ -0,0 +1,84 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 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
+
+struct EvaluationContext;
+struct ID;
+
+/* Unkomment 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
+
+namespace DEG {
+
+struct Depsgraph;
+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 Depsgraph *depsgraph,
+ const IDDepsNode *id_node);
+ID *deg_expand_copy_on_write_datablock(const struct Depsgraph *depsgraph,
+ struct ID *id_orig);
+
+/* Makes sure given CoW datablock is brought back to state of the original
+ * datablock.
+ */
+ID *deg_update_copy_on_write_datablock(const 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 EvaluationContext *eval_ctx,
+ const struct Depsgraph *depsgraph,
+ const struct IDDepsNode *id_node);
+
+/* Check that given ID is propely expanded and does not have any shallow
+ * copies inside.
+ */
+bool deg_validate_copy_on_write_datablock(ID *id_cow);
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_debug.cc b/source/blender/depsgraph/intern/eval/deg_eval_debug.cc
index 67d64aae8bf..e195fdd8ec8 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_debug.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_debug.cc
@@ -30,20 +30,20 @@
* Implementation of tools for debugging the depsgraph
*/
-#include <cstring>
-
#include "intern/eval/deg_eval_debug.h"
-extern "C" {
+#include <cstring> /* required for STREQ later on. */
+
#include "BLI_listbase.h"
#include "BLI_ghash.h"
-#include "DEG_depsgraph_debug.h"
-
+extern "C" {
#include "WM_api.h"
#include "WM_types.h"
} /* extern "C" */
+#include "DEG_depsgraph_debug.h"
+
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
#include "intern/nodes/deg_node_operation.h"
@@ -53,10 +53,10 @@ namespace DEG {
DepsgraphStats *DepsgraphDebug::stats = NULL;
-static string get_component_name(eDepsNode_Type type, const string &name = "")
+static string get_component_name(eDepsNode_Type type, const char *name = "")
{
DepsNodeFactory *factory = deg_get_node_factory(type);
- if (name.empty()) {
+ if (name[0] != '\0') {
return string(factory->tname());
}
else {
@@ -104,7 +104,7 @@ void DepsgraphDebug::task_started(Depsgraph *graph,
BLI_spin_lock(&graph->lock);
ComponentDepsNode *comp = node->owner;
- ID *id = comp->owner->id;
+ ID *id = comp->owner->id_orig;
DepsgraphStatsID *id_stats = get_id_stats(id, true);
times_clear(id_stats->times);
@@ -116,7 +116,7 @@ void DepsgraphDebug::task_started(Depsgraph *graph,
*/
DepsgraphStatsComponent *comp_stats =
get_component_stats(id, get_component_name(comp->type,
- comp->name),
+ comp->name).c_str(),
true);
times_clear(comp_stats->times);
}
@@ -133,7 +133,7 @@ void DepsgraphDebug::task_completed(Depsgraph *graph,
BLI_spin_lock(&graph->lock);
ComponentDepsNode *comp = node->owner;
- ID *id = comp->owner->id;
+ ID *id = comp->owner->id_orig;
DepsgraphStatsID *id_stats = get_id_stats(id, true);
times_add(id_stats->times, time);
@@ -146,7 +146,7 @@ void DepsgraphDebug::task_completed(Depsgraph *graph,
DepsgraphStatsComponent *comp_stats =
get_component_stats(id,
get_component_name(comp->type,
- comp->name),
+ comp->name).c_str(),
true);
times_add(comp_stats->times, time);
}
@@ -226,7 +226,7 @@ DepsgraphStatsID *DepsgraphDebug::get_id_stats(ID *id, bool create)
DepsgraphStatsComponent *DepsgraphDebug::get_component_stats(
DepsgraphStatsID *id_stats,
- const string &name,
+ const char *name,
bool create)
{
DepsgraphStatsComponent *comp_stats;
@@ -234,13 +234,14 @@ DepsgraphStatsComponent *DepsgraphDebug::get_component_stats(
comp_stats != NULL;
comp_stats = comp_stats->next)
{
- if (STREQ(comp_stats->name, name.c_str()))
+ if (STREQ(comp_stats->name, name)) {
break;
+ }
}
if (!comp_stats && create) {
comp_stats = (DepsgraphStatsComponent *)MEM_callocN(sizeof(DepsgraphStatsComponent),
"Depsgraph Component Stats");
- BLI_strncpy(comp_stats->name, name.c_str(), sizeof(comp_stats->name));
+ BLI_strncpy(comp_stats->name, name, sizeof(comp_stats->name));
BLI_addtail(&id_stats->components, comp_stats);
}
return comp_stats;
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_debug.h b/source/blender/depsgraph/intern/eval/deg_eval_debug.h
index 9109019eb2d..0bbe88cc9ca 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_debug.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_debug.h
@@ -66,10 +66,10 @@ struct DepsgraphDebug {
static DepsgraphStatsID *get_id_stats(ID *id, bool create);
static DepsgraphStatsComponent *get_component_stats(DepsgraphStatsID *id_stats,
- const string &name,
+ const char *name,
bool create);
static DepsgraphStatsComponent *get_component_stats(ID *id,
- const string &name,
+ const char *name,
bool create)
{
return get_component_stats(get_id_stats(id, create), name, create);
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
index f9e1504b3ce..605ca990e07 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
@@ -33,18 +33,18 @@
#include "intern/eval/deg_eval_flush.h"
// TODO(sergey): Use some sort of wrapper.
-#include <queue>
-
-extern "C" {
-#include "DNA_object_types.h"
+#include <deque>
#include "BLI_utildefines.h"
#include "BLI_task.h"
#include "BLI_ghash.h"
-#include "DEG_depsgraph.h"
+extern "C" {
+#include "DNA_object_types.h"
} /* extern "C" */
+#include "DEG_depsgraph.h"
+
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
#include "intern/nodes/deg_node_operation.h"
@@ -71,7 +71,7 @@ void lib_id_recalc_data_tag(Main *bmain, ID *id)
} /* namespace */
-typedef std::queue<OperationDepsNode *> FlushQueue;
+typedef std::deque<OperationDepsNode *> FlushQueue;
static void flush_init_func(void *data_v, int i)
{
@@ -120,26 +120,106 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
* NOTE: Count how many nodes we need to handle - entry nodes may be
* component nodes which don't count for this purpose!
*/
- GSET_FOREACH_BEGIN(OperationDepsNode *, node, graph->entry_tags)
+ GSET_FOREACH_BEGIN(OperationDepsNode *, op_node, graph->entry_tags)
{
- queue.push(node);
- node->scheduled = true;
+ if ((op_node->flag & DEPSOP_FLAG_SKIP_FLUSH) == 0) {
+ queue.push_back(op_node);
+ op_node->scheduled = true;
+ }
}
GSET_FOREACH_END();
+ int num_flushed_objects = 0;
while (!queue.empty()) {
OperationDepsNode *node = queue.front();
- queue.pop();
+ queue.pop_front();
for (;;) {
node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
ComponentDepsNode *comp_node = node->owner;
IDDepsNode *id_node = comp_node->owner;
+
+ /* TODO(sergey): Do we need to pass original or evaluated ID here? */
+ ID *id = id_node->id_orig;
+ if (id_node->done == 0) {
+ 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);
+
+#ifdef WITH_COPY_ON_WRITE
+ /* Currently this is needed to get ob->mesh to be replaced with
+ * original mesh (rather than being evaluated_mesh).
+ *
+ * TODO(sergey): This is something we need to avoid.
+ */
+ ComponentDepsNode *cow_comp =
+ id_node->find_component(DEG_NODE_TYPE_COPY_ON_WRITE);
+ cow_comp->tag_update(graph);
+#endif
+ }
+
+ if (comp_node->done == 0) {
+ Object *object = NULL;
+ if (GS(id->name) == ID_OB) {
+ object = (Object *)id;
+ if (id_node->done == 0) {
+ ++num_flushed_objects;
+ }
+ }
+ foreach (OperationDepsNode *op, comp_node->operations) {
+ op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+ }
+ if (object != NULL) {
+ /* This code is used to preserve those areas which does
+ * direct object update,
+ *
+ * Plus it ensures visibility changes and relations and
+ * layers visibility update has proper flags to work with.
+ */
+ 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_PARAMETERS:
+ case DEG_NODE_TYPE_SEQUENCER:
+ case DEG_NODE_TYPE_LAYER_COLLECTIONS:
+ case DEG_NODE_TYPE_COPY_ON_WRITE:
+ /* Ignore, does not translate to object component. */
+ 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;
+ }
+
+ /* TODO : replace with more granular flags */
+ object->deg_update_flag |= DEG_RUNTIME_DATA_UPDATE;
+ }
+ }
+
id_node->done = 1;
comp_node->done = 1;
/* Flush to nodes along links... */
+ /* TODO(sergey): This is mainly giving speedup due ot less queue pushes, which
+ * reduces number of memory allocations.
+ *
+ * We should try solve the allocation issue instead of doing crazy things here.
+ */
if (node->outlinks.size() == 1) {
OperationDepsNode *to_node = (OperationDepsNode *)node->outlinks[0]->to;
if (to_node->scheduled == false) {
@@ -154,7 +234,7 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
foreach (DepsRelation *rel, node->outlinks) {
OperationDepsNode *to_node = (OperationDepsNode *)rel->to;
if (to_node->scheduled == false) {
- queue.push(to_node);
+ queue.push_front(to_node);
to_node->scheduled = true;
}
}
@@ -162,52 +242,7 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
}
}
}
-
- GHASH_FOREACH_BEGIN(DEG::IDDepsNode *, id_node, graph->id_hash)
- {
- if (id_node->done == 1) {
- ID *id = id_node->id;
- Object *object = NULL;
-
- if (GS(id->name) == ID_OB) {
- object = (Object *)id;
- }
-
- deg_editors_id_update(bmain, id_node->id);
-
- lib_id_recalc_tag(bmain, id_node->id);
- /* TODO(sergey): For until we've got proper data nodes in the graph. */
- lib_id_recalc_data_tag(bmain, id_node->id);
-
- GHASH_FOREACH_BEGIN(const ComponentDepsNode *, comp_node, id_node->components)
- {
- if (comp_node->done) {
- foreach (OperationDepsNode *op, comp_node->operations) {
- op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
- }
- if (object != NULL) {
- /* This code is used to preserve those areas which does
- * direct object update,
- *
- * Plus it ensures visibility changes and relations and
- * layers visibility update has proper flags to work with.
- */
- if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
- object->recalc |= OB_RECALC_TIME;
- }
- else if (comp_node->type == DEPSNODE_TYPE_TRANSFORM) {
- object->recalc |= OB_RECALC_OB;
- }
- else {
- object->recalc |= OB_RECALC_DATA;
- }
- }
- }
- }
- GHASH_FOREACH_END();
- }
- }
- GHASH_FOREACH_END();
+ DEG_DEBUG_PRINTF("Update flushed to %d objects\n", num_flushed_objects);
}
static void graph_clear_func(void *data_v, int i)
diff --git a/source/blender/depsgraph/intern/nodes/deg_node.cc b/source/blender/depsgraph/intern/nodes/deg_node.cc
index eb408f293de..07aae7e15c4 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node.cc
@@ -31,7 +31,7 @@
#include "intern/nodes/deg_node.h"
#include <stdio.h>
-#include <string.h>
+#include <cstring> /* required for STREQ later on. */
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -39,17 +39,20 @@
extern "C" {
#include "DNA_ID.h"
#include "DNA_anim_types.h"
+#include "DNA_object_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_component.h"
#include "intern/nodes/deg_node_operation.h"
#include "intern/depsgraph_intern.h"
#include "util/deg_util_foreach.h"
-#include "util/deg_util_hash.h"
+#include "util/deg_util_function.h"
namespace DEG {
@@ -61,18 +64,18 @@ namespace DEG {
DepsNode::TypeInfo::TypeInfo(eDepsNode_Type type, const char *tname)
{
this->type = type;
- if (type == DEPSNODE_TYPE_OPERATION)
- this->tclass = DEPSNODE_CLASS_OPERATION;
- else if (type < DEPSNODE_TYPE_PARAMETERS)
- this->tclass = DEPSNODE_CLASS_GENERIC;
+ if (type == DEG_NODE_TYPE_OPERATION)
+ this->tclass = DEG_NODE_CLASS_OPERATION;
+ else if (type < DEG_NODE_TYPE_PARAMETERS)
+ this->tclass = DEG_NODE_CLASS_GENERIC;
else
- this->tclass = DEPSNODE_CLASS_COMPONENT;
+ this->tclass = DEG_NODE_CLASS_COMPONENT;
this->tname = tname;
}
DepsNode::DepsNode()
{
- name[0] = '\0';
+ name = "";
}
DepsNode::~DepsNode()
@@ -110,44 +113,31 @@ void TimeSourceDepsNode::tag_update(Depsgraph *graph)
}
}
+/* Time Source Node ======================================= */
-/* Root Node ============================================== */
+DEG_DEPSNODE_DEFINE(TimeSourceDepsNode, DEG_NODE_TYPE_TIMESOURCE, "Time Source");
+static DepsNodeFactoryImpl<TimeSourceDepsNode> DNTI_TIMESOURCE;
-RootDepsNode::RootDepsNode() : scene(NULL), time_source(NULL)
-{
-}
+/* ID Node ================================================ */
-RootDepsNode::~RootDepsNode()
+IDDepsNode::ComponentIDKey::ComponentIDKey(eDepsNode_Type type,
+ const char *name)
+ : type(type), name(name)
{
- OBJECT_GUARDED_DELETE(time_source, TimeSourceDepsNode);
}
-TimeSourceDepsNode *RootDepsNode::add_time_source(const string &name)
+bool IDDepsNode::ComponentIDKey::operator== (const ComponentIDKey &other) const
{
- if (!time_source) {
- DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_TIMESOURCE);
- time_source = (TimeSourceDepsNode *)factory->create_node(NULL, "", name);
- /*time_source->owner = this;*/ // XXX
- }
- return time_source;
+ return type == other.type &&
+ STREQ(name, other.name);
}
-DEG_DEPSNODE_DEFINE(RootDepsNode, DEPSNODE_TYPE_ROOT, "Root DepsNode");
-static DepsNodeFactoryImpl<RootDepsNode> DNTI_ROOT;
-
-/* Time Source Node ======================================= */
-
-DEG_DEPSNODE_DEFINE(TimeSourceDepsNode, DEPSNODE_TYPE_TIMESOURCE, "Time Source");
-static DepsNodeFactoryImpl<TimeSourceDepsNode> DNTI_TIMESOURCE;
-
-/* ID Node ================================================ */
-
static unsigned int id_deps_node_hash_key(const void *key_v)
{
const IDDepsNode::ComponentIDKey *key =
reinterpret_cast<const IDDepsNode::ComponentIDKey *>(key_v);
- return hash_combine(BLI_ghashutil_uinthash(key->type),
- BLI_ghashutil_strhash_p(key->name.c_str()));
+ return BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(key->type),
+ BLI_ghashutil_strhash_p(key->name));
}
static bool id_deps_node_hash_key_cmp(const void *a, const void *b)
@@ -173,50 +163,60 @@ 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 string &UNUSED(subdata))
+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->id_orig = (ID *)id;
this->eval_flags = 0;
- /* For object we initialize layers to layer from base. */
- if (GS(id->name) == ID_OB) {
- this->layers = 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...
+#ifdef WITH_COPY_ON_WRITE
+ /* 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.
*/
+ id_cow = (ID *)BKE_libblock_alloc_notest(GS(id->name));
+ DEG_COW_PRINT("Create shallow copy for %s: id_orig=%p id_cow=%p\n",
+ id_orig->name, id_orig, id_cow);
+#else
+ id_cow = id_orig;
+#endif
}
/* Free 'id' node. */
IDDepsNode::~IDDepsNode()
{
- clear_components();
- BLI_ghash_free(components, id_deps_node_hash_key_free, NULL);
+ BLI_ghash_free(components,
+ id_deps_node_hash_key_free,
+ id_deps_node_hash_value_free);
+
+#ifdef WITH_COPY_ON_WRITE
+ /* Free memory used by this CoW ID. */
+ deg_free_copy_on_write_datablock(id_cow);
+ MEM_freeN(id_cow);
+ DEG_COW_PRINT("Destroy CoW for %s: id_orig=%p id_cow=%p\n",
+ id_orig->name, id_orig, id_cow);
+#endif
}
ComponentDepsNode *IDDepsNode::find_component(eDepsNode_Type type,
- const string &name) const
+ const char *name) const
{
ComponentIDKey key(type, name);
return reinterpret_cast<ComponentDepsNode *>(BLI_ghash_lookup(components, &key));
}
ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type,
- const string &name)
+ const char *name)
{
ComponentDepsNode *comp_node = find_component(type, name);
if (!comp_node) {
DepsNodeFactory *factory = deg_get_node_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);
@@ -226,39 +226,27 @@ ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type,
return comp_node;
}
-void IDDepsNode::remove_component(eDepsNode_Type type, const string &name)
-{
- ComponentDepsNode *comp_node = find_component(type, name);
- if (comp_node) {
- /* Unregister. */
- ComponentIDKey key(type, name);
- BLI_ghash_remove(components,
- &key,
- id_deps_node_hash_key_free,
- id_deps_node_hash_value_free);
- }
-}
-
-void IDDepsNode::clear_components()
-{
- BLI_ghash_clear(components,
- id_deps_node_hash_key_free,
- id_deps_node_hash_value_free);
-}
-
void IDDepsNode::tag_update(Depsgraph *graph)
{
GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components)
{
- /* TODO(sergey): What about drievrs? */
- bool do_component_tag = comp_node->type != DEPSNODE_TYPE_ANIMATION;
- if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
- AnimData *adt = BKE_animdata_from_id(id);
+ /* TODO(sergey): What about drivers? */
+ 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_orig);
/* Animation data might be null if relations are tagged for update. */
if (adt != NULL && (adt->recalc & ADT_RECALC_ANIM)) {
do_component_tag = true;
}
}
+ else if (comp_node->type == DEG_NODE_TYPE_SHADING) {
+ /* TODO(sergey): For until we properly handle granular flags for DEG_id_tag_update()
+ * we skip flushing here to keep Luca happy.
+ */
+ if (GS(id_orig->name) != ID_MA) {
+ do_component_tag = false;
+ }
+ }
if (do_component_tag) {
comp_node->tag_update(graph);
}
@@ -266,55 +254,23 @@ void IDDepsNode::tag_update(Depsgraph *graph)
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();
}
-DEG_DEPSNODE_DEFINE(IDDepsNode, DEPSNODE_TYPE_ID_REF, "ID Node");
+DEG_DEPSNODE_DEFINE(IDDepsNode, DEG_NODE_TYPE_ID_REF, "ID Node");
static DepsNodeFactoryImpl<IDDepsNode> DNTI_ID_REF;
-/* Subgraph Node ========================================== */
-
-/* Initialize 'subgraph' node - from pointer data given. */
-void SubgraphDepsNode::init(const ID *id, const string &UNUSED(subdata))
-{
- /* Store ID-ref if provided. */
- this->root_id = (ID *)id;
-
- /* NOTE: graph will need to be added manually,
- * as we don't have any way of passing this down.
- */
-}
-
-/* Free 'subgraph' node */
-SubgraphDepsNode::~SubgraphDepsNode()
-{
- /* Only free if graph not shared, of if this node is the first
- * reference to it...
- */
- // XXX: prune these flags a bit...
- if ((this->flag & SUBGRAPH_FLAG_FIRSTREF) || !(this->flag & SUBGRAPH_FLAG_SHARED)) {
- /* Free the referenced graph. */
- DEG_graph_free(reinterpret_cast< ::Depsgraph* >(graph));
- graph = NULL;
- }
-}
-
-DEG_DEPSNODE_DEFINE(SubgraphDepsNode, DEPSNODE_TYPE_SUBGRAPH, "Subgraph Node");
-static DepsNodeFactoryImpl<SubgraphDepsNode> DNTI_SUBGRAPH;
-
void deg_register_base_depsnodes()
{
- deg_register_node_typeinfo(&DNTI_ROOT);
deg_register_node_typeinfo(&DNTI_TIMESOURCE);
-
deg_register_node_typeinfo(&DNTI_ID_REF);
- deg_register_node_typeinfo(&DNTI_SUBGRAPH);
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/nodes/deg_node.h b/source/blender/depsgraph/intern/nodes/deg_node.h
index b2262c4bd12..4e03072d486 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node.h
@@ -32,6 +32,8 @@
#include "intern/depsgraph_types.h"
+#include "BLI_utildefines.h"
+
struct ID;
struct GHash;
struct Scene;
@@ -57,7 +59,7 @@ struct DepsNode {
};
/* Identifier - mainly for debugging purposes. */
- string name;
+ const char *name;
/* Structural type of node. */
eDepsNode_Type type;
@@ -78,8 +80,9 @@ struct DepsNode {
/* Nodes which depend on this one. */
Relations outlinks;
- /* Generic tag for traversal algorithms */
+ /* Generic tags for traversal algorithms. */
int done;
+ int tag;
/* Methods. */
@@ -90,7 +93,7 @@ struct DepsNode {
string full_identifier() const;
virtual void init(const ID * /*id*/,
- const string &/*subdata*/) {}
+ const char * /*subdata*/) {}
virtual void tag_update(Depsgraph * /*graph*/) {}
@@ -124,60 +127,35 @@ struct TimeSourceDepsNode : public DepsNode {
DEG_DEPSNODE_DECLARE;
};
-/* Root Node. */
-struct RootDepsNode : public DepsNode {
- RootDepsNode();
- ~RootDepsNode();
-
- TimeSourceDepsNode *add_time_source(const string &name = "");
-
- /* scene that this corresponds to */
- Scene *scene;
-
- /* Entrypoint node for time-changed. */
- TimeSourceDepsNode *time_source;
-
- DEG_DEPSNODE_DECLARE;
-};
-
/* ID-Block Reference */
struct IDDepsNode : public DepsNode {
struct ComponentIDKey {
- ComponentIDKey(eDepsNode_Type type, const string &name = "")
- : type(type), name(name) {}
-
- bool operator== (const ComponentIDKey &other) const
- {
- return type == other.type && name == other.name;
- }
+ ComponentIDKey(eDepsNode_Type type, const char *name = "");
+ bool operator==(const ComponentIDKey &other) const;
eDepsNode_Type type;
- string name;
+ const char *name;
};
- void init(const ID *id, const string &subdata);
+ void init(const ID *id, const char *subdata);
~IDDepsNode();
ComponentDepsNode *find_component(eDepsNode_Type type,
- const string &name = "") const;
+ const char *name = "") const;
ComponentDepsNode *add_component(eDepsNode_Type type,
- const string &name = "");
- void remove_component(eDepsNode_Type type, const string &name = "");
- void clear_components();
+ const char *name = "");
void tag_update(Depsgraph *graph);
- void finalize_build();
+ void finalize_build(Depsgraph *graph);
/* 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.
@@ -187,41 +165,6 @@ struct IDDepsNode : public DepsNode {
DEG_DEPSNODE_DECLARE;
};
-/* Subgraph Reference. */
-struct SubgraphDepsNode : public DepsNode {
- void init(const ID *id, const string &subdata);
- ~SubgraphDepsNode();
-
- /* Instanced graph. */
- Depsgraph *graph;
-
- /* ID-block at root of subgraph (if applicable). */
- ID *root_id;
-
- /* Number of nodes which use/reference this subgraph - if just 1, it may be
- * possible to merge into main,
- */
- size_t num_users;
-
- /* (eSubgraphRef_Flag) assorted settings for subgraph node. */
- int flag;
-
- DEG_DEPSNODE_DECLARE;
-};
-
-/* Flags for subgraph node */
-typedef enum eSubgraphRef_Flag {
- /* Subgraph referenced is shared with another reference, so shouldn't
- * free on exit.
- */
- SUBGRAPH_FLAG_SHARED = (1 << 0),
-
- /* Node is first reference to subgraph, so it can be freed when we are
- * removed.
- */
- SUBGRAPH_FLAG_FIRSTREF = (1 << 1),
-} eSubgraphRef_Flag;
-
void deg_register_base_depsnodes();
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.cc b/source/blender/depsgraph/intern/nodes/deg_node_component.cc
index 01f33b6368b..bd9583a7b67 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_component.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node_component.cc
@@ -31,11 +31,12 @@
#include "intern/nodes/deg_node_component.h"
#include <stdio.h>
-#include <string.h>
+#include <cstring> /* required for STREQ later on. */
-extern "C" {
#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+extern "C" {
#include "DNA_object_types.h"
#include "BKE_action.h"
@@ -44,7 +45,6 @@ extern "C" {
#include "intern/nodes/deg_node_operation.h"
#include "intern/depsgraph_intern.h"
#include "util/deg_util_foreach.h"
-#include "util/deg_util_hash.h"
namespace DEG {
@@ -53,12 +53,50 @@ namespace DEG {
/* Standard Component Methods ============================= */
+ComponentDepsNode::OperationIDKey::OperationIDKey()
+ : opcode(DEG_OPCODE_OPERATION),
+ name(""),
+ name_tag(-1)
+{
+}
+
+ComponentDepsNode::OperationIDKey::OperationIDKey(eDepsOperation_Code opcode)
+ : opcode(opcode),
+ name(""),
+ name_tag(-1)
+{
+}
+
+ComponentDepsNode::OperationIDKey::OperationIDKey(eDepsOperation_Code opcode,
+ const char *name,
+ int name_tag)
+ : opcode(opcode),
+ name(name),
+ name_tag(name_tag)
+{
+}
+
+string ComponentDepsNode::OperationIDKey::identifier() const
+{
+ char codebuf[5];
+ BLI_snprintf(codebuf, sizeof(codebuf), "%d", opcode);
+ return string("OperationIDKey(") + codebuf + ", " + name + ")";
+}
+
+bool ComponentDepsNode::OperationIDKey::operator==(
+ const OperationIDKey &other) const
+{
+ return (opcode == other.opcode) &&
+ (STREQ(name, other.name)) &&
+ (name_tag == other.name_tag);
+}
+
static unsigned int comp_node_hash_key(const void *key_v)
{
const ComponentDepsNode::OperationIDKey *key =
reinterpret_cast<const ComponentDepsNode::OperationIDKey *>(key_v);
- return hash_combine(BLI_ghashutil_uinthash(key->opcode),
- BLI_ghashutil_strhash_p(key->name.c_str()));
+ return BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(key->opcode),
+ BLI_ghashutil_strhash_p(key->name));
}
static bool comp_node_hash_key_cmp(const void *a, const void *b)
@@ -85,8 +123,7 @@ static void comp_node_hash_value_free(void *value_v)
ComponentDepsNode::ComponentDepsNode() :
entry_operation(NULL),
- exit_operation(NULL),
- layers(0)
+ exit_operation(NULL)
{
operations_map = BLI_ghash_new(comp_node_hash_key,
comp_node_hash_key_cmp,
@@ -95,7 +132,7 @@ ComponentDepsNode::ComponentDepsNode() :
/* Initialize 'component' node - from pointer data given */
void ComponentDepsNode::init(const ID * /*id*/,
- const string & /*subdata*/)
+ const char * /*subdata*/)
{
/* hook up eval context? */
// XXX: maybe this needs a special API?
@@ -114,15 +151,12 @@ ComponentDepsNode::~ComponentDepsNode()
string ComponentDepsNode::identifier() const
{
- string &idname = this->owner->name;
+ string idname = this->owner->name;
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;
}
OperationDepsNode *ComponentDepsNode::find_operation(OperationIDKey key) const
@@ -139,9 +173,11 @@ OperationDepsNode *ComponentDepsNode::find_operation(OperationIDKey key) const
}
}
-OperationDepsNode *ComponentDepsNode::find_operation(eDepsOperation_Code opcode, const string &name) const
+OperationDepsNode *ComponentDepsNode::find_operation(eDepsOperation_Code opcode,
+ const char *name,
+ int name_tag) const
{
- OperationIDKey key(opcode, name);
+ OperationIDKey key(opcode, name, name_tag);
return find_operation(key);
}
@@ -151,34 +187,27 @@ OperationDepsNode *ComponentDepsNode::has_operation(OperationIDKey key) const
}
OperationDepsNode *ComponentDepsNode::has_operation(eDepsOperation_Code opcode,
- const string &name) const
+ const char *name,
+ int name_tag) const
{
- OperationIDKey key(opcode, name);
+ OperationIDKey key(opcode, name, name_tag);
return has_operation(key);
}
-OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &name)
+OperationDepsNode *ComponentDepsNode::add_operation(const DepsEvalOperationCb& op,
+ eDepsOperation_Code opcode,
+ const char *name,
+ int name_tag)
{
- OperationDepsNode *op_node = has_operation(opcode, name);
+ OperationDepsNode *op_node = has_operation(opcode, name, name_tag);
if (!op_node) {
- DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_OPERATION);
- op_node = (OperationDepsNode *)factory->create_node(this->owner->id, "", name);
+ DepsNodeFactory *factory = deg_get_node_factory(DEG_NODE_TYPE_OPERATION);
+ 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);
+ OperationIDKey *key = OBJECT_GUARDED_NEW(OperationIDKey, opcode, name, name_tag);
BLI_ghash_insert(operations_map, key, op_node);
- /* set as entry/exit node of component (if appropriate) */
- if (optype == DEPSOP_TYPE_INIT) {
- BLI_assert(this->entry_operation == NULL);
- this->entry_operation = op_node;
- }
- else if (optype == DEPSOP_TYPE_POST) {
- // XXX: review whether DEPSOP_TYPE_OUT is better than DEPSOP_TYPE_POST, or maybe have both?
- BLI_assert(this->exit_operation == NULL);
- this->exit_operation = op_node;
- }
-
/* set backlink */
op_node->owner = this;
}
@@ -190,21 +219,22 @@ OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype,
/* attach extra data */
op_node->evaluate = op;
- op_node->optype = optype;
op_node->opcode = opcode;
op_node->name = name;
return op_node;
}
-void ComponentDepsNode::remove_operation(eDepsOperation_Code opcode, const string &name)
+void ComponentDepsNode::set_entry_operation(OperationDepsNode *op_node)
+{
+ BLI_assert(entry_operation == NULL);
+ entry_operation = op_node;
+}
+
+void ComponentDepsNode::set_exit_operation(OperationDepsNode *op_node)
{
- /* unregister */
- OperationIDKey key(opcode, name);
- BLI_ghash_remove(operations_map,
- &key,
- comp_node_hash_key_free,
- comp_node_hash_key_free);
+ BLI_assert(exit_operation == NULL);
+ exit_operation = op_node;
}
void ComponentDepsNode::clear_operations()
@@ -285,7 +315,7 @@ OperationDepsNode *ComponentDepsNode::get_exit_operation()
return NULL;
}
-void ComponentDepsNode::finalize_build()
+void ComponentDepsNode::finalize_build(Depsgraph * /*graph*/)
{
operations.reserve(BLI_ghash_size(operations_map));
GHASH_FOREACH_BEGIN(OperationDepsNode *, op_node, operations_map)
@@ -301,43 +331,43 @@ void ComponentDepsNode::finalize_build()
/* Parameter Component Defines ============================ */
-DEG_DEPSNODE_DEFINE(ParametersComponentDepsNode, DEPSNODE_TYPE_PARAMETERS, "Parameters Component");
+DEG_DEPSNODE_DEFINE(ParametersComponentDepsNode, DEG_NODE_TYPE_PARAMETERS, "Parameters Component");
static DepsNodeFactoryImpl<ParametersComponentDepsNode> DNTI_PARAMETERS;
/* Animation Component Defines ============================ */
-DEG_DEPSNODE_DEFINE(AnimationComponentDepsNode, DEPSNODE_TYPE_ANIMATION, "Animation Component");
+DEG_DEPSNODE_DEFINE(AnimationComponentDepsNode, DEG_NODE_TYPE_ANIMATION, "Animation Component");
static DepsNodeFactoryImpl<AnimationComponentDepsNode> DNTI_ANIMATION;
/* Transform Component Defines ============================ */
-DEG_DEPSNODE_DEFINE(TransformComponentDepsNode, DEPSNODE_TYPE_TRANSFORM, "Transform Component");
+DEG_DEPSNODE_DEFINE(TransformComponentDepsNode, DEG_NODE_TYPE_TRANSFORM, "Transform Component");
static DepsNodeFactoryImpl<TransformComponentDepsNode> DNTI_TRANSFORM;
/* Proxy Component Defines ================================ */
-DEG_DEPSNODE_DEFINE(ProxyComponentDepsNode, DEPSNODE_TYPE_PROXY, "Proxy Component");
+DEG_DEPSNODE_DEFINE(ProxyComponentDepsNode, DEG_NODE_TYPE_PROXY, "Proxy Component");
static DepsNodeFactoryImpl<ProxyComponentDepsNode> DNTI_PROXY;
/* Geometry Component Defines ============================= */
-DEG_DEPSNODE_DEFINE(GeometryComponentDepsNode, DEPSNODE_TYPE_GEOMETRY, "Geometry Component");
+DEG_DEPSNODE_DEFINE(GeometryComponentDepsNode, DEG_NODE_TYPE_GEOMETRY, "Geometry Component");
static DepsNodeFactoryImpl<GeometryComponentDepsNode> DNTI_GEOMETRY;
/* Sequencer Component Defines ============================ */
-DEG_DEPSNODE_DEFINE(SequencerComponentDepsNode, DEPSNODE_TYPE_SEQUENCER, "Sequencer Component");
+DEG_DEPSNODE_DEFINE(SequencerComponentDepsNode, DEG_NODE_TYPE_SEQUENCER, "Sequencer Component");
static DepsNodeFactoryImpl<SequencerComponentDepsNode> DNTI_SEQUENCER;
/* Pose Component ========================================= */
-DEG_DEPSNODE_DEFINE(PoseComponentDepsNode, DEPSNODE_TYPE_EVAL_POSE, "Pose Eval Component");
+DEG_DEPSNODE_DEFINE(PoseComponentDepsNode, DEG_NODE_TYPE_EVAL_POSE, "Pose Eval Component");
static DepsNodeFactoryImpl<PoseComponentDepsNode> DNTI_EVAL_POSE;
/* Bone Component ========================================= */
/* Initialize 'bone component' node - from pointer data given */
-void BoneComponentDepsNode::init(const ID *id, const string &subdata)
+void BoneComponentDepsNode::init(const ID *id, const char *subdata)
{
/* generic component-node... */
ComponentDepsNode::init(id, subdata);
@@ -350,27 +380,36 @@ void BoneComponentDepsNode::init(const ID *id, const string &subdata)
/* bone-specific node data */
Object *ob = (Object *)id;
- this->pchan = BKE_pose_channel_find_name(ob->pose, subdata.c_str());
+ this->pchan = BKE_pose_channel_find_name(ob->pose, subdata);
}
-DEG_DEPSNODE_DEFINE(BoneComponentDepsNode, DEPSNODE_TYPE_BONE, "Bone Component");
+DEG_DEPSNODE_DEFINE(BoneComponentDepsNode, DEG_NODE_TYPE_BONE, "Bone Component");
static DepsNodeFactoryImpl<BoneComponentDepsNode> DNTI_BONE;
/* Particles Component Defines ============================ */
-DEG_DEPSNODE_DEFINE(ParticlesComponentDepsNode, DEPSNODE_TYPE_EVAL_PARTICLES, "Particles Component");
+DEG_DEPSNODE_DEFINE(ParticlesComponentDepsNode, DEG_NODE_TYPE_EVAL_PARTICLES, "Particles Component");
static DepsNodeFactoryImpl<ParticlesComponentDepsNode> DNTI_EVAL_PARTICLES;
/* Shading Component Defines ============================ */
-DEG_DEPSNODE_DEFINE(ShadingComponentDepsNode, DEPSNODE_TYPE_SHADING, "Shading Component");
+DEG_DEPSNODE_DEFINE(ShadingComponentDepsNode, DEG_NODE_TYPE_SHADING, "Shading Component");
static DepsNodeFactoryImpl<ShadingComponentDepsNode> DNTI_SHADING;
/* Cache Component Defines ============================ */
-DEG_DEPSNODE_DEFINE(CacheComponentDepsNode, DEPSNODE_TYPE_CACHE, "Cache Component");
+DEG_DEPSNODE_DEFINE(CacheComponentDepsNode, DEG_NODE_TYPE_CACHE, "Cache Component");
static DepsNodeFactoryImpl<CacheComponentDepsNode> DNTI_CACHE;
+/* Layer Collections Defines ============================ */
+
+DEG_DEPSNODE_DEFINE(LayerCollectionsDepsNode, DEG_NODE_TYPE_LAYER_COLLECTIONS, "Layer Collections Component");
+static DepsNodeFactoryImpl<LayerCollectionsDepsNode> DNTI_LAYER_COLLECTIONS;
+
+/* Copy-on-write Defines ============================ */
+
+DEG_DEPSNODE_DEFINE(CopyOnWriteDepsNode, DEG_NODE_TYPE_COPY_ON_WRITE, "Copy-on-Write Component");
+static DepsNodeFactoryImpl<CopyOnWriteDepsNode> DNTI_COPY_ON_WRITE;
/* Node Types Register =================================== */
@@ -390,6 +429,10 @@ void deg_register_component_depsnodes()
deg_register_node_typeinfo(&DNTI_SHADING);
deg_register_node_typeinfo(&DNTI_CACHE);
+
+ deg_register_node_typeinfo(&DNTI_LAYER_COLLECTIONS);
+
+ deg_register_node_typeinfo(&DNTI_COPY_ON_WRITE);
}
} // 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 7dec8eaaa90..955d197b33a 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_component.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node_component.h
@@ -53,50 +53,38 @@ struct ComponentDepsNode : public DepsNode {
struct OperationIDKey
{
eDepsOperation_Code opcode;
- string name;
-
-
- OperationIDKey() :
- opcode(DEG_OPCODE_OPERATION), name("")
- {}
- OperationIDKey(eDepsOperation_Code opcode) :
- opcode(opcode), name("")
- {}
- OperationIDKey(eDepsOperation_Code opcode, const string &name) :
- opcode(opcode), name(name)
- {}
-
- string identifier() const
- {
- char codebuf[5];
- BLI_snprintf(codebuf, sizeof(codebuf), "%d", opcode);
-
- return string("OperationIDKey(") + codebuf + ", " + name + ")";
- }
-
- bool operator==(const OperationIDKey &other) const
- {
- return (opcode == other.opcode) && (name == other.name);
- }
+ const char *name;
+ int name_tag;
+
+ OperationIDKey();
+ OperationIDKey(eDepsOperation_Code opcode);
+ OperationIDKey(eDepsOperation_Code opcode,
+ const char *name,
+ int name_tag);
+
+ string identifier() const;
+ bool operator==(const OperationIDKey &other) const;
};
/* Typedef for container of operations */
ComponentDepsNode();
~ComponentDepsNode();
- void init(const ID *id, const string &subdata);
+ void init(const ID *id, const char *subdata);
string identifier() const;
/* Find an existing operation, will throw an assert() if it does not exist. */
OperationDepsNode *find_operation(OperationIDKey key) const;
OperationDepsNode *find_operation(eDepsOperation_Code opcode,
- const string &name) const;
+ const char *name,
+ int name_tag) const;
/* Check operation exists and return it. */
OperationDepsNode *has_operation(OperationIDKey key) const;
OperationDepsNode *has_operation(eDepsOperation_Code opcode,
- const string &name) const;
+ const char *name,
+ int name_tag) const;
/**
* Create a new node for representing an operation and add this to graph
@@ -111,12 +99,18 @@ struct ComponentDepsNode : public DepsNode {
* \param op: The operation to perform
* \param name: Identifier for operation - used to find/locate it again
*/
- OperationDepsNode *add_operation(eDepsOperation_Type optype,
- DepsEvalOperationCb op,
+ OperationDepsNode *add_operation(const DepsEvalOperationCb& op,
eDepsOperation_Code opcode,
- const string &name);
+ const char *name,
+ int name_tag);
+
+ /* Entry/exit operations management.
+ *
+ * Use those instead of direct set since this will perform sanity checks.
+ */
+ void set_entry_operation(OperationDepsNode *op_node);
+ void set_exit_operation(OperationDepsNode *op_node);
- void remove_operation(eDepsOperation_Code opcode, const string &name);
void clear_operations();
void tag_update(Depsgraph *graph);
@@ -137,7 +131,7 @@ struct ComponentDepsNode : public DepsNode {
OperationDepsNode *get_entry_operation();
OperationDepsNode *get_exit_operation();
- void finalize_build();
+ void finalize_build(Depsgraph *graph);
IDDepsNode *owner;
@@ -157,9 +151,6 @@ struct ComponentDepsNode : public DepsNode {
OperationDepsNode *exit_operation;
// XXX: a poll() callback to check if component's first node can be started?
-
- /* Temporary bitmask, used during graph construction. */
- unsigned int layers;
};
/* ---------------------------------------- */
@@ -194,7 +185,7 @@ struct PoseComponentDepsNode : public ComponentDepsNode {
/* Bone Component */
struct BoneComponentDepsNode : public ComponentDepsNode {
- void init(const ID *id, const string &subdata);
+ void init(const ID *id, const char *subdata);
struct bPoseChannel *pchan; /* the bone that this component represents */
@@ -213,6 +204,14 @@ struct CacheComponentDepsNode : public ComponentDepsNode {
DEG_DEPSNODE_DECLARE;
};
+struct LayerCollectionsDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct CopyOnWriteDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
void deg_register_component_depsnodes();
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_operation.cc b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc
index 5847af29ac2..84b3d33f494 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_operation.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc
@@ -32,13 +32,11 @@
#include "MEM_guardedalloc.h"
-extern "C" {
#include "BLI_utildefines.h"
-} /* extern "C" */
+#include "BLI_ghash.h"
#include "intern/depsgraph.h"
#include "intern/depsgraph_intern.h"
-#include "util/deg_util_hash.h"
namespace DEG {
@@ -67,8 +65,8 @@ string OperationDepsNode::identifier() const
string OperationDepsNode::full_identifier() const
{
string owner_str = "";
- if (owner->type == DEPSNODE_TYPE_BONE) {
- owner_str = owner->owner->name + "." + owner->name;
+ if (owner->type == DEG_NODE_TYPE_BONE) {
+ owner_str = string(owner->owner->name) + "." + owner->name;
}
else {
owner_str = owner->owner->name;
@@ -78,6 +76,9 @@ string OperationDepsNode::full_identifier() const
void OperationDepsNode::tag_update(Depsgraph *graph)
{
+ if (flag & DEPSOP_FLAG_SKIP_FLUSH) {
+ flag &= ~DEPSOP_FLAG_SKIP_FLUSH;
+ }
if (flag & DEPSOP_FLAG_NEEDS_UPDATE) {
return;
}
@@ -86,7 +87,19 @@ void OperationDepsNode::tag_update(Depsgraph *graph)
graph->add_entry_tag(this);
}
-DEG_DEPSNODE_DEFINE(OperationDepsNode, DEPSNODE_TYPE_OPERATION, "Operation");
+void OperationDepsNode::set_as_entry()
+{
+ BLI_assert(owner != NULL);
+ owner->set_entry_operation(this);
+}
+
+void OperationDepsNode::set_as_exit()
+{
+ BLI_assert(owner != NULL);
+ owner->set_exit_operation(this);
+}
+
+DEG_DEPSNODE_DEFINE(OperationDepsNode, DEG_NODE_TYPE_OPERATION, "Operation");
static DepsNodeFactoryImpl<OperationDepsNode> DNTI_OPERATION;
void deg_register_operation_depsnodes()
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_operation.h b/source/blender/depsgraph/intern/nodes/deg_node_operation.h
index 598393054db..8a1fadd9c6c 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_operation.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.h
@@ -44,21 +44,21 @@ typedef enum eDepsOperation_Flag {
DEPSOP_FLAG_NEEDS_UPDATE = (1 << 0),
/* node was directly modified, causing need for update */
- /* XXX: intention is to make it easier to tell when we just need to
- * take subgraphs.
- */
DEPSOP_FLAG_DIRECTLY_MODIFIED = (1 << 1),
/* Operation is evaluated using CPython; has GIL and security
* implications...
*/
- DEPSOP_FLAG_USES_PYTHON = (1 << 2),
+ DEPSOP_FLAG_USES_PYTHON = (1 << 2),
+
+ /* Special flag which indicates that update tag sohuld not be flushed
+ * up to the dependent nodes.
+ */
+ DEPSOP_FLAG_SKIP_FLUSH = (1 << 3),
} eDepsOperation_Flag;
/* Atomic Operation - Base type for all operations */
struct OperationDepsNode : public DepsNode {
-
-
OperationDepsNode();
~OperationDepsNode();
@@ -72,21 +72,21 @@ struct OperationDepsNode : public DepsNode {
OperationDepsNode *get_entry_operation() { return this; }
OperationDepsNode *get_exit_operation() { return this; }
+ /* Set this operation as compoonent's entry/exit operation. */
+ void set_as_entry();
+ void set_as_exit();
+
/* Component that contains the operation. */
ComponentDepsNode *owner;
/* Callback for operation. */
DepsEvalOperationCb evaluate;
-
/* How many inlinks are we still waiting on before we can be evaluated. */
uint32_t num_links_pending;
float eval_priority;
bool scheduled;
- /* Stage of evaluation */
- eDepsOperation_Type optype;
-
/* Identifier for the operation being performed. */
eDepsOperation_Code opcode;
diff --git a/source/blender/depsgraph/util/deg_util_foreach.h b/source/blender/depsgraph/util/deg_util_foreach.h
index 14cf4fc11ed..e00aa5dbb5e 100644
--- a/source/blender/depsgraph/util/deg_util_foreach.h
+++ b/source/blender/depsgraph/util/deg_util_foreach.h
@@ -36,33 +36,5 @@
# include <boost/foreach.hpp>
# define foreach BOOST_FOREACH
#else
-#pragma message("No available foreach() implementation. Using stub instead, disabling new depsgraph")
-
-#ifndef WITH_LEGACY_DEPSGRAPH
-# error "Unable to build new depsgraph and legacy one is disabled."
-#endif
-
-#define DISABLE_NEW_DEPSGRAPH
-
-# define foreach(x, y) for (x; false; (void)y)
+# error "Depsgraph requires either Boost or C++11 for range-based loops."
#endif
-
-#define GHASH_FOREACH_BEGIN(type, var, what) \
- do { \
- GHashIterator gh_iter##var; \
- GHASH_ITER(gh_iter##var, what) { \
- type var = reinterpret_cast<type>(BLI_ghashIterator_getValue(&gh_iter##var)); \
-
-#define GHASH_FOREACH_END() \
- } \
- } while(0)
-
-#define GSET_FOREACH_BEGIN(type, var, what) \
- do { \
- GSetIterator gh_iter##var; \
- GSET_ITER(gh_iter##var, what) { \
- type var = reinterpret_cast<type>(BLI_gsetIterator_getKey(&gh_iter##var)); \
-
-#define GSET_FOREACH_END() \
- } \
- } while(0)
diff --git a/source/blender/depsgraph/util/deg_util_function.h b/source/blender/depsgraph/util/deg_util_function.h
index 1e34ae04d9a..da31bb037f9 100644
--- a/source/blender/depsgraph/util/deg_util_function.h
+++ b/source/blender/depsgraph/util/deg_util_function.h
@@ -47,64 +47,5 @@ using boost::function;
#define function_bind boost::bind
#else
-
-#pragma message("No available function binding implementation. Using stub instead, disabling new depsgraph")
-
-#ifndef WITH_LEGACY_DEPSGRAPH
-# error "Unable to build new depsgraph and legacy one is disabled."
-#endif
-
-#define DISABLE_NEW_DEPSGRAPH
-
-#include "BLI_utildefines.h"
-#include <cstdlib>
-
-template<typename T>
-class function {
-public:
- function() {};
- function(void *) {}
- operator bool() const { return false; }
- bool operator== (void *) { return false; }
-
- template<typename T1>
- void operator() (T1) {
- BLI_assert(!"Should not be used");
- }
-};
-
-class Wrap {
-public:
- Wrap() {}
- template <typename T>
- Wrap(T /*arg*/) {}
-};
-
-template <typename T>
-void *function_bind(T func,
- Wrap arg1 = Wrap(),
- Wrap arg2 = Wrap(),
- Wrap arg3 = Wrap(),
- Wrap arg4 = Wrap(),
- Wrap arg5 = Wrap(),
- Wrap arg6 = Wrap(),
- Wrap arg7 = Wrap())
-{
- BLI_assert(!"Should not be used");
- (void)func;
- (void)arg1;
- (void)arg2;
- (void)arg3;
- (void)arg4;
- (void)arg5;
- (void)arg6;
- (void)arg7;
- return NULL;
-}
-
-#define _1 Wrap()
-#define _2 Wrap()
-#define _3 Wrap()
-#define _4 Wrap()
-
+# error "Depsgraph requires either Boost or C++11 for function bindings."
#endif
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
new file mode 100644
index 00000000000..4b760f68705
--- /dev/null
+++ b/source/blender/draw/CMakeLists.txt
@@ -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.
+#
+# 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_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_particles.c
+ intern/draw_common.c
+ intern/draw_manager.c
+ intern/draw_manager_text.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_metaball_mode.c
+ modes/edit_surface_mode.c
+ modes/edit_text_mode.c
+ modes/object_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/clay/clay_engine.c
+ engines/eevee/eevee_data.c
+ engines/eevee/eevee_engine.c
+ engines/eevee/eevee_lights.c
+ engines/eevee/eevee_lightprobes.c
+ engines/eevee/eevee_materials.c
+ engines/eevee/eevee_effects.c
+ engines/external/external_engine.c
+
+ DRW_engine.h
+ intern/DRW_render.h
+ intern/draw_cache.h
+ intern/draw_cache_impl.h
+ intern/draw_common.h
+ intern/draw_manager_text.h
+ intern/draw_view.h
+ modes/draw_mode_engines.h
+ engines/basic/basic_engine.h
+ engines/clay/clay_engine.h
+ engines/eevee/eevee_engine.h
+ engines/eevee/eevee_lut.h
+ engines/eevee/eevee_private.h
+ engines/external/external_engine.h
+)
+
+if(WITH_CLAY_ENGINE)
+ add_definitions(-DWITH_CLAY_ENGINE)
+endif()
+
+data_to_c_simple(engines/clay/shaders/clay_frag.glsl SRC)
+data_to_c_simple(engines/clay/shaders/clay_vert.glsl SRC)
+data_to_c_simple(engines/clay/shaders/clay_particle_vert.glsl SRC)
+data_to_c_simple(engines/clay/shaders/clay_particle_strand_frag.glsl SRC)
+data_to_c_simple(engines/clay/shaders/ssao_alchemy.glsl SRC)
+data_to_c_simple(engines/clay/shaders/ssao_groundtruth.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/ambient_occlusion_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_minmaxz_frag.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_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_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_geom.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_dof_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_motion_blur_frag.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_geom.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_store_geom.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/shadow_store_vert.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/bsdf_lut_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/bsdf_direct_lib.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/ltc_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/volumetric_frag.glsl SRC)
+
+data_to_c_simple(modes/shaders/common_globals_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_loosevert_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_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_frag.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/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_grid_frag.glsl SRC)
+data_to_c_simple(modes/shaders/object_grid_vert.glsl SRC)
+data_to_c_simple(modes/shaders/object_particle_prim_vert.glsl SRC)
+data_to_c_simple(modes/shaders/object_particle_prim_frag.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_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)
+
+list(APPEND INC
+)
+
+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..b780e86b9ec
--- /dev/null
+++ b/source/blender/draw/DRW_engine.h
@@ -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 DRW_engine.h
+ * \ingroup draw
+ */
+
+#ifndef __DRW_ENGINE_H__
+#define __DRW_ENGINE_H__
+
+struct ARegion;
+struct CollectionEngineSettings;
+struct Depsgraph;
+struct DRWPass;
+struct Material;
+struct Scene;
+struct DrawEngineType;
+struct IDProperty;
+struct bContext;
+struct Object;
+struct SceneLayer;
+struct ViewContext;
+struct ViewportEngineData;
+struct View3D;
+struct rcti;
+struct GPUOffScreen;
+
+#include "BLI_sys_types.h" /* for bool */
+
+/* Buffer and textures used by the viewport by default */
+typedef struct DefaultFramebufferList {
+ struct GPUFrameBuffer *default_fb;
+} DefaultFramebufferList;
+
+typedef struct DefaultTextureList {
+ struct GPUTexture *color;
+ struct GPUTexture *depth;
+} DefaultTextureList;
+
+void DRW_engines_register(void);
+void DRW_engines_free(void);
+
+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);
+
+void DRW_draw_view(const struct bContext *C);
+
+void DRW_draw_render_loop_ex(
+ struct Depsgraph *graph,
+ struct ARegion *ar, struct View3D *v3d,
+ const struct bContext *evil_C);
+void DRW_draw_render_loop(
+ struct Depsgraph *graph,
+ struct ARegion *ar, struct View3D *v3d);
+void DRW_draw_render_loop_offscreen(
+ struct Depsgraph *graph,
+ struct ARegion *ar, struct View3D *v3d,
+ struct GPUOffScreen *ofs);
+void DRW_draw_select_loop(
+ struct Depsgraph *graph,
+ struct ARegion *ar, struct View3D *v3d,
+ bool use_obedit_skip, bool use_nearest, const struct rcti *rect);
+void DRW_draw_depth_loop(
+ struct Depsgraph *graph,
+ struct ARegion *ar, struct View3D *v3d);
+
+/* This is here because GPUViewport needs it */
+void DRW_pass_free(struct DRWPass *pass);
+
+/* Mode engines initialization */
+void OBJECT_collection_settings_create(struct IDProperty *properties);
+void EDIT_MESH_collection_settings_create(struct IDProperty *properties);
+void EDIT_ARMATURE_collection_settings_create(struct IDProperty *properties);
+void PAINT_WEIGHT_collection_settings_create(struct IDProperty *properties);
+void PAINT_VERTEX_collection_settings_create(struct IDProperty *properties);
+
+#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..d1afb0b4a1e
--- /dev/null
+++ b/source/blender/draw/engines/basic/basic_engine.c
@@ -0,0 +1,257 @@
+/*
+ * 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
+ *
+ * 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 "GPU_shader.h"
+
+#include "basic_engine.h"
+/* Shaders */
+
+#define BASIC_ENGINE "BLENDER_BASIC"
+
+/* we may want this later? */
+#define USE_DEPTH
+
+/* *********** LISTS *********** */
+
+/* GPUViewport.storage
+ * Is freed everytime the viewport engine changes */
+typedef struct BASIC_Storage {
+ int dummy;
+} BASIC_Storage;
+
+typedef struct BASIC_StorageList {
+ struct BASIC_Storage *storage;
+ struct BASIC_PrivateData *g_data;
+} BASIC_StorageList;
+
+typedef struct BASIC_FramebufferList {
+ /* default */
+ struct GPUFrameBuffer *default_fb;
+ /* engine specific */
+#ifdef USE_DEPTH
+ struct GPUFrameBuffer *dupli_depth;
+#endif
+} BASIC_FramebufferList;
+
+typedef struct BASIC_TextureList {
+ /* default */
+ struct GPUTexture *color;
+#ifdef USE_DEPTH
+ struct GPUTexture *depth;
+ /* engine specific */
+ struct GPUTexture *depth_dup;
+#endif
+} BASIC_TextureList;
+
+typedef struct BASIC_PassList {
+#ifdef USE_DEPTH
+ struct DRWPass *depth_pass;
+ struct DRWPass *depth_pass_cull;
+#endif
+ struct DRWPass *color_pass;
+} BASIC_PassList;
+
+typedef struct BASIC_Data {
+ void *engine_type;
+ BASIC_FramebufferList *fbl;
+ BASIC_TextureList *txl;
+ BASIC_PassList *psl;
+ BASIC_StorageList *stl;
+} BASIC_Data;
+
+/* *********** STATIC *********** */
+
+static struct {
+#ifdef USE_DEPTH
+ /* Depth Pre Pass */
+ struct GPUShader *depth_sh;
+#endif
+ /* Shading Pass */
+ struct GPUShader *color_sh;
+} e_data = {NULL}; /* Engine data */
+
+typedef struct BASIC_PrivateData {
+#ifdef USE_DEPTH
+ DRWShadingGroup *depth_shgrp;
+ DRWShadingGroup *depth_shgrp_cull;
+#endif
+ DRWShadingGroup *color_shgrp;
+} BASIC_PrivateData; /* Transient data */
+
+/* Functions */
+
+static void BASIC_engine_init(void *vedata)
+{
+ BASIC_StorageList *stl = ((BASIC_Data *)vedata)->stl;
+ BASIC_TextureList *txl = ((BASIC_Data *)vedata)->txl;
+ BASIC_FramebufferList *fbl = ((BASIC_Data *)vedata)->fbl;
+
+#ifdef USE_DEPTH
+ /* Depth prepass */
+ if (!e_data.depth_sh) {
+ e_data.depth_sh = DRW_shader_create_3D_depth_only();
+ }
+#endif
+
+ /* Shading pass */
+ if (!e_data.color_sh) {
+ e_data.color_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+
+ if (!stl->storage) {
+ stl->storage = MEM_callocN(sizeof(BASIC_Storage), "BASIC_Storage");
+ }
+
+#ifdef USE_DEPTH
+ if (DRW_state_is_fbo()) {
+ const float *viewport_size = DRW_viewport_size_get();
+ DRWFboTexture tex = {&txl->depth_dup, DRW_TEX_DEPTH_24, 0};
+ DRW_framebuffer_init(&fbl->dupli_depth, &draw_engine_basic_type,
+ (int)viewport_size[0], (int)viewport_size[1],
+ &tex, 1);
+ }
+#endif
+}
+
+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__);
+ }
+
+#ifdef USE_DEPTH
+ /* Depth Pass */
+ {
+ psl->depth_pass = DRW_pass_create("Depth Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
+ 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 | DRW_STATE_CULL_BACK);
+ stl->g_data->depth_shgrp_cull = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass_cull);
+ }
+#endif
+
+ /* Color Pass */
+ {
+ psl->color_pass = DRW_pass_create("Color Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL);
+ stl->g_data->color_shgrp = DRW_shgroup_create(e_data.color_sh, psl->color_pass);
+ }
+}
+
+static void BASIC_cache_populate(void *vedata, Object *ob)
+{
+ BASIC_StorageList *stl = ((BASIC_Data *)vedata)->stl;
+
+ if (!DRW_object_is_renderable(ob))
+ return;
+
+ struct Gwn_Batch *geom = DRW_cache_object_surface_get(ob);
+ if (geom) {
+ bool do_cull = false; /* TODO (we probably wan't to take this from the viewport?) */
+#ifdef USE_DEPTH
+ /* Depth Prepass */
+ DRW_shgroup_call_add((do_cull) ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp, geom, ob->obmat);
+#endif
+ /* Shading */
+ DRW_shgroup_call_add(stl->g_data->color_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;
+ BASIC_FramebufferList *fbl = ((BASIC_Data *)vedata)->fbl;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+#ifdef USE_DEPTH
+ /* Pass 1 : Depth pre-pass */
+ DRW_draw_pass(psl->depth_pass);
+ DRW_draw_pass(psl->depth_pass_cull);
+
+ /* Pass 2 : Duplicate depth */
+ /* Unless we go for deferred shading we need this to avoid manual depth test and artifacts */
+ if (DRW_state_is_fbo()) {
+ DRW_framebuffer_blit(dfbl->default_fb, fbl->dupli_depth, true);
+ }
+#endif
+
+ /* Pass 3 : Shading */
+ DRW_draw_pass(psl->color_pass);
+}
+
+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
+};
+
+/* 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, 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/clay/clay_engine.c b/source/blender/draw/engines/clay/clay_engine.c
new file mode 100644
index 00000000000..d92f0e6aad2
--- /dev/null
+++ b/source/blender/draw/engines/clay/clay_engine.c
@@ -0,0 +1,945 @@
+/*
+ * 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
+ *
+ */
+
+#include "DRW_render.h"
+
+#include "DNA_particle_types.h"
+
+#include "BKE_icons.h"
+#include "BKE_idprop.h"
+#include "BKE_main.h"
+#include "BKE_particle.h"
+
+#include "BLI_dynstr.h"
+#include "BLI_rand.h"
+
+#include "GPU_shader.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "UI_resources.h"
+#include "UI_interface_icons.h"
+
+#include "clay_engine.h"
+#include "../eevee/eevee_lut.h" /* TODO find somewhere to share blue noise Table */
+
+#ifdef WITH_CLAY_ENGINE
+/* Shaders */
+
+#define CLAY_ENGINE "BLENDER_CLAY"
+
+#define MAX_CLAY_MAT 512 /* 512 = 9 bit material id */
+
+#define SHADER_DEFINES \
+ "#define MAX_MATERIAL " STRINGIFY(MAX_CLAY_MAT) "\n" \
+ "#define USE_ROTATION\n" \
+ "#define USE_AO\n" \
+ "#define USE_HSV\n"
+
+extern char datatoc_clay_frag_glsl[];
+extern char datatoc_clay_vert_glsl[];
+extern char datatoc_clay_particle_vert_glsl[];
+extern char datatoc_clay_particle_strand_frag_glsl[];
+extern char datatoc_ssao_alchemy_glsl[];
+
+/* *********** LISTS *********** */
+
+/**
+ * UBOs data needs to be 16 byte aligned (size of vec4)
+ *
+ * Reminder: float, int, bool are 4 bytes
+ *
+ * \note struct is expected to be initialized with all pad-bits zero'd
+ * so we can use 'memcmp' to check for duplicates. Possibly hash data later.
+ */
+typedef struct CLAY_UBO_Material {
+ float ssao_params_var[4];
+ /* - 16 -*/
+ float matcap_hsv[3];
+ float matcap_id; /* even float encoding have enough precision */
+ /* - 16 -*/
+ float matcap_rot[2];
+ float pad[2]; /* ensure 16 bytes alignement */
+} CLAY_UBO_Material; /* 48 bytes */
+BLI_STATIC_ASSERT_ALIGN(CLAY_UBO_Material, 16)
+
+typedef struct CLAY_HAIR_UBO_Material {
+ float hair_randomness;
+ float matcap_id;
+ float matcap_rot[2];
+ float matcap_hsv[3];
+ float pad;
+} CLAY_HAIR_UBO_Material; /* 32 bytes */
+BLI_STATIC_ASSERT_ALIGN(CLAY_HAIR_UBO_Material, 16)
+
+typedef struct CLAY_UBO_Storage {
+ CLAY_UBO_Material materials[MAX_CLAY_MAT];
+} CLAY_UBO_Storage;
+
+typedef struct CLAY_HAIR_UBO_Storage {
+ CLAY_HAIR_UBO_Material materials[MAX_CLAY_MAT];
+} CLAY_HAIR_UBO_Storage;
+
+/* GPUViewport.storage
+ * Is freed everytime the viewport engine changes */
+typedef struct CLAY_Storage {
+ /* Materials Parameter UBO */
+ CLAY_UBO_Storage mat_storage;
+ CLAY_HAIR_UBO_Storage hair_mat_storage;
+ int ubo_current_id;
+ int hair_ubo_current_id;
+ DRWShadingGroup *shgrps[MAX_CLAY_MAT];
+ DRWShadingGroup *shgrps_flat[MAX_CLAY_MAT];
+ DRWShadingGroup *hair_shgrps[MAX_CLAY_MAT];
+} CLAY_Storage;
+
+typedef struct CLAY_StorageList {
+ struct CLAY_Storage *storage;
+ struct GPUUniformBuffer *mat_ubo;
+ struct GPUUniformBuffer *hair_mat_ubo;
+ struct CLAY_PrivateData *g_data;
+} CLAY_StorageList;
+
+typedef struct CLAY_FramebufferList {
+ /* default */
+ struct GPUFrameBuffer *default_fb;
+ /* engine specific */
+ struct GPUFrameBuffer *dupli_depth;
+} CLAY_FramebufferList;
+
+typedef struct CLAY_PassList {
+ struct DRWPass *depth_pass;
+ struct DRWPass *depth_pass_cull;
+ struct DRWPass *clay_pass;
+ struct DRWPass *clay_pass_flat;
+ struct DRWPass *hair_pass;
+} CLAY_PassList;
+
+typedef struct CLAY_Data {
+ void *engine_type;
+ CLAY_FramebufferList *fbl;
+ DRWViewportEmptyList *txl;
+ CLAY_PassList *psl;
+ CLAY_StorageList *stl;
+} CLAY_Data;
+
+typedef struct CLAY_SceneLayerData {
+ struct GPUTexture *jitter_tx;
+ struct GPUUniformBuffer *sampling_ubo;
+ int cached_sample_num;
+} CLAY_SceneLayerData;
+
+/* *********** STATIC *********** */
+
+static struct {
+ /* Depth Pre Pass */
+ struct GPUShader *depth_sh;
+ /* Shading Pass */
+ struct GPUShader *clay_sh;
+ struct GPUShader *clay_flat_sh;
+ struct GPUShader *hair_sh;
+
+ /* Matcap textures */
+ struct GPUTexture *matcap_array;
+ float matcap_colors[24][3];
+
+ /* Ssao */
+ float winmat[4][4];
+ float viewvecs[3][4];
+ float ssao_params[4];
+
+ /* Just a serie of int from 0 to MAX_CLAY_MAT-1 */
+ int ubo_mat_idxs[MAX_CLAY_MAT];
+
+ /* engine specific */
+ struct GPUTexture *depth_dup;
+} e_data = {NULL}; /* Engine data */
+
+typedef struct CLAY_PrivateData {
+ DRWShadingGroup *depth_shgrp;
+ DRWShadingGroup *depth_shgrp_select;
+ DRWShadingGroup *depth_shgrp_active;
+ DRWShadingGroup *depth_shgrp_cull;
+ DRWShadingGroup *depth_shgrp_cull_select;
+ DRWShadingGroup *depth_shgrp_cull_active;
+} CLAY_PrivateData; /* Transient data */
+
+/* Functions */
+
+static void clay_scene_layer_data_free(void *storage)
+{
+ CLAY_SceneLayerData *sldata = (CLAY_SceneLayerData *)storage;
+
+ DRW_UBO_FREE_SAFE(sldata->sampling_ubo);
+ DRW_TEXTURE_FREE_SAFE(sldata->jitter_tx);
+}
+
+static CLAY_SceneLayerData *CLAY_scene_layer_data_get(void)
+{
+ CLAY_SceneLayerData **sldata = (CLAY_SceneLayerData **)DRW_scene_layer_engine_data_get(&draw_engine_clay_type, &clay_scene_layer_data_free);
+
+ if (*sldata == NULL) {
+ *sldata = MEM_callocN(sizeof(**sldata), "CLAY_SceneLayerData");
+ }
+
+ return *sldata;
+}
+
+static void add_icon_to_rect(PreviewImage *prv, float *final_rect, int layer)
+{
+ int image_size = prv->w[0] * prv->h[0];
+ float *new_rect = &final_rect[image_size * 4 * layer];
+
+ IMB_buffer_float_from_byte(new_rect, (unsigned char *)prv->rect[0], IB_PROFILE_SRGB, IB_PROFILE_SRGB,
+ false, prv->w[0], prv->h[0], prv->w[0], prv->w[0]);
+
+ /* Find overall color */
+ for (int y = 0; y < 4; ++y) {
+ for (int x = 0; x < 4; ++x) {
+ e_data.matcap_colors[layer][0] += new_rect[y * 512 * 128 * 4 + x * 128 * 4 + 0];
+ e_data.matcap_colors[layer][1] += new_rect[y * 512 * 128 * 4 + x * 128 * 4 + 1];
+ e_data.matcap_colors[layer][2] += new_rect[y * 512 * 128 * 4 + x * 128 * 4 + 2];
+ }
+ }
+
+ e_data.matcap_colors[layer][0] /= 16.0f * 2.0f; /* the * 2 is to darken for shadows */
+ e_data.matcap_colors[layer][1] /= 16.0f * 2.0f;
+ e_data.matcap_colors[layer][2] /= 16.0f * 2.0f;
+}
+
+static struct GPUTexture *load_matcaps(PreviewImage *prv[24], int nbr)
+{
+ struct GPUTexture *tex;
+ int w = prv[0]->w[0];
+ int h = prv[0]->h[0];
+ float *final_rect = MEM_callocN(sizeof(float) * 4 * w * h * nbr, "Clay Matcap array rect");
+
+ for (int i = 0; i < nbr; ++i) {
+ add_icon_to_rect(prv[i], final_rect, i);
+ BKE_previewimg_free(&prv[i]);
+ }
+
+ tex = DRW_texture_create_2D_array(w, h, nbr, DRW_TEX_RGBA_8, DRW_TEX_FILTER, final_rect);
+ MEM_freeN(final_rect);
+
+ return tex;
+}
+
+static int matcap_to_index(int matcap)
+{
+ switch (matcap) {
+ case ICON_MATCAP_01: return 0;
+ case ICON_MATCAP_02: return 1;
+ case ICON_MATCAP_03: return 2;
+ case ICON_MATCAP_04: return 3;
+ case ICON_MATCAP_05: return 4;
+ case ICON_MATCAP_06: return 5;
+ case ICON_MATCAP_07: return 6;
+ case ICON_MATCAP_08: return 7;
+ case ICON_MATCAP_09: return 8;
+ case ICON_MATCAP_10: return 9;
+ case ICON_MATCAP_11: return 10;
+ case ICON_MATCAP_12: return 11;
+ case ICON_MATCAP_13: return 12;
+ case ICON_MATCAP_14: return 13;
+ case ICON_MATCAP_15: return 14;
+ case ICON_MATCAP_16: return 15;
+ case ICON_MATCAP_17: return 16;
+ case ICON_MATCAP_18: return 17;
+ case ICON_MATCAP_19: return 18;
+ case ICON_MATCAP_20: return 19;
+ case ICON_MATCAP_21: return 20;
+ case ICON_MATCAP_22: return 21;
+ case ICON_MATCAP_23: return 22;
+ case ICON_MATCAP_24: return 23;
+ }
+ BLI_assert(!"Should not happen");
+ return 0;
+}
+
+/* Van der Corput sequence */
+/* TODO this is duplicated code from eevee_lightprobes.c */
+ /* From http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html */
+static float radical_inverse(int i) {
+ unsigned int bits = (unsigned int)i;
+ bits = (bits << 16u) | (bits >> 16u);
+ bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
+ bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
+ bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
+ bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
+ return (float)bits * 2.3283064365386963e-10f;
+}
+
+/* Using Hammersley distribution */
+static float *create_disk_samples(int num_samples)
+{
+ /* vec4 to ensure memory alignment. */
+ float (*texels)[4] = MEM_mallocN(sizeof(float[4]) * num_samples, "concentric_tex");
+ const float num_samples_inv = 1.0f / num_samples;
+
+ for (int i = 0; i < num_samples; i++) {
+ float r = (i + 0.5f) * num_samples_inv;
+ float phi = radical_inverse(i) * 2.0f * M_PI;
+ texels[i][0] = cosf(phi);
+ texels[i][1] = sinf(phi);
+ /* This deliberatly 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, ltc_mag_ggx, ltc_mat_ggx);
+
+ return DRW_texture_create_2D(64, 64, DRW_TEX_RGB_16, DRW_TEX_FILTER | DRW_TEX_WRAP, &jitter[0][0]);
+}
+
+static void CLAY_engine_init(void *vedata)
+{
+ CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl;
+ CLAY_FramebufferList *fbl = ((CLAY_Data *)vedata)->fbl;
+ CLAY_SceneLayerData *sldata = CLAY_scene_layer_data_get();
+
+ /* Create Texture Array */
+ if (!e_data.matcap_array) {
+ PreviewImage *prv[24]; /* For now use all of the 24 internal matcaps */
+
+ /* TODO only load used matcaps */
+ prv[0] = UI_icon_to_preview(ICON_MATCAP_01);
+ prv[1] = UI_icon_to_preview(ICON_MATCAP_02);
+ prv[2] = UI_icon_to_preview(ICON_MATCAP_03);
+ prv[3] = UI_icon_to_preview(ICON_MATCAP_04);
+ prv[4] = UI_icon_to_preview(ICON_MATCAP_05);
+ prv[5] = UI_icon_to_preview(ICON_MATCAP_06);
+ prv[6] = UI_icon_to_preview(ICON_MATCAP_07);
+ prv[7] = UI_icon_to_preview(ICON_MATCAP_08);
+ prv[8] = UI_icon_to_preview(ICON_MATCAP_09);
+ prv[9] = UI_icon_to_preview(ICON_MATCAP_10);
+ prv[10] = UI_icon_to_preview(ICON_MATCAP_11);
+ prv[11] = UI_icon_to_preview(ICON_MATCAP_12);
+ prv[12] = UI_icon_to_preview(ICON_MATCAP_13);
+ prv[13] = UI_icon_to_preview(ICON_MATCAP_14);
+ prv[14] = UI_icon_to_preview(ICON_MATCAP_15);
+ prv[15] = UI_icon_to_preview(ICON_MATCAP_16);
+ prv[16] = UI_icon_to_preview(ICON_MATCAP_17);
+ prv[17] = UI_icon_to_preview(ICON_MATCAP_18);
+ prv[18] = UI_icon_to_preview(ICON_MATCAP_19);
+ prv[19] = UI_icon_to_preview(ICON_MATCAP_20);
+ prv[20] = UI_icon_to_preview(ICON_MATCAP_21);
+ prv[21] = UI_icon_to_preview(ICON_MATCAP_22);
+ prv[22] = UI_icon_to_preview(ICON_MATCAP_23);
+ prv[23] = UI_icon_to_preview(ICON_MATCAP_24);
+
+ e_data.matcap_array = load_matcaps(prv, 24);
+ }
+
+ /* Depth prepass */
+ if (!e_data.depth_sh) {
+ e_data.depth_sh = DRW_shader_create_3D_depth_only();
+ }
+
+ /* Shading pass */
+ if (!e_data.clay_sh) {
+ DynStr *ds = BLI_dynstr_new();
+ char *matcap_with_ao;
+
+ BLI_dynstr_append(ds, datatoc_clay_frag_glsl);
+ BLI_dynstr_append(ds, datatoc_ssao_alchemy_glsl);
+
+ matcap_with_ao = BLI_dynstr_get_cstring(ds);
+
+ e_data.clay_sh = DRW_shader_create(
+ datatoc_clay_vert_glsl, NULL, matcap_with_ao,
+ SHADER_DEFINES);
+ e_data.clay_flat_sh = DRW_shader_create(
+ datatoc_clay_vert_glsl, NULL, matcap_with_ao,
+ SHADER_DEFINES
+ "#define USE_FLAT_NORMAL\n");
+
+ BLI_dynstr_free(ds);
+ MEM_freeN(matcap_with_ao);
+ }
+
+ if (!e_data.hair_sh) {
+ e_data.hair_sh = DRW_shader_create(
+ datatoc_clay_particle_vert_glsl, NULL, datatoc_clay_particle_strand_frag_glsl,
+ "#define MAX_MATERIAL 512\n");
+ }
+
+ if (!stl->storage) {
+ stl->storage = MEM_callocN(sizeof(CLAY_Storage), "CLAY_Storage");
+ }
+
+ if (!stl->mat_ubo) {
+ stl->mat_ubo = DRW_uniformbuffer_create(sizeof(CLAY_UBO_Storage), NULL);
+ }
+
+ if (!stl->hair_mat_ubo) {
+ stl->hair_mat_ubo = DRW_uniformbuffer_create(sizeof(CLAY_HAIR_UBO_Storage), NULL);
+ }
+
+ if (e_data.ubo_mat_idxs[1] == 0) {
+ /* Just int to have pointers to them */
+ for (int i = 0; i < MAX_CLAY_MAT; ++i) {
+ e_data.ubo_mat_idxs[i] = i;
+ }
+ }
+
+ if (DRW_state_is_fbo()) {
+ const float *viewport_size = DRW_viewport_size_get();
+ DRWFboTexture tex = {&e_data.depth_dup, DRW_TEX_DEPTH_24, DRW_TEX_TEMP};
+ DRW_framebuffer_init(&fbl->dupli_depth, &draw_engine_clay_type,
+ (int)viewport_size[0], (int)viewport_size[1],
+ &tex, 1);
+ }
+
+ /* SSAO setup */
+ {
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ SceneLayer *scene_layer = draw_ctx->scene_layer;
+ IDProperty *props = BKE_scene_layer_engine_evaluated_get(
+ scene_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_CLAY);
+ int ssao_samples = BKE_collection_engine_property_value_get_int(props, "ssao_samples");
+
+ float invproj[4][4];
+ float dfdyfacs[2];
+ 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();
+
+ DRW_state_dfdy_factors_get(dfdyfacs);
+
+ e_data.ssao_params[0] = ssao_samples;
+ e_data.ssao_params[1] = size[0] / 64.0;
+ e_data.ssao_params[2] = size[1] / 64.0;
+ e_data.ssao_params[3] = dfdyfacs[1]; /* dfdy sign for offscreen */
+
+ /* invert the view matrix */
+ DRW_viewport_matrix_get(e_data.winmat, DRW_MAT_WIN);
+ invert_m4_m4(invproj, e_data.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(e_data.viewvecs[i], viewvecs[i]);
+ }
+
+ /* we need to store the differences */
+ e_data.viewvecs[1][0] -= e_data.viewvecs[0][0];
+ e_data.viewvecs[1][1] = e_data.viewvecs[2][1] - e_data.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]);
+ e_data.viewvecs[1][2] = vec_far[2] - e_data.viewvecs[0][2];
+ }
+
+ /* AO Samples Tex */
+ if (sldata->sampling_ubo && (sldata->cached_sample_num != ssao_samples)) {
+ DRW_UBO_FREE_SAFE(sldata->sampling_ubo);
+ DRW_TEXTURE_FREE_SAFE(sldata->jitter_tx);
+ }
+
+ if (sldata->sampling_ubo == NULL) {
+ float *samples = create_disk_samples(ssao_samples);
+ sldata->jitter_tx = create_jitter_texture(ssao_samples);
+ sldata->sampling_ubo = DRW_uniformbuffer_create(sizeof(float[4]) * ssao_samples, samples);
+ sldata->cached_sample_num = ssao_samples;
+ MEM_freeN(samples);
+ }
+ }
+}
+
+static DRWShadingGroup *CLAY_shgroup_create(CLAY_Data *UNUSED(vedata), DRWPass *pass, int *material_id, bool use_flat)
+{
+ CLAY_SceneLayerData *sldata = CLAY_scene_layer_data_get();
+ DRWShadingGroup *grp = DRW_shgroup_create(use_flat ? e_data.clay_flat_sh : e_data.clay_sh, pass);
+
+ DRW_shgroup_uniform_vec2(grp, "screenres", DRW_viewport_size_get(), 1);
+ DRW_shgroup_uniform_buffer(grp, "depthtex", &e_data.depth_dup);
+ DRW_shgroup_uniform_texture(grp, "matcaps", e_data.matcap_array);
+ DRW_shgroup_uniform_mat4(grp, "WinMatrix", (float *)e_data.winmat);
+ DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)e_data.viewvecs, 3);
+ DRW_shgroup_uniform_vec4(grp, "ssao_params", e_data.ssao_params, 1);
+ DRW_shgroup_uniform_vec3(grp, "matcaps_color[0]", (float *)e_data.matcap_colors, 24);
+
+ DRW_shgroup_uniform_int(grp, "mat_id", material_id, 1);
+
+ DRW_shgroup_uniform_texture(grp, "ssao_jitter", sldata->jitter_tx);
+ DRW_shgroup_uniform_block(grp, "samples_block", sldata->sampling_ubo);
+
+ return grp;
+}
+
+static DRWShadingGroup *CLAY_hair_shgroup_create(DRWPass *pass, int *material_id)
+{
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.hair_sh, pass);
+
+ DRW_shgroup_uniform_texture(grp, "matcaps", e_data.matcap_array);
+ DRW_shgroup_uniform_int(grp, "mat_id", material_id, 1);
+
+ return grp;
+}
+
+static int search_mat_to_ubo(CLAY_Storage *storage, const CLAY_UBO_Material *mat_ubo_test)
+{
+ /* For now just use a linear search and test all parameters */
+ /* TODO make a hash table */
+ for (int i = 0; i < storage->ubo_current_id; ++i) {
+ CLAY_UBO_Material *ubo = &storage->mat_storage.materials[i];
+ if (memcmp(ubo, mat_ubo_test, sizeof(*mat_ubo_test)) == 0) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+static int search_hair_mat_to_ubo(CLAY_Storage *storage, const CLAY_HAIR_UBO_Material *hair_mat_ubo_test)
+{
+ /* For now just use a linear search and test all parameters */
+ /* TODO make a hash table */
+ for (int i = 0; i < storage->hair_ubo_current_id; ++i) {
+ CLAY_HAIR_UBO_Material *ubo = &storage->hair_mat_storage.materials[i];
+ if (memcmp(ubo, hair_mat_ubo_test, sizeof(*hair_mat_ubo_test)) == 0) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+static int push_mat_to_ubo(CLAY_Storage *storage, const CLAY_UBO_Material *mat_ubo_test)
+{
+ int id = storage->ubo_current_id;
+ CLAY_UBO_Material *ubo = &storage->mat_storage.materials[id];
+
+ *ubo = *mat_ubo_test;
+
+ storage->ubo_current_id++;
+
+ return id;
+}
+
+static int push_hair_mat_to_ubo(CLAY_Storage *storage, const CLAY_HAIR_UBO_Material *hair_mat_ubo_test)
+{
+ int id = storage->hair_ubo_current_id;
+ CLAY_HAIR_UBO_Material *ubo = &storage->hair_mat_storage.materials[id];
+
+ *ubo = *hair_mat_ubo_test;
+
+ storage->hair_ubo_current_id++;
+
+ return id;
+}
+
+static int mat_in_ubo(CLAY_Storage *storage, const CLAY_UBO_Material *mat_ubo_test)
+{
+ /* Search material in UBO */
+ int id = search_mat_to_ubo(storage, mat_ubo_test);
+
+ /* if not found create it */
+ if (id == -1) {
+ id = push_mat_to_ubo(storage, mat_ubo_test);
+ }
+
+ return id;
+}
+
+static int hair_mat_in_ubo(CLAY_Storage *storage, const CLAY_HAIR_UBO_Material *hair_mat_ubo_test)
+{
+ /* Search material in UBO */
+ int id = search_hair_mat_to_ubo(storage, hair_mat_ubo_test);
+
+ /* if not found create it */
+ if (id == -1) {
+ id = push_hair_mat_to_ubo(storage, hair_mat_ubo_test);
+ }
+
+ return id;
+}
+
+static void ubo_mat_from_object(Object *ob, CLAY_UBO_Material *r_ubo)
+{
+ IDProperty *props = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_CLAY);
+
+ /* Default Settings */
+ float matcap_rot = BKE_collection_engine_property_value_get_float(props, "matcap_rotation");
+ float matcap_hue = BKE_collection_engine_property_value_get_float(props, "matcap_hue");
+ float matcap_sat = BKE_collection_engine_property_value_get_float(props, "matcap_saturation");
+ float matcap_val = BKE_collection_engine_property_value_get_float(props, "matcap_value");
+ float ssao_distance = BKE_collection_engine_property_value_get_float(props, "ssao_distance");
+ float ssao_factor_cavity = BKE_collection_engine_property_value_get_float(props, "ssao_factor_cavity");
+ float ssao_factor_edge = BKE_collection_engine_property_value_get_float(props, "ssao_factor_edge");
+ float ssao_attenuation = BKE_collection_engine_property_value_get_float(props, "ssao_attenuation");
+ int matcap_icon = BKE_collection_engine_property_value_get_int(props, "matcap_icon");
+
+ memset(r_ubo, 0x0, sizeof(*r_ubo));
+
+ r_ubo->matcap_rot[0] = cosf(matcap_rot * 3.14159f * 2.0f);
+ r_ubo->matcap_rot[1] = sinf(matcap_rot * 3.14159f * 2.0f);
+
+ r_ubo->matcap_hsv[0] = matcap_hue + 0.5f;
+ r_ubo->matcap_hsv[1] = matcap_sat * 2.0f;
+ r_ubo->matcap_hsv[2] = matcap_val * 2.0f;
+
+ r_ubo->ssao_params_var[0] = ssao_distance;
+ r_ubo->ssao_params_var[1] = ssao_factor_cavity;
+ r_ubo->ssao_params_var[2] = ssao_factor_edge;
+ r_ubo->ssao_params_var[3] = ssao_attenuation;
+ r_ubo->matcap_id = matcap_to_index(matcap_icon);
+}
+
+static void hair_ubo_mat_from_object(Object *ob, CLAY_HAIR_UBO_Material *r_ubo)
+{
+ IDProperty *props = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_CLAY);
+
+ /* Default Settings */
+ float matcap_rot = BKE_collection_engine_property_value_get_float(props, "matcap_rotation");
+ float matcap_hue = BKE_collection_engine_property_value_get_float(props, "matcap_hue");
+ float matcap_sat = BKE_collection_engine_property_value_get_float(props, "matcap_saturation");
+ float matcap_val = BKE_collection_engine_property_value_get_float(props, "matcap_value");
+ float hair_randomness = BKE_collection_engine_property_value_get_float(props, "hair_brightness_randomness");
+ int matcap_icon = BKE_collection_engine_property_value_get_int(props, "matcap_icon");
+
+ memset(r_ubo, 0x0, sizeof(*r_ubo));
+
+ r_ubo->matcap_rot[0] = cosf(matcap_rot * 3.14159f * 2.0f);
+ r_ubo->matcap_rot[1] = sinf(matcap_rot * 3.14159f * 2.0f);
+ r_ubo->matcap_hsv[0] = matcap_hue + 0.5f;
+ r_ubo->matcap_hsv[1] = matcap_sat * 2.0f;
+ r_ubo->matcap_hsv[2] = matcap_val * 2.0f;
+ r_ubo->hair_randomness = hair_randomness;
+ r_ubo->matcap_id = matcap_to_index(matcap_icon);
+}
+
+static DRWShadingGroup *CLAY_object_shgrp_get(
+ CLAY_Data *vedata, Object *ob, CLAY_StorageList *stl, CLAY_PassList *psl, bool use_flat)
+{
+ DRWShadingGroup **shgrps = use_flat ? stl->storage->shgrps_flat : stl->storage->shgrps;
+ CLAY_UBO_Material mat_ubo_test;
+
+ ubo_mat_from_object(ob, &mat_ubo_test);
+
+ int id = mat_in_ubo(stl->storage, &mat_ubo_test);
+
+ if (shgrps[id] == NULL) {
+ shgrps[id] = CLAY_shgroup_create(
+ vedata, use_flat ? psl->clay_pass_flat : psl->clay_pass, &e_data.ubo_mat_idxs[id], use_flat);
+ /* if it's the first shgrp, pass bind the material UBO */
+ if (stl->storage->ubo_current_id == 1) {
+ DRW_shgroup_uniform_block(shgrps[0], "material_block", stl->mat_ubo);
+ }
+ }
+
+ return shgrps[id];
+}
+
+static DRWShadingGroup *CLAY_hair_shgrp_get(Object *ob, CLAY_StorageList *stl, CLAY_PassList *psl)
+{
+ DRWShadingGroup **hair_shgrps = stl->storage->hair_shgrps;
+
+ CLAY_HAIR_UBO_Material hair_mat_ubo_test;
+ hair_ubo_mat_from_object(ob, &hair_mat_ubo_test);
+
+ int hair_id = hair_mat_in_ubo(stl->storage, &hair_mat_ubo_test);
+
+ if (hair_shgrps[hair_id] == NULL) {
+ hair_shgrps[hair_id] = CLAY_hair_shgroup_create(psl->hair_pass, &e_data.ubo_mat_idxs[hair_id]);
+ /* if it's the first shgrp, pass bind the material UBO */
+ if (stl->storage->hair_ubo_current_id == 1) {
+ DRW_shgroup_uniform_block(hair_shgrps[0], "material_block", stl->hair_mat_ubo);
+ }
+ }
+
+ return hair_shgrps[hair_id];
+}
+
+static DRWShadingGroup *CLAY_object_shgrp_default_mode_get(
+ CLAY_Data *vedata, Object *ob, CLAY_StorageList *stl, CLAY_PassList *psl)
+{
+ bool use_flat = DRW_object_is_flat_normal(ob);
+ return CLAY_object_shgrp_get(vedata, ob, stl, psl, use_flat);
+}
+
+static void CLAY_cache_init(void *vedata)
+{
+ CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl;
+ CLAY_StorageList *stl = ((CLAY_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);
+ 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 | DRW_STATE_CULL_BACK);
+ stl->g_data->depth_shgrp_cull = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass_cull);
+ }
+
+ /* Clay Pass */
+ {
+ psl->clay_pass = DRW_pass_create("Clay Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL);
+ stl->storage->ubo_current_id = 0;
+ memset(stl->storage->shgrps, 0, sizeof(DRWShadingGroup *) * MAX_CLAY_MAT);
+ }
+
+ /* Clay Pass (Flat) */
+ {
+ psl->clay_pass_flat = DRW_pass_create("Clay Pass Flat", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL);
+ memset(stl->storage->shgrps_flat, 0, sizeof(DRWShadingGroup *) * MAX_CLAY_MAT);
+ }
+
+ /* Hair Pass */
+ {
+ psl->hair_pass = DRW_pass_create(
+ "Hair Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_WIRE);
+ stl->storage->hair_ubo_current_id = 0;
+ memset(stl->storage->hair_shgrps, 0, sizeof(DRWShadingGroup *) * MAX_CLAY_MAT);
+ }
+}
+
+static void CLAY_cache_populate(void *vedata, Object *ob)
+{
+ CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl;
+ CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl;
+
+ DRWShadingGroup *clay_shgrp, *hair_shgrp;
+
+ if (!DRW_object_is_renderable(ob))
+ return;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const bool is_active = (ob == draw_ctx->obact);
+ if (is_active) {
+ if (DRW_object_is_mode_shade(ob) == true) {
+ return;
+ }
+ }
+
+ struct Gwn_Batch *geom = DRW_cache_object_surface_get(ob);
+ if (geom) {
+ IDProperty *ces_mode_ob = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_OBJECT, "");
+ const bool do_cull = BKE_collection_engine_property_value_get_bool(ces_mode_ob, "show_backface_culling");
+ const bool is_sculpt_mode = is_active && (ob->mode & OB_MODE_SCULPT) != 0;
+ const bool is_default_mode_shader = is_sculpt_mode;
+
+ /* Depth Prepass */
+ {
+ DRWShadingGroup *depth_shgrp = do_cull ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp;
+ if (is_sculpt_mode) {
+ DRW_shgroup_call_sculpt_add(depth_shgrp, ob, ob->obmat);
+ }
+ else {
+ DRW_shgroup_call_object_add(depth_shgrp, geom, ob);
+ }
+ }
+
+ /* Shading */
+ if (is_default_mode_shader) {
+ clay_shgrp = CLAY_object_shgrp_default_mode_get(vedata, ob, stl, psl);
+ }
+ else {
+ clay_shgrp = CLAY_object_shgrp_get(vedata, ob, stl, psl, false);
+ }
+
+ if (is_sculpt_mode) {
+ DRW_shgroup_call_sculpt_add(clay_shgrp, ob, ob->obmat);
+ }
+ else {
+ DRW_shgroup_call_add(clay_shgrp, geom, ob->obmat);
+ }
+ }
+
+ if (ob->type == OB_MESH) {
+ Scene *scene = draw_ctx->scene;
+ Object *obedit = scene->obedit;
+
+ if (ob != obedit) {
+ for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) {
+ if (psys_check_enabled(ob, psys, false)) {
+ ParticleSettings *part = psys->part;
+ int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
+
+ if (draw_as == PART_DRAW_PATH && !psys->pathcache && !psys->childcache) {
+ draw_as = PART_DRAW_DOT;
+ }
+
+ static float mat[4][4];
+ unit_m4(mat);
+
+ if (draw_as == PART_DRAW_PATH) {
+ geom = DRW_cache_particles_get_hair(psys, NULL);
+ hair_shgrp = CLAY_hair_shgrp_get(ob, stl, psl);
+ DRW_shgroup_call_add(hair_shgrp, geom, mat);
+ }
+ }
+ }
+ }
+ }
+}
+
+static void CLAY_cache_finish(void *vedata)
+{
+ CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl;
+
+ DRW_uniformbuffer_update(stl->mat_ubo, &stl->storage->mat_storage);
+ DRW_uniformbuffer_update(stl->hair_mat_ubo, &stl->storage->hair_mat_storage);
+}
+
+static void CLAY_draw_scene(void *vedata)
+{
+
+ CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl;
+ CLAY_FramebufferList *fbl = ((CLAY_Data *)vedata)->fbl;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+ /* Pass 1 : Depth pre-pass */
+ DRW_draw_pass(psl->depth_pass);
+ DRW_draw_pass(psl->depth_pass_cull);
+
+ /* Pass 2 : Duplicate depth */
+ /* Unless we go for deferred shading we need this to avoid manual depth test and artifacts */
+ if (DRW_state_is_fbo()) {
+ /* attach temp textures */
+ DRW_framebuffer_texture_attach(fbl->dupli_depth, e_data.depth_dup, 0, 0);
+
+ DRW_framebuffer_blit(dfbl->default_fb, fbl->dupli_depth, true);
+
+ /* detach temp textures */
+ DRW_framebuffer_texture_detach(e_data.depth_dup);
+
+ /* restore default fb */
+ DRW_framebuffer_bind(dfbl->default_fb);
+ }
+
+ /* Pass 3 : Shading */
+ DRW_draw_pass(psl->clay_pass);
+ DRW_draw_pass(psl->clay_pass_flat);
+ DRW_draw_pass(psl->hair_pass);
+}
+
+static void CLAY_layer_collection_settings_create(RenderEngine *UNUSED(engine), IDProperty *props)
+{
+ BLI_assert(props &&
+ props->type == IDP_GROUP &&
+ props->subtype == IDP_GROUP_SUB_ENGINE_RENDER);
+
+ BKE_collection_engine_property_add_int(props, "matcap_icon", ICON_MATCAP_01);
+ BKE_collection_engine_property_add_int(props, "type", CLAY_MATCAP_NONE);
+ BKE_collection_engine_property_add_float(props, "matcap_rotation", 0.0f);
+ BKE_collection_engine_property_add_float(props, "matcap_hue", 0.5f);
+ BKE_collection_engine_property_add_float(props, "matcap_saturation", 0.5f);
+ BKE_collection_engine_property_add_float(props, "matcap_value", 0.5f);
+ BKE_collection_engine_property_add_float(props, "ssao_distance", 0.2f);
+ BKE_collection_engine_property_add_float(props, "ssao_attenuation", 1.0f);
+ BKE_collection_engine_property_add_float(props, "ssao_factor_cavity", 1.0f);
+ BKE_collection_engine_property_add_float(props, "ssao_factor_edge", 1.0f);
+ BKE_collection_engine_property_add_float(props, "hair_brightness_randomness", 0.0f);
+}
+
+static void CLAY_scene_layer_settings_create(RenderEngine *UNUSED(engine), IDProperty *props)
+{
+ BLI_assert(props &&
+ props->type == IDP_GROUP &&
+ props->subtype == IDP_GROUP_SUB_ENGINE_RENDER);
+
+ BKE_collection_engine_property_add_int(props, "ssao_samples", 16);
+}
+
+static void CLAY_engine_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.clay_sh);
+ DRW_SHADER_FREE_SAFE(e_data.clay_flat_sh);
+ DRW_SHADER_FREE_SAFE(e_data.hair_sh);
+ DRW_TEXTURE_FREE_SAFE(e_data.matcap_array);
+}
+
+static const DrawEngineDataSize CLAY_data_size = DRW_VIEWPORT_DATA_SIZE(CLAY_Data);
+
+DrawEngineType draw_engine_clay_type = {
+ NULL, NULL,
+ N_("Clay"),
+ &CLAY_data_size,
+ &CLAY_engine_init,
+ &CLAY_engine_free,
+ &CLAY_cache_init,
+ &CLAY_cache_populate,
+ &CLAY_cache_finish,
+ NULL,
+ &CLAY_draw_scene
+};
+
+RenderEngineType DRW_engine_viewport_clay_type = {
+ NULL, NULL,
+ CLAY_ENGINE, N_("Clay"), RE_INTERNAL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ &CLAY_layer_collection_settings_create,
+ &CLAY_scene_layer_settings_create,
+ &draw_engine_clay_type,
+ {NULL, NULL, NULL}
+};
+
+
+#undef CLAY_ENGINE
+
+#endif
diff --git a/source/blender/draw/engines/clay/clay_engine.h b/source/blender/draw/engines/clay/clay_engine.h
new file mode 100644
index 00000000000..b7c9d00c9ae
--- /dev/null
+++ b/source/blender/draw/engines/clay/clay_engine.h
@@ -0,0 +1,36 @@
+/*
+ * 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 clay_engine.h
+ * \ingroup draw_engine
+ */
+
+#ifndef __CLAY_ENGINE_H__
+#define __CLAY_ENGINE_H__
+
+extern DrawEngineType draw_engine_clay_type;
+extern RenderEngineType DRW_engine_viewport_clay_type;
+
+struct IDProperty;
+
+struct IDProperty *CLAY_render_settings_create(void);
+
+#endif /* __CLAY_ENGINE_H__ */
diff --git a/source/blender/draw/engines/clay/shaders/clay_frag.glsl b/source/blender/draw/engines/clay/shaders/clay_frag.glsl
new file mode 100644
index 00000000000..9c8c90bd5b6
--- /dev/null
+++ b/source/blender/draw/engines/clay/shaders/clay_frag.glsl
@@ -0,0 +1,201 @@
+uniform vec2 screenres;
+uniform sampler2D depthtex;
+uniform mat4 WinMatrix;
+
+/* Matcap */
+uniform sampler2DArray matcaps;
+uniform vec3 matcaps_color[24];
+
+/* Screen Space Occlusion */
+/* 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];
+uniform vec4 ssao_params;
+
+uniform sampler2D ssao_jitter;
+
+/* Material Parameters packed in an UBO */
+struct Material {
+ vec4 ssao_params_var;
+ vec4 matcap_hsv_id;
+ vec4 matcap_rot; /* vec4 to ensure 16 bytes alignement (don't trust compiler) */
+};
+
+layout(std140) uniform samples_block {
+ vec4 ssao_samples[500];
+};
+
+layout(std140) uniform material_block {
+ Material matcaps_param[MAX_MATERIAL];
+};
+
+uniform int mat_id;
+
+/* Aliases */
+#define ssao_samples_num ssao_params.x
+#define jitter_tilling ssao_params.yz
+#define dfdy_sign ssao_params.w
+
+#define matcap_hsv matcaps_param[mat_id].matcap_hsv_id.xyz
+#define matcap_index matcaps_param[mat_id].matcap_hsv_id.w
+#define matcap_rotation matcaps_param[mat_id].matcap_rot.xy
+
+#ifdef USE_FLAT_NORMAL
+flat in vec3 normal;
+#else
+in vec3 normal;
+#endif
+
+out vec4 fragColor;
+
+/* TODO Move this to SSAO modules */
+/* 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. */
+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;
+ }
+}
+
+#ifdef USE_HSV
+void rgb_to_hsv(vec3 rgb, out vec3 outcol)
+{
+ float cmax, cmin, h, s, v, cdelta;
+ vec3 c;
+
+ cmax = max(rgb[0], max(rgb[1], rgb[2]));
+ cmin = min(rgb[0], min(rgb[1], rgb[2]));
+ cdelta = cmax - cmin;
+
+ v = cmax;
+ if (cmax != 0.0)
+ s = cdelta / cmax;
+ else {
+ s = 0.0;
+ h = 0.0;
+ }
+
+ if (s == 0.0) {
+ h = 0.0;
+ }
+ else {
+ c = (vec3(cmax, cmax, 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];
+ else h = 4.0 + c[1] - c[0];
+
+ h /= 6.0;
+
+ if (h < 0.0)
+ h += 1.0;
+ }
+
+ outcol = vec3(h, s, v);
+}
+
+void hsv_to_rgb(vec3 hsv, out vec3 outcol)
+{
+ float i, f, p, q, t, h, s, v;
+ vec3 rgb;
+
+ h = hsv[0];
+ s = hsv[1];
+ v = hsv[2];
+
+ if (s == 0.0) {
+ rgb = vec3(v, v, v);
+ }
+ else {
+ if (h == 1.0)
+ h = 0.0;
+
+ h *= 6.0;
+ i = floor(h);
+ f = h - i;
+ rgb = vec3(f, f, f);
+ p = v * (1.0 - s);
+ q = v * (1.0 - (s * f));
+ t = v * (1.0 - (s * (1.0 - f)));
+
+ if (i == 0.0) rgb = vec3(v, t, p);
+ else if (i == 1.0) rgb = vec3(q, v, p);
+ else if (i == 2.0) rgb = vec3(p, v, t);
+ else if (i == 3.0) rgb = vec3(p, q, v);
+ else if (i == 4.0) rgb = vec3(t, p, v);
+ else rgb = vec3(v, p, q);
+ }
+
+ outcol = rgb;
+}
+
+void hue_sat(float hue, float sat, float value, inout vec3 col)
+{
+ vec3 hsv;
+
+ rgb_to_hsv(col, hsv);
+
+ hsv.x += hue;
+ hsv.x -= floor(hsv.x);
+ hsv.y *= sat;
+ hsv.y = clamp(hsv.y, 0.0, 1.0);
+ hsv.z *= value;
+ hsv.z = clamp(hsv.z, 0.0, 1.0);
+
+ hsv_to_rgb(hsv, col);
+}
+#endif
+
+#ifdef USE_AO
+/* Prototype */
+void ssao_factors(
+ in float depth, in vec3 normal, in vec3 position, in vec2 screenco,
+ out float cavities, out float edges);
+#endif
+
+void main() {
+ vec2 screenco = vec2(gl_FragCoord.xy) / screenres;
+ float depth = texture(depthtex, screenco).r;
+
+ vec3 position = get_view_space_from_depth(screenco, depth);
+
+#ifdef USE_ROTATION
+ /* Rotate texture coordinates */
+ vec2 rotY = vec2(-matcap_rotation.y, matcap_rotation.x);
+ vec2 texco = abs(vec2(dot(normal.xy, matcap_rotation), dot(normal.xy, rotY)) * .49 + 0.5);
+#else
+ vec2 texco = abs(normal.xy * .49 + 0.5);
+#endif
+ vec3 col = texture(matcaps, vec3(texco, matcap_index)).rgb;
+
+#ifdef USE_AO
+ float cavity, edges;
+ ssao_factors(depth, normal, position, screenco, cavity, edges);
+
+ col *= mix(vec3(1.0), matcaps_color[int(matcap_index)], cavity);
+#endif
+
+#ifdef USE_HSV
+ hue_sat(matcap_hsv.x, matcap_hsv.y, matcap_hsv.z, col);
+#endif
+
+#ifdef USE_AO
+ /* Apply highlights after hue shift */
+ col *= edges + 1.0;
+#endif
+
+ fragColor = vec4(col, 1.0);
+}
diff --git a/source/blender/draw/engines/clay/shaders/clay_particle_strand_frag.glsl b/source/blender/draw/engines/clay/shaders/clay_particle_strand_frag.glsl
new file mode 100644
index 00000000000..980a1e4690d
--- /dev/null
+++ b/source/blender/draw/engines/clay/shaders/clay_particle_strand_frag.glsl
@@ -0,0 +1,144 @@
+
+/* Material Parameters packed in an UBO */
+struct Material {
+ vec4 one;
+ vec4 two;
+};
+
+layout(std140) uniform material_block {
+ Material shader_param[MAX_MATERIAL];
+};
+
+uniform mat4 ProjectionMatrix;
+uniform sampler2DArray matcaps;
+uniform int mat_id;
+
+#define randomness shader_param[mat_id].one.x
+#define matcap_index shader_param[mat_id].one.y
+#define matcap_rotation shader_param[mat_id].one.zw
+#define matcap_hsv shader_param[mat_id].two.xyz
+
+in vec3 tangent;
+in vec3 viewPosition;
+flat in float colRand;
+out vec4 fragColor;
+
+vec3 rotate(vec3 norm, vec3 ortho, float ang)
+{
+ return norm * cos(ang) + ortho * sin(ang);
+}
+
+void rgb_to_hsv(vec3 rgb, out vec3 outcol)
+{
+ float cmax, cmin, h, s, v, cdelta;
+ vec3 c;
+
+ cmax = max(rgb[0], max(rgb[1], rgb[2]));
+ cmin = min(rgb[0], min(rgb[1], rgb[2]));
+ cdelta = cmax - cmin;
+
+ v = cmax;
+ if (cmax != 0.0)
+ s = cdelta / cmax;
+ else {
+ s = 0.0;
+ h = 0.0;
+ }
+
+ if (s == 0.0) {
+ h = 0.0;
+ }
+ else {
+ c = (vec3(cmax, cmax, 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];
+ else h = 4.0 + c[1] - c[0];
+
+ h /= 6.0;
+
+ if (h < 0.0)
+ h += 1.0;
+ }
+
+ outcol = vec3(h, s, v);
+}
+
+void hsv_to_rgb(vec3 hsv, out vec3 outcol)
+{
+ float i, f, p, q, t, h, s, v;
+ vec3 rgb;
+
+ h = hsv[0];
+ s = hsv[1];
+ v = hsv[2];
+
+ if (s == 0.0) {
+ rgb = vec3(v, v, v);
+ }
+ else {
+ if (h == 1.0)
+ h = 0.0;
+
+ h *= 6.0;
+ i = floor(h);
+ f = h - i;
+ rgb = vec3(f, f, f);
+ p = v * (1.0 - s);
+ q = v * (1.0 - (s * f));
+ t = v * (1.0 - (s * (1.0 - f)));
+
+ if (i == 0.0) rgb = vec3(v, t, p);
+ else if (i == 1.0) rgb = vec3(q, v, p);
+ else if (i == 2.0) rgb = vec3(p, v, t);
+ else if (i == 3.0) rgb = vec3(p, q, v);
+ else if (i == 4.0) rgb = vec3(t, p, v);
+ else rgb = vec3(v, p, q);
+ }
+
+ outcol = rgb;
+}
+
+void hue_sat(float hue, float sat, float value, inout vec3 col)
+{
+ vec3 hsv;
+
+ rgb_to_hsv(col, hsv);
+
+ hsv.x += hue;
+ hsv.x -= floor(hsv.x);
+ hsv.y *= sat;
+ hsv.y = clamp(hsv.y, 0.0, 1.0);
+ hsv.z *= value;
+ hsv.z = clamp(hsv.z, 0.0, 1.0);
+
+ hsv_to_rgb(hsv, col);
+}
+
+void main()
+{
+ vec3 viewvec = (ProjectionMatrix[3][3] == 0.0) ? normalize(viewPosition) : vec3(0.0, 0.0, -1.0);
+ vec3 ortho = normalize(cross(viewvec, tangent));
+ vec3 norm = normalize(cross(ortho, tangent));
+
+ vec3 col = vec3(0);
+
+ vec2 rotY = vec2(-matcap_rotation.y, matcap_rotation.x);
+
+ for (int i = 0; i < 9; i++) {
+ vec3 rotNorm = rotate(norm, ortho, -0.5 + (i * 0.125));
+ vec3 ray = reflect(viewvec, rotNorm);
+ vec2 texco = abs(vec2(dot(ray.xy, matcap_rotation), dot(ray.xy, rotY)) * .49 + 0.5);
+
+ col += texture(matcaps, vec3(texco, matcap_index)).rgb / 9.0;
+ }
+
+ hue_sat(matcap_hsv.x, matcap_hsv.y, matcap_hsv.z, col);
+
+ float maxChan = max(max(col.r, col.g), col.b);
+
+ col += (colRand * maxChan * randomness * 1.5) - (maxChan * randomness * 0.75);
+
+ fragColor.rgb = col;
+ fragColor.a = 1.0;
+}
diff --git a/source/blender/draw/engines/clay/shaders/clay_particle_vert.glsl b/source/blender/draw/engines/clay/shaders/clay_particle_vert.glsl
new file mode 100644
index 00000000000..d4c35d14182
--- /dev/null
+++ b/source/blender/draw/engines/clay/shaders/clay_particle_vert.glsl
@@ -0,0 +1,34 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat3 NormalMatrix;
+uniform mat4 ModelViewMatrix;
+
+in vec3 pos;
+in vec3 nor;
+in int ind;
+out vec3 tangent;
+out vec3 viewPosition;
+flat out float colRand;
+
+float rand(int s)
+{
+ int seed = s * 1023423;
+
+ seed = (seed ^ 61) ^ (seed >> 16);
+ seed *= 9;
+ seed = seed ^ (seed >> 4);
+ seed *= 0x27d4eb2d;
+ seed = seed ^ (seed >> 15);
+
+ float value = float(seed);
+ value *= 1.0 / 42596.0;
+ return fract(value);
+}
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ tangent = normalize(NormalMatrix * nor);
+ viewPosition = (ModelViewMatrix * vec4(pos, 1.0)).xyz;
+ colRand = rand(ind);
+}
diff --git a/source/blender/draw/engines/clay/shaders/clay_vert.glsl b/source/blender/draw/engines/clay/shaders/clay_vert.glsl
new file mode 100644
index 00000000000..8f8866b3839
--- /dev/null
+++ b/source/blender/draw/engines/clay/shaders/clay_vert.glsl
@@ -0,0 +1,17 @@
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat3 NormalMatrix;
+
+in vec3 pos;
+in vec3 nor;
+
+#ifdef USE_FLAT_NORMAL
+flat out vec3 normal;
+#else
+out vec3 normal;
+#endif
+
+void main()
+{
+ normal = normalize(NormalMatrix * nor);
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+}
diff --git a/source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl b/source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl
new file mode 100644
index 00000000000..48c117c3d8d
--- /dev/null
+++ b/source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl
@@ -0,0 +1,78 @@
+#define ssao_distance matcaps_param[mat_id].ssao_params_var.x
+#define ssao_factor_cavity matcaps_param[mat_id].ssao_params_var.y
+#define ssao_factor_edge matcaps_param[mat_id].ssao_params_var.z
+#define ssao_attenuation matcaps_param[mat_id].ssao_params_var.w
+
+/* 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)
+{
+ /* 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;
+
+ cavities = edges = 0.0;
+ 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 < 500; x++) {
+ /* 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[x].xy, rotX), dot(ssao_samples[x].xy, rotY));
+ dir_jittered.xy *= ssao_samples[x].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(depthtex, 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/clay/shaders/ssao_groundtruth.glsl b/source/blender/draw/engines/clay/shaders/ssao_groundtruth.glsl
new file mode 100644
index 00000000000..9c203a4246c
--- /dev/null
+++ b/source/blender/draw/engines/clay/shaders/ssao_groundtruth.glsl
@@ -0,0 +1,122 @@
+#define ssao_distance matcaps_param[mat_id].ssao_params_var.x
+#define ssao_factor_cavity matcaps_param[mat_id].ssao_params_var.y
+#define ssao_factor_edge matcaps_param[mat_id].ssao_params_var.z
+#define ssao_attenuation matcaps_param[mat_id].ssao_params_var.w
+
+/* 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 */
+
+#define COSINE_WEIGHTING
+
+float integrate_arc(in float h1, in float h2, in float gamma, in float n_proj_len)
+{
+ float a = 0.0;
+#ifdef COSINE_WEIGHTING
+ float cos_gamma = cos(gamma);
+ float sin_gamma_2 = 2.0 * sin(gamma);
+ a += -cos(2.0 * h1 - gamma) + cos_gamma + h1 * sin_gamma_2;
+ a += -cos(2.0 * h2 - gamma) + cos_gamma + h2 * sin_gamma_2;
+ a *= 0.25; /* 1/4 */
+ a *= n_proj_len;
+#else
+ /* Uniform weighting (slide 59) */
+ a += 1 - cos(h1);
+ a += 1 - cos(h2);
+#endif
+ return a;
+}
+
+float get_max_horizon(in vec2 co, in vec3 x, in vec3 omega_o, in float h)
+{
+ if (co.x > 1.0 || co.x < 0.0 || co.y > 1.0 || co.y < 0.0)
+ return h;
+
+ float depth = texture(depthtex, co).r;
+
+ /* Background case */
+ if (depth == 1.0)
+ return h;
+
+ vec3 s = get_view_space_from_depth(co, depth); /* s View coordinate */
+ vec3 omega_s = s - x;
+ float len = length(omega_s);
+
+ if (len < ssao_distance) {
+ omega_s /= len;
+ h = max(h, dot(omega_s, omega_o));
+ }
+ return h;
+}
+
+void ssao_factors(
+ in float depth, in vec3 normal, in vec3 position, in vec2 screenco,
+ out float cavities, out float edges)
+{
+ /* Renaming */
+ vec3 omega_o = -normalize(position); /* viewvec */
+ vec2 x_ = screenco; /* x^ Screen coordinate */
+ vec3 x = position; /* x view space coordinate */
+
+#ifdef SPATIAL_DENOISE
+ float noise_dir = (1.0 / 16.0) * float(((int(gl_FragCoord.x + gl_FragCoord.y) & 0x3) << 2) + (int(gl_FragCoord.x) & 0x3));
+ float noise_offset = (1.0 / 4.0) * float(int(gl_FragCoord.y - gl_FragCoord.x) & 0x3);
+#else
+ float noise_dir = (1.0 / 16.0) * float(((int(gl_FragCoord.x + gl_FragCoord.y) & 0x3) << 2) + (int(gl_FragCoord.x) & 0x3));
+ float noise_offset = (0.5 / 16.0) + (1.0 / 16.0) * float(((int(gl_FragCoord.x - gl_FragCoord.y) & 0x3) << 2) + (int(gl_FragCoord.x) & 0x3));
+#endif
+
+ const float phi_step = 16.0;
+ const float theta_step = 16.0;
+ const float m_pi = 3.14159265358979323846;
+ vec2 pixel_ratio = vec2(screenres.y / screenres.x, 1.0);
+ vec2 pixel_size = vec2(1.0) / screenres.xy;
+ float min_stride = length(pixel_size);
+ float homcco = WinMatrix[2][3] * position.z + WinMatrix[3][3];
+ float n = max(min_stride * theta_step, ssao_distance / homcco); /* Search distance */
+
+ /* Integral over PI */
+ float A = 0.0;
+ for (float i = 0.0; i < phi_step; i++) {
+ float phi = m_pi * ((noise_dir + i) / phi_step);
+
+ vec2 t_phi = vec2(cos(phi), sin(phi)); /* Screen space direction */
+
+ /* Search maximum horizon angles Theta1 and Theta2 */
+ float theta1 = -1.0, theta2 = -1.0; /* init at cos(pi) */
+ for (float j = 0.0; j < theta_step; j++) {
+ vec2 s_ = t_phi * pixel_ratio * n * ((j + noise_offset)/ theta_step); /* s^ Screen coordinate */
+ vec2 co;
+
+ co = x_ + s_;
+ theta1 = get_max_horizon(co, x, omega_o, theta1);
+
+ co = x_ - s_;
+ theta2 = get_max_horizon(co, x, omega_o, theta2);
+ }
+
+ /* (Slide 54) */
+ theta1 = -acos(theta1);
+ theta2 = acos(theta2);
+
+ /* Projecting Normal to Plane P defined by t_phi and omega_o */
+ vec3 h = normalize(cross(vec3(t_phi, 0.0), omega_o)); /* Normal vector to Integration plane */
+ vec3 t = cross(h, omega_o); /* Normal vector to plane */
+ vec3 n_proj = normal - h * dot(normal, h);
+ float n_proj_len = length(n_proj);
+ vec3 n_proj_norm = normalize(n_proj);
+
+ /* Clamping thetas (slide 58) */
+ float gamma = sign(dot(n_proj_norm, t)) * acos(dot(normal, omega_o)); /* Angle between view vec and normal */
+ theta1 = gamma + max(theta1 - gamma, -m_pi * 0.5);
+ theta2 = gamma + min(theta2 - gamma, m_pi * 0.5);
+
+ /* Solving inner integral */
+ A += integrate_arc(theta1, theta2, gamma, n_proj_len);
+ }
+
+ A /= phi_step;
+
+ cavities = 1.0 - A;
+ edges = 0.0;
+}
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..36d91c0cc28
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_data.c
@@ -0,0 +1,128 @@
+/*
+ * 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
+ *
+ */
+
+/* All specific data handler for Objects, Lights, SceneLayers, ...
+ */
+
+/** \file eevee_data.c
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "eevee_private.h"
+
+static void eevee_scene_layer_data_free(void *storage)
+{
+ EEVEE_SceneLayerData *sldata = (EEVEE_SceneLayerData *)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);
+ DRW_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cube_target_fb);
+ DRW_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cube_fb);
+ DRW_FRAMEBUFFER_FREE_SAFE(sldata->shadow_map_fb);
+ DRW_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cascade_fb);
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_depth_cube_target);
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_color_cube_target);
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_depth_cube_pool);
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_depth_map_pool);
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_depth_cascade_pool);
+ BLI_freelistN(&sldata->shadow_casters);
+
+ /* 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_FRAMEBUFFER_FREE_SAFE(sldata->probe_fb);
+ DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_filter_fb);
+ DRW_TEXTURE_FREE_SAFE(sldata->probe_rt);
+ DRW_TEXTURE_FREE_SAFE(sldata->probe_pool);
+ DRW_TEXTURE_FREE_SAFE(sldata->irradiance_pool);
+ DRW_TEXTURE_FREE_SAFE(sldata->irradiance_rt);
+
+ /* Volumetrics */
+ MEM_SAFE_FREE(sldata->volumetrics);
+}
+
+static void eevee_lamp_data_free(void *storage)
+{
+ EEVEE_LampEngineData *led = (EEVEE_LampEngineData *)storage;
+
+ MEM_SAFE_FREE(led->storage);
+ BLI_freelistN(&led->shadow_caster_list);
+}
+
+static void eevee_lightprobe_data_free(void *storage)
+{
+ EEVEE_LightProbeEngineData *ped = (EEVEE_LightProbeEngineData *)storage;
+
+ BLI_freelistN(&ped->captured_object_list);
+}
+
+EEVEE_SceneLayerData *EEVEE_scene_layer_data_get(void)
+{
+ EEVEE_SceneLayerData **sldata = (EEVEE_SceneLayerData **)DRW_scene_layer_engine_data_get(&draw_engine_eevee_type, &eevee_scene_layer_data_free);
+
+ if (*sldata == NULL) {
+ *sldata = MEM_callocN(sizeof(**sldata), "EEVEE_SceneLayerData");
+ }
+
+ return *sldata;
+}
+
+EEVEE_ObjectEngineData *EEVEE_object_data_get(Object *ob)
+{
+ EEVEE_ObjectEngineData **oedata = (EEVEE_ObjectEngineData **)DRW_object_engine_data_get(ob, &draw_engine_eevee_type, NULL);
+
+ if (*oedata == NULL) {
+ *oedata = MEM_callocN(sizeof(**oedata), "EEVEE_ObjectEngineData");
+ }
+
+ return *oedata;
+}
+
+EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_get(Object *ob)
+{
+ EEVEE_LightProbeEngineData **pedata = (EEVEE_LightProbeEngineData **)DRW_object_engine_data_get(ob, &draw_engine_eevee_type, &eevee_lightprobe_data_free);
+
+ if (*pedata == NULL) {
+ *pedata = MEM_callocN(sizeof(**pedata), "EEVEE_LightProbeEngineData");
+ (*pedata)->need_update = true;
+ }
+
+ return *pedata;
+}
+
+EEVEE_LampEngineData *EEVEE_lamp_data_get(Object *ob)
+{
+ EEVEE_LampEngineData **ledata = (EEVEE_LampEngineData **)DRW_object_engine_data_get(ob, &draw_engine_eevee_type, &eevee_lamp_data_free);
+
+ if (*ledata == NULL) {
+ *ledata = MEM_callocN(sizeof(**ledata), "EEVEE_LampEngineData");
+ (*ledata)->need_update = true;
+ }
+
+ return *ledata;
+}
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..861d862657e
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_effects.c
@@ -0,0 +1,895 @@
+/*
+ * 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
+ *
+ */
+
+/* Gather all screen space effects technique such as Bloom, Motion Blur, DoF, SSAO, SSR, ...
+ */
+
+/** \file eevee_effects.c
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_world_types.h"
+
+#include "BKE_camera.h"
+#include "BKE_object.h"
+#include "BKE_animsys.h"
+#include "BKE_screen.h"
+
+#include "BLI_dynstr.h"
+
+#include "eevee_private.h"
+#include "GPU_texture.h"
+
+typedef struct EEVEE_LightProbeData {
+ short probe_id, shadow_id;
+} EEVEE_LightProbeData;
+
+static struct {
+ /* Downsample Depth */
+ struct GPUShader *minmaxz_downlevel_sh;
+ struct GPUShader *minmaxz_downdepth_sh;
+ struct GPUShader *minmaxz_copydepth_sh;
+
+ /* Motion Blur */
+ struct GPUShader *motion_blur_sh;
+
+ /* 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];
+
+ /* Depth Of Field */
+ struct GPUShader *dof_downsample_sh;
+ struct GPUShader *dof_scatter_sh;
+ struct GPUShader *dof_resolve_sh;
+
+ /* Volumetric */
+ struct GPUShader *volumetric_upsample_sh;
+
+ struct GPUTexture *depth_src;
+} e_data = {NULL}; /* Engine data */
+
+extern char datatoc_effect_minmaxz_frag_glsl[];
+extern char datatoc_effect_motion_blur_frag_glsl[];
+extern char datatoc_effect_bloom_frag_glsl[];
+extern char datatoc_effect_dof_vert_glsl[];
+extern char datatoc_effect_dof_geom_glsl[];
+extern char datatoc_effect_dof_frag_glsl[];
+extern char datatoc_tonemap_frag_glsl[];
+extern char datatoc_volumetric_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;
+
+ /* Past matrix */
+ /* FIXME : This is a temporal solution that does not take care of parent animations */
+ /* Recalc Anim manualy */
+ BKE_animsys_evaluate_animdata(scene, &cam_cpy.id, cam_cpy.adt, time, ADT_RECALC_ALL);
+ BKE_animsys_evaluate_animdata(scene, &camdata_cpy.id, camdata_cpy.adt, time, ADT_RECALC_ALL);
+ BKE_object_where_is_calc_time(scene, &cam_cpy, time);
+
+ /* Compute winmat */
+ CameraParams params;
+ BKE_camera_params_init(&params);
+
+ /* copy of BKE_camera_params_from_view3d */
+ {
+ params.lens = v3d->lens;
+ params.clipsta = v3d->near;
+ params.clipend = v3d->far;
+
+ /* camera view */
+ BKE_camera_params_from_object(&params, &cam_cpy);
+
+ params.zoom = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom);
+
+ params.offsetx = 2.0f * rv3d->camdx * params.zoom;
+ params.offsety = 2.0f * rv3d->camdy * params.zoom;
+
+ params.shiftx *= params.zoom;
+ params.shifty *= params.zoom;
+
+ params.zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB / params.zoom;
+ }
+
+ BKE_camera_params_compute_viewplane(&params, ar->winx, ar->winy, 1.0f, 1.0f);
+ 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);
+}
+
+void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_EffectsInfo *effects;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ SceneLayer *scene_layer = draw_ctx->scene_layer;
+ Scene *scene = draw_ctx->scene;
+ View3D *v3d = draw_ctx->v3d;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ ARegion *ar = draw_ctx->ar;
+ IDProperty *props = BKE_scene_layer_engine_evaluated_get(scene_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE);
+
+ const float *viewport_size = DRW_viewport_size_get();
+
+ /* Shaders */
+ if (!e_data.motion_blur_sh) {
+ e_data.volumetric_upsample_sh = DRW_shader_create_fullscreen(datatoc_volumetric_frag_glsl, "#define STEP_UPSAMPLE\n");
+
+ e_data.minmaxz_downlevel_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, NULL);
+ e_data.minmaxz_downdepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define INPUT_DEPTH\n");
+ e_data.minmaxz_copydepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define INPUT_DEPTH\n"
+ "#define COPY_DEPTH\n");
+
+ e_data.motion_blur_sh = DRW_shader_create_fullscreen(datatoc_effect_motion_blur_frag_glsl, NULL);
+
+ e_data.dof_downsample_sh = DRW_shader_create(datatoc_effect_dof_vert_glsl, NULL,
+ datatoc_effect_dof_frag_glsl, "#define STEP_DOWNSAMPLE\n");
+ e_data.dof_scatter_sh = DRW_shader_create(datatoc_effect_dof_vert_glsl, NULL,
+ datatoc_effect_dof_frag_glsl, "#define STEP_SCATTER\n");
+ e_data.dof_resolve_sh = DRW_shader_create(datatoc_effect_dof_vert_glsl, NULL,
+ datatoc_effect_dof_frag_glsl, "#define STEP_RESOLVE\n");
+
+ 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");
+ }
+
+ if (!stl->effects) {
+ stl->effects = MEM_callocN(sizeof(EEVEE_EffectsInfo), "EEVEE_EffectsInfo");
+ }
+
+ effects = stl->effects;
+
+ int enabled_effects = 0;
+
+ if (BKE_collection_engine_property_value_get_bool(props, "motion_blur_enable")) {
+ /* Update Motion Blur Matrices */
+ if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
+ float persmat[4][4];
+ float ctime = BKE_scene_frame_get(scene);
+ float delta = BKE_collection_engine_property_value_get_float(props, "motion_blur_shutter");
+
+ /* Current matrix */
+ eevee_motion_blur_camera_get_matrix_at_time(scene, ar, rv3d, v3d, v3d->camera, 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 (compare_m4m4(persmat, effects->current_ndc_to_world, 0.0001f)) {
+
+ /* Past matrix */
+ eevee_motion_blur_camera_get_matrix_at_time(scene, ar, rv3d, v3d, v3d->camera, 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, v3d->camera, ctime + delta, effects->future_world_to_ndc);
+#endif
+ invert_m4(effects->current_ndc_to_world);
+
+ effects->motion_blur_samples = BKE_collection_engine_property_value_get_int(props, "motion_blur_samples");
+ enabled_effects |= EFFECT_MOTION_BLUR;
+ }
+ }
+ }
+
+ if (BKE_collection_engine_property_value_get_bool(props, "bloom_enable")) {
+ /* 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];
+
+ DRWFboTexture tex_blit = {&txl->bloom_blit, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER};
+ DRW_framebuffer_init(&fbl->bloom_blit_fb, &draw_engine_eevee_type,
+ (int)blitsize[0], (int)blitsize[1],
+ &tex_blit, 1);
+
+ /* Parameters */
+ float threshold = BKE_collection_engine_property_value_get_float(props, "bloom_threshold");
+ float knee = BKE_collection_engine_property_value_get_float(props, "bloom_knee");
+ float intensity = BKE_collection_engine_property_value_get_float(props, "bloom_intensity");
+ float radius = BKE_collection_engine_property_value_get_float(props, "bloom_radius");
+
+ /* 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_ct = (int)maxIter;
+
+ CLAMP(effects->bloom_iteration_ct, 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;
+ effects->bloom_intensity = intensity;
+
+ /* Downsample buffers */
+ copy_v2_v2_int(texsize, blitsize);
+ for (int i = 0; i < effects->bloom_iteration_ct; ++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];
+
+ DRWFboTexture tex_bloom = {&txl->bloom_downsample[i], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER};
+ DRW_framebuffer_init(&fbl->bloom_down_fb[i], &draw_engine_eevee_type,
+ (int)texsize[0], (int)texsize[1],
+ &tex_bloom, 1);
+ }
+
+ /* Upsample buffers */
+ copy_v2_v2_int(texsize, blitsize);
+ for (int i = 0; i < effects->bloom_iteration_ct - 1; ++i) {
+ texsize[0] /= 2; texsize[1] /= 2;
+ texsize[0] = MAX2(texsize[0], 2);
+ texsize[1] = MAX2(texsize[1], 2);
+
+ DRWFboTexture tex_bloom = {&txl->bloom_upsample[i], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER};
+ DRW_framebuffer_init(&fbl->bloom_accum_fb[i], &draw_engine_eevee_type,
+ (int)texsize[0], (int)texsize[1],
+ &tex_bloom, 1);
+ }
+
+ enabled_effects |= EFFECT_BLOOM;
+ }
+
+ if (BKE_collection_engine_property_value_get_bool(props, "dof_enable")) {
+ /* Depth Of Field */
+ if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
+ Camera *cam = (Camera *)v3d->camera->data;
+
+ /* Retreive 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};
+
+ struct GPUTexture **dof_down_near = &txl->dof_down_near;
+ bool fb_reset = false;
+
+ /* Reuse buffer from Bloom if available */
+ /* WATCH IT : must have the same size */
+ if ((enabled_effects & EFFECT_BLOOM) != 0) {
+ dof_down_near = &txl->bloom_downsample[0]; /* should always exists */
+ if ((effects->enabled_effects & EFFECT_BLOOM) == 0) {
+ fb_reset = true;
+ }
+ }
+ else if ((effects->enabled_effects & EFFECT_BLOOM) != 0) {
+ fb_reset = true;
+ }
+
+ /* if framebuffer config must be changed */
+ if (fb_reset && (fbl->dof_down_fb != NULL)) {
+ DRW_framebuffer_free(fbl->dof_down_fb);
+ fbl->dof_down_fb = NULL;
+ }
+
+ /* Setup buffers */
+ DRWFboTexture tex_down[3] = {{dof_down_near, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, /* filter to not interfeer with bloom */
+ {&txl->dof_down_far, DRW_TEX_RGB_11_11_10, 0},
+ {&txl->dof_coc, DRW_TEX_RG_16, 0}};
+ DRW_framebuffer_init(&fbl->dof_down_fb, &draw_engine_eevee_type, buffer_size[0], buffer_size[1], tex_down, 3);
+
+ DRWFboTexture tex_scatter_far = {&txl->dof_far_blur, DRW_TEX_RGBA_16, DRW_TEX_FILTER};
+ DRW_framebuffer_init(&fbl->dof_scatter_far_fb, &draw_engine_eevee_type, buffer_size[0], buffer_size[1], &tex_scatter_far, 1);
+
+ DRWFboTexture tex_scatter_near = {&txl->dof_near_blur, DRW_TEX_RGBA_16, DRW_TEX_FILTER};
+ DRW_framebuffer_init(&fbl->dof_scatter_near_fb, &draw_engine_eevee_type, buffer_size[0], buffer_size[1], &tex_scatter_near, 1);
+
+ /* 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(v3d->camera);
+ float focal_len = cam->lens;
+
+ UNUSED_VARS(rotation, ratio);
+
+ /* 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 = 0.5f * scale_camera * focal_len / fstop;
+ float focal_len_scaled = scale_camera * focal_len;
+ float sensor_scaled = scale_camera * sensor;
+
+ 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] / (rv3d->viewcamtexcofac[0] * sensor_scaled);
+ effects->dof_bokeh[0] = blades;
+ effects->dof_bokeh[1] = rotation;
+ effects->dof_bokeh[2] = ratio;
+ effects->dof_bokeh[3] = BKE_collection_engine_property_value_get_float(props, "bokeh_max_size");
+
+ enabled_effects |= EFFECT_DOF;
+ }
+ }
+
+ effects->enabled_effects = enabled_effects;
+
+ /* Only allocate if at least one effect is activated */
+ if (effects->enabled_effects != 0) {
+ /* Ping Pong buffer */
+ DRWFboTexture tex = {&txl->color_post, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER};
+
+ DRW_framebuffer_init(&fbl->effect_fb, &draw_engine_eevee_type,
+ (int)viewport_size[0], (int)viewport_size[1],
+ &tex, 1);
+ }
+
+ {
+ /* Ambient Occlusion*/
+ stl->effects->ao_dist = BKE_collection_engine_property_value_get_float(props, "gtao_distance");
+ stl->effects->ao_samples = BKE_collection_engine_property_value_get_int(props, "gtao_samples");
+ stl->effects->ao_factor = BKE_collection_engine_property_value_get_float(props, "gtao_factor");
+ }
+
+ /* MinMax Pyramid */
+ /* TODO reduce precision */
+ DRWFboTexture tex = {&stl->g_data->minmaxz, DRW_TEX_RG_32, DRW_TEX_MIPMAP | DRW_TEX_TEMP};
+
+ DRW_framebuffer_init(&fbl->minmaxz_fb, &draw_engine_eevee_type,
+ (int)viewport_size[0] / 2, (int)viewport_size[1] / 2,
+ &tex, 1);
+
+ if (BKE_collection_engine_property_value_get_bool(props, "volumetric_enable")) {
+ World *wo = scene->world;
+
+ /* TODO: this will not be the case if we support object volumetrics */
+ if ((wo != NULL) && (wo->use_nodes) && (wo->nodetree != NULL)) {
+ effects->enabled_effects |= EFFECT_VOLUMETRIC;
+
+ if (sldata->volumetrics == NULL) {
+ sldata->volumetrics = MEM_callocN(sizeof(EEVEE_VolumetricsInfo), "EEVEE_VolumetricsInfo");
+ }
+
+ EEVEE_VolumetricsInfo *volumetrics = sldata->volumetrics;
+ bool last_use_colored_transmit = volumetrics->use_colored_transmit; /* Save to compare */
+
+ volumetrics->integration_start = BKE_collection_engine_property_value_get_float(props, "volumetric_start");
+ volumetrics->integration_end = BKE_collection_engine_property_value_get_float(props, "volumetric_end");
+
+ if (DRW_viewport_is_persp_get()) {
+ /* Negate */
+ volumetrics->integration_start = -volumetrics->integration_start;
+ volumetrics->integration_end = -volumetrics->integration_end;
+ }
+ else {
+ const float clip_start = stl->g_data->viewvecs[0][2];
+ const float clip_end = stl->g_data->viewvecs[1][2];
+ volumetrics->integration_start = min_ff(volumetrics->integration_end, clip_start);
+ volumetrics->integration_end = max_ff(-volumetrics->integration_end, clip_end);
+ }
+
+ volumetrics->sample_distribution = BKE_collection_engine_property_value_get_float(props, "volumetric_sample_distribution");
+ volumetrics->integration_step_count = (float)BKE_collection_engine_property_value_get_int(props, "volumetric_samples");
+ volumetrics->shadow_step_count = (float)BKE_collection_engine_property_value_get_int(props, "volumetric_shadow_samples");
+ volumetrics->light_clamp = BKE_collection_engine_property_value_get_float(props, "volumetric_light_clamp");
+
+ /* Disable clamp if equal to 0. */
+ if (volumetrics->light_clamp == 0.0) {
+ volumetrics->light_clamp = FLT_MAX;
+ }
+
+ volumetrics->use_lights = BKE_collection_engine_property_value_get_bool(props, "volumetric_lights");
+ volumetrics->use_volume_shadows = BKE_collection_engine_property_value_get_bool(props, "volumetric_shadows");
+ volumetrics->use_colored_transmit = BKE_collection_engine_property_value_get_bool(props, "volumetric_colored_transmittance");
+
+ if (last_use_colored_transmit != volumetrics->use_colored_transmit) {
+ if (fbl->volumetric_fb != NULL) {
+ DRW_framebuffer_free(fbl->volumetric_fb);
+ fbl->volumetric_fb = NULL;
+ }
+ }
+
+ /* Integration result buffer(s) */
+ if (volumetrics->use_colored_transmit == false) {
+ /* Monocromatic transmittance in alpha */
+ DRWFboTexture tex_vol = {&stl->g_data->volumetric, DRW_TEX_RGBA_16, DRW_TEX_MIPMAP | DRW_TEX_FILTER | DRW_TEX_TEMP};
+
+ DRW_framebuffer_init(&fbl->volumetric_fb, &draw_engine_eevee_type,
+ (int)viewport_size[0] / 2, (int)viewport_size[1] / 2,
+ &tex_vol, 1);
+ }
+ else {
+ /* Transmittance is separated, No need for alpha and DRW_TEX_RGB_11_11_10 gives the same vram usage */
+ /* Hint ! Could reuse this for transparency! */
+ DRWFboTexture tex_vol[2] = {{&stl->g_data->volumetric, DRW_TEX_RGB_11_11_10, DRW_TEX_MIPMAP | DRW_TEX_FILTER | DRW_TEX_TEMP},
+ {&stl->g_data->volumetric_transmit, DRW_TEX_RGB_11_11_10, DRW_TEX_MIPMAP | DRW_TEX_FILTER | DRW_TEX_TEMP}};
+
+ DRW_framebuffer_init(&fbl->volumetric_fb, &draw_engine_eevee_type,
+ (int)viewport_size[0] / 2, (int)viewport_size[1] / 2,
+ tex_vol, 2);
+ }
+ }
+ }
+}
+
+static DRWShadingGroup *eevee_create_bloom_pass(const char *name, EEVEE_EffectsInfo *effects, struct GPUShader *sh, DRWPass **pass, bool upsample)
+{
+ struct Gwn_Batch *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_buffer(grp, "sourceBuffer", &effects->unf_source_buffer);
+ DRW_shgroup_uniform_vec2(grp, "sourceBufferTexelSize", effects->unf_source_texel_size, 1);
+ if (upsample) {
+ DRW_shgroup_uniform_buffer(grp, "baseBuffer", &effects->unf_base_buffer);
+ DRW_shgroup_uniform_float(grp, "sampleScale", &effects->bloom_sample_scale, 1);
+ }
+
+ return grp;
+}
+
+void EEVEE_effects_cache_init(EEVEE_SceneLayerData *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 Gwn_Batch *quad = DRW_cache_fullscreen_quad_get();
+
+ if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) {
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ struct World *wo = scene->world; /* Already checked non NULL */
+ EEVEE_VolumetricsInfo *volumetrics = sldata->volumetrics;
+
+ struct GPUMaterial *mat = EEVEE_material_world_volume_get(
+ scene, wo, volumetrics->use_lights, volumetrics->use_volume_shadows,
+ false, volumetrics->use_colored_transmit);
+
+ psl->volumetric_integrate_ps = DRW_pass_create("Volumetric Integration", DRW_STATE_WRITE_COLOR);
+ DRWShadingGroup *grp = DRW_shgroup_material_create(mat, psl->volumetric_integrate_ps);
+
+ if (grp != NULL) {
+ DRW_shgroup_uniform_buffer(grp, "depthFull", &e_data.depth_src);
+ DRW_shgroup_uniform_buffer(grp, "shadowCubes", &sldata->shadow_depth_cube_pool);
+ DRW_shgroup_uniform_buffer(grp, "irradianceGrid", &sldata->irradiance_pool);
+ 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, "shadow_block", sldata->shadow_ubo);
+ DRW_shgroup_uniform_int(grp, "light_count", &sldata->lamps->num_light, 1);
+ DRW_shgroup_uniform_int(grp, "grid_count", &sldata->probes->num_render_grid, 1);
+ DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
+ DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2);
+ DRW_shgroup_uniform_vec2(grp, "volume_start_end", &sldata->volumetrics->integration_start, 1);
+ DRW_shgroup_uniform_vec4(grp, "volume_samples_clamp", &sldata->volumetrics->integration_step_count, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ if (volumetrics->use_colored_transmit == false) { /* Monochromatic transmittance */
+ psl->volumetric_resolve_ps = DRW_pass_create("Volumetric Resolve", DRW_STATE_WRITE_COLOR | DRW_STATE_TRANSMISSION);
+ grp = DRW_shgroup_create(e_data.volumetric_upsample_sh, psl->volumetric_resolve_ps);
+ DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2);
+ DRW_shgroup_uniform_buffer(grp, "depthFull", &e_data.depth_src);
+ DRW_shgroup_uniform_buffer(grp, "volumetricBuffer", &stl->g_data->volumetric);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+ else {
+ psl->volumetric_resolve_transmit_ps = DRW_pass_create("Volumetric Transmittance Resolve", DRW_STATE_WRITE_COLOR | DRW_STATE_MULTIPLY);
+ grp = DRW_shgroup_create(e_data.volumetric_upsample_sh, psl->volumetric_resolve_transmit_ps);
+ DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2);
+ DRW_shgroup_uniform_buffer(grp, "depthFull", &e_data.depth_src);
+ DRW_shgroup_uniform_buffer(grp, "volumetricBuffer", &stl->g_data->volumetric_transmit);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ psl->volumetric_resolve_ps = DRW_pass_create("Volumetric Resolve", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE);
+ grp = DRW_shgroup_create(e_data.volumetric_upsample_sh, psl->volumetric_resolve_ps);
+ DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2);
+ DRW_shgroup_uniform_buffer(grp, "depthFull", &e_data.depth_src);
+ DRW_shgroup_uniform_buffer(grp, "volumetricBuffer", &stl->g_data->volumetric);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+ }
+ else {
+ /* Compilation failled */
+ effects->enabled_effects &= ~EFFECT_VOLUMETRIC;
+ }
+ }
+
+ {
+ psl->minmaxz_downlevel = DRW_pass_create("HiZ Down Level", DRW_STATE_WRITE_COLOR);
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.minmaxz_downlevel_sh, psl->minmaxz_downlevel);
+ DRW_shgroup_uniform_buffer(grp, "depthBuffer", &stl->g_data->minmaxz);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ psl->minmaxz_downdepth = DRW_pass_create("HiZ Down Depth", DRW_STATE_WRITE_COLOR);
+ grp = DRW_shgroup_create(e_data.minmaxz_downdepth_sh, psl->minmaxz_downdepth);
+ DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ psl->minmaxz_copydepth = DRW_pass_create("HiZ Copy Depth", DRW_STATE_WRITE_COLOR);
+ grp = DRW_shgroup_create(e_data.minmaxz_copydepth_sh, psl->minmaxz_copydepth);
+ DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+
+ {
+ 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", (float *)effects->current_ndc_to_world);
+ DRW_shgroup_uniform_mat4(grp, "pastViewProjMatrix", (float *)effects->past_world_to_ndc);
+ DRW_shgroup_uniform_buffer(grp, "colorBuffer", &effects->source_buffer);
+ DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+
+ {
+ /** 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);
+ grp = eevee_create_bloom_pass("Bloom Resolve", effects, e_data.bloom_resolve_sh[use_highres], &psl->bloom_resolve, true);
+ DRW_shgroup_uniform_float(grp, "bloomIntensity", &effects->bloom_intensity, 1);
+ }
+
+ {
+ /** 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;
+
+ psl->dof_down = DRW_pass_create("DoF Downsample", DRW_STATE_WRITE_COLOR);
+
+ grp = DRW_shgroup_create(e_data.dof_downsample_sh, psl->dof_down);
+ DRW_shgroup_uniform_buffer(grp, "colorBuffer", &effects->source_buffer);
+ DRW_shgroup_uniform_buffer(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);
+
+ /* 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_ct = ((int)viewport_size[0]/2) * ((int)viewport_size[1]/2); /* brackets matters */
+ grp = DRW_shgroup_empty_tri_batch_create(e_data.dof_scatter_sh, psl->dof_scatter, sprite_ct);
+
+ DRW_shgroup_uniform_buffer(grp, "colorBuffer", &effects->unf_source_buffer);
+ DRW_shgroup_uniform_buffer(grp, "cocBuffer", &txl->dof_coc);
+ DRW_shgroup_uniform_vec2(grp, "layerSelection", effects->dof_layer_select, 1);
+ DRW_shgroup_uniform_vec4(grp, "bokehParams", effects->dof_bokeh, 1);
+
+ psl->dof_resolve = DRW_pass_create("DoF Resolve", DRW_STATE_WRITE_COLOR);
+
+ grp = DRW_shgroup_create(e_data.dof_resolve_sh, psl->dof_resolve);
+ DRW_shgroup_uniform_buffer(grp, "colorBuffer", &effects->source_buffer);
+ DRW_shgroup_uniform_buffer(grp, "nearBuffer", &txl->dof_near_blur);
+ DRW_shgroup_uniform_buffer(grp, "farBuffer", &txl->dof_far_blur);
+ DRW_shgroup_uniform_buffer(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);
+ }
+}
+
+#define SWAP_BUFFERS() { \
+ if (effects->source_buffer == txl->color) { \
+ effects->source_buffer = txl->color_post; \
+ effects->target_buffer = fbl->main; \
+ } \
+ else { \
+ effects->source_buffer = txl->color; \
+ effects->target_buffer = fbl->effect_fb; \
+ } \
+} ((void)0)
+
+static void minmax_downsample_cb(void *vedata, int UNUSED(level))
+{
+ EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ DRW_draw_pass(psl->minmaxz_downlevel);
+}
+
+void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, GPUTexture *depth_src)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_StorageList *stl = vedata->stl;
+
+ e_data.depth_src = depth_src;
+
+ /* Copy depth buffer to minmax texture top level */
+ DRW_framebuffer_texture_attach(fbl->minmaxz_fb, stl->g_data->minmaxz, 0, 0);
+ DRW_framebuffer_bind(fbl->minmaxz_fb);
+ DRW_draw_pass(psl->minmaxz_downdepth);
+ DRW_framebuffer_texture_detach(stl->g_data->minmaxz);
+
+ /* Create lower levels */
+ DRW_framebuffer_recursive_downsample(fbl->minmaxz_fb, stl->g_data->minmaxz, 6, &minmax_downsample_cb, vedata);
+}
+
+void EEVEE_effects_do_volumetrics(EEVEE_SceneLayerData *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_VOLUMETRIC) != 0) {
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ e_data.depth_src = dtxl->depth;
+
+ /* Compute volumetric integration at halfres. */
+ DRW_framebuffer_texture_attach(fbl->volumetric_fb, stl->g_data->volumetric, 0, 0);
+ if (sldata->volumetrics->use_colored_transmit) {
+ DRW_framebuffer_texture_attach(fbl->volumetric_fb, stl->g_data->volumetric_transmit, 1, 0);
+ }
+ DRW_framebuffer_bind(fbl->volumetric_fb);
+ DRW_draw_pass(psl->volumetric_integrate_ps);
+
+ /* Resolve at fullres */
+ DRW_framebuffer_texture_detach(dtxl->depth);
+ DRW_framebuffer_bind(fbl->main);
+ if (sldata->volumetrics->use_colored_transmit) {
+ DRW_draw_pass(psl->volumetric_resolve_transmit_ps);
+ }
+ DRW_draw_pass(psl->volumetric_resolve_ps);
+
+ /* Restore */
+ DRW_framebuffer_texture_attach(fbl->main, dtxl->depth, 0, 0);
+ DRW_framebuffer_texture_detach(stl->g_data->volumetric);
+ if (sldata->volumetrics->use_colored_transmit) {
+ DRW_framebuffer_texture_detach(stl->g_data->volumetric_transmit);
+ }
+ }
+}
+
+void EEVEE_draw_effects(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;
+
+ /* Default framebuffer and texture */
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ /* Init pointers */
+ effects->source_buffer = txl->color; /* latest updated texture */
+ effects->target_buffer = fbl->effect_fb; /* next target to render to */
+
+ /* Detach depth for effects to use it */
+ DRW_framebuffer_texture_detach(dtxl->depth);
+
+ /* Motion Blur */
+ if ((effects->enabled_effects & EFFECT_MOTION_BLUR) != 0) {
+ DRW_framebuffer_bind(effects->target_buffer);
+ DRW_draw_pass(psl->motion_blur);
+ SWAP_BUFFERS();
+ }
+
+ /* Depth Of Field */
+ if ((effects->enabled_effects & EFFECT_DOF) != 0) {
+ float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+ /* Downsample */
+ DRW_framebuffer_bind(fbl->dof_down_fb);
+ DRW_draw_pass(psl->dof_down);
+
+ /* Scatter Far */
+ effects->unf_source_buffer = txl->dof_down_far;
+ copy_v2_fl2(effects->dof_layer_select, 0.0f, 1.0f);
+ DRW_framebuffer_bind(fbl->dof_scatter_far_fb);
+ DRW_framebuffer_clear(true, false, false, clear_col, 0.0f);
+ DRW_draw_pass(psl->dof_scatter);
+
+ /* Scatter Near */
+ if ((effects->enabled_effects & EFFECT_BLOOM) != 0) {
+ /* Reuse bloom half res buffer */
+ effects->unf_source_buffer = txl->bloom_downsample[0];
+ }
+ else {
+ effects->unf_source_buffer = txl->dof_down_near;
+ }
+ copy_v2_fl2(effects->dof_layer_select, 1.0f, 0.0f);
+ DRW_framebuffer_bind(fbl->dof_scatter_near_fb);
+ DRW_framebuffer_clear(true, false, false, clear_col, 0.0f);
+ DRW_draw_pass(psl->dof_scatter);
+
+ /* Resolve */
+ DRW_framebuffer_bind(effects->target_buffer);
+ DRW_draw_pass(psl->dof_resolve);
+ SWAP_BUFFERS();
+ }
+
+ /* 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;
+
+ DRW_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 = txl->bloom_blit;
+
+ DRW_framebuffer_bind(fbl->bloom_down_fb[0]);
+ DRW_draw_pass(psl->bloom_downsample_first);
+
+ last = txl->bloom_downsample[0];
+
+ for (int i = 1; i < effects->bloom_iteration_ct; ++i) {
+ copy_v2_v2(effects->unf_source_texel_size, effects->downsamp_texel_size[i-1]);
+ effects->unf_source_buffer = last;
+
+ DRW_framebuffer_bind(fbl->bloom_down_fb[i]);
+ DRW_draw_pass(psl->bloom_downsample);
+
+ /* Used in next loop */
+ last = txl->bloom_downsample[i];
+ }
+
+ /* Upsample and accumulate */
+ for (int i = effects->bloom_iteration_ct - 2; i >= 0; --i) {
+ copy_v2_v2(effects->unf_source_texel_size, effects->downsamp_texel_size[i]);
+ effects->unf_source_buffer = txl->bloom_downsample[i];
+ effects->unf_base_buffer = last;
+
+ DRW_framebuffer_bind(fbl->bloom_accum_fb[i]);
+ DRW_draw_pass(psl->bloom_upsample);
+
+ last = txl->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;
+
+ DRW_framebuffer_bind(effects->target_buffer);
+ DRW_draw_pass(psl->bloom_resolve);
+ SWAP_BUFFERS();
+ }
+
+ /* Restore default framebuffer */
+ DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0);
+ DRW_framebuffer_bind(dfbl->default_fb);
+
+ /* Tonemapping */
+ DRW_transform_to_display(effects->source_buffer);
+}
+
+void EEVEE_effects_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.volumetric_upsample_sh);
+
+ DRW_SHADER_FREE_SAFE(e_data.minmaxz_downlevel_sh);
+ DRW_SHADER_FREE_SAFE(e_data.minmaxz_downdepth_sh);
+ DRW_SHADER_FREE_SAFE(e_data.minmaxz_copydepth_sh);
+
+ DRW_SHADER_FREE_SAFE(e_data.motion_blur_sh);
+ DRW_SHADER_FREE_SAFE(e_data.dof_downsample_sh);
+ DRW_SHADER_FREE_SAFE(e_data.dof_scatter_sh);
+ DRW_SHADER_FREE_SAFE(e_data.dof_resolve_sh);
+
+ DRW_SHADER_FREE_SAFE(e_data.bloom_blit_sh[0]);
+ DRW_SHADER_FREE_SAFE(e_data.bloom_downsample_sh[0]);
+ DRW_SHADER_FREE_SAFE(e_data.bloom_upsample_sh[0]);
+ DRW_SHADER_FREE_SAFE(e_data.bloom_resolve_sh[0]);
+ DRW_SHADER_FREE_SAFE(e_data.bloom_blit_sh[1]);
+ DRW_SHADER_FREE_SAFE(e_data.bloom_downsample_sh[1]);
+ DRW_SHADER_FREE_SAFE(e_data.bloom_upsample_sh[1]);
+ DRW_SHADER_FREE_SAFE(e_data.bloom_resolve_sh[1]);
+} \ No newline at end of file
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..1f178fb1302
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_engine.c
@@ -0,0 +1,251 @@
+/*
+ * 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 "DNA_world_types.h"
+#include "DRW_render.h"
+
+#include "BLI_dynstr.h"
+#include "BLI_rand.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_SceneLayerData *sldata = EEVEE_scene_layer_data_get();
+
+ DRWFboTexture tex = {&txl->color, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER};
+
+ const float *viewport_size = DRW_viewport_size_get();
+ DRW_framebuffer_init(&fbl->main, &draw_engine_eevee_type,
+ (int)viewport_size[0], (int)viewport_size[1],
+ &tex, 1);
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+ stl->g_data->background_alpha = 1.0f;
+
+ EEVEE_materials_init(stl);
+ EEVEE_lights_init(sldata);
+ EEVEE_lightprobes_init(sldata, vedata);
+ EEVEE_effects_init(sldata, vedata);
+}
+
+static void EEVEE_cache_init(void *vedata)
+{
+ EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ EEVEE_SceneLayerData *sldata = EEVEE_scene_layer_data_get();
+
+ EEVEE_materials_cache_init(vedata);
+ EEVEE_lights_cache_init(sldata, psl);
+ EEVEE_lightprobes_cache_init(sldata, vedata);
+ EEVEE_effects_cache_init(sldata, vedata);
+}
+
+static void EEVEE_cache_populate(void *vedata, Object *ob)
+{
+ EEVEE_SceneLayerData *sldata = EEVEE_scene_layer_data_get();
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const bool is_active = (ob == draw_ctx->obact);
+ if (is_active) {
+ if (DRW_object_is_mode_shade(ob) == true) {
+ return;
+ }
+ }
+
+ if (ELEM(ob->type, OB_MESH)) {
+ EEVEE_materials_cache_populate(vedata, sldata, ob);
+
+ const bool cast_shadow = true;
+
+ if (cast_shadow) {
+ BLI_addtail(&sldata->shadow_casters, BLI_genericNodeN(ob));
+ EEVEE_ObjectEngineData *oedata = EEVEE_object_data_get(ob);
+ oedata->need_update = ((ob->deg_update_flag & DEG_RUNTIME_DATA_UPDATE) != 0);
+ }
+ }
+ else if (ob->type == OB_LIGHTPROBE) {
+ EEVEE_lightprobes_cache_add(sldata, ob);
+ }
+ else if (ob->type == OB_LAMP) {
+ EEVEE_lights_cache_add(sldata, ob);
+ }
+}
+
+static void EEVEE_cache_finish(void *vedata)
+{
+ EEVEE_SceneLayerData *sldata = EEVEE_scene_layer_data_get();
+
+ EEVEE_materials_cache_finish(vedata);
+ EEVEE_lights_cache_finish(sldata);
+ EEVEE_lightprobes_cache_finish(sldata, vedata);
+}
+
+static void EEVEE_draw_scene(void *vedata)
+{
+ EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ EEVEE_FramebufferList *fbl = ((EEVEE_Data *)vedata)->fbl;
+ EEVEE_SceneLayerData *sldata = EEVEE_scene_layer_data_get();
+
+ /* Default framebuffer and texture */
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ /* Refresh shadows */
+ EEVEE_draw_shadows(sldata, psl);
+
+ /* Refresh Probes */
+ EEVEE_lightprobes_refresh(sldata, vedata);
+
+ /* Attach depth to the hdr buffer and bind it */
+ DRW_framebuffer_texture_detach(dtxl->depth);
+ DRW_framebuffer_texture_attach(fbl->main, dtxl->depth, 0, 0);
+ DRW_framebuffer_bind(fbl->main);
+ DRW_framebuffer_clear(false, true, false, NULL, 1.0f);
+
+ DRW_draw_pass(psl->background_pass);
+
+ /* 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);
+
+ /* Restore main FB */
+ DRW_framebuffer_bind(fbl->main);
+
+ /* Shading pass */
+ DRW_draw_pass(psl->probe_display);
+ EEVEE_draw_default_passes(psl);
+ DRW_draw_pass(psl->material_pass);
+
+ /* Volumetrics */
+ EEVEE_effects_do_volumetrics(sldata, vedata);
+
+ /* Transparent */
+ DRW_pass_sort_shgroup_z(psl->transparent_pass);
+ DRW_draw_pass(psl->transparent_pass);
+
+ /* Post Process */
+ EEVEE_draw_effects(vedata);
+}
+
+static void EEVEE_engine_free(void)
+{
+ EEVEE_materials_free();
+ EEVEE_effects_free();
+ EEVEE_lights_free();
+ EEVEE_lightprobes_free();
+}
+
+static void EEVEE_layer_collection_settings_create(RenderEngine *UNUSED(engine), IDProperty *props)
+{
+ BLI_assert(props &&
+ props->type == IDP_GROUP &&
+ props->subtype == IDP_GROUP_SUB_ENGINE_RENDER);
+ // BKE_collection_engine_property_add_int(props, "high_quality_sphere_lamps", false);
+ UNUSED_VARS_NDEBUG(props);
+}
+
+static void EEVEE_scene_layer_settings_create(RenderEngine *UNUSED(engine), IDProperty *props)
+{
+ BLI_assert(props &&
+ props->type == IDP_GROUP &&
+ props->subtype == IDP_GROUP_SUB_ENGINE_RENDER);
+
+ BKE_collection_engine_property_add_bool(props, "volumetric_enable", false);
+ BKE_collection_engine_property_add_float(props, "volumetric_start", 0.1f);
+ BKE_collection_engine_property_add_float(props, "volumetric_end", 100.0f);
+ BKE_collection_engine_property_add_int(props, "volumetric_samples", 64);
+ BKE_collection_engine_property_add_float(props, "volumetric_sample_distribution", 0.8f);
+ BKE_collection_engine_property_add_bool(props, "volumetric_lights", true);
+ BKE_collection_engine_property_add_float(props, "volumetric_light_clamp", 0.0f);
+ BKE_collection_engine_property_add_bool(props, "volumetric_shadows", false);
+ BKE_collection_engine_property_add_int(props, "volumetric_shadow_samples", 16);
+ BKE_collection_engine_property_add_bool(props, "volumetric_colored_transmittance", true);
+
+ BKE_collection_engine_property_add_bool(props, "gtao_enable", false);
+ BKE_collection_engine_property_add_bool(props, "gtao_use_bent_normals", true);
+ BKE_collection_engine_property_add_float(props, "gtao_distance", 0.2f);
+ BKE_collection_engine_property_add_float(props, "gtao_factor", 1.0f);
+ BKE_collection_engine_property_add_int(props, "gtao_samples", 2);
+
+ BKE_collection_engine_property_add_bool(props, "dof_enable", false);
+ BKE_collection_engine_property_add_float(props, "bokeh_max_size", 100.0f);
+ BKE_collection_engine_property_add_float(props, "bokeh_threshold", 1.0f);
+
+ BKE_collection_engine_property_add_bool(props, "bloom_enable", false);
+ BKE_collection_engine_property_add_float(props, "bloom_threshold", 0.8f);
+ BKE_collection_engine_property_add_float(props, "bloom_knee", 0.5f);
+ BKE_collection_engine_property_add_float(props, "bloom_intensity", 0.8f);
+ BKE_collection_engine_property_add_float(props, "bloom_radius", 6.5f);
+
+ BKE_collection_engine_property_add_bool(props, "motion_blur_enable", false);
+ BKE_collection_engine_property_add_int(props, "motion_blur_samples", 8);
+ BKE_collection_engine_property_add_float(props, "motion_blur_shutter", 1.0f);
+}
+
+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_scene,
+ NULL//&EEVEE_draw_scene
+};
+
+RenderEngineType DRW_engine_viewport_eevee_type = {
+ NULL, NULL,
+ EEVEE_ENGINE, N_("Eevee"), RE_INTERNAL | RE_USE_SHADING_NODES,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ &EEVEE_layer_collection_settings_create, &EEVEE_scene_layer_settings_create,
+ &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..0cbd89a79fa
--- /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__ */ \ No newline at end of file
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..b2c21278cdd
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c
@@ -0,0 +1,1345 @@
+/*
+ * 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 "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_object.h"
+
+#include "BLI_dynstr.h"
+
+#include "ED_screen.h"
+
+#include "DRW_render.h"
+
+#include "GPU_material.h"
+#include "GPU_texture.h"
+#include "GPU_glew.h"
+
+#include "DRW_render.h"
+
+#include "eevee_engine.h"
+#include "eevee_private.h"
+
+/* TODO Option */
+#define PROBE_RT_SIZE 512 /* Cube render target */
+#define PROBE_OCTAHEDRON_SIZE 1024
+#define IRRADIANCE_POOL_SIZE 1024
+
+static struct {
+ struct GPUShader *probe_default_sh;
+ struct GPUShader *probe_filter_glossy_sh;
+ struct GPUShader *probe_filter_diffuse_sh;
+ struct GPUShader *probe_grid_display_sh;
+ struct GPUShader *probe_planar_display_sh;
+ struct GPUShader *probe_planar_downsample_sh;
+ struct GPUShader *probe_cube_display_sh;
+
+ struct GPUTexture *hammersley;
+ struct GPUTexture *planar_depth;
+ struct GPUTexture *planar_minmaxz;
+ struct GPUTexture *planar_pool_placeholder;
+ struct GPUTexture *cube_face_depth;
+ struct GPUTexture *cube_face_minmaxz;
+
+ bool update_world;
+ bool world_ready_to_shade;
+} e_data = {NULL}; /* Engine data */
+
+extern char datatoc_background_vert_glsl[];
+extern char datatoc_default_world_frag_glsl[];
+extern char datatoc_lightprobe_filter_glossy_frag_glsl[];
+extern char datatoc_lightprobe_filter_diffuse_frag_glsl[];
+extern char datatoc_lightprobe_geom_glsl[];
+extern char datatoc_lightprobe_vert_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_lightprobe_cube_display_frag_glsl[];
+extern char datatoc_lightprobe_cube_display_vert_glsl[];
+extern char datatoc_lightprobe_grid_display_frag_glsl[];
+extern char datatoc_lightprobe_grid_display_vert_glsl[];
+extern char datatoc_irradiance_lib_glsl[];
+extern char datatoc_lightprobe_lib_glsl[];
+extern char datatoc_octahedron_lib_glsl[];
+extern char datatoc_bsdf_common_lib_glsl[];
+extern char datatoc_bsdf_sampling_lib_glsl[];
+
+extern GlobalsUboStorage ts;
+
+/* *********** FUNCTIONS *********** */
+
+/* Van der Corput sequence */
+ /* From http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html */
+static float radical_inverse(int i) {
+ unsigned int bits = (unsigned int)i;
+ bits = (bits << 16u) | (bits >> 16u);
+ bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
+ bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
+ bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
+ bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
+ return (float)bits * 2.3283064365386963e-10f;
+}
+
+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++) {
+ float phi = radical_inverse(i) * 2.0f * M_PI;
+ texels[i][0] = cosf(phi);
+ texels[i][1] = sinf(phi);
+ }
+
+ tex = DRW_texture_create_1D(samples, DRW_TEX_RG_16, DRW_TEX_WRAP, (float *)texels);
+ MEM_freeN(texels);
+ return tex;
+}
+
+static void planar_pool_ensure_alloc(EEVEE_Data *vedata, int num_planar_ref)
+{
+ /* 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. */
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_TextureList *txl = vedata->txl;
+
+ const float *viewport_size = DRW_viewport_size_get();
+
+ /* TODO get screen percentage from layer setting */
+ // const DRWContextState *draw_ctx = DRW_context_state_get();
+ // SceneLayer *sl = draw_ctx->sl;
+ 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),
+ DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP, 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, DRW_TEX_RGBA_8, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
+ }
+ }
+
+ if (num_planar_ref > 0) {
+ /* NOTE : Depth buffer is 2D but the planar_pool tex is 2D array.
+ * DRW_framebuffer_init binds the whole texture making the framebuffer invalid.
+ * To overcome this, we bind the planar pool ourselves later */
+
+ /* XXX Do this one first so it gets it's mipmap done. */
+ DRWFboTexture tex_minmaxz = {&e_data.planar_minmaxz, DRW_TEX_RG_32, DRW_TEX_MIPMAP | DRW_TEX_TEMP};
+ DRW_framebuffer_init(&fbl->planarref_fb, &draw_engine_eevee_type,
+ width / 2, height / 2, &tex_minmaxz, 1);
+
+ /* Note: this is not the configuration used when rendering. */
+ DRWFboTexture tex = {&e_data.planar_depth, DRW_TEX_DEPTH_24, DRW_TEX_TEMP};
+ DRW_framebuffer_init(&fbl->planarref_fb, &draw_engine_eevee_type,
+ width, height, &tex, 1);
+ }
+}
+
+void EEVEE_lightprobes_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *UNUSED(vedata))
+{
+ /* Shaders */
+ if (!e_data.probe_filter_glossy_sh) {
+ char *shader_str = NULL;
+
+ DynStr *ds_frag = BLI_dynstr_new();
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_lightprobe_filter_glossy_frag_glsl);
+ shader_str = BLI_dynstr_get_cstring(ds_frag);
+ BLI_dynstr_free(ds_frag);
+
+ e_data.probe_filter_glossy_sh = DRW_shader_create(
+ datatoc_lightprobe_vert_glsl, datatoc_lightprobe_geom_glsl, shader_str,
+ "#define HAMMERSLEY_SIZE 1024\n"
+ "#define NOISE_SIZE 64\n");
+
+ e_data.probe_default_sh = DRW_shader_create(
+ datatoc_background_vert_glsl, NULL, datatoc_default_world_frag_glsl, NULL);
+
+ MEM_freeN(shader_str);
+
+ ds_frag = BLI_dynstr_new();
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_lightprobe_filter_diffuse_frag_glsl);
+ shader_str = BLI_dynstr_get_cstring(ds_frag);
+ BLI_dynstr_free(ds_frag);
+
+ e_data.probe_filter_diffuse_sh = DRW_shader_create_fullscreen(
+ shader_str,
+#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 HAMMERSLEY_SIZE 1024\n"
+ "#define NOISE_SIZE 64\n");
+
+ MEM_freeN(shader_str);
+
+ ds_frag = BLI_dynstr_new();
+ BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_lightprobe_grid_display_frag_glsl);
+ shader_str = BLI_dynstr_get_cstring(ds_frag);
+ BLI_dynstr_free(ds_frag);
+
+ e_data.probe_grid_display_sh = DRW_shader_create(
+ datatoc_lightprobe_grid_display_vert_glsl, NULL, shader_str,
+#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
+ );
+
+ MEM_freeN(shader_str);
+
+ ds_frag = BLI_dynstr_new();
+ BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_lightprobe_cube_display_frag_glsl);
+ shader_str = BLI_dynstr_get_cstring(ds_frag);
+ BLI_dynstr_free(ds_frag);
+
+ e_data.probe_cube_display_sh = DRW_shader_create(
+ datatoc_lightprobe_cube_display_vert_glsl, NULL, shader_str, NULL);
+
+ MEM_freeN(shader_str);
+
+ ds_frag = BLI_dynstr_new();
+ BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_lightprobe_planar_display_frag_glsl);
+ shader_str = BLI_dynstr_get_cstring(ds_frag);
+ BLI_dynstr_free(ds_frag);
+
+ e_data.probe_planar_display_sh = DRW_shader_create(
+ datatoc_lightprobe_planar_display_vert_glsl, NULL, shader_str,
+ "#define MAX_PLANAR " STRINGIFY(MAX_PLANAR) "\n");
+
+ MEM_freeN(shader_str);
+
+ 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);
+
+ e_data.hammersley = create_hammersley_sample_texture(1024);
+ }
+
+ if (!sldata->probes) {
+ sldata->probes = MEM_callocN(sizeof(EEVEE_LightProbesInfo), "EEVEE_LightProbesInfo");
+ sldata->probes->specular_toggle = true;
+ 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);
+ }
+
+ /* Setup Render Target Cubemap */
+
+ /* We do this detach / attach dance to not generate an invalid framebuffer (mixed cubemap / 2D map) */
+ if (sldata->probe_rt) {
+ /* XXX Silly,TODO Cleanup this mess */
+ DRW_framebuffer_texture_detach(sldata->probe_rt);
+ }
+
+ DRWFboTexture tex_probe = {&e_data.cube_face_depth, DRW_TEX_DEPTH_24, DRW_TEX_TEMP};
+ DRW_framebuffer_init(&sldata->probe_fb, &draw_engine_eevee_type, PROBE_RT_SIZE, PROBE_RT_SIZE, &tex_probe, 1);
+
+ if (!sldata->probe_rt) {
+ sldata->probe_rt = DRW_texture_create_cube(PROBE_RT_SIZE, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
+ }
+
+ if (sldata->probe_rt) {
+ /* XXX Silly,TODO Cleanup this mess */
+ DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_rt, 0, 0);
+ }
+
+ /* Minmaxz Pyramid */
+ /* Highjacking the minmaxz_fb but that's ok because it's reconfigured before usage. */
+ // DRWFboTexture tex_minmaxz = {&e_data.cube_face_minmaxz, DRW_TEX_RG_32, DRW_TEX_MIPMAP | DRW_TEX_TEMP};
+ // DRW_framebuffer_init(&vedata->fbl->minmaxz_fb, &draw_engine_eevee_type, PROBE_RT_SIZE / 2, PROBE_RT_SIZE / 2, &tex_minmaxz, 1);
+
+ /* 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, DRW_TEX_RGBA_8, DRW_TEX_FILTER, NULL);
+ }
+}
+
+void EEVEE_lightprobes_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+
+ pinfo->num_cube = 1; /* at least one for the world */
+ pinfo->num_grid = 1;
+ pinfo->num_planar = 0;
+ memset(pinfo->probes_cube_ref, 0, sizeof(pinfo->probes_cube_ref));
+ memset(pinfo->probes_grid_ref, 0, sizeof(pinfo->probes_grid_ref));
+ memset(pinfo->probes_planar_ref, 0, sizeof(pinfo->probes_planar_ref));
+
+ {
+ psl->probe_background = DRW_pass_create("World Probe Pass", DRW_STATE_WRITE_COLOR);
+
+ struct Gwn_Batch *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;
+ if (wo) {
+ col = &wo->horr;
+ e_data.update_world = (wo->update_flag != 0);
+ wo->update_flag = 0;
+
+ if (wo->use_nodes && wo->nodetree) {
+ struct GPUMaterial *gpumat = EEVEE_material_world_lightprobe_get(scene, wo);
+
+ grp = DRW_shgroup_material_create(gpumat, psl->probe_background);
+
+ if (grp) {
+ DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
+ DRW_shgroup_call_add(grp, geom, NULL);
+ }
+ else {
+ /* Shader failed : pink background */
+ static float pink[3] = {1.0f, 0.0f, 1.0f};
+ col = pink;
+ }
+ }
+ }
+
+ /* Fallback if shader fails or if not using nodetree. */
+ if (grp == NULL) {
+ grp = DRW_shgroup_create(e_data.probe_default_sh, 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);
+ }
+ }
+
+ {
+ psl->probe_glossy_compute = DRW_pass_create("LightProbe Glossy Compute", DRW_STATE_WRITE_COLOR);
+
+ struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get();
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(e_data.probe_filter_glossy_sh, psl->probe_glossy_compute, geom);
+ DRW_shgroup_uniform_float(grp, "sampleCount", &sldata->probes->samples_ct, 1);
+ DRW_shgroup_uniform_float(grp, "invSampleCount", &sldata->probes->invsamples_ct, 1);
+ DRW_shgroup_uniform_float(grp, "roughnessSquared", &sldata->probes->roughness, 1);
+ DRW_shgroup_uniform_float(grp, "lodFactor", &sldata->probes->lodfactor, 1);
+ DRW_shgroup_uniform_float(grp, "lodMax", &sldata->probes->lod_rt_max, 1);
+ DRW_shgroup_uniform_float(grp, "texelSize", &sldata->probes->texel_size, 1);
+ DRW_shgroup_uniform_float(grp, "paddingSize", &sldata->probes->padding_size, 1);
+ DRW_shgroup_uniform_int(grp, "Layer", &sldata->probes->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", sldata->probe_rt);
+
+ DRW_shgroup_call_dynamic_add_empty(grp);
+ }
+
+ {
+ psl->probe_diffuse_compute = DRW_pass_create("LightProbe Diffuse Compute", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_filter_diffuse_sh, psl->probe_diffuse_compute);
+#ifdef IRRADIANCE_SH_L2
+ DRW_shgroup_uniform_int(grp, "probeSize", &sldata->probes->shres, 1);
+#else
+ DRW_shgroup_uniform_float(grp, "sampleCount", &sldata->probes->samples_ct, 1);
+ DRW_shgroup_uniform_float(grp, "invSampleCount", &sldata->probes->invsamples_ct, 1);
+ DRW_shgroup_uniform_float(grp, "lodFactor", &sldata->probes->lodfactor, 1);
+ DRW_shgroup_uniform_float(grp, "lodMax", &sldata->probes->lod_rt_max, 1);
+ DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
+#endif
+ DRW_shgroup_uniform_texture(grp, "probeHdr", sldata->probe_rt);
+
+ struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get();
+ DRW_shgroup_call_add(grp, geom, NULL);
+ }
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_CULL_BACK;
+ psl->probe_display = DRW_pass_create("LightProbe Display", state);
+
+ struct Gwn_Batch *geom = DRW_cache_sphere_get();
+ DRWShadingGroup *grp = stl->g_data->cube_display_shgrp = DRW_shgroup_instance_create(e_data.probe_cube_display_sh, psl->probe_display, geom);
+ DRW_shgroup_attrib_float(grp, "probe_id", 1); /* XXX this works because we are still uploading 4bytes and using the right stride */
+ DRW_shgroup_attrib_float(grp, "probe_location", 3);
+ DRW_shgroup_attrib_float(grp, "sphere_size", 1);
+ DRW_shgroup_uniform_float(grp, "lodCubeMax", &sldata->probes->lod_cube_max, 1);
+ DRW_shgroup_uniform_buffer(grp, "probeCubes", &sldata->probe_pool);
+ }
+
+ {
+ psl->probe_planar_downsample_ps = DRW_pass_create("LightProbe Planar Downsample", DRW_STATE_WRITE_COLOR);
+
+ struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get();
+ DRWShadingGroup *grp = stl->g_data->planar_downsample = DRW_shgroup_instance_create(e_data.probe_planar_downsample_sh, psl->probe_planar_downsample_ps, geom);
+ DRW_shgroup_uniform_buffer(grp, "source", &txl->planar_pool);
+ DRW_shgroup_uniform_vec2(grp, "texelSize", stl->g_data->texel_size, 1);
+ }
+}
+
+void EEVEE_lightprobes_cache_add(EEVEE_SceneLayerData *sldata, Object *ob)
+{
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ LightProbe *probe = (LightProbe *)ob->data;
+
+ /* Step 1 find all lamps in the scene and setup them */
+ if ((probe->type == LIGHTPROBE_TYPE_CUBE && pinfo->num_cube >= MAX_PROBE) ||
+ (probe->type == LIGHTPROBE_TYPE_GRID && pinfo->num_grid >= MAX_PROBE))
+ {
+ printf("Too much probes in the scene !!!\n");
+ return;
+ }
+
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
+
+ ped->num_cell = probe->grid_resolution_x * probe->grid_resolution_y * probe->grid_resolution_z;
+
+ if ((ob->deg_update_flag & DEG_RUNTIME_DATA_UPDATE) != 0) {
+ ped->need_update = true;
+ ped->probe_id = 0;
+
+ if (probe->type == LIGHTPROBE_TYPE_GRID) {
+ ped->updated_cells = 0;
+ pinfo->updated_bounce = 0;
+ }
+ }
+
+ if (e_data.update_world) {
+ ped->need_update = true;
+ ped->updated_cells = 0;
+ ped->probe_id = 0;
+ pinfo->updated_bounce = 0;
+ }
+
+ if (probe->type == LIGHTPROBE_TYPE_CUBE) {
+ pinfo->probes_cube_ref[pinfo->num_cube] = ob;
+ pinfo->num_cube++;
+ }
+ else if (probe->type == LIGHTPROBE_TYPE_PLANAR) {
+ pinfo->probes_planar_ref[pinfo->num_planar] = ob;
+ pinfo->num_planar++;
+ }
+ else { /* GRID */
+ pinfo->probes_grid_ref[pinfo->num_grid] = ob;
+ pinfo->num_grid++;
+ }
+}
+
+/* TODO find a nice name to push it to math_matrix.c */
+static void scale_m4_v3(float R[4][4], float v[3])
+{
+ for (int i = 0; i < 4; ++i)
+ mul_v3_v3(R[i], v);
+}
+
+static void EEVEE_planar_reflections_updates(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl, EEVEE_TextureList *txl)
+{
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ Object *ob;
+ float mtx[4][4], normat[4][4], imat[4][4], rangemat[4][4];
+
+ float viewmat[4][4], winmat[4][4];
+ DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW);
+ DRW_viewport_matrix_get(winmat, DRW_MAT_WIN);
+
+ zero_m4(rangemat);
+ rangemat[0][0] = rangemat[1][1] = rangemat[2][2] = 0.5f;
+ rangemat[3][0] = rangemat[3][1] = rangemat[3][2] = 0.5f;
+ rangemat[3][3] = 1.0f;
+
+ /* PLANAR REFLECTION */
+ for (int i = 0; (ob = pinfo->probes_planar_ref[i]) && (i < MAX_PLANAR); i++) {
+ LightProbe *probe = (LightProbe *)ob->data;
+ EEVEE_PlanarReflection *eplanar = &pinfo->planar_data[i];
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
+
+ /* 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 */
+
+ float reflect[3] = {1.0f, 1.0f, -1.0f}; /* XY reflection plane */
+ scale_m4_v3(imat, reflect); /* world > object > mirrored obj */
+ mul_m4_m4m4(mtx, normat, imat); /* world > object > mirrored obj > world */
+
+ /* Reflect Camera Matrix. */
+ mul_m4_m4m4(ped->viewmat, viewmat, mtx);
+
+ /* TODO FOV margin */
+ float winmat_fov[4][4];
+ copy_m4_m4(winmat_fov, winmat);
+
+ /* Apply Perspective Matrix. */
+ mul_m4_m4m4(ped->persmat, winmat_fov, ped->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, winmat_fov, viewmat); /* TODO FOV margin */
+ /* Convert from [-1, 1] to [0, 1] (NDC to Texture coord). */
+ mul_m4_m4m4(eplanar->reflectionmat, rangemat, eplanar->reflectionmat);
+
+ /* TODO frustum check. */
+ ped->need_update = true;
+
+ /* Compute clip plane equation / normal. */
+ float refpoint[3];
+ 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]);
+
+ /* Compute offset plane equation (fix missing texels near reflection plane). */
+ copy_v3_v3(ped->planer_eq_offset, eplanar->plane_equation);
+ mul_v3_v3fl(refpoint, eplanar->plane_equation, -probe->clipsta);
+ add_v3_v3(refpoint, ob->obmat[3]);
+ ped->planer_eq_offset[3] = -dot_v3v3(eplanar->plane_equation, refpoint);
+
+ /* 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, 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;
+
+ /* Debug Display */
+ if (DRW_state_draw_support() && (probe->flag & LIGHTPROBE_FLAG_SHOW_DATA)) {
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_planar_display_sh, psl->probe_display);
+
+ DRW_shgroup_uniform_int(grp, "probeIdx", &ped->probe_id, 1);
+ DRW_shgroup_uniform_buffer(grp, "probePlanars", &txl->planar_pool);
+ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
+
+ struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get();
+ DRW_shgroup_call_add(grp, geom, ob->obmat);
+ }
+ }
+}
+
+static void EEVEE_lightprobes_updates(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl, EEVEE_StorageList *stl)
+{
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ Object *ob;
+
+ /* CUBE REFLECTION */
+ for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) {
+ LightProbe *probe = (LightProbe *)ob->data;
+ EEVEE_LightProbe *eprobe = &pinfo->probe_data[i];
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
+
+ /* 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 */
+ float dist;
+ if ((probe->flag & LIGHTPROBE_FLAG_CUSTOM_PARALLAX) != 0) {
+ eprobe->parallax_type = probe->parallax_type;
+ dist = probe->distpar;
+ }
+ else {
+ eprobe->parallax_type = probe->attenuation_type;
+ dist = probe->distinf;
+ }
+
+ unit_m4(eprobe->parallaxmat);
+ scale_m4_fl(eprobe->parallaxmat, dist);
+ mul_m4_m4m4(eprobe->parallaxmat, ob->obmat, eprobe->parallaxmat);
+ invert_m4(eprobe->parallaxmat);
+
+ /* Debug Display */
+ if (DRW_state_draw_support() && (probe->flag & LIGHTPROBE_FLAG_SHOW_DATA)) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->cube_display_shgrp, &ped->probe_id, ob->obmat[3], &probe->data_draw_size);
+ }
+ }
+
+ /* IRRADIANCE GRID */
+ int offset = 1; /* to account for the world probe */
+ for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) {
+ LightProbe *probe = (LightProbe *)ob->data;
+ EEVEE_LightGrid *egrid = &pinfo->grid_data[i];
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
+
+ egrid->offset = offset;
+ float fac = 1.0f / max_ff(1e-8f, probe->falloff);
+ egrid->attenuation_scale = fac / max_ff(1e-8f, probe->distinf);
+ egrid->attenuation_bias = fac;
+
+ /* Set offset for the next grid */
+ offset += ped->num_cell;
+
+ /* Update transforms */
+ float cell_dim[3], half_cell_dim[3];
+ cell_dim[0] = 2.0f / (float)(probe->grid_resolution_x);
+ cell_dim[1] = 2.0f / (float)(probe->grid_resolution_y);
+ cell_dim[2] = 2.0f / (float)(probe->grid_resolution_z);
+
+ 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);
+
+ copy_v3_v3_int(egrid->resolution, &probe->grid_resolution_x);
+
+ /* Debug Display */
+ if (DRW_state_draw_support() && (probe->flag & LIGHTPROBE_FLAG_SHOW_DATA)) {
+ struct Gwn_Batch *geom = DRW_cache_sphere_get();
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(e_data.probe_grid_display_sh, psl->probe_display, geom);
+ DRW_shgroup_set_instance_count(grp, ped->num_cell);
+ DRW_shgroup_uniform_int(grp, "offset", &egrid->offset, 1);
+ DRW_shgroup_uniform_ivec3(grp, "grid_resolution", egrid->resolution, 1);
+ DRW_shgroup_uniform_vec3(grp, "corner", egrid->corner, 1);
+ DRW_shgroup_uniform_vec3(grp, "increment_x", egrid->increment_x, 1);
+ DRW_shgroup_uniform_vec3(grp, "increment_y", egrid->increment_y, 1);
+ DRW_shgroup_uniform_vec3(grp, "increment_z", egrid->increment_z, 1);
+ DRW_shgroup_uniform_buffer(grp, "irradianceGrid", &sldata->irradiance_pool);
+ DRW_shgroup_uniform_float(grp, "sphere_size", &probe->data_draw_size, 1);
+ }
+ }
+}
+
+void EEVEE_lightprobes_cache_finish(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ Object *ob;
+
+ /* Setup enough layers. */
+ /* Free textures if number mismatch. */
+ if (pinfo->num_cube != pinfo->cache_num_cube) {
+ DRW_TEXTURE_FREE_SAFE(sldata->probe_pool);
+ }
+
+ if (pinfo->num_planar != pinfo->cache_num_planar) {
+ DRW_TEXTURE_FREE_SAFE(vedata->txl->planar_pool);
+ pinfo->cache_num_planar = pinfo->num_planar;
+ }
+
+ /* XXX this should be run each frame as it ensure planar_depth is set */
+ planar_pool_ensure_alloc(vedata, pinfo->num_planar);
+
+ /* Setup planar filtering pass */
+ DRW_shgroup_set_instance_count(stl->g_data->planar_downsample, pinfo->num_planar);
+
+ if (!sldata->probe_pool) {
+ sldata->probe_pool = DRW_texture_create_2D_array(PROBE_OCTAHEDRON_SIZE, PROBE_OCTAHEDRON_SIZE, max_ff(1, pinfo->num_cube),
+ DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
+ if (sldata->probe_filter_fb) {
+ DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0);
+ }
+
+ /* Tag probes to refresh */
+ e_data.update_world = true;
+ e_data.world_ready_to_shade = false;
+ pinfo->num_render_cube = 0;
+ pinfo->update_flag |= PROBE_UPDATE_CUBE;
+ pinfo->cache_num_cube = pinfo->num_cube;
+
+ for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) {
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
+ ped->need_update = true;
+ ped->ready_to_shade = false;
+ ped->probe_id = 0;
+ }
+ }
+
+ DRWFboTexture tex_filter = {&sldata->probe_pool, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP};
+
+ DRW_framebuffer_init(&sldata->probe_filter_fb, &draw_engine_eevee_type, PROBE_OCTAHEDRON_SIZE, PROBE_OCTAHEDRON_SIZE, &tex_filter, 1);
+
+
+#ifdef IRRADIANCE_SH_L2
+ /* we need a signed format for Spherical Harmonics */
+ int irradiance_format = DRW_TEX_RGBA_16;
+#else
+ int irradiance_format = DRW_TEX_RGB_11_11_10;
+#endif
+
+ /* TODO Allocate bigger storage if needed. */
+ if (!sldata->irradiance_pool) {
+ sldata->irradiance_pool = DRW_texture_create_2D(IRRADIANCE_POOL_SIZE, IRRADIANCE_POOL_SIZE, irradiance_format, DRW_TEX_FILTER, NULL);
+ pinfo->num_render_grid = 0;
+ pinfo->updated_bounce = 0;
+
+ for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_PROBE); i++) {
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
+ ped->need_update = true;
+ ped->updated_cells = 0;
+ }
+ }
+
+ if (!sldata->irradiance_rt) {
+ sldata->irradiance_rt = DRW_texture_create_2D(IRRADIANCE_POOL_SIZE, IRRADIANCE_POOL_SIZE, irradiance_format, DRW_TEX_FILTER, NULL);
+ pinfo->num_render_grid = 0;
+ pinfo->updated_bounce = 0;
+
+ for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_PROBE); i++) {
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
+ ped->need_update = true;
+ ped->updated_cells = 0;
+ }
+ }
+
+ EEVEE_lightprobes_updates(sldata, vedata->psl, vedata->stl);
+ EEVEE_planar_reflections_updates(sldata, vedata->psl, vedata->txl);
+
+ DRW_uniformbuffer_update(sldata->probe_ubo, &sldata->probes->probe_data);
+ DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data);
+ DRW_uniformbuffer_update(sldata->planar_ubo, &sldata->probes->planar_data);
+}
+
+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->texel_size, size);
+ for (int i = 0; i < level - 1; ++i) {
+ stl->g_data->texel_size[0] /= 2.0f;
+ stl->g_data->texel_size[1] /= 2.0f;
+ min_ff(floorf(stl->g_data->texel_size[0]), 1.0f);
+ min_ff(floorf(stl->g_data->texel_size[1]), 1.0f);
+ }
+ invert_v2(stl->g_data->texel_size);
+
+ DRW_draw_pass(psl->probe_planar_downsample_ps);
+}
+
+/* Glossy filter probe_rt to probe_pool at index probe_idx */
+static void glossy_filter_probe(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl, int probe_idx)
+{
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+
+ /* 2 - Let gpu create Mipmaps for Filtered Importance Sampling. */
+ /* Bind next framebuffer to be able to gen. mips for probe_rt. */
+ DRW_framebuffer_bind(sldata->probe_filter_fb);
+ DRW_texture_generate_mipmaps(sldata->probe_rt);
+
+ /* 3 - Render to probe array to the specified layer, do prefiltering. */
+ /* Detach to rebind the right mipmap. */
+ DRW_framebuffer_texture_detach(sldata->probe_pool);
+ float mipsize = PROBE_OCTAHEDRON_SIZE;
+ const int maxlevel = (int)floorf(log2f(PROBE_OCTAHEDRON_SIZE));
+ const int min_lod_level = 3;
+ for (int i = 0; i < maxlevel - min_lod_level; i++) {
+ float bias = (i == 0) ? 0.0f : 1.0f;
+ pinfo->texel_size = 1.0f / mipsize;
+ pinfo->padding_size = powf(2.0f, (float)(maxlevel - min_lod_level - 1 - i));
+ /* XXX : WHY THE HECK DO WE NEED THIS ??? */
+ /* padding is incorrect without this! float precision issue? */
+ if (pinfo->padding_size > 32) {
+ pinfo->padding_size += 5;
+ }
+ if (pinfo->padding_size > 16) {
+ pinfo->padding_size += 4;
+ }
+ else if (pinfo->padding_size > 8) {
+ pinfo->padding_size += 2;
+ }
+ else if (pinfo->padding_size > 4) {
+ pinfo->padding_size += 1;
+ }
+ pinfo->layer = probe_idx;
+ pinfo->roughness = (float)i / ((float)maxlevel - 4.0f);
+ 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_ct = 1.0f; break;
+ case 1: pinfo->samples_ct = 16.0f; break;
+ case 2: pinfo->samples_ct = 32.0f; break;
+ case 3: pinfo->samples_ct = 64.0f; break;
+ default: pinfo->samples_ct = 128.0f; break;
+ }
+#else /* Constant Sample count (slow) */
+ pinfo->samples_ct = 1024.0f;
+#endif
+
+ pinfo->invsamples_ct = 1.0f / pinfo->samples_ct;
+ pinfo->lodfactor = bias + 0.5f * log((float)(PROBE_RT_SIZE * PROBE_RT_SIZE) * pinfo->invsamples_ct) / log(2);
+ pinfo->lod_rt_max = floorf(log2f(PROBE_RT_SIZE)) - 2.0f;
+
+ DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, i);
+ DRW_framebuffer_viewport_size(sldata->probe_filter_fb, 0, 0, mipsize, mipsize);
+ DRW_draw_pass(psl->probe_glossy_compute);
+ DRW_framebuffer_texture_detach(sldata->probe_pool);
+
+ mipsize /= 2;
+ CLAMP_MIN(mipsize, 1);
+ }
+ /* For shading, save max level of the octahedron map */
+ pinfo->lod_cube_max = (float)(maxlevel - min_lod_level) - 1.0f;
+
+ /* reattach to have a valid framebuffer. */
+ DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0);
+}
+
+/* Diffuse filter probe_rt to irradiance_pool at index probe_idx */
+static void diffuse_filter_probe(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl, int offset)
+{
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+
+ /* 4 - Compute spherical harmonics */
+ /* Tweaking parameters to balance perf. vs precision */
+ DRW_framebuffer_bind(sldata->probe_filter_fb);
+ DRW_texture_generate_mipmaps(sldata->probe_rt);
+
+ /* Bind the right texture layer (one layer per irradiance grid) */
+ DRW_framebuffer_texture_detach(sldata->probe_pool);
+ DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0);
+
+ /* 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_ct = 1024.0f;
+#elif defined(IRRADIANCE_HL2)
+ int size[2] = {3, 2};
+ pinfo->samples_ct = 1024.0f;
+#endif
+
+ int cell_per_row = IRRADIANCE_POOL_SIZE / size[0];
+ int x = size[0] * (offset % cell_per_row);
+ int y = size[1] * (offset / cell_per_row);
+
+#ifndef IRRADIANCE_SH_L2
+ const float bias = 0.0f;
+ pinfo->invsamples_ct = 1.0f / pinfo->samples_ct;
+ pinfo->lodfactor = bias + 0.5f * log((float)(PROBE_RT_SIZE * PROBE_RT_SIZE) * pinfo->invsamples_ct) / log(2);
+ pinfo->lod_rt_max = floorf(log2f(PROBE_RT_SIZE)) - 2.0f;
+#else
+ pinfo->shres = 32; /* Less texture fetches & reduce branches */
+ pinfo->lod_rt_max = 2.0f; /* Improve cache reuse */
+#endif
+
+ DRW_framebuffer_viewport_size(sldata->probe_filter_fb, x, y, size[0], size[1]);
+ DRW_draw_pass(psl->probe_diffuse_compute);
+
+ /* reattach to have a valid framebuffer. */
+ DRW_framebuffer_texture_detach(sldata->irradiance_rt);
+ DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0);
+}
+
+/* Render the scene to the probe_rt texture. */
+static void render_scene_to_probe(
+ EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata,
+ const float pos[3], float clipsta, float clipend)
+{
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+
+ float winmat[4][4], posmat[4][4], tmp_ao_dist, tmp_ao_samples;
+
+ unit_m4(posmat);
+
+ /* Move to capture position */
+ negate_v3_v3(posmat[3], pos);
+
+ /* Disable specular lighting when rendering probes to avoid feedback loops (looks bad). */
+ sldata->probes->specular_toggle = false;
+
+ /* Disable AO until we find a way to hide really bad discontinuities between cubefaces. */
+ tmp_ao_dist = stl->effects->ao_dist;
+ tmp_ao_samples = stl->effects->ao_samples;
+ stl->effects->ao_dist = 0.0f;
+ stl->effects->ao_samples = 0.0f;
+
+ /* 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 dependant effects). */
+ pinfo->layer = 0;
+ perspective_m4(winmat, -clipsta, clipsta, -clipsta, clipsta, clipsta, clipend);
+
+ /* Avoid using the texture attached to framebuffer when rendering. */
+ /* XXX */
+ GPUTexture *tmp_planar_pool = txl->planar_pool;
+ GPUTexture *tmp_minmaxz = stl->g_data->minmaxz;
+ txl->planar_pool = e_data.planar_pool_placeholder;
+ // stl->g_data->minmaxz = e_data.cube_face_minmaxz;
+
+ /* Detach to rebind the right cubeface. */
+ DRW_framebuffer_bind(sldata->probe_fb);
+ DRW_framebuffer_texture_attach(sldata->probe_fb, e_data.cube_face_depth, 0, 0);
+ DRW_framebuffer_texture_detach(sldata->probe_rt);
+ for (int i = 0; i < 6; ++i) {
+ float viewmat[4][4], persmat[4][4];
+ float viewinv[4][4], persinv[4][4];
+
+ DRW_framebuffer_cubeface_attach(sldata->probe_fb, sldata->probe_rt, 0, i, 0);
+ DRW_framebuffer_viewport_size(sldata->probe_fb, 0, 0, PROBE_RT_SIZE, PROBE_RT_SIZE);
+
+ DRW_framebuffer_clear(false, true, false, NULL, 1.0);
+
+ /* Setup custom matrices */
+ mul_m4_m4m4(viewmat, cubefacemat[i], posmat);
+ mul_m4_m4m4(persmat, winmat, viewmat);
+ invert_m4_m4(persinv, persmat);
+ invert_m4_m4(viewinv, viewmat);
+
+ DRW_viewport_matrix_override_set(persmat, DRW_MAT_PERS);
+ DRW_viewport_matrix_override_set(persinv, DRW_MAT_PERSINV);
+ DRW_viewport_matrix_override_set(viewmat, DRW_MAT_VIEW);
+ DRW_viewport_matrix_override_set(viewinv, DRW_MAT_VIEWINV);
+ DRW_viewport_matrix_override_set(winmat, DRW_MAT_WIN);
+
+ DRW_draw_pass(psl->probe_background);
+
+ /* Depth prepass */
+ DRW_draw_pass(psl->depth_pass);
+ DRW_draw_pass(psl->depth_pass_cull);
+
+ // EEVEE_create_minmax_buffer(vedata, e_data.cube_face_depth);
+
+ /* Rebind Planar FB */
+ DRW_framebuffer_bind(sldata->probe_fb);
+
+ /* Shading pass */
+ EEVEE_draw_default_passes(psl);
+ DRW_draw_pass(psl->material_pass);
+
+ DRW_framebuffer_texture_detach(sldata->probe_rt);
+ }
+ DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_rt, 0, 0);
+ DRW_framebuffer_texture_detach(e_data.cube_face_depth);
+
+ DRW_viewport_matrix_override_unset(DRW_MAT_PERS);
+ DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV);
+ DRW_viewport_matrix_override_unset(DRW_MAT_VIEW);
+ DRW_viewport_matrix_override_unset(DRW_MAT_VIEWINV);
+ DRW_viewport_matrix_override_unset(DRW_MAT_WIN);
+
+ /* Restore */
+ sldata->probes->specular_toggle = true;
+ txl->planar_pool = tmp_planar_pool;
+ stl->g_data->minmaxz = tmp_minmaxz;
+ stl->effects->ao_dist = tmp_ao_dist;
+ stl->effects->ao_samples = tmp_ao_samples;
+}
+
+static void render_scene_to_planar(
+ EEVEE_Data *vedata, int layer,
+ float (*viewmat)[4], float (*persmat)[4],
+ float clip_plane[4])
+{
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+
+ float viewinv[4][4];
+ float persinv[4][4];
+
+ invert_m4_m4(viewinv, viewmat);
+ invert_m4_m4(persinv, persmat);
+
+ /* Attach depth here since it's a DRW_TEX_TEMP */
+ DRW_framebuffer_texture_attach(fbl->planarref_fb, e_data.planar_depth, 0, 0);
+ DRW_framebuffer_texture_layer_attach(fbl->planarref_fb, txl->planar_pool, 0, layer, 0);
+ DRW_framebuffer_bind(fbl->planarref_fb);
+
+ DRW_framebuffer_clear(false, true, false, NULL, 1.0);
+
+ /* Avoid using the texture attached to framebuffer when rendering. */
+ /* XXX */
+ GPUTexture *tmp_planar_pool = txl->planar_pool;
+ GPUTexture *tmp_minmaxz = stl->g_data->minmaxz;
+ txl->planar_pool = e_data.planar_pool_placeholder;
+ stl->g_data->minmaxz = e_data.planar_minmaxz;
+ stl->g_data->background_alpha = FLT_MAX; /* Alpha is distance for planar reflections. */
+
+ DRW_viewport_matrix_override_set(persmat, DRW_MAT_PERS);
+ DRW_viewport_matrix_override_set(persinv, DRW_MAT_PERSINV);
+ DRW_viewport_matrix_override_set(viewmat, DRW_MAT_VIEW);
+ DRW_viewport_matrix_override_set(viewinv, DRW_MAT_VIEWINV);
+
+ /* Background */
+ DRW_draw_pass(psl->probe_background);
+
+ /* 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();
+ DRW_state_clip_planes_add(clip_plane);
+
+ /* Depth prepass */
+ DRW_draw_pass(psl->depth_pass_clip);
+ DRW_draw_pass(psl->depth_pass_clip_cull);
+
+ EEVEE_create_minmax_buffer(vedata, e_data.planar_depth);
+
+ /* Rebind Planar FB */
+ DRW_framebuffer_bind(fbl->planarref_fb);
+
+ /* Shading pass */
+ EEVEE_draw_default_passes(psl);
+ DRW_draw_pass(psl->material_pass);
+
+ DRW_state_invert_facing();
+ DRW_state_clip_planes_reset();
+
+ /* Restore */
+ txl->planar_pool = tmp_planar_pool;
+ stl->g_data->minmaxz = tmp_minmaxz;
+ stl->g_data->background_alpha = 1.0;
+ DRW_viewport_matrix_override_unset(DRW_MAT_PERS);
+ DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV);
+ DRW_viewport_matrix_override_unset(DRW_MAT_VIEW);
+ DRW_viewport_matrix_override_unset(DRW_MAT_VIEWINV);
+
+ DRW_framebuffer_texture_detach(txl->planar_pool);
+ DRW_framebuffer_texture_detach(e_data.planar_depth);
+}
+
+static void render_world_to_probe(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
+{
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ float winmat[4][4];
+
+ /* 1 - Render to cubemap target using geometry shader. */
+ /* For world probe, we don't need to clear since we render the background directly. */
+ pinfo->layer = 0;
+
+ perspective_m4(winmat, -0.1f, 0.1f, -0.1f, 0.1f, 0.1f, 1.0f);
+
+ /* Detach to rebind the right cubeface. */
+ DRW_framebuffer_bind(sldata->probe_fb);
+ DRW_framebuffer_texture_detach(sldata->probe_rt);
+ for (int i = 0; i < 6; ++i) {
+ float viewmat[4][4], persmat[4][4];
+ float viewinv[4][4], persinv[4][4];
+
+ DRW_framebuffer_cubeface_attach(sldata->probe_fb, sldata->probe_rt, 0, i, 0);
+ DRW_framebuffer_viewport_size(sldata->probe_fb, 0, 0, PROBE_RT_SIZE, PROBE_RT_SIZE);
+
+ /* Setup custom matrices */
+ copy_m4_m4(viewmat, cubefacemat[i]);
+ mul_m4_m4m4(persmat, winmat, viewmat);
+ invert_m4_m4(persinv, persmat);
+ invert_m4_m4(viewinv, viewmat);
+
+ DRW_viewport_matrix_override_set(persmat, DRW_MAT_PERS);
+ DRW_viewport_matrix_override_set(persinv, DRW_MAT_PERSINV);
+ DRW_viewport_matrix_override_set(viewmat, DRW_MAT_VIEW);
+ DRW_viewport_matrix_override_set(viewinv, DRW_MAT_VIEWINV);
+ DRW_viewport_matrix_override_set(winmat, DRW_MAT_WIN);
+
+ DRW_draw_pass(psl->probe_background);
+
+ DRW_framebuffer_texture_detach(sldata->probe_rt);
+ }
+ DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_rt, 0, 0);
+
+ DRW_viewport_matrix_override_unset(DRW_MAT_PERS);
+ DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV);
+ DRW_viewport_matrix_override_unset(DRW_MAT_VIEW);
+ DRW_viewport_matrix_override_unset(DRW_MAT_VIEWINV);
+ DRW_viewport_matrix_override_unset(DRW_MAT_WIN);
+}
+
+static void lightprobe_cell_location_get(EEVEE_LightGrid *egrid, int cell_idx, float r_pos[3])
+{
+ float tmp[3], local_cell[3];
+ /* Keep in sync with lightprobe_grid_display_vert */
+ local_cell[2] = (float)(cell_idx % egrid->resolution[2]);
+ local_cell[1] = (float)((cell_idx / egrid->resolution[2]) % egrid->resolution[1]);
+ local_cell[0] = (float)(cell_idx / (egrid->resolution[2] * egrid->resolution[1]));
+
+ copy_v3_v3(r_pos, egrid->corner);
+ mul_v3_v3fl(tmp, egrid->increment_x, local_cell[0]);
+ add_v3_v3(r_pos, tmp);
+ mul_v3_v3fl(tmp, egrid->increment_y, local_cell[1]);
+ add_v3_v3(r_pos, tmp);
+ mul_v3_v3fl(tmp, egrid->increment_z, local_cell[2]);
+ add_v3_v3(r_pos, tmp);
+}
+
+void EEVEE_lightprobes_refresh(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ Object *ob;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ RegionView3D *rv3d = draw_ctx->rv3d;
+
+ /* Render world in priority */
+ if (e_data.update_world) {
+ render_world_to_probe(sldata, psl);
+ glossy_filter_probe(sldata, psl, 0);
+ diffuse_filter_probe(sldata, psl, 0);
+
+ /* Swap and redo prefiltering for other rendertarget.
+ * This way we have world lighting waiting for irradiance grids to catch up. */
+ SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
+ diffuse_filter_probe(sldata, psl, 0);
+
+ e_data.update_world = false;
+
+ if (!e_data.world_ready_to_shade) {
+ e_data.world_ready_to_shade = true;
+ pinfo->num_render_cube = 1;
+ pinfo->num_render_grid = 1;
+ }
+
+ DRW_viewport_request_redraw();
+ }
+ else if (true) { /* TODO if at least one probe needs refresh */
+
+ if (draw_ctx->evil_C != NULL) {
+ /* Only compute probes if not navigating or in playback */
+ struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C);
+ if (((rv3d->rflag & RV3D_NAVIGATING) != 0) || ED_screen_animation_no_scrub(wm) != NULL) {
+ goto update_planar;
+ }
+ }
+
+ /* Reflection probes depend on diffuse lighting thus on irradiance grid */
+ const int max_bounce = 3;
+ while (pinfo->updated_bounce < max_bounce) {
+ pinfo->num_render_grid = pinfo->num_grid;
+
+ for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) {
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
+
+ if (ped->need_update) {
+ EEVEE_LightGrid *egrid = &pinfo->grid_data[i];
+ LightProbe *prb = (LightProbe *)ob->data;
+ int cell_id = ped->updated_cells;
+
+ SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
+
+ /* Temporary Remove all probes. */
+ int tmp_num_render_grid = pinfo->num_render_grid;
+ int tmp_num_render_cube = pinfo->num_render_cube;
+ int tmp_num_planar = pinfo->num_planar;
+ pinfo->num_render_cube = 0;
+ pinfo->num_planar = 0;
+
+ /* Use light from previous bounce when capturing radiance. */
+ if (pinfo->updated_bounce == 0) {
+ pinfo->num_render_grid = 0;
+ }
+
+ float pos[3];
+ lightprobe_cell_location_get(egrid, cell_id, pos);
+
+ render_scene_to_probe(sldata, vedata, pos, prb->clipsta, prb->clipend);
+ diffuse_filter_probe(sldata, psl, egrid->offset + cell_id);
+
+ /* Restore */
+ pinfo->num_render_grid = tmp_num_render_grid;
+ pinfo->num_render_cube = tmp_num_render_cube;
+ pinfo->num_planar = tmp_num_planar;
+
+ /* To see what is going on. */
+ SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
+
+ ped->updated_cells++;
+ if (ped->updated_cells >= ped->num_cell) {
+ ped->need_update = false;
+ }
+
+ /* Only do one probe per frame */
+ DRW_viewport_request_redraw();
+ goto update_planar;
+ }
+ }
+
+ pinfo->updated_bounce++;
+ pinfo->num_render_grid = pinfo->num_grid;
+
+ if (pinfo->updated_bounce < max_bounce) {
+ /* Retag all grids to update for next bounce */
+ for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) {
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
+ ped->need_update = true;
+ ped->updated_cells = 0;
+ }
+ SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
+ }
+ }
+
+ for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) {
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
+
+ if (ped->need_update) {
+ LightProbe *prb = (LightProbe *)ob->data;
+
+ render_scene_to_probe(sldata, vedata, ob->obmat[3], prb->clipsta, prb->clipend);
+ glossy_filter_probe(sldata, psl, i);
+
+ ped->need_update = false;
+ ped->probe_id = i;
+
+ if (!ped->ready_to_shade) {
+ pinfo->num_render_cube++;
+ ped->ready_to_shade = true;
+ }
+
+ DRW_viewport_request_redraw();
+
+ /* Only do one probe per frame */
+ goto update_planar;
+ }
+ }
+ }
+
+update_planar:
+
+ for (int i = 0; (ob = pinfo->probes_planar_ref[i]) && (i < MAX_PLANAR); i++) {
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
+
+ if (ped->need_update) {
+ /* Temporary Remove all planar reflections (avoid lag effect). */
+ int tmp_num_planar = pinfo->num_planar;
+ pinfo->num_planar = 0;
+
+ render_scene_to_planar(vedata, i, ped->viewmat, ped->persmat, ped->planer_eq_offset);
+
+ /* Restore */
+ pinfo->num_planar = tmp_num_planar;
+
+ ped->need_update = false;
+ ped->probe_id = i;
+ }
+ }
+
+ /* If there is at least one planar probe */
+ if (pinfo->num_planar > 0) {
+ const int max_lod = 5;
+ DRW_framebuffer_recursive_downsample(vedata->fbl->minmaxz_fb, txl->planar_pool, max_lod, &downsample_planar, vedata);
+ /* For shading, save max level of the planar map */
+ pinfo->lod_planar_max = (float)(max_lod);
+ }
+}
+
+void EEVEE_lightprobes_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_grid_display_sh);
+ DRW_SHADER_FREE_SAFE(e_data.probe_planar_display_sh);
+ DRW_SHADER_FREE_SAFE(e_data.probe_planar_downsample_sh);
+ DRW_SHADER_FREE_SAFE(e_data.probe_cube_display_sh);
+ DRW_TEXTURE_FREE_SAFE(e_data.hammersley);
+ DRW_TEXTURE_FREE_SAFE(e_data.planar_pool_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..8f5c633c24a
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_lights.c
@@ -0,0 +1,821 @@
+/*
+ * 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 "BKE_object.h"
+
+#include "eevee_engine.h"
+#include "eevee_private.h"
+
+/* 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_LightData {
+ short light_id, shadow_id;
+} EEVEE_LightData;
+
+typedef struct EEVEE_ShadowCubeData {
+ short light_id, shadow_id;
+ float viewprojmat[6][4][4];
+} EEVEE_ShadowCubeData;
+
+typedef struct EEVEE_ShadowMapData {
+ short light_id, shadow_id;
+ float viewprojmat[4][4]; /* World->Lamp->NDC : used for rendering the shadow map. */
+} EEVEE_ShadowMapData;
+
+typedef struct EEVEE_ShadowCascadeData {
+ short light_id, shadow_id;
+ float viewprojmat[MAX_CASCADE_NUM][4][4]; /* World->Lamp->NDC : used for rendering the shadow map. */
+} EEVEE_ShadowCascadeData;
+
+typedef struct ShadowCaster {
+ struct ShadowCaster *next, *prev;
+ void *ob;
+ bool prune;
+} ShadowCaster;
+
+static struct {
+ struct GPUShader *shadow_sh;
+ struct GPUShader *shadow_store_sh;
+} e_data = {NULL}; /* Engine data */
+
+extern char datatoc_shadow_vert_glsl[];
+extern char datatoc_shadow_geom_glsl[];
+extern char datatoc_shadow_frag_glsl[];
+extern char datatoc_shadow_store_vert_glsl[];
+extern char datatoc_shadow_store_geom_glsl[];
+extern char datatoc_shadow_store_frag_glsl[];
+
+/* *********** FUNCTIONS *********** */
+
+void EEVEE_lights_init(EEVEE_SceneLayerData *sldata)
+{
+ const unsigned int shadow_ubo_size = sizeof(EEVEE_ShadowCube) * MAX_SHADOW_CUBE +
+ sizeof(EEVEE_ShadowMap) * MAX_SHADOW_MAP +
+ sizeof(EEVEE_ShadowCascade) * MAX_SHADOW_CASCADE;
+
+ if (!e_data.shadow_sh) {
+ e_data.shadow_sh = DRW_shader_create(
+ datatoc_shadow_vert_glsl, datatoc_shadow_geom_glsl, datatoc_shadow_frag_glsl, NULL);
+
+ e_data.shadow_store_sh = DRW_shader_create(
+ datatoc_shadow_store_vert_glsl, datatoc_shadow_store_geom_glsl, datatoc_shadow_store_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);
+ }
+}
+
+void EEVEE_lights_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
+{
+ EEVEE_LampsInfo *linfo = sldata->lamps;
+
+ linfo->num_light = linfo->num_cube = linfo->num_map = linfo->num_cascade = 0;
+ memset(linfo->light_ref, 0, sizeof(linfo->light_ref));
+ memset(linfo->shadow_cube_ref, 0, sizeof(linfo->shadow_cube_ref));
+ memset(linfo->shadow_map_ref, 0, sizeof(linfo->shadow_map_ref));
+ memset(linfo->shadow_cascade_ref, 0, sizeof(linfo->shadow_cascade_ref));
+
+ {
+ psl->shadow_cube_store_pass = DRW_pass_create("Shadow Storage Pass", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.shadow_store_sh, psl->shadow_cube_store_pass);
+ DRW_shgroup_uniform_buffer(grp, "shadowCube", &sldata->shadow_color_cube_target);
+ DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+ }
+
+ {
+ psl->shadow_cube_pass = DRW_pass_create("Shadow Cube Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
+ }
+
+ {
+ psl->shadow_cascade_pass = DRW_pass_create("Shadow Cascade Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
+ }
+
+ /* Reset shadow casters list */
+ BLI_freelistN(&sldata->shadow_casters);
+}
+
+void EEVEE_lights_cache_add(EEVEE_SceneLayerData *sldata, Object *ob)
+{
+ EEVEE_LampsInfo *linfo = sldata->lamps;
+
+ /* Step 1 find all lamps in the scene and setup them */
+ if (linfo->num_light > MAX_LIGHT) {
+ printf("Too much lamps in the scene !!!\n");
+ linfo->num_light = MAX_LIGHT;
+ }
+ else {
+ Lamp *la = (Lamp *)ob->data;
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob);
+
+ if ((ob->deg_update_flag & DEG_RUNTIME_DATA_UPDATE) != 0) {
+ led->need_update = true;
+ }
+
+ MEM_SAFE_FREE(led->storage);
+
+#if 1 /* TODO Waiting for notified refresh. only on scene change. Else too much perf cost. */
+ if (la->mode & (LA_SHAD_BUF | LA_SHAD_RAY)) {
+ if (la->type == LA_SUN && linfo->num_cascade < MAX_SHADOW_CASCADE) {
+#if 0 /* TODO filter cascaded shadow map */
+ led->storage = MEM_mallocN(sizeof(EEVEE_ShadowCascadeData), "EEVEE_ShadowCascadeData");
+ ((EEVEE_ShadowCascadeData *)led->storage)->shadow_id = linfo->num_cascade;
+ linfo->shadow_cascade_ref[linfo->num_cascade] = ob;
+ linfo->num_cascade++;
+#endif
+ }
+ else if ((la->type == LA_SPOT || la->type == LA_LOCAL || la->type == LA_AREA)
+ && linfo->num_cube < MAX_SHADOW_CUBE) {
+ led->storage = MEM_mallocN(sizeof(EEVEE_ShadowCubeData), "EEVEE_ShadowCubeData");
+ ((EEVEE_ShadowCubeData *)led->storage)->shadow_id = linfo->num_cube;
+ linfo->shadow_cube_ref[linfo->num_cube] = ob;
+ linfo->num_cube++;
+ }
+
+ }
+#else
+ UNUSED_VARS(la);
+#endif
+ /* Default light without shadows */
+ if (!led->storage) {
+ led->storage = MEM_mallocN(sizeof(EEVEE_LightData), "EEVEE_LightData");
+ ((EEVEE_LightData *)led->storage)->shadow_id = -1;
+ }
+
+ ((EEVEE_LightData *)led->storage)->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_SceneLayerData *sldata, EEVEE_PassList *psl, struct Gwn_Batch *geom, float (*obmat)[4])
+{
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(e_data.shadow_sh, psl->shadow_cube_pass, geom);
+ DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
+ DRW_shgroup_uniform_mat4(grp, "ShadowModelMatrix", (float *)obmat);
+
+ for (int i = 0; i < 6; ++i)
+ DRW_shgroup_call_dynamic_add_empty(grp);
+
+ grp = DRW_shgroup_instance_create(e_data.shadow_sh, psl->shadow_cascade_pass, geom);
+ DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
+ DRW_shgroup_uniform_mat4(grp, "ShadowModelMatrix", (float *)obmat);
+
+ for (int i = 0; i < MAX_CASCADE_NUM; ++i)
+ DRW_shgroup_call_dynamic_add_empty(grp);
+}
+
+void EEVEE_lights_cache_shcaster_material_add(
+ EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl, struct GPUMaterial *gpumat, struct Gwn_Batch *geom, float (*obmat)[4], float *alpha_threshold)
+{
+ DRWShadingGroup *grp = DRW_shgroup_material_instance_create(gpumat, psl->shadow_cube_pass, geom);
+
+ if (grp == NULL) return;
+
+ DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
+ DRW_shgroup_uniform_mat4(grp, "ShadowModelMatrix", (float *)obmat);
+
+ if (alpha_threshold != NULL)
+ DRW_shgroup_uniform_float(grp, "alphaThreshold", alpha_threshold, 1);
+
+ for (int i = 0; i < 6; ++i)
+ DRW_shgroup_call_dynamic_add_empty(grp);
+
+ grp = DRW_shgroup_material_instance_create(gpumat, psl->shadow_cascade_pass, geom);
+ DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
+ DRW_shgroup_uniform_mat4(grp, "ShadowModelMatrix", (float *)obmat);
+
+ if (alpha_threshold != NULL)
+ DRW_shgroup_uniform_float(grp, "alphaThreshold", alpha_threshold, 1);
+
+ for (int i = 0; i < MAX_CASCADE_NUM; ++i)
+ DRW_shgroup_call_dynamic_add_empty(grp);
+}
+
+void EEVEE_lights_cache_finish(EEVEE_SceneLayerData *sldata)
+{
+ EEVEE_LampsInfo *linfo = sldata->lamps;
+
+ /* Setup enough layers. */
+ /* Free textures if number mismatch. */
+ if (linfo->num_cube != linfo->cache_num_cube) {
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_depth_cube_pool);
+ linfo->cache_num_cube = linfo->num_cube;
+ linfo->update_flag |= LIGHT_UPDATE_SHADOW_CUBE;
+ }
+ if (linfo->num_map != linfo->cache_num_map) {
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_depth_map_pool);
+ linfo->cache_num_map = linfo->num_map;
+ }
+ if (linfo->num_cascade != linfo->cache_num_cascade) {
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_depth_cascade_pool);
+ linfo->cache_num_cascade = linfo->num_cascade;
+ }
+
+ /* Initialize Textures Arrays first so DRW_framebuffer_init just bind them. */
+ if (!sldata->shadow_depth_cube_target) {
+ /* Render Cubemap */
+ sldata->shadow_depth_cube_target = DRW_texture_create_cube(512, DRW_TEX_DEPTH_24, 0, NULL);
+ sldata->shadow_color_cube_target = DRW_texture_create_cube(512, DRW_TEX_R_32, DRW_TEX_FILTER, NULL);
+ if (sldata->shadow_cube_fb) {
+ DRW_framebuffer_texture_attach(sldata->shadow_cube_fb, sldata->shadow_depth_cube_target, 0, 0);
+ DRW_framebuffer_texture_attach(sldata->shadow_cube_fb, sldata->shadow_color_cube_target, 0, 0);
+ }
+ }
+ if (!sldata->shadow_depth_cube_pool) {
+ /* Cubemap / octahedral map pool */
+ /* TODO Cubemap array */
+ sldata->shadow_depth_cube_pool = DRW_texture_create_2D_array(
+ 512, 512, max_ff(1, linfo->num_cube), DRW_TEX_R_16,
+ DRW_TEX_FILTER | DRW_TEX_COMPARE, NULL);
+ if (sldata->shadow_cube_fb) {
+ DRW_framebuffer_texture_attach(sldata->shadow_cube_fb, sldata->shadow_depth_cube_pool, 0, 0);
+ }
+ }
+ if (!sldata->shadow_depth_map_pool) {
+ sldata->shadow_depth_map_pool = DRW_texture_create_2D_array(
+ 512, 512, max_ff(1, linfo->num_map), DRW_TEX_DEPTH_24,
+ DRW_TEX_FILTER | DRW_TEX_COMPARE, NULL);
+ if (sldata->shadow_map_fb) {
+ DRW_framebuffer_texture_attach(sldata->shadow_map_fb, sldata->shadow_depth_map_pool, 0, 0);
+ }
+ }
+ if (!sldata->shadow_depth_cascade_pool) {
+ sldata->shadow_depth_cascade_pool = DRW_texture_create_2D_array(
+ 512, 512, max_ff(1, linfo->num_cascade * MAX_CASCADE_NUM), DRW_TEX_DEPTH_24,
+ DRW_TEX_FILTER | DRW_TEX_COMPARE, NULL);
+ if (sldata->shadow_cascade_fb) {
+ DRW_framebuffer_texture_attach(sldata->shadow_cascade_fb, sldata->shadow_depth_map_pool, 0, 0);
+ }
+ }
+
+ DRWFboTexture tex_cube_target[2] = {
+ {&sldata->shadow_depth_cube_target, DRW_TEX_DEPTH_24, 0},
+ {&sldata->shadow_color_cube_target, DRW_TEX_R_16, DRW_TEX_FILTER}};
+ DRW_framebuffer_init(&sldata->shadow_cube_target_fb, &draw_engine_eevee_type, 512, 512, tex_cube_target, 2);
+
+ DRWFboTexture tex_cube = {&sldata->shadow_depth_cube_pool, DRW_TEX_R_16, DRW_TEX_FILTER};
+ DRW_framebuffer_init(&sldata->shadow_cube_fb, &draw_engine_eevee_type, 512, 512, &tex_cube, 1);
+
+ DRWFboTexture tex_cascade = {&sldata->shadow_depth_cascade_pool, DRW_TEX_DEPTH_24, DRW_TEX_FILTER | DRW_TEX_COMPARE};
+ DRW_framebuffer_init(&sldata->shadow_cascade_fb, &draw_engine_eevee_type, 512, 512, &tex_cascade, 1);
+
+ /* Update Lamps UBOs. */
+ EEVEE_lights_update(sldata);
+}
+
+/* Update buffer with lamp data */
+static void eevee_light_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led)
+{
+ /* TODO only update if data changes */
+ EEVEE_LightData *evld = led->storage;
+ EEVEE_Light *evli = linfo->light_data + evld->light_id;
+ Lamp *la = (Lamp *)ob->data;
+ float mat[4][4], scale[3], power;
+
+ /* Position */
+ copy_v3_v3(evli->position, ob->obmat[3]);
+
+ /* Color */
+ copy_v3_v3(evli->color, &la->r);
+
+ /* Influence Radius */
+ evli->dist = la->dist;
+
+ /* 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);
+
+ /* Spot size & blend */
+ if (la->type == LA_SPOT) {
+ 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.0001f, la->area_size * scale[0] * 0.5f);
+ if (la->area_shape == LA_AREA_RECT) {
+ evli->sizey = max_ff(0.0001f, la->area_sizey * scale[1] * 0.5f);
+ }
+ else {
+ evli->sizey = max_ff(0.0001f, la->area_size * scale[1] * 0.5f);
+ }
+ }
+ else {
+ evli->radius = max_ff(0.001f, la->area_size);
+ }
+
+ /* 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 */
+ }
+ 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 * 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;
+ }
+ mul_v3_fl(evli->color, power * la->energy);
+
+ /* Lamp Type */
+ evli->lamptype = (float)la->type;
+
+ /* No shadow by default */
+ evli->shadowid = -1.0f;
+}
+
+static void eevee_shadow_cube_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led)
+{
+ float projmat[4][4];
+
+ EEVEE_ShadowCubeData *evsmp = (EEVEE_ShadowCubeData *)led->storage;
+ EEVEE_Light *evli = linfo->light_data + evsmp->light_id;
+ EEVEE_ShadowCube *evsh = linfo->shadow_cube_data + evsmp->shadow_id;
+ Lamp *la = (Lamp *)ob->data;
+
+ perspective_m4(projmat, -la->clipsta, la->clipsta, -la->clipsta, la->clipsta, la->clipsta, la->clipend);
+
+ for (int i = 0; i < 6; ++i) {
+ float tmp[4][4];
+ unit_m4(tmp);
+ negate_v3_v3(tmp[3], ob->obmat[3]);
+ mul_m4_m4m4(tmp, cubefacemat[i], tmp);
+ mul_m4_m4m4(evsmp->viewprojmat[i], projmat, tmp);
+ }
+
+ evsh->bias = 0.05f * la->bias;
+ evsh->near = la->clipsta;
+ evsh->far = la->clipend;
+ evsh->exp = la->bleedexp;
+
+ evli->shadowid = (float)(evsmp->shadow_id);
+}
+
+static void eevee_shadow_map_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led)
+{
+ float viewmat[4][4], projmat[4][4];
+
+ EEVEE_ShadowMapData *evsmp = (EEVEE_ShadowMapData *)led->storage;
+ EEVEE_Light *evli = linfo->light_data + evsmp->light_id;
+ EEVEE_ShadowMap *evsh = linfo->shadow_map_data + evsmp->shadow_id;
+ Lamp *la = (Lamp *)ob->data;
+
+ invert_m4_m4(viewmat, ob->obmat);
+ normalize_v3(viewmat[0]);
+ normalize_v3(viewmat[1]);
+ normalize_v3(viewmat[2]);
+
+ float wsize = la->shadow_frustum_size;
+ orthographic_m4(projmat, -wsize, wsize, -wsize, wsize, la->clipsta, la->clipend);
+
+ mul_m4_m4m4(evsmp->viewprojmat, projmat, viewmat);
+ mul_m4_m4m4(evsh->shadowmat, texcomat, evsmp->viewprojmat);
+
+ evsh->bias = 0.005f * la->bias;
+
+ evli->shadowid = (float)(MAX_SHADOW_CUBE + evsmp->shadow_id);
+}
+
+#define LERP(t, a, b) ((a) + (t) * ((b) - (a)))
+
+static void frustum_min_bounding_sphere(const float corners[8][4], float r_center[3], float *r_radius)
+{
+#if 0 /* Simple solution but waist 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
+ /* Make the bouding sphere always centered on the front diagonal */
+ add_v3_v3v3(r_center, corners[4], corners[7]);
+ mul_v3_fl(r_center, 0.5f);
+ *r_radius = len_v3v3(corners[0], r_center);
+
+ /* Search the largest distance between the sphere center
+ * and the front plane corners. */
+ for (int i = 0; i < 4; ++i) {
+ float rad = len_v3v3(corners[4+i], r_center);
+ if (rad > *r_radius) {
+ *r_radius = rad;
+ }
+ }
+#endif
+}
+
+static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led)
+{
+ /* Camera Matrices */
+ float persmat[4][4], persinv[4][4];
+ float viewprojmat[4][4], projinv[4][4];
+ float near, far;
+ float near_v[4] = {0.0f, 0.0f, -1.0f, 1.0f};
+ float far_v[4] = {0.0f, 0.0f, 1.0f, 1.0f};
+ bool is_persp = DRW_viewport_is_persp_get();
+ DRW_viewport_matrix_get(persmat, DRW_MAT_PERS);
+ invert_m4_m4(persinv, persmat);
+ /* FIXME : Get near / far from Draw manager? */
+ DRW_viewport_matrix_get(viewprojmat, DRW_MAT_WIN);
+ invert_m4_m4(projinv, viewprojmat);
+ mul_m4_v4(projinv, near_v);
+ mul_m4_v4(projinv, far_v);
+ near = near_v[2];
+ far = far_v[2]; /* TODO: Should be a shadow parameter */
+ if (is_persp) {
+ near /= near_v[3];
+ far /= far_v[3];
+ }
+
+ /* Lamps Matrices */
+ float viewmat[4][4], projmat[4][4];
+ int cascade_ct = MAX_CASCADE_NUM;
+ float shadow_res = 512.0f; /* TODO parameter */
+
+ EEVEE_ShadowCascadeData *evscp = (EEVEE_ShadowCascadeData *)led->storage;
+ EEVEE_Light *evli = linfo->light_data + evscp->light_id;
+ EEVEE_ShadowCascade *evsh = linfo->shadow_cascade_data + evscp->shadow_id;
+ Lamp *la = (Lamp *)ob->data;
+
+ /* The technique consists into splitting
+ * the view frustum into several sub-frustum
+ * that are individually receiving one shadow map */
+
+ /* init near/far */
+ for (int c = 0; c < MAX_CASCADE_NUM; ++c) {
+ evsh->split[c] = far;
+ }
+
+ /* Compute split planes */
+ float splits_ndc[MAX_CASCADE_NUM + 1];
+ splits_ndc[0] = -1.0f;
+ splits_ndc[cascade_ct] = 1.0f;
+ for (int c = 1; c < cascade_ct; ++c) {
+ const float lambda = 0.8f; /* TODO : Parameter */
+
+ /* View Space */
+ float linear_split = LERP(((float)(c) / (float)cascade_ct), near, far);
+ float exp_split = near * powf(far / near, (float)(c) / (float)cascade_ct);
+
+ if (is_persp) {
+ evsh->split[c-1] = LERP(lambda, linear_split, exp_split);
+ }
+ else {
+ evsh->split[c-1] = linear_split;
+ }
+
+ /* NDC Space */
+ float p[4] = {1.0f, 1.0f, evsh->split[c-1], 1.0f};
+ mul_m4_v4(viewprojmat, p);
+ splits_ndc[c] = p[2];
+
+ if (is_persp) {
+ splits_ndc[c] /= p[3];
+ }
+ }
+
+ /* For each cascade */
+ for (int c = 0; c < cascade_ct; ++c) {
+ /* Given 8 frustrum corners */
+ float corners[8][4] = {
+ /* Near Cap */
+ {-1.0f, -1.0f, splits_ndc[c], 1.0f},
+ { 1.0f, -1.0f, splits_ndc[c], 1.0f},
+ {-1.0f, 1.0f, splits_ndc[c], 1.0f},
+ { 1.0f, 1.0f, splits_ndc[c], 1.0f},
+ /* Far Cap */
+ {-1.0f, -1.0f, splits_ndc[c+1], 1.0f},
+ { 1.0f, -1.0f, splits_ndc[c+1], 1.0f},
+ {-1.0f, 1.0f, splits_ndc[c+1], 1.0f},
+ { 1.0f, 1.0f, splits_ndc[c+1], 1.0f}
+ };
+
+ /* Transform them into world space */
+ for (int i = 0; i < 8; ++i) {
+ mul_m4_v4(persinv, corners[i]);
+ mul_v3_fl(corners[i], 1.0f / corners[i][3]);
+ corners[i][3] = 1.0f;
+ }
+
+ /* Project them into light space */
+ invert_m4_m4(viewmat, ob->obmat);
+ normalize_v3(viewmat[0]);
+ normalize_v3(viewmat[1]);
+ normalize_v3(viewmat[2]);
+
+ for (int i = 0; i < 8; ++i) {
+ mul_m4_v4(viewmat, corners[i]);
+ }
+
+ float center[3], radius;
+ frustum_min_bounding_sphere(corners, center, &radius);
+
+ /* Snap projection center to nearest texel to cancel shimering. */
+ float shadow_origin[2], shadow_texco[2];
+ mul_v2_v2fl(shadow_origin, center, shadow_res / (2.0f * radius)); /* Light to texture space. */
+
+ /* Find the nearest texel. */
+ shadow_texco[0] = round(shadow_origin[0]);
+ shadow_texco[1] = round(shadow_origin[1]);
+
+ /* Compute offset. */
+ sub_v2_v2(shadow_texco, shadow_origin);
+ mul_v2_fl(shadow_texco, (2.0f * radius) / shadow_res); /* Texture to light space. */
+
+ /* Apply offset. */
+ add_v2_v2(center, shadow_texco);
+
+ /* Expand the projection to cover frustum range */
+ orthographic_m4(projmat,
+ center[0] - radius,
+ center[0] + radius,
+ center[1] - radius,
+ center[1] + radius,
+ la->clipsta, la->clipend);
+
+ mul_m4_m4m4(evscp->viewprojmat[c], projmat, viewmat);
+ mul_m4_m4m4(evsh->shadowmat[c], texcomat, evscp->viewprojmat[c]);
+
+ /* TODO modify bias depending on the cascade radius */
+ evsh->bias[c] = 0.005f * la->bias;
+ }
+
+ evli->shadowid = (float)(MAX_SHADOW_CUBE + MAX_SHADOW_MAP + evscp->shadow_id);
+}
+
+/* Used for checking if object is inside the shadow volume. */
+static bool cube_bbox_intersect(const float cube_center[3], float cube_half_dim, const BoundBox *bb, float (*obmat)[4])
+{
+ float min[3], max[4], tmp[4][4];
+ unit_m4(tmp);
+ translate_m4(tmp, -cube_center[0], -cube_center[1], -cube_center[2]);
+ mul_m4_m4m4(tmp, tmp, obmat);
+
+ /* Just simple AABB intersection test in world space. */
+ INIT_MINMAX(min, max);
+ for (int i = 0; i < 8; ++i) {
+ float vec[3];
+ copy_v3_v3(vec, bb->vec[i]);
+ mul_m4_v3(tmp, vec);
+ minmax_v3v3_v3(min, max, vec);
+ }
+
+ if (MAX3(max[0], max[1], max[2]) < -cube_half_dim) return false;
+ if (MIN3(min[0], min[1], min[2]) > cube_half_dim) return false;
+
+ return true;
+}
+
+static ShadowCaster *search_object_in_list(ListBase *list, Object *ob)
+{
+ for (ShadowCaster *ldata = list->first; ldata; ldata = ldata->next) {
+ if (ldata->ob == ob)
+ return ldata;
+ }
+
+ return NULL;
+}
+
+static void delete_pruned_shadowcaster(EEVEE_LampEngineData *led)
+{
+ ShadowCaster *next;
+ for (ShadowCaster *ldata = led->shadow_caster_list.first; ldata; ldata = next) {
+ next = ldata->next;
+ if (ldata->prune == true) {
+ led->need_update = true;
+ BLI_freelinkN(&led->shadow_caster_list, ldata);
+ }
+ }
+}
+
+static void light_tag_shadow_update(Object *lamp, Object *ob)
+{
+ Lamp *la = lamp->data;
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_get(lamp);
+
+ bool is_inside_range = cube_bbox_intersect(lamp->obmat[3], la->clipend, BKE_object_boundbox_get(ob), ob->obmat);
+ ShadowCaster *ldata = search_object_in_list(&led->shadow_caster_list, ob);
+
+ if (is_inside_range) {
+ if (ldata == NULL) {
+ /* Object was not a shadow caster previously but is now. Add it. */
+ ldata = MEM_callocN(sizeof(ShadowCaster), "ShadowCaster");
+ ldata->ob = ob;
+ BLI_addtail(&led->shadow_caster_list, ldata);
+ led->need_update = true;
+ }
+ else {
+ EEVEE_ObjectEngineData *oedata = EEVEE_object_data_get(ob);
+ if (oedata->need_update) {
+ led->need_update = true;
+ }
+ }
+ ldata->prune = false;
+ }
+ else if (ldata != NULL) {
+ /* Object was a shadow caster previously and is not anymore. Remove it. */
+ led->need_update = true;
+ BLI_freelinkN(&led->shadow_caster_list, ldata);
+ }
+}
+
+static void eevee_lights_shcaster_updated(EEVEE_SceneLayerData *sldata, Object *ob)
+{
+ Object *lamp;
+ EEVEE_LampsInfo *linfo = sldata->lamps;
+
+ /* Iterate over all shadow casting lamps to see if
+ * each of them needs update because of this object */
+ for (int i = 0; (lamp = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) {
+ light_tag_shadow_update(lamp, ob);
+ }
+}
+
+void EEVEE_lights_update(EEVEE_SceneLayerData *sldata)
+{
+ EEVEE_LampsInfo *linfo = sldata->lamps;
+ Object *ob;
+ int i;
+
+ /* Prune shadow casters to remove if object does not exists anymore (unprune them if object exists) */
+ Object *lamp;
+ for (i = 0; (lamp = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) {
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_get(lamp);
+
+ if ((linfo->update_flag & LIGHT_UPDATE_SHADOW_CUBE) != 0) {
+ led->need_update = true;
+ }
+
+ for (ShadowCaster *ldata = led->shadow_caster_list.first; ldata; ldata = ldata->next) {
+ ldata->prune = true;
+ }
+ }
+
+ for (LinkData *ldata = sldata->shadow_casters.first; ldata; ldata = ldata->next) {
+ eevee_lights_shcaster_updated(sldata, ldata->data);
+ }
+
+ for (i = 0; (ob = linfo->light_ref[i]) && (i < MAX_LIGHT); i++) {
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob);
+ eevee_light_setup(ob, linfo, led);
+ }
+
+ for (i = 0; (ob = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) {
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob);
+ eevee_shadow_cube_setup(ob, linfo, led);
+ delete_pruned_shadowcaster(led);
+ }
+
+ for (i = 0; (ob = linfo->shadow_map_ref[i]) && (i < MAX_SHADOW_MAP); i++) {
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob);
+ eevee_shadow_map_setup(ob, linfo, led);
+ }
+
+ for (i = 0; (ob = linfo->shadow_cascade_ref[i]) && (i < MAX_SHADOW_CASCADE); i++) {
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob);
+ eevee_shadow_cascade_setup(ob, linfo, led);
+ }
+
+ DRW_uniformbuffer_update(sldata->light_ubo, &linfo->light_data);
+ DRW_uniformbuffer_update(sldata->shadow_ubo, &linfo->shadow_cube_data); /* Update all data at once */
+}
+
+/* this refresh lamps shadow buffers */
+void EEVEE_draw_shadows(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
+{
+ EEVEE_LampsInfo *linfo = sldata->lamps;
+ Object *ob;
+ int i;
+ float clear_color[4] = {FLT_MAX, FLT_MAX, FLT_MAX, 0.0f};
+
+ /* 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_get(ob);
+ Lamp *la = (Lamp *)ob->data;
+
+ if (led->need_update) {
+ EEVEE_ShadowCubeData *evscd = (EEVEE_ShadowCubeData *)led->storage;
+ EEVEE_ShadowRender *srd = &linfo->shadow_render_data;
+
+ srd->layer = i;
+ srd->exponent = la->bleedexp;
+ copy_v3_v3(srd->position, ob->obmat[3]);
+ for (int j = 0; j < 6; j++) {
+ float tmp[4][4];
+
+ unit_m4(tmp);
+ negate_v3_v3(tmp[3], ob->obmat[3]);
+ mul_m4_m4m4(srd->viewmat[j], cubefacemat[j], tmp);
+
+ copy_m4_m4(srd->shadowmat[j], evscd->viewprojmat[j]);
+ }
+ DRW_uniformbuffer_update(sldata->shadow_render_ubo, &linfo->shadow_render_data);
+
+ DRW_framebuffer_bind(sldata->shadow_cube_target_fb);
+ DRW_framebuffer_clear(true, true, false, clear_color, 1.0f);
+ /* Render shadow cube */
+ DRW_draw_pass(psl->shadow_cube_pass);
+
+ /* Push it to shadowmap array */
+ DRW_framebuffer_bind(sldata->shadow_cube_fb);
+ DRW_draw_pass(psl->shadow_cube_store_pass);
+
+ led->need_update = false;
+ }
+ }
+ linfo->update_flag &= ~LIGHT_UPDATE_SHADOW_CUBE;
+
+#if 0
+ /* Standard Shadow Maps */
+ DRW_framebuffer_bind(fbl->shadow_map_fb);
+ DRW_framebuffer_clear(false, true, false, NULL, 1.0);
+
+ /* Render each shadow to one layer of the array */
+ for (i = 0; (ob = linfo->shadow_map_ref[i]) && (i < MAX_SHADOW_MAP); i++) {
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob);
+ EEVEE_ShadowMapData *evsmd = (EEVEE_ShadowMapData *)led->storage;
+
+ linfo->layer = i;
+ copy_m4_m4(linfo->shadowmat, evsmd->viewprojmat);
+ DRW_draw_pass(vedata->psl->shadow_pass);
+ }
+#endif
+
+ /* Cascaded Shadow Maps */
+// DRW_framebuffer_bind(fbl->shadow_cascade_fb);
+// DRW_framebuffer_clear(false, true, false, NULL, 1.0);
+
+// /* Render each shadow to one layer of the array */
+// for (i = 0; (ob = linfo->shadow_cascade_ref[i]) && (i < MAX_SHADOW_CASCADE); i++) {
+// EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob);
+// EEVEE_ShadowCascadeData *evscd = (EEVEE_ShadowCascadeData *)led->storage;
+// EEVEE_ShadowRender *srd = &linfo->shadow_render_data;
+
+// srd->layer = i;
+// for (int j = 0; j < MAX_CASCADE_NUM; ++j) {
+// copy_m4_m4(srd->shadowmat[j], evscd->viewprojmat[j]);
+// }
+// DRW_uniformbuffer_update(sldata->shadow_render_ubo, &linfo->shadow_render_data);
+
+// DRW_draw_pass(psl->shadow_cascade_pass);
+// }
+}
+
+void EEVEE_lights_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.shadow_sh);
+ DRW_SHADER_FREE_SAFE(e_data.shadow_store_sh);
+} \ No newline at end of file
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..711defee35d
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_lut.h
@@ -0,0 +1,5400 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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 eeveee_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
+};
+
+/* 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..46ed858603d
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -0,0 +1,1158 @@
+/*
+ * 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 "DNA_world_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BLI_dynstr.h"
+#include "BLI_ghash.h"
+#include "BLI_alloca.h"
+
+#include "BKE_particle.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+
+#include "GPU_material.h"
+
+#include "eevee_engine.h"
+#include "eevee_lut.h"
+#include "eevee_private.h"
+
+#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_CUBE " STRINGIFY(MAX_SHADOW_CUBE) "\n" \
+ "#define MAX_SHADOW_MAP " STRINGIFY(MAX_SHADOW_MAP) "\n" \
+ "#define MAX_SHADOW_CASCADE " STRINGIFY(MAX_SHADOW_CASCADE) "\n" \
+ "#define MAX_CASCADE_NUM " STRINGIFY(MAX_CASCADE_NUM) "\n" \
+ SHADER_IRRADIANCE
+
+/* *********** STATIC *********** */
+static struct {
+ char *frag_shader_lib;
+ char *volume_shader_lib;
+
+ struct GPUShader *default_prepass_sh;
+ struct GPUShader *default_prepass_clip_sh;
+ struct GPUShader *default_lit[VAR_MAT_MAX];
+
+ struct GPUShader *default_background;
+
+ /* 64*64 array texture containing all LUTs and other utilitarian arrays.
+ * Packing enables us to same precious textures slots. */
+ struct GPUTexture *util_tex;
+
+ float viewvecs[2][4];
+} 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_bsdf_common_lib_glsl[];
+extern char datatoc_bsdf_direct_lib_glsl[];
+extern char datatoc_bsdf_sampling_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_shadow_vert_glsl[];
+extern char datatoc_shadow_geom_glsl[];
+extern char datatoc_lightprobe_geom_glsl[];
+extern char datatoc_lightprobe_vert_glsl[];
+extern char datatoc_background_vert_glsl[];
+extern char datatoc_volumetric_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_ct = 8192.0f;
+ static float inv_samples_ct = 1.0f / 8192.0f;
+
+ char *lib_str = NULL;
+
+ DynStr *ds_vert = BLI_dynstr_new();
+ BLI_dynstr_append(ds_vert, datatoc_bsdf_common_lib_glsl);
+ BLI_dynstr_append(ds_vert, datatoc_bsdf_sampling_lib_glsl);
+ lib_str = BLI_dynstr_get_cstring(ds_vert);
+ BLI_dynstr_free(ds_vert);
+
+ 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_ct, 1);
+ DRW_shgroup_uniform_float(grp, "invSampleCount", &inv_samples_ct, 1);
+ DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
+ DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter);
+
+ struct Gwn_Batch *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, DRW_TEX_RG_16, DRW_TEX_FILTER, (float *)texels);
+
+ DRWFboTexture tex_filter = {&tex, DRW_TEX_RG_16, DRW_TEX_FILTER};
+ DRW_framebuffer_init(&fb, &draw_engine_eevee_type, w, h, &tex_filter, 1);
+
+ DRW_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;
+}
+#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 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_AO) != 0) {
+ BLI_dynstr_appendf(ds, "#define USE_AO\n");
+ }
+ if ((options & VAR_MAT_FLAT) != 0) {
+ BLI_dynstr_appendf(ds, "#define USE_FLAT_NORMAL\n");
+ }
+ if ((options & VAR_MAT_BENT) != 0) {
+ BLI_dynstr_appendf(ds, "#define USE_BENT_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");
+ }
+
+ str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+
+ return str;
+}
+
+static char *eevee_get_volume_defines(int options)
+{
+ char *str = NULL;
+
+ BLI_assert(options < VAR_MAT_MAX);
+
+ DynStr *ds = BLI_dynstr_new();
+ BLI_dynstr_appendf(ds, SHADER_DEFINES);
+ BLI_dynstr_appendf(ds, "#define VOLUMETRICS\n");
+
+ if ((options & VAR_VOLUME_SHADOW) != 0) {
+ BLI_dynstr_appendf(ds, "#define VOLUME_SHADOW\n");
+ }
+ if ((options & VAR_VOLUME_HOMO) != 0) {
+ BLI_dynstr_appendf(ds, "#define VOLUME_HOMOGENEOUS\n");
+ }
+ if ((options & VAR_VOLUME_LIGHT) != 0) {
+ BLI_dynstr_appendf(ds, "#define VOLUME_LIGHTING\n");
+ }
+ if ((options & VAR_VOLUME_COLOR) != 0) {
+ BLI_dynstr_appendf(ds, "#define COLOR_TRANSMITTANCE\n");
+ }
+
+ str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+
+ return str;
+}
+
+static void add_standard_uniforms(DRWShadingGroup *shgrp, EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
+{
+ 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_int(shgrp, "light_count", &sldata->lamps->num_light, 1);
+ DRW_shgroup_uniform_int(shgrp, "probe_count", &sldata->probes->num_render_cube, 1);
+ DRW_shgroup_uniform_int(shgrp, "grid_count", &sldata->probes->num_render_grid, 1);
+ DRW_shgroup_uniform_int(shgrp, "planar_count", &sldata->probes->num_planar, 1);
+ DRW_shgroup_uniform_bool(shgrp, "specToggle", &sldata->probes->specular_toggle, 1);
+ DRW_shgroup_uniform_float(shgrp, "lodCubeMax", &sldata->probes->lod_cube_max, 1);
+ DRW_shgroup_uniform_float(shgrp, "lodPlanarMax", &sldata->probes->lod_planar_max, 1);
+ DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex);
+ DRW_shgroup_uniform_buffer(shgrp, "probeCubes", &sldata->probe_pool);
+ DRW_shgroup_uniform_buffer(shgrp, "probePlanars", &vedata->txl->planar_pool);
+ DRW_shgroup_uniform_buffer(shgrp, "irradianceGrid", &sldata->irradiance_pool);
+ DRW_shgroup_uniform_buffer(shgrp, "shadowCubes", &sldata->shadow_depth_cube_pool);
+ DRW_shgroup_uniform_buffer(shgrp, "shadowCascades", &sldata->shadow_depth_cascade_pool);
+ if (vedata->stl->effects->use_ao) {
+ DRW_shgroup_uniform_vec4(shgrp, "viewvecs[0]", (float *)&vedata->stl->g_data->viewvecs, 2);
+ DRW_shgroup_uniform_buffer(shgrp, "minMaxDepthTex", &vedata->stl->g_data->minmaxz);
+ DRW_shgroup_uniform_vec3(shgrp, "aoParameters", &vedata->stl->effects->ao_dist, 1);
+ }
+}
+
+static void create_default_shader(int options)
+{
+ DynStr *ds_frag = BLI_dynstr_new();
+ BLI_dynstr_append(ds_frag, e_data.frag_shader_lib);
+ BLI_dynstr_append(ds_frag, datatoc_default_frag_glsl);
+ char *frag_str = BLI_dynstr_get_cstring(ds_frag);
+ BLI_dynstr_free(ds_frag);
+
+ char *defines = eevee_get_defines(options);
+
+ e_data.default_lit[options] = DRW_shader_create(datatoc_lit_surface_vert_glsl, NULL, frag_str, defines);
+
+ MEM_freeN(defines);
+ MEM_freeN(frag_str);
+}
+
+void EEVEE_materials_init(EEVEE_StorageList *stl)
+{
+ if (!e_data.frag_shader_lib) {
+ char *frag_str = NULL;
+
+ /* Shaders */
+ DynStr *ds_frag = BLI_dynstr_new();
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_ambient_occlusion_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_ltc_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_direct_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_lamps_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_lit_surface_frag_glsl);
+ e_data.frag_shader_lib = BLI_dynstr_get_cstring(ds_frag);
+ BLI_dynstr_free(ds_frag);
+
+ ds_frag = BLI_dynstr_new();
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_ambient_occlusion_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_ltc_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_direct_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_lamps_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_volumetric_frag_glsl);
+ e_data.volume_shader_lib = BLI_dynstr_get_cstring(ds_frag);
+ BLI_dynstr_free(ds_frag);
+
+ ds_frag = BLI_dynstr_new();
+ BLI_dynstr_append(ds_frag, e_data.frag_shader_lib);
+ BLI_dynstr_append(ds_frag, datatoc_default_frag_glsl);
+ frag_str = BLI_dynstr_get_cstring(ds_frag);
+ BLI_dynstr_free(ds_frag);
+
+ e_data.default_background = DRW_shader_create_fullscreen(
+ 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");
+
+ MEM_freeN(frag_str);
+
+ /* Textures */
+ const int layers = 3;
+ 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 += 64 * 64;
+
+ for (int i = 0; i < 64 * 64; i++) {
+ texels_layer[i][0] = blue_noise[i][0];
+ texels_layer[i][1] = blue_noise[i][1] * 0.5 + 0.5;
+ texels_layer[i][2] = cosf(blue_noise[i][1] * 2.0 * M_PI);
+ texels_layer[i][3] = sinf(blue_noise[i][1] * 2.0 * M_PI);
+ }
+
+ e_data.util_tex = DRW_texture_create_2D_array(64, 64, layers, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_WRAP, (float *)texels);
+ MEM_freeN(texels);
+ }
+
+ {
+ /* Update viewvecs */
+ const bool is_persp = DRW_viewport_is_persp_get();
+ float invproj[4][4], winmat[4][4];
+ /* 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}
+ };
+
+ /* invert the view matrix */
+ DRW_viewport_matrix_get(winmat, DRW_MAT_WIN);
+ invert_m4_m4(invproj, winmat);
+
+ /* convert the view vectors to view space */
+ for (int 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(stl->g_data->viewvecs[0], viewvecs[0]);
+ copy_v4_v4(stl->g_data->viewvecs[1], viewvecs[1]);
+
+ /* we need to store the differences */
+ stl->g_data->viewvecs[1][0] -= viewvecs[0][0];
+ stl->g_data->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]);
+ stl->g_data->viewvecs[1][2] = vec_far[2] - viewvecs[0][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 = GPU_material_from_nodetree_find(&wo->gpumaterial, engine, options);
+ if (mat != NULL) {
+ return mat;
+ }
+ return GPU_material_from_nodetree(
+ scene, wo->nodetree, &wo->gpumaterial, engine, options,
+ datatoc_background_vert_glsl, NULL, e_data.frag_shader_lib,
+ SHADER_DEFINES "#define PROBE_CAPTURE\n");
+}
+
+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 = GPU_material_from_nodetree_find(&wo->gpumaterial, engine, options);
+ if (mat != NULL) {
+ return mat;
+ }
+ return GPU_material_from_nodetree(
+ scene, wo->nodetree, &wo->gpumaterial, engine, options,
+ datatoc_background_vert_glsl, NULL, e_data.frag_shader_lib,
+ SHADER_DEFINES "#define WORLD_BACKGROUND\n");
+}
+
+struct GPUMaterial *EEVEE_material_world_volume_get(
+ struct Scene *scene, World *wo,
+ bool use_lights, bool use_volume_shadows, bool is_homogeneous, bool use_color_transmit)
+{
+ const void *engine = &DRW_engine_viewport_eevee_type;
+ int options = VAR_WORLD_VOLUME;
+
+ if (use_lights) options |= VAR_VOLUME_LIGHT;
+ if (is_homogeneous) options |= VAR_VOLUME_HOMO;
+ if (use_volume_shadows) options |= VAR_VOLUME_SHADOW;
+ if (use_color_transmit) options |= VAR_VOLUME_COLOR;
+
+ GPUMaterial *mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine, options);
+ if (mat != NULL) {
+ return mat;
+ }
+
+ char *defines = eevee_get_volume_defines(options);
+
+ mat = GPU_material_from_nodetree(
+ scene, wo->nodetree, &wo->gpumaterial, engine, options,
+ datatoc_background_vert_glsl, NULL, e_data.volume_shader_lib,
+ defines);
+
+ MEM_freeN(defines);
+
+ return mat;
+}
+
+struct GPUMaterial *EEVEE_material_mesh_get(
+ struct Scene *scene, Material *ma,
+ bool use_ao, bool use_bent_normals, bool use_blend, bool use_multiply)
+{
+ const void *engine = &DRW_engine_viewport_eevee_type;
+ int options = VAR_MAT_MESH;
+
+ if (use_ao) options |= VAR_MAT_AO;
+ if (use_bent_normals) options |= VAR_MAT_BENT;
+ if (use_blend) options |= VAR_MAT_BLEND;
+ if (use_multiply) options |= VAR_MAT_MULT;
+
+ GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine, options);
+ if (mat) {
+ return mat;
+ }
+
+ char *defines = eevee_get_defines(options);
+
+ mat = GPU_material_from_nodetree(
+ scene, ma->nodetree, &ma->gpumaterial, engine, options,
+ datatoc_lit_surface_vert_glsl, NULL, e_data.frag_shader_lib,
+ defines);
+
+ 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 = GPU_material_from_nodetree_find(&ma->gpumaterial, engine, options);
+ if (mat) {
+ return mat;
+ }
+
+ char *defines = eevee_get_defines(options);
+
+ DynStr *ds_frag = BLI_dynstr_new();
+ BLI_dynstr_append(ds_frag, e_data.frag_shader_lib);
+ BLI_dynstr_append(ds_frag, datatoc_prepass_frag_glsl);
+ char *frag_str = BLI_dynstr_get_cstring(ds_frag);
+ BLI_dynstr_free(ds_frag);
+
+ mat = GPU_material_from_nodetree(
+ scene, ma->nodetree, &ma->gpumaterial, engine, options,
+ (is_shadow) ? datatoc_shadow_vert_glsl : datatoc_lit_surface_vert_glsl,
+ (is_shadow) ? datatoc_shadow_geom_glsl : NULL,
+ frag_str,
+ defines);
+
+ MEM_freeN(frag_str);
+ MEM_freeN(defines);
+
+ return mat;
+}
+
+struct GPUMaterial *EEVEE_material_hair_get(
+ struct Scene *scene, Material *ma,
+ bool use_ao, bool use_bent_normals)
+{
+ const void *engine = &DRW_engine_viewport_eevee_type;
+ int options = VAR_MAT_MESH | VAR_MAT_HAIR;
+
+ if (use_ao) options |= VAR_MAT_AO;
+ if (use_bent_normals) options |= VAR_MAT_BENT;
+
+ GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine, options);
+ if (mat) {
+ return mat;
+ }
+
+ char *defines = eevee_get_defines(options);
+
+ mat = GPU_material_from_nodetree(
+ scene, ma->nodetree, &ma->gpumaterial, engine, options,
+ datatoc_lit_surface_vert_glsl, NULL, e_data.frag_shader_lib,
+ defines);
+
+ MEM_freeN(defines);
+
+ return mat;
+}
+
+/**
+ * Create a default shading group inside the given pass.
+ **/
+static struct DRWShadingGroup *EEVEE_default_shading_group_create(
+ EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata, DRWPass *pass,
+ bool is_hair, bool is_flat_normal, bool use_ao, bool use_bent_normals, bool use_blend)
+{
+ int options = VAR_MAT_MESH;
+
+ if (is_hair) options |= VAR_MAT_HAIR;
+ if (use_ao) options |= VAR_MAT_AO;
+ if (use_bent_normals) options |= VAR_MAT_BENT;
+ if (is_flat_normal) options |= VAR_MAT_FLAT;
+ if (use_blend) options |= VAR_MAT_BLEND;
+
+ 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);
+
+ return shgrp;
+}
+
+/**
+ * Create a default shading group inside the default pass without standard uniforms.
+ **/
+static struct DRWShadingGroup *EEVEE_default_shading_group_get(
+ EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata,
+ bool is_hair, bool is_flat_normal, bool use_ao, bool use_bent_normals)
+{
+ int options = VAR_MAT_MESH;
+
+ if (is_hair) options |= VAR_MAT_HAIR;
+ if (use_ao) options |= VAR_MAT_AO;
+ if (use_bent_normals) options |= VAR_MAT_BENT;
+ if (is_flat_normal) options |= VAR_MAT_FLAT;
+
+ 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);
+
+ DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]);
+ add_standard_uniforms(shgrp, sldata, vedata);
+ }
+
+ return DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]);
+}
+
+void EEVEE_materials_cache_init(EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
+
+ {
+ /* Global AO Switch*/
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ SceneLayer *scene_layer = draw_ctx->scene_layer;
+ IDProperty *props = BKE_scene_layer_engine_evaluated_get(scene_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE);
+ stl->effects->use_ao = BKE_collection_engine_property_value_get_bool(props, "gtao_enable");
+ stl->effects->use_bent_normals = BKE_collection_engine_property_value_get_bool(props, "gtao_use_bent_normals");
+ }
+
+ /* Create Material Ghash */
+ {
+ stl->g_data->material_hash = BLI_ghash_ptr_new("Eevee_material ghash");
+ stl->g_data->hair_material_hash = BLI_ghash_ptr_new("Eevee_hair_material ghash");
+ }
+
+ {
+ psl->background_pass = DRW_pass_create("Background Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR);
+
+ struct Gwn_Batch *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;
+
+ if (wo) {
+ col = &wo->horr;
+
+ if (wo->use_nodes && wo->nodetree) {
+ struct GPUMaterial *gpumat = EEVEE_material_world_background_get(scene, wo);
+ grp = DRW_shgroup_material_create(gpumat, psl->background_pass);
+
+ if (grp) {
+ DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
+ DRW_shgroup_call_add(grp, geom, NULL);
+ }
+ else {
+ /* Shader failed : pink background */
+ static float pink[3] = {1.0f, 0.0f, 1.0f};
+ col = pink;
+ }
+ }
+ }
+
+ /* 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 | 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 | 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 | 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);
+
+ state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | 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);
+ }
+
+ {
+ 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_COLOR | DRW_STATE_DEPTH_LESS | DRW_STATE_CLIP_PLANES | DRW_STATE_WIRE;
+ psl->transparent_pass = DRW_pass_create("Material Transparent Pass", state);
+ }
+}
+
+#define ADD_SHGROUP_CALL(shgrp, ob, geom) do { \
+ if (is_sculpt_mode_draw) { \
+ DRW_shgroup_call_sculpt_add(shgrp, ob, ob->obmat); \
+ } \
+ else { \
+ DRW_shgroup_call_object_add(shgrp, geom, ob); \
+ } \
+} while (0)
+
+#define ADD_SHGROUP_CALL_SAFE(shgrp, ob, geom) do { \
+ if (shgrp) { \
+ ADD_SHGROUP_CALL(shgrp, ob, geom); \
+ } \
+} 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_SceneLayerData *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)
+{
+ 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;
+
+ float *color_p = &ma->r;
+ float *metal_p = &ma->ray_mirror;
+ float *spec_p = &ma->spec;
+ float *rough_p = &ma->gloss_mir;
+
+ const bool use_gpumat = (ma->use_nodes && ma->nodetree);
+
+ 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, stl->effects->use_ao, stl->effects->use_bent_normals, false, false) : NULL;
+ *gpumat_depth = (use_gpumat) ? EEVEE_material_mesh_depth_get(
+ scene, ma, (ma->blend_method == MA_BM_HASHED), false) : NULL;
+ return;
+ }
+
+ if (use_gpumat) {
+ /* Shading */
+ *gpumat = EEVEE_material_mesh_get(scene, ma,
+ stl->effects->use_ao, stl->effects->use_bent_normals, false, false);
+
+ *shgrp = DRW_shgroup_material_create(*gpumat, psl->material_pass);
+ if (*shgrp) {
+ add_standard_uniforms(*shgrp, sldata, vedata);
+ }
+ else {
+ /* Shader failed : pink color */
+ static float col[3] = {1.0f, 0.0f, 1.0f};
+ static float half = 0.5f;
+
+ color_p = col;
+ metal_p = spec_p = rough_p = &half;
+ }
+
+ /* 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);
+
+ *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) {
+ 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);
+ }
+ }
+ }
+ }
+
+ /* Fallback to default shader */
+ if (*shgrp == NULL) {
+ *shgrp = EEVEE_default_shading_group_get(sldata, vedata, false, use_flat_nor,
+ stl->effects->use_ao, stl->effects->use_bent_normals);
+ 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) {
+ *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_SceneLayerData *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;
+
+ float *color_p = &ma->r;
+ float *metal_p = &ma->ray_mirror;
+ float *spec_p = &ma->spec;
+ float *rough_p = &ma->gloss_mir;
+
+ if (ma->use_nodes && ma->nodetree) {
+ /* Shading */
+ *gpumat = EEVEE_material_mesh_get(scene, ma,
+ stl->effects->use_ao, stl->effects->use_bent_normals,
+ true, (ma->blend_method == MA_BM_MULTIPLY));
+
+ *shgrp = DRW_shgroup_material_create(*gpumat, psl->transparent_pass);
+ if (*shgrp) {
+ add_standard_uniforms(*shgrp, sldata, vedata);
+ }
+ else {
+ /* Shader failed : pink color */
+ static float col[3] = {1.0f, 0.0f, 1.0f};
+ static float half = 0.5f;
+
+ color_p = col;
+ metal_p = spec_p = rough_p = &half;
+ }
+ }
+
+ /* Fallback to default shader */
+ if (*shgrp == NULL) {
+ *shgrp = EEVEE_default_shading_group_create(
+ sldata, vedata, psl->transparent_pass,
+ false, use_flat_nor, stl->effects->use_ao, stl->effects->use_bent_normals, true);
+ 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 | 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;
+ 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);
+
+ cur_state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS;
+ 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_SceneLayerData *sldata, Object *ob)
+{
+ EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ GHash *material_hash = stl->g_data->material_hash;
+
+ IDProperty *ces_mode_ob = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_OBJECT, "");
+ const bool do_cull = BKE_collection_engine_property_value_get_bool(ces_mode_ob, "show_backface_culling");
+ const bool is_active = (ob == draw_ctx->obact);
+ const bool is_sculpt_mode = is_active && (ob->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 is_default_mode_shader = is_sculpt_mode;
+
+ /* First get materials for this mesh. */
+ if (ELEM(ob->type, OB_MESH)) {
+ 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);
+ }
+
+ /* Get per-material split surface */
+ struct Gwn_Batch **mat_geom = DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len);
+ if (mat_geom) {
+ for (int i = 0; i < materials_len; ++i) {
+ Material *ma = give_current_material(ob, i + 1);
+
+ if (ma == NULL)
+ ma = &defmaterial;
+
+ /* Shading pass */
+ ADD_SHGROUP_CALL(shgrp_array[i], ob, mat_geom[i]);
+
+ /* Depth Prepass */
+ ADD_SHGROUP_CALL_SAFE(shgrp_depth_array[i], ob, mat_geom[i]);
+ ADD_SHGROUP_CALL_SAFE(shgrp_depth_clip_array[i], ob, mat_geom[i]);
+
+ /* 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, psl, mat_geom[i], ob->obmat);
+ 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->obmat, &ma->alpha_threshold);
+ 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->obmat, NULL);
+ break;
+ case MA_BS_NONE:
+ default:
+ break;
+ }
+ }
+ else {
+ EEVEE_lights_cache_shcaster_add(sldata, psl, mat_geom[i], ob->obmat);
+ }
+ }
+ }
+ }
+
+ if (ob->type == OB_MESH) {
+ if (ob != draw_ctx->scene->obedit) {
+ material_hash = stl->g_data->hair_material_hash;
+
+ for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_ParticleSystem) {
+ ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
+
+ if (psys_check_enabled(ob, psys, false)) {
+ ParticleSettings *part = psys->part;
+ int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
+
+ if (draw_as == PART_DRAW_PATH && (psys->pathcache || psys->childcache)) {
+ struct Gwn_Batch *hair_geom = DRW_cache_particles_get_hair(psys, md);
+ DRWShadingGroup *shgrp = NULL;
+ Material *ma = give_current_material(ob, part->omat);
+ static float mat[4][4];
+
+ unit_m4(mat);
+
+ if (ma == NULL) {
+ ma = &defmaterial;
+ }
+
+ float *color_p = &ma->r;
+ float *metal_p = &ma->ray_mirror;
+ float *spec_p = &ma->spec;
+ float *rough_p = &ma->gloss_mir;
+
+ DRW_shgroup_call_add(stl->g_data->depth_shgrp, hair_geom, mat);
+ DRW_shgroup_call_add(stl->g_data->depth_shgrp_clip, hair_geom, mat);
+
+ shgrp = BLI_ghash_lookup(material_hash, (const void *)ma);
+
+ if (shgrp) {
+ DRW_shgroup_call_add(shgrp, hair_geom, mat);
+ }
+ else {
+ if (ma->use_nodes && ma->nodetree) {
+ struct GPUMaterial *gpumat = EEVEE_material_hair_get(scene, ma,
+ stl->effects->use_ao, stl->effects->use_bent_normals);
+
+ shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass);
+ if (shgrp) {
+ add_standard_uniforms(shgrp, sldata, vedata);
+
+ BLI_ghash_insert(material_hash, ma, shgrp);
+
+ DRW_shgroup_call_add(shgrp, hair_geom, mat);
+ }
+ else {
+ /* Shader failed : pink color */
+ static float col[3] = {1.0f, 0.0f, 1.0f};
+ static float half = 0.5f;
+
+ color_p = col;
+ metal_p = spec_p = rough_p = &half;
+ }
+ }
+
+ /* Fallback to default shader */
+ if (shgrp == NULL) {
+ shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, false,
+ stl->effects->use_ao, stl->effects->use_bent_normals);
+ 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);
+
+ BLI_ghash_insert(material_hash, ma, shgrp);
+
+ DRW_shgroup_call_add(shgrp, hair_geom, mat);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void EEVEE_materials_cache_finish(EEVEE_Data *vedata)
+{
+ EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
+
+ BLI_ghash_free(stl->g_data->material_hash, NULL, MEM_freeN);
+ BLI_ghash_free(stl->g_data->hair_material_hash, NULL, NULL);
+}
+
+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.volume_shader_lib);
+ 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_TEXTURE_FREE_SAFE(e_data.util_tex);
+}
+
+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_private.h b/source/blender/draw/engines/eevee/eevee_private.h
new file mode 100644
index 00000000000..eb420e2a8c7
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -0,0 +1,534 @@
+/*
+ * 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__
+
+struct Object;
+
+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_SHADOW_CUBE 42 /* TODO : Make this depends on GL_MAX_ARRAY_TEXTURE_LAYERS */
+#define MAX_SHADOW_MAP 64
+#define MAX_SHADOW_CASCADE 8
+#define MAX_CASCADE_NUM 4
+#define MAX_BLOOM_STEP 16
+
+/* Only define one of these. */
+// #define IRRADIANCE_SH_L2
+// #define IRRADIANCE_CUBEMAP
+#define IRRADIANCE_HL2
+
+/* World shader variations */
+enum {
+ VAR_WORLD_BACKGROUND = 0,
+ VAR_WORLD_PROBE = 1,
+ VAR_WORLD_VOLUME = 2,
+
+ VAR_VOLUME_SHADOW = (1 << 2),
+ VAR_VOLUME_HOMO = (1 << 3),
+ VAR_VOLUME_LIGHT = (1 << 4),
+ VAR_VOLUME_COLOR = (1 << 5),
+};
+
+/* Material shader variations */
+enum {
+ VAR_MAT_MESH = (1 << 0),
+ VAR_MAT_PROBE = (1 << 1),
+ VAR_MAT_HAIR = (1 << 2),
+ VAR_MAT_AO = (1 << 3),
+ VAR_MAT_FLAT = (1 << 4),
+ VAR_MAT_BENT = (1 << 5),
+ VAR_MAT_BLEND = (1 << 6),
+ /* Max number of variation */
+ /* IMPORTANT : Leave it last and set
+ * it's value accordingly. */
+ VAR_MAT_MAX = (1 << 7),
+ /* These are options that are not counted in VAR_MAT_MAX
+ * because they are not cumulative with the others above. */
+ VAR_MAT_CLIP = (1 << 8),
+ VAR_MAT_HASH = (1 << 9),
+ VAR_MAT_MULT = (1 << 10),
+ VAR_MAT_SHADOW = (1 << 11),
+};
+
+typedef struct EEVEE_PassList {
+ /* Shadows */
+ struct DRWPass *shadow_pass;
+ struct DRWPass *shadow_cube_pass;
+ struct DRWPass *shadow_cube_store_pass;
+ struct DRWPass *shadow_cascade_pass;
+
+ /* Probes */
+ struct DRWPass *probe_background;
+ struct DRWPass *probe_glossy_compute;
+ struct DRWPass *probe_diffuse_compute;
+ struct DRWPass *probe_display;
+ struct DRWPass *probe_planar_downsample_ps;
+
+ /* Effects */
+ 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 *minmaxz_downlevel;
+ struct DRWPass *minmaxz_downdepth;
+ struct DRWPass *minmaxz_copydepth;
+ struct DRWPass *volumetric_integrate_ps;
+ struct DRWPass *volumetric_resolve_ps;
+ struct DRWPass *volumetric_resolve_transmit_ps;
+
+ struct DRWPass *depth_pass;
+ struct DRWPass *depth_pass_cull;
+ struct DRWPass *depth_pass_clip;
+ struct DRWPass *depth_pass_clip_cull;
+ struct DRWPass *default_pass[VAR_MAT_MAX];
+ struct DRWPass *material_pass;
+ struct DRWPass *transparent_pass;
+ struct DRWPass *background_pass;
+} EEVEE_PassList;
+
+typedef struct EEVEE_FramebufferList {
+ /* Effects */
+ struct GPUFrameBuffer *minmaxz_fb;
+ struct GPUFrameBuffer *effect_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 *dof_down_fb;
+ struct GPUFrameBuffer *dof_scatter_far_fb;
+ struct GPUFrameBuffer *dof_scatter_near_fb;
+ struct GPUFrameBuffer *volumetric_fb;
+
+ struct GPUFrameBuffer *planarref_fb;
+
+ struct GPUFrameBuffer *main;
+} EEVEE_FramebufferList;
+
+typedef struct EEVEE_TextureList {
+ /* Effects */
+ struct GPUTexture *color_post; /* R16_G16_B16 */
+ struct GPUTexture *dof_down_near; /* R16_G16_B16_A16 */
+ struct GPUTexture *dof_down_far; /* R16_G16_B16_A16 */
+ struct GPUTexture *dof_coc; /* R16_G16 */
+ struct GPUTexture *dof_near_blur; /* R16_G16_B16_A16 */
+ struct GPUTexture *dof_far_blur; /* R16_G16_B16_A16 */
+ struct GPUTexture *bloom_blit; /* R16_G16_B16 */
+ struct GPUTexture *bloom_downsample[MAX_BLOOM_STEP]; /* R16_G16_B16 */
+ struct GPUTexture *bloom_upsample[MAX_BLOOM_STEP-1]; /* R16_G16_B16 */
+
+ struct GPUTexture *planar_pool;
+
+ struct GPUTexture *color; /* R16_G16_B16 */
+} EEVEE_TextureList;
+
+typedef struct EEVEE_StorageList {
+ /* Effects */
+ struct EEVEE_EffectsInfo *effects;
+
+ struct EEVEE_PrivateData *g_data;
+} EEVEE_StorageList;
+
+/* ************ LIGHT UBO ************* */
+typedef struct EEVEE_Light {
+ float position[3], dist;
+ float color[3], spec;
+ float spotsize, spotblend, radius, shadowid;
+ float rightvec[3], sizex;
+ float upvec[3], sizey;
+ float forwardvec[3], lamptype;
+} EEVEE_Light;
+
+typedef struct EEVEE_ShadowCube {
+ float near, far, bias, exp;
+} EEVEE_ShadowCube;
+
+typedef struct EEVEE_ShadowMap {
+ float shadowmat[4][4]; /* World->Lamp->NDC->Tex : used for sampling the shadow map. */
+ float near, far, bias, pad;
+} EEVEE_ShadowMap;
+
+typedef struct EEVEE_ShadowCascade {
+ float shadowmat[MAX_CASCADE_NUM][4][4]; /* World->Lamp->NDC->Tex : used for sampling the shadow map. */
+ float split[4];
+ float bias[4];
+} EEVEE_ShadowCascade;
+
+typedef struct EEVEE_ShadowRender {
+ float shadowmat[6][4][4]; /* World->Lamp->NDC : used to render the shadow map. 6 frustrum for cubemap shadow */
+ float viewmat[6][4][4]; /* World->Lamp : used to render the shadow map. 6 viewmat for cubemap shadow */
+ float position[3];
+ float pad;
+ int layer;
+ float exponent;
+} EEVEE_ShadowRender;
+
+/* ************ VOLUME DATA ************ */
+typedef struct EEVEE_VolumetricsInfo {
+ float integration_step_count, shadow_step_count, sample_distribution, light_clamp;
+ float integration_start, integration_end;
+ bool use_lights, use_volume_shadows, use_colored_transmit;
+} EEVEE_VolumetricsInfo;
+
+/* ************ LIGHT DATA ************* */
+typedef struct EEVEE_LampsInfo {
+ int num_light, cache_num_light;
+ int num_cube, cache_num_cube;
+ int num_map, cache_num_map;
+ int num_cascade, cache_num_cascade;
+ int update_flag;
+ /* 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_map_ref[MAX_SHADOW_MAP];
+ 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_ShadowCube shadow_cube_data[MAX_SHADOW_CUBE];
+ struct EEVEE_ShadowMap shadow_map_data[MAX_SHADOW_MAP];
+ struct EEVEE_ShadowCascade shadow_cascade_data[MAX_SHADOW_CASCADE];
+} EEVEE_LampsInfo;
+
+/* EEVEE_LampsInfo->update_flag */
+enum {
+ LIGHT_UPDATE_SHADOW_CUBE = (1 << 0),
+};
+
+/* ************ PROBE UBO ************* */
+typedef struct EEVEE_LightProbe {
+ float position[3], parallax_type;
+ float attenuation_fac;
+ float attenuation_type;
+ float pad3[2];
+ float attenuationmat[4][4];
+ float parallaxmat[4][4];
+} EEVEE_LightProbe;
+
+typedef struct EEVEE_LightGrid {
+ float mat[4][4];
+ int resolution[3], offset;
+ float corner[3], attenuation_scale;
+ float increment_x[3], attenuation_bias; /* world space vector between 2 opposite cells */
+ float increment_y[3], pad3;
+ float increment_z[3], pad4;
+} 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, pad[2];
+ float reflectionmat[4][4];
+} EEVEE_PlanarReflection;
+
+/* ************ PROBE DATA ************* */
+typedef struct EEVEE_LightProbesInfo {
+ int num_cube, cache_num_cube;
+ int num_grid, cache_num_grid;
+ int num_planar, cache_num_planar;
+ int update_flag;
+ int updated_bounce;
+ /* Actual number of probes that have datas. */
+ int num_render_cube;
+ int num_render_grid;
+ /* For rendering probes */
+ float probemat[6][4][4];
+ int layer;
+ float texel_size;
+ float padding_size;
+ float samples_ct;
+ float invsamples_ct;
+ float roughness;
+ float lodfactor;
+ float lod_rt_max, lod_cube_max, lod_planar_max;
+ int shres;
+ int shnbr;
+ bool specular_toggle;
+ /* List of probes in the scene. */
+ /* XXX This is fragile, can get out of sync quickly. */
+ struct Object *probes_cube_ref[MAX_PROBE];
+ struct Object *probes_grid_ref[MAX_GRID];
+ struct Object *probes_planar_ref[MAX_PLANAR];
+ /* UBO Storage : data used by UBO */
+ struct EEVEE_LightProbe probe_data[MAX_PROBE];
+ struct EEVEE_LightGrid grid_data[MAX_GRID];
+ struct EEVEE_PlanarReflection planar_data[MAX_PLANAR];
+} EEVEE_LightProbesInfo;
+
+/* EEVEE_LightProbesInfo->update_flag */
+enum {
+ PROBE_UPDATE_CUBE = (1 << 0),
+};
+
+/* ************ EFFECTS DATA ************* */
+typedef struct EEVEE_EffectsInfo {
+ int enabled_effects;
+
+ /* Ambient Occlusion */
+ bool use_ao, use_bent_normals;
+ float ao_dist, ao_samples, ao_factor;
+
+ /* Motion Blur */
+ float current_ndc_to_world[4][4];
+ float past_world_to_ndc[4][4];
+ float tmp_mat[4][4];
+ int motion_blur_samples;
+
+ /* Depth Of Field */
+ float dof_near_far[2];
+ float dof_params[3];
+ float dof_bokeh[4];
+ float dof_layer_select[2];
+ int dof_target_size[2];
+
+ /* Bloom */
+ int bloom_iteration_ct;
+ float source_texel_size[2];
+ float blit_texel_size[2];
+ float downsamp_texel_size[MAX_BLOOM_STEP][2];
+ float bloom_intensity;
+ float bloom_sample_scale;
+ float bloom_curve_threshold[4];
+ float unf_source_texel_size[2];
+ 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 */
+} EEVEE_EffectsInfo;
+
+enum {
+ EFFECT_MOTION_BLUR = (1 << 0),
+ EFFECT_BLOOM = (1 << 1),
+ EFFECT_DOF = (1 << 2),
+ EFFECT_VOLUMETRIC = (1 << 3),
+};
+
+/* ************** SCENE LAYER DATA ************** */
+typedef struct EEVEE_SceneLayerData {
+ /* Lamps */
+ struct EEVEE_LampsInfo *lamps;
+
+ struct GPUUniformBuffer *light_ubo;
+ struct GPUUniformBuffer *shadow_ubo;
+ struct GPUUniformBuffer *shadow_render_ubo;
+
+ struct GPUFrameBuffer *shadow_cube_target_fb;
+ struct GPUFrameBuffer *shadow_cube_fb;
+ struct GPUFrameBuffer *shadow_map_fb;
+ struct GPUFrameBuffer *shadow_cascade_fb;
+
+ struct GPUTexture *shadow_depth_cube_target;
+ struct GPUTexture *shadow_color_cube_target;
+ struct GPUTexture *shadow_depth_cube_pool;
+ struct GPUTexture *shadow_depth_map_pool;
+ struct GPUTexture *shadow_depth_cascade_pool;
+
+ struct ListBase shadow_casters; /* Shadow casters gathered during cache iteration */
+
+ /* Probes */
+ struct EEVEE_LightProbesInfo *probes;
+
+ struct GPUUniformBuffer *probe_ubo;
+ struct GPUUniformBuffer *grid_ubo;
+ struct GPUUniformBuffer *planar_ubo;
+
+ struct GPUFrameBuffer *probe_fb;
+ struct GPUFrameBuffer *probe_filter_fb;
+
+ struct GPUTexture *probe_rt;
+ struct GPUTexture *probe_pool;
+ struct GPUTexture *irradiance_pool;
+ struct GPUTexture *irradiance_rt;
+
+ struct ListBase probe_queue; /* List of probes to update */
+
+ /* Volumetrics */
+ struct EEVEE_VolumetricsInfo *volumetrics;
+} EEVEE_SceneLayerData;
+
+/* ************ OBJECT DATA ************ */
+typedef struct EEVEE_LampEngineData {
+ bool need_update;
+ struct ListBase shadow_caster_list;
+ void *storage; /* either EEVEE_LightData, EEVEE_ShadowCubeData, EEVEE_ShadowCascadeData */
+} EEVEE_LampEngineData;
+
+typedef struct EEVEE_LightProbeEngineData {
+ bool need_update;
+ bool ready_to_shade;
+ int updated_cells;
+ int num_cell;
+ int probe_id; /* Only used for display data */
+ /* For planar reflection rendering */
+ float viewmat[4][4];
+ float persmat[4][4];
+ float planer_eq_offset[4];
+ struct ListBase captured_object_list;
+} EEVEE_LightProbeEngineData;
+
+typedef struct EEVEE_ObjectEngineData {
+ bool need_update;
+} EEVEE_ObjectEngineData;
+
+/* *********************************** */
+
+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 *cube_display_shgrp;
+ struct DRWShadingGroup *planar_downsample;
+ struct GHash *material_hash;
+ struct GHash *hair_material_hash;
+ struct GPUTexture *minmaxz;
+ struct GPUTexture *volumetric;
+ struct GPUTexture *volumetric_transmit;
+ float background_alpha; /* TODO find a better place for this. */
+ float viewvecs[2][4];
+ /* For planar probes */
+ float texel_size[2];
+} EEVEE_PrivateData; /* Transient data */
+
+/* eevee_data.c */
+EEVEE_SceneLayerData *EEVEE_scene_layer_data_get(void);
+EEVEE_ObjectEngineData *EEVEE_object_data_get(Object *ob);
+EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_get(Object *ob);
+EEVEE_LampEngineData *EEVEE_lamp_data_get(Object *ob);
+
+/* eevee_materials.c */
+struct GPUTexture *EEVEE_materials_get_util_tex(void); /* XXX */
+void EEVEE_materials_init(EEVEE_StorageList *stl);
+void EEVEE_materials_cache_init(EEVEE_Data *vedata);
+void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sldata, Object *ob);
+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, bool use_lights, bool use_volume_shadows, bool is_homogeneous, bool use_color_transmit);
+struct GPUMaterial *EEVEE_material_mesh_get(
+ struct Scene *scene, Material *ma, bool use_ao, bool use_bent_normals, bool use_blend, bool use_multiply);
+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, bool use_ao, bool use_bent_normals);
+void EEVEE_materials_free(void);
+void EEVEE_draw_default_passes(EEVEE_PassList *psl);
+
+/* eevee_lights.c */
+void EEVEE_lights_init(EEVEE_SceneLayerData *sldata);
+void EEVEE_lights_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl);
+void EEVEE_lights_cache_add(EEVEE_SceneLayerData *sldata, struct Object *ob);
+void EEVEE_lights_cache_shcaster_add(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl, struct Gwn_Batch *geom, float (*obmat)[4]);
+void EEVEE_lights_cache_shcaster_material_add(
+ EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl,
+ struct GPUMaterial *gpumat, struct Gwn_Batch *geom, float (*obmat)[4], float *alpha_threshold);
+void EEVEE_lights_cache_finish(EEVEE_SceneLayerData *sldata);
+void EEVEE_lights_update(EEVEE_SceneLayerData *sldata);
+void EEVEE_draw_shadows(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl);
+void EEVEE_lights_free(void);
+
+/* eevee_lightprobes.c */
+void EEVEE_lightprobes_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_lightprobes_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_lightprobes_cache_add(EEVEE_SceneLayerData *sldata, Object *ob);
+void EEVEE_lightprobes_cache_finish(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_lightprobes_refresh(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_lightprobes_free(void);
+
+/* eevee_effects.c */
+void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, struct GPUTexture *depth_src);
+void EEVEE_effects_do_volumetrics(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_draw_effects(EEVEE_Data *vedata);
+void EEVEE_effects_free(void);
+
+/* Shadow Matrix */
+static const float texcomat[4][4] = { /* From NDC to TexCo */
+ {0.5, 0.0, 0.0, 0.0},
+ {0.0, 0.5, 0.0, 0.0},
+ {0.0, 0.0, 0.5, 0.0},
+ {0.5, 0.5, 0.5, 1.0}
+};
+
+/* Cubemap Matrices */
+static const float cubefacemat[6][4][4] = {
+ /* Pos X */
+ {{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}},
+ /* Neg X */
+ {{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}},
+ /* Pos Y */
+ {{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}},
+ /* Neg Y */
+ {{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}},
+ /* Pos Z */
+ {{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}},
+ /* Neg Z */
+ {{-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}},
+};
+
+#endif /* __EEVEE_PRIVATE_H__ */
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..77bae174985
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
@@ -0,0 +1,242 @@
+
+/* 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 */
+
+#define MAX_PHI_STEP 32
+/* NOTICE : this is multiplied by 2 */
+#define MAX_THETA_STEP 12
+
+uniform sampler2D minMaxDepthTex;
+uniform vec3 aoParameters;
+
+#define aoDistance aoParameters.x
+#define aoSamples aoParameters.y
+#define aoFactor aoParameters.z
+
+float get_max_horizon(vec2 co, vec3 x, float h, float lod)
+{
+ float depth = textureLod(minMaxDepthTex, co, floor(lod)).g;
+
+ /* Background case */
+ /* this is really slow and is only a problem
+ * if the far clip plane is near enough to notice */
+ // depth += step(1.0, depth) * 1e20;
+
+ vec3 s = get_view_space_from_depth(co, depth); /* s View coordinate */
+ vec3 omega_s = s - x;
+ float len = length(omega_s);
+
+ float max_h = max(h, omega_s.z / len);
+ /* Blend weight after half the aoDistance to fade artifacts */
+ float blend = saturate((1.0 - len / aoDistance) * 2.0);
+
+ return mix(h, max_h, blend);
+}
+
+void search_step(
+ vec2 t_phi, vec3 x, vec2 x_, float rand, vec2 pixel_ratio,
+ inout float j, inout float ofs, inout float h1, inout float h2)
+{
+ ofs += ofs; /* Step size is doubled each iteration */
+
+ vec2 s_ = t_phi * ofs * rand * pixel_ratio; /* s^ Screen coordinate */
+ vec2 co;
+
+ co = x_ + s_;
+ h1 = get_max_horizon(co, x, h1, j);
+
+ co = x_ - s_;
+ h2 = get_max_horizon(co, x, h2, j);
+
+ j += 0.5;
+}
+
+void search_horizon(
+ vec2 t_phi, vec3 x, vec2 x_, float rand,
+ float max_dist, vec2 pixel_ratio, float pixel_len,
+ inout float h1, inout float h2)
+{
+ float ofs = 1.5 * pixel_len;
+ float j = 0.0;
+
+#if 0 /* manually unrolled bellow */
+ for (int i = 0; i < MAX_THETA_STEP; i++) {
+ search_step(t_phi, x, x_, rand, pixel_ratio, j, ofs, h1, h2);
+ if (ofs > max_dist)
+ return;
+ }
+#endif
+ search_step(t_phi, x, x_, rand, pixel_ratio, j, ofs, h1, h2);
+ if (ofs > max_dist) return;
+
+ search_step(t_phi, x, x_, rand, pixel_ratio, j, ofs, h1, h2);
+ if (ofs > max_dist) return;
+
+ search_step(t_phi, x, x_, rand, pixel_ratio, j, ofs, h1, h2);
+ if (ofs > max_dist) return;
+
+ search_step(t_phi, x, x_, rand, pixel_ratio, j, ofs, h1, h2);
+ if (ofs > max_dist) return;
+
+ search_step(t_phi, x, x_, rand, pixel_ratio, j, ofs, h1, h2);
+ if (ofs > max_dist) return;
+
+ search_step(t_phi, x, x_, rand, pixel_ratio, j, ofs, h1, h2);
+ if (ofs > max_dist) return;
+
+ search_step(t_phi, x, x_, rand, pixel_ratio, j, ofs, h1, h2);
+ if (ofs > max_dist) return;
+
+ search_step(t_phi, x, x_, rand, pixel_ratio, j, ofs, h1, h2);
+ if (ofs > max_dist) return;
+
+ search_step(t_phi, x, x_, rand, pixel_ratio, j, ofs, h1, h2);
+ if (ofs > max_dist) return;
+
+ search_step(t_phi, x, x_, rand, pixel_ratio, j, ofs, h1, h2);
+ if (ofs > max_dist) return;
+
+ search_step(t_phi, x, x_, rand, pixel_ratio, j, ofs, h1, h2);
+ if (ofs > max_dist) return;
+
+ search_step(t_phi, x, x_, rand, pixel_ratio, j, ofs, h1, h2);
+}
+
+void integrate_slice(
+ float iter, vec3 x, vec3 normal, vec2 x_, vec2 noise,
+ float max_dist, vec2 pixel_ratio, float pixel_len,
+ inout float visibility, inout vec3 bent_normal)
+{
+ float phi = M_PI * ((noise.r + iter) / aoSamples);
+
+ /* Rotate with random direction to get jittered result. */
+ vec2 t_phi = vec2(cos(phi), sin(phi)); /* Screen space direction */
+
+ /* Search maximum horizon angles h1 and h2 */
+ float h1 = -1.0, h2 = -1.0; /* init at cos(pi) */
+ search_horizon(t_phi, x, x_, noise.g, max_dist, pixel_ratio, pixel_len, h1, h2);
+
+ /* (Slide 54) */
+ h1 = -fast_acos(h1);
+ h2 = fast_acos(h2);
+
+ /* Projecting Normal to Plane P defined by t_phi and omega_o */
+ vec3 h = 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 - h * dot(h, normal);
+ float n_proj_len = max(1e-16, length(n_proj));
+
+ /* Clamping thetas (slide 58) */
+ 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 */
+ h1 = n + max(h1 - n, -M_PI_2);
+ h2 = n + min(h2 - n, M_PI_2);
+
+ /* Solving inner integral */
+ float sin_n = sin(n);
+ float h1_2 = 2.0 * h1;
+ float h2_2 = 2.0 * h2;
+ float vd = (-cos(h1_2 - n) + cos_n + h1_2 * sin_n) + (-cos(h2_2 - n) + cos_n + h2_2 * sin_n);
+ vd *= 0.25 * n_proj_len;
+ visibility += vd;
+
+#ifdef USE_BENT_NORMAL
+ /* Finding Bent normal */
+ float b_angle = (h1 + h2) / 2.0;
+ /* 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). */
+ /* Weight sample by vd */
+ bent_normal += vec3(sin(b_angle) * -t_phi, cos(b_angle) * 0.5) * vd;
+#endif
+}
+
+void gtao(vec3 normal, vec3 position, vec2 noise, out float visibility
+#ifdef USE_BENT_NORMAL
+ , out vec3 bent_normal
+#endif
+ )
+{
+ vec2 screenres = vec2(textureSize(minMaxDepthTex, 0)) * 2.0;
+ vec2 pixel_size = vec2(1.0) / screenres.xy;
+
+ /* Renaming */
+ vec2 x_ = gl_FragCoord.xy * pixel_size; /* x^ Screen coordinate */
+ vec3 x = position; /* x view space coordinate */
+
+ /* NOTE : We set up integration domain around the camera forward axis
+ * and not the view vector like in the paper.
+ * This allows us to save a lot of dot products. */
+ /* omega_o = vec3(0.0, 0.0, 1.0); */
+
+ vec2 pixel_ratio = vec2(screenres.y / screenres.x, 1.0);
+ float pixel_len = length(pixel_size);
+ float homcco = ProjectionMatrix[2][3] * position.z + ProjectionMatrix[3][3];
+ float max_dist = aoDistance / homcco; /* Search distance */
+
+ /* Integral over PI */
+ visibility = 0.0;
+#ifdef USE_BENT_NORMAL
+ bent_normal = vec3(0.0);
+#else
+ vec3 bent_normal = vec3(0.0);
+#endif
+ for (float i = 0.0; i < MAX_PHI_STEP; i++) {
+ if (i >= aoSamples) break;
+ integrate_slice(i, x, normal, x_, noise, max_dist, pixel_ratio, pixel_len, visibility, bent_normal);
+ }
+
+ /* aoSamples can be 0.0 to temporary disable the effect. */
+ visibility = clamp(max(1e-8, visibility) / max(1e-8, aoSamples), 1e-8, 1.0);
+
+#ifdef USE_BENT_NORMAL
+ /* The bent normal will show the facet look of the mesh. Try to minimize this. */
+ bent_normal = normalize(mix(bent_normal / visibility, normal, visibility * visibility * visibility));
+#endif
+
+ /* Scale by user factor */
+ visibility = pow(visibility, aoFactor);
+}
+
+/* Multibounce approximation base on surface albedo.
+ * Page 78 in the .pdf version. */
+float gtao_multibounce(float visibility, vec3 albedo)
+{
+ /* Median luminance. Because Colored multibounce looks bad. */
+ float lum = albedo.x * 0.3333;
+ lum += albedo.y * 0.3333;
+ lum += albedo.z * 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, vec2 randuv, out vec3 bent_normal)
+{
+#ifdef USE_AO /* Screen Space Occlusion */
+
+ float computed_occlusion;
+ vec3 vnor = mat3(ViewMatrix) * N;
+
+#ifdef USE_BENT_NORMAL
+ gtao(vnor, vpos, randuv, computed_occlusion, bent_normal);
+ bent_normal = mat3(ViewMatrixInverse) * bent_normal;
+#else
+ gtao(vnor, vpos, randuv, computed_occlusion);
+ bent_normal = N;
+#endif
+ return min(computed_occlusion, user_occlusion);
+
+#else /* No added Occlusion. */
+
+ bent_normal = N;
+ return user_occlusion;
+
+#endif
+}
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..b81aae9bcda
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/background_vert.glsl
@@ -0,0 +1,20 @@
+
+in vec2 pos;
+
+out vec3 varposition;
+out vec3 varnormal;
+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);
+ varposition = viewPosition = vec3(pos, -1.0);
+ varnormal = normalize(-varposition);
+}
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..f3f9d8af7f0
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
@@ -0,0 +1,414 @@
+
+#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
+
+uniform mat4 ProjectionMatrix;
+uniform mat4 ViewMatrixInverse;
+uniform vec4 viewvecs[2];
+#ifndef SHADOW_SHADER
+uniform mat4 ViewMatrix;
+#else
+layout(std140) uniform shadow_render_block {
+ mat4 ShadowMatrix[6];
+ mat4 FaceViewMatrix[6];
+ vec4 lampPosition;
+ int layer;
+ float exponent;
+};
+
+flat in int shFace; /* Shadow layer we are rendering to. */
+#define ViewMatrix FaceViewMatrix[shFace]
+#endif
+
+#define cameraForward normalize(ViewMatrixInverse[2].xyz)
+#define cameraPos ViewMatrixInverse[3].xyz
+
+
+/* ------- Structures -------- */
+#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;
+}
+#else
+
+struct Closure {
+ vec3 radiance;
+ float opacity;
+};
+
+#define CLOSURE_DEFAULT Closure(vec3(0.0), 1.0)
+
+Closure closure_mix(Closure cl1, Closure cl2, float fac)
+{
+ Closure cl;
+ cl.radiance = mix(cl1.radiance, cl2.radiance, fac);
+ cl.opacity = mix(cl1.opacity, cl2.opacity, fac);
+ return cl;
+}
+
+Closure closure_add(Closure cl1, Closure cl2)
+{
+ Closure cl;
+ cl.radiance = cl1.radiance + cl2.radiance;
+ cl.opacity = cl1.opacity + cl2.opacity;
+ return cl;
+}
+
+#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
+
+struct LightData {
+ vec4 position_influence; /* w : InfluenceRadius */
+ 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
+
+
+struct ShadowCubeData {
+ vec4 near_far_bias_exp;
+};
+
+/* convenience aliases */
+#define sh_cube_near near_far_bias_exp.x
+#define sh_cube_far near_far_bias_exp.y
+#define sh_cube_bias near_far_bias_exp.z
+#define sh_cube_exp near_far_bias_exp.w
+
+
+struct ShadowMapData {
+ mat4 shadowmat;
+ vec4 near_far_bias;
+};
+
+/* convenience aliases */
+#define sh_map_near near_far_bias.x
+#define sh_map_far near_far_bias.y
+#define sh_map_bias near_far_bias.z
+
+#ifndef MAX_CASCADE_NUM
+#define MAX_CASCADE_NUM 4
+#endif
+
+struct ShadowCascadeData {
+ mat4 shadowmat[MAX_CASCADE_NUM];
+ /* arrays of float are not aligned so use vec4 */
+ vec4 split_distances;
+ vec4 bias;
+};
+
+#define cameraVec ((ProjectionMatrix[3][3] == 0.0) ? normalize(cameraPos - worldPosition) : cameraForward)
+
+/* ------- Convenience functions --------- */
+
+vec3 mul(mat3 m, vec3 v) { return m * v; }
+mat3 mul(mat3 m1, mat3 m2) { return m1 * m2; }
+vec3 transform_point(mat4 m, vec3 v) { return (m * vec4(v, 1.0)).xyz; }
+
+float min_v3(vec3 v) { return min(v.x, min(v.y, v.z)); }
+
+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); }
+
+/* ------- Fast Math ------- */
+
+/* [Drobot2014a] Low Level Optimizations for GCN */
+float fast_sqrt(float x)
+{
+ return intBitsToFloat(0x1fbd1df5 + (floatBitsToInt(x) >> 1));
+}
+
+/* [Eberly2014] GPGPU Programming for Games and Science */
+float fast_acos(float x)
+{
+ float res = -0.156583 * abs(x) + M_PI_2;
+ res *= fast_sqrt(1.0 - abs(x));
+ return (x >= 0) ? res : M_PI - res;
+}
+
+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;
+}
+
+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;
+ }
+}
+
+vec3 get_view_space_from_depth(vec2 uvcoords, float depth)
+{
+ if (ProjectionMatrix[3][3] == 0.0) {
+ return (viewvecs[0].xyz + vec3(uvcoords, 0.0) * viewvecs[1].xyz) * get_view_z_from_depth(depth);
+ }
+ else {
+ return viewvecs[0].xyz + vec3(uvcoords, depth) * viewvecs[1].xyz;
+ }
+}
+
+vec3 get_specular_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);
+}
+
+/* Fresnel */
+vec3 F_schlick(vec3 f0, float cos_theta)
+{
+ float fac = pow(1.0 - cos_theta, 5);
+
+ /* 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);
+
+ /* 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 LTC area lights (not MRP) */
+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 transmition 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));
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl
new file mode 100644
index 00000000000..5ab572e03ea
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl
@@ -0,0 +1,180 @@
+/* Bsdf direct light function */
+/* in other word, how materials react to scene lamps */
+
+/* Naming convention
+ * V View vector (normalized)
+ * N World Normal (normalized)
+ * L Outgoing Light Vector (Surface to Light in World Space) (normalized)
+ * Ldist Distance from surface to the light
+ * W World Pos
+ */
+
+/* ------------ Diffuse ------------- */
+
+float direct_diffuse_point(vec3 N, vec4 l_vector)
+{
+ float dist = l_vector.w;
+ vec3 L = l_vector.xyz / dist;
+ float bsdf = max(0.0, dot(N, L));
+ bsdf /= dist * dist;
+ return bsdf;
+}
+
+/* infinitly far away point source, no decay */
+float direct_diffuse_sun(LightData ld, vec3 N)
+{
+ float bsdf = max(0.0, dot(N, -ld.l_forward));
+ bsdf *= M_1_PI; /* Normalize */
+ return bsdf;
+}
+
+/* From Frostbite PBR Course
+ * Analytical irradiance from a sphere with correct horizon handling
+ * http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf */
+float direct_diffuse_sphere(LightData ld, vec3 N, vec4 l_vector)
+{
+ float dist = l_vector.w;
+ vec3 L = l_vector.xyz / dist;
+ float radius = max(ld.l_sizex, 0.0001);
+ float costheta = clamp(dot(N, L), -0.999, 0.999);
+ float h = min(ld.l_radius / dist , 0.9999);
+ float h2 = h*h;
+ float costheta2 = costheta * costheta;
+ float bsdf;
+
+ if (costheta2 > h2) {
+ bsdf = M_PI * h2 * clamp(costheta, 0.0, 1.0);
+ }
+ else {
+ float sintheta = sqrt(1.0 - costheta2);
+ float x = sqrt(1.0 / h2 - 1.0);
+ float y = -x * (costheta / sintheta);
+ float sinthetasqrty = sintheta * sqrt(1.0 - y * y);
+ bsdf = (costheta * acos(y) - x * sinthetasqrty) * h2 + atan(sinthetasqrty / x);
+ }
+
+ bsdf = max(bsdf, 0.0);
+ bsdf *= M_1_PI2;
+
+ return bsdf;
+}
+
+/* From Frostbite PBR Course
+ * http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf */
+float direct_diffuse_rectangle(LightData ld, vec3 N, vec3 V, vec4 l_vector)
+{
+ 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;
+
+ float bsdf = ltc_evaluate(N, V, mat3(1.0), corners);
+ bsdf *= M_1_2PI;
+ return bsdf;
+}
+
+
+#if 0
+float direct_diffuse_unit_disc(vec3 N, vec3 L)
+{
+
+}
+#endif
+
+/* ----------- GGx ------------ */
+vec3 direct_ggx_point(vec3 N, vec3 V, vec4 l_vector, float roughness, vec3 f0)
+{
+ float dist = l_vector.w;
+ vec3 L = l_vector.xyz / dist;
+ float bsdf = bsdf_ggx(N, L, V, roughness);
+ bsdf /= dist * dist;
+
+ /* Fresnel */
+ float VH = max(dot(V, normalize(V + L)), 0.0);
+ return F_schlick(f0, VH) * bsdf;
+}
+
+vec3 direct_ggx_sun(LightData ld, vec3 N, vec3 V, float roughness, vec3 f0)
+{
+ float bsdf = bsdf_ggx(N, -ld.l_forward, V, roughness);
+ float VH = max(dot(V, normalize(V - ld.l_forward)), 0.0);
+ return F_schlick(f0, VH) * bsdf;
+}
+
+vec3 direct_ggx_sphere(LightData ld, vec3 N, vec3 V, vec4 l_vector, float roughness, vec3 f0)
+{
+ vec3 L = l_vector.xyz / l_vector.w;
+ vec3 spec_dir = get_specular_dominant_dir(N, V, roughness);
+ vec3 P = line_aligned_plane_intersect(vec3(0.0), spec_dir, l_vector.xyz);
+
+ vec3 Px = normalize(P - l_vector.xyz) * ld.l_radius;
+ vec3 Py = cross(Px, L);
+
+ vec2 uv = lut_coords(dot(N, V), sqrt(roughness));
+ vec3 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rgb;
+ vec4 ltc_lut = texture(utilTex, vec3(uv, 0.0)).rgba;
+ mat3 ltc_mat = ltc_matrix(ltc_lut);
+
+// #define HIGHEST_QUALITY
+#ifdef HIGHEST_QUALITY
+ vec3 Pxy1 = normalize( Px + Py) * ld.l_radius;
+ vec3 Pxy2 = normalize(-Px + Py) * ld.l_radius;
+
+ /* counter clockwise */
+ vec3 points[8];
+ points[0] = l_vector.xyz + Px;
+ points[1] = l_vector.xyz - Pxy2;
+ points[2] = l_vector.xyz - Py;
+ points[3] = l_vector.xyz - Pxy1;
+ points[4] = l_vector.xyz - Px;
+ points[5] = l_vector.xyz + Pxy2;
+ points[6] = l_vector.xyz + Py;
+ points[7] = l_vector.xyz + Pxy1;
+ float bsdf = ltc_evaluate_circle(N, V, ltc_mat, points);
+#else
+ vec3 points[4];
+ points[0] = l_vector.xyz + Px;
+ points[1] = l_vector.xyz - Py;
+ points[2] = l_vector.xyz - Px;
+ points[3] = l_vector.xyz + Py;
+ float bsdf = ltc_evaluate(N, V, ltc_mat, points);
+ /* sqrt(pi/2) difference between square and disk area */
+ bsdf *= 1.25331413731;
+#endif
+
+ bsdf *= brdf_lut.b; /* Bsdf intensity */
+ bsdf *= M_1_2PI * M_1_PI;
+
+ vec3 spec = F_area(f0, brdf_lut.xy) * bsdf;
+
+ return spec;
+}
+
+vec3 direct_ggx_rectangle(LightData ld, vec3 N, vec3 V, vec4 l_vector, float roughness, vec3 f0)
+{
+ 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;
+
+ vec2 uv = lut_coords(dot(N, V), sqrt(roughness));
+ vec3 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rgb;
+ vec4 ltc_lut = texture(utilTex, vec3(uv, 0.0)).rgba;
+ mat3 ltc_mat = ltc_matrix(ltc_lut);
+ float bsdf = ltc_evaluate(N, V, ltc_mat, corners);
+ bsdf *= brdf_lut.b; /* Bsdf intensity */
+ bsdf *= M_1_2PI;
+
+ vec3 spec = F_area(f0, brdf_lut.xy) * bsdf;
+
+ return spec;
+}
+
+#if 0
+float direct_ggx_disc(vec3 N, vec3 L)
+{
+
+}
+#endif \ No newline at end of file
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..b8fac61519e
--- /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);
+} \ No newline at end of file
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..3997de7a22d
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl
@@ -0,0 +1,73 @@
+
+uniform sampler1D texHammersley;
+uniform sampler2D texJitter;
+uniform float sampleCount;
+uniform float invSampleCount;
+
+vec2 jitternoise = vec2(0.0);
+
+void setup_noise(void)
+{
+ jitternoise = texture(texJitter, gl_FragCoord.xy / NOISE_SIZE).rg; /* Global variable */
+}
+
+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);
+}
+
+/* -------------- 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(float nsample, float a2, vec3 N, vec3 T, vec3 B)
+{
+ vec3 Xi = hammersley_3d(nsample);
+
+ /* Theta is the aperture angle of the cone */
+ float z = sqrt( (1.0 - Xi.x) / ( 1.0 + a2 * Xi.x - Xi.x ) ); /* cos theta */
+ float r = sqrt( 1.0 - z * z ); /* sin theta */
+ float x = r * Xi.y;
+ float y = r * Xi.z;
+
+ /* Microfacet Normal */
+ vec3 Ht = vec3(x, y, z);
+
+ 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( 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);
+} \ No newline at end of file
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..b50eb481f94
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/default_frag.glsl
@@ -0,0 +1,20 @@
+
+uniform vec3 basecol;
+uniform float metallic;
+uniform float specular;
+uniform float roughness;
+
+out vec4 FragColor;
+
+void main()
+{
+ vec3 dielectric = vec3(0.034) * specular * 2.0;
+ vec3 diffuse = mix(basecol, vec3(0.0), metallic);
+ vec3 f0 = mix(dielectric, basecol, metallic);
+ vec3 radiance = eevee_surface_lit((gl_FrontFacing) ? worldNormal : -worldNormal, diffuse, f0, roughness, 1.0);
+#if defined(USE_ALPHA_BLEND)
+ FragColor = vec4(radiance, 1.0);
+#else
+ FragColor = vec4(radiance, length(viewPosition));
+#endif
+}
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..90af87756f0
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/default_world_frag.glsl
@@ -0,0 +1,9 @@
+
+uniform float backgroundAlpha;
+uniform vec3 color;
+
+out vec4 FragColor;
+
+void main() {
+ FragColor = vec4(color, 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..8e0eefec6e2
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl
@@ -0,0 +1,210 @@
+/* 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;
+
+/* Step Upsample */
+uniform sampler2D baseBuffer; /* Previous accumulation buffer */
+uniform vec2 baseBufferTexelSize;
+uniform float sampleScale;
+
+/* Step Resolve */
+uniform float bloomIntensity;
+
+in vec4 uvcoordsvar;
+
+out vec4 FragColor;
+
+/* -------------- Utils ------------- */
+
+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 = texture(tex, uv + d.xy).rgb;
+ vec3 s2 = texture(tex, uv + d.zy).rgb;
+ vec3 s3 = texture(tex, uv + d.xw).rgb;
+ vec3 s4 = texture(tex, uv + d.zw).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 = texture(tex, uv + d.xy).rgb;
+ s += texture(tex, uv + d.zy).rgb;
+ s += texture(tex, uv + d.xw).rgb;
+ s += texture(tex, uv + d.zw).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 = texture(tex, uv - d.xy).rgb;
+ s += texture(tex, uv - d.wy).rgb * 2;
+ s += texture(tex, uv - d.zy).rgb;
+
+ s += texture(tex, uv + d.zw).rgb * 2;
+ s += texture(tex, uv ).rgb * 4;
+ s += texture(tex, uv + d.xw).rgb * 2;
+
+ s += texture(tex, uv + d.zy).rgb;
+ s += texture(tex, uv + d.wy).rgb * 2;
+ s += texture(tex, uv + d.xy).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 = texture(tex, uv + d.xy).rgb;
+ s += texture(tex, uv + d.zy).rgb;
+ s += texture(tex, uv + d.xw).rgb;
+ s += texture(tex, uv + d.zw).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 = texture(sourceBuffer, uvcoordsvar.xy).rgb;
+ vec3 s1 = texture(sourceBuffer, uvcoordsvar.xy - d.xz).rgb;
+ vec3 s2 = texture(sourceBuffer, uvcoordsvar.xy + d.xz).rgb;
+ vec3 s3 = texture(sourceBuffer, uvcoordsvar.xy - d.zy).rgb;
+ vec3 s4 = texture(sourceBuffer, uvcoordsvar.xy + d.zy).rgb;
+ vec3 m = median(median(s0.rgb, s1, s2), s3, s4);
+#else
+ vec3 s0 = texture(sourceBuffer, uvcoordsvar.xy).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(br, 1e-5);
+
+ /* Clamp to avoid black square artifacts if a pixel goes NaN. */
+ clamp(m, vec3(0.0), vec3(1e20)); /* 1e20 arbitrary. */
+
+ 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 = texture(baseBuffer, uvcoordsvar.xy).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 = texture(baseBuffer, uvcoordsvar.xy);
+ vec3 cout = base.rgb + blur * bloomIntensity;
+ 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
+} \ No newline at end of file
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..2f5143390ce
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl
@@ -0,0 +1,261 @@
+
+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;
+
+#define bokeh_sides bokehParams.x /* Polygon Bokeh shape number of sides */
+#define bokeh_rotation bokehParams.y
+#define bokeh_ratio bokehParams.z
+#define bokeh_maxsize bokehParams.w
+
+uniform vec2 nearFar; /* Near & far view depths values */
+
+/* initial uv coordinate */
+in vec2 uvcoord;
+
+layout(location = 0) out vec4 fragData0;
+layout(location = 1) out vec4 fragData1;
+layout(location = 2) out vec4 fragData2;
+
+#define M_PI 3.1415926535897932384626433832795
+#define M_2PI 6.2831853071795864769252868
+
+/* -------------- Utils ------------- */
+
+/* calculate 4 samples at once */
+float calculate_coc(in float zdepth)
+{
+ float coc = dof_aperturesize * (dof_distance / zdepth - 1.0);
+
+ /* multiply by 1.0 / sensor size to get the normalized size */
+ return coc * dof_invsensorsize;
+}
+
+vec4 calculate_coc(in vec4 zdepth)
+{
+ vec4 coc = dof_aperturesize * (vec4(dof_distance) / zdepth - vec4(1.0));
+
+ /* multiply by 1.0 / sensor size to get the normalized size */
+ return coc * dof_invsensorsize;
+}
+
+float max4(vec4 x)
+{
+ return max(max(x.x, x.y), max(x.z, x.w));
+}
+
+float linear_depth(float z)
+{
+ /* if persp */
+ if (ProjectionMatrix[3][3] == 0.0) {
+ return (nearFar.x * nearFar.y) / (z * (nearFar.x - nearFar.y) + nearFar.y);
+ }
+ else {
+ return (z * 2.0 - 1.0) * nearFar.y;
+ }
+}
+
+vec4 linear_depth(vec4 z)
+{
+ /* if persp */
+ if (ProjectionMatrix[3][3] == 0.0) {
+ return (nearFar.xxxx * nearFar.yyyy) / (z * (nearFar.xxxx - nearFar.yyyy) + nearFar.yyyy);
+ }
+ else {
+ return (z * 2.0 - 1.0) * nearFar.yyyy;
+ }
+}
+
+#define THRESHOLD 0.0
+
+/* ----------- Steps ----------- */
+
+/* Downsample the color buffer to half resolution.
+ * Weight color samples by
+ * Compute maximum CoC for near and far blur. */
+void step_downsample(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;
+
+ /* now we need to write the near-far fields premultiplied by the coc */
+ vec4 near_weights = step(THRESHOLD, coc_near);
+ vec4 far_weights = step(THRESHOLD, coc_far);
+
+ /* now write output to weighted buffers. */
+ fragData0 = color1 * near_weights.x +
+ color2 * near_weights.y +
+ color3 * near_weights.z +
+ color4 * near_weights.w;
+
+ fragData1 = color1 * far_weights.x +
+ color2 * far_weights.y +
+ color3 * far_weights.z +
+ color4 * far_weights.w;
+
+ float norm_near = dot(near_weights, near_weights);
+ float norm_far = dot(far_weights, far_weights);
+
+ if (norm_near > 0.0) {
+ fragData0 /= norm_near;
+ }
+
+ if (norm_far > 0.0) {
+ fragData1 /= norm_far;
+ }
+
+ float max_near_coc = max(max4(coc_near), 0.0);
+ float max_far_coc = max(max4(coc_far), 0.0);
+
+ fragData2 = vec4(max_near_coc, max_far_coc, 0.0, 1.0);
+}
+
+/* coordinate used for calculating radius et al set in geometry shader */
+in vec2 particlecoord;
+flat in vec4 color;
+
+/* accumulate color in the near/far blur buffers */
+void step_scatter(void)
+{
+ /* Early out */
+ float dist_sqrd = dot(particlecoord, particlecoord);
+
+ /* Circle Dof */
+ if (dist_sqrd > 1.0) {
+ discard;
+ }
+
+ /* Regular Polygon Dof */
+ if (bokeh_sides > 0.0) {
+ /* Circle parametrization */
+ float theta = atan(particlecoord.y, particlecoord.x) + bokeh_rotation;
+ float r;
+
+ r = cos(M_PI / bokeh_sides) /
+ (cos(theta - (M_2PI / bokeh_sides) * floor((bokeh_sides * theta + M_PI) / M_2PI)));
+
+ if (dist_sqrd > r * r) {
+ discard;
+ }
+ }
+
+ fragData0 = color;
+}
+
+#define MERGE_THRESHOLD 4.0
+
+uniform sampler2D farBuffer;
+uniform sampler2D nearBuffer;
+
+vec4 upsample_filter_high(sampler2D tex, vec2 uv, vec2 texelSize)
+{
+ /* 9-tap bilinear upsampler (tent filter) */
+ vec4 d = texelSize.xyxy * vec4(1, 1, -1, 0);
+
+ vec4 s;
+ s = texture(tex, uv - d.xy);
+ s += texture(tex, uv - d.wy) * 2;
+ s += texture(tex, uv - d.zy);
+
+ s += texture(tex, uv + d.zw) * 2;
+ s += texture(tex, uv ) * 4;
+ s += texture(tex, uv + d.xw) * 2;
+
+ s += texture(tex, uv + d.zy);
+ s += texture(tex, uv + d.wy) * 2;
+ s += texture(tex, uv + d.xy);
+
+ return s * (1.0 / 16.0);
+}
+
+vec4 upsample_filter(sampler2D tex, vec2 uv, vec2 texelSize)
+{
+ /* 4-tap bilinear upsampler */
+ vec4 d = texelSize.xyxy * vec4(-1, -1, +1, +1) * 0.5;
+
+ vec4 s;
+ s = texture(tex, uv + d.xy);
+ s += texture(tex, uv + d.zy);
+ s += texture(tex, uv + d.xw);
+ s += texture(tex, uv + d.zw);
+
+ return s * (1.0 / 4.0);
+}
+
+/* Combine the Far and Near color buffers */
+void step_resolve(void)
+{
+ /* Recompute Near / Far CoC */
+ float depth = texture(depthBuffer, uvcoord).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);
+
+ /* Recompute Near / Far CoC */
+ vec2 texelSize = 1.0 / vec2(textureSize(farBuffer, 0));
+ vec4 srccolor = texture(colorBuffer, uvcoord);
+ vec4 farcolor = upsample_filter_high(farBuffer, uvcoord, texelSize);
+ vec4 nearcolor = upsample_filter_high(nearBuffer, uvcoord, texelSize);
+
+ float farweight = farcolor.a;
+ if (farweight > 0.0)
+ farcolor /= farweight;
+
+ float mixfac = smoothstep(1.0, MERGE_THRESHOLD, coc_far);
+
+ farweight = mix(1.0, farweight, mixfac);
+
+ float nearweight = nearcolor.a;
+ if (nearweight > 0.0) {
+ nearcolor /= nearweight;
+ }
+
+ if (coc_near > 1.0) {
+ mixfac = smoothstep(1.0, MERGE_THRESHOLD, coc_near);
+ fragData0 = mix(srccolor, nearcolor, mixfac);
+ }
+ else {
+ float totalweight = nearweight + farweight;
+ vec4 finalcolor = mix(srccolor, farcolor, mixfac);
+ fragData0 = mix(finalcolor, nearcolor, nearweight / totalweight);
+ }
+}
+
+void main()
+{
+#ifdef STEP_DOWNSAMPLE
+ step_downsample();
+#elif defined(STEP_SCATTER)
+ step_scatter();
+#elif defined(STEP_RESOLVE)
+ step_resolve();
+#endif
+}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_geom.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_geom.glsl
new file mode 100644
index 00000000000..1c774885a32
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_geom.glsl
@@ -0,0 +1,55 @@
+uniform ivec2 targetBufferSize;
+
+uniform vec2 layerSelection;
+
+uniform sampler2D colorBuffer;
+uniform sampler2D cocBuffer;
+
+layout(points) in;
+layout(triangle_strip, max_vertices = 4) out;
+
+#define POS gl_in[0].gl_Position
+
+in vec2 uvcoord[];
+out vec2 particlecoord;
+flat out vec4 color;
+
+#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(targetBufferSize.x, targetBufferSize.y);
+
+ color = colortex;
+
+ gl_Position = POS + vec4(-offset_far.x, -offset_far.y, 0.0, 0.0);
+ 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);
+ EmitVertex();
+
+ gl_Position = POS + vec4(offset_far.x, -offset_far.y, 0.0, 0.0);
+ 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);
+ EmitVertex();
+
+ EndPrimitive();
+}
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..0f5c5e5b16b
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_vert.glsl
@@ -0,0 +1,99 @@
+
+in vec2 pos;
+in vec2 uvs;
+
+uniform vec2 layerSelection;
+
+uniform vec4 bokehParams;
+
+#define bokeh_sides bokehParams.x /* Polygon Bokeh shape number of sides */
+#define bokeh_rotation bokehParams.y
+#define bokeh_ratio bokehParams.z
+#define bokeh_maxsize bokehParams.w
+
+uniform sampler2D colorBuffer;
+uniform sampler2D cocBuffer;
+
+flat out vec4 color;
+out vec2 particlecoord;
+
+#define M_PI 3.1415926535897932384626433832795
+
+/* geometry shading pass, calculate a texture coordinate based on the indexed id */
+void step_scatter()
+{
+ ivec2 tex_size = textureSize(cocBuffer, 0);
+ vec2 texel_size = 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;
+
+ float coc = dot(layerSelection, texelFetch(cocBuffer, texelco, 0).rg);
+
+ /* Clamp to max size for performance */
+ coc = min(coc, bokeh_maxsize);
+
+ if (coc >= 1.0) {
+ color = texelFetch(colorBuffer, texelco, 0);
+ /* find the area the pixel will cover and divide the color by it */
+ float alpha = 1.0 / (coc * coc * M_PI);
+ color *= alpha;
+ color.a = alpha;
+ }
+ else {
+ color = vec4(0.0);
+ }
+
+ /* 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;
+}
+
+out vec2 uvcoord;
+
+void passthrough()
+{
+ uvcoord = uvs;
+ gl_Position = vec4(pos, 0.0, 1.0);
+}
+
+void main()
+{
+#if defined(STEP_DOWNSAMPLE)
+ passthrough();
+#elif defined(STEP_SCATTER)
+ step_scatter();
+#elif defined(STEP_RESOLVE)
+ passthrough();
+#endif
+} \ No newline at end of file
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..9f81206070b
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl
@@ -0,0 +1,66 @@
+/**
+ * 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/
+ **/
+
+uniform sampler2D depthBuffer;
+
+out vec4 FragMinMax;
+
+vec2 sampleLowerMip(ivec2 texel)
+{
+#ifdef INPUT_DEPTH
+ return texelFetch(depthBuffer, texel, 0).rr;
+#else
+ return texelFetch(depthBuffer, texel, 0).rg;
+#endif
+}
+
+void minmax(inout vec2 val[2])
+{
+ val[0].x = min(val[0].x, val[1].x);
+ val[0].y = max(val[0].y, val[1].y);
+}
+
+void main()
+{
+ vec2 val[2];
+ ivec2 texelPos = ivec2(gl_FragCoord.xy);
+ ivec2 mipsize = textureSize(depthBuffer, 0);
+#ifndef COPY_DEPTH
+ texelPos *= 2;
+#endif
+
+ val[0] = sampleLowerMip(texelPos);
+#ifndef COPY_DEPTH
+ val[1] = sampleLowerMip(texelPos + ivec2(1, 0));
+ minmax(val);
+ val[1] = sampleLowerMip(texelPos + ivec2(1, 1));
+ minmax(val);
+ val[1] = sampleLowerMip(texelPos + ivec2(0, 1));
+ minmax(val);
+
+ /* if we are reducing an odd-width texture then fetch the edge texels */
+ if (((mipsize.x & 1) != 0) && (int(gl_FragCoord.x) == mipsize.x-3)) {
+ /* if both edges are odd, fetch the top-left corner texel */
+ if (((mipsize.y & 1) != 0) && (int(gl_FragCoord.y) == mipsize.y-3)) {
+ val[1] = sampleLowerMip(texelPos + ivec2(-1, -1));
+ minmax(val);
+ }
+ val[1] = sampleLowerMip(texelPos + ivec2(0, -1));
+ minmax(val);
+ val[1] = sampleLowerMip(texelPos + ivec2(1, -1));
+ minmax(val);
+ }
+ /* if we are reducing an odd-height texture then fetch the edge texels */
+ else if (((mipsize.y & 1) != 0) && (int(gl_FragCoord.y) == mipsize.y-3)) {
+ val[1] = sampleLowerMip(texelPos + ivec2(0, -1));
+ minmax(val);
+ val[1] = sampleLowerMip(texelPos + ivec2(1, -1));
+ minmax(val);
+ }
+#endif
+
+ FragMinMax = vec4(val[0], 0.0, 1.0);
+} \ No newline at end of file
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..045fcd11fae
--- /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, 0.0, 0.0, 1.0);
+ for (int j = 0; j < samples && j < MAX_SAMPLE; j++) {
+ FragColor += texture(colorBuffer, uvcoordsvar.xy + motion * i) * inv_samples;
+ i += inc;
+ }
+}
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..95e7af41398
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl
@@ -0,0 +1,141 @@
+
+uniform sampler2D 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, uvs).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, cell_co + ofs.xx, 0).rgb;
+ ir.shcoefs[1] = texelFetch(irradianceGrid, cell_co + ofs.yx, 0).rgb;
+ ir.shcoefs[2] = texelFetch(irradianceGrid, cell_co + ofs.zx, 0).rgb;
+ ir.shcoefs[3] = texelFetch(irradianceGrid, cell_co + ofs.xy, 0).rgb;
+ ir.shcoefs[4] = texelFetch(irradianceGrid, cell_co + ofs.yy, 0).rgb;
+ ir.shcoefs[5] = texelFetch(irradianceGrid, cell_co + ofs.zy, 0).rgb;
+ ir.shcoefs[6] = texelFetch(irradianceGrid, cell_co + ofs.xz, 0).rgb;
+ ir.shcoefs[7] = texelFetch(irradianceGrid, cell_co + ofs.yz, 0).rgb;
+ ir.shcoefs[8] = texelFetch(irradianceGrid, cell_co + ofs.zz, 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] = texelFetch(irradianceGrid, cell_co + ivec2(0, is_negative.x), 0).rgb;
+ ir.cubesides[1] = texelFetch(irradianceGrid, cell_co + ivec2(1, is_negative.y), 0).rgb;
+ ir.cubesides[2] = texelFetch(irradianceGrid, cell_co + ivec2(2, is_negative.z), 0).rgb;
+
+#endif
+
+ return ir;
+}
+
+/* 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..061719b5685
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl
@@ -0,0 +1,195 @@
+
+uniform sampler2DArray shadowCubes;
+uniform sampler2DArrayShadow shadowCascades;
+
+layout(std140) uniform shadow_block {
+ ShadowCubeData shadows_cube_data[MAX_SHADOW_CUBE];
+ ShadowMapData shadows_map_data[MAX_SHADOW_MAP];
+ ShadowCascadeData shadows_cascade_data[MAX_SHADOW_CASCADE];
+};
+
+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];
+};
+
+layout(std140) uniform light_block {
+ LightData lights_data[MAX_LIGHT];
+};
+
+/* type */
+#define POINT 0.0
+#define SUN 1.0
+#define SPOT 2.0
+#define HEMI 3.0
+#define AREA 4.0
+
+float shadow_cubemap(float shid, vec4 l_vector)
+{
+ ShadowCubeData scd = shadows_cube_data[int(shid)];
+
+ vec3 cubevec = -l_vector.xyz / l_vector.w;
+ float dist = l_vector.w - scd.sh_cube_bias;
+
+ float z = texture_octahedron(shadowCubes, vec4(cubevec, shid)).r;
+
+ float esm_test = saturate(exp(scd.sh_cube_exp * (z - dist)));
+ // float sh_test = step(0, z - dist);
+
+ return esm_test;
+}
+
+float shadow_cascade(float shid, vec3 W)
+{
+ /* Shadow Cascade */
+ shid -= (MAX_SHADOW_CUBE + MAX_SHADOW_MAP);
+ ShadowCascadeData smd = shadows_cascade_data[int(shid)];
+
+ /* Finding Cascade index */
+ vec4 z = vec4(-dot(cameraPos - W, cameraForward));
+ vec4 comp = step(z, smd.split_distances);
+ float cascade = dot(comp, comp);
+ mat4 shadowmat;
+ float bias;
+
+ /* Manual Unrolling of a loop for better performance.
+ * Doing fetch directly with cascade index leads to
+ * major performance impact. (0.27ms -> 10.0ms for 1 light) */
+ if (cascade == 0.0) {
+ shadowmat = smd.shadowmat[0];
+ bias = smd.bias[0];
+ }
+ else if (cascade == 1.0) {
+ shadowmat = smd.shadowmat[1];
+ bias = smd.bias[1];
+ }
+ else if (cascade == 2.0) {
+ shadowmat = smd.shadowmat[2];
+ bias = smd.bias[2];
+ }
+ else {
+ shadowmat = smd.shadowmat[3];
+ bias = smd.bias[3];
+ }
+
+ vec4 shpos = shadowmat * vec4(W, 1.0);
+ shpos.z -= bias * shpos.w;
+ shpos.xyz /= shpos.w;
+
+ return texture(shadowCascades, vec4(shpos.xy, shid * float(MAX_CASCADE_NUM) + cascade, shpos.z));
+}
+
+float light_visibility(LightData ld, vec3 W, vec4 l_vector)
+{
+ float vis = 1.0;
+
+ if (ld.l_type == SPOT) {
+ 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 = 1.0 / sqrt(1.0 + x * x + y * y);
+
+ float spotmask = smoothstep(0.0, 1.0, (ellipse - ld.l_spot_size) / ld.l_spot_blend);
+
+ vis *= spotmask;
+ vis *= step(0.0, -dot(l_vector.xyz, ld.l_forward));
+ }
+ else if (ld.l_type == AREA) {
+ vis *= step(0.0, -dot(l_vector.xyz, ld.l_forward));
+ }
+
+#if !defined(VOLUMETRICS) || defined(VOLUME_SHADOW)
+ /* shadowing */
+ if (ld.l_shadowid >= (MAX_SHADOW_MAP + MAX_SHADOW_CUBE)) {
+ vis *= shadow_cascade(ld.l_shadowid, W);
+ }
+ else if (ld.l_shadowid >= 0.0) {
+ vis *= shadow_cubemap(ld.l_shadowid, l_vector);
+ }
+#endif
+
+ return vis;
+}
+
+float light_diffuse(LightData ld, vec3 N, vec3 V, vec4 l_vector)
+{
+#ifdef USE_LTC
+ if (ld.l_type == SUN) {
+ /* TODO disk area light */
+ return direct_diffuse_sun(ld, N);
+ }
+ else if (ld.l_type == AREA) {
+ return direct_diffuse_rectangle(ld, N, V, l_vector);
+ }
+ else {
+ return direct_diffuse_sphere(ld, N, l_vector);
+ }
+#else
+ if (ld.l_type == SUN) {
+ return direct_diffuse_sun(ld, N, V);
+ }
+ else {
+ return direct_diffuse_point(N, l_vector);
+ }
+#endif
+}
+
+vec3 light_specular(LightData ld, vec3 N, vec3 V, vec4 l_vector, float roughness, vec3 f0)
+{
+#ifdef USE_LTC
+ if (ld.l_type == SUN) {
+ /* TODO disk area light */
+ return direct_ggx_sun(ld, N, V, roughness, f0);
+ }
+ else if (ld.l_type == AREA) {
+ return direct_ggx_rectangle(ld, N, V, l_vector, roughness, f0);
+ }
+ else {
+ return direct_ggx_sphere(ld, N, V, l_vector, roughness, f0);
+ }
+#else
+ if (ld.l_type == SUN) {
+ return direct_ggx_sun(ld, N, V, roughness, f0);
+ }
+ else {
+ return direct_ggx_point(N, V, l_vector, roughness, f0);
+ }
+#endif
+}
+
+#ifdef HAIR_SHADER
+void light_hair_common(
+ LightData ld, vec3 N, vec3 V, vec4 l_vector, vec3 norm_view,
+ out float occlu_trans, out float occlu,
+ out vec3 norm_lamp, out vec3 view_vec)
+{
+ const float transmission = 0.3; /* Uniform internal scattering factor */
+
+ vec3 lamp_vec;
+
+ if (ld.l_type == SUN || ld.l_type == AREA) {
+ lamp_vec = ld.l_forward;
+ }
+ else {
+ lamp_vec = -l_vector.xyz;
+ }
+
+ norm_lamp = cross(lamp_vec, N);
+ norm_lamp = normalize(cross(N, norm_lamp)); /* Normal facing lamp */
+
+ /* Rotate view vector onto the cross(tangent, light) plane */
+ view_vec = normalize(norm_lamp * dot(norm_view, V) + N * dot(N, V));
+
+ occlu = (dot(norm_view, norm_lamp) * 0.5 + 0.5);
+ occlu_trans = transmission + (occlu * (1.0 - transmission)); /* Includes transmission component */
+}
+#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..fc0b5b9548b
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl
@@ -0,0 +1,15 @@
+
+flat in int pid;
+in vec3 worldNormal;
+in vec3 worldPosition;
+
+out vec4 FragColor;
+
+void main()
+{
+ vec3 V = (ProjectionMatrix[3][3] == 0.0) /* if perspective */
+ ? normalize(cameraPos - worldPosition)
+ : cameraForward;
+ vec3 N = normalize(worldNormal);
+ FragColor = vec4(textureLod_octahedron(probeCubes, vec4(reflect(-V, N), pid), 0.0, lodCubeMax).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..b943a59feeb
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl
@@ -0,0 +1,22 @@
+
+in vec3 pos;
+in vec3 nor;
+
+/* Instance attrib */
+in int probe_id;
+in vec3 probe_location;
+in float sphere_size;
+
+uniform mat4 ViewProjectionMatrix;
+
+flat out int pid;
+out vec3 worldNormal;
+out vec3 worldPosition;
+
+void main()
+{
+ pid = probe_id;
+ worldPosition = pos * 0.1 * sphere_size + probe_location;
+ gl_Position = ViewProjectionMatrix * vec4(worldPosition, 1.0);
+ worldNormal = normalize(nor);
+} \ No newline at end of file
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..0b97548c8df
--- /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;
+
+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 * 2.0;
+ uvs -= 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 = vec4(out_radiance / weight, 1.0);
+#endif
+} \ No newline at end of file
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..33714c5293c
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl
@@ -0,0 +1,86 @@
+
+uniform samplerCube probeHdr;
+uniform float roughnessSquared;
+uniform float texelSize;
+uniform float lodFactor;
+uniform float lodMax;
+uniform float paddingSize;
+
+in vec3 worldPosition;
+
+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;
+}
+
+void main() {
+ vec2 uvs = gl_FragCoord.xy * texelSize;
+
+ /* Add a N pixel border to ensure filtering is correct
+ * for N mipmap levels. */
+ uvs += uvs * texelSize * paddingSize * 2.0;
+ uvs -= 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);
+
+ 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) ;
+
+ out_radiance += textureLod(probeHdr, L, lod).rgb * NL;
+ weight += NL;
+ }
+ }
+
+ FragColor = vec4(out_radiance / weight, 1.0);
+} \ No newline at end of file
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..222d272da72
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_geom.glsl
@@ -0,0 +1,33 @@
+
+layout(triangles) in;
+layout(triangle_strip, max_vertices=3) out;
+
+uniform int Layer;
+
+in vec4 vPos[];
+flat in int face[];
+
+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() {
+ int f = face[0];
+ gl_Layer = Layer + f;
+
+ for (int v = 0; v < 3; ++v) {
+ gl_Position = vPos[v];
+ worldPosition = x_axis[f] * vPos[v].x + y_axis[f] * vPos[v].y + maj_axes[f];
+#ifdef ATTRIB
+ pass_attrib(v);
+#endif
+ EmitVertex();
+ }
+
+ EndPrimitive();
+} \ No newline at end of file
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..d333ad34bb0
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_frag.glsl
@@ -0,0 +1,11 @@
+
+flat in int cellOffset;
+in vec3 worldNormal;
+
+out vec4 FragColor;
+
+void main()
+{
+ IrradianceData ir_data = load_irradiance_cell(cellOffset, worldNormal);
+ FragColor = vec4(compute_irradiance(worldNormal, 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..121859c98f1
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl
@@ -0,0 +1,35 @@
+
+in vec3 pos;
+in vec3 nor;
+
+uniform mat4 ViewProjectionMatrix;
+
+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;
+
+flat out int cellOffset;
+out vec3 worldNormal;
+
+void main()
+{
+ vec3 ls_cell_location;
+ /* Keep in sync with update_irradiance_probe */
+ ls_cell_location.z = float(gl_InstanceID % grid_resolution.z);
+ ls_cell_location.y = float((gl_InstanceID / grid_resolution.z) % grid_resolution.y);
+ ls_cell_location.x = float(gl_InstanceID / (grid_resolution.z * grid_resolution.y));
+
+ cellOffset = offset + gl_InstanceID;
+
+ 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(pos * 0.02 * sphere_size + ws_cell_location, 1.0);
+ worldNormal = normalize(nor);
+} \ No newline at end of file
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..32da31339d1
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
@@ -0,0 +1,245 @@
+/* ----------- Uniforms --------- */
+
+uniform sampler2DArray probePlanars;
+uniform float lodPlanarMax;
+
+uniform sampler2DArray probeCubes;
+uniform float lodCubeMax;
+
+/* ----------- 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 */
+};
+
+#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;
+ vec4 ws_increment_z;
+};
+
+#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_increment_x ws_increment_x_atten_bias.xyz
+#define g_increment_y ws_increment_y.xyz
+#define g_increment_z ws_increment_z.xyz
+#define g_resolution resolution_offset.xyz
+#define g_offset resolution_offset.w
+
+/* ----------- Functions --------- */
+
+float probe_attenuation_cube(CubeData pd, vec3 W)
+{
+ vec3 localpos = transform_point(pd.influencemat, W);
+
+ float fac;
+ if (pd.p_atten_type == PROBE_ATTENUATION_BOX) {
+ vec3 axes_fac = saturate(pd.p_atten_fac - pd.p_atten_fac * abs(localpos));
+ fac = min_v3(axes_fac);
+ }
+ else {
+ fac = saturate(pd.p_atten_fac - pd.p_atten_fac * length(localpos));
+ }
+
+ return fac;
+}
+
+float probe_attenuation_planar(PlanarData pd, vec3 W, vec3 N)
+{
+ /* 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);
+ fac *= step(2.0, dot(step(pd.pl_clip_edges, dist_to_clip.xxyy), vec2(-1.0, 1.0).xyxy)); /* compare and add all tests */
+
+ return fac;
+}
+
+float probe_attenuation_grid(GridData gd, vec3 W, out vec3 localpos)
+{
+ localpos = transform_point(gd.localmat, W);
+
+ float fade = min(1.0, min_v3(1.0 - abs(localpos)));
+ return saturate(fade * gd.g_atten_scale + gd.g_atten_bias);
+}
+
+vec3 probe_evaluate_cube(float id, CubeData cd, vec3 W, vec3 R, float roughness)
+{
+ /* Correct reflection ray using parallax volume intersection. */
+ vec3 localpos = transform_point(cd.parallaxmat, W);
+ vec3 localray = mat3(cd.parallaxmat) * R;
+
+ float dist;
+ if (cd.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 - cd.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, id), roughness * lodCubeMax, lodCubeMax).rgb;
+}
+
+vec3 probe_evaluate_world_spec(vec3 R, float roughness)
+{
+ return textureLod_octahedron(probeCubes, vec4(R, 0.0), roughness * lodCubeMax, lodCubeMax).rgb;
+}
+
+vec3 probe_evaluate_planar(
+ float id, PlanarData pd, vec3 W, vec3 N, vec3 V,
+ float rand, vec3 camera_pos, float roughness,
+ inout float fade)
+{
+ /* Sample reflection depth. */
+ vec4 refco = pd.reflectionmat * vec4(W, 1.0);
+ refco.xy /= refco.w;
+ float ref_depth = textureLod(probePlanars, vec3(refco.xy, id), 0.0).a;
+
+ /* Find view vector / reflection plane intersection. (dist_to_plane is negative) */
+ float dist_to_plane = line_plane_intersect_dist(camera_pos, V, pd.pl_plane_eq);
+ vec3 point_on_plane = camera_pos + V * dist_to_plane;
+
+ /* How far the pixel is from the plane. */
+ ref_depth = ref_depth + dist_to_plane;
+
+ /* 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. */
+ refco = pd.reflectionmat * vec4(ref_pos, 1.0);
+ refco.xy /= refco.w;
+
+ /* Distance to roughness */
+ float linear_roughness = sqrt(roughness);
+ float distance_roughness = min(linear_roughness, ref_depth * linear_roughness);
+ linear_roughness = mix(distance_roughness, linear_roughness, linear_roughness);
+
+ /* Decrease influence for high roughness */
+ fade *= saturate((1.0 - linear_roughness) * 5.0 - 2.0);
+
+ float lod = linear_roughness * 2.5 * lodPlanarMax;
+ vec3 sample = textureLod(probePlanars, vec3(refco.xy, id), lod).rgb;
+
+ /* Use a second sample randomly rotated to blur out the lowres aspect */
+ vec2 rot_sample = (1.0 / vec2(textureSize(probePlanars, 0).xy)) * vec2(cos(rand * M_2PI), sin(rand * M_2PI)) * lod;
+ sample += textureLod(probePlanars, vec3(refco.xy + rot_sample, id), lod).rgb;
+ sample *= 0.5;
+
+ return sample;
+}
+
+#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(cell_cos);
+ 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;
+ // vec3 ws_light = normalize(ws_point_to_cell);
+
+ vec3 trilinear = mix(1 - trilinear_weight, trilinear_weight, offset);
+ float weight = trilinear.x * trilinear.y * trilinear.z;
+
+ /* Smooth backface test */
+ // weight *= sqrt(max(0.002, dot(ws_light, N)));
+
+ /* 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..2cb43336ace
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_frag.glsl
@@ -0,0 +1,29 @@
+
+uniform int probeIdx;
+
+layout(std140) uniform planar_block {
+ PlanarData planars_data[MAX_PLANAR];
+};
+
+in vec3 worldPosition;
+
+out vec4 FragColor;
+
+void main()
+{
+ PlanarData pd = planars_data[probeIdx];
+
+ /* Fancy fast clipping calculation */
+ vec2 dist_to_clip;
+ dist_to_clip.x = dot(pd.pl_clip_pos_x, worldPosition);
+ dist_to_clip.y = dot(pd.pl_clip_pos_y, worldPosition);
+ float fac = dot(step(pd.pl_clip_edges, dist_to_clip.xxyy), vec2(-1.0, 1.0).xyxy); /* compare and add all tests */
+
+ if (fac != 2.0) {
+ discard;
+ }
+
+ vec4 refco = pd.reflectionmat * vec4(worldPosition, 1.0);
+ refco.xy /= refco.w;
+ FragColor = vec4(textureLod(probePlanars, vec3(refco.xy, 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..3c620982273
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl
@@ -0,0 +1,13 @@
+
+in vec3 pos;
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat4 ModelMatrix;
+
+out vec3 worldPosition;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ worldPosition = (ModelMatrix * vec4(pos, 1.0)).xyz;
+} \ No newline at end of file
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..fa70fb5590f
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl
@@ -0,0 +1,27 @@
+/**
+ * Simple downsample shader. Takes the average of the 4 texels of lower mip.
+ **/
+
+uniform sampler2DArray source;
+uniform vec2 texelSize;
+
+in vec2 uvs;
+flat in float layer;
+
+out vec4 FragColor;
+
+void main()
+{
+ /* Reconstructing Target uvs like this avoid missing pixels */
+ vec2 uvs = floor(gl_FragCoord.xy) * 2.0 * texelSize + texelSize;
+
+ /* Downsample with a 4x4 box filter */
+ vec4 d = texelSize.xyxy * vec4(-1, -1, +1, +1);
+
+ FragColor = texture(source, vec3(uvs + d.xy, layer)).rgba;
+ FragColor += texture(source, vec3(uvs + d.zy, layer)).rgba;
+ FragColor += texture(source, vec3(uvs + d.xw, layer)).rgba;
+ FragColor += texture(source, vec3(uvs + d.zw, layer)).rgba;
+
+ FragColor /= 4.0;
+} \ No newline at end of file
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..40b04c986f3
--- /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, 0.0);
+ EmitVertex();
+
+ gl_Position = vec4(vPos[1], 0.0, 0.0);
+ EmitVertex();
+
+ gl_Position = vec4(vPos[2], 0.0, 0.0);
+ EmitVertex();
+
+ EndPrimitive();
+} \ No newline at end of file
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..ac4e3da4158
--- /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;
+} \ No newline at end of file
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..f5077d52845
--- /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;
+} \ No newline at end of file
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..1cfc00ef8d7
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
@@ -0,0 +1,489 @@
+
+uniform int light_count;
+uniform int probe_count;
+uniform int grid_count;
+uniform int planar_count;
+
+uniform bool specToggle;
+
+#ifndef UTIL_TEX
+#define UTIL_TEX
+uniform sampler2DArray utilTex;
+#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
+
+/* ----------- default ----------- */
+
+vec3 eevee_surface_lit(vec3 N, vec3 albedo, vec3 f0, float roughness, float ao)
+{
+ /* Zero length vectors cause issues, see: T51979. */
+#if 0
+ N = normalize(N);
+#else
+ {
+ float len = length(N);
+ if (isnan(len)) {
+ return vec3(0.0);
+ }
+ N /= len;
+ }
+#endif
+
+ roughness = clamp(roughness, 1e-8, 0.9999);
+ float roughnessSquared = roughness * roughness;
+
+ vec3 V = cameraVec;
+
+ vec4 rand = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0));
+
+ /* ---------------- SCENE LAMPS LIGHTING ----------------- */
+
+#ifdef HAIR_SHADER
+ vec3 norm_view = cross(V, N);
+ norm_view = normalize(cross(norm_view, N)); /* Normal facing view */
+#endif
+
+ vec3 diff = vec3(0.0);
+ vec3 spec = vec3(0.0);
+ for (int i = 0; i < MAX_LIGHT && i < light_count; ++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);
+
+ vec3 l_color_vis = ld.l_color * light_visibility(ld, worldPosition, l_vector);
+
+#ifdef HAIR_SHADER
+ vec3 norm_lamp, view_vec;
+ float occlu_trans, occlu;
+ light_hair_common(ld, N, V, l_vector, norm_view, occlu_trans, occlu, norm_lamp, view_vec);
+
+ diff += l_color_vis * light_diffuse(ld, -norm_lamp, V, l_vector) * occlu_trans;
+ spec += l_color_vis * light_specular(ld, N, view_vec, l_vector, roughnessSquared, f0) * occlu;
+#else
+ diff += l_color_vis * light_diffuse(ld, N, V, l_vector);
+ spec += l_color_vis * light_specular(ld, N, V, l_vector, roughnessSquared, f0);
+#endif
+ }
+
+ /* Accumulate outgoing radiance */
+ vec3 out_light = diff * albedo + spec * float(specToggle);
+
+#ifdef HAIR_SHADER
+ N = -norm_view;
+#endif
+
+ /* ---------------- SPECULAR ENVIRONMENT LIGHTING ----------------- */
+
+ /* Accumulate light from all sources until accumulator is full. Then apply Occlusion and BRDF. */
+ vec4 spec_accum = vec4(0.0);
+
+ /* Planar Reflections */
+ for (int i = 0; i < MAX_PLANAR && i < planar_count && spec_accum.a < 0.999; ++i) {
+ PlanarData pd = planars_data[i];
+
+ float fade = probe_attenuation_planar(pd, worldPosition, N);
+
+ if (fade > 0.0) {
+ vec3 spec = probe_evaluate_planar(float(i), pd, worldPosition, N, V, rand.r, cameraPos, roughness, fade);
+ accumulate_light(spec, fade, spec_accum);
+ }
+ }
+
+ /* Specular probes */
+ vec3 spec_dir = get_specular_dominant_dir(N, V, roughnessSquared);
+
+ /* Starts at 1 because 0 is world probe */
+ for (int i = 1; i < MAX_PROBE && i < probe_count && spec_accum.a < 0.999; ++i) {
+ CubeData cd = probes_data[i];
+
+ float fade = probe_attenuation_cube(cd, worldPosition);
+
+ if (fade > 0.0) {
+ vec3 spec = probe_evaluate_cube(float(i), cd, worldPosition, spec_dir, roughness);
+ accumulate_light(spec, fade, spec_accum);
+ }
+ }
+
+ /* World Specular */
+ if (spec_accum.a < 0.999) {
+ vec3 spec = probe_evaluate_world_spec(spec_dir, roughness);
+ accumulate_light(spec, 1.0, spec_accum);
+ }
+
+ /* Ambient Occlusion */
+ vec3 bent_normal;
+ float final_ao = occlusion_compute(N, viewPosition, ao, rand.rg, bent_normal);
+
+ /* Get Brdf intensity */
+ vec2 uv = lut_coords(dot(N, V), roughness);
+ vec2 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rg;
+
+ out_light += spec_accum.rgb * F_ibl(f0, brdf_lut) * specular_occlusion(dot(N, V), final_ao, roughness) * float(specToggle);
+
+ /* ---------------- DIFFUSE ENVIRONMENT LIGHTING ----------------- */
+
+ /* Accumulate light from all sources until accumulator is full. Then apply Occlusion and BRDF. */
+ vec4 diff_accum = vec4(0.0);
+
+ /* Start at 1 because 0 is world irradiance */
+ for (int i = 1; i < MAX_GRID && i < grid_count && diff_accum.a < 0.999; ++i) {
+ GridData gd = grids_data[i];
+
+ vec3 localpos;
+ float fade = probe_attenuation_grid(gd, 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 && grid_count > 0) {
+ vec3 diff = probe_evaluate_world_diff(bent_normal);
+ accumulate_light(diff, 1.0, diff_accum);
+ }
+
+ out_light += diff_accum.rgb * albedo * gtao_multibounce(final_ao, albedo);
+
+ return out_light;
+}
+
+/* ----------- CLEAR COAT ----------- */
+
+vec3 eevee_surface_clearcoat_lit(
+ vec3 N, vec3 albedo, vec3 f0, float roughness,
+ vec3 C_N, float C_intensity, float C_roughness, /* Clearcoat params */
+ float ao)
+{
+ roughness = clamp(roughness, 1e-8, 0.9999);
+ float roughnessSquared = roughness * roughness;
+ C_roughness = clamp(C_roughness, 1e-8, 0.9999);
+ float C_roughnessSquared = C_roughness * C_roughness;
+
+ vec3 V = cameraVec;
+ N = normalize(N);
+ C_N = normalize(C_N);
+
+ vec4 rand = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0));
+
+ /* ---------------- SCENE LAMPS LIGHTING ----------------- */
+
+#ifdef HAIR_SHADER
+ vec3 norm_view = cross(V, N);
+ norm_view = normalize(cross(norm_view, N)); /* Normal facing view */
+#endif
+
+ vec3 diff = vec3(0.0);
+ vec3 spec = vec3(0.0);
+ for (int i = 0; i < MAX_LIGHT && i < light_count; ++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);
+
+ vec3 l_color_vis = ld.l_color * light_visibility(ld, worldPosition, l_vector);
+
+#ifdef HAIR_SHADER
+ vec3 norm_lamp, view_vec;
+ float occlu_trans, occlu;
+ light_hair_common(ld, N, V, l_vector, norm_view, occlu_trans, occlu, norm_lamp, view_vec);
+
+ diff += l_color_vis * light_diffuse(ld, -norm_lamp, V, l_vector) * occlu_trans;
+ spec += l_color_vis * light_specular(ld, N, view_vec, l_vector, roughnessSquared, f0) * occlu;
+ spec += l_color_vis * light_specular(ld, C_N, view_vec, l_vector, C_roughnessSquared, f0) * C_intensity * occlu;
+#else
+ diff += l_color_vis * light_diffuse(ld, N, V, l_vector);
+ spec += l_color_vis * light_specular(ld, N, V, l_vector, roughnessSquared, f0);
+ spec += l_color_vis * light_specular(ld, C_N, V, l_vector, C_roughnessSquared, f0) * C_intensity;
+#endif
+ }
+
+ /* Accumulate outgoing radiance */
+ vec3 out_light = diff * albedo + spec * float(specToggle);
+
+#ifdef HAIR_SHADER
+ N = -norm_view;
+#endif
+
+ /* ---------------- SPECULAR ENVIRONMENT LIGHTING ----------------- */
+
+ /* Accumulate light from all sources until accumulator is full. Then apply Occlusion and BRDF. */
+ vec4 spec_accum = vec4(0.0);
+ vec4 C_spec_accum = vec4(0.0);
+
+ /* Planar Reflections */
+ for (int i = 0; i < MAX_PLANAR && i < planar_count && spec_accum.a < 0.999; ++i) {
+ PlanarData pd = planars_data[i];
+
+ /* Fade on geometric normal. */
+ float fade = probe_attenuation_planar(pd, worldPosition, worldNormal);
+
+ if (fade > 0.0) {
+ vec3 spec = probe_evaluate_planar(float(i), pd, worldPosition, N, V, rand.r, cameraPos, roughness, fade);
+ accumulate_light(spec, fade, spec_accum);
+
+ vec3 C_spec = probe_evaluate_planar(float(i), pd, worldPosition, C_N, V, rand.r, cameraPos, C_roughness, fade);
+ accumulate_light(C_spec, fade, C_spec_accum);
+ }
+ }
+
+ /* Specular probes */
+ vec3 spec_dir = get_specular_dominant_dir(N, V, roughnessSquared);
+ vec3 C_spec_dir = get_specular_dominant_dir(C_N, V, C_roughnessSquared);
+
+ /* Starts at 1 because 0 is world probe */
+ for (int i = 1; i < MAX_PROBE && i < probe_count && spec_accum.a < 0.999; ++i) {
+ CubeData cd = probes_data[i];
+
+ float fade = probe_attenuation_cube(cd, worldPosition);
+
+ if (fade > 0.0) {
+ vec3 spec = probe_evaluate_cube(float(i), cd, worldPosition, spec_dir, roughness);
+ accumulate_light(spec, fade, spec_accum);
+
+ vec3 C_spec = probe_evaluate_cube(float(i), cd, worldPosition, C_spec_dir, C_roughness);
+ accumulate_light(C_spec, fade, C_spec_accum);
+ }
+ }
+
+ /* World Specular */
+ if (spec_accum.a < 0.999) {
+ vec3 spec = probe_evaluate_world_spec(spec_dir, roughness);
+ accumulate_light(spec, 1.0, spec_accum);
+
+ vec3 C_spec = probe_evaluate_world_spec(C_spec_dir, C_roughness);
+ accumulate_light(C_spec, 1.0, C_spec_accum);
+ }
+
+ /* Ambient Occlusion */
+ vec3 bent_normal;
+ float final_ao = occlusion_compute(N, viewPosition, ao, rand.rg, bent_normal);
+
+ /* Get Brdf intensity */
+ vec2 uv = lut_coords(dot(N, V), roughness);
+ vec2 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rg;
+
+ out_light += spec_accum.rgb * F_ibl(f0, brdf_lut) * specular_occlusion(dot(N, V), final_ao, roughness) * float(specToggle);
+
+ uv = lut_coords(dot(C_N, V), C_roughness);
+ brdf_lut = texture(utilTex, vec3(uv, 1.0)).rg;
+
+ out_light += C_spec_accum.rgb * F_ibl(vec3(0.04), brdf_lut) * specular_occlusion(dot(C_N, V), final_ao, C_roughness) * float(specToggle) * C_intensity;
+
+ /* ---------------- DIFFUSE ENVIRONMENT LIGHTING ----------------- */
+
+ /* Accumulate light from all sources until accumulator is full. Then apply Occlusion and BRDF. */
+ vec4 diff_accum = vec4(0.0);
+
+ /* Start at 1 because 0 is world irradiance */
+ for (int i = 1; i < MAX_GRID && i < grid_count && diff_accum.a < 0.999; ++i) {
+ GridData gd = grids_data[i];
+
+ vec3 localpos;
+ float fade = probe_attenuation_grid(gd, 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 && grid_count > 0) {
+ vec3 diff = probe_evaluate_world_diff(bent_normal);
+ accumulate_light(diff, 1.0, diff_accum);
+ }
+
+ out_light += diff_accum.rgb * albedo * gtao_multibounce(final_ao, albedo);
+
+ return out_light;
+}
+
+/* ----------- Diffuse ----------- */
+
+vec3 eevee_surface_diffuse_lit(vec3 N, vec3 albedo, float ao)
+{
+ vec3 V = cameraVec;
+ N = normalize(N);
+
+ vec4 rand = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0));
+
+ /* ---------------- SCENE LAMPS LIGHTING ----------------- */
+
+#ifdef HAIR_SHADER
+ vec3 norm_view = cross(V, N);
+ norm_view = normalize(cross(norm_view, N)); /* Normal facing view */
+#endif
+
+ vec3 diff = vec3(0.0);
+ for (int i = 0; i < MAX_LIGHT && i < light_count; ++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);
+
+ vec3 l_color_vis = ld.l_color * light_visibility(ld, worldPosition, l_vector);
+
+#ifdef HAIR_SHADER
+ vec3 norm_lamp, view_vec;
+ float occlu_trans, occlu;
+ light_hair_common(ld, N, V, l_vector, norm_view, occlu_trans, occlu, norm_lamp, view_vec);
+
+ diff += l_color_vis * light_diffuse(ld, -norm_lamp, V, l_vector) * occlu_trans;
+#else
+ diff += l_color_vis * light_diffuse(ld, N, V, l_vector);
+#endif
+ }
+
+ /* Accumulate outgoing radiance */
+ vec3 out_light = diff * albedo;
+
+#ifdef HAIR_SHADER
+ N = -norm_view;
+#endif
+
+ /* ---------------- DIFFUSE ENVIRONMENT LIGHTING ----------------- */
+
+ /* Ambient Occlusion */
+ vec3 bent_normal;
+ float final_ao = occlusion_compute(N, viewPosition, ao, rand.rg, bent_normal);
+
+ /* Accumulate light from all sources until accumulator is full. Then apply Occlusion and BRDF. */
+ vec4 diff_accum = vec4(0.0);
+
+ /* Start at 1 because 0 is world irradiance */
+ for (int i = 1; i < MAX_GRID && i < grid_count && diff_accum.a < 0.999; ++i) {
+ GridData gd = grids_data[i];
+
+ vec3 localpos;
+ float fade = probe_attenuation_grid(gd, 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 && grid_count > 0) {
+ vec3 diff = probe_evaluate_world_diff(bent_normal);
+ accumulate_light(diff, 1.0, diff_accum);
+ }
+
+ out_light += diff_accum.rgb * albedo * gtao_multibounce(final_ao, albedo);
+
+ return out_light;
+}
+
+/* ----------- Glossy ----------- */
+
+vec3 eevee_surface_glossy_lit(vec3 N, vec3 f0, float roughness, float ao)
+{
+ roughness = clamp(roughness, 1e-8, 0.9999);
+ float roughnessSquared = roughness * roughness;
+
+ vec3 V = cameraVec;
+ N = normalize(N);
+
+ vec4 rand = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0));
+
+ /* ---------------- SCENE LAMPS LIGHTING ----------------- */
+
+#ifdef HAIR_SHADER
+ vec3 norm_view = cross(V, N);
+ norm_view = normalize(cross(norm_view, N)); /* Normal facing view */
+#endif
+
+ vec3 spec = vec3(0.0);
+ for (int i = 0; i < MAX_LIGHT && i < light_count; ++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);
+
+ vec3 l_color_vis = ld.l_color * light_visibility(ld, worldPosition, l_vector);
+
+#ifdef HAIR_SHADER
+ vec3 norm_lamp, view_vec;
+ float occlu_trans, occlu;
+ light_hair_common(ld, N, V, l_vector, norm_view, occlu_trans, occlu, norm_lamp, view_vec);
+
+ spec += l_color_vis * light_specular(ld, N, view_vec, l_vector, roughnessSquared, f0) * occlu;
+#else
+ spec += l_color_vis * light_specular(ld, N, V, l_vector, roughnessSquared, f0);
+#endif
+ }
+
+ /* Accumulate outgoing radiance */
+ vec3 out_light = spec * float(specToggle);
+
+#ifdef HAIR_SHADER
+ N = -norm_view;
+#endif
+
+ /* ---------------- SPECULAR ENVIRONMENT LIGHTING ----------------- */
+
+ /* Accumulate light from all sources until accumulator is full. Then apply Occlusion and BRDF. */
+ vec4 spec_accum = vec4(0.0);
+
+ /* Planar Reflections */
+ for (int i = 0; i < MAX_PLANAR && i < planar_count && spec_accum.a < 0.999; ++i) {
+ PlanarData pd = planars_data[i];
+
+ float fade = probe_attenuation_planar(pd, worldPosition, N);
+
+ if (fade > 0.0) {
+ vec3 spec = probe_evaluate_planar(float(i), pd, worldPosition, N, V, rand.r, cameraPos, roughness, fade);
+ accumulate_light(spec, fade, spec_accum);
+ }
+ }
+
+ /* Specular probes */
+ vec3 spec_dir = get_specular_dominant_dir(N, V, roughnessSquared);
+
+ /* Starts at 1 because 0 is world probe */
+ for (int i = 1; i < MAX_PROBE && i < probe_count && spec_accum.a < 0.999; ++i) {
+ CubeData cd = probes_data[i];
+
+ float fade = probe_attenuation_cube(cd, worldPosition);
+
+ if (fade > 0.0) {
+ vec3 spec = probe_evaluate_cube(float(i), cd, worldPosition, spec_dir, roughness);
+ accumulate_light(spec, fade, spec_accum);
+ }
+ }
+
+ /* World Specular */
+ if (spec_accum.a < 0.999) {
+ vec3 spec = probe_evaluate_world_spec(spec_dir, roughness);
+ accumulate_light(spec, 1.0, spec_accum);
+ }
+
+ /* Ambient Occlusion */
+ vec3 bent_normal;
+ float final_ao = occlusion_compute(N, viewPosition, ao, rand.rg, bent_normal);
+
+ /* Get Brdf intensity */
+ vec2 uv = lut_coords(dot(N, V), roughness);
+ vec2 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rg;
+
+ out_light += spec_accum.rgb * F_ibl(f0, brdf_lut) * specular_occlusion(dot(N, V), final_ao, roughness) * float(specToggle);
+
+ return out_light;
+}
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..998ccfa453a
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl
@@ -0,0 +1,40 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat4 ModelMatrix;
+uniform mat4 ModelViewMatrix;
+uniform mat3 WorldNormalMatrix;
+#ifndef ATTRIB
+uniform mat3 NormalMatrix;
+#endif
+
+in vec3 pos;
+in vec3 nor;
+
+out vec3 worldPosition;
+out vec3 viewPosition;
+
+/* Used for planar reflections */
+uniform vec4 ClipPlanes[1];
+
+#ifdef USE_FLAT_NORMAL
+flat out vec3 worldNormal;
+flat out vec3 viewNormal;
+#else
+out vec3 worldNormal;
+out vec3 viewNormal;
+#endif
+
+void main() {
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ viewPosition = (ModelViewMatrix * vec4(pos, 1.0)).xyz;
+ worldPosition = (ModelMatrix * vec4(pos, 1.0)).xyz;
+ viewNormal = normalize(NormalMatrix * nor);
+ worldNormal = normalize(WorldNormalMatrix * nor);
+
+ /* Used for planar reflections */
+ gl_ClipDistance[0] = dot(vec4(worldPosition, 1.0), ClipPlanes[0]);
+
+#ifdef ATTRIB
+ pass_attrib(pos);
+#endif
+} \ No newline at end of file
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..f296eedc3ee
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl
@@ -0,0 +1,234 @@
+/* Mainly From https://eheitzresearch.wordpress.com/415-2/ */
+
+#define USE_LTC
+
+#ifndef UTIL_TEX
+#define UTIL_TEX
+uniform sampler2DArray utilTex;
+#endif /* UTIL_TEX */
+
+/* from Real-Time Area Lighting: a Journey from Research to Production
+ * Stephen Hill and Eric Heitz */
+float edge_integral(vec3 p1, vec3 p2)
+{
+#if 0
+ /* more accurate replacement of acos */
+ float x = dot(p1, p2);
+ float y = abs(x);
+
+ float a = 5.42031 + (3.12829 + 0.0902326 * y) * y;
+ float b = 3.45068 + (4.18814 + y) * y;
+ float theta_sintheta = a / b;
+
+ if (x < 0.0) {
+ theta_sintheta = (M_PI / sqrt(1.0 - x * x)) - theta_sintheta;
+ }
+ vec3 u = cross(p1, p2);
+ return theta_sintheta * dot(u, N);
+#endif
+ float cos_theta = dot(p1, p2);
+ cos_theta = clamp(cos_theta, -0.9999, 0.9999);
+
+ float theta = acos(cos_theta);
+ vec3 u = normalize(cross(p1, p2));
+ return theta * cross(p1, p2).z / sin(theta);
+}
+
+int clip_quad_to_horizon(inout vec3 L[5])
+{
+ /* detect clipping config */
+ int config = 0;
+ if (L[0].z > 0.0) config += 1;
+ if (L[1].z > 0.0) config += 2;
+ if (L[2].z > 0.0) config += 4;
+ if (L[3].z > 0.0) config += 8;
+
+ /* clip */
+ int n = 0;
+
+ if (config == 0)
+ {
+ /* clip all */
+ }
+ else if (config == 1) /* V1 clip V2 V3 V4 */
+ {
+ n = 3;
+ L[1] = -L[1].z * L[0] + L[0].z * L[1];
+ L[2] = -L[3].z * L[0] + L[0].z * L[3];
+ }
+ else if (config == 2) /* V2 clip V1 V3 V4 */
+ {
+ n = 3;
+ L[0] = -L[0].z * L[1] + L[1].z * L[0];
+ L[2] = -L[2].z * L[1] + L[1].z * L[2];
+ }
+ else if (config == 3) /* V1 V2 clip V3 V4 */
+ {
+ n = 4;
+ L[2] = -L[2].z * L[1] + L[1].z * L[2];
+ L[3] = -L[3].z * L[0] + L[0].z * L[3];
+ }
+ else if (config == 4) /* V3 clip V1 V2 V4 */
+ {
+ n = 3;
+ L[0] = -L[3].z * L[2] + L[2].z * L[3];
+ L[1] = -L[1].z * L[2] + L[2].z * L[1];
+ }
+ else if (config == 5) /* V1 V3 clip V2 V4) impossible */
+ {
+ n = 0;
+ }
+ else if (config == 6) /* V2 V3 clip V1 V4 */
+ {
+ n = 4;
+ L[0] = -L[0].z * L[1] + L[1].z * L[0];
+ L[3] = -L[3].z * L[2] + L[2].z * L[3];
+ }
+ else if (config == 7) /* V1 V2 V3 clip V4 */
+ {
+ n = 5;
+ L[4] = -L[3].z * L[0] + L[0].z * L[3];
+ L[3] = -L[3].z * L[2] + L[2].z * L[3];
+ }
+ else if (config == 8) /* V4 clip V1 V2 V3 */
+ {
+ n = 3;
+ L[0] = -L[0].z * L[3] + L[3].z * L[0];
+ L[1] = -L[2].z * L[3] + L[3].z * L[2];
+ L[2] = L[3];
+ }
+ else if (config == 9) /* V1 V4 clip V2 V3 */
+ {
+ n = 4;
+ L[1] = -L[1].z * L[0] + L[0].z * L[1];
+ L[2] = -L[2].z * L[3] + L[3].z * L[2];
+ }
+ else if (config == 10) /* V2 V4 clip V1 V3) impossible */
+ {
+ n = 0;
+ }
+ else if (config == 11) /* V1 V2 V4 clip V3 */
+ {
+ n = 5;
+ L[4] = L[3];
+ L[3] = -L[2].z * L[3] + L[3].z * L[2];
+ L[2] = -L[2].z * L[1] + L[1].z * L[2];
+ }
+ else if (config == 12) /* V3 V4 clip V1 V2 */
+ {
+ n = 4;
+ L[1] = -L[1].z * L[2] + L[2].z * L[1];
+ L[0] = -L[0].z * L[3] + L[3].z * L[0];
+ }
+ else if (config == 13) /* V1 V3 V4 clip V2 */
+ {
+ n = 5;
+ L[4] = L[3];
+ L[3] = L[2];
+ L[2] = -L[1].z * L[2] + L[2].z * L[1];
+ L[1] = -L[1].z * L[0] + L[0].z * L[1];
+ }
+ else if (config == 14) /* V2 V3 V4 clip V1 */
+ {
+ n = 5;
+ L[4] = -L[0].z * L[3] + L[3].z * L[0];
+ L[0] = -L[0].z * L[1] + L[1].z * L[0];
+ }
+ else if (config == 15) /* V1 V2 V3 V4 */
+ {
+ n = 4;
+ }
+
+ if (n == 3)
+ L[3] = L[0];
+ if (n == 4)
+ L[4] = L[0];
+
+ return n;
+}
+
+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;
+}
+
+float ltc_evaluate(vec3 N, vec3 V, mat3 Minv, vec3 corners[4])
+{
+ /* 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 */
+ Minv = Minv * transpose(mat3(T1, T2, N));
+
+ /* polygon (allocate 5 vertices for clipping) */
+ vec3 L[5];
+ L[0] = Minv * corners[0];
+ L[1] = Minv * corners[1];
+ L[2] = Minv * corners[2];
+ L[3] = Minv * corners[3];
+
+ int n = clip_quad_to_horizon(L);
+
+ if (n == 0)
+ return 0.0;
+
+ /* project onto sphere */
+ L[0] = normalize(L[0]);
+ L[1] = normalize(L[1]);
+ L[2] = normalize(L[2]);
+ L[3] = normalize(L[3]);
+ L[4] = normalize(L[4]);
+
+ /* integrate */
+ float sum = 0.0;
+
+ sum += edge_integral(L[0], L[1]);
+ sum += edge_integral(L[1], L[2]);
+ sum += edge_integral(L[2], L[3]);
+ if (n >= 4)
+ sum += edge_integral(L[3], L[4]);
+ if (n == 5)
+ sum += edge_integral(L[4], L[0]);
+
+ return abs(sum);
+}
+
+/* Aproximate circle with an octogone */
+#define LTC_CIRCLE_RES 8
+float ltc_evaluate_circle(vec3 N, vec3 V, mat3 Minv, vec3 p[LTC_CIRCLE_RES])
+{
+ /* 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 */
+ Minv = Minv * transpose(mat3(T1, T2, N));
+
+ for (int i = 0; i < LTC_CIRCLE_RES; ++i) {
+ p[i] = Minv * p[i];
+ /* clip to horizon */
+ p[i].z = max(0.0, p[i].z);
+ /* project onto sphere */
+ p[i] = normalize(p[i]);
+ }
+
+ /* integrate */
+ float sum = 0.0;
+ for (int i = 0; i < LTC_CIRCLE_RES - 1; ++i) {
+ sum += edge_integral(p[i], p[i + 1]);
+ }
+ sum += edge_integral(p[LTC_CIRCLE_RES - 1], p[0]);
+
+ return max(0.0, sum);
+}
+
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..631b325ae37
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/octahedron_lib.glsl
@@ -0,0 +1,38 @@
+
+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..cf59b29548a
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
@@ -0,0 +1,94 @@
+
+#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 hashScale;
+float hashScale = 0.001;
+
+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 / (hashScale * 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);
+
+ return threshold;
+}
+
+#endif
+
+#ifdef USE_ALPHA_CLIP
+uniform float alphaThreshold;
+#endif
+
+#ifdef SHADOW_SHADER
+out vec4 FragColor;
+#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
+
+#ifdef SHADOW_SHADER
+ float dist = distance(lampPosition.xyz, worldPosition.xyz);
+ FragColor = vec4(dist, 0.0, 0.0, 1.0);
+#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..6f26a815736
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl
@@ -0,0 +1,18 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat4 ModelMatrix;
+#ifdef CLIP_PLANES
+uniform vec4 ClipPlanes[1];
+#endif
+
+in vec3 pos;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+#ifdef CLIP_PLANES
+ vec4 worldPosition = (ModelMatrix * vec4(pos, 1.0));
+ gl_ClipDistance[0] = dot(worldPosition, ClipPlanes[0]);
+#endif
+ /* TODO motion vectors */
+}
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..df6fbc4c2fe
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/shadow_frag.glsl
@@ -0,0 +1,17 @@
+
+layout(std140) uniform shadow_render_block {
+ mat4 ShadowMatrix[6];
+ mat4 FaceViewMatrix[6];
+ vec4 lampPosition;
+ int layer;
+ float exponent;
+};
+
+in vec3 worldPosition;
+
+out vec4 FragColor;
+
+void main() {
+ float dist = distance(lampPosition.xyz, worldPosition.xyz);
+ FragColor = vec4(dist, 0.0, 0.0, 1.0);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_geom.glsl b/source/blender/draw/engines/eevee/shaders/shadow_geom.glsl
new file mode 100644
index 00000000000..d9d30c4d9e6
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/shadow_geom.glsl
@@ -0,0 +1,50 @@
+
+layout(std140) uniform shadow_render_block {
+ mat4 ShadowMatrix[6];
+ mat4 FaceViewMatrix[6];
+ vec4 lampPosition;
+ int layer;
+ float exponent;
+};
+
+layout(triangles) in;
+layout(triangle_strip, max_vertices=3) out;
+
+in vec4 vPos[];
+flat in int face[];
+
+#ifdef MESH_SHADER
+in vec3 vNor[];
+in vec3 vNor[];
+#endif
+
+out vec3 worldPosition;
+#ifdef MESH_SHADER
+out vec3 viewPosition; /* Required. otherwise generate linking error. */
+out vec3 worldNormal; /* Required. otherwise generate linking error. */
+out vec3 viewNormal; /* Required. otherwise generate linking error. */
+flat out int shFace;
+#else
+int shFace;
+#endif
+
+void main() {
+ shFace = face[0];
+ gl_Layer = shFace;
+
+ for (int v = 0; v < 3; ++v) {
+ gl_Position = ShadowMatrix[shFace] * vPos[v];
+ worldPosition = vPos[v].xyz;
+#ifdef MESH_SHADER
+ worldNormal = vNor[v];
+ viewPosition = (FaceViewMatrix[shFace] * vec4(worldPosition, 1.0)).xyz;
+ viewNormal = (FaceViewMatrix[shFace] * vec4(worldNormal, 0.0)).xyz;
+#ifdef ATTRIB
+ pass_attrib(v);
+#endif
+#endif
+ EmitVertex();
+ }
+
+ EndPrimitive();
+} \ No newline at end of file
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..6782922a2e4
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl
@@ -0,0 +1,113 @@
+
+layout(std140) uniform shadow_render_block {
+ mat4 ShadowMatrix[6];
+ mat4 FaceViewMatrix[6];
+ vec4 lampPosition;
+ int layer;
+ float exponent;
+};
+
+uniform samplerCube shadowCube;
+
+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;
+}
+
+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);
+}
+
+#define NUM_SAMPLE 32
+vec2 poisson_disc[32] = vec2[32](
+ vec2( 0.476, 0.854), vec2(-0.659, -0.670),
+ vec2( 0.905, -0.270), vec2( 0.215, -0.133),
+ vec2(-0.595, 0.242), vec2(-0.146, 0.519),
+ vec2( 0.108, -0.930), vec2( 0.807, 0.449),
+
+ vec2(-0.476, -0.854), vec2( 0.659, 0.670),
+ vec2(-0.905, 0.270), vec2(-0.215, 0.133),
+ vec2( 0.595, -0.242), vec2( 0.146, -0.519),
+ vec2(-0.108, 0.930), vec2(-0.807, -0.449),
+
+ vec2(-0.854, 0.476), vec2( 0.670, -0.659),
+ vec2( 0.270, 0.905), vec2( 0.133, 0.215),
+ vec2(-0.242, -0.595), vec2(-0.519, -0.146),
+ vec2( 0.930, 0.108), vec2(-0.449, 0.807),
+
+ vec2( 0.854, -0.476), vec2(-0.670, 0.659),
+ vec2(-0.270, -0.905), vec2(-0.133, -0.215),
+ vec2( 0.242, 0.595), vec2( 0.519, 0.146),
+ vec2(-0.930, -0.108), vec2( 0.449, -0.807)
+);
+
+/* Marco Salvi's GDC 2008 presentation about shadow maps pre-filtering techniques slide 24 */
+float ln_space_prefilter(float w0, float x, float w1, float y)
+{
+ return x + log(w0 + w1 * exp(y - x));
+}
+
+void main() {
+ const vec2 texelSize = vec2(1.0 / 512.0);
+
+ vec2 uvs = gl_FragCoord.xy * texelSize;
+
+ /* add a 2 pixel border to ensure filtering is correct */
+ uvs.xy *= 1.0 + texelSize * 2.0;
+ uvs.xy -= texelSize;
+
+ float pattern = 1.0;
+
+ /* 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.xy = 1.0 - uvs.xy;
+ }
+
+ /* clamp to [0-1] */
+ uvs.xy = fract(uvs.xy);
+
+ /* get cubemap vector */
+ vec3 cubevec = octahedral_to_cubemap_proj(uvs.xy);
+
+ vec3 T, B;
+ make_orthonormal_basis(cubevec, T, B);
+
+ /* get cubemap shadow value */
+ const float blur_radius = 5.0 / 512.0; /* Totally arbitrary */
+ const float weight = 1.0 / float(NUM_SAMPLE);
+ float accum = 0.0;
+
+ /* Poisson disc blur in log space. */
+ vec2 offsetvec = poisson_disc[0].xy * blur_radius;
+ float depth1 = texture(shadowCube, cubevec + offsetvec.x * T + offsetvec.y * B).r;
+
+ offsetvec = poisson_disc[1].xy * blur_radius;
+ float depth2 = texture(shadowCube, cubevec + offsetvec.x * T + offsetvec.y * B).r;
+
+ accum = ln_space_prefilter(weight, depth1, weight, depth2);
+
+ for (int i = 2; i < NUM_SAMPLE; ++i) {
+ vec2 offsetvec = poisson_disc[i].xy * blur_radius;
+ depth1 = texture(shadowCube, cubevec + offsetvec.x * T + offsetvec.y * B).r;
+ accum = ln_space_prefilter(1.0, accum, weight, depth1);
+ }
+
+ FragColor = vec4(accum, accum, accum, 1.0);
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_store_geom.glsl b/source/blender/draw/engines/eevee/shaders/shadow_store_geom.glsl
new file mode 100644
index 00000000000..78ccb025ce6
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/shadow_store_geom.glsl
@@ -0,0 +1,24 @@
+
+layout(std140) uniform shadow_render_block {
+ mat4 ShadowMatrix[6];
+ mat4 FaceViewMatrix[6];
+ vec4 lampPosition;
+ int layer;
+ float exponent;
+};
+
+layout(triangles) in;
+layout(triangle_strip, max_vertices=3) out;
+
+in vec4 vPos[];
+
+void main() {
+ gl_Layer = layer;
+
+ for (int v = 0; v < 3; ++v) {
+ gl_Position = vPos[v];
+ EmitVertex();
+ }
+
+ EndPrimitive();
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_store_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_store_vert.glsl
new file mode 100644
index 00000000000..dee020f19b4
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/shadow_store_vert.glsl
@@ -0,0 +1,8 @@
+
+in vec3 pos;
+
+out vec4 vPos;
+
+void main() {
+ vPos = vec4(pos, 1.0);
+} \ No newline at end of file
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..777902ccba8
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
@@ -0,0 +1,29 @@
+
+uniform mat4 ShadowModelMatrix;
+#ifdef MESH_SHADER
+uniform mat3 WorldNormalMatrix;
+#endif
+
+in vec3 pos;
+#ifdef MESH_SHADER
+in vec3 nor;
+#endif
+
+out vec4 vPos;
+#ifdef MESH_SHADER
+out vec3 vNor;
+#endif
+
+flat out int face;
+
+void main() {
+ vPos = ShadowModelMatrix * vec4(pos, 1.0);
+ face = gl_InstanceID;
+
+#ifdef MESH_SHADER
+ vNor = WorldNormalMatrix * nor;
+#ifdef ATTRIB
+ pass_attrib(pos);
+#endif
+#endif
+}
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..7f44dd53163
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
@@ -0,0 +1,396 @@
+
+#ifdef VOLUMETRICS
+
+#define NODETREE_EXEC
+
+#define VOLUMETRIC_INTEGRATION_MAX_STEP 256
+#define VOLUMETRIC_SHADOW_MAX_STEP 128
+
+uniform int light_count;
+uniform vec2 volume_start_end;
+uniform vec4 volume_samples_clamp;
+
+#define volume_start volume_start_end.x
+#define volume_end volume_start_end.y
+
+#define volume_integration_steps volume_samples_clamp.x
+#define volume_shadows_steps volume_samples_clamp.y
+#define volume_sample_distribution volume_samples_clamp.z
+#define volume_light_clamp volume_samples_clamp.w
+
+#ifdef COLOR_TRANSMITTANCE
+layout(location = 0) out vec4 outScattering;
+layout(location = 1) out vec4 outTransmittance;
+#else
+out vec4 outScatteringTransmittance;
+#endif
+
+/* Warning: theses are not attributes, theses are global vars. */
+vec3 worldPosition = vec3(0.0);
+vec3 viewPosition = vec3(0.0);
+vec3 viewNormal = vec3(0.0);
+
+uniform sampler2D depthFull;
+
+void participating_media_properties(vec3 wpos, out vec3 extinction, out vec3 scattering, out vec3 emission, out float anisotropy)
+{
+#ifndef VOLUME_HOMOGENEOUS
+ worldPosition = wpos;
+ viewPosition = (ViewMatrix * vec4(wpos, 1.0)).xyz; /* warning, Perf. */
+#endif
+
+ Closure cl = nodetree_exec();
+
+ scattering = cl.scatter;
+ emission = cl.emission;
+ anisotropy = cl.anisotropy;
+ extinction = max(vec3(1e-4), cl.absorption + cl.scatter);
+}
+
+vec3 participating_media_extinction(vec3 wpos)
+{
+#ifndef VOLUME_HOMOGENEOUS
+ worldPosition = wpos;
+ viewPosition = (ViewMatrix * vec4(wpos, 1.0)).xyz; /* warning, Perf. */
+#endif
+
+ Closure cl = nodetree_exec();
+
+ return max(vec3(1e-4), cl.absorption + cl.scatter);
+}
+
+float phase_function_isotropic()
+{
+ return 1.0 / (4.0 * M_PI);
+}
+
+float phase_function(vec3 v, vec3 l, float g)
+{
+#ifndef VOLUME_ISOTROPIC /* TODO Use this flag when only isotropic closures are used */
+ /* 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) / (4.0 * M_PI * pow(1 + sqr_g - 2 * g * cos_theta, 3.0 / 2.0));
+#else
+ return phase_function_isotropic();
+#endif
+}
+
+float light_volume(LightData ld, vec4 l_vector)
+{
+ float power;
+ float dist = max(1e-4, abs(l_vector.w - ld.l_radius));
+ /* TODO : Area lighting ? */
+ /* Removing Area Power. */
+ /* TODO : put this out of the shader. */
+ if (ld.l_type == AREA) {
+ power = 0.0962 * (ld.l_sizex * ld.l_sizey * 4.0f * M_PI);
+ }
+ else {
+ power = 0.0248 * (4.0 * ld.l_radius * ld.l_radius * M_PI * M_PI);
+ }
+ return min(power / (l_vector.w * l_vector.w), volume_light_clamp);
+}
+
+vec3 irradiance_volumetric(vec3 wpos)
+{
+ 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;
+}
+
+vec3 light_volume_shadow(LightData ld, vec3 ray_wpos, vec4 l_vector, vec3 s_extinction)
+{
+#ifdef VOLUME_SHADOW
+
+#ifdef VOLUME_HOMOGENEOUS
+ /* Simple extinction */
+ return exp(-s_extinction * l_vector.w);
+#else
+ /* Heterogeneous volume shadows */
+ float dd = l_vector.w / volume_shadows_steps;
+ vec3 L = l_vector.xyz * l_vector.w;
+ vec3 shadow = vec3(1.0);
+ for (float s = 0.5; s < VOLUMETRIC_SHADOW_MAX_STEP && s < (volume_shadows_steps - 0.1); s += 1.0) {
+ vec3 pos = ray_wpos + L * (s / volume_shadows_steps);
+ vec3 s_extinction = participating_media_extinction(pos);
+ shadow *= exp(-s_extinction * dd);
+ }
+ return shadow;
+#endif /* VOLUME_HOMOGENEOUS */
+
+#else
+ return vec3(1.0);
+#endif /* VOLUME_SHADOW */
+}
+
+float find_next_step(float iter, float noise)
+{
+ float progress = (iter + noise) / volume_integration_steps;
+
+ float linear_split = mix(volume_start, volume_end, progress);
+
+ if (ProjectionMatrix[3][3] == 0.0) {
+ float exp_split = volume_start * pow(volume_end / volume_start, progress);
+ return mix(linear_split, exp_split, volume_sample_distribution);
+ }
+ else {
+ return linear_split;
+ }
+}
+
+/* Based on Frosbite Unified Volumetric.
+ * https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */
+void main()
+{
+ vec2 uv = (gl_FragCoord.xy * 2.0) / ivec2(textureSize(depthFull, 0));
+ float scene_depth = texelFetch(depthFull, ivec2(gl_FragCoord.xy) * 2, 0).r; /* use the same depth as in the upsample step */
+ vec3 vpos = get_view_space_from_depth(uv, scene_depth);
+ vec3 wpos = (ViewMatrixInverse * vec4(vpos, 1.0)).xyz;
+ vec3 wdir = (ProjectionMatrix[3][3] == 0.0) ? normalize(cameraPos - wpos) : cameraForward;
+
+ /* Note: this is NOT the distance to the camera. */
+ float max_z = vpos.z;
+
+ /* project ray to clip plane so we can integrate in even steps in clip space. */
+ vec3 wdir_proj = wdir / abs(dot(cameraForward, wdir));
+ float wlen = length(wdir_proj);
+
+ /* Transmittance: How much light can get through. */
+ vec3 transmittance = vec3(1.0);
+
+ /* Scattering: Light that has been accumulated from scattered light sources. */
+ vec3 scattering = vec3(0.0);
+
+ vec3 ray_origin = (ProjectionMatrix[3][3] == 0.0)
+ ? cameraPos
+ : (ViewMatrixInverse * vec4(get_view_space_from_depth(uv, 0.5), 1.0)).xyz;
+
+#ifdef VOLUME_HOMOGENEOUS
+ /* Put it out of the loop for homogeneous media. */
+ vec3 s_extinction, s_scattering, s_emission;
+ float s_anisotropy;
+ participating_media_properties(vec3(0.0), s_extinction, s_scattering, s_emission, s_anisotropy);
+#endif
+
+ /* Start from near clip. TODO make start distance an option. */
+ float rand = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0)).r;
+ /* Less noisy but noticeable patterns, could work better with temporal AA. */
+ // float rand = (1.0 / 16.0) * float(((int(gl_FragCoord.x + gl_FragCoord.y) & 0x3) << 2) + (int(gl_FragCoord.x) & 0x3));
+ float dist = volume_start;
+ for (float i = 0.5; i < VOLUMETRIC_INTEGRATION_MAX_STEP && i < (volume_integration_steps - 0.1); ++i) {
+ float new_dist = max(max_z, find_next_step(rand, i));
+ float step = dist - new_dist; /* Marching step */
+ dist = new_dist;
+
+ vec3 ray_wpos = ray_origin + wdir_proj * dist;
+
+#ifndef VOLUME_HOMOGENEOUS
+ vec3 s_extinction, s_scattering, s_emission;
+ float s_anisotropy;
+ participating_media_properties(ray_wpos, s_extinction, s_scattering, s_emission, s_anisotropy);
+#endif
+
+ /* Evaluate each light */
+ vec3 Lscat = s_emission;
+
+#ifdef VOLUME_LIGHTING /* Lights */
+ for (int i = 0; i < MAX_LIGHT && i < light_count; ++i) {
+ LightData ld = lights_data[i];
+
+ vec4 l_vector;
+ l_vector.xyz = ld.l_position - ray_wpos;
+ l_vector.w = length(l_vector.xyz);
+
+ float Vis = light_visibility(ld, ray_wpos, l_vector);
+
+ vec3 Li = ld.l_color * light_volume(ld, l_vector) * light_volume_shadow(ld, ray_wpos, l_vector, s_extinction);
+
+ Lscat += Li * Vis * s_scattering * phase_function(-wdir, l_vector.xyz / l_vector.w, s_anisotropy);
+ }
+#endif
+
+ /* Environment : Average color. */
+ Lscat += irradiance_volumetric(wpos) * s_scattering * phase_function_isotropic();
+
+ /* Evaluate Scattering */
+ float s_len = wlen * step;
+ vec3 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 */
+ scattering += transmittance * Lscat;
+
+ /* Evaluate transmittance to view independantely */
+ transmittance *= Tr;
+
+ if (dist <= max_z)
+ break;
+ }
+
+#ifdef COLOR_TRANSMITTANCE
+ outScattering = vec4(scattering, 1.0);
+ outTransmittance = vec4(transmittance, 1.0);
+#else
+ float mono_transmittance = dot(transmittance, vec3(1.0)) / 3.0;
+
+ outScatteringTransmittance = vec4(scattering, mono_transmittance);
+#endif
+}
+
+#else /* STEP_UPSAMPLE */
+
+out vec4 FragColor;
+
+uniform sampler2D depthFull;
+uniform sampler2D volumetricBuffer;
+
+uniform mat4 ProjectionMatrix;
+
+vec4 get_view_z_from_depth(vec4 depth)
+{
+ vec4 d = 2.0 * depth - 1.0;
+ return -ProjectionMatrix[3][2] / (d + ProjectionMatrix[2][2]);
+}
+
+void main()
+{
+#if 0 /* 2 x 2 with bilinear */
+
+ const vec4 bilinear_weights[4] = vec4[4](
+ vec4(9.0 / 16.0, 3.0 / 16.0, 3.0 / 16.0, 1.0 / 16.0 ),
+ vec4(3.0 / 16.0, 9.0 / 16.0, 1.0 / 16.0, 3.0 / 16.0 ),
+ vec4(3.0 / 16.0, 1.0 / 16.0, 9.0 / 16.0, 3.0 / 16.0 ),
+ vec4(1.0 / 16.0, 3.0 / 16.0, 3.0 / 16.0, 9.0 / 16.0 )
+ );
+
+ /* Depth aware upsampling */
+ vec4 depths;
+ ivec2 texel_co = ivec2(gl_FragCoord.xy * 0.5) * 2;
+
+ /* TODO use textureGather on glsl 4.0 */
+ depths.x = texelFetchOffset(depthFull, texel_co, 0, ivec2(0, 0)).r;
+ depths.y = texelFetchOffset(depthFull, texel_co, 0, ivec2(2, 0)).r;
+ depths.z = texelFetchOffset(depthFull, texel_co, 0, ivec2(0, 2)).r;
+ depths.w = texelFetchOffset(depthFull, texel_co, 0, ivec2(2, 2)).r;
+
+ vec4 target_depth = texelFetch(depthFull, ivec2(gl_FragCoord.xy), 0).rrrr;
+
+ depths = get_view_z_from_depth(depths);
+ target_depth = get_view_z_from_depth(target_depth);
+
+ vec4 weights = 1.0 - step(0.05, abs(depths - target_depth));
+
+ /* Index in range [0-3] */
+ int pix_id = int(dot(mod(ivec2(gl_FragCoord.xy), 2), ivec2(1, 2)));
+ weights *= bilinear_weights[pix_id];
+
+ float weight_sum = dot(weights, vec4(1.0));
+
+ if (weight_sum == 0.0) {
+ weights.x = 1.0;
+ weight_sum = 1.0;
+ }
+
+ texel_co = ivec2(gl_FragCoord.xy * 0.5);
+
+ vec4 integration_result;
+ integration_result = texelFetchOffset(volumetricBuffer, texel_co, 0, ivec2(0, 0)) * weights.x;
+ integration_result += texelFetchOffset(volumetricBuffer, texel_co, 0, ivec2(1, 0)) * weights.y;
+ integration_result += texelFetchOffset(volumetricBuffer, texel_co, 0, ivec2(0, 1)) * weights.z;
+ integration_result += texelFetchOffset(volumetricBuffer, texel_co, 0, ivec2(1, 1)) * weights.w;
+
+#else /* 4 x 4 */
+
+ /* Depth aware upsampling */
+ vec4 depths[4];
+ ivec2 texel_co = ivec2(gl_FragCoord.xy * 0.5) * 2;
+
+ /* TODO use textureGather on glsl 4.0 */
+ texel_co += ivec2(-2, -2);
+ depths[0].x = texelFetchOffset(depthFull, texel_co, 0, ivec2(0, 0)).r;
+ depths[0].y = texelFetchOffset(depthFull, texel_co, 0, ivec2(2, 0)).r;
+ depths[0].z = texelFetchOffset(depthFull, texel_co, 0, ivec2(0, 2)).r;
+ depths[0].w = texelFetchOffset(depthFull, texel_co, 0, ivec2(2, 2)).r;
+
+ texel_co += ivec2(4, 0);
+ depths[1].x = texelFetchOffset(depthFull, texel_co, 0, ivec2(0, 0)).r;
+ depths[1].y = texelFetchOffset(depthFull, texel_co, 0, ivec2(2, 0)).r;
+ depths[1].z = texelFetchOffset(depthFull, texel_co, 0, ivec2(0, 2)).r;
+ depths[1].w = texelFetchOffset(depthFull, texel_co, 0, ivec2(2, 2)).r;
+
+ texel_co += ivec2(-4, 4);
+ depths[2].x = texelFetchOffset(depthFull, texel_co, 0, ivec2(0, 0)).r;
+ depths[2].y = texelFetchOffset(depthFull, texel_co, 0, ivec2(2, 0)).r;
+ depths[2].z = texelFetchOffset(depthFull, texel_co, 0, ivec2(0, 2)).r;
+ depths[2].w = texelFetchOffset(depthFull, texel_co, 0, ivec2(2, 2)).r;
+
+ texel_co += ivec2(4, 0);
+ depths[3].x = texelFetchOffset(depthFull, texel_co, 0, ivec2(0, 0)).r;
+ depths[3].y = texelFetchOffset(depthFull, texel_co, 0, ivec2(2, 0)).r;
+ depths[3].z = texelFetchOffset(depthFull, texel_co, 0, ivec2(0, 2)).r;
+ depths[3].w = texelFetchOffset(depthFull, texel_co, 0, ivec2(2, 2)).r;
+
+ vec4 target_depth = texelFetch(depthFull, ivec2(gl_FragCoord.xy), 0).rrrr;
+
+ depths[0] = get_view_z_from_depth(depths[0]);
+ depths[1] = get_view_z_from_depth(depths[1]);
+ depths[2] = get_view_z_from_depth(depths[2]);
+ depths[3] = get_view_z_from_depth(depths[3]);
+
+ target_depth = get_view_z_from_depth(target_depth);
+
+ vec4 weights[4];
+ weights[0] = 1.0 - step(0.05, abs(depths[0] - target_depth));
+ weights[1] = 1.0 - step(0.05, abs(depths[1] - target_depth));
+ weights[2] = 1.0 - step(0.05, abs(depths[2] - target_depth));
+ weights[3] = 1.0 - step(0.05, abs(depths[3] - target_depth));
+
+ float weight_sum;
+ weight_sum = dot(weights[0], vec4(1.0));
+ weight_sum += dot(weights[1], vec4(1.0));
+ weight_sum += dot(weights[2], vec4(1.0));
+ weight_sum += dot(weights[3], vec4(1.0));
+
+ if (weight_sum == 0.0) {
+ weights[0].x = 1.0;
+ weight_sum = 1.0;
+ }
+
+ texel_co = ivec2(gl_FragCoord.xy * 0.5);
+
+ vec4 integration_result;
+
+ texel_co += ivec2(-1, -1);
+ integration_result = texelFetchOffset(volumetricBuffer, texel_co, 0, ivec2(0, 0)) * weights[0].x;
+ integration_result += texelFetchOffset(volumetricBuffer, texel_co, 0, ivec2(1, 0)) * weights[0].y;
+ integration_result += texelFetchOffset(volumetricBuffer, texel_co, 0, ivec2(0, 1)) * weights[0].z;
+ integration_result += texelFetchOffset(volumetricBuffer, texel_co, 0, ivec2(1, 1)) * weights[0].w;
+
+ texel_co += ivec2(2, 0);
+ integration_result += texelFetchOffset(volumetricBuffer, texel_co, 0, ivec2(0, 0)) * weights[1].x;
+ integration_result += texelFetchOffset(volumetricBuffer, texel_co, 0, ivec2(1, 0)) * weights[1].y;
+ integration_result += texelFetchOffset(volumetricBuffer, texel_co, 0, ivec2(0, 1)) * weights[1].z;
+ integration_result += texelFetchOffset(volumetricBuffer, texel_co, 0, ivec2(1, 1)) * weights[1].w;
+
+ texel_co += ivec2(-2, 2);
+ integration_result += texelFetchOffset(volumetricBuffer, texel_co, 0, ivec2(0, 0)) * weights[2].x;
+ integration_result += texelFetchOffset(volumetricBuffer, texel_co, 0, ivec2(1, 0)) * weights[2].y;
+ integration_result += texelFetchOffset(volumetricBuffer, texel_co, 0, ivec2(0, 1)) * weights[2].z;
+ integration_result += texelFetchOffset(volumetricBuffer, texel_co, 0, ivec2(1, 1)) * weights[2].w;
+
+ texel_co += ivec2(2, 0);
+ integration_result += texelFetchOffset(volumetricBuffer, texel_co, 0, ivec2(0, 0)) * weights[3].x;
+ integration_result += texelFetchOffset(volumetricBuffer, texel_co, 0, ivec2(1, 0)) * weights[3].y;
+ integration_result += texelFetchOffset(volumetricBuffer, texel_co, 0, ivec2(0, 1)) * weights[3].z;
+ integration_result += texelFetchOffset(volumetricBuffer, texel_co, 0, ivec2(1, 1)) * weights[3].w;
+#endif
+
+ FragColor = integration_result / weight_sum;
+}
+#endif
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..e487b29ebfd
--- /dev/null
+++ b/source/blender/draw/engines/external/external_engine.c
@@ -0,0 +1,232 @@
+/*
+ * 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
+ *
+ * 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);
+ 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 Gwn_Batch *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(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);
+
+ /* Create render engine. */
+ if (!rv3d->render_engine) {
+ RenderEngine *engine;
+ type = RE_engines_find(scene->r.engine);
+
+ if (!(type->view_update && type->render_to_view)) {
+ return;
+ }
+
+ engine = RE_engine_create_ex(type, true);
+ engine->tile_x = scene->r.tilex;
+ engine->tile_y = scene->r.tiley;
+ type->view_update(engine, draw_ctx->evil_C);
+ rv3d->render_engine = engine;
+ }
+
+ /* Rendered draw. */
+ gpuPushProjectionMatrix();
+ ED_region_pixelspace(ar);
+
+ /* Render result draw. */
+ type = rv3d->render_engine->type;
+ type->render_to_view(rv3d->render_engine, draw_ctx->evil_C);
+
+ gpuPopProjectionMatrix();
+
+ /* 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(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
+};
+
+/* 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, 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/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
new file mode 100644
index 00000000000..ca6a89f174a
--- /dev/null
+++ b/source/blender/draw/intern/DRW_render.h
@@ -0,0 +1,416 @@
+/*
+ * 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 "BKE_context.h"
+#include "BKE_layer.h"
+#include "BKE_material.h"
+#include "BKE_scene.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math_matrix.h"
+#include "BLI_math_vector.h"
+#include "BLI_string.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 "draw_common.h"
+#include "draw_cache.h"
+#include "draw_view.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RE_engine.h"
+
+struct bContext;
+struct GPUFrameBuffer;
+struct GPUShader;
+struct GPUMaterial;
+struct GPUTexture;
+struct GPUUniformBuffer;
+struct Object;
+struct Gwn_Batch;
+struct DefaultFramebufferList;
+struct DefaultTextureList;
+struct DRWTextStore;
+struct LampEngineData;
+struct RenderEngineType;
+struct ViewportEngineData;
+struct ViewportEngineData_Info;
+
+typedef struct DRWUniform DRWUniform;
+typedef struct DRWInterface DRWInterface;
+typedef struct DRWPass DRWPass;
+typedef struct DRWShadingGroup DRWShadingGroup;
+
+/* 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)) \
+}
+
+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);
+} DrawEngineType;
+
+#ifndef __DRW_ENGINE_H__
+/* Buffer and textures used by the viewport by default */
+typedef struct DefaultFramebufferList {
+ struct GPUFrameBuffer *default_fb;
+} DefaultFramebufferList;
+
+typedef struct DefaultTextureList {
+ struct GPUTexture *color;
+ struct GPUTexture *depth;
+} DefaultTextureList;
+#endif
+
+/* Textures */
+
+typedef enum {
+ DRW_TEX_RGBA_8,
+ DRW_TEX_RGBA_16,
+ DRW_TEX_RGBA_32,
+ DRW_TEX_RGB_11_11_10,
+ DRW_TEX_RGB_8,
+ DRW_TEX_RGB_16,
+ DRW_TEX_RGB_32,
+ DRW_TEX_RG_8,
+ DRW_TEX_RG_16,
+ DRW_TEX_RG_32,
+ DRW_TEX_R_8,
+ DRW_TEX_R_16,
+ DRW_TEX_R_32,
+ DRW_TEX_DEPTH_16,
+ DRW_TEX_DEPTH_24,
+ DRW_TEX_DEPTH_32,
+} DRWTextureFormat;
+
+typedef enum {
+ DRW_TEX_FILTER = (1 << 0),
+ DRW_TEX_WRAP = (1 << 1),
+ DRW_TEX_COMPARE = (1 << 2),
+ DRW_TEX_MIPMAP = (1 << 3),
+ DRW_TEX_TEMP = (1 << 4),
+} DRWTextureFlag;
+
+struct GPUTexture *DRW_texture_create_1D(
+ int w, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels);
+struct GPUTexture *DRW_texture_create_2D(
+ int w, int h, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels);
+struct GPUTexture *DRW_texture_create_2D_array(
+ int w, int h, int d, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels);
+struct GPUTexture *DRW_texture_create_cube(
+ int w, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels);
+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)
+
+/* Buffers */
+#define MAX_FBO_TEX 5
+
+typedef struct DRWFboTexture {
+ struct GPUTexture **tex;
+ int format;
+ DRWTextureFlag flag;
+} DRWFboTexture;
+
+void DRW_framebuffer_init(
+ struct GPUFrameBuffer **fb, void *engine_type, int width, int height,
+ DRWFboTexture textures[MAX_FBO_TEX], int textures_len);
+void DRW_framebuffer_bind(struct GPUFrameBuffer *fb);
+void DRW_framebuffer_clear(bool color, bool depth, bool stencil, float clear_col[4], float clear_depth);
+void DRW_framebuffer_read_data(int x, int y, int w, int h, int channels, int slot, float *data);
+void DRW_framebuffer_texture_attach(struct GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int mip);
+void DRW_framebuffer_texture_layer_attach(struct GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int layer, int mip);
+void DRW_framebuffer_cubeface_attach(struct GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int face, int mip);
+void DRW_framebuffer_texture_detach(struct GPUTexture *tex);
+void DRW_framebuffer_blit(struct GPUFrameBuffer *fb_read, struct GPUFrameBuffer *fb_write, bool depth);
+void DRW_framebuffer_recursive_downsample(
+ struct GPUFrameBuffer *fb, struct GPUTexture *tex, int num_iter,
+ void (*callback)(void *userData, int level), void *userData);
+void DRW_framebuffer_viewport_size(struct GPUFrameBuffer *fb_read, int x, int y, int w, int h);
+void DRW_framebuffer_free(struct GPUFrameBuffer *fb);
+#define DRW_FRAMEBUFFER_FREE_SAFE(fb) do { \
+ if (fb != NULL) { \
+ DRW_framebuffer_free(fb); \
+ fb = NULL; \
+ } \
+} while (0)
+
+void DRW_transform_to_display(struct GPUTexture *tex);
+
+/* 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_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);
+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_LESS = (1 << 2),
+ DRW_STATE_DEPTH_EQUAL = (1 << 3),
+ DRW_STATE_DEPTH_GREATER = (1 << 4),
+ DRW_STATE_DEPTH_ALWAYS = (1 << 5),
+ DRW_STATE_CULL_BACK = (1 << 6),
+ DRW_STATE_CULL_FRONT = (1 << 7),
+ DRW_STATE_WIRE = (1 << 8),
+ DRW_STATE_WIRE_LARGE = (1 << 9),
+ DRW_STATE_POINT = (1 << 10),
+ DRW_STATE_STIPPLE_2 = (1 << 11),
+ DRW_STATE_STIPPLE_3 = (1 << 12),
+ DRW_STATE_STIPPLE_4 = (1 << 13),
+ DRW_STATE_BLEND = (1 << 14),
+ DRW_STATE_ADDITIVE = (1 << 15),
+ DRW_STATE_MULTIPLY = (1 << 16),
+ DRW_STATE_TRANSMISSION = (1 << 17),
+ DRW_STATE_CLIP_PLANES = (1 << 18),
+
+ DRW_STATE_WRITE_STENCIL_SELECT = (1 << 27),
+ DRW_STATE_WRITE_STENCIL_ACTIVE = (1 << 28),
+ DRW_STATE_TEST_STENCIL_SELECT = (1 << 29),
+ DRW_STATE_TEST_STENCIL_ACTIVE = (1 << 30),
+} DRWState;
+
+#define DRW_STATE_DEFAULT (DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS)
+
+
+DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass);
+DRWShadingGroup *DRW_shgroup_material_create(struct GPUMaterial *material, DRWPass *pass);
+DRWShadingGroup *DRW_shgroup_material_instance_create(struct GPUMaterial *material, DRWPass *pass, struct Gwn_Batch *geom);
+DRWShadingGroup *DRW_shgroup_instance_create(struct GPUShader *shader, DRWPass *pass, struct Gwn_Batch *geom);
+DRWShadingGroup *DRW_shgroup_point_batch_create(struct GPUShader *shader, DRWPass *pass);
+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);
+
+typedef void (DRWCallGenerateFn)(
+ DRWShadingGroup *shgroup,
+ void (*draw_fn)(DRWShadingGroup *shgroup, struct Gwn_Batch *geom),
+ void *user_data);
+
+void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct Gwn_Batch *instances);
+
+void DRW_shgroup_free(struct DRWShadingGroup *shgroup);
+void DRW_shgroup_call_add(DRWShadingGroup *shgroup, struct Gwn_Batch *geom, float (*obmat)[4]);
+void DRW_shgroup_call_object_add(DRWShadingGroup *shgroup, struct Gwn_Batch *geom, struct Object *ob);
+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[], unsigned int 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)
+#define DRW_shgroup_call_dynamic_add_empty(shgroup) do { \
+ DRW_shgroup_call_dynamic_add_array(shgroup, NULL, 0); \
+} while (0)
+void DRW_shgroup_set_instance_count(DRWShadingGroup *shgroup, int count);
+
+void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state);
+void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state);
+void DRW_shgroup_attrib_float(DRWShadingGroup *shgroup, const char *name, int size);
+
+void DRW_shgroup_uniform_texture(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_buffer(DRWShadingGroup *shgroup, const char *name, struct GPUTexture **tex);
+void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const char *name, const bool *value, int arraysize);
+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);
+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_mat3(DRWShadingGroup *shgroup, const char *name, const float *value);
+void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float *value);
+
+/* Passes */
+DRWPass *DRW_pass_create(const char *name, 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);
+
+/* Viewport */
+typedef enum {
+ DRW_MAT_PERS = 0,
+ DRW_MAT_PERSINV,
+ DRW_MAT_VIEW,
+ DRW_MAT_VIEWINV,
+ DRW_MAT_WIN,
+ DRW_MAT_WININV,
+} DRWViewportMatrixType;
+
+void DRW_viewport_init(const bContext *C);
+void DRW_viewport_matrix_get(float mat[4][4], DRWViewportMatrixType type);
+void DRW_viewport_matrix_override_set(float mat[4][4], DRWViewportMatrixType type);
+void DRW_viewport_matrix_override_unset(DRWViewportMatrixType type);
+const float *DRW_viewport_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);
+
+/* SceneLayers */
+void **DRW_scene_layer_engine_data_get(DrawEngineType *engine_type, void (*callback)(void *storage));
+
+/* Objects */
+void **DRW_object_engine_data_get(
+ Object *ob, DrawEngineType *engine_type, void (*callback)(void *storage));
+struct LampEngineData *DRW_lamp_engine_data_get(Object *ob, struct RenderEngineType *engine_type);
+void DRW_lamp_engine_data_free(struct LampEngineData *led);
+
+/* Settings */
+bool DRW_object_is_renderable(struct Object *ob);
+bool DRW_object_is_flat_normal(const struct Object *ob);
+int DRW_object_is_mode_shade(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);
+
+int DRW_draw_region_engine_info_offset(void);
+void DRW_draw_region_engine_info(void);
+
+void DRW_state_reset_ex(DRWState state);
+void DRW_state_reset(void);
+
+void DRW_state_invert_facing(void);
+
+void DRW_state_clip_planes_add(float plane_eq[4]);
+void DRW_state_clip_planes_reset(void);
+
+/* Selection */
+void DRW_select_load_id(unsigned int 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_show_text(void);
+bool DRW_state_draw_support(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 SceneLayer *scene_layer; /* 'CTX_data_scene_layer(C)' */
+
+ /* Use 'scene->obedit' for edit-mode */
+ struct Object *obact; /* 'OBACT_NEW' */
+
+ /* 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;
+} DRWContextState;
+
+const DRWContextState *DRW_context_state_get(void);
+
+#endif /* __DRW_RENDER_H__ */
diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c
new file mode 100644
index 00000000000..e31fbeb054c
--- /dev/null
+++ b/source/blender/draw/intern/draw_armature.c
@@ -0,0 +1,1442 @@
+/*
+ * 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))
+
+/* 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_box_solid;
+ DRWShadingGroup *bone_box_wire;
+ DRWShadingGroup *bone_wire_wire;
+ DRWShadingGroup *bone_envelope_solid;
+ DRWShadingGroup *bone_envelope_distance;
+ DRWShadingGroup *bone_envelope_wire;
+ DRWShadingGroup *bone_envelope_head_wire;
+ DRWShadingGroup *bone_point_solid;
+ DRWShadingGroup *bone_point_wire;
+ DRWShadingGroup *bone_axes;
+ DRWShadingGroup *relationship_lines;
+
+ DRWPass *pass_bone_solid;
+ DRWPass *pass_bone_wire;
+ DRWPass *pass_bone_envelope;
+} g_data = {NULL};
+
+/* -------------------------------------------------------------------- */
+
+/** \name Shader Groups (DRW_shgroup)
+ * \{ */
+
+/* Octahedral */
+static void DRW_shgroup_bone_octahedral_solid(const float (*bone_mat)[4], const float color[4])
+{
+ if (g_data.bone_octahedral_solid == NULL) {
+ struct Gwn_Batch *geom = DRW_cache_bone_octahedral_get();
+ g_data.bone_octahedral_solid = shgroup_instance_objspace_solid(g_data.pass_bone_solid, geom, g_data.ob->obmat);
+ }
+
+ DRW_shgroup_call_dynamic_add(g_data.bone_octahedral_solid, bone_mat, color);
+}
+
+static void DRW_shgroup_bone_octahedral_wire(const float (*bone_mat)[4], const float color[4])
+{
+ if (g_data.bone_octahedral_wire == NULL) {
+ struct Gwn_Batch *geom = DRW_cache_bone_octahedral_wire_outline_get();
+ g_data.bone_octahedral_wire = shgroup_instance_objspace_wire(g_data.pass_bone_wire, geom, g_data.ob->obmat);
+ }
+
+ DRW_shgroup_call_dynamic_add(g_data.bone_octahedral_wire, bone_mat, color);
+}
+
+/* Box / B-Bone */
+static void DRW_shgroup_bone_box_solid(const float (*bone_mat)[4], const float color[4])
+{
+ if (g_data.bone_box_solid == NULL) {
+ struct Gwn_Batch *geom = DRW_cache_bone_box_get();
+ g_data.bone_box_solid = shgroup_instance_objspace_solid(g_data.pass_bone_solid, geom, g_data.ob->obmat);
+ }
+
+ DRW_shgroup_call_dynamic_add(g_data.bone_box_solid, bone_mat, color);
+}
+
+static void DRW_shgroup_bone_box_wire(const float (*bone_mat)[4], const float color[4])
+{
+ if (g_data.bone_box_wire == NULL) {
+ struct Gwn_Batch *geom = DRW_cache_bone_box_wire_outline_get();
+ g_data.bone_box_wire = shgroup_instance_objspace_wire(g_data.pass_bone_wire, geom, g_data.ob->obmat);
+ }
+
+ DRW_shgroup_call_dynamic_add(g_data.bone_box_wire, bone_mat, color);
+}
+
+/* Wire */
+static void DRW_shgroup_bone_wire_wire(const float (*bone_mat)[4], const float color[4])
+{
+ if (g_data.bone_wire_wire == NULL) {
+ struct Gwn_Batch *geom = DRW_cache_bone_wire_wire_outline_get();
+ g_data.bone_wire_wire = shgroup_instance_objspace_wire(g_data.pass_bone_wire, geom, g_data.ob->obmat);
+ }
+
+ DRW_shgroup_call_dynamic_add(g_data.bone_wire_wire, bone_mat, color);
+}
+
+/* Envelope */
+static void DRW_shgroup_bone_envelope_distance(
+ const float (*bone_mat)[4], const float color[4],
+ const float *radius_head, const float *radius_tail, const float *distance)
+{
+ if (g_data.pass_bone_envelope != NULL) {
+ if (g_data.bone_envelope_distance == NULL) {
+ struct Gwn_Batch *geom = DRW_cache_bone_envelope_distance_outline_get();
+ /* Note: bone_wire draw pass is not really working, think we need another one here? */
+ g_data.bone_envelope_distance = shgroup_instance_bone_envelope_wire(g_data.pass_bone_envelope, geom, g_data.ob->obmat);
+ }
+
+ DRW_shgroup_call_dynamic_add(g_data.bone_envelope_distance, bone_mat, color, radius_head, radius_tail, distance);
+ }
+}
+
+static void DRW_shgroup_bone_envelope_solid(
+ const float (*bone_mat)[4], const float color[4],
+ const float *radius_head, const float *radius_tail)
+{
+ if (g_data.bone_envelope_solid == NULL) {
+ struct Gwn_Batch *geom = DRW_cache_bone_envelope_solid_get();
+ g_data.bone_envelope_solid = shgroup_instance_bone_envelope_solid(g_data.pass_bone_solid, geom, g_data.ob->obmat);
+ }
+
+ DRW_shgroup_call_dynamic_add(g_data.bone_envelope_solid, bone_mat, color, radius_head, radius_tail);
+}
+
+static void DRW_shgroup_bone_envelope_wire(
+ const float (*bone_mat)[4], const float color[4],
+ const float *radius_head, const float *radius_tail, const float *distance)
+{
+ if (g_data.bone_envelope_wire == NULL) {
+ struct Gwn_Batch *geom = DRW_cache_bone_envelope_wire_outline_get();
+ g_data.bone_envelope_wire = shgroup_instance_bone_envelope_wire(g_data.pass_bone_wire, geom, g_data.ob->obmat);
+ }
+
+ DRW_shgroup_call_dynamic_add(g_data.bone_envelope_wire, bone_mat, color, radius_head, radius_tail, distance);
+}
+
+static void DRW_shgroup_bone_envelope_head_wire(
+ const float (*bone_mat)[4], const float color[4],
+ const float *radius_head, const float *radius_tail, const float *distance)
+{
+ if (g_data.bone_envelope_head_wire == NULL) {
+ struct Gwn_Batch *geom = DRW_cache_bone_envelope_head_wire_outline_get();
+ g_data.bone_envelope_head_wire = shgroup_instance_bone_envelope_wire(g_data.pass_bone_wire, geom, g_data.ob->obmat);
+ }
+
+ DRW_shgroup_call_dynamic_add(g_data.bone_envelope_head_wire, bone_mat, color, radius_head, radius_tail, distance);
+}
+
+/* Custom (geometry) */
+
+static void DRW_shgroup_bone_custom_solid(const float (*bone_mat)[4], const float color[4], Object *custom)
+{
+ /* grr, not re-using instances! */
+ struct Gwn_Batch *geom = DRW_cache_object_surface_get(custom);
+ if (geom) {
+ DRWShadingGroup *shgrp_geom_solid = shgroup_instance_objspace_solid(g_data.pass_bone_solid, geom, g_data.ob->obmat);
+ DRW_shgroup_call_dynamic_add(shgrp_geom_solid, bone_mat, 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 Gwn_Batch *geom = DRW_cache_object_wire_outline_get(custom);
+ if (geom) {
+ DRWShadingGroup *shgrp_geom_wire = shgroup_instance_objspace_wire(g_data.pass_bone_wire, geom, g_data.ob->obmat);
+ DRW_shgroup_call_dynamic_add(shgrp_geom_wire, bone_mat, color);
+ }
+}
+
+/* Head and tail sphere */
+static void DRW_shgroup_bone_point_solid(const float (*bone_mat)[4], const float color[4])
+{
+ if (g_data.bone_point_solid == NULL) {
+ struct Gwn_Batch *geom = DRW_cache_bone_point_get();
+ g_data.bone_point_solid = shgroup_instance_objspace_solid(g_data.pass_bone_solid, geom, g_data.ob->obmat);
+ }
+
+ DRW_shgroup_call_dynamic_add(g_data.bone_point_solid, bone_mat, color);
+}
+
+static void DRW_shgroup_bone_point_wire(const float (*bone_mat)[4], const float color[4])
+{
+ if (g_data.bone_point_wire == NULL) {
+ struct Gwn_Batch *geom = DRW_cache_bone_point_wire_outline_get();
+ g_data.bone_point_wire = shgroup_instance_objspace_wire(g_data.pass_bone_wire, geom, g_data.ob->obmat);
+ }
+
+ DRW_shgroup_call_dynamic_add(g_data.bone_point_wire, bone_mat, color);
+}
+
+/* Axes */
+static void DRW_shgroup_bone_axes(const float (*bone_mat)[4], const float color[4])
+{
+ if (g_data.bone_axes == NULL) {
+ struct Gwn_Batch *geom = DRW_cache_bone_arrows_get();
+ g_data.bone_axes = shgroup_instance_objspace_wire(g_data.pass_bone_wire, geom, g_data.ob->obmat);
+ }
+
+ DRW_shgroup_call_dynamic_add(g_data.bone_axes, bone_mat, color);
+}
+
+/* Relationship lines */
+static void UNUSED_FUNCTION(DRW_shgroup_bone_relationship_lines)(const float head[3], const float tail[3])
+{
+ DRW_shgroup_call_dynamic_add(g_data.relationship_lines, head);
+ DRW_shgroup_call_dynamic_add(g_data.relationship_lines, tail);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Drawing Theme Helpers
+ *
+ * Note, this section is duplicate of code in 'drawarmature.c'.
+ *
+ * \{ */
+
+/* global here is reset before drawing each bone */
+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(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_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) {
+ unsigned char 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:
+ {
+ if (bcolor) {
+ rgb_uchar_to_float(fcolor, (unsigned char *)bcolor->solid);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor);
+ }
+
+ return true;
+ }
+ case PCHAN_COLOR_CONSTS:
+ {
+ if ((bcolor == NULL) || (bcolor->flag & TH_WIRECOLOR_CONSTCOLS)) {
+ unsigned char 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);
+
+ rgba_uchar_to_float(fcolor, cp);
+
+ return true;
+ }
+ return false;
+ }
+ case PCHAN_COLOR_SPHEREBONE_BASE:
+ {
+ if (bcolor) {
+ unsigned char 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) {
+ unsigned char 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))) {
+ unsigned char 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, (unsigned char *)cp);
+ fcolor[3] = 204.f / 255.f;
+ }
+ else {
+ UI_GetThemeColorShade4fv(TH_BACK, -30, fcolor);
+ }
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Drawing Color Helpers
+ * \{ */
+
+/**
+ * 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;
+} g_theme;
+
+/** See: 'set_pchan_color'*/
+static void update_color(const float const_color[4])
+{
+ g_theme.const_color = const_color;
+
+#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 *eBone, const bPoseChannel *pchan, const bArmature *arm,
+ const int boneflag, const short constflag)
+{
+ if (g_theme.const_color)
+ return g_theme.bone_solid_color;
+
+#ifdef USE_SOLID_COLOR
+ /* Edit Mode */
+ if (eBone) {
+ bool is_active = (arm->act_edbone == eBone);
+ if (eBone->flag & BONE_SELECTED) {
+ if (is_active) {
+ return g_theme.edge_select_color;
+ }
+ else {
+ return g_theme.bone_select_color;
+ }
+ }
+ }
+ else if (arm->flag & ARM_POSEMODE) {
+ bool is_active = (arm->act_bone == pchan->bone);
+ if (pchan->bone->flag & BONE_SELECTED) {
+ if (is_active) {
+ return g_theme.bone_pose_active_color;
+ }
+ else {
+ return g_theme.bone_pose_color;
+ }
+ }
+ }
+#else
+ if (arm->drawtype == ARM_ENVELOPE) {
+ /* Edit Mode */
+ if (eBone) {
+ bool is_active = (arm->act_edbone == eBone);
+ if (eBone->flag & BONE_SELECTED) {
+ if (is_active) {
+ return g_theme.edge_select_color;
+ }
+ else {
+ return g_theme.bone_select_color;
+ }
+ }
+ }
+ else if (arm->flag & ARM_POSEMODE) {
+ bool is_active = (arm->act_bone == pchan->bone);
+ if (pchan->bone->flag & BONE_SELECTED) {
+ if (is_active) {
+ return g_theme.bone_pose_active_color;
+ }
+ else {
+ return g_theme.bone_pose_color;
+ }
+ }
+ }
+ }
+#endif
+
+ if (arm->flag & ARM_POSEMODE) {
+ float *disp_color = pchan->draw_data->solid_color;
+ set_pchan_color(PCHAN_COLOR_SOLID, boneflag, constflag, disp_color);
+ disp_color[3] = 1.0;
+ return disp_color;
+ }
+
+ return g_theme.bone_solid_color;
+}
+
+static const float *get_bone_wire_color(
+ const EditBone *eBone, const bPoseChannel *pchan, const bArmature *arm,
+ const int boneflag, const short constflag)
+{
+ if (g_theme.const_color)
+ return g_theme.const_color;
+
+ if (eBone) {
+ if (boneflag & BONE_SELECTED) {
+ if (boneflag & BONE_DRAW_ACTIVE) {
+ return g_theme.edge_select_color;
+ }
+ else {
+ return g_theme.bone_select_color;
+ }
+ }
+ else {
+ if (boneflag & BONE_DRAW_ACTIVE) {
+ return g_theme.bone_active_unselect_color;
+ }
+ else {
+ return g_theme.wire_edit_color;
+ }
+ }
+ }
+ else if (arm->flag & ARM_POSEMODE) {
+ float *disp_color = pchan->draw_data->wire_color;
+ set_pchan_color(PCHAN_COLOR_NORMAL, boneflag, constflag, disp_color);
+ disp_color[3] = 1.0;
+ return disp_color;
+
+
+#if 0
+ if (boneflag & BONE_SELECTED) {
+ if (is_active) {
+ return g_theme.bone_pose_active_color;
+ }
+ else {
+ return g_theme.bone_pose_color;
+ }
+ }
+ else {
+ if (is_active) {
+ return g_theme.bone_pose_active_unselect_color;
+ }
+ else {
+ return g_theme.wire_color;
+ }
+ }
+#endif
+ }
+
+ return g_theme.vertex_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);
+}
+
+/* XXX Direct copy from drawarmature.c... This is ugly! */
+/* 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, float result_array[MAX_BBONE_SUBDIV][4][4])
+{
+ 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], mat3);
+ copy_v3_v3(result_array[a][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], result_array[a], bscalemat);
+ }
+ }
+}
+
+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) {
+ b_bone_spline_setup(pchan, 0, 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)
+{
+ 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;
+
+ DRW_shgroup_bone_axes(BONE_VAR(eBone, pchan, disp_mat), col);
+}
+
+static void draw_points(
+ const EditBone *eBone, const bPoseChannel *pchan, const bArmature *arm,
+ const int boneflag, const short constflag,
+ const int select_id)
+{
+ const float *col_solid_root = g_theme.bone_solid_color;
+ const float *col_solid_tail = g_theme.bone_solid_color;
+ const float *col_wire_root = (g_theme.const_color) ? g_theme.const_color : g_theme.vertex_color;
+ const float *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;
+
+ /* Edit bone points can be selected */
+ if (eBone) {
+ if (eBone->flag & BONE_ROOTSEL) {
+#ifdef USE_SOLID_COLOR
+ col_solid_root = g_theme.vertex_select_color;
+#else
+ if (is_envelope_draw) {
+ col_solid_root = g_theme.vertex_select_color;
+ }
+#endif
+ col_wire_root = g_theme.vertex_select_color;
+ }
+ if (eBone->flag & BONE_TIPSEL) {
+#ifdef USE_SOLID_COLOR
+ col_solid_tail = g_theme.vertex_select_color;
+#else
+ if (is_envelope_draw) {
+ col_solid_tail = g_theme.vertex_select_color;
+ }
+#endif
+ col_wire_tail = g_theme.vertex_select_color;
+ }
+ }
+ else if (arm->flag & ARM_POSEMODE) {
+ col_solid_root = col_solid_tail = get_bone_solid_color(eBone, pchan, arm, boneflag, constflag);
+ col_wire_root = col_wire_tail = get_bone_wire_color(eBone, pchan, arm, boneflag, constflag);
+ }
+
+ /* 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_solid(eBone->disp_mat, col_solid_root,
+ &eBone->rad_head, &envelope_ignore);
+ DRW_shgroup_bone_envelope_head_wire(eBone->disp_mat, col_wire_root,
+ &eBone->rad_head, &envelope_ignore, &envelope_ignore);
+ }
+ else {
+ DRW_shgroup_bone_point_solid(eBone->disp_mat, col_solid_root);
+ DRW_shgroup_bone_point_wire(eBone->disp_mat, 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_solid(pchan->disp_mat, col_solid_root,
+ &bone->rad_head, &envelope_ignore);
+ DRW_shgroup_bone_envelope_head_wire(pchan->disp_mat, col_wire_root,
+ &bone->rad_head, &envelope_ignore, &envelope_ignore);
+ }
+ else {
+ DRW_shgroup_bone_point_solid(pchan->disp_mat, col_solid_root);
+ DRW_shgroup_bone_point_wire(pchan->disp_mat, 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_solid(
+ BONE_VAR(eBone, pchan, disp_mat), col_solid_tail, &envelope_ignore, rad_tail);
+ DRW_shgroup_bone_envelope_head_wire(
+ BONE_VAR(eBone, pchan, disp_mat), col_wire_tail, &envelope_ignore, rad_tail, &envelope_ignore);
+ }
+ else {
+ DRW_shgroup_bone_point_solid(BONE_VAR(eBone, pchan, disp_tail_mat), col_solid_tail);
+ DRW_shgroup_bone_point_wire(BONE_VAR(eBone, pchan, disp_tail_mat), 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 (*disp_mat)[4] = pchan->disp_mat;
+
+ if (select_id != -1) {
+ DRW_select_load_id(select_id | BONESEL_BONE);
+ }
+
+ DRW_shgroup_bone_custom_solid(disp_mat, col_solid, pchan->custom);
+ 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_color(eBone, pchan, arm, boneflag, constflag);
+ const float *col_wire = get_bone_wire_color(eBone, pchan, arm, boneflag, constflag);
+
+ static const float col_white[4] = {1.0f, 1.0f, 1.0f, 0.2f};
+
+ 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 ((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), col_white, rad_head, rad_tail, distance);
+ }
+
+ if (select_id != -1) {
+ DRW_select_load_id(select_id | BONESEL_BONE);
+ }
+
+ DRW_shgroup_bone_envelope_solid(BONE_VAR(eBone, pchan, disp_mat), col_solid, rad_head, rad_tail);
+ DRW_shgroup_bone_envelope_wire(BONE_VAR(eBone, pchan, disp_mat), col_wire, rad_head, rad_tail, distance);
+
+ if (select_id != -1) {
+ DRW_select_load_id(-1);
+ }
+
+ draw_points(eBone, pchan, arm, boneflag, constflag, select_id);
+}
+
+static void draw_bone_line(
+ EditBone *UNUSED(eBone), bPoseChannel *UNUSED(pchan), bArmature *UNUSED(arm),
+ const int UNUSED(boneflag), const short UNUSED(constflag),
+ const int UNUSED(select_id))
+{
+ /* work in progress -- fclem */
+}
+
+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_wire(bbones_mat->mat, col_wire);
+ }
+ }
+ else if (eBone) {
+ for (int i = 0; i < eBone->segments; i++) {
+ DRW_shgroup_bone_wire_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_color(eBone, pchan, arm, boneflag, constflag);
+ 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_box_solid(bbones_mat->mat, col_solid);
+ DRW_shgroup_bone_box_wire(bbones_mat->mat, col_wire);
+ }
+ }
+ else if (eBone) {
+ for (int i = 0; i < eBone->segments; i++) {
+ DRW_shgroup_bone_box_solid(eBone->disp_bbone_mat[i], col_solid);
+ DRW_shgroup_bone_box_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_octahedral(
+ 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);
+
+ if (select_id != -1) {
+ DRW_select_load_id(select_id | BONESEL_BONE);
+ }
+
+ DRW_shgroup_bone_octahedral_solid(BONE_VAR(eBone, pchan, disp_mat), col_solid);
+ DRW_shgroup_bone_octahedral_wire(BONE_VAR(eBone, pchan, disp_mat), col_wire);
+
+ if (select_id != -1) {
+ DRW_select_load_id(-1);
+ }
+
+ draw_points(eBone, pchan, arm, boneflag, constflag, select_id);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Main Draw Loops
+ * \{ */
+
+static void draw_armature_edit(Object *ob)
+{
+ EditBone *eBone;
+ bArmature *arm = ob->data;
+ int index;
+ const bool is_select = DRW_state_is_select();
+
+ update_color(NULL);
+
+ const bool show_text = DRW_state_show_text();
+
+ for (eBone = arm->edbo->first, index = 0; eBone; eBone = eBone->next, index++) {
+ if (eBone->layer & arm->layer) {
+ if ((eBone->flag & BONE_HIDDEN_A) == 0) {
+ const int select_id = is_select ? index : (unsigned int)-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;
+ }
+
+ 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)) {
+ unsigned char 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, 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])
+{
+ bArmature *arm = ob->data;
+ bPoseChannel *pchan;
+ int index = -1;
+ Bone *bone;
+
+ update_color(const_color);
+
+ /* We can't safely draw non-updated pose, might contain NULL bone pointers... */
+ if (ob->pose->flag & POSE_RECALC) {
+ BKE_pose_rebuild(ob, arm);
+ }
+
+ // if (!(base->flag & OB_FROMDUPLI)) // TODO
+ {
+ if (ob->mode & OB_MODE_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();
+
+ /* being set below */
+ arm->layer_used = 0;
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ bone = pchan->bone;
+ arm->layer_used |= bone->layer;
+
+ /* 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 : (unsigned int)-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;
+
+
+ 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);
+ }
+
+ /* Draw names of bone */
+ if (show_text && (arm->flag & ARM_DRAWNAMES)) {
+ unsigned char 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, 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, DRWPass *pass_bone_solid, DRWPass *pass_bone_wire, DRWPass *pass_bone_envelope,
+ DRWShadingGroup *shgrp_relationship_lines)
+{
+ memset(&g_data, 0x0, sizeof(g_data));
+ g_data.ob = ob;
+
+ g_data.pass_bone_solid = pass_bone_solid;
+ g_data.pass_bone_wire = pass_bone_wire;
+ g_data.pass_bone_envelope = pass_bone_envelope;
+ g_data.relationship_lines = shgrp_relationship_lines;
+
+ memset(&g_color, 0x0, sizeof(g_color));
+}
+
+void DRW_shgroup_armature_object(
+ Object *ob, SceneLayer *sl, DRWPass *pass_bone_solid, DRWPass *pass_bone_wire, DRWPass *UNUSED(pass_bone_envelope),
+ DRWShadingGroup *shgrp_relationship_lines)
+{
+ float *color;
+ DRW_object_wire_theme_get(ob, sl, &color);
+
+ DRW_shgroup_armature(ob, pass_bone_solid, pass_bone_wire, NULL, shgrp_relationship_lines);
+ draw_armature_pose(ob, color);
+}
+
+void DRW_shgroup_armature_pose(
+ Object *ob, DRWPass *pass_bone_solid, DRWPass *pass_bone_wire, DRWPass *pass_bone_envelope,
+ DRWShadingGroup *shgrp_relationship_lines)
+{
+ DRW_shgroup_armature(ob, pass_bone_solid, pass_bone_wire, pass_bone_envelope, shgrp_relationship_lines);
+ draw_armature_pose(ob, NULL);
+}
+
+void DRW_shgroup_armature_edit(
+ Object *ob, DRWPass *pass_bone_solid, DRWPass *pass_bone_wire, DRWPass *pass_bone_envelope,
+ DRWShadingGroup *shgrp_relationship_lines)
+{
+ DRW_shgroup_armature(ob, pass_bone_solid, pass_bone_wire, pass_bone_envelope, shgrp_relationship_lines);
+ 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..c0338de3d54
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache.c
@@ -0,0 +1,2586 @@
+/*
+ * 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_curve_types.h"
+#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_lattice_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "GPU_batch.h"
+
+#include "draw_cache.h"
+#include "draw_cache_impl.h"
+
+static struct DRWShapeCache {
+ Gwn_Batch *drw_single_vertice;
+ Gwn_Batch *drw_fullscreen_quad;
+ Gwn_Batch *drw_screenspace_circle;
+ Gwn_Batch *drw_plain_axes;
+ Gwn_Batch *drw_single_arrow;
+ Gwn_Batch *drw_cube;
+ Gwn_Batch *drw_circle;
+ Gwn_Batch *drw_square;
+ Gwn_Batch *drw_line;
+ Gwn_Batch *drw_line_endpoints;
+ Gwn_Batch *drw_empty_sphere;
+ Gwn_Batch *drw_empty_cone;
+ Gwn_Batch *drw_arrows;
+ Gwn_Batch *drw_axis_names;
+ Gwn_Batch *drw_image_plane;
+ Gwn_Batch *drw_image_plane_wire;
+ Gwn_Batch *drw_field_wind;
+ Gwn_Batch *drw_field_force;
+ Gwn_Batch *drw_field_vortex;
+ Gwn_Batch *drw_field_tube_limit;
+ Gwn_Batch *drw_field_cone_limit;
+ Gwn_Batch *drw_lamp;
+ Gwn_Batch *drw_lamp_sunrays;
+ Gwn_Batch *drw_lamp_area;
+ Gwn_Batch *drw_lamp_hemi;
+ Gwn_Batch *drw_lamp_spot;
+ Gwn_Batch *drw_lamp_spot_square;
+ Gwn_Batch *drw_speaker;
+ Gwn_Batch *drw_lightprobe_cube;
+ Gwn_Batch *drw_lightprobe_planar;
+ Gwn_Batch *drw_lightprobe_grid;
+ Gwn_Batch *drw_bone_octahedral;
+ Gwn_Batch *drw_bone_octahedral_wire;
+ Gwn_Batch *drw_bone_box;
+ Gwn_Batch *drw_bone_box_wire;
+ Gwn_Batch *drw_bone_wire_wire;
+ Gwn_Batch *drw_bone_envelope;
+ Gwn_Batch *drw_bone_envelope_distance;
+ Gwn_Batch *drw_bone_envelope_wire;
+ Gwn_Batch *drw_bone_envelope_head_wire;
+ Gwn_Batch *drw_bone_point;
+ Gwn_Batch *drw_bone_point_wire;
+ Gwn_Batch *drw_bone_arrows;
+ Gwn_Batch *drw_camera;
+ Gwn_Batch *drw_camera_tria;
+ Gwn_Batch *drw_camera_focus;
+ Gwn_Batch *drw_particle_cross;
+ Gwn_Batch *drw_particle_circle;
+ Gwn_Batch *drw_particle_axis;
+} SHC = {NULL};
+
+void DRW_shape_cache_free(void)
+{
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_single_vertice);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_fullscreen_quad);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_plain_axes);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_single_arrow);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_cube);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_circle);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_square);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_line);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_line_endpoints);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_empty_sphere);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_empty_cone);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_arrows);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_axis_names);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_image_plane);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_image_plane_wire);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_field_wind);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_field_force);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_field_vortex);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_field_tube_limit);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_field_cone_limit);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_lamp);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_lamp_sunrays);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_lamp_area);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_lamp_hemi);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_lamp_spot);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_lamp_spot_square);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_speaker);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_lightprobe_cube);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_lightprobe_planar);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_lightprobe_grid);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_octahedral);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_octahedral_wire);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_box);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_box_wire);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_wire_wire);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_envelope);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_envelope_distance);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_envelope_wire);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_envelope_head_wire);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_point);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_point_wire);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_bone_arrows);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_camera);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_camera_tria);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_camera_focus);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_particle_cross);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_particle_circle);
+ BATCH_DISCARD_ALL_SAFE(SHC.drw_particle_axis);
+}
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Helper functions
+ * \{ */
+
+static void add_fancy_edge(
+ Gwn_VertBuf *vbo, unsigned int pos_id, unsigned int n1_id, unsigned int n2_id,
+ unsigned int *v_idx, const float co1[3], const float co2[3],
+const float n1[3], const float n2[3])
+{
+ GWN_vertbuf_attr_set(vbo, n1_id, *v_idx, n1);
+ GWN_vertbuf_attr_set(vbo, n2_id, *v_idx, n2);
+ GWN_vertbuf_attr_set(vbo, pos_id, (*v_idx)++, co1);
+
+ GWN_vertbuf_attr_set(vbo, n1_id, *v_idx, n1);
+ GWN_vertbuf_attr_set(vbo, n2_id, *v_idx, n2);
+ GWN_vertbuf_attr_set(vbo, pos_id, (*v_idx)++, co2);
+}
+
+static void add_lat_lon_vert(
+ Gwn_VertBuf *vbo, unsigned int pos_id, unsigned int nor_id,
+ unsigned int *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);
+
+ GWN_vertbuf_attr_set(vbo, nor_id, *v_idx, nor);
+ GWN_vertbuf_attr_set(vbo, pos_id, (*v_idx)++, pos);
+}
+
+static Gwn_VertBuf *fill_arrows_vbo(const float scale)
+{
+ /* Position Only 3D format */
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ /* Line */
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_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);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, axis * 6 + 0, vtmp1);
+ GWN_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);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, axis * 6 + 2, vtmp1);
+ GWN_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);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, axis * 6 + 4, vtmp1);
+ GWN_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;
+}
+
+static Gwn_VertBuf *sphere_wire_vbo(const float rad)
+{
+#define NSEGMENTS 32
+ /* Position Only 3D format */
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_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)
+ v[0] = cv[0], v[1] = cv[1], v[2] = 0.0f;
+ else if (axis == 1)
+ v[0] = cv[0], v[1] = 0.0f, v[2] = cv[1];
+ else
+ v[0] = 0.0f, v[1] = cv[0], v[2] = cv[1];
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, i * 2 + j + (NSEGMENTS * 2 * axis), v);
+ }
+ }
+ }
+
+ return vbo;
+#undef NSEGMENTS
+}
+
+/* Quads */
+Gwn_Batch *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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos, uvs; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ attr_id.uvs = GWN_vertformat_attr_add(&format, "uvs", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 3);
+
+ for (int i = 0; i < 3; ++i) {
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, i, pos[i]);
+ GWN_vertbuf_attr_set(vbo, attr_id.uvs, i, uvs[i]);
+ }
+
+ SHC.drw_fullscreen_quad = GWN_batch_create(GWN_PRIM_TRIS, vbo, NULL);
+ }
+ return SHC.drw_fullscreen_quad;
+}
+
+/* Sphere */
+Gwn_Batch *DRW_cache_sphere_get(void)
+{
+ return Batch_get_sphere(2);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Common
+ * \{ */
+
+Gwn_Batch *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 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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 24);
+
+ for (int i = 0; i < 24; ++i) {
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, i, verts[indices[i]]);
+ }
+
+ SHC.drw_cube = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_cube;
+}
+
+Gwn_Batch *DRW_cache_circle_get(void)
+{
+#define CIRCLE_RESOL 32
+ if (!SHC.drw_circle) {
+ float v[3] = {0.0f, 0.0f, 0.0f};
+
+ /* Position Only 3D format */
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, CIRCLE_RESOL * 2);
+
+ 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;
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 2, v);
+
+ v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
+ v[2] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
+ v[1] = 0.0f;
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 2 + 1, v);
+ }
+
+ SHC.drw_circle = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_circle;
+#undef CIRCLE_RESOL
+}
+
+Gwn_Batch *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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 8);
+
+ for (int i = 0; i < 4; i++) {
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, i * 2, p[i % 4]);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, i * 2 + 1, p[(i+1) % 4]);
+ }
+
+ SHC.drw_square = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_square;
+}
+
+Gwn_Batch *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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 2);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 0, v1);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 1, v2);
+
+ SHC.drw_line = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_line;
+}
+
+Gwn_Batch *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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 2);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 0, v1);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 1, v2);
+
+ SHC.drw_line_endpoints = GWN_batch_create(GWN_PRIM_POINTS, vbo, NULL);
+ }
+ return SHC.drw_line_endpoints;
+}
+
+Gwn_Batch *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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_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));
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, a, v);
+ }
+
+ SHC.drw_screenspace_circle = GWN_batch_create(GWN_PRIM_LINE_STRIP, vbo, NULL);
+ }
+ return SHC.drw_screenspace_circle;
+#undef CIRCLE_RESOL
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Common Object API
+ * \{ */
+
+Gwn_Batch *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;
+ }
+}
+
+Gwn_Batch *DRW_cache_object_surface_get(Object *ob)
+{
+ switch (ob->type) {
+ case OB_MESH:
+ return DRW_cache_mesh_surface_get(ob);
+ 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);
+ default:
+ return NULL;
+ }
+}
+
+Gwn_Batch **DRW_cache_object_surface_material_get(
+ struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len)
+{
+ switch (ob->type) {
+ case OB_MESH:
+ return DRW_cache_mesh_surface_shaded_get(ob, gpumat_array, gpumat_array_len);
+ default:
+ return NULL;
+ }
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Empties
+ * \{ */
+
+Gwn_Batch *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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 6);
+
+ for (axis = 0; axis < 3; axis++) {
+ v1[axis] = 1.0f;
+ v2[axis] = -1.0f;
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, axis * 2, v1);
+ GWN_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 = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_plain_axes;
+}
+
+Gwn_Batch *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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ /* Square Pyramid */
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_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];
+ }
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, sides * 3 + 0, v1);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, sides * 3 + 1, v2);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, sides * 3 + 2, v3);
+ }
+
+ SHC.drw_single_arrow = GWN_batch_create(GWN_PRIM_TRIS, vbo, NULL);
+ }
+ return SHC.drw_single_arrow;
+}
+
+Gwn_Batch *DRW_cache_empty_sphere_get(void)
+{
+ if (!SHC.drw_empty_sphere) {
+ Gwn_VertBuf *vbo = sphere_wire_vbo(1.0f);
+ SHC.drw_empty_sphere = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_empty_sphere;
+}
+
+Gwn_Batch *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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_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 */
+ v[0] = cv[0], v[1] = 0.0f, v[2] = cv[1];
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, i * 4, v);
+ v[0] = 0.0f, v[1] = 2.0f, v[2] = 0.0f;
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 1, v);
+
+ /* end ring */
+ v[0] = cv[0], v[1] = 0.0f, v[2] = cv[1];
+ GWN_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];
+ v[0] = cv[0], v[1] = 0.0f, v[2] = cv[1];
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 3, v);
+ }
+
+ SHC.drw_empty_cone = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_empty_cone;
+#undef NSEGMENTS
+}
+
+Gwn_Batch *DRW_cache_arrows_get(void)
+{
+ if (!SHC.drw_arrows) {
+ Gwn_VertBuf *vbo = fill_arrows_vbo(1.0f);
+
+ SHC.drw_arrows = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_arrows;
+}
+
+Gwn_Batch *DRW_cache_axis_names_get(void)
+{
+ if (!SHC.drw_axis_names) {
+ const float size = 0.1f;
+ float v1[3], v2[3];
+
+ /* Position Only 3D format */
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ /* Using 3rd component as axis indicator */
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ /* Line */
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 14);
+
+ /* X */
+ copy_v3_fl3(v1, -size, size, 0.0f);
+ copy_v3_fl3(v2, size, -size, 0.0f);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 0, v1);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 1, v2);
+
+ copy_v3_fl3(v1, size, size, 0.0f);
+ copy_v3_fl3(v2, -size, -size, 0.0f);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 2, v1);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 3, v2);
+
+ /* Y */
+ copy_v3_fl3(v1, -size + 0.25f * size, size, 1.0f);
+ copy_v3_fl3(v2, 0.0f, 0.0f, 1.0f);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 4, v1);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 5, v2);
+
+ copy_v3_fl3(v1, size - 0.25f * size, size, 1.0f);
+ copy_v3_fl3(v2, -size + 0.25f * size, -size, 1.0f);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 6, v1);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 7, v2);
+
+ /* Z */
+ copy_v3_fl3(v1, -size, size, 2.0f);
+ copy_v3_fl3(v2, size, size, 2.0f);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 8, v1);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 9, v2);
+
+ copy_v3_fl3(v1, size, size, 2.0f);
+ copy_v3_fl3(v2, -size, -size, 2.0f);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 10, v1);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 11, v2);
+
+ copy_v3_fl3(v1, -size, -size, 2.0f);
+ copy_v3_fl3(v2, size, -size, 2.0f);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 12, v1);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 13, v2);
+
+ SHC.drw_axis_names = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_axis_names;
+}
+
+Gwn_Batch *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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos, texCoords; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ attr_id.texCoords = GWN_vertformat_attr_add(&format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ }
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 4);
+ for (uint j = 0; j < 4; j++) {
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, j, quad[j]);
+ GWN_vertbuf_attr_set(vbo, attr_id.texCoords, j, quad[j]);
+ }
+ SHC.drw_image_plane = GWN_batch_create(GWN_PRIM_TRI_FAN, vbo, NULL);
+ }
+ return SHC.drw_image_plane;
+}
+
+Gwn_Batch *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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ }
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 4);
+ for (uint j = 0; j < 4; j++) {
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, j, quad[j]);
+ }
+ SHC.drw_image_plane_wire = GWN_batch_create(GWN_PRIM_LINE_LOOP, vbo, NULL);
+ }
+ return SHC.drw_image_plane_wire;
+}
+
+/* Force Field */
+Gwn_Batch *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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_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;
+ GWN_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;
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, i * CIRCLE_RESOL * 2 + a * 2 + 1, v);
+ }
+ }
+
+ SHC.drw_field_wind = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_field_wind;
+#undef CIRCLE_RESOL
+}
+
+Gwn_Batch *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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_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;
+ GWN_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;
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, i * CIRCLE_RESOL * 2 + a * 2 + 1, v);
+ }
+ }
+
+ SHC.drw_field_force = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_field_force;
+#undef CIRCLE_RESOL
+}
+
+Gwn_Batch *DRW_cache_field_vortex_get(void)
+{
+#define SPIRAL_RESOL 32
+ if (!SHC.drw_field_vortex) {
+ float v[3] = {0.0f, 0.0f, 0.0f};
+ unsigned int v_idx = 0;
+
+ /* Position Only 3D format */
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_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);
+
+ GWN_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);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
+ }
+
+ SHC.drw_field_vortex = GWN_batch_create(GWN_PRIM_LINE_STRIP, vbo, NULL);
+ }
+ return SHC.drw_field_vortex;
+#undef SPIRAL_RESOL
+}
+
+Gwn_Batch *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};
+ unsigned int v_idx = 0;
+
+ /* Position Only 3D format */
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_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;
+ GWN_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;
+ GWN_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;
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
+ }
+ }
+
+ SHC.drw_field_tube_limit = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_field_tube_limit;
+#undef CIRCLE_RESOL
+}
+
+Gwn_Batch *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};
+ unsigned int v_idx = 0;
+
+ /* Position Only 3D format */
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_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;
+ GWN_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;
+ GWN_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;
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
+ }
+ }
+
+ SHC.drw_field_cone_limit = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_field_cone_limit;
+#undef CIRCLE_RESOL
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Lamps
+ * \{ */
+
+Gwn_Batch *DRW_cache_lamp_get(void)
+{
+#define NSEGMENTS 8
+ if (!SHC.drw_lamp) {
+ float v[2];
+
+ /* Position Only 3D format */
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, NSEGMENTS * 2);
+
+ for (int a = 0; a < NSEGMENTS; a++) {
+ v[0] = sinf((2.0f * M_PI * a) / ((float)NSEGMENTS));
+ v[1] = cosf((2.0f * M_PI * a) / ((float)NSEGMENTS));
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 2, v);
+
+ v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS));
+ v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS));
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 2 + 1, v);
+ }
+
+ SHC.drw_lamp = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_lamp;
+#undef NSEGMENTS
+}
+
+Gwn_Batch *DRW_cache_lamp_sunrays_get(void)
+{
+ if (!SHC.drw_lamp_sunrays) {
+ float v[2], v1[2], v2[2];
+
+ /* Position Only 3D format */
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 16);
+
+ 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.2f);
+ mul_v2_v2fl(v2, v, 2.5f);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 2, v1);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 2 + 1, v2);
+ }
+
+ SHC.drw_lamp_sunrays = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_lamp_sunrays;
+}
+
+Gwn_Batch *DRW_cache_lamp_area_get(void)
+{
+ if (!SHC.drw_lamp_area) {
+ float v1[3] = {0.0f, 0.0f, 0.0f};
+
+ /* Position Only 3D format */
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 8);
+
+ v1[0] = v1[1] = 0.5f;
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 0, v1);
+ v1[0] = -0.5f;
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 1, v1);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 2, v1);
+ v1[1] = -0.5f;
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 3, v1);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 4, v1);
+ v1[0] = 0.5f;
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 5, v1);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 6, v1);
+ v1[1] = 0.5f;
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 7, v1);
+
+ SHC.drw_lamp_area = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_lamp_area;
+}
+
+Gwn_Batch *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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_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;
+ GWN_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;
+ GWN_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;
+ GWN_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;
+ GWN_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));
+ GWN_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));
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+ }
+
+
+ SHC.drw_lamp_hemi = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_lamp_hemi;
+#undef CIRCLE_RESOL
+}
+
+
+Gwn_Batch *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]);
+ }
+
+ /* Position Only 3D format */
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos, n1, n2; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ attr_id.n1 = GWN_vertformat_attr_add(&format, "N1", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ attr_id.n2 = GWN_vertformat_attr_add(&format, "N2", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_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 */
+ v[0] = cv[0], v[1] = cv[1], v[2] = -1.0f;
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, i * 4, v);
+ v[0] = 0.0f, v[1] = 0.0f, v[2] = 0.0f;
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 1, v);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.n1, i * 4, n[(i) % NSEGMENTS]);
+ GWN_vertbuf_attr_set(vbo, attr_id.n1, i * 4 + 1, n[(i) % NSEGMENTS]);
+ GWN_vertbuf_attr_set(vbo, attr_id.n2, i * 4, n[(i+1) % NSEGMENTS]);
+ GWN_vertbuf_attr_set(vbo, attr_id.n2, i * 4 + 1, n[(i+1) % NSEGMENTS]);
+
+ /* end ring */
+ v[0] = cv[0], v[1] = cv[1], v[2] = -1.0f;
+ GWN_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];
+ v[0] = cv[0], v[1] = cv[1], v[2] = -1.0f;
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 3, v);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.n1, i * 4 + 2, n[(i) % NSEGMENTS]);
+ GWN_vertbuf_attr_set(vbo, attr_id.n1, i * 4 + 3, n[(i) % NSEGMENTS]);
+ GWN_vertbuf_attr_set(vbo, attr_id.n2, i * 4 + 2, neg[(i) % NSEGMENTS]);
+ GWN_vertbuf_attr_set(vbo, attr_id.n2, i * 4 + 3, neg[(i) % NSEGMENTS]);
+ }
+
+ SHC.drw_lamp_spot = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_lamp_spot;
+#undef NSEGMENTS
+}
+
+Gwn_Batch *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}};
+
+ unsigned int v_idx = 0;
+
+ /* Position Only 3D format */
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 16);
+
+ /* piramid sides */
+ for (int i = 1; i <= 4; ++i) {
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[0]);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[i]);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[(i % 4)+1]);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[((i+1) % 4)+1]);
+ }
+
+ SHC.drw_lamp_spot_square = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_lamp_spot_square;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Speaker
+ * \{ */
+
+Gwn_Batch *DRW_cache_speaker_get(void)
+{
+ if (!SHC.drw_speaker) {
+ float v[3];
+ const int segments = 16;
+ int vidx = 0;
+
+ /* Position Only 3D format */
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_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);
+ GWN_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);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+ }
+ copy_v3_fl3(v, r, 0.0f, z);
+ GWN_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);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+ if (i == 1) {
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+ }
+ }
+ }
+
+ SHC.drw_speaker = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_speaker;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Probe
+ * \{ */
+
+Gwn_Batch *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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, (6 + 3) * 2);
+
+ for (int i = 0; i < 6; ++i) {
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[i]);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[(i + 1) % 6]);
+ }
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[1]);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[5]);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[3]);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
+
+ SHC.drw_lightprobe_cube = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_lightprobe_cube;
+}
+
+Gwn_Batch *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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, (6 * 3 + 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]);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, tmp_v1);
+ GWN_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);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, tmp_v1);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, tmp_v2);
+ }
+ }
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[1]);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[5]);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[3]);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
+
+ SHC.drw_lightprobe_grid = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_lightprobe_grid;
+}
+
+Gwn_Batch *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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 4 * 2);
+
+ for (int i = 0; i < 4; ++i) {
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[i]);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[(i + 1) % 4]);
+ }
+
+ SHC.drw_lightprobe_planar = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ 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 unsigned int 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 unsigned int 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,
+};
+
+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}
+};
+
+Gwn_Batch *DRW_cache_bone_octahedral_get(void)
+{
+ if (!SHC.drw_bone_octahedral) {
+ unsigned int v_idx = 0;
+
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos, nor; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ attr_id.nor = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ /* Vertices */
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 24);
+
+ for (int i = 0; i < 8; i++) {
+ GWN_vertbuf_attr_set(vbo, attr_id.nor, v_idx, bone_octahedral_solid_normals[i]);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, bone_octahedral_verts[bone_octahedral_solid_tris[i][0]]);
+ GWN_vertbuf_attr_set(vbo, attr_id.nor, v_idx, bone_octahedral_solid_normals[i]);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, bone_octahedral_verts[bone_octahedral_solid_tris[i][1]]);
+ GWN_vertbuf_attr_set(vbo, attr_id.nor, v_idx, bone_octahedral_solid_normals[i]);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, bone_octahedral_verts[bone_octahedral_solid_tris[i][2]]);
+ }
+
+ SHC.drw_bone_octahedral = GWN_batch_create(GWN_PRIM_TRIS, vbo, NULL);
+ }
+ return SHC.drw_bone_octahedral;
+}
+
+Gwn_Batch *DRW_cache_bone_octahedral_wire_outline_get(void)
+{
+ if (!SHC.drw_bone_octahedral_wire) {
+ unsigned int v_idx = 0;
+
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos, n1, n2; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ attr_id.n1 = GWN_vertformat_attr_add(&format, "N1", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ attr_id.n2 = GWN_vertformat_attr_add(&format, "N2", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ /* Vertices */
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 12 * 2);
+
+ for (int i = 0; i < 12; i++) {
+ const float *co1 = bone_octahedral_verts[bone_octahedral_wire[i * 2]];
+ const float *co2 = bone_octahedral_verts[bone_octahedral_wire[i * 2 + 1]];
+ const float *n1 = bone_octahedral_solid_normals[bone_octahedral_wire_adjacent_face[i * 2]];
+ const float *n2 = bone_octahedral_solid_normals[bone_octahedral_wire_adjacent_face[i * 2 + 1]];
+ add_fancy_edge(vbo, attr_id.pos, attr_id.n1, attr_id.n2, &v_idx, co1, co2, n1, n2);
+ }
+
+ SHC.drw_bone_octahedral_wire = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ 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 unsigned int 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 unsigned int 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,
+};
+
+static const unsigned int bone_box_solid_tris[12][3] = {
+ {0, 1, 2}, /* bottom */
+ {0, 2, 3},
+
+ {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},
+};
+
+/* aligned with bone_octahedral_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},
+};
+
+Gwn_Batch *DRW_cache_bone_box_get(void)
+{
+ if (!SHC.drw_bone_box) {
+ unsigned int v_idx = 0;
+
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos, nor; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ attr_id.nor = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ /* Vertices */
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 36);
+
+ for (int i = 0; i < 12; i++) {
+ for (int j = 0; j < 3; j++) {
+ GWN_vertbuf_attr_set(vbo, attr_id.nor, v_idx, bone_box_solid_normals[i]);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, bone_box_verts[bone_box_solid_tris[i][j]]);
+ }
+ }
+
+ SHC.drw_bone_box = GWN_batch_create(GWN_PRIM_TRIS, vbo, NULL);
+ }
+ return SHC.drw_bone_box;
+}
+
+Gwn_Batch *DRW_cache_bone_box_wire_outline_get(void)
+{
+ if (!SHC.drw_bone_box_wire) {
+ unsigned int v_idx = 0;
+
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos, n1, n2; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ attr_id.n1 = GWN_vertformat_attr_add(&format, "N1", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ attr_id.n2 = GWN_vertformat_attr_add(&format, "N2", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ /* Vertices */
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 12 * 2);
+
+ for (int i = 0; i < 12; i++) {
+ const float *co1 = bone_box_verts[bone_box_wire[i * 2]];
+ const float *co2 = bone_box_verts[bone_box_wire[i * 2 + 1]];
+ const float *n1 = bone_box_solid_normals[bone_box_wire_adjacent_face[i * 2]];
+ const float *n2 = bone_box_solid_normals[bone_box_wire_adjacent_face[i * 2 + 1]];
+ add_fancy_edge(vbo, attr_id.pos, attr_id.n1, attr_id.n2, &v_idx, co1, co2, n1, n2);
+ }
+
+ SHC.drw_bone_box_wire = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_bone_box_wire;
+}
+
+
+Gwn_Batch *DRW_cache_bone_wire_wire_outline_get(void)
+{
+ if (!SHC.drw_bone_wire_wire) {
+ unsigned int v_idx = 0;
+
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos, n1, n2; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ attr_id.n1 = GWN_vertformat_attr_add(&format, "N1", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ attr_id.n2 = GWN_vertformat_attr_add(&format, "N2", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ /* Vertices */
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 2);
+
+ const float co1[3] = {0.0f, 0.0f, 0.0f};
+ const float co2[3] = {0.0f, 1.0f, 0.0f};
+ const float n[3] = {1.0f, 0.0f, 0.0f};
+ add_fancy_edge(vbo, attr_id.pos, attr_id.n1, attr_id.n2, &v_idx, co1, co2, n, n);
+
+ SHC.drw_bone_wire_wire = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_bone_wire_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])
+{
+ /* Poles are along Y axis. */
+ r_nor[0] = sinf(lat) * cosf(lon);
+ r_nor[1] = cosf(lat);
+ r_nor[2] = sinf(lat) * sinf(lon);
+}
+
+static void benv_add_tri(Gwn_VertBuf *vbo, uint pos_id, uint *v_idx, float *co1, float *co2, float *co3)
+{
+ /* Given tri and its seven other mirrors along X/Y/Z axes. */
+ for (int x = -1; x <= 1; x += 2) {
+ for (int y = -1; y <= 1; y += 2) {
+ const float head_tail = (y == -1) ? 0.0f : 1.0f;
+ for (int z = -1; z <= 1; z += 2) {
+ GWN_vertbuf_attr_set(vbo, pos_id, (*v_idx)++,
+ (const float[4]){co1[0] * x, co1[1] * y, co1[2] * z, head_tail});
+ GWN_vertbuf_attr_set(vbo, pos_id, (*v_idx)++,
+ (const float[4]){co2[0] * x, co2[1] * y, co2[2] * z, head_tail});
+ GWN_vertbuf_attr_set(vbo, pos_id, (*v_idx)++,
+ (const float[4]){co3[0] * x, co3[1] * y, co3[2] * z, head_tail});
+ }
+ }
+ }
+}
+
+Gwn_Batch *DRW_cache_bone_envelope_solid_get(void)
+{
+#define CIRCLE_RESOL 32 /* Must be multiple of 4 */
+ if (!SHC.drw_bone_envelope) {
+ const int lon_res = CIRCLE_RESOL / 4;
+ const int lat_res = CIRCLE_RESOL / 4;
+ const float lon_inc = M_PI_2 / lon_res;
+ const float lat_inc = M_PI_2 / lat_res;
+ unsigned int v_idx = 0;
+
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 4, GWN_FETCH_FLOAT);
+ }
+
+ /* Vertices */
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, lat_res * lon_res * 8 * 6);
+
+ float lon = 0.0f;
+ for (int i = 0; i < lon_res; i++, lon += lon_inc) {
+ float lat = 0.0f;
+ float co1[3], co2[3], co3[3], co4[3];
+
+ 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);
+ benv_lat_lon_to_co(lat + lat_inc, lon + lon_inc, co3);
+ benv_lat_lon_to_co(lat + lat_inc, lon , co4);
+
+ if (j != 0) { /* At pole, n1 and n2 are identical. */
+ benv_add_tri(vbo, attr_id.pos, &v_idx, co1, co2, co3);
+ }
+ benv_add_tri(vbo, attr_id.pos, &v_idx, co1, co3, co4);
+ }
+
+ /* lat is at equator (i.e. lat == pi / 2). */
+ /* We need to add 'cylinder' part between the equators (along XZ plane). */
+ for (int x = -1; x <= 1; x += 2) {
+ for (int z = -1; z <= 1; z += 2) {
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++,
+ (const float[4]){co3[0] * x, co3[1], co3[2] * z, 0.0f});
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++,
+ (const float[4]){co4[0] * x, co4[1], co4[2] * z, 0.0f});
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++,
+ (const float[4]){co4[0] * x, co4[1], co4[2] * z, 1.0f});
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++,
+ (const float[4]){co3[0] * x, co3[1], co3[2] * z, 0.0f});
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++,
+ (const float[4]){co4[0] * x, co4[1], co4[2] * z, 1.0f});
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++,
+ (const float[4]){co3[0] * x, co3[1], co3[2] * z, 1.0f});
+ }
+ }
+ }
+
+ SHC.drw_bone_envelope = GWN_batch_create(GWN_PRIM_TRIS, vbo, NULL);
+ }
+ return SHC.drw_bone_envelope;
+}
+
+
+Gwn_Batch *DRW_cache_bone_envelope_distance_outline_get(void)
+{
+#define CIRCLE_RESOL 32 /* Must be multiple of 2 */
+ if (!SHC.drw_bone_envelope_distance) {
+ unsigned int v_idx = 0;
+
+ static Gwn_VertFormat format = { 0 };
+ static unsigned int pos_id;
+ if (format.attrib_ct == 0) {
+ pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 4, GWN_FETCH_FLOAT);
+ }
+
+ /* Vertices */
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, CIRCLE_RESOL * 2 + 6);
+
+ /* Encoded triangle strip, vertex shader gives them final correct value. */
+ for (int i = 0; i < CIRCLE_RESOL + 1; i++) {
+ const bool is_headtail_transition = ELEM(i, CIRCLE_RESOL / 2, CIRCLE_RESOL);
+ const float head_tail = (i > CIRCLE_RESOL / 2) ? 1.0f : 0.0f;
+ const float alpha = 2.0f * M_PI * i / CIRCLE_RESOL;
+ const float x = cosf(alpha);
+ const float y = -sinf(alpha);
+
+ /* { X, Y, head/tail, inner/outer border } */
+ GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){x, y, head_tail, 0.0f});
+ GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){x, y, head_tail, 1.0f});
+ if (is_headtail_transition) {
+ GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){x, y, 1.0f - head_tail, 0.0f});
+ GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){x, y, 1.0f - head_tail, 1.0f});
+ }
+ }
+
+ SHC.drw_bone_envelope_distance = GWN_batch_create(GWN_PRIM_TRI_STRIP, vbo, NULL);
+ }
+ return SHC.drw_bone_envelope_distance;
+#undef CIRCLE_RESOL
+}
+
+
+/* Bone body. */
+Gwn_Batch *DRW_cache_bone_envelope_wire_outline_get(void)
+{
+ if (!SHC.drw_bone_envelope_wire) {
+ unsigned int v_idx = 0;
+
+ static Gwn_VertFormat format = { 0 };
+ static unsigned int pos_id;
+ if (format.attrib_ct == 0) {
+ pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 4, GWN_FETCH_FLOAT);
+ }
+
+ /* Vertices */
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 4);
+
+ /* Two lines between head and tail circles. */
+ /* Encoded lines, vertex shader gives them final correct value. */
+ /* { X, Y, head/tail, inner/outer border } */
+ GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){ 1.0f, 0.0f, 0.0f, 0.0f});
+ GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){ 1.0f, 0.0f, 1.0f, 0.0f});
+ GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){-1.0f, 0.0f, 0.0f, 0.0f});
+ GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){-1.0f, 0.0f, 1.0f, 0.0f});
+
+ SHC.drw_bone_envelope_wire = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_bone_envelope_wire;
+}
+
+
+/* Bone head and tail. */
+Gwn_Batch *DRW_cache_bone_envelope_head_wire_outline_get(void)
+{
+#define CIRCLE_RESOL 32 /* Must be multiple of 2 */
+ if (!SHC.drw_bone_envelope_head_wire) {
+ unsigned int v_idx = 0;
+
+ static Gwn_VertFormat format = { 0 };
+ static unsigned int pos_id;
+ if (format.attrib_ct == 0) {
+ pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 4, GWN_FETCH_FLOAT);
+ }
+
+ /* Vertices */
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, CIRCLE_RESOL);
+
+ /* Encoded lines, vertex shader gives them final correct value. */
+ /* Only head circle (tail is drawn in disp_tail_mat space as a head one by draw_armature.c's draw_point()). */
+ for (int i = 0; i < CIRCLE_RESOL; i++) {
+ const float alpha = 2.0f * M_PI * i / CIRCLE_RESOL;
+ const float x = cosf(alpha);
+ const float y = -sinf(alpha);
+
+ /* { X, Y, head/tail, inner/outer border } */
+ GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){ x, y, 0.0f, 0.0f});
+ }
+
+ SHC.drw_bone_envelope_head_wire = GWN_batch_create(GWN_PRIM_LINE_LOOP, vbo, NULL);
+ }
+ return SHC.drw_bone_envelope_head_wire;
+#undef CIRCLE_RESOL
+}
+
+
+Gwn_Batch *DRW_cache_bone_point_get(void)
+{
+ if (!SHC.drw_bone_point) {
+ 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;
+ unsigned int v_idx = 0;
+
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos, nor; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ attr_id.nor = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ /* Vertices */
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_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 = GWN_batch_create(GWN_PRIM_TRIS, vbo, NULL);
+ }
+ return SHC.drw_bone_point;
+}
+
+Gwn_Batch *DRW_cache_bone_point_wire_outline_get(void)
+{
+ if (!SHC.drw_bone_point_wire) {
+ Gwn_VertBuf *vbo = sphere_wire_vbo(0.05f);
+ SHC.drw_bone_point_wire = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_bone_point_wire;
+}
+
+Gwn_Batch *DRW_cache_bone_arrows_get(void)
+{
+ if (!SHC.drw_bone_arrows) {
+ Gwn_VertBuf *vbo = fill_arrows_vbo(0.25f);
+ SHC.drw_bone_arrows = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_bone_arrows;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Camera
+ * \{ */
+
+Gwn_Batch *DRW_cache_camera_get(void)
+{
+ if (!SHC.drw_camera) {
+ float v0 = 0.0f; /* Center point */
+ float v1 = 1.0f; /* + X + Y */
+ float v2 = 2.0f; /* + X - Y */
+ float v3 = 3.0f; /* - X - Y */
+ float v4 = 4.0f; /* - X + Y */
+ float v5 = 5.0f; /* tria + X */
+ float v6 = 6.0f; /* tria - X */
+ float v7 = 7.0f; /* tria + Y */
+ int v_idx = 0;
+
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ /* use x coordinate to identify the vertex
+ * the vertex shader take care to place it
+ * appropriatelly */
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 1, GWN_FETCH_FLOAT);
+ }
+
+ /* Vertices */
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 22);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v0);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v1);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v0);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v2);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v0);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v3);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v0);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v4);
+
+ /* camera frame */
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v1);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v2);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v2);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v3);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v3);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v4);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v4);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v1);
+
+ /* tria */
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v5);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v6);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v6);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v7);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v7);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v5);
+
+ SHC.drw_camera = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+ return SHC.drw_camera;
+}
+
+Gwn_Batch *DRW_cache_camera_tria_get(void)
+{
+ if (!SHC.drw_camera_tria) {
+ float v5 = 5.0f; /* tria + X */
+ float v6 = 6.0f; /* tria - X */
+ float v7 = 7.0f; /* tria + Y */
+ int v_idx = 0;
+
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ /* use x coordinate to identify the vertex
+ * the vertex shader take care to place it
+ * appropriatelly */
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 1, GWN_FETCH_FLOAT);
+ }
+
+ /* Vertices */
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 6);
+
+ /* tria */
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v5);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v6);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v7);
+
+ SHC.drw_camera_tria = GWN_batch_create(GWN_PRIM_TRIS, vbo, NULL);
+ }
+ return SHC.drw_camera_tria;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Object Mode Helpers
+ * \{ */
+
+/* Object Center */
+Gwn_Batch *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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 1);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 0, v1);
+
+ SHC.drw_single_vertice = GWN_batch_create(GWN_PRIM_POINTS, vbo, NULL);
+ }
+ return SHC.drw_single_vertice;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Meshes
+ * \{ */
+
+Gwn_Batch *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,
+ Gwn_Batch **r_tris, Gwn_Batch **r_ledges, Gwn_Batch **r_lverts)
+{
+ 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);
+}
+
+void DRW_cache_mesh_normals_overlay_get(
+ Object *ob,
+ Gwn_Batch **r_tris, Gwn_Batch **r_ledges, Gwn_Batch **r_lverts)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+
+ *r_tris = DRW_mesh_batch_cache_get_overlay_triangles_nor(me);
+ *r_ledges = DRW_mesh_batch_cache_get_overlay_loose_edges_nor(me);
+ *r_lverts = DRW_mesh_batch_cache_get_overlay_loose_verts(me);
+}
+
+Gwn_Batch *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);
+}
+
+Gwn_Batch *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);
+}
+
+Gwn_Batch *DRW_cache_mesh_surface_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+ return DRW_mesh_batch_cache_get_triangles_with_normals(me);
+}
+
+Gwn_Batch *DRW_cache_mesh_surface_weights_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+ return DRW_mesh_batch_cache_get_triangles_with_normals_and_weights(me, ob->actdef - 1);
+}
+
+Gwn_Batch *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 */
+Gwn_Batch **DRW_cache_mesh_surface_shaded_get(
+ Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+ return DRW_mesh_batch_cache_get_surface_shaded(me, gpumat_array, gpumat_array_len);
+}
+
+/* Return list of batches */
+Gwn_Batch **DRW_cache_mesh_surface_texpaint_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+ return DRW_mesh_batch_cache_get_surface_texpaint(me);
+}
+
+Gwn_Batch *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);
+}
+
+Gwn_Batch *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);
+}
+
+Gwn_Batch *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);
+}
+
+Gwn_Batch *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);
+}
+
+Gwn_Batch *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);
+}
+
+Gwn_Batch *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);
+}
+
+Gwn_Batch *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
+ * \{ */
+
+Gwn_Batch *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->curve_cache);
+}
+
+Gwn_Batch *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->curve_cache, normal_size);
+}
+
+Gwn_Batch *DRW_cache_curve_edge_overlay_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_CURVE);
+
+ struct Curve *cu = ob->data;
+ return DRW_curve_batch_cache_get_overlay_edges(cu);
+}
+
+Gwn_Batch *DRW_cache_curve_vert_overlay_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_CURVE);
+
+ struct Curve *cu = ob->data;
+ return DRW_curve_batch_cache_get_overlay_verts(cu);
+}
+
+Gwn_Batch *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->curve_cache);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Font
+ * \{ */
+
+Gwn_Batch *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->curve_cache);
+}
+
+Gwn_Batch *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->curve_cache);
+}
+
+Gwn_Batch *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);
+}
+
+Gwn_Batch *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
+ * \{ */
+
+Gwn_Batch *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->curve_cache);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Lattice
+ * \{ */
+
+Gwn_Batch *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);
+}
+
+Gwn_Batch *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);
+}
+
+Gwn_Batch *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
+ * \{ */
+
+Gwn_Batch *DRW_cache_particles_get_hair(ParticleSystem *psys, ModifierData *md)
+{
+ return DRW_particles_batch_cache_get_hair(psys, md);
+}
+
+Gwn_Batch *DRW_cache_particles_get_dots(ParticleSystem *psys)
+{
+ return DRW_particles_batch_cache_get_dots(psys);
+}
+
+Gwn_Batch *DRW_cache_particles_get_prim(int type)
+{
+ switch (type) {
+ case PART_DRAW_CROSS:
+ if (!SHC.drw_particle_cross) {
+ static Gwn_VertFormat format = { 0 };
+ static unsigned pos_id, axis_id;
+
+ if (format.attrib_ct == 0) {
+ pos_id = GWN_vertformat_attr_add(&format, "inst_pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ axis_id = GWN_vertformat_attr_add(&format, "axis", GWN_COMP_I32, 1, GWN_FETCH_INT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 6);
+
+ /* X axis */
+ float co[3] = {-1.0f, 0.0f, 0.0f};
+ int axis = -1;
+ GWN_vertbuf_attr_set(vbo, pos_id, 0, co);
+ GWN_vertbuf_attr_set(vbo, axis_id, 0, &axis);
+
+ co[0] = 1.0f;
+ GWN_vertbuf_attr_set(vbo, pos_id, 1, co);
+ GWN_vertbuf_attr_set(vbo, axis_id, 1, &axis);
+
+ /* Y axis */
+ co[0] = 0.0f;
+ co[1] = -1.0f;
+ GWN_vertbuf_attr_set(vbo, pos_id, 2, co);
+ GWN_vertbuf_attr_set(vbo, axis_id, 2, &axis);
+
+ co[1] = 1.0f;
+ GWN_vertbuf_attr_set(vbo, pos_id, 3, co);
+ GWN_vertbuf_attr_set(vbo, axis_id, 3, &axis);
+
+ /* Z axis */
+ co[1] = 0.0f;
+ co[2] = -1.0f;
+ GWN_vertbuf_attr_set(vbo, pos_id, 4, co);
+ GWN_vertbuf_attr_set(vbo, axis_id, 4, &axis);
+
+ co[2] = 1.0f;
+ GWN_vertbuf_attr_set(vbo, pos_id, 5, co);
+ GWN_vertbuf_attr_set(vbo, axis_id, 5, &axis);
+
+ SHC.drw_particle_cross = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+
+ return SHC.drw_particle_cross;
+ case PART_DRAW_AXIS:
+ if (!SHC.drw_particle_axis) {
+ static Gwn_VertFormat format = { 0 };
+ static unsigned pos_id, axis_id;
+
+ if (format.attrib_ct == 0) {
+ pos_id = GWN_vertformat_attr_add(&format, "inst_pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ axis_id = GWN_vertformat_attr_add(&format, "axis", GWN_COMP_I32, 1, GWN_FETCH_INT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 6);
+
+ /* X axis */
+ float co[3] = {0.0f, 0.0f, 0.0f};
+ int axis = 0;
+ GWN_vertbuf_attr_set(vbo, pos_id, 0, co);
+ GWN_vertbuf_attr_set(vbo, axis_id, 0, &axis);
+
+ co[0] = 1.0f;
+ GWN_vertbuf_attr_set(vbo, pos_id, 1, co);
+ GWN_vertbuf_attr_set(vbo, axis_id, 1, &axis);
+
+ /* Y axis */
+ co[0] = 0.0f;
+ axis = 1;
+ GWN_vertbuf_attr_set(vbo, pos_id, 2, co);
+ GWN_vertbuf_attr_set(vbo, axis_id, 2, &axis);
+
+ co[1] = 1.0f;
+ GWN_vertbuf_attr_set(vbo, pos_id, 3, co);
+ GWN_vertbuf_attr_set(vbo, axis_id, 3, &axis);
+
+ /* Z axis */
+ co[1] = 0.0f;
+ axis = 2;
+ GWN_vertbuf_attr_set(vbo, pos_id, 4, co);
+ GWN_vertbuf_attr_set(vbo, axis_id, 4, &axis);
+
+ co[2] = 1.0f;
+ GWN_vertbuf_attr_set(vbo, pos_id, 5, co);
+ GWN_vertbuf_attr_set(vbo, axis_id, 5, &axis);
+
+ SHC.drw_particle_axis = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+
+ 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 Gwn_VertFormat format = { 0 };
+ static unsigned pos_id, axis_id;
+
+ if (format.attrib_ct == 0) {
+ pos_id = GWN_vertformat_attr_add(&format, "inst_pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ axis_id = GWN_vertformat_attr_add(&format, "axis", GWN_COMP_I32, 1, GWN_FETCH_INT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_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;
+ GWN_vertbuf_attr_set(vbo, pos_id, a, v);
+ GWN_vertbuf_attr_set(vbo, axis_id, a, &axis);
+ }
+
+ SHC.drw_particle_circle = GWN_batch_create(GWN_PRIM_LINE_LOOP, vbo, NULL);
+ }
+
+ return SHC.drw_particle_circle;
+#undef CIRCLE_RESOL
+ default:
+ BLI_assert(false);
+ break;
+ }
+
+ return NULL;
+}
diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h
new file mode 100644
index 00000000000..ac7062b3cc8
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache.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 draw_cache.h
+ * \ingroup draw
+ */
+
+#ifndef __DRAW_CACHE_H__
+#define __DRAW_CACHE_H__
+
+struct Gwn_Batch;
+struct GPUMaterial;
+struct Object;
+struct ModifierData;
+
+void DRW_shape_cache_free(void);
+
+/* Common Shapes */
+struct Gwn_Batch *DRW_cache_fullscreen_quad_get(void);
+struct Gwn_Batch *DRW_cache_sphere_get(void);
+struct Gwn_Batch *DRW_cache_single_vert_get(void);
+struct Gwn_Batch *DRW_cache_single_line_get(void);
+struct Gwn_Batch *DRW_cache_single_line_endpoints_get(void);
+struct Gwn_Batch *DRW_cache_screenspace_circle_get(void);
+
+/* Common Object */
+struct Gwn_Batch *DRW_cache_object_wire_outline_get(struct Object *ob);
+struct Gwn_Batch *DRW_cache_object_surface_get(struct Object *ob);
+struct Gwn_Batch **DRW_cache_object_surface_material_get(
+ struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len);
+
+/* Empties */
+struct Gwn_Batch *DRW_cache_plain_axes_get(void);
+struct Gwn_Batch *DRW_cache_single_arrow_get(void);
+struct Gwn_Batch *DRW_cache_cube_get(void);
+struct Gwn_Batch *DRW_cache_circle_get(void);
+struct Gwn_Batch *DRW_cache_square_get(void);
+struct Gwn_Batch *DRW_cache_empty_sphere_get(void);
+struct Gwn_Batch *DRW_cache_empty_cone_get(void);
+struct Gwn_Batch *DRW_cache_arrows_get(void);
+struct Gwn_Batch *DRW_cache_axis_names_get(void);
+struct Gwn_Batch *DRW_cache_image_plane_get(void);
+struct Gwn_Batch *DRW_cache_image_plane_wire_get(void);
+
+/* Force Field */
+struct Gwn_Batch *DRW_cache_field_wind_get(void);
+struct Gwn_Batch *DRW_cache_field_force_get(void);
+struct Gwn_Batch *DRW_cache_field_vortex_get(void);
+struct Gwn_Batch *DRW_cache_field_tube_limit_get(void);
+struct Gwn_Batch *DRW_cache_field_cone_limit_get(void);
+
+/* Lamps */
+struct Gwn_Batch *DRW_cache_lamp_get(void);
+struct Gwn_Batch *DRW_cache_lamp_sunrays_get(void);
+struct Gwn_Batch *DRW_cache_lamp_area_get(void);
+struct Gwn_Batch *DRW_cache_lamp_hemi_get(void);
+struct Gwn_Batch *DRW_cache_lamp_spot_get(void);
+struct Gwn_Batch *DRW_cache_lamp_spot_square_get(void);
+
+/* Camera */
+struct Gwn_Batch *DRW_cache_camera_get(void);
+struct Gwn_Batch *DRW_cache_camera_tria_get(void);
+
+/* Speaker */
+struct Gwn_Batch *DRW_cache_speaker_get(void);
+
+/* Probe */
+struct Gwn_Batch *DRW_cache_lightprobe_cube_get(void);
+struct Gwn_Batch *DRW_cache_lightprobe_grid_get(void);
+struct Gwn_Batch *DRW_cache_lightprobe_planar_get(void);
+
+/* Bones */
+struct Gwn_Batch *DRW_cache_bone_octahedral_get(void);
+struct Gwn_Batch *DRW_cache_bone_octahedral_wire_outline_get(void);
+struct Gwn_Batch *DRW_cache_bone_box_get(void);
+struct Gwn_Batch *DRW_cache_bone_box_wire_outline_get(void);
+struct Gwn_Batch *DRW_cache_bone_wire_wire_outline_get(void);
+struct Gwn_Batch *DRW_cache_bone_envelope_solid_get(void);
+struct Gwn_Batch *DRW_cache_bone_envelope_distance_outline_get(void);
+struct Gwn_Batch *DRW_cache_bone_envelope_wire_outline_get(void);
+struct Gwn_Batch *DRW_cache_bone_envelope_head_wire_outline_get(void);
+struct Gwn_Batch *DRW_cache_bone_point_get(void);
+struct Gwn_Batch *DRW_cache_bone_point_wire_outline_get(void);
+struct Gwn_Batch *DRW_cache_bone_arrows_get(void);
+
+/* Meshes */
+struct Gwn_Batch *DRW_cache_mesh_surface_overlay_get(struct Object *ob);
+void DRW_cache_mesh_wire_overlay_get(
+ struct Object *ob,
+ struct Gwn_Batch **r_tris, struct Gwn_Batch **r_ledges, struct Gwn_Batch **r_lverts);
+void DRW_cache_mesh_normals_overlay_get(
+ struct Object *ob,
+ struct Gwn_Batch **r_tris, struct Gwn_Batch **r_ledges, struct Gwn_Batch **r_lverts);
+struct Gwn_Batch *DRW_cache_face_centers_get(struct Object *ob);
+struct Gwn_Batch *DRW_cache_mesh_wire_outline_get(struct Object *ob);
+struct Gwn_Batch *DRW_cache_mesh_surface_get(struct Object *ob);
+struct Gwn_Batch *DRW_cache_mesh_surface_weights_get(struct Object *ob);
+struct Gwn_Batch *DRW_cache_mesh_surface_vert_colors_get(struct Object *ob);
+struct Gwn_Batch *DRW_cache_mesh_surface_verts_get(struct Object *ob);
+struct Gwn_Batch *DRW_cache_mesh_edges_get(struct Object *ob);
+struct Gwn_Batch *DRW_cache_mesh_verts_get(struct Object *ob);
+struct Gwn_Batch *DRW_cache_mesh_edges_paint_overlay_get(struct Object *ob, bool use_wire, bool use_sel);
+struct Gwn_Batch *DRW_cache_mesh_faces_weight_overlay_get(struct Object *ob);
+struct Gwn_Batch *DRW_cache_mesh_verts_weight_overlay_get(struct Object *ob);
+struct Gwn_Batch **DRW_cache_mesh_surface_shaded_get(
+ struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len);
+struct Gwn_Batch **DRW_cache_mesh_surface_texpaint_get(struct Object *ob);
+struct Gwn_Batch *DRW_cache_mesh_surface_texpaint_single_get(struct Object *ob);
+
+void DRW_cache_mesh_sculpt_coords_ensure(struct Object *ob);
+
+/* Curve */
+struct Gwn_Batch *DRW_cache_curve_surface_get(struct Object *ob);
+struct Gwn_Batch *DRW_cache_curve_surface_verts_get(struct Object *ob);
+struct Gwn_Batch *DRW_cache_curve_edge_wire_get(struct Object *ob);
+/* edit-mode */
+struct Gwn_Batch *DRW_cache_curve_edge_normal_get(struct Object *ob, float normal_size);
+struct Gwn_Batch *DRW_cache_curve_edge_overlay_get(struct Object *ob);
+struct Gwn_Batch *DRW_cache_curve_vert_overlay_get(struct Object *ob);
+
+/* Font */
+struct Gwn_Batch *DRW_cache_text_edge_wire_get(struct Object *ob);
+struct Gwn_Batch *DRW_cache_text_surface_get(struct Object *ob);
+/* edit-mode */
+struct Gwn_Batch *DRW_cache_text_cursor_overlay_get(struct Object *ob);
+struct Gwn_Batch *DRW_cache_text_select_overlay_get(struct Object *ob);
+
+/* Surface */
+struct Gwn_Batch *DRW_cache_surf_surface_get(struct Object *ob);
+
+/* Lattice */
+struct Gwn_Batch *DRW_cache_lattice_verts_get(struct Object *ob);
+struct Gwn_Batch *DRW_cache_lattice_wire_get(struct Object *ob, bool use_weight);
+struct Gwn_Batch *DRW_cache_lattice_vert_overlay_get(struct Object *ob);
+
+/* Particles */
+struct Gwn_Batch *DRW_cache_particles_get_hair(struct ParticleSystem *psys, struct ModifierData *md);
+struct Gwn_Batch *DRW_cache_particles_get_dots(struct ParticleSystem *psys);
+struct Gwn_Batch *DRW_cache_particles_get_prim(int type);
+
+#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..f8feeb37b82
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -0,0 +1,105 @@
+/*
+ * 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 Gwn_Batch;
+struct GPUMaterial;
+struct ListBase;
+struct CurveCache;
+struct ParticleSystem;
+struct ModifierData;
+
+struct Curve;
+struct Lattice;
+struct Mesh;
+
+/* Expose via BKE callbacks */
+void DRW_curve_batch_cache_dirty(struct Curve *cu, int mode);
+void DRW_curve_batch_cache_free(struct Curve *cu);
+
+void DRW_mesh_batch_cache_dirty(struct Mesh *me, int mode);
+void DRW_mesh_batch_cache_free(struct Mesh *me);
+
+void DRW_lattice_batch_cache_dirty(struct Lattice *lt, int mode);
+void DRW_lattice_batch_cache_free(struct Lattice *lt);
+
+void DRW_particle_batch_cache_dirty(struct ParticleSystem *psys, int mode);
+void DRW_particle_batch_cache_free(struct ParticleSystem *psys);
+
+/* Curve */
+struct Gwn_Batch *DRW_curve_batch_cache_get_wire_edge(struct Curve *cu, struct CurveCache *ob_curve_cache);
+struct Gwn_Batch *DRW_curve_batch_cache_get_normal_edge(
+ struct Curve *cu, struct CurveCache *ob_curve_cache, float normal_size);
+struct Gwn_Batch *DRW_curve_batch_cache_get_overlay_edges(struct Curve *cu);
+struct Gwn_Batch *DRW_curve_batch_cache_get_overlay_verts(struct Curve *cu);
+
+struct Gwn_Batch *DRW_curve_batch_cache_get_triangles_with_normals(struct Curve *cu, struct CurveCache *ob_curve_cache);
+
+/* Curve (Font) */
+struct Gwn_Batch *DRW_curve_batch_cache_get_overlay_cursor(struct Curve *cu);
+struct Gwn_Batch *DRW_curve_batch_cache_get_overlay_select(struct Curve *cu);
+
+/* DispList */
+struct Gwn_Batch *BLI_displist_batch_calc_surface(struct ListBase *lb);
+
+/* Lattice */
+struct Gwn_Batch *DRW_lattice_batch_cache_get_all_edges(struct Lattice *lt, bool use_weight, const int actdef);
+struct Gwn_Batch *DRW_lattice_batch_cache_get_all_verts(struct Lattice *lt);
+struct Gwn_Batch *DRW_lattice_batch_cache_get_overlay_verts(struct Lattice *lt);
+
+/* Mesh */
+
+struct Gwn_Batch **DRW_mesh_batch_cache_get_surface_shaded(
+ struct Mesh *me, struct GPUMaterial **gpumat_array, uint gpumat_array_len);
+struct Gwn_Batch **DRW_mesh_batch_cache_get_surface_texpaint(struct Mesh *me);
+struct Gwn_Batch *DRW_mesh_batch_cache_get_surface_texpaint_single(struct Mesh *me);
+struct Gwn_Batch *DRW_mesh_batch_cache_get_weight_overlay_edges(struct Mesh *me, bool use_wire, bool use_sel);
+struct Gwn_Batch *DRW_mesh_batch_cache_get_weight_overlay_faces(struct Mesh *me);
+struct Gwn_Batch *DRW_mesh_batch_cache_get_weight_overlay_verts(struct Mesh *me);
+struct Gwn_Batch *DRW_mesh_batch_cache_get_all_edges(struct Mesh *me);
+struct Gwn_Batch *DRW_mesh_batch_cache_get_all_triangles(struct Mesh *me);
+struct Gwn_Batch *DRW_mesh_batch_cache_get_triangles_with_normals(struct Mesh *me);
+struct Gwn_Batch *DRW_mesh_batch_cache_get_triangles_with_normals_and_weights(struct Mesh *me, int defgroup);
+struct Gwn_Batch *DRW_mesh_batch_cache_get_triangles_with_normals_and_vert_colors(struct Mesh *me);
+struct Gwn_Batch *DRW_mesh_batch_cache_get_triangles_with_select_id(struct Mesh *me, bool use_hide);
+struct Gwn_Batch *DRW_mesh_batch_cache_get_points_with_normals(struct Mesh *me);
+struct Gwn_Batch *DRW_mesh_batch_cache_get_all_verts(struct Mesh *me);
+struct Gwn_Batch *DRW_mesh_batch_cache_get_fancy_edges(struct Mesh *me);
+struct Gwn_Batch *DRW_mesh_batch_cache_get_overlay_triangles(struct Mesh *me);
+struct Gwn_Batch *DRW_mesh_batch_cache_get_overlay_triangles_nor(struct Mesh *me);
+struct Gwn_Batch *DRW_mesh_batch_cache_get_overlay_loose_edges(struct Mesh *me);
+struct Gwn_Batch *DRW_mesh_batch_cache_get_overlay_loose_edges_nor(struct Mesh *me);
+struct Gwn_Batch *DRW_mesh_batch_cache_get_overlay_loose_verts(struct Mesh *me);
+struct Gwn_Batch *DRW_mesh_batch_cache_get_overlay_facedots(struct Mesh *me);
+
+void DRW_mesh_cache_sculpt_coords_ensure(struct Mesh *me);
+
+/* Particles */
+struct Gwn_Batch *DRW_particles_batch_cache_get_hair(struct ParticleSystem *psys, struct ModifierData *md);
+struct Gwn_Batch *DRW_particles_batch_cache_get_dots(struct ParticleSystem *psys);
+
+#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..9ff9fab4c64
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_impl_curve.c
@@ -0,0 +1,1047 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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 "draw_cache_impl.h" /* own include */
+
+#define SELECT 1
+
+/**
+ * TODO
+ * - Ensure `CurveCache`, `SEQUENCER_DAG_WORKAROUND`.
+ * - Check number of verts/edges to see if cache is valid.
+ * - Check if 'overlay.edges' can use single attribyte 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, bool hide_handles,
+ 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 += hide_handles ? nu->pntsu : (nu->pntsu * 3);
+ /* 2x handles per point*/
+ edge_len += 2 * nu->pntsu;
+ }
+ else if (nu->bp) {
+ vert_len += nu->pntsu;
+ /* segments between points */
+ edge_len += nu->pntsu - 1;
+ }
+ }
+ 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
+ normal_len += max_ii((nr + max_ii(skip - 1, 0)) / (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;
+
+ bool hide_handles;
+ bool hide_normals;
+
+ /* 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->hide_handles = (cu->drawflag & CU_HIDE_HANDLES) != 0;
+ rdata->hide_normals = (cu->drawflag & CU_HIDE_NORMALS) != 0;
+
+ 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->hide_handles,
+ &rdata->overlay.vert_len,
+ rdata->hide_handles ? NULL : &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;
+}
+
+enum {
+ VFLAG_VERTEX_SELECTED = 1 << 0,
+ VFLAG_VERTEX_ACTIVE = 1 << 1,
+};
+
+/* ---------------------------------------------------------------------- */
+/* Curve Gwn_Batch Cache */
+
+typedef struct CurveBatchCache {
+ /* center-line */
+ struct {
+ Gwn_VertBuf *verts;
+ Gwn_VertBuf *edges;
+ Gwn_Batch *batch;
+ Gwn_IndexBuf *elem;
+ } wire;
+
+ /* normals */
+ struct {
+ Gwn_VertBuf *verts;
+ Gwn_VertBuf *edges;
+ Gwn_Batch *batch;
+ Gwn_IndexBuf *elem;
+ } normal;
+
+ /* control handles and vertices */
+ struct {
+ Gwn_Batch *edges;
+ Gwn_Batch *verts;
+ } overlay;
+
+ struct {
+ Gwn_Batch *batch;
+ } surface;
+
+ /* 3d text */
+ struct {
+ Gwn_Batch *select;
+ Gwn_Batch *cursor;
+ } text;
+
+ /* settings to determine if cache is invalid */
+ bool is_dirty;
+
+ bool hide_handles;
+ bool hide_normals;
+
+ float normal_size;
+
+ bool is_editmode;
+} CurveBatchCache;
+
+/* Gwn_Batch cache management. */
+
+static bool curve_batch_cache_valid(Curve *cu)
+{
+ CurveBatchCache *cache = cu->batch_cache;
+
+ if (cache == NULL) {
+ return false;
+ }
+
+ if (cache->is_editmode != ((cu->editnurb != NULL) || (cu->editfont != NULL))) {
+ return false;
+ }
+
+ if (cache->is_editmode) {
+ if (cu->editnurb) {
+ if ((cache->hide_handles != ((cu->drawflag & CU_HIDE_HANDLES) != 0))) {
+ return false;
+ }
+ else if ((cache->hide_normals != ((cu->drawflag & CU_HIDE_NORMALS) != 0))) {
+ return false;
+ }
+ }
+ else if (cu->editfont) {
+ /* TODO */
+ }
+ }
+
+ if (cache->is_dirty == false) {
+ return true;
+ }
+ else {
+ /* TODO: check number of vertices/edges? */
+ if (cache->is_editmode) {
+ return false;
+ }
+ }
+
+ 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));
+ }
+
+ cache->hide_handles = (cu->drawflag & CU_HIDE_HANDLES) != 0;
+ cache->hide_normals = (cu->drawflag & CU_HIDE_NORMALS) != 0;
+
+#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(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 */
+ BATCH_DISCARD_ALL_SAFE(cache->overlay.verts);
+ BATCH_DISCARD_ALL_SAFE(cache->overlay.edges);
+
+ /* editfont */
+ BATCH_DISCARD_ALL_SAFE(cache->text.select);
+ BATCH_DISCARD_ALL_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;
+ }
+
+ BATCH_DISCARD_ALL_SAFE(cache->overlay.verts);
+ BATCH_DISCARD_ALL_SAFE(cache->overlay.edges);
+
+ BATCH_DISCARD_ALL_SAFE(cache->surface.batch);
+
+ if (cache->wire.batch) {
+ BATCH_DISCARD_ALL_SAFE(cache->wire.batch);
+ cache->wire.verts = NULL;
+ cache->wire.edges = NULL;
+ cache->wire.elem = NULL;
+ }
+ else {
+ GWN_VERTBUF_DISCARD_SAFE(cache->wire.verts);
+ GWN_VERTBUF_DISCARD_SAFE(cache->wire.edges);
+ GWN_INDEXBUF_DISCARD_SAFE(cache->wire.elem);
+ }
+
+ if (cache->normal.batch) {
+ BATCH_DISCARD_ALL_SAFE(cache->normal.batch);
+ cache->normal.verts = NULL;
+ cache->normal.edges = NULL;
+ cache->normal.elem = NULL;
+ }
+ else {
+ GWN_VERTBUF_DISCARD_SAFE(cache->normal.verts);
+ GWN_VERTBUF_DISCARD_SAFE(cache->normal.edges);
+ GWN_INDEXBUF_DISCARD_SAFE(cache->normal.elem);
+ }
+
+ /* 3d text */
+ BATCH_DISCARD_ALL_SAFE(cache->text.cursor);
+ BATCH_DISCARD_ALL_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
+ * \{ */
+
+/* Gwn_Batch cache usage. */
+static Gwn_VertBuf *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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ /* initialize vertex format */
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ const int vert_len = curve_render_data_wire_verts_len_get(rdata);
+
+ Gwn_VertBuf *vbo = cache->wire.verts = GWN_vertbuf_create_with_format(&format);
+ GWN_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++) {
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bevp->vec);
+ }
+ }
+ }
+ BLI_assert(vbo_len_used == vert_len);
+ }
+
+ return cache->wire.verts;
+}
+
+static Gwn_IndexBuf *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;
+
+ Gwn_IndexBufBuilder elb;
+ GWN_indexbuf_init(&elb, GWN_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++) {
+ GWN_indexbuf_add_line_verts(&elb, i_prev, i);
+ edge_len_used += 1;
+ }
+ }
+ }
+
+ if (rdata->hide_handles) {
+ BLI_assert(edge_len_used <= edge_len);
+ }
+ else {
+ BLI_assert(edge_len_used == edge_len);
+ }
+
+ cache->wire.elem = GWN_indexbuf_build(&elb);
+ }
+
+ return cache->wire.elem;
+}
+
+static Gwn_VertBuf *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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ /* initialize vertex format */
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ const int normal_len = curve_render_data_normal_len_get(rdata);
+ const int vert_len = normal_len * 3;
+
+ Gwn_VertBuf *vbo = cache->normal.verts = GWN_vertbuf_create_with_format(&format);
+ GWN_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);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, vec_a);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, bevp->vec);
+ GWN_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 Gwn_IndexBuf *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;
+
+ Gwn_IndexBufBuilder elb;
+ GWN_indexbuf_init(&elb, GWN_PRIM_LINES, edge_len, vert_len);
+
+ int vbo_len_used = 0;
+ for (int i = 0; i < normal_len; i++) {
+ GWN_indexbuf_add_line_verts(&elb, vbo_len_used + 0, vbo_len_used + 1);
+ GWN_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 = GWN_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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos, data; } attr_id;
+ if (format.attrib_ct == 0) {
+ /* initialize vertex format */
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ attr_id.data = GWN_vertformat_attr_add(&format, "data", GWN_COMP_U8, 1, GWN_FETCH_INT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ const int vbo_len_capacity = curve_render_data_overlay_verts_len_get(rdata);
+ int vbo_len_used = 0;
+ GWN_vertbuf_data_alloc(vbo, vbo_len_capacity);
+ int i = 0;
+ for (Nurb *nu = rdata->nurbs->first; nu; nu = nu->next) {
+ 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);
+ char vflag;
+
+ if (rdata->hide_handles) {
+ vflag = (bezt->f2 & SELECT) ?
+ (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED) : 0;
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[1]);
+ GWN_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag);
+ vbo_len_used += 1;
+ }
+ else {
+ for (int j = 0; j < 3; j++) {
+ vflag = ((&bezt->f1)[j] & SELECT) ?
+ (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED) : 0;
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[j]);
+ GWN_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag);
+ vbo_len_used += 1;
+ }
+ }
+ }
+ i += 1;
+ }
+ }
+ else if (nu->bp) {
+ int a = 0;
+ for (const BPoint *bp = nu->bp; a < nu->pntsu; a++, bp++) {
+ if (bp->hide == false) {
+ const bool is_active = (i == rdata->actvert);
+ char vflag;
+ vflag = (bp->f1 & SELECT) ? (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED) : 0;
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bp->vec);
+ GWN_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) {
+ GWN_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+
+ cache->overlay.verts = GWN_batch_create(GWN_PRIM_POINTS, vbo, NULL);
+ }
+
+
+ if ((cache->overlay.edges == NULL) && (rdata->hide_handles == false)) {
+ /* Note: we could reference indices to vertices (above) */
+
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos, data; } attr_id;
+ if (format.attrib_ct == 0) {
+ /* initialize vertex format */
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ attr_id.data = GWN_vertformat_attr_add(&format, "data", GWN_COMP_U8, 1, GWN_FETCH_INT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ const int edge_len = curve_render_data_overlay_edges_len_get(rdata);
+ const int vbo_len_capacity = edge_len * 2;
+ int vbo_len_used = 0;
+ GWN_vertbuf_data_alloc(vbo, vbo_len_capacity);
+ int i = 0;
+ for (Nurb *nu = rdata->nurbs->first; nu; nu = nu->next) {
+ 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);
+ char vflag;
+
+ vflag = (bezt->f1 & SELECT) ? (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED) : 0;
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[0]);
+ GWN_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag);
+ vbo_len_used += 1;
+
+ /* same vertex twice, only check different selection */
+ for (int j = 0; j < 2; j++) {
+ vflag = ((j ? bezt->f3 : bezt->f1) & SELECT) ?
+ (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED) : 0;
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[1]);
+ GWN_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag);
+ vbo_len_used += 1;
+ }
+
+ vflag = (bezt->f3 & SELECT) ? (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED) : 0;
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[2]);
+ GWN_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag);
+ vbo_len_used += 1;
+ }
+ i += 1;
+ }
+ }
+ else if (nu->bp) {
+ int a = 1;
+ for (const BPoint *bp_prev = nu->bp, *bp_curr = &nu->bp[1]; a < nu->pntsu; a++, bp_prev = bp_curr++) {
+ if ((bp_prev->hide == false) && (bp_curr->hide == false)) {
+ char vflag;
+ vflag = ((bp_prev->f1 & SELECT) && (bp_curr->f1 & SELECT)) ? VFLAG_VERTEX_SELECTED : 0;
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bp_prev->vec);
+ GWN_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag);
+ vbo_len_used += 1;
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bp_curr->vec);
+ GWN_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag);
+ vbo_len_used += 1;
+
+ }
+ }
+ }
+ }
+ if (vbo_len_capacity != vbo_len_used) {
+ GWN_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+
+ cache->overlay.edges = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+ }
+
+ curve_render_data_free(rdata);
+}
+
+static Gwn_Batch *curve_batch_cache_get_pos_and_normals(CurveRenderData *rdata, CurveBatchCache *cache)
+{
+ BLI_assert(rdata->types & CU_DATATYPE_SURFACE);
+ if (cache->surface.batch == NULL) {
+ cache->surface.batch = BLI_displist_batch_calc_surface(&rdata->ob_curve_cache->disp);
+ }
+ return cache->surface.batch;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Private Object/Font Cache API
+ * \{ */
+
+
+static Gwn_Batch *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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ const int vbo_len_capacity = ef->selboxes_len * 6;
+ int vbo_len_used = 0;
+ GWN_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);
+ }
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[0]);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[1]);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[2]);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[0]);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[2]);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[3]);
+ }
+ BLI_assert(vbo_len_used == vbo_len_capacity);
+ cache->text.select = GWN_batch_create(GWN_PRIM_TRIS, vbo, NULL);
+ }
+ return cache->text.select;
+}
+
+static Gwn_Batch *curve_batch_cache_get_overlay_cursor(CurveRenderData *rdata, CurveBatchCache *cache)
+{
+ BLI_assert(rdata->types & CU_DATATYPE_TEXT_SELECT);
+ if (cache->text.cursor == NULL) {
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ const int vbo_len_capacity = 4;
+ GWN_vertbuf_data_alloc(vbo, vbo_len_capacity);
+ for (int i = 0; i < 4; i++) {
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, i, rdata->text.edit_font->textcurs[i]);
+ }
+ cache->text.cursor = GWN_batch_create(GWN_PRIM_TRI_FAN, vbo, NULL);
+ }
+ return cache->text.cursor;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Public Object/Curve API
+ * \{ */
+
+Gwn_Batch *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 = GWN_batch_create(
+ GWN_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;
+}
+
+Gwn_Batch *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) {
+ BATCH_DISCARD_ALL_SAFE(cache->normal.batch);
+ }
+ }
+ 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 = GWN_batch_create(
+ GWN_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;
+}
+
+Gwn_Batch *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;
+}
+
+Gwn_Batch *DRW_curve_batch_cache_get_overlay_verts(Curve *cu)
+{
+ CurveBatchCache *cache = curve_batch_cache_get(cu);
+
+ if (cache->overlay.verts == NULL) {
+ curve_batch_cache_create_overlay_batches(cu);
+ }
+
+ return cache->overlay.verts;
+}
+
+Gwn_Batch *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;
+}
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Public Object/Font API
+ * \{ */
+
+Gwn_Batch *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;
+}
+
+Gwn_Batch *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;
+}
+
+/** \} */ \ No newline at end of file
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..fd36b7ad4a3
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_impl_displist.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 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_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;
+}
+
+Gwn_Batch *BLI_displist_batch_calc_surface(ListBase *lb)
+{
+ const int tri_len = curve_render_surface_tri_len_get(lb);
+ if (tri_len == 0) {
+ return NULL;
+ }
+
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos, nor; } attr_id;
+ if (format.attrib_ct == 0) {
+ /* initialize vertex format */
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ attr_id.nor = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ const int vert_len = curve_render_surface_vert_len_get(lb);
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ {
+ const int vbo_len_capacity = vert_len;
+ int vbo_len_used = 0;
+ GWN_vertbuf_data_alloc(vbo, vbo_len_capacity);
+
+ BKE_displist_normals_add(lb);
+
+ 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) {
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, fp_co);
+ if (fp_no) {
+ GWN_vertbuf_attr_set(vbo, attr_id.nor, vbo_len_used, fp_no);
+ if (ndata_is_single == false) {
+ fp_no += 3;
+ }
+ }
+ fp_co += 3;
+ vbo_len_used += 1;
+ }
+ }
+ }
+ }
+
+ {
+ Gwn_IndexBufBuilder elb;
+ GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, tri_len, vert_len);
+
+ int ofs = 0;
+ int tri_len_used = 0;
+ for (const DispList *dl = lb->first; dl; dl = dl->next) {
+ if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
+ if (dl->type == DL_INDEX3) {
+ const int *idx = dl->index;
+ const int i_end = dl->parts;
+ for (int i = 0; i < i_end; i++) {
+ GWN_indexbuf_add_tri_verts(&elb, idx[0] + ofs, idx[1] + ofs, idx[2] + ofs);
+ tri_len_used += 1;
+ idx += 3;
+ }
+ }
+ else if (ELEM(dl->type, DL_INDEX4, DL_SURF)) {
+ const int *idx = dl->index;
+ const int i_end = dl->totindex;
+ for (int i = 0; i < i_end; i++) {
+ GWN_indexbuf_add_tri_verts(&elb, idx[0] + ofs, idx[1] + ofs, idx[2] + ofs);
+ tri_len_used += 1;
+ GWN_indexbuf_add_tri_verts(&elb, idx[0] + ofs, idx[2] + ofs, idx[3] + ofs);
+ tri_len_used += 1;
+ idx += 4;
+ }
+ }
+ ofs += dl_vert_len(dl);
+ }
+ }
+
+ return GWN_batch_create(GWN_PRIM_TRIS, vbo, GWN_indexbuf_build(&elb));
+ }
+}
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..84b061aff9a
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_impl_lattice.c
@@ -0,0 +1,587 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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_texture.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) {
+ do_colorband(&U.coba_weight, weight, r_col);
+ }
+ else {
+ rgb_from_weight(r_col, weight);
+ }
+
+ r_col[3] = 1.0f;
+ }
+ else {
+ zero_v4(r_col);
+ }
+}
+
+enum {
+ VFLAG_VERTEX_SELECTED = 1 << 0,
+ VFLAG_VERTEX_ACTIVE = 1 << 1,
+};
+
+/* ---------------------------------------------------------------------- */
+/* Lattice Gwn_Batch Cache */
+
+typedef struct LatticeBatchCache {
+ Gwn_VertBuf *pos;
+ Gwn_IndexBuf *edges;
+
+ Gwn_Batch *all_verts;
+ Gwn_Batch *all_edges;
+
+ Gwn_Batch *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;
+
+/* Gwn_Batch 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 == false) {
+ return true;
+ }
+ else {
+ if (cache->is_editmode) {
+ 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(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 */
+ BATCH_DISCARD_ALL_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;
+ }
+
+ GWN_BATCH_DISCARD_SAFE(cache->all_verts);
+ GWN_BATCH_DISCARD_SAFE(cache->all_edges);
+ BATCH_DISCARD_ALL_SAFE(cache->overlay_verts);
+
+ GWN_VERTBUF_DISCARD_SAFE(cache->pos);
+ GWN_INDEXBUF_DISCARD_SAFE(cache->edges);
+}
+
+void DRW_lattice_batch_cache_free(Lattice *lt)
+{
+ lattice_batch_cache_clear(lt);
+ MEM_SAFE_FREE(lt->batch_cache);
+}
+
+/* Gwn_Batch cache usage. */
+static Gwn_VertBuf *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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos, col; } attr_id;
+
+ GWN_vertformat_clear(&format);
+
+ /* initialize vertex format */
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ if (use_weight) {
+ attr_id.col = GWN_vertformat_attr_add(&format, "color", GWN_COMP_F32, 4, GWN_FETCH_FLOAT);
+ }
+
+ const int vert_len = lattice_render_data_verts_len_get(rdata);
+
+ cache->pos = GWN_vertbuf_create_with_format(&format);
+ GWN_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);
+ GWN_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);
+
+ GWN_vertbuf_attr_set(cache->pos, attr_id.col, i, w_col);
+ }
+ }
+ }
+
+ return cache->pos;
+}
+
+static Gwn_IndexBuf *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;
+
+ Gwn_IndexBufBuilder elb;
+ GWN_indexbuf_init(&elb, GWN_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)) {
+ GWN_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)) {
+ GWN_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)) {
+ GWN_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 = GWN_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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos, data; } attr_id;
+ if (format.attrib_ct == 0) {
+ /* initialize vertex format */
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ attr_id.data = GWN_vertformat_attr_add(&format, "data", GWN_COMP_U8, 1, GWN_FETCH_INT);
+ }
+
+ const int vert_len = lattice_render_data_verts_len_get(rdata);
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_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;
+ }
+ }
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, i, bp->vec);
+ GWN_vertbuf_attr_set(vbo, attr_id.data, i, &vflag);
+ }
+
+ cache->overlay_verts = GWN_batch_create(GWN_PRIM_POINTS, vbo, NULL);
+ }
+
+ lattice_render_data_free(rdata);
+}
+
+Gwn_Batch *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 = GWN_batch_create(GWN_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;
+}
+
+Gwn_Batch *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 = GWN_batch_create(GWN_PRIM_POINTS, lattice_batch_cache_get_pos(rdata, cache, false, -1), NULL);
+
+ lattice_render_data_free(rdata);
+ }
+
+ return cache->all_verts;
+}
+
+Gwn_Batch *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..f48d739f11b
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -0,0 +1,3472 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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_utildefines.h"
+#include "BLI_math_vector.h"
+#include "BLI_math_bits.h"
+#include "BLI_string.h"
+#include "BLI_alloca.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_deform.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_editmesh.h"
+#include "BKE_editmesh_tangent.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_tangent.h"
+#include "BKE_texture.h"
+
+#include "bmesh.h"
+
+#include "GPU_batch.h"
+#include "GPU_draw.h"
+#include "GPU_material.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 EdgeDrawAttr {
+ unsigned char v_flag;
+ unsigned char e_flag;
+ unsigned char crease;
+ unsigned char 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;
+
+ BMEditMesh *edit_bmesh;
+ MVert *mvert;
+ MEdge *medge;
+ MLoop *mloop;
+ MPoly *mpoly;
+ float (*orco)[3];
+ MDeformVert *dvert;
+ MLoopUV *mloopuv;
+ MLoopCol *mloopcol;
+
+ /* 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;
+ } 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_color)[3];
+ char (*vert_color)[3];
+ Gwn_PackedNormal *poly_normals_pack;
+ Gwn_PackedNormal *vert_normals_pack;
+ bool *edge_select_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;
+ }
+ }
+ }
+ }
+ }
+}
+
+/**
+ * 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 thats 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);
+
+ if (me->edit_btmesh) {
+ BMEditMesh *embm = me->edit_btmesh;
+ BMesh *bm = embm->bm;
+
+ rdata->edit_bmesh = embm;
+
+ 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) {
+ BKE_editmesh_tessface_calc(embm);
+ rdata->tri_len = embm->tottri;
+ }
+ if (types & MR_DATATYPE_LOOP) {
+ rdata->loop_len = bm->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);
+ }
+ if (types & (MR_DATATYPE_DVERT)) {
+ 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_OVERLAY) {
+ rdata->loose_vert_len = rdata->loose_edge_len = 0;
+
+ int *lverts = rdata->loose_verts = MEM_mallocN(rdata->vert_len * sizeof(int), "Loose Vert");
+ int *ledges = rdata->loose_edges = MEM_mallocN(rdata->edge_len * sizeof(int), "Loose Edges");
+
+ {
+ BLI_assert((bm->elem_table_dirty & BM_VERT) == 0);
+ BMVert **vtable = bm->vtable;
+ for (int i = 0; i < bm->totvert; i++) {
+ const BMVert *eve = vtable[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;
+ }
+ }
+ }
+ }
+
+ {
+ BLI_assert((bm->elem_table_dirty & BM_EDGE) == 0);
+ BMEdge **etable = bm->etable;
+ for (int i = 0; i < bm->totedge; i++) {
+ const BMEdge *eed = etable[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_verts = MEM_reallocN(rdata->loose_verts, rdata->loose_vert_len * sizeof(int));
+ rdata->loose_edges = MEM_reallocN(rdata->loose_edges, rdata->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);
+ rdata->mlooptri = MEM_mallocN(sizeof(*rdata->mlooptri) * tri_len, __func__);
+ BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, rdata->mlooptri);
+ }
+ if (types & MR_DATATYPE_LOOP) {
+ rdata->loop_len = me->totloop;
+ rdata->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP);
+ }
+ 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
+
+ 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) {
+ 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);
+ BMVert **vtable = bm->vtable;
+ for (int i = 0; i < bm->totvert; i++) {
+ copy_v3_v3(rdata->orco[i], vtable[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;
+ }
+
+ const bool is_auto_smooth = (me->flag & ME_AUTOSMOOTH) != 0;
+
+ /* 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);
+ unsigned int 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);
+ unsigned int 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) {
+ /* TODO: split normals, see below */
+ }
+
+ bool calc_active_tangent = false;
+ float (*poly_normals)[3] = rdata->poly_normals;
+ float (*loop_normals)[3] = CustomData_get_layer(cd_ldata, CD_NORMAL);
+
+ BKE_editmesh_loop_tangent_calc(
+ em, calc_active_tangent,
+ tangent_names, actual_tangent_len,
+ poly_normals, loop_normals,
+ rdata->orco,
+ &rdata->cd.output.ldata, bm->totloop,
+ &rdata->cd.output.tangent_mask);
+ }
+ else {
+#undef me
+
+ if (is_auto_smooth) {
+ if (!CustomData_has_layer(cd_ldata, CD_NORMAL)) {
+ BKE_mesh_calc_normals_split(me);
+ }
+ }
+
+ bool calc_active_tangent = false;
+ const float (*poly_normals)[3] = rdata->poly_normals;
+ const float (*loop_normals)[3] = CustomData_get_layer(cd_ldata, CD_NORMAL);
+
+ 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,
+ poly_normals, 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);
+ unsigned int 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);
+ unsigned int 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)
+{
+ 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->poly_normals);
+ MEM_SAFE_FREE(rdata->poly_normals_pack);
+ MEM_SAFE_FREE(rdata->vert_normals_pack);
+ MEM_SAFE_FREE(rdata->vert_weight_color);
+ MEM_SAFE_FREE(rdata->edge_select_bool);
+ MEM_SAFE_FREE(rdata->vert_color);
+
+ 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_loose_verts_len_get(const MeshRenderData *rdata)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_OVERLAY);
+ return rdata->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_loose_edges_len_get(const MeshRenderData *rdata)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_OVERLAY);
+ return rdata->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_mat_len_get(const MeshRenderData *rdata)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_POLY);
+ return rdata->mat_len;
+}
+
+static int UNUSED_FUNCTION(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;
+}
+
+/** \} */
+
+
+/* ---------------------------------------------------------------------- */
+
+/** \name Internal Cache (Lazy Initialization)
+ * \{ */
+
+/** Ensure #MeshRenderData.poly_normals_pack */
+static void mesh_render_data_ensure_poly_normals_pack(MeshRenderData *rdata)
+{
+ Gwn_PackedNormal *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__);
+ BM_ITER_MESH_INDEX(efa, &fiter, bm, BM_FACES_OF_MESH, i) {
+ pnors_pack[i] = GWN_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] = GWN_normal_convert_i10_v3(pnors[i]);
+ }
+ }
+ }
+}
+
+/** Ensure #MeshRenderData.vert_normals_pack */
+static void mesh_render_data_ensure_vert_normals_pack(MeshRenderData *rdata)
+{
+ Gwn_PackedNormal *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] = GWN_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;
+ }
+}
+
+/* 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;
+ }
+}
+
+
+/** Ensure #MeshRenderData.vert_weight_color */
+static void mesh_render_data_ensure_vert_weight_color(MeshRenderData *rdata, const int defgroup)
+{
+ float (*vweight)[3] = rdata->vert_weight_color;
+ if (vweight == NULL) {
+ if (defgroup == -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_color = 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);
+ float weight = defvert_find_weight(dvert, defgroup);
+ if (U.flag & USER_CUSTOM_RANGE) {
+ do_colorband(&U.coba_weight, weight, vweight[i]);
+ }
+ else {
+ rgb_from_weight(vweight[i], weight);
+ }
+ }
+ }
+ else {
+ if (rdata->dvert == NULL) {
+ goto fallback;
+ }
+
+ vweight = rdata->vert_weight_color = MEM_mallocN(sizeof(*vweight) * rdata->vert_len, __func__);
+ for (int i = 0; i < rdata->vert_len; i++) {
+ float weight = defvert_find_weight(&rdata->dvert[i], defgroup);
+ if (U.flag & USER_CUSTOM_RANGE) {
+ do_colorband(&U.coba_weight, weight, vweight[i]);
+ }
+ else {
+ rgb_from_weight(vweight[i], weight);
+ }
+ }
+ }
+ }
+ return;
+
+fallback:
+ vweight = rdata->vert_weight_color = MEM_callocN(sizeof(*vweight) * rdata->vert_len, __func__);
+
+ for (int i = 0; i < rdata->vert_len; i++) {
+ vweight[i][2] = 0.5f;
+ }
+}
+
+/** 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++) {
+ MPoly *poly = &rdata->mpoly[i];
+
+ if (poly->flag & ME_FACE_SEL) {
+ for (int j = 0; j < poly->totloop; j++) {
+ 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];
+ }
+ }
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+
+/** \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;
+ }
+ 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_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 {
+ *r_is_manifold = false;
+ }
+ }
+ else {
+ MVert *mvert = rdata->mvert;
+ 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 = (pnors == NULL);
+
+ eap = rdata->edges_adjacent_polys = MEM_callocN(sizeof(*eap) * rdata->edge_len, __func__);
+ 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 && pnors);
+
+ *r_vco1 = mvert[medge[edge_index].v1].co;
+ *r_vco2 = mvert[medge[edge_index].v2].co;
+ if (eap[edge_index].count == 2) {
+ *r_pnor1 = pnors[eap[edge_index].face_index[0]];
+ *r_pnor2 = pnors[eap[edge_index].face_index[1]];
+ *r_is_manifold = true;
+ }
+ else {
+ *r_is_manifold = false;
+ }
+ }
+
+ return true;
+}
+
+
+/* First 2 bytes are bit flags
+ * 3rd is for sharp edges
+ * 4rd is for creased edges */
+enum {
+ VFLAG_VERTEX_ACTIVE = 1 << 0,
+ VFLAG_VERTEX_SELECTED = 1 << 1,
+ VFLAG_FACE_ACTIVE = 1 << 2,
+ VFLAG_FACE_SELECTED = 1 << 3,
+};
+
+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,
+ /* Beware to not go over 1 << 7
+ * (see gpu_shader_edit_mesh_overlay_geom.glsl) */
+};
+
+static unsigned char mesh_render_data_looptri_flag(MeshRenderData *rdata, const BMFace *efa)
+{
+ unsigned char fflag = 0;
+
+ if (efa == rdata->efa_act)
+ fflag |= VFLAG_FACE_ACTIVE;
+
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ fflag |= VFLAG_FACE_SELECTED;
+
+ 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 = (char)(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 = (char)(bweight * 255.0f);
+ }
+ }
+}
+
+static unsigned char mesh_render_data_vertex_flag(MeshRenderData *rdata, const BMVert *eve)
+{
+
+ unsigned char vflag = 0;
+
+ /* 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, Gwn_VertBuf *vbo_pos, Gwn_VertBuf *vbo_nor, Gwn_VertBuf *vbo_data,
+ const unsigned int pos_id, const unsigned int vnor_id, const unsigned int lnor_id, const unsigned int data_id,
+ const BMLoop **bm_looptri, const int base_vert_idx)
+{
+ unsigned char fflag;
+ unsigned char vflag;
+
+ if (vbo_pos) {
+ for (uint i = 0; i < 3; i++) {
+ const float *pos = bm_looptri[i]->v->co;
+ GWN_vertbuf_attr_set(vbo_pos, pos_id, base_vert_idx + i, pos);
+ }
+ }
+
+ if (vbo_nor) {
+ /* TODO real loop normal */
+ Gwn_PackedNormal lnor = GWN_normal_convert_i10_v3(bm_looptri[0]->f->no);
+ for (uint i = 0; i < 3; i++) {
+ Gwn_PackedNormal vnor = GWN_normal_convert_i10_v3(bm_looptri[i]->v->no);
+ GWN_vertbuf_attr_set(vbo_nor, vnor_id, base_vert_idx + i, &vnor);
+ GWN_vertbuf_attr_set(vbo_nor, lnor_id, base_vert_idx + i, &lnor);
+ }
+ }
+
+ if (vbo_data) {
+ fflag = mesh_render_data_looptri_flag(rdata, bm_looptri[0]->f);
+ uint i_prev = 1, i = 2;
+ for (uint i_next = 0; i_next < 3; i_next++) {
+ vflag = mesh_render_data_vertex_flag(rdata, bm_looptri[i]->v);
+ EdgeDrawAttr eattr = {0};
+ if (bm_looptri[i_next] == bm_looptri[i_prev]->prev) {
+ mesh_render_data_edge_flag(rdata, bm_looptri[i_next]->e, &eattr);
+ }
+ eattr.v_flag = fflag | vflag;
+ GWN_vertbuf_attr_set(vbo_data, data_id, base_vert_idx + i, &eattr);
+
+ i_prev = i;
+ i = i_next;
+ }
+ }
+}
+
+static void add_overlay_loose_edge(
+ MeshRenderData *rdata, Gwn_VertBuf *vbo_pos, Gwn_VertBuf *vbo_nor, Gwn_VertBuf *vbo_data,
+ const unsigned int pos_id, const unsigned int vnor_id, const unsigned int data_id,
+ const BMEdge *eed, const int base_vert_idx)
+{
+ if (vbo_pos) {
+ for (int i = 0; i < 2; ++i) {
+ const float *pos = (&eed->v1)[i]->co;
+ GWN_vertbuf_attr_set(vbo_pos, pos_id, base_vert_idx + i, pos);
+ }
+ }
+
+ if (vbo_nor) {
+ for (int i = 0; i < 2; ++i) {
+ Gwn_PackedNormal vnor = GWN_normal_convert_i10_v3((&eed->v1)[i]->no);
+ GWN_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]);
+ GWN_vertbuf_attr_set(vbo_data, data_id, base_vert_idx + i, &eattr);
+ }
+ }
+}
+
+static void add_overlay_loose_vert(
+ MeshRenderData *rdata, Gwn_VertBuf *vbo_pos, Gwn_VertBuf *vbo_nor, Gwn_VertBuf *vbo_data,
+ const unsigned int pos_id, const unsigned int vnor_id, const unsigned int data_id,
+ const BMVert *eve, const int base_vert_idx)
+{
+ if (vbo_pos) {
+ const float *pos = eve->co;
+ GWN_vertbuf_attr_set(vbo_pos, pos_id, base_vert_idx, pos);
+ }
+
+ if (vbo_nor) {
+ Gwn_PackedNormal vnor = GWN_normal_convert_i10_v3(eve->no);
+ GWN_vertbuf_attr_set(vbo_nor, vnor_id, base_vert_idx, &vnor);
+ }
+
+ if (vbo_data) {
+ unsigned char vflag[4] = {0, 0, 0, 0};
+ vflag[0] = mesh_render_data_vertex_flag(rdata, eve);
+ GWN_vertbuf_attr_set(vbo_data, data_id, base_vert_idx, vflag);
+ }
+}
+
+/** \} */
+
+
+/* ---------------------------------------------------------------------- */
+
+/** \name Mesh Gwn_Batch Cache
+ * \{ */
+
+typedef struct MeshBatchCache {
+ Gwn_VertBuf *pos_in_order;
+ Gwn_VertBuf *nor_in_order;
+ Gwn_IndexBuf *edges_in_order;
+ Gwn_IndexBuf *triangles_in_order;
+ Gwn_IndexBuf *overlay_triangles_vpaint;
+
+ Gwn_Batch *all_verts;
+ Gwn_Batch *all_edges;
+ Gwn_Batch *all_triangles;
+
+ Gwn_VertBuf *pos_with_normals;
+ Gwn_VertBuf *pos_with_normals_visible_only; /* for paint modes with vert/face hide support. */
+ Gwn_VertBuf *tri_aligned_weights;
+ Gwn_VertBuf *tri_aligned_vert_colors;
+ Gwn_VertBuf *tri_aligned_select_id;
+ Gwn_VertBuf *tri_aligned_uv; /* Active UV layer (mloopuv) */
+ Gwn_VertBuf *edge_pos_with_select_bool;
+ Gwn_VertBuf *pos_with_select_bool;
+ Gwn_Batch *triangles_with_normals;
+
+ /* Skip hidden (depending on paint select mode),
+ * 'pos_with_normals' or 'pos_with_normals_visible_only'. */
+ Gwn_Batch *triangles_with_weights;
+ Gwn_Batch *triangles_with_vert_colors;
+ /* Always skip hidden */
+ Gwn_Batch *triangles_with_select_id;
+
+ Gwn_Batch *points_with_normals;
+ Gwn_Batch *fancy_edges; /* owns its vertex buffer (not shared) */
+
+ /* Maybe have shaded_triangles_data split into pos_nor and uv_tangent
+ * to minimise data transfer for skinned mesh. */
+ Gwn_VertFormat shaded_triangles_format;
+ Gwn_VertBuf *shaded_triangles_data;
+ Gwn_IndexBuf **shaded_triangles_in_order;
+ Gwn_Batch **shaded_triangles;
+
+ /* Texture Paint.*/
+ /* per-texture batch */
+ Gwn_Batch **texpaint_triangles;
+ Gwn_Batch *texpaint_triangles_single;
+
+ /* Edit Cage Mesh buffers */
+ Gwn_VertBuf *ed_tri_pos;
+ Gwn_VertBuf *ed_tri_nor; /* LoopNor, VertNor */
+ Gwn_VertBuf *ed_tri_data;
+
+ Gwn_VertBuf *ed_ledge_pos;
+ Gwn_VertBuf *ed_ledge_nor; /* VertNor */
+ Gwn_VertBuf *ed_ledge_data;
+
+ Gwn_VertBuf *ed_lvert_pos;
+ Gwn_VertBuf *ed_lvert_nor; /* VertNor */
+ Gwn_VertBuf *ed_lvert_data;
+
+ Gwn_VertBuf *ed_fcenter_pos;
+ Gwn_VertBuf *ed_fcenter_nor;
+
+ Gwn_Batch *overlay_triangles;
+ Gwn_Batch *overlay_triangles_nor; /* GWN_PRIM_POINTS */
+ Gwn_Batch *overlay_loose_edges;
+ Gwn_Batch *overlay_loose_edges_nor; /* GWN_PRIM_POINTS */
+ Gwn_Batch *overlay_loose_verts;
+ Gwn_Batch *overlay_facedots;
+
+ Gwn_Batch *overlay_weight_faces;
+ Gwn_Batch *overlay_weight_verts;
+ Gwn_Batch *overlay_paint_edges;
+
+ /* settings to determine if cache is invalid */
+ bool is_dirty;
+ bool is_really_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;
+
+ /* XXX, only keep for as long as sculpt mode uses shaded drawing. */
+ bool is_sculpt_points_tag;
+} MeshBatchCache;
+
+/* Gwn_Batch cache management. */
+
+static bool mesh_batch_cache_valid(Mesh *me)
+{
+ MeshBatchCache *cache = me->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_dirty = true;
+ }
+
+ if (cache->is_editmode != (me->edit_btmesh != NULL)) {
+ return false;
+ }
+
+ if (cache->is_really_dirty) {
+ return false;
+ }
+
+ if (cache->is_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->batch_cache;
+
+ if (!cache) {
+ cache = me->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_dirty = false;
+ cache->is_really_dirty = false;
+}
+
+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->batch_cache;
+}
+
+void DRW_mesh_batch_cache_dirty(Mesh *me, int mode)
+{
+ MeshBatchCache *cache = me->batch_cache;
+ if (cache == NULL) {
+ return;
+ }
+ switch (mode) {
+ case BKE_MESH_BATCH_DIRTY_ALL:
+ cache->is_dirty = true;
+ break;
+ case BKE_MESH_BATCH_DIRTY_SELECT:
+ GWN_VERTBUF_DISCARD_SAFE(cache->ed_tri_data);
+ GWN_VERTBUF_DISCARD_SAFE(cache->ed_ledge_data);
+ GWN_VERTBUF_DISCARD_SAFE(cache->ed_lvert_data);
+ GWN_VERTBUF_DISCARD_SAFE(cache->ed_fcenter_nor); /* Contains select flag */
+ GWN_BATCH_DISCARD_SAFE(cache->overlay_triangles);
+ GWN_BATCH_DISCARD_SAFE(cache->overlay_loose_verts);
+ GWN_BATCH_DISCARD_SAFE(cache->overlay_loose_edges);
+
+ BATCH_DISCARD_ALL_SAFE(cache->overlay_facedots);
+ break;
+ case BKE_MESH_BATCH_DIRTY_NOCHECK:
+ cache->is_really_dirty = true;
+ break;
+ case BKE_MESH_BATCH_DIRTY_SHADING:
+ /* TODO: This should only update UV and tangent data,
+ * and not free the entire cache. */
+ cache->is_really_dirty = true;
+ break;
+ case BKE_MESH_BATCH_DIRTY_SCULPT_COORDS:
+ cache->is_sculpt_points_tag = true;
+ break;
+ default:
+ BLI_assert(0);
+ }
+}
+
+static void mesh_batch_cache_clear(Mesh *me)
+{
+ MeshBatchCache *cache = me->batch_cache;
+ if (!cache) {
+ return;
+ }
+
+ GWN_BATCH_DISCARD_SAFE(cache->all_verts);
+ GWN_BATCH_DISCARD_SAFE(cache->all_edges);
+ GWN_BATCH_DISCARD_SAFE(cache->all_triangles);
+
+ GWN_VERTBUF_DISCARD_SAFE(cache->pos_in_order);
+ GWN_VERTBUF_DISCARD_SAFE(cache->pos_with_select_bool);
+ GWN_INDEXBUF_DISCARD_SAFE(cache->edges_in_order);
+ GWN_INDEXBUF_DISCARD_SAFE(cache->triangles_in_order);
+ GWN_INDEXBUF_DISCARD_SAFE(cache->overlay_triangles_vpaint);
+
+ GWN_VERTBUF_DISCARD_SAFE(cache->ed_tri_pos);
+ GWN_VERTBUF_DISCARD_SAFE(cache->ed_tri_nor);
+ GWN_VERTBUF_DISCARD_SAFE(cache->ed_tri_data);
+ GWN_VERTBUF_DISCARD_SAFE(cache->ed_ledge_pos);
+ GWN_VERTBUF_DISCARD_SAFE(cache->ed_ledge_nor);
+ GWN_VERTBUF_DISCARD_SAFE(cache->ed_ledge_data);
+ GWN_VERTBUF_DISCARD_SAFE(cache->ed_lvert_pos);
+ GWN_VERTBUF_DISCARD_SAFE(cache->ed_lvert_nor);
+ GWN_VERTBUF_DISCARD_SAFE(cache->ed_lvert_data);
+ GWN_VERTBUF_DISCARD_SAFE(cache->ed_fcenter_pos);
+ GWN_VERTBUF_DISCARD_SAFE(cache->ed_fcenter_nor);
+ GWN_BATCH_DISCARD_SAFE(cache->overlay_triangles);
+ GWN_BATCH_DISCARD_SAFE(cache->overlay_triangles_nor);
+ GWN_BATCH_DISCARD_SAFE(cache->overlay_loose_verts);
+ GWN_BATCH_DISCARD_SAFE(cache->overlay_loose_edges);
+ GWN_BATCH_DISCARD_SAFE(cache->overlay_loose_edges_nor);
+
+ GWN_BATCH_DISCARD_SAFE(cache->overlay_weight_faces);
+ GWN_BATCH_DISCARD_SAFE(cache->overlay_weight_verts);
+ BATCH_DISCARD_ALL_SAFE(cache->overlay_paint_edges);
+ BATCH_DISCARD_ALL_SAFE(cache->overlay_facedots);
+
+ GWN_BATCH_DISCARD_SAFE(cache->triangles_with_normals);
+ GWN_BATCH_DISCARD_SAFE(cache->points_with_normals);
+ GWN_VERTBUF_DISCARD_SAFE(cache->pos_with_normals);
+ GWN_VERTBUF_DISCARD_SAFE(cache->pos_with_normals_visible_only);
+ GWN_VERTBUF_DISCARD_SAFE(cache->tri_aligned_vert_colors);
+ GWN_VERTBUF_DISCARD_SAFE(cache->tri_aligned_weights);
+ GWN_BATCH_DISCARD_SAFE(cache->triangles_with_weights);
+ GWN_BATCH_DISCARD_SAFE(cache->triangles_with_vert_colors);
+ GWN_VERTBUF_DISCARD_SAFE(cache->tri_aligned_select_id);
+ GWN_VERTBUF_DISCARD_SAFE(cache->tri_aligned_uv);
+ GWN_BATCH_DISCARD_SAFE(cache->triangles_with_select_id);
+
+ BATCH_DISCARD_ALL_SAFE(cache->fancy_edges);
+
+ GWN_VERTBUF_DISCARD_SAFE(cache->shaded_triangles_data);
+ if (cache->shaded_triangles_in_order) {
+ for (int i = 0; i < cache->mat_len; ++i) {
+ GWN_INDEXBUF_DISCARD_SAFE(cache->shaded_triangles_in_order[i]);
+ }
+ }
+ if (cache->shaded_triangles) {
+ for (int i = 0; i < cache->mat_len; ++i) {
+ GWN_BATCH_DISCARD_SAFE(cache->shaded_triangles[i]);
+ }
+ }
+
+ MEM_SAFE_FREE(cache->shaded_triangles_in_order);
+ MEM_SAFE_FREE(cache->shaded_triangles);
+
+ if (cache->texpaint_triangles) {
+ for (int i = 0; i < cache->mat_len; ++i) {
+ GWN_BATCH_DISCARD_SAFE(cache->texpaint_triangles[i]);
+ }
+ }
+ MEM_SAFE_FREE(cache->texpaint_triangles);
+
+ GWN_BATCH_DISCARD_SAFE(cache->texpaint_triangles_single);
+
+}
+
+void DRW_mesh_batch_cache_free(Mesh *me)
+{
+ mesh_batch_cache_clear(me);
+ MEM_SAFE_FREE(me->batch_cache);
+}
+
+/* Gwn_Batch cache usage. */
+
+static Gwn_VertBuf *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));
+#define USE_COMP_MESH_DATA
+
+ 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;
+
+ if (layers_combined_len == 0) {
+ return NULL;
+ }
+
+ Gwn_VertFormat *format = &cache->shaded_triangles_format;
+
+ GWN_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; }
+
+ 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] = GWN_vertformat_attr_add(format, attrib_name, GWN_COMP_I16, 2, GWN_FETCH_INT_TO_FLOAT_UNIT);
+#else
+ uv_id[i] = GWN_vertformat_attr_add(format, attrib_name, GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+#endif
+
+ /* Auto Name */
+ attrib_name = mesh_render_data_uv_auto_layer_uuid_get(rdata, i);
+ GWN_vertformat_alias_add(format, attrib_name);
+
+ if (i == rdata->cd.layers.uv_active) {
+ GWN_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);
+ /* WATCH IT : only specifying 3 component instead of 4 (4th is sign).
+ * That may cause some problem but I could not make it to fail (fclem) */
+#ifdef USE_COMP_MESH_DATA
+ /* Tangents need more precision than 10_10_10 */
+ tangent_id[i] = GWN_vertformat_attr_add(format, attrib_name, GWN_COMP_I16, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+#else
+ tangent_id[i] = GWN_vertformat_attr_add(format, attrib_name, GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+#endif
+
+ if (i == rdata->cd.layers.tangent_active) {
+ GWN_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] = GWN_vertformat_attr_add(format, attrib_name, GWN_COMP_U8, 3, GWN_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);
+ GWN_vertformat_alias_add(format, attrib_name);
+ }
+
+ if (i == rdata->cd.layers.vcol_active) {
+ GWN_vertformat_alias_add(format, "c");
+ }
+ }
+
+ const uint tri_len = mesh_render_data_looptri_len_get(rdata);
+
+ Gwn_VertBuf *vbo = cache->shaded_triangles_data = GWN_vertbuf_create_with_format(format);
+
+ const int vbo_len_capacity = tri_len * 3;
+ int vbo_len_used = 0;
+ GWN_vertbuf_data_alloc(vbo, vbo_len_capacity);
+
+ Gwn_VertBufRaw *layers_combined_step = BLI_array_alloca(layers_combined_step, layers_combined_len);
+
+ Gwn_VertBufRaw *uv_step = layers_combined_step;
+ Gwn_VertBufRaw *tangent_step = uv_step + uv_len;
+ Gwn_VertBufRaw *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++) {
+ GWN_vertbuf_attr_get_raw_data(vbo, uv_id[i], &uv_step[i]);
+ }
+ for (uint i = 0; i < tangent_len; i++) {
+ GWN_vertbuf_attr_get_raw_data(vbo, tangent_id[i], &tangent_step[i]);
+ }
+ for (uint i = 0; i < vcol_len; i++) {
+ GWN_vertbuf_attr_get_raw_data(vbo, vcol_id[i], &vcol_step[i]);
+ }
+
+ /* TODO deduplicate all verts and make use of Gwn_IndexBuf 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(GWN_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])];
+ normal_float_to_short_v3(GWN_vertbuf_raw_step(&tangent_step[j]), elem);
+ }
+ }
+ /* 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(GWN_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(GWN_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_v3(GWN_vertbuf_raw_step(&tangent_step[j]), elem);
+#else
+ copy_v3_v3(GWN_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(GWN_vertbuf_raw_step(&vcol_step[j]), elem);
+ }
+ }
+ }
+ }
+
+ vbo_len_used = GWN_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 == GWN_vertbuf_raw_used(&layers_combined_step[i]));
+ }
+ }
+#endif
+
+ if (vbo_len_capacity != vbo_len_used) {
+ GWN_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+ }
+
+#undef USE_COMP_MESH_DATA
+
+ return cache->shaded_triangles_data;
+}
+
+static Gwn_VertBuf *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));
+ BLI_assert(rdata->edit_bmesh == NULL);
+
+ if (cache->tri_aligned_uv == NULL) {
+ unsigned int vidx = 0;
+
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint uv; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.uv = GWN_vertformat_attr_add(&format, "uv", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ }
+
+ const int tri_len = mesh_render_data_looptri_len_get(rdata);
+
+ Gwn_VertBuf *vbo = cache->tri_aligned_uv = GWN_vertbuf_create_with_format(&format);
+
+ const int vbo_len_capacity = tri_len * 3;
+ int vbo_len_used = 0;
+ GWN_vertbuf_data_alloc(vbo, vbo_len_capacity);
+
+ const MLoopUV *mloopuv = rdata->mloopuv;
+
+ for (int i = 0; i < tri_len; i++) {
+ const MLoopTri *mlt = &rdata->mlooptri[i];
+ GWN_vertbuf_attr_set(vbo, attr_id.uv, vidx++, mloopuv[mlt->tri[0]].uv);
+ GWN_vertbuf_attr_set(vbo, attr_id.uv, vidx++, mloopuv[mlt->tri[1]].uv);
+ GWN_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 Gwn_VertBuf *mesh_batch_cache_get_tri_pos_and_normals_ex(
+ MeshRenderData *rdata, const bool use_hide,
+ Gwn_VertBuf **r_vbo)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY));
+
+ if (*r_vbo == NULL) {
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos, nor; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ attr_id.nor = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_I10, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ }
+
+ const int tri_len = mesh_render_data_looptri_len_get(rdata);
+
+ Gwn_VertBuf *vbo = *r_vbo = GWN_vertbuf_create_with_format(&format);
+
+ const int vbo_len_capacity = tri_len * 3;
+ int vbo_len_used = 0;
+ GWN_vertbuf_data_alloc(vbo, vbo_len_capacity);
+
+ Gwn_VertBufRaw pos_step, nor_step;
+ GWN_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step);
+ GWN_vertbuf_attr_get_raw_data(vbo, attr_id.nor, &nor_step);
+
+ if (rdata->edit_bmesh) {
+ mesh_render_data_ensure_poly_normals_pack(rdata);
+ mesh_render_data_ensure_vert_normals_pack(rdata);
+
+ Gwn_PackedNormal *pnors_pack = rdata->poly_normals_pack;
+ Gwn_PackedNormal *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;
+ }
+
+ const uint vtri[3] = {
+ BM_elem_index_get(bm_looptri[0]->v),
+ BM_elem_index_get(bm_looptri[1]->v),
+ BM_elem_index_get(bm_looptri[2]->v),
+ };
+
+ if (BM_elem_flag_test(bm_face, BM_ELEM_SMOOTH)) {
+ for (uint t = 0; t < 3; t++) {
+ *((Gwn_PackedNormal *)GWN_vertbuf_raw_step(&nor_step)) = vnors_pack[vtri[t]];
+ }
+ }
+ else {
+ const Gwn_PackedNormal *snor_pack = &pnors_pack[BM_elem_index_get(bm_face)];
+ for (uint t = 0; t < 3; t++) {
+ *((Gwn_PackedNormal *)GWN_vertbuf_raw_step(&nor_step)) = *snor_pack;
+ }
+ }
+
+ for (uint t = 0; t < 3; t++) {
+ copy_v3_v3(GWN_vertbuf_raw_step(&pos_step), bm_looptri[t]->v->co);
+ }
+ }
+ }
+ else {
+
+ /* 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 (mp->flag & ME_SMOOTH) {
+ for (uint t = 0; t < 3; t++) {
+ const MVert *mv = &rdata->mvert[vtri[t]];
+ *((Gwn_PackedNormal *)GWN_vertbuf_raw_step(&nor_step)) = GWN_normal_convert_i10_s3(mv->no);
+ }
+ }
+ else {
+ const Gwn_PackedNormal *pnors_pack = &rdata->poly_normals_pack[mlt->poly];
+ for (uint t = 0; t < 3; t++) {
+ *((Gwn_PackedNormal *)GWN_vertbuf_raw_step(&nor_step)) = *pnors_pack;
+ }
+ }
+
+ for (uint t = 0; t < 3; t++) {
+ const MVert *mv = &rdata->mvert[vtri[t]];
+ copy_v3_v3(GWN_vertbuf_raw_step(&pos_step), mv->co);
+ }
+ }
+ }
+
+ vbo_len_used = GWN_vertbuf_raw_used(&pos_step);
+ BLI_assert(vbo_len_used == GWN_vertbuf_raw_used(&nor_step));
+
+ if (vbo_len_capacity != vbo_len_used) {
+ GWN_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+ }
+ return *r_vbo;
+}
+
+static Gwn_VertBuf *mesh_batch_cache_get_tri_pos_and_normals(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ return mesh_batch_cache_get_tri_pos_and_normals_ex(
+ rdata, false,
+ &cache->pos_with_normals);
+}
+static Gwn_VertBuf *mesh_batch_cache_get_tri_pos_and_normals_visible_only(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ return mesh_batch_cache_get_tri_pos_and_normals_ex(
+ rdata, true,
+ &cache->pos_with_normals_visible_only);
+}
+
+static Gwn_VertBuf *mesh_batch_cache_get_tri_weights(
+ MeshRenderData *rdata, MeshBatchCache *cache, bool use_hide, int defgroup)
+{
+ BLI_assert(
+ rdata->types &
+ (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_DVERT));
+
+ if (cache->tri_aligned_weights == NULL) {
+ unsigned int cidx = 0;
+
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint col; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.col = GWN_vertformat_attr_add(&format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ const int tri_len = mesh_render_data_looptri_len_get(rdata);
+
+ Gwn_VertBuf *vbo = cache->tri_aligned_weights = GWN_vertbuf_create_with_format(&format);
+
+ const int vbo_len_capacity = tri_len * 3;
+ int vbo_len_used = 0;
+ GWN_vertbuf_data_alloc(vbo, vbo_len_capacity);
+
+ mesh_render_data_ensure_vert_weight_color(rdata, defgroup);
+ const float (*vert_weight_color)[3] = rdata->vert_weight_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 v_index = BM_elem_index_get(ltri[tri_corner]->v);
+ GWN_vertbuf_attr_set(vbo, attr_id.col, cidx++, vert_weight_color[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;
+ GWN_vertbuf_attr_set(vbo, attr_id.col, cidx++, vert_weight_color[v_index]);
+ }
+ }
+ }
+ }
+ vbo_len_used = cidx;
+
+ if (vbo_len_capacity != vbo_len_used) {
+ GWN_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+ }
+
+ return cache->tri_aligned_weights;
+}
+
+static Gwn_VertBuf *mesh_batch_cache_get_tri_vert_colors(
+ MeshRenderData *rdata, MeshBatchCache *cache, bool use_hide)
+{
+ BLI_assert(
+ rdata->types &
+ (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_LOOPCOL));
+
+ if (cache->tri_aligned_vert_colors == NULL) {
+ unsigned int cidx = 0;
+
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint col; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.col = GWN_vertformat_attr_add(&format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ }
+
+ const int tri_len = mesh_render_data_looptri_len_get(rdata);
+
+ Gwn_VertBuf *vbo = cache->tri_aligned_vert_colors = GWN_vertbuf_create_with_format(&format);
+
+ const uint vbo_len_capacity = tri_len * 3;
+ GWN_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]);
+ GWN_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];
+ GWN_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) {
+ GWN_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+ }
+
+ return cache->tri_aligned_vert_colors;
+}
+
+static Gwn_VertBuf *mesh_batch_cache_get_tri_select_id(
+ MeshRenderData *rdata, MeshBatchCache *cache, bool use_hide)
+{
+ BLI_assert(
+ rdata->types &
+ (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY));
+
+ if (cache->tri_aligned_select_id == NULL) {
+ unsigned int cidx = 0;
+
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint col; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.col = GWN_vertformat_attr_add(&format, "color", GWN_COMP_I32, 1, GWN_FETCH_INT);
+ }
+
+ const int tri_len = mesh_render_data_looptri_len_get(rdata);
+
+ Gwn_VertBuf *vbo = cache->tri_aligned_select_id = GWN_vertbuf_create_with_format(&format);
+
+ const int vbo_len_capacity = tri_len * 3;
+ int vbo_len_used = 0;
+ GWN_vertbuf_data_alloc(vbo, vbo_len_capacity);
+
+ 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 + 1, &select_id);
+ for (uint tri_corner = 0; tri_corner < 3; tri_corner++) {
+ GWN_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 + 1, &select_id);
+ for (uint tri_corner = 0; tri_corner < 3; tri_corner++) {
+ GWN_vertbuf_attr_set(vbo, attr_id.col, cidx++, &select_id);
+ }
+ }
+ }
+ }
+ vbo_len_used = cidx;
+
+ if (vbo_len_capacity != vbo_len_used) {
+ GWN_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+ }
+
+ return cache->tri_aligned_select_id;
+}
+
+static Gwn_VertBuf *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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos, nor; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ attr_id.nor = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_I16, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ }
+
+ Gwn_VertBuf *vbo = cache->pos_in_order = GWN_vertbuf_create_with_format(&format);
+ const int vbo_len_capacity = mesh_render_data_verts_len_get(rdata);
+ GWN_vertbuf_data_alloc(vbo, vbo_len_capacity);
+
+ 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[3];
+ normal_float_to_short_v3(no_short, eve->no);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, i, eve->co);
+ GWN_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) {
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, i, rdata->mvert[i].co);
+ GWN_vertbuf_attr_set(vbo, attr_id.nor, i, rdata->mvert[i].no);
+ }
+ }
+ }
+
+ return cache->pos_in_order;
+}
+
+static Gwn_VertFormat *edit_mesh_overlay_pos_format(unsigned int *r_pos_id)
+{
+ static Gwn_VertFormat format_pos = { 0 };
+ static unsigned pos_id;
+ if (format_pos.attrib_ct == 0) {
+ pos_id = GWN_vertformat_attr_add(&format_pos, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+ *r_pos_id = pos_id;
+ return &format_pos;
+}
+
+static Gwn_VertFormat *edit_mesh_overlay_nor_format(unsigned int *r_vnor_id, unsigned int *r_lnor_id)
+{
+ static Gwn_VertFormat format_nor = { 0 };
+ static Gwn_VertFormat format_nor_loop = { 0 };
+ static unsigned vnor_id, vnor_loop_id, lnor_id;
+ if (format_nor.attrib_ct == 0) {
+ vnor_id = GWN_vertformat_attr_add(&format_nor, "vnor", GWN_COMP_I10, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ vnor_loop_id = GWN_vertformat_attr_add(&format_nor_loop, "vnor", GWN_COMP_I10, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ lnor_id = GWN_vertformat_attr_add(&format_nor_loop, "lnor", GWN_COMP_I10, 3, GWN_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 Gwn_VertFormat *edit_mesh_overlay_data_format(unsigned int *r_data_id)
+{
+ static Gwn_VertFormat format_flag = { 0 };
+ static unsigned data_id;
+ if (format_flag.attrib_ct == 0) {
+ data_id = GWN_vertformat_attr_add(&format_flag, "data", GWN_COMP_U8, 4, GWN_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));
+
+ const int tri_len = mesh_render_data_looptri_len_get(rdata);
+
+ const int vbo_len_capacity = tri_len * 3;
+ int vbo_len_used = 0;
+
+ /* Positions */
+ Gwn_VertBuf *vbo_pos = NULL;
+ static struct { uint pos, vnor, lnor, data; } attr_id;
+ if (cache->ed_tri_pos == NULL) {
+ vbo_pos = cache->ed_tri_pos =
+ GWN_vertbuf_create_with_format(edit_mesh_overlay_pos_format(&attr_id.pos));
+ GWN_vertbuf_data_alloc(vbo_pos, vbo_len_capacity);
+ }
+
+ /* Normals */
+ Gwn_VertBuf *vbo_nor = NULL;
+ if (cache->ed_tri_nor == NULL) {
+ vbo_nor = cache->ed_tri_nor =
+ GWN_vertbuf_create_with_format(edit_mesh_overlay_nor_format(&attr_id.vnor, &attr_id.lnor));
+ GWN_vertbuf_data_alloc(vbo_nor, vbo_len_capacity);
+ }
+
+ /* Data */
+ Gwn_VertBuf *vbo_data = NULL;
+ if (cache->ed_tri_data == NULL) {
+ vbo_data = cache->ed_tri_data =
+ GWN_vertbuf_create_with_format(edit_mesh_overlay_data_format(&attr_id.data));
+ GWN_vertbuf_data_alloc(vbo_data, vbo_len_capacity);
+ }
+
+ 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,
+ attr_id.pos, attr_id.vnor, attr_id.lnor, attr_id.data,
+ bm_looptri, vbo_len_used);
+
+ vbo_len_used += 3;
+ }
+ }
+
+ /* Finish */
+ if (vbo_len_used != vbo_len_capacity) {
+ if (vbo_pos != NULL) {
+ GWN_vertbuf_data_resize(vbo_pos, vbo_len_used);
+ }
+ if (vbo_nor != NULL) {
+ GWN_vertbuf_data_resize(vbo_nor, vbo_len_used);
+ }
+ if (vbo_data != NULL) {
+ GWN_vertbuf_data_resize(vbo_data, vbo_len_used);
+ }
+ }
+}
+
+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(rdata);
+
+ const int vbo_len_capacity = ledge_len * 2;
+ int vbo_len_used = 0;
+
+ /* Positions */
+ Gwn_VertBuf *vbo_pos = NULL;
+ static struct { uint pos, vnor, data; } attr_id;
+ if (cache->ed_ledge_pos == NULL) {
+ vbo_pos = cache->ed_ledge_pos =
+ GWN_vertbuf_create_with_format(edit_mesh_overlay_pos_format(&attr_id.pos));
+ GWN_vertbuf_data_alloc(vbo_pos, vbo_len_capacity);
+ }
+
+ /* Normals */
+ Gwn_VertBuf *vbo_nor = NULL;
+ if (cache->ed_ledge_nor == NULL) {
+ vbo_nor = cache->ed_ledge_nor =
+ GWN_vertbuf_create_with_format(edit_mesh_overlay_nor_format(&attr_id.vnor, NULL));
+ GWN_vertbuf_data_alloc(vbo_nor, vbo_len_capacity);
+ }
+
+ /* Data */
+ Gwn_VertBuf *vbo_data = NULL;
+ if (cache->ed_ledge_data == NULL) {
+ vbo_data = cache->ed_ledge_data =
+ GWN_vertbuf_create_with_format(edit_mesh_overlay_data_format(&attr_id.data));
+ GWN_vertbuf_data_alloc(vbo_data, vbo_len_capacity);
+ }
+
+ 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]);
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ 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;
+ }
+ }
+ }
+
+ /* Finish */
+ if (vbo_len_used != vbo_len_capacity) {
+ if (vbo_pos != NULL) {
+ GWN_vertbuf_data_resize(vbo_pos, vbo_len_used);
+ }
+ if (vbo_nor != NULL) {
+ GWN_vertbuf_data_resize(vbo_nor, vbo_len_used);
+ }
+ if (vbo_data != NULL) {
+ GWN_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(rdata);
+
+ const int vbo_len_capacity = lvert_len;
+ int vbo_len_used = 0;
+
+ static struct { uint pos, vnor, data; } attr_id;
+
+ /* Positions */
+ Gwn_VertBuf *vbo_pos = NULL;
+ if (cache->ed_lvert_pos == NULL) {
+ vbo_pos = cache->ed_lvert_pos =
+ GWN_vertbuf_create_with_format(edit_mesh_overlay_pos_format(&attr_id.pos));
+ GWN_vertbuf_data_alloc(vbo_pos, vbo_len_capacity);
+ }
+
+ /* Normals */
+ Gwn_VertBuf *vbo_nor = NULL;
+ if (cache->ed_lvert_nor == NULL) {
+ vbo_nor = cache->ed_lvert_nor =
+ GWN_vertbuf_create_with_format(edit_mesh_overlay_nor_format(&attr_id.vnor, NULL));
+ GWN_vertbuf_data_alloc(vbo_nor, vbo_len_capacity);
+ }
+
+ /* Data */
+ Gwn_VertBuf *vbo_data = NULL;
+ if (cache->ed_lvert_data == NULL) {
+ vbo_data = cache->ed_lvert_data =
+ GWN_vertbuf_create_with_format(edit_mesh_overlay_data_format(&attr_id.data));
+ GWN_vertbuf_data_alloc(vbo_data, vbo_len_capacity);
+ }
+
+ 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;
+ }
+
+ /* Finish */
+ if (vbo_len_used != vbo_len_capacity) {
+ if (vbo_pos != NULL) {
+ GWN_vertbuf_data_resize(vbo_pos, vbo_len_used);
+ }
+ if (vbo_nor != NULL) {
+ GWN_vertbuf_data_resize(vbo_nor, vbo_len_used);
+ }
+ if (vbo_data != NULL) {
+ GWN_vertbuf_data_resize(vbo_data, vbo_len_used);
+ }
+ }
+}
+
+/* Position */
+static Gwn_VertBuf *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 Gwn_VertBuf *mesh_batch_cache_get_edit_ledge_pos(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_VERT);
+
+ if (cache->ed_ledge_pos == NULL) {
+ mesh_batch_cache_create_overlay_ledge_buffers(rdata, cache);
+ }
+
+ return cache->ed_ledge_pos;
+}
+
+static Gwn_VertBuf *mesh_batch_cache_get_edit_lvert_pos(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_VERT);
+
+ if (cache->ed_lvert_pos == NULL) {
+ mesh_batch_cache_create_overlay_lvert_buffers(rdata, cache);
+ }
+
+ return cache->ed_lvert_pos;
+}
+
+/* Normal */
+static Gwn_VertBuf *mesh_batch_cache_get_edit_tri_nor(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_VERT);
+
+ if (cache->ed_tri_nor == NULL) {
+ mesh_batch_cache_create_overlay_tri_buffers(rdata, cache);
+ }
+
+ return cache->ed_tri_nor;
+}
+
+static Gwn_VertBuf *mesh_batch_cache_get_edit_ledge_nor(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_VERT);
+
+ if (cache->ed_ledge_nor == NULL) {
+ mesh_batch_cache_create_overlay_ledge_buffers(rdata, cache);
+ }
+
+ return cache->ed_ledge_nor;
+}
+
+static Gwn_VertBuf *mesh_batch_cache_get_edit_lvert_nor(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_VERT);
+
+ if (cache->ed_lvert_nor == NULL) {
+ mesh_batch_cache_create_overlay_lvert_buffers(rdata, cache);
+ }
+
+ return cache->ed_lvert_nor;
+}
+
+/* Data */
+static Gwn_VertBuf *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 Gwn_VertBuf *mesh_batch_cache_get_edit_ledge_data(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_VERT);
+
+ if (cache->ed_ledge_data == NULL) {
+ mesh_batch_cache_create_overlay_ledge_buffers(rdata, cache);
+ }
+
+ return cache->ed_ledge_data;
+}
+
+static Gwn_VertBuf *mesh_batch_cache_get_edit_lvert_data(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_VERT);
+
+ if (cache->ed_lvert_data == NULL) {
+ mesh_batch_cache_create_overlay_lvert_buffers(rdata, cache);
+ }
+
+ return cache->ed_lvert_data;
+}
+
+static Gwn_IndexBuf *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);
+
+ Gwn_IndexBufBuilder elb;
+ GWN_indexbuf_init(&elb, GWN_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)) {
+ GWN_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++) {
+ GWN_indexbuf_add_line_verts(&elb, ed->v1, ed->v2);
+ }
+ }
+ cache->edges_in_order = GWN_indexbuf_build(&elb);
+ }
+
+ return cache->edges_in_order;
+}
+
+static Gwn_IndexBuf *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);
+
+ Gwn_IndexBufBuilder elb;
+ GWN_indexbuf_init(&elb, GWN_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++) {
+ GWN_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++) {
+ GWN_indexbuf_add_generic_vert(&elb, mlt->tri[tri_corner]);
+ }
+ }
+ }
+ cache->triangles_in_order = GWN_indexbuf_build(&elb);
+ }
+
+ return cache->triangles_in_order;
+}
+
+static Gwn_IndexBuf **mesh_batch_cache_get_triangles_in_order_split_by_material(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ 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__);
+ Gwn_IndexBufBuilder *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 {
+ for (uint i = 0; i < poly_len; i++) {
+ 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) {
+ GWN_indexbuf_init(&elb[i], GWN_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++) {
+ GWN_indexbuf_add_tri_verts(&elb[ma_id], nidx + 0, nidx + 1, nidx + 2);
+ nidx += 3;
+ }
+ }
+ }
+ }
+ else {
+ for (uint i = 0; i < poly_len; i++) {
+ const MPoly *mp = &rdata->mpoly[i]; ;
+ const short ma_id = mp->mat_nr < mat_len ? mp->mat_nr : 0;
+ for (int j = 2; j < mp->totloop; j++) {
+ GWN_indexbuf_add_tri_verts(&elb[ma_id], nidx + 0, nidx + 1, nidx + 2);
+ nidx += 3;
+ }
+ }
+ }
+
+ /* Build ELBs. */
+ for (int i = 0; i < mat_len; ++i) {
+ cache->shaded_triangles_in_order[i] = GWN_indexbuf_build(&elb[i]);
+ }
+
+ MEM_freeN(mat_tri_len);
+ MEM_freeN(elb);
+ }
+
+ return cache->shaded_triangles_in_order;
+}
+
+static Gwn_VertBuf *mesh_batch_cache_get_edge_pos_with_sel(
+ MeshRenderData *rdata, MeshBatchCache *cache, bool use_wire, bool use_select_bool)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_POLY | MR_DATATYPE_LOOP));
+ BLI_assert(rdata->edit_bmesh == NULL);
+
+ if (!cache->edge_pos_with_select_bool) {
+ unsigned int vidx = 0, cidx = 0;
+
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos, sel; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ attr_id.sel = GWN_vertformat_attr_add(&format, "select", GWN_COMP_U8, 1, GWN_FETCH_INT);
+ }
+
+ const int edge_len = mesh_render_data_edges_len_get(rdata);
+
+ Gwn_VertBuf *vbo = cache->edge_pos_with_select_bool = GWN_vertbuf_create_with_format(&format);
+
+ const int vbo_len_capacity = edge_len * 2;
+ int vbo_len_used = 0;
+ GWN_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;
+
+ for (int i = 0; i < edge_len; i++) {
+ const MEdge *ed = &rdata->medge[i];
+
+ 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;
+ }
+
+ GWN_vertbuf_attr_set(vbo, attr_id.sel, cidx++, &edge_vert_sel);
+ GWN_vertbuf_attr_set(vbo, attr_id.sel, cidx++, &edge_vert_sel);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vidx++, rdata->mvert[ed->v1].co);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vidx++, rdata->mvert[ed->v2].co);
+ }
+ vbo_len_used = vidx;
+
+ if (vbo_len_capacity != vbo_len_used) {
+ GWN_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+ }
+
+ return cache->edge_pos_with_select_bool;
+}
+
+static Gwn_IndexBuf *mesh_batch_cache_get_tri_overlay_weight_faces(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI));
+
+ if (cache->overlay_triangles_vpaint == NULL) {
+ const int vert_len = mesh_render_data_verts_len_get(rdata);
+ const int tri_len = mesh_render_data_looptri_len_get(rdata);
+
+ Gwn_IndexBufBuilder elb;
+ GWN_indexbuf_init(&elb, GWN_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++) {
+ GWN_indexbuf_add_generic_vert(&elb, rdata->mloop[mlt->tri[tri_corner]].v);
+ }
+ }
+ }
+ cache->overlay_triangles_vpaint = GWN_indexbuf_build(&elb);
+ }
+
+ return cache->overlay_triangles_vpaint;
+}
+
+/**
+ * Non-edit mode vertices (only used for weight-paint mode).
+ */
+static Gwn_VertBuf *mesh_batch_cache_get_vert_pos_with_overlay_data(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT));
+ BLI_assert(rdata->edit_bmesh == NULL);
+
+ if (cache->pos_with_select_bool == NULL) {
+ unsigned int cidx = 0;
+
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint data; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.data = GWN_vertformat_attr_add(&format, "data", GWN_COMP_I8, 1, GWN_FETCH_INT);
+ }
+
+ const int vert_len = mesh_render_data_verts_len_get(rdata);
+
+ Gwn_VertBuf *vbo = cache->pos_with_select_bool = GWN_vertbuf_create_with_format(&format);
+
+ const int vbo_len_capacity = vert_len;
+ int vbo_len_used = 0;
+ GWN_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);
+ GWN_vertbuf_attr_set(vbo, attr_id.data, cidx++, &data);
+ }
+ vbo_len_used = cidx;
+
+ if (vbo_len_capacity != vbo_len_used) {
+ GWN_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+ }
+
+ return cache->pos_with_select_bool;
+}
+
+/** \} */
+
+
+/* ---------------------------------------------------------------------- */
+
+/** \name Public API
+ * \{ */
+
+Gwn_Batch *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 = GWN_batch_create(
+ GWN_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;
+}
+
+Gwn_Batch *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 = GWN_batch_create(
+ GWN_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;
+}
+
+Gwn_Batch *DRW_mesh_batch_cache_get_triangles_with_normals(Mesh *me)
+{
+ 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 = GWN_batch_create(
+ GWN_PRIM_TRIS, mesh_batch_cache_get_tri_pos_and_normals(rdata, cache), NULL);
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->triangles_with_normals;
+}
+
+Gwn_Batch *DRW_mesh_batch_cache_get_triangles_with_normals_and_weights(Mesh *me, int defgroup)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ 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 = GWN_batch_create(
+ GWN_PRIM_TRIS, mesh_batch_cache_get_tri_weights(rdata, cache, use_hide, defgroup), NULL);
+
+ Gwn_VertBuf *vbo_tris = use_hide ?
+ mesh_batch_cache_get_tri_pos_and_normals_visible_only(rdata, cache) :
+ mesh_batch_cache_get_tri_pos_and_normals(rdata, cache);
+
+ GWN_batch_vertbuf_add(cache->triangles_with_weights, vbo_tris);
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->triangles_with_weights;
+}
+
+Gwn_Batch *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 = GWN_batch_create(
+ GWN_PRIM_TRIS, mesh_batch_cache_get_tri_vert_colors(rdata, cache, use_hide), NULL);
+
+ Gwn_VertBuf *vbo_tris = use_hide ?
+ mesh_batch_cache_get_tri_pos_and_normals_visible_only(rdata, cache) :
+ mesh_batch_cache_get_tri_pos_and_normals(rdata, cache);
+ GWN_batch_vertbuf_add(cache->triangles_with_vert_colors, vbo_tris);
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->triangles_with_vert_colors;
+}
+
+
+struct Gwn_Batch *DRW_mesh_batch_cache_get_triangles_with_select_id(struct Mesh *me, bool use_hide)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ 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);
+
+ cache->triangles_with_select_id = GWN_batch_create(
+ GWN_PRIM_TRIS, mesh_batch_cache_get_tri_select_id(rdata, cache, use_hide), NULL);
+
+ Gwn_VertBuf *vbo_tris = use_hide ?
+ mesh_batch_cache_get_tri_pos_and_normals_visible_only(rdata, cache) :
+ mesh_batch_cache_get_tri_pos_and_normals(rdata, cache);
+ GWN_batch_vertbuf_add(cache->triangles_with_select_id, vbo_tris);
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->triangles_with_select_id;
+}
+
+Gwn_Batch *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 = GWN_batch_create(
+ GWN_PRIM_POINTS, mesh_batch_cache_get_tri_pos_and_normals(rdata, cache), NULL);
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->points_with_normals;
+}
+
+Gwn_Batch *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 = GWN_batch_create(
+ GWN_PRIM_POINTS, mesh_batch_cache_get_vert_pos_and_nor_in_order(rdata, cache), NULL);
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->all_verts;
+}
+
+Gwn_Batch *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 Gwn_VertFormat format = { 0 };
+ static struct { uint pos, n1, n2; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ attr_id.n1 = GWN_vertformat_attr_add(&format, "N1", GWN_COMP_I10, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ attr_id.n2 = GWN_vertformat_attr_add(&format, "N2", GWN_COMP_I10, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ }
+ Gwn_VertBuf *vbo = GWN_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;
+ GWN_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)) {
+
+ Gwn_PackedNormal n1value = { .x = 0, .y = 0, .z = +511 };
+ Gwn_PackedNormal n2value = { .x = 0, .y = 0, .z = -511 };
+
+ if (is_manifold) {
+ n1value = GWN_normal_convert_i10_v3(pnor1);
+ n2value = GWN_normal_convert_i10_v3(pnor2);
+ }
+
+ const Gwn_PackedNormal *n1 = &n1value;
+ const Gwn_PackedNormal *n2 = &n2value;
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 2 * i, vcos1);
+ GWN_vertbuf_attr_set(vbo, attr_id.n1, 2 * i, n1);
+ GWN_vertbuf_attr_set(vbo, attr_id.n2, 2 * i, n2);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 2 * i + 1, vcos2);
+ GWN_vertbuf_attr_set(vbo, attr_id.n1, 2 * i + 1, n1);
+ GWN_vertbuf_attr_set(vbo, attr_id.n2, 2 * i + 1, n2);
+
+ vbo_len_used += 2;
+ }
+ }
+ if (vbo_len_used != vbo_len_capacity) {
+ GWN_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+
+ cache->fancy_edges = GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->fancy_edges;
+}
+
+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 (cache->overlay_triangles == NULL) {
+ cache->overlay_triangles = GWN_batch_create(
+ GWN_PRIM_TRIS, mesh_batch_cache_get_edit_tri_pos(rdata, cache), NULL);
+ GWN_batch_vertbuf_add(cache->overlay_triangles, mesh_batch_cache_get_edit_tri_nor(rdata, cache));
+ GWN_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 = GWN_batch_create(
+ GWN_PRIM_LINES, mesh_batch_cache_get_edit_ledge_pos(rdata, cache), NULL);
+ GWN_batch_vertbuf_add(cache->overlay_loose_edges, mesh_batch_cache_get_edit_ledge_nor(rdata, cache));
+ GWN_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 = GWN_batch_create(
+ GWN_PRIM_POINTS, mesh_batch_cache_get_edit_lvert_pos(rdata, cache), NULL);
+ GWN_batch_vertbuf_add(cache->overlay_loose_verts, mesh_batch_cache_get_edit_lvert_nor(rdata, cache));
+ GWN_batch_vertbuf_add(cache->overlay_loose_verts, mesh_batch_cache_get_edit_lvert_data(rdata, cache));
+ }
+
+ if (cache->overlay_triangles_nor == NULL) {
+ cache->overlay_triangles_nor = GWN_batch_create(
+ GWN_PRIM_POINTS, mesh_batch_cache_get_edit_tri_pos(rdata, cache), NULL);
+ GWN_batch_vertbuf_add(cache->overlay_triangles_nor, mesh_batch_cache_get_edit_tri_nor(rdata, cache));
+ }
+
+ if (cache->overlay_loose_edges_nor == NULL) {
+ cache->overlay_loose_edges_nor = GWN_batch_create(
+ GWN_PRIM_POINTS, mesh_batch_cache_get_edit_ledge_pos(rdata, cache), NULL);
+ GWN_batch_vertbuf_add(cache->overlay_loose_edges_nor, mesh_batch_cache_get_edit_ledge_nor(rdata, cache));
+ }
+
+ mesh_render_data_free(rdata);
+}
+
+Gwn_Batch *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;
+}
+
+Gwn_Batch *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;
+}
+
+Gwn_Batch *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;
+}
+
+Gwn_Batch *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;
+}
+
+Gwn_Batch *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;
+}
+
+Gwn_Batch *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);
+
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos, data; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ attr_id.data = GWN_vertformat_attr_add(&format, "norAndFlag", GWN_COMP_I10, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ }
+
+ const int vbo_len_capacity = mesh_render_data_polys_len_get(rdata);
+ int vidx = 0;
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, vbo_len_capacity);
+ 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)) {
+
+ Gwn_PackedNormal nor = { .x = 0, .y = 0, .z = -511 };
+ nor = GWN_normal_convert_i10_v3(pnor);
+ nor.w = selected ? 1 : 0;
+ GWN_vertbuf_attr_set(vbo, attr_id.data, vidx, &nor);
+
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, vidx, pcenter);
+
+ vidx += 1;
+
+ }
+ }
+ const int vbo_len_used = vidx;
+ if (vbo_len_used != vbo_len_capacity) {
+ GWN_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+
+ cache->overlay_facedots = GWN_batch_create(GWN_PRIM_POINTS, vbo, NULL);
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->overlay_facedots;
+}
+
+Gwn_Batch **DRW_mesh_batch_cache_get_surface_shaded(
+ Mesh *me, struct GPUMaterial **gpumat_array, uint gpumat_array_len)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->shaded_triangles == NULL) {
+ /* 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__);
+
+ Gwn_IndexBuf **el = mesh_batch_cache_get_triangles_in_order_split_by_material(rdata, cache);
+
+ Gwn_VertBuf *vbo = mesh_batch_cache_get_tri_pos_and_normals(rdata, cache);
+ for (int i = 0; i < mat_len; ++i) {
+ cache->shaded_triangles[i] = GWN_batch_create(
+ GWN_PRIM_TRIS, vbo, el[i]);
+ Gwn_VertBuf *vbo_shading = mesh_batch_cache_get_tri_shading_data(rdata, cache);
+ if (vbo_shading) {
+ GWN_batch_vertbuf_add(cache->shaded_triangles[i], vbo_shading);
+ }
+ }
+
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->shaded_triangles;
+}
+
+Gwn_Batch **DRW_mesh_batch_cache_get_surface_texpaint(Mesh *me)
+{
+ 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__);
+
+ Gwn_IndexBuf **el = mesh_batch_cache_get_triangles_in_order_split_by_material(rdata, cache);
+
+ Gwn_VertBuf *vbo = mesh_batch_cache_get_tri_pos_and_normals(rdata, cache);
+ for (int i = 0; i < mat_len; ++i) {
+ cache->texpaint_triangles[i] = GWN_batch_create(
+ GWN_PRIM_TRIS, vbo, el[i]);
+ Gwn_VertBuf *vbo_uv = mesh_batch_cache_get_tri_uv_active(rdata, cache);
+ if (vbo_uv) {
+ GWN_batch_vertbuf_add(cache->texpaint_triangles[i], vbo_uv);
+ }
+ }
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->texpaint_triangles;
+}
+
+Gwn_Batch *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);
+
+ Gwn_VertBuf *vbo = mesh_batch_cache_get_tri_pos_and_normals(rdata, cache);
+
+ cache->texpaint_triangles_single = GWN_batch_create(
+ GWN_PRIM_TRIS, vbo, NULL);
+ Gwn_VertBuf *vbo_uv = mesh_batch_cache_get_tri_uv_active(rdata, cache);
+ if (vbo_uv) {
+ GWN_batch_vertbuf_add(cache->texpaint_triangles_single, vbo_uv);
+ }
+ mesh_render_data_free(rdata);
+ }
+ return cache->texpaint_triangles_single;
+}
+
+Gwn_Batch *DRW_mesh_batch_cache_get_weight_overlay_edges(Mesh *me, bool use_wire, bool use_sel)
+{
+ 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 = GWN_batch_create(
+ GWN_PRIM_LINES, mesh_batch_cache_get_edge_pos_with_sel(rdata, cache, use_wire, use_sel), NULL);
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->overlay_paint_edges;
+}
+
+Gwn_Batch *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 = GWN_batch_create(
+ GWN_PRIM_TRIS, mesh_batch_cache_get_vert_pos_and_nor_in_order(rdata, cache),
+ mesh_batch_cache_get_tri_overlay_weight_faces(rdata, cache));
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->overlay_weight_faces;
+}
+
+Gwn_Batch *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 = GWN_batch_create(
+ GWN_PRIM_POINTS, mesh_batch_cache_get_vert_pos_and_nor_in_order(rdata, cache), NULL);
+
+ GWN_batch_vertbuf_add(
+ cache->overlay_weight_verts,
+ mesh_batch_cache_get_vert_pos_with_overlay_data(rdata, cache));
+ 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->batch_cache) {
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+ if (cache && cache->pos_with_normals && cache->is_sculpt_points_tag) {
+
+ const int datatype = MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY;
+ MeshRenderData *rdata = mesh_render_data_create(me, datatype);
+
+ Gwn_VertBuf *pos_with_normals = cache->pos_with_normals;
+ cache->pos_with_normals = NULL;
+ GWN_vertbuf_clear(pos_with_normals);
+ Gwn_VertBuf *vbo = mesh_batch_cache_get_tri_pos_and_normals(rdata, cache);
+ *pos_with_normals = *vbo;
+ GWN_vertformat_copy(&pos_with_normals->format, &vbo->format);
+
+ free(vbo);
+ cache->pos_with_normals = pos_with_normals;
+
+ mesh_render_data_free(rdata);
+ }
+ cache->is_sculpt_points_tag = false;
+ }
+}
+
+/** \} */
+
+#undef MESH_RENDER_FUNCTION
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..afee6ea182b
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_impl_particles.c
@@ -0,0 +1,519 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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 "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+#include "BLI_ghash.h"
+
+#include "DNA_modifier_types.h"
+#include "DNA_particle_types.h"
+
+#include "BKE_particle.h"
+#include "BKE_DerivedMesh.h"
+
+#include "GPU_batch.h"
+
+#include "draw_cache_impl.h" /* own include */
+
+static void particle_batch_cache_clear(ParticleSystem *psys);
+
+/* ---------------------------------------------------------------------- */
+/* Particle Gwn_Batch Cache */
+
+typedef struct ParticleBatchCache {
+ Gwn_VertBuf *pos;
+ Gwn_IndexBuf *segments;
+
+ Gwn_Batch *hairs;
+
+ int segment_count;
+ int point_count;
+
+ /* settings to determine if cache is invalid */
+ bool is_dirty;
+} ParticleBatchCache;
+
+/* Gwn_Batch cache management. */
+
+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(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(ParticleSystem *psys)
+{
+ ParticleBatchCache *cache = psys->batch_cache;
+ if (!cache) {
+ return;
+ }
+
+ GWN_BATCH_DISCARD_SAFE(cache->hairs);
+
+ GWN_VERTBUF_DISCARD_SAFE(cache->pos);
+ GWN_INDEXBUF_DISCARD_SAFE(cache->segments);
+}
+
+void DRW_particle_batch_cache_free(ParticleSystem *psys)
+{
+ particle_batch_cache_clear(psys);
+ MEM_SAFE_FREE(psys->batch_cache);
+}
+
+static void ensure_seg_pt_count(ParticleSystem *psys, ParticleBatchCache *cache)
+{
+ if (cache->pos == NULL || cache->segments == NULL) {
+ cache->segment_count = 0;
+ cache->point_count = 0;
+
+ if (psys->pathcache && (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) {
+ for (int i = 0; i < psys->totpart; i++) {
+ ParticleCacheKey *path = psys->pathcache[i];
+
+ if (path->segments > 0) {
+ cache->segment_count += path->segments;
+ cache->point_count += path->segments + 1;
+ }
+ }
+ }
+
+ if (psys->childcache) {
+ int child_count = psys->totchild * psys->part->disp / 100;
+
+ for (int i = 0; i < child_count; i++) {
+ ParticleCacheKey *path = psys->childcache[i];
+
+ if (path->segments > 0) {
+ cache->segment_count += path->segments;
+ cache->point_count += path->segments + 1;
+ }
+ }
+ }
+ }
+}
+
+/* Gwn_Batch cache usage. */
+static void particle_batch_cache_ensure_pos_and_seg(ParticleSystem *psys, ModifierData *md, ParticleBatchCache *cache)
+{
+ if (cache->pos == NULL || cache->segments == NULL) {
+ int curr_point = 0;
+ ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
+
+ GWN_VERTBUF_DISCARD_SAFE(cache->pos);
+ GWN_INDEXBUF_DISCARD_SAFE(cache->segments);
+
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos, tan, ind; } attr_id;
+ unsigned int *uv_id = NULL;
+ int uv_layers = 0;
+ MTFace **mtfaces = NULL;
+ float (**parent_uvs)[2] = NULL;
+ bool simple = psys->part->childtype == PART_CHILD_PARTICLES;
+
+ if (psmd) {
+ if (CustomData_has_layer(&psmd->dm_final->loopData, CD_MLOOPUV)) {
+ uv_layers = CustomData_number_of_layers(&psmd->dm_final->loopData, CD_MLOOPUV);
+ }
+ }
+
+ GWN_vertformat_clear(&format);
+
+ /* initialize vertex format */
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ attr_id.tan = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ attr_id.ind = GWN_vertformat_attr_add(&format, "ind", GWN_COMP_I32, 1, GWN_FETCH_INT);
+
+ if (psmd) {
+ uv_id = MEM_mallocN(sizeof(*uv_id) * uv_layers, "UV attrib format");
+
+ for (int i = 0; i < uv_layers; i++) {
+ const char *name = CustomData_get_layer_name(&psmd->dm_final->loopData, CD_MLOOPUV, i);
+ char uuid[32];
+
+ BLI_snprintf(uuid, sizeof(uuid), "u%u", BLI_ghashutil_strhash_p(name));
+ uv_id[i] = GWN_vertformat_attr_add(&format, uuid, GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ }
+ }
+
+ cache->pos = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(cache->pos, cache->point_count);
+
+ Gwn_IndexBufBuilder elb;
+ GWN_indexbuf_init(&elb, GWN_PRIM_LINES, cache->segment_count, cache->point_count);
+
+ if (uv_layers) {
+ DM_ensure_tessface(psmd->dm_final);
+
+ mtfaces = MEM_mallocN(sizeof(*mtfaces) * uv_layers, "Faces UV layers");
+
+ for (int i = 0; i < uv_layers; i++) {
+ mtfaces[i] = (MTFace *)CustomData_get_layer_n(&psmd->dm_final->faceData, CD_MTFACE, i);
+ }
+ }
+
+ if (psys->pathcache && (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) {
+ if (simple) {
+ parent_uvs = MEM_callocN(sizeof(*parent_uvs) * psys->totpart, "Parent particle UVs");
+ }
+
+ for (int i = 0; i < psys->totpart; i++) {
+ ParticleCacheKey *path = psys->pathcache[i];
+
+ if (path->segments > 0) {
+ float tangent[3];
+ int from = psmd ? psmd->psys->part->from : 0;
+ float (*uv)[2] = NULL;
+
+ if (psmd) {
+ uv = MEM_callocN(sizeof(*uv) * uv_layers, "Particle UVs");
+
+ if (simple) {
+ parent_uvs[i] = uv;
+ }
+ }
+
+ if (ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) {
+ ParticleData *particle = &psys->particles[i];
+ int num = particle->num_dmcache;
+
+ if (num == DMCACHE_NOTFOUND) {
+ if (particle->num < psmd->dm_final->getNumTessFaces(psmd->dm_final)) {
+ num = particle->num;
+ }
+ }
+
+ if (num != DMCACHE_NOTFOUND) {
+ MFace *mface = psmd->dm_final->getTessFaceData(psmd->dm_final, num, CD_MFACE);
+
+ for (int j = 0; j < uv_layers; j++) {
+ psys_interpolate_uvs(mtfaces[j] + num, mface->v4, particle->fuv, uv[j]);
+ }
+ }
+ }
+
+ 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);
+ }
+
+ GWN_vertbuf_attr_set(cache->pos, attr_id.pos, curr_point, path[j].co);
+ GWN_vertbuf_attr_set(cache->pos, attr_id.tan, curr_point, tangent);
+ GWN_vertbuf_attr_set(cache->pos, attr_id.ind, curr_point, &i);
+
+ if (psmd) {
+ for (int k = 0; k < uv_layers; k++) {
+ GWN_vertbuf_attr_set(cache->pos, uv_id[k], curr_point, uv[k]);
+ }
+ }
+
+ GWN_indexbuf_add_line_verts(&elb, curr_point, curr_point + 1);
+
+ curr_point++;
+ }
+
+ sub_v3_v3v3(tangent, path[path->segments].co, path[path->segments - 1].co);
+
+ GWN_vertbuf_attr_set(cache->pos, attr_id.pos, curr_point, path[path->segments].co);
+ GWN_vertbuf_attr_set(cache->pos, attr_id.tan, curr_point, tangent);
+ GWN_vertbuf_attr_set(cache->pos, attr_id.ind, curr_point, &i);
+
+ if (psmd) {
+ for (int k = 0; k < uv_layers; k++) {
+ GWN_vertbuf_attr_set(cache->pos, uv_id[k], curr_point, uv[k]);
+ }
+
+ if (!simple) {
+ MEM_freeN(uv);
+ }
+ }
+
+ curr_point++;
+ }
+ }
+ }
+
+ if (psys->childcache) {
+ int child_count = psys->totchild * psys->part->disp / 100;
+
+ if (simple && !parent_uvs) {
+ parent_uvs = MEM_callocN(sizeof(*parent_uvs) * psys->totpart, "Parent particle UVs");
+ }
+
+ for (int i = 0, x = psys->totpart; i < child_count; i++, x++) {
+ ParticleCacheKey *path = psys->childcache[i];
+ float tangent[3];
+
+ if (path->segments > 0) {
+ int from = psmd ? psmd->psys->part->from : 0;
+ float (*uv)[2] = NULL;
+
+ if (!simple) {
+ if (psmd) {
+ uv = MEM_callocN(sizeof(*uv) * uv_layers, "Particle UVs");
+ }
+
+ if (ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) {
+ ChildParticle *particle = &psys->child[i];
+ int num = particle->num;
+
+ if (num != DMCACHE_NOTFOUND) {
+ MFace *mface = psmd->dm_final->getTessFaceData(psmd->dm_final, num, CD_MFACE);
+
+ for (int j = 0; j < uv_layers; j++) {
+ psys_interpolate_uvs(mtfaces[j] + num, mface->v4, particle->fuv, uv[j]);
+ }
+ }
+ }
+ }
+ else if (!parent_uvs[psys->child[i].parent]) {
+ if (psmd) {
+ parent_uvs[psys->child[i].parent] = MEM_callocN(sizeof(*uv) * uv_layers, "Particle UVs");
+ }
+
+ if (ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) {
+ ParticleData *particle = &psys->particles[psys->child[i].parent];
+ int num = particle->num_dmcache;
+
+ if (num == DMCACHE_NOTFOUND) {
+ if (particle->num < psmd->dm_final->getNumTessFaces(psmd->dm_final)) {
+ num = particle->num;
+ }
+ }
+
+ if (num != DMCACHE_NOTFOUND) {
+ MFace *mface = psmd->dm_final->getTessFaceData(psmd->dm_final, num, CD_MFACE);
+
+ for (int j = 0; j < uv_layers; j++) {
+ psys_interpolate_uvs(mtfaces[j] + num, mface->v4, particle->fuv, parent_uvs[psys->child[i].parent][j]);
+ }
+ }
+ }
+ }
+
+ 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);
+ }
+
+ GWN_vertbuf_attr_set(cache->pos, attr_id.pos, curr_point, path[j].co);
+ GWN_vertbuf_attr_set(cache->pos, attr_id.tan, curr_point, tangent);
+ GWN_vertbuf_attr_set(cache->pos, attr_id.ind, curr_point, &x);
+
+ if (psmd) {
+ for (int k = 0; k < uv_layers; k++) {
+ GWN_vertbuf_attr_set(cache->pos, uv_id[k], curr_point,
+ simple ? parent_uvs[psys->child[i].parent][k] : uv[k]);
+ }
+ }
+
+ GWN_indexbuf_add_line_verts(&elb, curr_point, curr_point + 1);
+
+ curr_point++;
+ }
+
+ sub_v3_v3v3(tangent, path[path->segments].co, path[path->segments - 1].co);
+
+ GWN_vertbuf_attr_set(cache->pos, attr_id.pos, curr_point, path[path->segments].co);
+ GWN_vertbuf_attr_set(cache->pos, attr_id.tan, curr_point, tangent);
+ GWN_vertbuf_attr_set(cache->pos, attr_id.ind, curr_point, &x);
+
+ if (psmd) {
+ for (int k = 0; k < uv_layers; k++) {
+ GWN_vertbuf_attr_set(cache->pos, uv_id[k], curr_point,
+ simple ? parent_uvs[psys->child[i].parent][k] : uv[k]);
+ }
+
+ if (!simple) {
+ MEM_freeN(uv);
+ }
+ }
+
+ curr_point++;
+ }
+ }
+ }
+
+ if (parent_uvs) {
+ for (int i = 0; i < psys->totpart; i++) {
+ MEM_SAFE_FREE(parent_uvs[i]);
+ }
+
+ MEM_freeN(parent_uvs);
+ }
+
+ if (uv_layers) {
+ MEM_freeN(mtfaces);
+ }
+
+ if (psmd) {
+ MEM_freeN(uv_id);
+ }
+
+ cache->segments = GWN_indexbuf_build(&elb);
+ }
+}
+
+static void particle_batch_cache_ensure_pos(ParticleSystem *psys, ParticleBatchCache *cache)
+{
+ if (cache->pos == NULL) {
+ static Gwn_VertFormat format = { 0 };
+ static unsigned pos_id, rot_id, val_id;
+ int i, curr_point;
+ ParticleData *pa;
+
+ GWN_VERTBUF_DISCARD_SAFE(cache->pos);
+ GWN_INDEXBUF_DISCARD_SAFE(cache->segments);
+
+ if (format.attrib_ct == 0) {
+ /* initialize vertex format */
+ pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ rot_id = GWN_vertformat_attr_add(&format, "rot", GWN_COMP_F32, 4, GWN_FETCH_FLOAT);
+ val_id = GWN_vertformat_attr_add(&format, "val", GWN_COMP_F32, 1, GWN_FETCH_FLOAT);
+ }
+
+ cache->pos = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(cache->pos, psys->totpart);
+
+ for (curr_point = 0, i = 0, pa = psys->particles; i < psys->totpart; i++, pa++) {
+ if (pa->state.time >= pa->time && pa->state.time < pa->dietime &&
+ !(pa->flag & (PARS_NO_DISP | PARS_UNEXIST)))
+ {
+ float val;
+
+ GWN_vertbuf_attr_set(cache->pos, pos_id, curr_point, pa->state.co);
+ GWN_vertbuf_attr_set(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;
+ }
+
+ GWN_vertbuf_attr_set(cache->pos, val_id, curr_point, &val);
+
+ curr_point++;
+ }
+ }
+
+ if (curr_point != psys->totpart) {
+ GWN_vertbuf_data_resize(cache->pos, curr_point);
+ }
+ }
+}
+
+Gwn_Batch *DRW_particles_batch_cache_get_hair(ParticleSystem *psys, ModifierData *md)
+{
+ ParticleBatchCache *cache = particle_batch_cache_get(psys);
+
+ if (cache->hairs == NULL) {
+ ensure_seg_pt_count(psys, cache);
+ particle_batch_cache_ensure_pos_and_seg(psys, md, cache);
+ cache->hairs = GWN_batch_create(GWN_PRIM_LINES, cache->pos, cache->segments);
+ }
+
+ return cache->hairs;
+}
+
+Gwn_Batch *DRW_particles_batch_cache_get_dots(ParticleSystem *psys)
+{
+ ParticleBatchCache *cache = particle_batch_cache_get(psys);
+
+ if (cache->hairs == NULL) {
+ particle_batch_cache_ensure_pos(psys, cache);
+ cache->hairs = GWN_batch_create(GWN_PRIM_POINTS, cache->pos, NULL);
+ }
+
+ return cache->hairs;
+}
diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c
new file mode 100644
index 00000000000..c3d95d700a0
--- /dev/null
+++ b/source/blender/draw/intern/draw_common.c
@@ -0,0 +1,449 @@
+/*
+ * 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_global.h"
+#include "BKE_texture.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;
+
+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_GetThemeColor4fv(TH_GROUP_ACTIVE, ts.colorGroupActive);
+ UI_GetThemeColorShade4fv(TH_GROUP_ACTIVE, -25, ts.colorGroupSelect);
+ UI_GetThemeColor4fv(TH_GROUP, ts.colorGroup);
+ 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_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);
+
+ /* 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.12 >
+ 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 = ceil(UI_GetThemeValuef(TH_VERTEX_SIZE) * M_SQRT2 / 2.0f);
+ ts.sizeFaceDot = ceil(UI_GetThemeValuef(TH_FACEDOT_SIZE) * M_SQRT2);
+ ts.sizeEdge = 1.0f / 2.0f; /* TODO Theme */
+ ts.sizeEdgeFix = 0.5f + 2.0f * (2.0f * (MAX2(ts.sizeVertex, ts.sizeEdge)) * M_SQRT1_2);
+
+ /* TODO Waiting for notifiers to invalidate cache */
+ if (globals_ubo) {
+ DRW_uniformbuffer_free(globals_ubo);
+ }
+
+ globals_ubo = DRW_uniformbuffer_create(sizeof(GlobalsUboStorage), &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;
+
+ colorband_table_RGBA(&ramp, &colors, &col_size);
+
+ if (globals_ramp) {
+ GPU_texture_free(globals_ramp);
+ }
+ globals_ramp = GPU_texture_create_1D(col_size, colors, NULL);
+
+ MEM_freeN(colors);
+}
+
+/* ********************************* SHGROUP ************************************* */
+
+DRWShadingGroup *shgroup_dynlines_uniform_color(DRWPass *pass, float color[4])
+{
+ GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_line_batch_create(sh, pass);
+ DRW_shgroup_uniform_vec4(grp, "color", color, 1);
+
+ 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 Gwn_Batch *geom, float *size)
+{
+ GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_SCREENSPACE_VARIYING_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom);
+ DRW_shgroup_attrib_float(grp, "world_pos", 3);
+ DRW_shgroup_attrib_float(grp, "color", 3);
+ 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_objspace_solid(DRWPass *pass, struct Gwn_Batch *geom, float (*obmat)[4])
+{
+ 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);
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom);
+ DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16);
+ DRW_shgroup_attrib_float(grp, "color", 4);
+ DRW_shgroup_uniform_mat4(grp, "ObjectModelMatrix", (float *)obmat);
+ DRW_shgroup_uniform_vec3(grp, "light", light, 1);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_instance_objspace_wire(DRWPass *pass, struct Gwn_Batch *geom, float (*obmat)[4])
+{
+ GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_OBJECTSPACE_VARIYING_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom);
+ DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16);
+ DRW_shgroup_attrib_float(grp, "color", 4);
+ DRW_shgroup_uniform_mat4(grp, "ObjectModelMatrix", (float *)obmat);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_instance_screen_aligned(DRWPass *pass, struct Gwn_Batch *geom)
+{
+ GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED);
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom);
+ DRW_shgroup_attrib_float(grp, "color", 3);
+ DRW_shgroup_attrib_float(grp, "size", 1);
+ DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16);
+ DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_instance_axis_names(DRWPass *pass, struct Gwn_Batch *geom)
+{
+ GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED_AXIS);
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom);
+ DRW_shgroup_attrib_float(grp, "color", 3);
+ DRW_shgroup_attrib_float(grp, "size", 1);
+ DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16);
+ DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_instance_scaled(DRWPass *pass, struct Gwn_Batch *geom)
+{
+ GPUShader *sh_inst = GPU_shader_get_builtin_shader(GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SCALE);
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom);
+ DRW_shgroup_attrib_float(grp, "color", 3);
+ DRW_shgroup_attrib_float(grp, "size", 3);
+ DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_instance(DRWPass *pass, struct Gwn_Batch *geom)
+{
+ GPUShader *sh_inst = GPU_shader_get_builtin_shader(GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE);
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom);
+ DRW_shgroup_attrib_float(grp, "color", 3);
+ DRW_shgroup_attrib_float(grp, "size", 1);
+ DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_camera_instance(DRWPass *pass, struct Gwn_Batch *geom)
+{
+ GPUShader *sh_inst = GPU_shader_get_builtin_shader(GPU_SHADER_CAMERA);
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom);
+ DRW_shgroup_attrib_float(grp, "color", 3);
+ DRW_shgroup_attrib_float(grp, "corners", 8);
+ DRW_shgroup_attrib_float(grp, "depth", 1);
+ DRW_shgroup_attrib_float(grp, "tria", 4);
+ DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_distance_lines_instance(DRWPass *pass, struct Gwn_Batch *geom)
+{
+ GPUShader *sh_inst = GPU_shader_get_builtin_shader(GPU_SHADER_DISTANCE_LINES);
+ static float point_size = 4.0f;
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom);
+ DRW_shgroup_attrib_float(grp, "color", 3);
+ DRW_shgroup_attrib_float(grp, "start", 1);
+ DRW_shgroup_attrib_float(grp, "end", 1);
+ DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16);
+ DRW_shgroup_uniform_float(grp, "size", &point_size, 1);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_spot_instance(DRWPass *pass, struct Gwn_Batch *geom)
+{
+ GPUShader *sh_inst = GPU_shader_get_builtin_shader(GPU_SHADER_INSTANCE_EDGES_VARIYING_COLOR);
+ static bool True = true;
+ static bool False = false;
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom);
+ DRW_shgroup_attrib_float(grp, "color", 3);
+ DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16);
+ 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_envelope_wire(DRWPass *pass, struct Gwn_Batch *geom, float (*obmat)[4])
+{
+ GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_WIRE);
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom);
+ DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16);
+ DRW_shgroup_attrib_float(grp, "color", 4);
+ DRW_shgroup_attrib_float(grp, "radius_head", 1);
+ DRW_shgroup_attrib_float(grp, "radius_tail", 1);
+ DRW_shgroup_attrib_float(grp, "distance", 1);
+ DRW_shgroup_uniform_mat4(grp, "ObjectModelMatrix", (float *)obmat);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_instance_bone_envelope_solid(DRWPass *pass, struct Gwn_Batch *geom, float (*obmat)[4])
+{
+ static float light[3] = {0.0f, 0.0f, 1.0f};
+ GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_SOLID);
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom);
+ DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16);
+ DRW_shgroup_attrib_float(grp, "color", 4);
+ DRW_shgroup_attrib_float(grp, "radius_head", 1);
+ DRW_shgroup_attrib_float(grp, "radius_tail", 1);
+ DRW_shgroup_uniform_mat4(grp, "ObjectModelMatrix", (float *)obmat);
+ DRW_shgroup_uniform_vec3(grp, "light", light, 1);
+
+ return grp;
+}
+
+
+/* ******************************************** 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, SceneLayer *sl, float **r_color)
+{
+ const bool is_edit = (ob->mode & OB_MODE_EDIT) != 0;
+ const bool active = (sl->basact && sl->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->flag & OB_FROMGROUP) != 0) {
+ if ((ob->base_flag & BASE_SELECTED) != 0) {
+ theme_id = TH_GROUP_ACTIVE;
+ }
+ else {
+ theme_id = TH_GROUP;
+ }
+ }
+ else {
+ 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;
+ /* fallback to TH_WIRE */
+ }
+ }
+ }
+
+ if (r_color != NULL) {
+ switch (theme_id) {
+ case TH_WIRE_EDIT: *r_color = ts.colorTransform; break;
+ case TH_ACTIVE: *r_color = ts.colorActive; break;
+ case TH_SELECT: *r_color = ts.colorSelect; break;
+ case TH_GROUP: *r_color = ts.colorGroup; break;
+ case TH_GROUP_ACTIVE: *r_color = ts.colorGroupActive; break;
+ case TH_TRANSFORM: *r_color = ts.colorTransform; break;
+ case OB_SPEAKER: *r_color = ts.colorSpeaker; break;
+ case OB_CAMERA: *r_color = ts.colorCamera; break;
+ case OB_EMPTY: *r_color = ts.colorEmpty; break;
+ case OB_LAMP: *r_color = ts.colorLamp; break;
+ default: *r_color = ts.colorWire; break;
+ }
+
+ /* uses darker active color for non-active + selected */
+ if ((theme_id == TH_GROUP_ACTIVE) && !active) {
+ *r_color = ts.colorGroupSelect;
+ }
+ }
+
+ return theme_id;
+}
+
+/* XXX This is utter shit, 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_GROUP: ret = colors[3]; break;
+ case TH_GROUP_ACTIVE: ret = colors[4]; break;
+ case TH_TRANSFORM: ret = colors[5]; break;
+ case OB_SPEAKER: ret = colors[6]; break;
+ case OB_CAMERA: ret = colors[7]; break;
+ case OB_EMPTY: ret = colors[8]; break;
+ case OB_LAMP: ret = colors[9]; break;
+ default: ret = colors[10]; break;
+ }
+
+ UI_GetThemeColorBlendShade4fv(theme_id, TH_BACK, 0.5, 0, ret);
+
+ return ret;
+}
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
new file mode 100644
index 00000000000..a6c9b24af7d
--- /dev/null
+++ b/source/blender/draw/intern/draw_common.h
@@ -0,0 +1,131 @@
+/*
+ * 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 Gwn_Batch;
+struct Object;
+struct SceneLayer;
+
+/* Used as ubo but colors can be directly referenced as well */
+/* Keep in sync with: common_globals_lib.glsl (globalsBlock) */
+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 colorGroupActive[4];
+ float colorGroupSelect[4];
+ float colorGroup[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 colorEditMeshActive[4];
+ float colorEdgeSelect[4];
+ float colorEdgeSeam[4];
+ float colorEdgeSharp[4];
+ float colorEdgeCrease[4];
+ float colorEdgeBWeight[4];
+ float colorEdgeFaceSelect[4];
+ float colorFace[4];
+ float colorFaceSelect[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 colorGrid[4];
+ float colorGridEmphasise[4];
+ float colorGridAxisX[4];
+ float colorGridAxisY[4];
+ float colorGridAxisZ[4];
+
+ /* Pack individual float at the end of the buffer to avoid alignement errors */
+ float sizeLampCenter, sizeLampCircle, sizeLampCircleShadow;
+ float sizeVertex, sizeEdge, sizeEdgeFix, sizeFaceDot;
+ float gridDistance, gridResolution, gridSubdivisions, gridScale;
+} GlobalsUboStorage;
+/* Keep in sync with globalsBlock in shaders */
+
+void DRW_globals_update(void);
+
+struct DRWShadingGroup *shgroup_dynlines_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 Gwn_Batch *geom, float *size);
+struct DRWShadingGroup *shgroup_instance_objspace_solid(struct DRWPass *pass, struct Gwn_Batch *geom, float (*obmat)[4]);
+struct DRWShadingGroup *shgroup_instance_objspace_wire(struct DRWPass *pass, struct Gwn_Batch *geom, float (*obmat)[4]);
+struct DRWShadingGroup *shgroup_instance_screen_aligned(struct DRWPass *pass, struct Gwn_Batch *geom);
+struct DRWShadingGroup *shgroup_instance_axis_names(struct DRWPass *pass, struct Gwn_Batch *geom);
+struct DRWShadingGroup *shgroup_instance_image_plane(struct DRWPass *pass, struct Gwn_Batch *geom);
+struct DRWShadingGroup *shgroup_instance_scaled(struct DRWPass *pass, struct Gwn_Batch *geom);
+struct DRWShadingGroup *shgroup_instance(struct DRWPass *pass, struct Gwn_Batch *geom);
+struct DRWShadingGroup *shgroup_camera_instance(struct DRWPass *pass, struct Gwn_Batch *geom);
+struct DRWShadingGroup *shgroup_distance_lines_instance(struct DRWPass *pass, struct Gwn_Batch *geom);
+struct DRWShadingGroup *shgroup_spot_instance(struct DRWPass *pass, struct Gwn_Batch *geom);
+struct DRWShadingGroup *shgroup_instance_bone_envelope_wire(struct DRWPass *pass, struct Gwn_Batch *geom, float (*obmat)[4]);
+struct DRWShadingGroup *shgroup_instance_bone_envelope_solid(struct DRWPass *pass, struct Gwn_Batch *geom, float (*obmat)[4]);
+
+int DRW_object_wire_theme_get(struct Object *ob, struct SceneLayer *sl, float **r_color);
+float *DRW_color_background_blend_get(int theme_id);
+
+/* draw_armature.c */
+void DRW_shgroup_armature_object(
+ struct Object *ob, struct SceneLayer *sl,
+ struct DRWPass *pass_bone_solid, struct DRWPass *pass_bone_wire, struct DRWPass *pass_bone_envelope,
+ struct DRWShadingGroup *shgrp_relationship_lines);
+
+void DRW_shgroup_armature_pose(
+ struct Object *ob,
+ struct DRWPass *pass_bone_solid, struct DRWPass *pass_bone_wire, struct DRWPass *pass_bone_envelope,
+ struct DRWShadingGroup *shgrp_relationship_lines);
+
+void DRW_shgroup_armature_edit(
+ struct Object *ob,
+ struct DRWPass *pass_bone_solid, struct DRWPass *pass_bone_wire, struct DRWPass *pass_bone_envelope,
+ struct DRWShadingGroup *shgrp_relationship_lines);
+
+/* 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_manager.c b/source/blender/draw/intern/draw_manager.c
new file mode 100644
index 00000000000..70e9d985e6c
--- /dev/null
+++ b/source/blender/draw/intern/draw_manager.c
@@ -0,0 +1,3580 @@
+/*
+ * 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_dynstr.h"
+#include "BLI_listbase.h"
+#include "BLI_rect.h"
+#include "BLI_string.h"
+
+#include "BIF_glutil.h"
+
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_pbvh.h"
+#include "BKE_paint.h"
+
+#include "BLT_translation.h"
+#include "BLF_api.h"
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "ED_space_api.h"
+#include "ED_screen.h"
+
+#include "intern/gpu_codegen.h"
+#include "GPU_batch.h"
+#include "GPU_draw.h"
+#include "GPU_extensions.h"
+#include "GPU_framebuffer.h"
+#include "GPU_immediate.h"
+#include "GPU_lamp.h"
+#include "GPU_material.h"
+#include "GPU_shader.h"
+#include "GPU_texture.h"
+#include "GPU_uniformbuffer.h"
+#include "GPU_viewport.h"
+#include "GPU_matrix.h"
+
+#include "IMB_colormanagement.h"
+
+#include "PIL_time.h"
+
+#include "RE_engine.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "draw_manager_text.h"
+
+/* only for callbacks */
+#include "draw_cache_impl.h"
+
+#include "draw_mode_engines.h"
+#include "engines/clay/clay_engine.h"
+#include "engines/eevee/eevee_engine.h"
+#include "engines/basic/basic_engine.h"
+#include "engines/external/external_engine.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#define MAX_ATTRIB_NAME 32
+#define MAX_PASS_NAME 32
+#define MAX_CLIP_PLANES 6 /* GL_MAX_CLIP_PLANES is at least 6 */
+
+/* Use draw manager to call GPU_select, see: DRW_draw_select_loop */
+#define USE_GPU_SELECT
+
+#ifdef USE_GPU_SELECT
+# include "ED_view3d.h"
+# include "ED_armature.h"
+# include "GPU_select.h"
+#endif
+
+extern char datatoc_gpu_shader_2D_vert_glsl[];
+extern char datatoc_gpu_shader_3D_vert_glsl[];
+extern char datatoc_gpu_shader_fullscreen_vert_glsl[];
+
+/* Prototypes. */
+static void DRW_engines_enable_external(void);
+
+/* Structures */
+typedef enum {
+ DRW_UNIFORM_BOOL,
+ DRW_UNIFORM_SHORT_TO_INT,
+ DRW_UNIFORM_SHORT_TO_FLOAT,
+ DRW_UNIFORM_INT,
+ DRW_UNIFORM_FLOAT,
+ DRW_UNIFORM_TEXTURE,
+ DRW_UNIFORM_BUFFER,
+ DRW_UNIFORM_MAT3,
+ DRW_UNIFORM_MAT4,
+ DRW_UNIFORM_BLOCK
+} DRWUniformType;
+
+typedef enum {
+ DRW_ATTRIB_INT,
+ DRW_ATTRIB_FLOAT,
+} DRWAttribType;
+
+struct DRWUniform {
+ struct DRWUniform *next, *prev;
+ DRWUniformType type;
+ int location;
+ int length;
+ int arraysize;
+ int bindloc;
+ const void *value;
+};
+
+typedef struct DRWAttrib {
+ struct DRWAttrib *next, *prev;
+ char name[MAX_ATTRIB_NAME];
+ int location;
+ int format_id;
+ int size; /* number of component */
+ int type;
+} DRWAttrib;
+
+struct DRWInterface {
+ ListBase uniforms; /* DRWUniform */
+ ListBase attribs; /* DRWAttrib */
+ int attribs_count;
+ int attribs_stride;
+ int attribs_size[16];
+ int attribs_loc[16];
+ /* matrices locations */
+ int model;
+ int modelinverse;
+ int modelview;
+ int modelviewinverse;
+ int projection;
+ int projectioninverse;
+ int view;
+ int viewinverse;
+ int modelviewprojection;
+ int viewprojection;
+ int viewprojectioninverse;
+ int normal;
+ int worldnormal;
+ int camtexfac;
+ int orcotexfac;
+ int eye;
+ int clipplanes;
+ /* Textures */
+ int tex_bind; /* next texture binding point */
+ /* UBO */
+ int ubo_bind; /* next ubo binding point */
+ /* Dynamic batch */
+ Gwn_Batch *instance_batch; /* contains instances attributes */
+ GLuint instance_vbo; /* same as instance_batch but generated from DRWCalls */
+ int instance_count;
+ Gwn_VertFormat vbo_format;
+};
+
+struct DRWPass {
+ ListBase shgroups; /* DRWShadingGroup */
+ DRWState state;
+ char name[MAX_PASS_NAME];
+ /* use two query to not stall the cpu waiting for queries to complete */
+ unsigned int timer_queries[2];
+ /* alternate between front and back query */
+ unsigned int front_idx;
+ unsigned int back_idx;
+ bool wasdrawn; /* if it was drawn during this frame */
+};
+
+typedef struct DRWCallHeader {
+ void *next, *prev;
+#ifdef USE_GPU_SELECT
+ int select_id;
+#endif
+ uchar type;
+} DRWCallHeader;
+
+typedef struct DRWCall {
+ DRWCallHeader head;
+
+ float obmat[4][4];
+ Gwn_Batch *geometry;
+
+ Object *ob; /* Optional */
+ ID *ob_data; /* Optional. */
+} DRWCall;
+
+typedef struct DRWCallGenerate {
+ DRWCallHeader head;
+
+ float obmat[4][4];
+
+ DRWCallGenerateFn *geometry_fn;
+ void *user_data;
+} DRWCallGenerate;
+
+typedef struct DRWCallDynamic {
+ DRWCallHeader head;
+
+ const void *data[];
+} DRWCallDynamic;
+
+struct DRWShadingGroup {
+ struct DRWShadingGroup *next, *prev;
+
+ GPUShader *shader; /* Shader to bind */
+ DRWInterface *interface; /* Uniforms pointers */
+ ListBase calls; /* DRWCall or DRWCallDynamic depending of type */
+ 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) */
+ int type;
+
+ Gwn_Batch *instance_geom; /* Geometry to instance */
+ Gwn_Batch *batch_geom; /* Result of call batching */
+
+#ifdef USE_GPU_SELECT
+ /* backlink to pass we're in */
+ DRWPass *pass_parent;
+#endif
+};
+
+/* Used by DRWShadingGroup.type */
+enum {
+ DRW_SHG_NORMAL,
+ DRW_SHG_POINT_BATCH,
+ DRW_SHG_LINE_BATCH,
+ DRW_SHG_TRIANGLE_BATCH,
+ DRW_SHG_INSTANCE,
+};
+
+/* Used by DRWCall.type */
+enum {
+ /* A single batch */
+ DRW_CALL_SINGLE,
+ /* Uses a callback to draw with any number of batches. */
+ DRW_CALL_GENERATE,
+ /* Arbitrary number of multiple args. */
+ DRW_CALL_DYNAMIC,
+};
+
+/* only 16 bits long */
+enum {
+ STENCIL_SELECT = (1 << 0),
+ STENCIL_ACTIVE = (1 << 1),
+};
+
+/* Render State */
+static struct DRWGlobalState {
+ /* Rendering state */
+ GPUShader *shader;
+ ListBase bound_texs;
+ int tex_bind_id;
+
+ /* Managed by `DRW_state_set`, `DRW_state_reset` */
+ DRWState state;
+
+ /* Per viewport */
+ GPUViewport *viewport;
+ struct GPUFrameBuffer *default_framebuffer;
+ float size[2];
+ float screenvecs[2][3];
+ float pixsize;
+
+ GLenum backface, frontface;
+
+ /* Clip planes */
+ int num_clip_planes;
+ float clip_planes_eq[MAX_CLIP_PLANES][4];
+
+ struct {
+ unsigned int is_select : 1;
+ unsigned int is_depth : 1;
+ unsigned int is_image_render : 1;
+ unsigned int is_scene_render : 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 */
+} DST = {NULL};
+
+static struct DRWMatrixOveride {
+ float mat[6][4][4];
+ bool override[6];
+} viewport_matrix_override = {{{{0}}}};
+
+ListBase DRW_engines = {NULL, NULL};
+
+#ifdef USE_GPU_SELECT
+static unsigned int g_DRW_select_id = (unsigned int)-1;
+
+void DRW_select_load_id(unsigned int id)
+{
+ BLI_assert(G.f & G_PICKSEL);
+ g_DRW_select_id = id;
+}
+#endif
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Textures (DRW_texture)
+ * \{ */
+
+static void drw_texture_get_format(
+ DRWTextureFormat format,
+ GPUTextureFormat *r_data_type, int *r_channels)
+{
+ switch (format) {
+ case DRW_TEX_RGBA_8: *r_data_type = GPU_RGBA8; break;
+ case DRW_TEX_RGBA_16: *r_data_type = GPU_RGBA16F; break;
+ case DRW_TEX_RGB_16: *r_data_type = GPU_RGB16F; break;
+ case DRW_TEX_RGB_11_11_10: *r_data_type = GPU_R11F_G11F_B10F; break;
+ case DRW_TEX_RG_16: *r_data_type = GPU_RG16F; break;
+ case DRW_TEX_RG_32: *r_data_type = GPU_RG32F; break;
+ case DRW_TEX_R_8: *r_data_type = GPU_R8; break;
+ case DRW_TEX_R_16: *r_data_type = GPU_R16F; break;
+ case DRW_TEX_R_32: *r_data_type = GPU_R32F; break;
+#if 0
+ case DRW_TEX_RGBA_32: *data_type = GPU_RGBA32F; break;
+ case DRW_TEX_RGB_8: *data_type = GPU_RGB8; break;
+ case DRW_TEX_RGB_32: *data_type = GPU_RGB32F; break;
+ case DRW_TEX_RG_8: *data_type = GPU_RG8; break;
+#endif
+ case DRW_TEX_DEPTH_16: *r_data_type = GPU_DEPTH_COMPONENT16; break;
+ case DRW_TEX_DEPTH_24: *r_data_type = GPU_DEPTH_COMPONENT24; break;
+ case DRW_TEX_DEPTH_32: *r_data_type = GPU_DEPTH_COMPONENT32F; break;
+ default :
+ /* file type not supported you must uncomment it from above */
+ BLI_assert(false);
+ break;
+ }
+
+ switch (format) {
+ case DRW_TEX_RGBA_8:
+ case DRW_TEX_RGBA_16:
+ case DRW_TEX_RGBA_32:
+ *r_channels = 4;
+ break;
+ case DRW_TEX_RGB_8:
+ case DRW_TEX_RGB_16:
+ case DRW_TEX_RGB_32:
+ case DRW_TEX_RGB_11_11_10:
+ *r_channels = 3;
+ break;
+ case DRW_TEX_RG_8:
+ case DRW_TEX_RG_16:
+ case DRW_TEX_RG_32:
+ *r_channels = 2;
+ break;
+ default:
+ *r_channels = 1;
+ break;
+ }
+}
+
+static 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);
+ DRW_texture_generate_mipmaps(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, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels)
+{
+ GPUTexture *tex;
+ GPUTextureFormat data_type;
+ int channels;
+
+ drw_texture_get_format(format, &data_type, &channels);
+ tex = GPU_texture_create_1D_custom(w, channels, data_type, fpixels, NULL);
+ drw_texture_set_parameters(tex, flags);
+
+ return tex;
+}
+
+GPUTexture *DRW_texture_create_2D(int w, int h, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels)
+{
+ GPUTexture *tex;
+ GPUTextureFormat data_type;
+ int channels;
+
+ drw_texture_get_format(format, &data_type, &channels);
+ tex = GPU_texture_create_2D_custom(w, h, channels, data_type, fpixels, NULL);
+ drw_texture_set_parameters(tex, flags);
+
+ return tex;
+}
+
+GPUTexture *DRW_texture_create_2D_array(
+ int w, int h, int d, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels)
+{
+ GPUTexture *tex;
+ GPUTextureFormat data_type;
+ int channels;
+
+ drw_texture_get_format(format, &data_type, &channels);
+ tex = GPU_texture_create_2D_array_custom(w, h, d, channels, data_type, fpixels, NULL);
+ drw_texture_set_parameters(tex, flags);
+
+ return tex;
+}
+
+GPUTexture *DRW_texture_create_cube(int w, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels)
+{
+ GPUTexture *tex;
+ GPUTextureFormat data_type;
+ int channels;
+
+ drw_texture_get_format(format, &data_type, &channels);
+ tex = GPU_texture_create_cube_custom(w, channels, data_type, fpixels, NULL);
+ drw_texture_set_parameters(tex, flags);
+
+ return tex;
+}
+
+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);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \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 Shaders (DRW_shader)
+ * \{ */
+
+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);
+}
+
+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;
+
+ DynStr *ds_vert = BLI_dynstr_new();
+ BLI_dynstr_append(ds_vert, lib);
+ BLI_dynstr_append(ds_vert, vert);
+ vert_with_lib = BLI_dynstr_get_cstring(ds_vert);
+ BLI_dynstr_free(ds_vert);
+
+ DynStr *ds_frag = BLI_dynstr_new();
+ BLI_dynstr_append(ds_frag, lib);
+ BLI_dynstr_append(ds_frag, frag);
+ frag_with_lib = BLI_dynstr_get_cstring(ds_frag);
+ BLI_dynstr_free(ds_frag);
+
+ if (geom) {
+ DynStr *ds_geom = BLI_dynstr_new();
+ BLI_dynstr_append(ds_geom, lib);
+ BLI_dynstr_append(ds_geom, geom);
+ geom_with_lib = BLI_dynstr_get_cstring(ds_geom);
+ BLI_dynstr_free(ds_geom);
+ }
+
+ sh = GPU_shader_create(vert_with_lib, frag_with_lib, geom_with_lib, NULL, defines);
+
+ MEM_freeN(vert_with_lib);
+ MEM_freeN(frag_with_lib);
+ if (geom) {
+ MEM_freeN(geom_with_lib);
+ }
+
+ return sh;
+}
+
+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);
+}
+
+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);
+}
+
+GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *defines)
+{
+ return GPU_shader_create(datatoc_gpu_shader_fullscreen_vert_glsl, frag, NULL, NULL, defines);
+}
+
+GPUShader *DRW_shader_create_3D_depth_only(void)
+{
+ return GPU_shader_get_builtin_shader(GPU_SHADER_3D_DEPTH_ONLY);
+}
+
+void DRW_shader_free(GPUShader *shader)
+{
+ GPU_shader_free(shader);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Interface (DRW_interface)
+ * \{ */
+
+static DRWInterface *DRW_interface_create(GPUShader *shader)
+{
+ DRWInterface *interface = MEM_mallocN(sizeof(DRWInterface), "DRWInterface");
+
+ interface->model = GPU_shader_get_uniform(shader, "ModelMatrix");
+ interface->modelinverse = GPU_shader_get_uniform(shader, "ModelMatrixInverse");
+ interface->modelview = GPU_shader_get_uniform(shader, "ModelViewMatrix");
+ interface->modelviewinverse = GPU_shader_get_uniform(shader, "ModelViewMatrixInverse");
+ interface->projection = GPU_shader_get_uniform(shader, "ProjectionMatrix");
+ interface->projectioninverse = GPU_shader_get_uniform(shader, "ProjectionMatrixInverse");
+ interface->view = GPU_shader_get_uniform(shader, "ViewMatrix");
+ interface->viewinverse = GPU_shader_get_uniform(shader, "ViewMatrixInverse");
+ interface->viewprojection = GPU_shader_get_uniform(shader, "ViewProjectionMatrix");
+ interface->viewprojectioninverse = GPU_shader_get_uniform(shader, "ViewProjectionMatrixInverse");
+ interface->modelviewprojection = GPU_shader_get_uniform(shader, "ModelViewProjectionMatrix");
+ interface->normal = GPU_shader_get_uniform(shader, "NormalMatrix");
+ interface->worldnormal = GPU_shader_get_uniform(shader, "WorldNormalMatrix");
+ interface->camtexfac = GPU_shader_get_uniform(shader, "CameraTexCoFactors");
+ interface->orcotexfac = GPU_shader_get_uniform(shader, "OrcoTexCoFactors[0]");
+ interface->eye = GPU_shader_get_uniform(shader, "eye");
+ interface->clipplanes = GPU_shader_get_uniform(shader, "ClipPlanes[0]");
+ interface->instance_count = 0;
+ interface->attribs_count = 0;
+ interface->attribs_stride = 0;
+ interface->instance_vbo = 0;
+ interface->instance_batch = NULL;
+ interface->tex_bind = GPU_max_textures() - 1;
+ interface->ubo_bind = GPU_max_ubo_binds() - 1;
+
+ memset(&interface->vbo_format, 0, sizeof(Gwn_VertFormat));
+
+ BLI_listbase_clear(&interface->uniforms);
+ BLI_listbase_clear(&interface->attribs);
+
+ return interface;
+}
+
+#ifdef USE_GPU_SELECT
+static DRWInterface *DRW_interface_duplicate(DRWInterface *interface_src)
+{
+ DRWInterface *interface_dst = MEM_dupallocN(interface_src);
+ BLI_duplicatelist(&interface_dst->uniforms, &interface_src->uniforms);
+ BLI_duplicatelist(&interface_dst->attribs, &interface_src->attribs);
+ return interface_dst;
+}
+#endif
+
+static void DRW_interface_uniform(DRWShadingGroup *shgroup, const char *name,
+ DRWUniformType type, const void *value, int length, int arraysize, int bindloc)
+{
+ DRWUniform *uni = MEM_mallocN(sizeof(DRWUniform), "DRWUniform");
+
+ if (type == DRW_UNIFORM_BLOCK) {
+ uni->location = GPU_shader_get_uniform_block(shgroup->shader, name);
+ }
+ else {
+ uni->location = GPU_shader_get_uniform(shgroup->shader, name);
+ }
+
+ BLI_assert(arraysize > 0);
+
+ uni->type = type;
+ uni->value = value;
+ uni->length = length;
+ uni->arraysize = arraysize;
+ uni->bindloc = bindloc; /* for textures */
+
+ if (uni->location == -1) {
+ if (G.debug & G_DEBUG)
+ fprintf(stderr, "Uniform '%s' not found!\n", name);
+ /* Nice to enable eventually, for now eevee uses uniforms that might not exist. */
+ // BLI_assert(0);
+ MEM_freeN(uni);
+ return;
+ }
+
+ BLI_addtail(&shgroup->interface->uniforms, uni);
+}
+
+static void DRW_interface_attrib(DRWShadingGroup *shgroup, const char *name, DRWAttribType type, int size, bool dummy)
+{
+ DRWAttrib *attrib = MEM_mallocN(sizeof(DRWAttrib), "DRWAttrib");
+ GLuint program = GPU_shader_get_program(shgroup->shader);
+
+ attrib->location = glGetAttribLocation(program, name);
+ attrib->type = type;
+ attrib->size = size;
+
+/* Adding attribute even if not found for now (to keep memory alignment).
+ * Should ideally take vertex format automatically from batch eventually */
+#if 0
+ if (attrib->location == -1 && !dummy) {
+ if (G.debug & G_DEBUG)
+ fprintf(stderr, "Attribute '%s' not found!\n", name);
+ BLI_assert(0);
+ MEM_freeN(attrib);
+ return;
+ }
+#else
+ UNUSED_VARS(dummy);
+#endif
+
+ BLI_assert(BLI_strnlen(name, 32) < 32);
+ BLI_strncpy(attrib->name, name, 32);
+
+ shgroup->interface->attribs_count += 1;
+
+ BLI_addtail(&shgroup->interface->attribs, attrib);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Shading Group (DRW_shgroup)
+ * \{ */
+
+DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass)
+{
+ DRWShadingGroup *shgroup = MEM_mallocN(sizeof(DRWShadingGroup), "DRWShadingGroup");
+
+ shgroup->type = DRW_SHG_NORMAL;
+ shgroup->shader = shader;
+ shgroup->interface = DRW_interface_create(shader);
+ shgroup->state_extra = 0;
+ shgroup->state_extra_disable = ~0x0;
+ shgroup->batch_geom = NULL;
+ shgroup->instance_geom = NULL;
+
+ BLI_addtail(&pass->shgroups, shgroup);
+ BLI_listbase_clear(&shgroup->calls);
+
+#ifdef USE_GPU_SELECT
+ shgroup->pass_parent = pass;
+#endif
+
+ return shgroup;
+}
+
+DRWShadingGroup *DRW_shgroup_material_create(struct GPUMaterial *material, DRWPass *pass)
+{
+ double time = 0.0; /* TODO make time variable */
+
+ /* TODO : Ideally we should not convert. But since the whole codegen
+ * is relying on GPUPass we keep it as is for now. */
+ GPUPass *gpupass = GPU_material_get_pass(material);
+
+ if (!gpupass) {
+ /* Shader compilation error */
+ return NULL;
+ }
+
+ struct GPUShader *shader = GPU_pass_shader(gpupass);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(shader, pass);
+
+ /* Converting dynamic GPUInput to DRWUniform */
+ ListBase *inputs = &gpupass->inputs;
+
+ for (GPUInput *input = inputs->first; input; input = input->next) {
+ /* Textures */
+ if (input->ima) {
+ GPUTexture *tex = GPU_texture_from_blender(
+ input->ima, input->iuser, input->textarget, input->image_isdata, time, 1);
+
+ if (input->bindtex) {
+ DRW_shgroup_uniform_texture(grp, input->shadername, tex);
+ }
+ }
+ /* Color Ramps */
+ else if (input->tex) {
+ DRW_shgroup_uniform_texture(grp, input->shadername, input->tex);
+ }
+ /* Floats */
+ else {
+ switch (input->type) {
+ case GPU_FLOAT:
+ DRW_shgroup_uniform_float(grp, input->shadername, (float *)input->dynamicvec, 1);
+ break;
+ case GPU_VEC2:
+ DRW_shgroup_uniform_vec2(grp, input->shadername, (float *)input->dynamicvec, 1);
+ break;
+ case GPU_VEC3:
+ DRW_shgroup_uniform_vec3(grp, input->shadername, (float *)input->dynamicvec, 1);
+ break;
+ case GPU_VEC4:
+ DRW_shgroup_uniform_vec4(grp, input->shadername, (float *)input->dynamicvec, 1);
+ break;
+ case GPU_MAT3:
+ DRW_shgroup_uniform_mat3(grp, input->shadername, (float *)input->dynamicvec);
+ break;
+ case GPU_MAT4:
+ DRW_shgroup_uniform_mat4(grp, input->shadername, (float *)input->dynamicvec);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ GPUUniformBuffer *ubo = GPU_material_get_uniform_buffer(material);
+ if (ubo != NULL) {
+ DRW_shgroup_uniform_block(grp, GPU_UBO_BLOCK_NAME, ubo);
+ }
+
+ return grp;
+}
+
+DRWShadingGroup *DRW_shgroup_material_instance_create(struct GPUMaterial *material, DRWPass *pass, Gwn_Batch *geom)
+{
+ DRWShadingGroup *shgroup = DRW_shgroup_material_create(material, pass);
+
+ if (shgroup) {
+ shgroup->type = DRW_SHG_INSTANCE;
+ shgroup->instance_geom = geom;
+ }
+
+ return shgroup;
+}
+
+DRWShadingGroup *DRW_shgroup_instance_create(struct GPUShader *shader, DRWPass *pass, Gwn_Batch *geom)
+{
+ DRWShadingGroup *shgroup = DRW_shgroup_create(shader, pass);
+
+ shgroup->type = DRW_SHG_INSTANCE;
+ shgroup->instance_geom = geom;
+
+ return shgroup;
+}
+
+DRWShadingGroup *DRW_shgroup_point_batch_create(struct GPUShader *shader, DRWPass *pass)
+{
+ DRWShadingGroup *shgroup = DRW_shgroup_create(shader, pass);
+
+ shgroup->type = DRW_SHG_POINT_BATCH;
+ DRW_shgroup_attrib_float(shgroup, "pos", 3);
+
+ return shgroup;
+}
+
+DRWShadingGroup *DRW_shgroup_line_batch_create(struct GPUShader *shader, DRWPass *pass)
+{
+ DRWShadingGroup *shgroup = DRW_shgroup_create(shader, pass);
+
+ shgroup->type = DRW_SHG_LINE_BATCH;
+ DRW_shgroup_attrib_float(shgroup, "pos", 3);
+
+ return shgroup;
+}
+
+/* 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 size)
+{
+ DRWShadingGroup *shgroup = DRW_shgroup_create(shader, pass);
+
+ shgroup->type = DRW_SHG_TRIANGLE_BATCH;
+ shgroup->interface->instance_count = size * 3;
+ DRW_interface_attrib(shgroup, "dummy", DRW_ATTRIB_FLOAT, 1, true);
+
+ return shgroup;
+}
+
+void DRW_shgroup_free(struct DRWShadingGroup *shgroup)
+{
+ BLI_freelistN(&shgroup->calls);
+ BLI_freelistN(&shgroup->interface->uniforms);
+ BLI_freelistN(&shgroup->interface->attribs);
+
+ if (shgroup->interface->instance_vbo &&
+ (shgroup->interface->instance_batch == 0))
+ {
+ glDeleteBuffers(1, &shgroup->interface->instance_vbo);
+ }
+
+ MEM_freeN(shgroup->interface);
+
+ BATCH_DISCARD_ALL_SAFE(shgroup->batch_geom);
+}
+
+void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct Gwn_Batch *instances)
+{
+ BLI_assert(shgroup->type == DRW_SHG_INSTANCE);
+ BLI_assert(shgroup->interface->instance_batch == NULL);
+
+ shgroup->interface->instance_batch = instances;
+}
+
+void DRW_shgroup_call_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, float (*obmat)[4])
+{
+ BLI_assert(geom != NULL);
+
+ DRWCall *call = MEM_callocN(sizeof(DRWCall), "DRWCall");
+
+ call->head.type = DRW_CALL_SINGLE;
+#ifdef USE_GPU_SELECT
+ call->head.select_id = g_DRW_select_id;
+#endif
+
+ if (obmat != NULL) {
+ copy_m4_m4(call->obmat, obmat);
+ }
+
+ call->geometry = geom;
+
+ BLI_addtail(&shgroup->calls, call);
+}
+
+void DRW_shgroup_call_object_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, Object *ob)
+{
+ BLI_assert(geom != NULL);
+
+ DRWCall *call = MEM_callocN(sizeof(DRWCall), "DRWCall");
+
+ call->head.type = DRW_CALL_SINGLE;
+#ifdef USE_GPU_SELECT
+ call->head.select_id = g_DRW_select_id;
+#endif
+
+ copy_m4_m4(call->obmat, ob->obmat);
+ call->geometry = geom;
+ call->ob_data = ob->data;
+
+ BLI_addtail(&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);
+
+ DRWCallGenerate *call = MEM_callocN(sizeof(DRWCallGenerate), "DRWCallGenerate");
+
+ call->head.type = DRW_CALL_GENERATE;
+#ifdef USE_GPU_SELECT
+ call->head.select_id = g_DRW_select_id;
+#endif
+
+ if (obmat != NULL) {
+ copy_m4_m4(call->obmat, obmat);
+ }
+
+ call->geometry_fn = geometry_fn;
+ call->user_data = user_data;
+
+ BLI_addtail(&shgroup->calls, call);
+}
+
+static void sculpt_draw_cb(
+ DRWShadingGroup *shgroup,
+ void (*draw_fn)(DRWShadingGroup *shgroup, Gwn_Batch *geom),
+ void *user_data)
+{
+ Object *ob = user_data;
+ PBVH *pbvh = ob->sculpt->pbvh;
+
+ if (pbvh) {
+ BKE_pbvh_draw_cb(
+ pbvh, NULL, NULL, false,
+ (void (*)(void *, Gwn_Batch *))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[], unsigned int attr_len)
+{
+ DRWInterface *interface = shgroup->interface;
+
+#ifdef USE_GPU_SELECT
+ if ((G.f & G_PICKSEL) && (interface->instance_count > 0)) {
+ shgroup = MEM_dupallocN(shgroup);
+ BLI_listbase_clear(&shgroup->calls);
+
+ shgroup->interface = interface = DRW_interface_duplicate(interface);
+ interface->instance_count = 0;
+
+ BLI_addtail(&shgroup->pass_parent->shgroups, shgroup);
+ }
+#endif
+
+ unsigned int data_size = sizeof(void *) * interface->attribs_count;
+ int size = sizeof(DRWCallDynamic) + data_size;
+
+ DRWCallDynamic *call = MEM_callocN(size, "DRWCallDynamic");
+
+ BLI_assert(attr_len == interface->attribs_count);
+ UNUSED_VARS_NDEBUG(attr_len);
+
+ call->head.type = DRW_CALL_DYNAMIC;
+#ifdef USE_GPU_SELECT
+ call->head.select_id = g_DRW_select_id;
+#endif
+
+ if (data_size != 0) {
+ memcpy((void *)call->data, attr, data_size);
+ }
+
+ interface->instance_count += 1;
+
+ BLI_addtail(&shgroup->calls, call);
+}
+
+/* Used for instancing with no attributes */
+void DRW_shgroup_set_instance_count(DRWShadingGroup *shgroup, int count)
+{
+ DRWInterface *interface = shgroup->interface;
+
+ BLI_assert(interface->attribs_count == 0);
+
+ interface->instance_count = 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_attrib_float(DRWShadingGroup *shgroup, const char *name, int size)
+{
+ DRW_interface_attrib(shgroup, name, DRW_ATTRIB_FLOAT, size, false);
+}
+
+void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex)
+{
+ DRWInterface *interface = shgroup->interface;
+
+ if (interface->tex_bind < 0) {
+ /* TODO alert user */
+ printf("Not enough texture slot for %s\n", name);
+ return;
+ }
+
+ DRW_interface_uniform(shgroup, name, DRW_UNIFORM_TEXTURE, tex, 0, 1, interface->tex_bind--);
+}
+
+void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const GPUUniformBuffer *ubo)
+{
+ DRWInterface *interface = shgroup->interface;
+
+ /* Be carefull: there is also a limit per shader stage. Usually 1/3 of normal limit. */
+ if (interface->ubo_bind < 0) {
+ /* TODO alert user */
+ printf("Not enough ubo slots for %s\n", name);
+ return;
+ }
+
+ DRW_interface_uniform(shgroup, name, DRW_UNIFORM_BLOCK, ubo, 0, 1, interface->ubo_bind--);
+}
+
+void DRW_shgroup_uniform_buffer(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex)
+{
+ DRWInterface *interface = shgroup->interface;
+
+ if (interface->tex_bind < 0) {
+ /* TODO alert user */
+ printf("Not enough texture slot for %s\n", name);
+ return;
+ }
+
+ DRW_interface_uniform(shgroup, name, DRW_UNIFORM_BUFFER, tex, 0, 1, interface->tex_bind--);
+}
+
+void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const char *name, const bool *value, int arraysize)
+{
+ DRW_interface_uniform(shgroup, name, DRW_UNIFORM_BOOL, value, 1, arraysize, 0);
+}
+
+void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
+{
+ DRW_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 1, arraysize, 0);
+}
+
+void DRW_shgroup_uniform_vec2(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
+{
+ DRW_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 2, arraysize, 0);
+}
+
+void DRW_shgroup_uniform_vec3(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
+{
+ DRW_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 3, arraysize, 0);
+}
+
+void DRW_shgroup_uniform_vec4(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
+{
+ DRW_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 4, arraysize, 0);
+}
+
+void DRW_shgroup_uniform_short_to_int(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize)
+{
+ DRW_interface_uniform(shgroup, name, DRW_UNIFORM_SHORT_TO_INT, value, 1, arraysize, 0);
+}
+
+void DRW_shgroup_uniform_short_to_float(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize)
+{
+ DRW_interface_uniform(shgroup, name, DRW_UNIFORM_SHORT_TO_FLOAT, value, 1, arraysize, 0);
+}
+
+void DRW_shgroup_uniform_int(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize)
+{
+ DRW_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 1, arraysize, 0);
+}
+
+void DRW_shgroup_uniform_ivec2(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize)
+{
+ DRW_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 2, arraysize, 0);
+}
+
+void DRW_shgroup_uniform_ivec3(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize)
+{
+ DRW_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 3, arraysize, 0);
+}
+
+void DRW_shgroup_uniform_mat3(DRWShadingGroup *shgroup, const char *name, const float *value)
+{
+ DRW_interface_uniform(shgroup, name, DRW_UNIFORM_MAT3, value, 9, 1, 0);
+}
+
+void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float *value)
+{
+ DRW_interface_uniform(shgroup, name, DRW_UNIFORM_MAT4, value, 16, 1, 0);
+}
+
+/* Creates a VBO containing OGL primitives for all DRWCallDynamic */
+static void shgroup_dynamic_batch(DRWShadingGroup *shgroup)
+{
+ DRWInterface *interface = shgroup->interface;
+ int nbr = interface->instance_count;
+
+ Gwn_PrimType type = (shgroup->type == DRW_SHG_POINT_BATCH) ? GWN_PRIM_POINTS :
+ (shgroup->type == DRW_SHG_TRIANGLE_BATCH) ? GWN_PRIM_TRIS : GWN_PRIM_LINES;
+
+ if (nbr == 0)
+ return;
+
+ /* Upload Data */
+ if (interface->vbo_format.attrib_ct == 0) {
+ for (DRWAttrib *attrib = interface->attribs.first; attrib; attrib = attrib->next) {
+ BLI_assert(attrib->size <= 4); /* matrices have no place here for now */
+ if (attrib->type == DRW_ATTRIB_FLOAT) {
+ attrib->format_id = GWN_vertformat_attr_add(
+ &interface->vbo_format, attrib->name, GWN_COMP_F32, attrib->size, GWN_FETCH_FLOAT);
+ }
+ else if (attrib->type == DRW_ATTRIB_INT) {
+ attrib->format_id = GWN_vertformat_attr_add(
+ &interface->vbo_format, attrib->name, GWN_COMP_I8, attrib->size, GWN_FETCH_INT);
+ }
+ else {
+ BLI_assert(false);
+ }
+ }
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&interface->vbo_format);
+ GWN_vertbuf_data_alloc(vbo, nbr);
+
+ int j = 0;
+ for (DRWCallDynamic *call = shgroup->calls.first; call; call = call->head.next, j++) {
+ int i = 0;
+ for (DRWAttrib *attrib = interface->attribs.first; attrib; attrib = attrib->next, i++) {
+ GWN_vertbuf_attr_set(vbo, attrib->format_id, j, call->data[i]);
+ }
+ }
+
+ /* TODO make the batch dynamic instead of freeing it every times */
+ if (shgroup->batch_geom)
+ GWN_batch_discard_all(shgroup->batch_geom);
+
+ shgroup->batch_geom = GWN_batch_create(type, vbo, NULL);
+}
+
+static void shgroup_dynamic_instance(DRWShadingGroup *shgroup)
+{
+ int i = 0;
+ int offset = 0;
+ DRWInterface *interface = shgroup->interface;
+ int buffer_size = 0;
+
+ if (interface->instance_batch != NULL) {
+ return;
+ }
+
+ /* TODO We still need this because gawain does not support Matrix attribs. */
+ if (interface->instance_count == 0) {
+ if (interface->instance_vbo) {
+ glDeleteBuffers(1, &interface->instance_vbo);
+ interface->instance_vbo = 0;
+ }
+ return;
+ }
+
+ /* only once */
+ if (interface->attribs_stride == 0) {
+ for (DRWAttrib *attrib = interface->attribs.first; attrib; attrib = attrib->next, i++) {
+ BLI_assert(attrib->type == DRW_ATTRIB_FLOAT); /* Only float for now */
+ interface->attribs_stride += attrib->size;
+ interface->attribs_size[i] = attrib->size;
+ interface->attribs_loc[i] = attrib->location;
+ }
+ }
+
+ /* Gather Data */
+ buffer_size = sizeof(float) * interface->attribs_stride * interface->instance_count;
+ float *data = MEM_mallocN(buffer_size, "Instance VBO data");
+
+ for (DRWCallDynamic *call = shgroup->calls.first; call; call = call->head.next) {
+ for (int j = 0; j < interface->attribs_count; ++j) {
+ memcpy(data + offset, call->data[j], sizeof(float) * interface->attribs_size[j]);
+ offset += interface->attribs_size[j];
+ }
+ }
+
+ /* TODO poke mike to add this to gawain */
+ if (interface->instance_vbo) {
+ glDeleteBuffers(1, &interface->instance_vbo);
+ interface->instance_vbo = 0;
+ }
+
+ glGenBuffers(1, &interface->instance_vbo);
+ glBindBuffer(GL_ARRAY_BUFFER, interface->instance_vbo);
+ glBufferData(GL_ARRAY_BUFFER, buffer_size, data, GL_STATIC_DRAW);
+
+ MEM_freeN(data);
+}
+
+static void shgroup_dynamic_batch_from_calls(DRWShadingGroup *shgroup)
+{
+ if ((shgroup->interface->instance_vbo || shgroup->batch_geom) &&
+ (G.debug_value == 667))
+ {
+ return;
+ }
+
+ if (shgroup->type == DRW_SHG_INSTANCE) {
+ shgroup_dynamic_instance(shgroup);
+ }
+ else {
+ shgroup_dynamic_batch(shgroup);
+ }
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Passes (DRW_pass)
+ * \{ */
+
+DRWPass *DRW_pass_create(const char *name, DRWState state)
+{
+ DRWPass *pass = MEM_callocN(sizeof(DRWPass), name);
+ pass->state = state;
+ BLI_strncpy(pass->name, name, MAX_PASS_NAME);
+
+ BLI_listbase_clear(&pass->shgroups);
+
+ return pass;
+}
+
+void DRW_pass_free(DRWPass *pass)
+{
+ for (DRWShadingGroup *shgroup = pass->shgroups.first; shgroup; shgroup = shgroup->next) {
+ DRW_shgroup_free(shgroup);
+ }
+
+ glDeleteQueries(2, pass->timer_queries);
+ BLI_freelistN(&pass->shgroups);
+}
+
+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 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;
+ const ZSortData *zsortdata = (ZSortData *)thunk;
+
+ float tmp[3];
+ sub_v3_v3v3(tmp, zsortdata->origin, call_a->obmat[3]);
+ const float a_sq = dot_v3v3(zsortdata->axis, tmp);
+ sub_v3_v3v3(tmp, zsortdata->origin, call_b->obmat[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;
+ }
+}
+
+/**
+ * Sort Shading groups by decreasing Z of their first draw call.
+ * This is usefull for order dependant effect such as transparency.
+ **/
+void DRW_pass_sort_shgroup_z(DRWPass *pass)
+{
+ RegionView3D *rv3d = DST.draw_ctx.rv3d;
+
+ float (*viewinv)[4];
+ viewinv = (viewport_matrix_override.override[DRW_MAT_VIEWINV])
+ ? viewport_matrix_override.mat[DRW_MAT_VIEWINV] : rv3d->viewinv;
+
+ ZSortData zsortdata = {viewinv[2], viewinv[3]};
+ BLI_listbase_sort_r(&pass->shgroups, pass_shgroup_dist_sort, &zsortdata);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Draw (DRW_draw)
+ * \{ */
+
+static void DRW_state_set(DRWState state)
+{
+ if (DST.state == state) {
+ return;
+ }
+
+
+#define CHANGED_TO(f) \
+ ((DST.state & (f)) ? \
+ ((state & (f)) ? 0 : -1) : \
+ ((state & (f)) ? 1 : 0))
+
+#define CHANGED_ANY(f) \
+ ((DST.state & (f)) != (state & (f)))
+
+#define CHANGED_ANY_STORE_VAR(f, enabled) \
+ ((DST.state & (f)) != (enabled = (state & (f))))
+
+ /* 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);
+ }
+ }
+ }
+
+ /* 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_EQUAL | DRW_STATE_DEPTH_GREATER | DRW_STATE_DEPTH_ALWAYS,
+ test))
+ {
+ if (test) {
+ glEnable(GL_DEPTH_TEST);
+
+ if (state & DRW_STATE_DEPTH_LESS) {
+ 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_ALWAYS) {
+ glDepthFunc(GL_ALWAYS);
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ else {
+ glDisable(GL_DEPTH_TEST);
+ }
+ }
+ }
+
+ /* Wire Width */
+ {
+ if (CHANGED_ANY(DRW_STATE_WIRE | DRW_STATE_WIRE_LARGE)) {
+ if ((state & DRW_STATE_WIRE) != 0) {
+ glLineWidth(1.0f);
+ }
+ else if ((state & DRW_STATE_WIRE_LARGE) != 0) {
+ glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
+ }
+ else {
+ /* do nothing */
+ }
+ }
+ }
+
+ /* 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_ADDITIVE | DRW_STATE_MULTIPLY | DRW_STATE_TRANSMISSION,
+ test))
+ {
+ if (test) {
+ glEnable(GL_BLEND);
+
+ if ((state & DRW_STATE_BLEND) != 0) {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ else if ((state & DRW_STATE_MULTIPLY) != 0) {
+ glBlendFunc(GL_DST_COLOR, GL_ZERO);
+ }
+ else if ((state & DRW_STATE_TRANSMISSION) != 0) {
+ glBlendFunc(GL_ONE, GL_SRC_ALPHA);
+ }
+ else if ((state & DRW_STATE_ADDITIVE) != 0) {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ else {
+ glDisable(GL_BLEND);
+ }
+ }
+ }
+
+ /* 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_SELECT |
+ DRW_STATE_WRITE_STENCIL_ACTIVE |
+ DRW_STATE_TEST_STENCIL_SELECT |
+ DRW_STATE_TEST_STENCIL_ACTIVE,
+ test))
+ {
+ if (test) {
+ glEnable(GL_STENCIL_TEST);
+
+ /* Stencil Write */
+ if ((state & DRW_STATE_WRITE_STENCIL_SELECT) != 0) {
+ glStencilMask(STENCIL_SELECT);
+ glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
+ glStencilFunc(GL_ALWAYS, 0xFF, STENCIL_SELECT);
+ }
+ else if ((state & DRW_STATE_WRITE_STENCIL_ACTIVE) != 0) {
+ glStencilMask(STENCIL_ACTIVE);
+ glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
+ glStencilFunc(GL_ALWAYS, 0xFF, STENCIL_ACTIVE);
+ }
+ /* Stencil Test */
+ else if ((state & DRW_STATE_TEST_STENCIL_SELECT) != 0) {
+ glStencilMask(0x00); /* disable write */
+ glStencilFunc(GL_NOTEQUAL, 0xFF, STENCIL_SELECT);
+ }
+ else if ((state & DRW_STATE_TEST_STENCIL_ACTIVE) != 0) {
+ glStencilMask(0x00); /* disable write */
+ glStencilFunc(GL_NOTEQUAL, 0xFF, STENCIL_ACTIVE);
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ else {
+ /* disable write & test */
+ glStencilMask(0x00);
+ glStencilFunc(GL_ALWAYS, 1, 0xFF);
+ glDisable(GL_STENCIL_TEST);
+ }
+ }
+ }
+
+#undef CHANGED_TO
+#undef CHANGED_ANY
+#undef CHANGED_ANY_STORE_VAR
+
+ DST.state = state;
+}
+
+typedef struct DRWBoundTexture {
+ struct DRWBoundTexture *next, *prev;
+ GPUTexture *tex;
+} DRWBoundTexture;
+
+static void draw_geometry_prepare(
+ DRWShadingGroup *shgroup, const float (*obmat)[4], const float *texcoloc, const float *texcosize)
+{
+ RegionView3D *rv3d = DST.draw_ctx.rv3d;
+ DRWInterface *interface = shgroup->interface;
+
+ float mvp[4][4], mv[4][4], mi[4][4], mvi[4][4], pi[4][4], n[3][3], wn[3][3];
+ float orcofacs[2][3] = {{0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f}};
+ float eye[3] = { 0.0f, 0.0f, 1.0f }; /* looking into the screen */
+
+ bool do_pi = (interface->projectioninverse != -1);
+ bool do_mvp = (interface->modelviewprojection != -1);
+ bool do_mi = (interface->modelinverse != -1);
+ bool do_mv = (interface->modelview != -1);
+ bool do_mvi = (interface->modelviewinverse != -1);
+ bool do_n = (interface->normal != -1);
+ bool do_wn = (interface->worldnormal != -1);
+ bool do_eye = (interface->eye != -1);
+ bool do_orco = (interface->orcotexfac != -1) && (texcoloc != NULL) && (texcosize != NULL);
+
+ /* Matrix override */
+ float (*persmat)[4];
+ float (*persinv)[4];
+ float (*viewmat)[4];
+ float (*viewinv)[4];
+ float (*winmat)[4];
+ float (*wininv)[4];
+
+ persmat = (viewport_matrix_override.override[DRW_MAT_PERS])
+ ? viewport_matrix_override.mat[DRW_MAT_PERS] : rv3d->persmat;
+ persinv = (viewport_matrix_override.override[DRW_MAT_PERSINV])
+ ? viewport_matrix_override.mat[DRW_MAT_PERSINV] : rv3d->persinv;
+ viewmat = (viewport_matrix_override.override[DRW_MAT_VIEW])
+ ? viewport_matrix_override.mat[DRW_MAT_VIEW] : rv3d->viewmat;
+ viewinv = (viewport_matrix_override.override[DRW_MAT_VIEWINV])
+ ? viewport_matrix_override.mat[DRW_MAT_VIEWINV] : rv3d->viewinv;
+ winmat = (viewport_matrix_override.override[DRW_MAT_WIN])
+ ? viewport_matrix_override.mat[DRW_MAT_WIN] : rv3d->winmat;
+
+ if (do_pi) {
+ if (viewport_matrix_override.override[DRW_MAT_WININV]) {
+ wininv = viewport_matrix_override.mat[DRW_MAT_WININV];
+ }
+ else {
+ invert_m4_m4(pi, winmat);
+ wininv = pi;
+ }
+ }
+ if (do_mi) {
+ invert_m4_m4(mi, obmat);
+ }
+ if (do_mvp) {
+ mul_m4_m4m4(mvp, persmat, obmat);
+ }
+ if (do_mv || do_mvi || do_n || do_eye) {
+ mul_m4_m4m4(mv, viewmat, obmat);
+ }
+ if (do_mvi) {
+ invert_m4_m4(mvi, mv);
+ }
+ if (do_n || do_eye) {
+ copy_m3_m4(n, mv);
+ invert_m3(n);
+ transpose_m3(n);
+ }
+ if (do_wn) {
+ copy_m3_m4(wn, obmat);
+ invert_m3(wn);
+ transpose_m3(wn);
+ }
+ if (do_eye) {
+ /* Used by orthographic wires */
+ float tmp[3][3];
+ invert_m3_m3(tmp, n);
+ /* set eye vector, transformed to object coords */
+ mul_m3_v3(tmp, eye);
+ }
+ if (do_orco) {
+ mul_v3_v3fl(orcofacs[1], texcosize, 2.0f);
+ invert_v3(orcofacs[1]);
+ sub_v3_v3v3(orcofacs[0], texcoloc, texcosize);
+ negate_v3(orcofacs[0]);
+ mul_v3_v3(orcofacs[0], orcofacs[1]); /* result in a nice MADD in the shader */
+ }
+
+ /* Should be really simple */
+ /* step 1 : bind object dependent matrices */
+ /* TODO : Some of these are not object dependant.
+ * They should be grouped inside a UBO updated once per redraw.
+ * The rest can also go into a UBO to reduce API calls. */
+ GPU_shader_uniform_vector(shgroup->shader, interface->model, 16, 1, (float *)obmat);
+ GPU_shader_uniform_vector(shgroup->shader, interface->modelinverse, 16, 1, (float *)mi);
+ GPU_shader_uniform_vector(shgroup->shader, interface->modelviewprojection, 16, 1, (float *)mvp);
+ GPU_shader_uniform_vector(shgroup->shader, interface->viewinverse, 16, 1, (float *)viewinv);
+ GPU_shader_uniform_vector(shgroup->shader, interface->viewprojection, 16, 1, (float *)persmat);
+ GPU_shader_uniform_vector(shgroup->shader, interface->viewprojectioninverse, 16, 1, (float *)persinv);
+ GPU_shader_uniform_vector(shgroup->shader, interface->projection, 16, 1, (float *)winmat);
+ GPU_shader_uniform_vector(shgroup->shader, interface->projectioninverse, 16, 1, (float *)wininv);
+ GPU_shader_uniform_vector(shgroup->shader, interface->view, 16, 1, (float *)viewmat);
+ GPU_shader_uniform_vector(shgroup->shader, interface->modelview, 16, 1, (float *)mv);
+ GPU_shader_uniform_vector(shgroup->shader, interface->modelviewinverse, 16, 1, (float *)mvi);
+ GPU_shader_uniform_vector(shgroup->shader, interface->normal, 9, 1, (float *)n);
+ GPU_shader_uniform_vector(shgroup->shader, interface->worldnormal, 9, 1, (float *)wn);
+ GPU_shader_uniform_vector(shgroup->shader, interface->camtexfac, 4, 1, (float *)rv3d->viewcamtexcofac);
+ GPU_shader_uniform_vector(shgroup->shader, interface->orcotexfac, 3, 2, (float *)orcofacs);
+ GPU_shader_uniform_vector(shgroup->shader, interface->eye, 3, 1, (float *)eye);
+ GPU_shader_uniform_vector(shgroup->shader, interface->clipplanes, 4, DST.num_clip_planes, (float *)DST.clip_planes_eq);
+}
+
+static void draw_geometry_execute(DRWShadingGroup *shgroup, Gwn_Batch *geom)
+{
+ DRWInterface *interface = shgroup->interface;
+ /* step 2 : bind vertex array & draw */
+ GWN_batch_program_set(geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader));
+ if (interface->instance_batch) {
+ GWN_batch_draw_stupid_instanced_with_batch(geom, interface->instance_batch);
+ }
+ else if (interface->instance_vbo) {
+ GWN_batch_draw_stupid_instanced(
+ geom, interface->instance_vbo, interface->instance_count, interface->attribs_count,
+ interface->attribs_stride, interface->attribs_size, interface->attribs_loc);
+ }
+ else {
+ GWN_batch_draw_stupid(geom);
+ }
+}
+
+static void draw_geometry(DRWShadingGroup *shgroup, Gwn_Batch *geom, const float (*obmat)[4], ID *ob_data)
+{
+ float *texcoloc = NULL;
+ float *texcosize = NULL;
+
+ if (ob_data != NULL) {
+ switch (GS(ob_data->name)) {
+ case OB_MESH:
+ BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, NULL, &texcosize);
+ /* TODO, curve, metaball? */
+ default:
+ break;
+ }
+ }
+
+ draw_geometry_prepare(shgroup, obmat, texcoloc, texcosize);
+
+ draw_geometry_execute(shgroup, geom);
+}
+
+static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
+{
+ BLI_assert(shgroup->shader);
+ BLI_assert(shgroup->interface);
+
+ DRWInterface *interface = shgroup->interface;
+ GPUTexture *tex;
+ int val;
+ float fval;
+
+ if (DST.shader != shgroup->shader) {
+ if (DST.shader) GPU_shader_unbind();
+ GPU_shader_bind(shgroup->shader);
+ DST.shader = shgroup->shader;
+ }
+
+ const bool is_normal = ELEM(shgroup->type, DRW_SHG_NORMAL);
+
+ if (!is_normal) {
+ shgroup_dynamic_batch_from_calls(shgroup);
+ }
+
+ DRW_state_set((pass_state & shgroup->state_extra_disable) | shgroup->state_extra);
+
+ /* Binding Uniform */
+ /* Don't check anything, Interface should already contain the least uniform as possible */
+ for (DRWUniform *uni = interface->uniforms.first; uni; uni = uni->next) {
+ DRWBoundTexture *bound_tex;
+
+ switch (uni->type) {
+ case DRW_UNIFORM_SHORT_TO_INT:
+ val = (int)*((short *)uni->value);
+ GPU_shader_uniform_vector_int(
+ shgroup->shader, uni->location, uni->length, uni->arraysize, (int *)&val);
+ break;
+ case DRW_UNIFORM_SHORT_TO_FLOAT:
+ fval = (float)*((short *)uni->value);
+ GPU_shader_uniform_vector(
+ shgroup->shader, uni->location, uni->length, uni->arraysize, (float *)&fval);
+ break;
+ case DRW_UNIFORM_BOOL:
+ case DRW_UNIFORM_INT:
+ GPU_shader_uniform_vector_int(
+ shgroup->shader, uni->location, uni->length, uni->arraysize, (int *)uni->value);
+ break;
+ case DRW_UNIFORM_FLOAT:
+ case DRW_UNIFORM_MAT3:
+ case DRW_UNIFORM_MAT4:
+ GPU_shader_uniform_vector(
+ shgroup->shader, uni->location, uni->length, uni->arraysize, (float *)uni->value);
+ break;
+ case DRW_UNIFORM_TEXTURE:
+ tex = (GPUTexture *)uni->value;
+ BLI_assert(tex);
+ GPU_texture_bind(tex, uni->bindloc);
+
+ bound_tex = MEM_callocN(sizeof(DRWBoundTexture), "DRWBoundTexture");
+ bound_tex->tex = tex;
+ BLI_addtail(&DST.bound_texs, bound_tex);
+
+ GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
+ break;
+ case DRW_UNIFORM_BUFFER:
+ if (!DRW_state_is_fbo()) {
+ break;
+ }
+ tex = *((GPUTexture **)uni->value);
+ BLI_assert(tex);
+ GPU_texture_bind(tex, uni->bindloc);
+
+ bound_tex = MEM_callocN(sizeof(DRWBoundTexture), "DRWBoundTexture");
+ bound_tex->tex = tex;
+ BLI_addtail(&DST.bound_texs, bound_tex);
+
+ GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
+ break;
+ case DRW_UNIFORM_BLOCK:
+ GPU_uniformbuffer_bind((GPUUniformBuffer *)uni->value, uni->bindloc);
+ GPU_shader_uniform_buffer(shgroup->shader, uni->location, (GPUUniformBuffer *)uni->value);
+ break;
+ }
+ }
+
+#ifdef USE_GPU_SELECT
+ /* use the first item because of selection we only ever add one */
+# define GPU_SELECT_LOAD_IF_PICKSEL(_call) \
+ if ((G.f & G_PICKSEL) && (_call)) { \
+ GPU_select_load_id((_call)->head.select_id); \
+ } ((void)0)
+# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(_call_ls) \
+ if ((G.f & G_PICKSEL) && (_call_ls)->first) { \
+ BLI_assert(BLI_listbase_is_single(_call_ls)); \
+ GPU_select_load_id(((DRWCall *)(_call_ls)->first)->head.select_id); \
+ } ((void)0)
+#else
+# define GPU_SELECT_LOAD_IF_PICKSEL(call)
+# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(call)
+#endif
+
+ /* Rendering Calls */
+ if (!is_normal) {
+ /* Replacing multiple calls with only one */
+ float obmat[4][4];
+ unit_m4(obmat);
+
+ if (shgroup->type == DRW_SHG_INSTANCE &&
+ (interface->instance_count > 0 || interface->instance_batch != NULL))
+ {
+ GPU_SELECT_LOAD_IF_PICKSEL_LIST(&shgroup->calls);
+ draw_geometry(shgroup, shgroup->instance_geom, obmat, NULL);
+ }
+ else {
+ /* Some dynamic batch can have no geom (no call to aggregate) */
+ if (shgroup->batch_geom) {
+ GPU_SELECT_LOAD_IF_PICKSEL_LIST(&shgroup->calls);
+ draw_geometry(shgroup, shgroup->batch_geom, obmat, NULL);
+ }
+ }
+ }
+ else {
+ for (DRWCall *call = shgroup->calls.first; call; call = call->head.next) {
+ bool neg_scale = is_negative_m4(call->obmat);
+
+ /* Negative scale objects */
+ if (neg_scale) {
+ glFrontFace(DST.backface);
+ }
+
+ GPU_SELECT_LOAD_IF_PICKSEL(call);
+
+ if (call->head.type == DRW_CALL_SINGLE) {
+ draw_geometry(shgroup, call->geometry, call->obmat, call->ob_data);
+ }
+ else {
+ BLI_assert(call->head.type == DRW_CALL_GENERATE);
+ DRWCallGenerate *callgen = ((DRWCallGenerate *)call);
+ draw_geometry_prepare(shgroup, callgen->obmat, NULL, NULL);
+ callgen->geometry_fn(shgroup, draw_geometry_execute, callgen->user_data);
+ }
+
+ /* Reset state */
+ if (neg_scale) {
+ glFrontFace(DST.frontface);
+ }
+ }
+ }
+
+ /* TODO: remove, (currently causes alpha issue with sculpt, need to investigate) */
+ DRW_state_reset();
+}
+
+static void DRW_draw_pass_ex(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group)
+{
+ /* Start fresh */
+ DST.shader = NULL;
+ DST.tex_bind_id = 0;
+
+ DRW_state_set(pass->state);
+ BLI_listbase_clear(&DST.bound_texs);
+
+ /* Init Timer queries */
+ if (pass->timer_queries[0] == 0) {
+ pass->front_idx = 0;
+ pass->back_idx = 1;
+
+ glGenQueries(2, pass->timer_queries);
+
+ /* dummy query, avoid gl error */
+ glBeginQuery(GL_TIME_ELAPSED, pass->timer_queries[pass->front_idx]);
+ glEndQuery(GL_TIME_ELAPSED);
+ }
+ else {
+ /* swap indices */
+ unsigned int tmp = pass->back_idx;
+ pass->back_idx = pass->front_idx;
+ pass->front_idx = tmp;
+ }
+
+ if (!pass->wasdrawn) {
+ /* issue query for the next frame */
+ glBeginQuery(GL_TIME_ELAPSED, pass->timer_queries[pass->back_idx]);
+ }
+
+ 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 (DRWBoundTexture *bound_tex = DST.bound_texs.first; bound_tex; bound_tex = bound_tex->next) {
+ GPU_texture_unbind(bound_tex->tex);
+ }
+ DST.tex_bind_id = 0;
+ BLI_freelistN(&DST.bound_texs);
+
+ if (DST.shader) {
+ GPU_shader_unbind();
+ DST.shader = NULL;
+ }
+
+ if (!pass->wasdrawn) {
+ glEndQuery(GL_TIME_ELAPSED);
+ }
+
+ pass->wasdrawn = true;
+}
+
+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);
+}
+
+void DRW_draw_callbacks_pre_scene(void)
+{
+ RegionView3D *rv3d = DST.draw_ctx.rv3d;
+
+ gpuLoadProjectionMatrix(rv3d->winmat);
+ gpuLoadMatrix(rv3d->viewmat);
+}
+
+void DRW_draw_callbacks_post_scene(void)
+{
+ RegionView3D *rv3d = DST.draw_ctx.rv3d;
+
+ gpuLoadProjectionMatrix(rv3d->winmat);
+ gpuLoadMatrix(rv3d->viewmat);
+}
+
+/* Reset state to not interfer with other UI drawcall */
+void DRW_state_reset_ex(DRWState state)
+{
+ DST.state = ~state;
+ DRW_state_set(state);
+}
+
+void DRW_state_reset(void)
+{
+ /* Reset blending function */
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ DRW_state_reset_ex(DRW_STATE_DEFAULT);
+}
+
+/* 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_add(float plane_eq[4])
+{
+ copy_v4_v4(DST.clip_planes_eq[DST.num_clip_planes++], plane_eq);
+}
+
+void DRW_state_clip_planes_reset(void)
+{
+ DST.num_clip_planes = 0;
+}
+
+/** \} */
+
+
+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(Object *ob)
+{
+ Scene *scene = DST.draw_ctx.scene;
+ Object *obedit = scene->obedit;
+
+ if (ob->type == OB_MESH) {
+ if (ob == obedit) {
+ IDProperty *props = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_EDIT, "");
+ bool do_show_occlude_wire = BKE_collection_engine_property_value_get_bool(props, "show_occlude_wire");
+ if (do_show_occlude_wire) {
+ return false;
+ }
+ bool do_show_weight = BKE_collection_engine_property_value_get_bool(props, "show_weight");
+ if (do_show_weight) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+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;
+}
+
+
+/**
+ * Return true if the object has its own draw mode.
+ * Caller must check this is active */
+int DRW_object_is_mode_shade(const Object *ob)
+{
+ BLI_assert(ob == DST.draw_ctx.obact);
+ if ((ob->mode & OB_MODE_EDIT) == 0) {
+ if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)) {
+ if ((DST.draw_ctx.v3d->flag2 & V3D_SHOW_MODE_SHADE_OVERRIDE) == 0) {
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ }
+ return -1;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Framebuffers (DRW_framebuffer)
+ * \{ */
+
+static GPUTextureFormat convert_tex_format(
+ int fbo_format,
+ int *r_channels, bool *r_is_depth)
+{
+ *r_is_depth = ELEM(fbo_format, DRW_TEX_DEPTH_16, DRW_TEX_DEPTH_24);
+
+ switch (fbo_format) {
+ case DRW_TEX_R_16: *r_channels = 1; return GPU_R16F;
+ case DRW_TEX_R_32: *r_channels = 1; return GPU_R32F;
+ case DRW_TEX_RG_16: *r_channels = 2; return GPU_RG16F;
+ case DRW_TEX_RG_32: *r_channels = 2; return GPU_RG32F;
+ case DRW_TEX_RGBA_8: *r_channels = 4; return GPU_RGBA8;
+ case DRW_TEX_RGBA_16: *r_channels = 4; return GPU_RGBA16F;
+ case DRW_TEX_RGBA_32: *r_channels = 4; return GPU_RGBA32F;
+ case DRW_TEX_DEPTH_24: *r_channels = 1; return GPU_DEPTH_COMPONENT24;
+ case DRW_TEX_RGB_11_11_10: *r_channels = 3; return GPU_R11F_G11F_B10F;
+ default:
+ BLI_assert(false && "Texture format unsupported as render target!");
+ *r_channels = 4; return GPU_RGBA8;
+ }
+}
+
+void DRW_framebuffer_init(
+ struct GPUFrameBuffer **fb, void *engine_type, int width, int height,
+ DRWFboTexture textures[MAX_FBO_TEX], int textures_len)
+{
+ BLI_assert(textures_len <= MAX_FBO_TEX);
+
+ bool create_fb = false;
+ int color_attachment = -1;
+
+ if (!*fb) {
+ *fb = GPU_framebuffer_create();
+ create_fb = true;
+ }
+
+ for (int i = 0; i < textures_len; ++i) {
+ int channels;
+ bool is_depth;
+
+ DRWFboTexture fbotex = textures[i];
+ bool is_temp = (fbotex.flag & DRW_TEX_TEMP) != 0;
+
+ GPUTextureFormat gpu_format = convert_tex_format(fbotex.format, &channels, &is_depth);
+
+ if (!*fbotex.tex || is_temp) {
+ /* Temp textures need to be queried each frame, others not. */
+ if (is_temp) {
+ *fbotex.tex = GPU_viewport_texture_pool_query(
+ DST.viewport, engine_type, width, height, channels, gpu_format);
+ }
+ else if (create_fb) {
+ *fbotex.tex = GPU_texture_create_2D_custom(
+ width, height, channels, gpu_format, NULL, NULL);
+ }
+ }
+
+ if (create_fb) {
+ if (!is_depth) {
+ ++color_attachment;
+ }
+ drw_texture_set_parameters(*fbotex.tex, fbotex.flag);
+ GPU_framebuffer_texture_attach(*fb, *fbotex.tex, color_attachment, 0);
+ }
+ }
+
+ if (create_fb) {
+ if (!GPU_framebuffer_check_valid(*fb, NULL)) {
+ printf("Error invalid framebuffer\n");
+ }
+
+ /* Detach temp textures */
+ for (int i = 0; i < textures_len; ++i) {
+ DRWFboTexture fbotex = textures[i];
+
+ if ((fbotex.flag & DRW_TEX_TEMP) != 0) {
+ GPU_framebuffer_texture_detach(*fbotex.tex);
+ }
+ }
+
+ GPU_framebuffer_bind(DST.default_framebuffer);
+ }
+}
+
+void DRW_framebuffer_free(struct GPUFrameBuffer *fb)
+{
+ GPU_framebuffer_free(fb);
+}
+
+void DRW_framebuffer_bind(struct GPUFrameBuffer *fb)
+{
+ GPU_framebuffer_bind(fb);
+}
+
+void DRW_framebuffer_clear(bool color, bool depth, bool stencil, float clear_col[4], float clear_depth)
+{
+ if (color) {
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glClearColor(clear_col[0], clear_col[1], clear_col[2], clear_col[3]);
+ }
+ if (depth) {
+ glDepthMask(GL_TRUE);
+ glClearDepth(clear_depth);
+ }
+ if (stencil) {
+ glStencilMask(0xFF);
+ }
+ glClear(((color) ? GL_COLOR_BUFFER_BIT : 0) |
+ ((depth) ? GL_DEPTH_BUFFER_BIT : 0) |
+ ((stencil) ? GL_STENCIL_BUFFER_BIT : 0));
+}
+
+void DRW_framebuffer_read_data(int x, int y, int w, int h, int channels, int slot, float *data)
+{
+ 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);
+}
+
+void DRW_framebuffer_texture_attach(struct GPUFrameBuffer *fb, GPUTexture *tex, int slot, int mip)
+{
+ GPU_framebuffer_texture_attach(fb, tex, slot, mip);
+}
+
+void DRW_framebuffer_texture_layer_attach(struct GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int layer, int mip)
+{
+ GPU_framebuffer_texture_layer_attach(fb, tex, slot, layer, mip);
+}
+
+void DRW_framebuffer_cubeface_attach(struct GPUFrameBuffer *fb, GPUTexture *tex, int slot, int face, int mip)
+{
+ GPU_framebuffer_texture_cubeface_attach(fb, tex, slot, face, mip);
+}
+
+void DRW_framebuffer_texture_detach(GPUTexture *tex)
+{
+ GPU_framebuffer_texture_detach(tex);
+}
+
+void DRW_framebuffer_blit(struct GPUFrameBuffer *fb_read, struct GPUFrameBuffer *fb_write, bool depth)
+{
+ GPU_framebuffer_blit(fb_read, 0, fb_write, 0, depth);
+}
+
+void DRW_framebuffer_recursive_downsample(
+ struct GPUFrameBuffer *fb, struct GPUTexture *tex, int num_iter,
+ void (*callback)(void *userData, int level), void *userData)
+{
+ GPU_framebuffer_recursive_downsample(fb, tex, num_iter, callback, userData);
+}
+
+void DRW_framebuffer_viewport_size(struct GPUFrameBuffer *UNUSED(fb_read), int x, int y, int w, int h)
+{
+ glViewport(x, y, w, h);
+}
+
+/* Use color management profile to draw texture to framebuffer */
+void DRW_transform_to_display(GPUTexture *tex)
+{
+ DRW_state_set(DRW_STATE_WRITE_COLOR);
+
+ Gwn_VertFormat *vert_format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(vert_format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int texco = GWN_vertformat_attr_add(vert_format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ const float dither = 1.0f;
+
+ bool use_ocio = false;
+
+ {
+ Scene *scene = DST.draw_ctx.scene;
+ use_ocio = IMB_colormanagement_setup_glsl_draw_from_space(
+ &scene->view_settings, &scene->display_settings, NULL, dither, false);
+ }
+
+ if (!use_ocio) {
+ 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(GWN_PRIM_TRIS, 3);
+ immAttrib2f(texco, 0.0f, 0.0f);
+ immVertex2f(pos, -1.0f, -1.0f);
+
+ immAttrib2f(texco, 2.0f, 0.0f);
+ immVertex2f(pos, 3.0f, -1.0f);
+
+ immAttrib2f(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();
+ }
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Viewport (DRW_viewport)
+ * \{ */
+
+static void *DRW_viewport_engine_data_get(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;
+ }
+}
+
+const float *DRW_viewport_size_get(void)
+{
+ return &DST.size[0];
+}
+
+const float *DRW_viewport_screenvecs_get(void)
+{
+ return &DST.screenvecs[0][0];
+}
+
+const float *DRW_viewport_pixelsize_get(void)
+{
+ return &DST.pixsize;
+}
+
+/* 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];
+
+ DefaultFramebufferList *fbl = (DefaultFramebufferList *)GPU_viewport_framebuffer_list_get(DST.viewport);
+ DST.default_framebuffer = fbl->default_fb;
+ }
+ else {
+ DST.size[0] = 0;
+ DST.size[1] = 0;
+
+ DST.default_framebuffer = 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;
+
+ /* Reset facing */
+ DST.frontface = GL_CCW;
+ DST.backface = GL_CW;
+ glFrontFace(DST.frontface);
+}
+
+void DRW_viewport_matrix_get(float mat[4][4], DRWViewportMatrixType type)
+{
+ RegionView3D *rv3d = DST.draw_ctx.rv3d;
+
+ switch (type) {
+ case DRW_MAT_PERS:
+ copy_m4_m4(mat, rv3d->persmat);
+ break;
+ case DRW_MAT_PERSINV:
+ copy_m4_m4(mat, rv3d->persinv);
+ break;
+ case DRW_MAT_VIEW:
+ copy_m4_m4(mat, rv3d->viewmat);
+ break;
+ case DRW_MAT_VIEWINV:
+ copy_m4_m4(mat, rv3d->viewinv);
+ break;
+ case DRW_MAT_WIN:
+ copy_m4_m4(mat, rv3d->winmat);
+ break;
+ case DRW_MAT_WININV:
+ invert_m4_m4(mat, rv3d->winmat);
+ break;
+ default:
+ BLI_assert(!"Matrix type invalid");
+ break;
+ }
+}
+
+void DRW_viewport_matrix_override_set(float mat[4][4], DRWViewportMatrixType type)
+{
+ copy_m4_m4(viewport_matrix_override.mat[type], mat);
+ viewport_matrix_override.override[type] = true;
+}
+
+void DRW_viewport_matrix_override_unset(DRWViewportMatrixType type)
+{
+ viewport_matrix_override.override[type] = false;
+}
+
+bool DRW_viewport_is_persp_get(void)
+{
+ RegionView3D *rv3d = DST.draw_ctx.rv3d;
+ return rv3d->is_persp;
+}
+
+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)
+{
+ /* XXXXXXXXXXX HAAAAAAAACKKKK */
+ WM_main_add_notifier(NC_MATERIAL | ND_SHADING_DRAW, NULL);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/** \name SceneLayers (DRW_scenelayer)
+ * \{ */
+
+void **DRW_scene_layer_engine_data_get(DrawEngineType *engine_type, void (*callback)(void *storage))
+{
+ SceneLayerEngineData *sled;
+
+ for (sled = DST.draw_ctx.scene_layer->drawdata.first; sled; sled = sled->next) {
+ if (sled->engine_type == engine_type) {
+ return &sled->storage;
+ }
+ }
+
+ sled = MEM_callocN(sizeof(SceneLayerEngineData), "SceneLayerEngineData");
+ sled->engine_type = engine_type;
+ sled->free = callback;
+ BLI_addtail(&DST.draw_ctx.scene_layer->drawdata, sled);
+
+ return &sled->storage;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Objects (DRW_object)
+ * \{ */
+
+void **DRW_object_engine_data_get(
+ Object *ob, DrawEngineType *engine_type, void (*callback)(void *storage))
+{
+ ObjectEngineData *oed;
+
+ for (oed = ob->drawdata.first; oed; oed = oed->next) {
+ if (oed->engine_type == engine_type) {
+ return &oed->storage;
+ }
+ }
+
+ oed = MEM_callocN(sizeof(ObjectEngineData), "ObjectEngineData");
+ oed->engine_type = engine_type;
+ oed->free = callback;
+ BLI_addtail(&ob->drawdata, oed);
+
+ return &oed->storage;
+}
+
+/* XXX There is definitly some overlap between this and DRW_object_engine_data_get.
+ * We should get rid of one of the two. */
+LampEngineData *DRW_lamp_engine_data_get(Object *ob, RenderEngineType *engine_type)
+{
+ BLI_assert(ob->type == OB_LAMP);
+
+ Scene *scene = DST.draw_ctx.scene;
+
+ /* TODO Dupliobjects */
+ /* TODO Should be per scenelayer */
+ return GPU_lamp_engine_data_get(scene, ob, NULL, engine_type);
+}
+
+void DRW_lamp_engine_data_free(LampEngineData *led)
+{
+ GPU_lamp_engine_data_free(led);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Rendering (DRW_engines)
+ * \{ */
+
+#define TIMER_FALLOFF 0.1f
+
+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_get(engine);
+ double stime = PIL_check_seconds_timer();
+
+ if (engine->engine_init) {
+ engine->engine_init(data);
+ }
+
+ double ftime = (PIL_check_seconds_timer() - stime) * 1e3;
+ data->init_time = data->init_time * (1.0f - TIMER_FALLOFF) + ftime * TIMER_FALLOFF; /* exp average */
+ }
+}
+
+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_get(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;
+ }
+
+ double stime = PIL_check_seconds_timer();
+ data->cache_time = 0.0;
+
+ if (engine->cache_init) {
+ engine->cache_init(data);
+ }
+
+ data->cache_time += (PIL_check_seconds_timer() - stime) * 1e3;
+ }
+}
+
+static void DRW_engines_cache_populate(Object *ob)
+{
+ for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ DrawEngineType *engine = link->data;
+ ViewportEngineData *data = DRW_viewport_engine_data_get(engine);
+ double stime = PIL_check_seconds_timer();
+
+ if (engine->cache_populate) {
+ engine->cache_populate(data, ob);
+ }
+
+ data->cache_time += (PIL_check_seconds_timer() - stime) * 1e3;
+ }
+}
+
+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_get(engine);
+ double stime = PIL_check_seconds_timer();
+
+ if (engine->cache_finish) {
+ engine->cache_finish(data);
+ }
+
+ data->cache_time += (PIL_check_seconds_timer() - stime) * 1e3;
+ }
+}
+
+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_get(engine);
+ double stime = PIL_check_seconds_timer();
+
+ if (engine->draw_background) {
+ engine->draw_background(data);
+ return;
+ }
+
+ double ftime = (PIL_check_seconds_timer() - stime) * 1e3;
+ data->background_time = data->background_time * (1.0f - TIMER_FALLOFF) + ftime * TIMER_FALLOFF; /* exp average */
+ }
+
+ /* No draw_background found, doing default 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_get(engine);
+ double stime = PIL_check_seconds_timer();
+
+ if (engine->draw_scene) {
+ engine->draw_scene(data);
+ }
+
+ double ftime = (PIL_check_seconds_timer() - stime) * 1e3;
+ data->render_time = data->render_time * (1.0f - TIMER_FALLOFF) + ftime * TIMER_FALLOFF; /* exp average */
+ }
+}
+
+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_get(engine);
+ double stime = PIL_check_seconds_timer();
+
+ if (data->text_draw_cache) {
+ DRW_text_cache_draw(data->text_draw_cache, DST.draw_ctx.v3d, DST.draw_ctx.ar, false);
+ }
+
+ double ftime = (PIL_check_seconds_timer() - stime) * 1e3;
+ data->render_time = data->render_time * (1.0f - TIMER_FALLOFF) + ftime * TIMER_FALLOFF; /* exp average */
+ }
+}
+
+#define MAX_INFO_LINES 10
+
+/**
+ * Returns the offset required for the drawing of engines info.
+ */
+int DRW_draw_region_engine_info_offset(void)
+{
+ int lines = 0;
+ for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ DrawEngineType *engine = link->data;
+ ViewportEngineData *data = DRW_viewport_engine_data_get(engine);
+
+ /* Count the number of lines. */
+ if (data->info[0] != '\0') {
+ lines++;
+ char *c = data->info;
+ while (*c++ != '\0') {
+ if (*c == '\n') {
+ lines++;
+ }
+ }
+ }
+ }
+ return MIN2(MAX_INFO_LINES, lines) * UI_UNIT_Y;
+}
+
+/**
+ * Actual drawing;
+ */
+void DRW_draw_region_engine_info(void)
+{
+ const char *info_array_final[MAX_INFO_LINES + 1];
+ /* This should be maxium number of engines running at the same time. */
+ char info_array[MAX_INFO_LINES][GPU_INFO_SIZE];
+ int i = 0;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ARegion *ar = draw_ctx->ar;
+ float fill_color[4] = {0.0f, 0.0f, 0.0f, 0.25f};
+
+ UI_GetThemeColor3fv(TH_HIGH_GRAD, fill_color);
+ mul_v3_fl(fill_color, fill_color[3]);
+
+ for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ DrawEngineType *engine = link->data;
+ ViewportEngineData *data = DRW_viewport_engine_data_get(engine);
+
+ if (data->info[0] != '\0') {
+ char *chr_current = data->info;
+ char *chr_start = chr_current;
+ int line_len = 0;
+
+ while (*chr_current++ != '\0') {
+ line_len++;
+ if (*chr_current == '\n') {
+ BLI_strncpy(info_array[i++], chr_start, line_len + 1);
+ /* Re-start counting. */
+ chr_start = chr_current + 1;
+ line_len = -1;
+ }
+ }
+
+ BLI_strncpy(info_array[i++], chr_start, line_len + 1);
+
+ if (i >= MAX_INFO_LINES) {
+ break;
+ }
+ }
+ }
+
+ for (int j = 0; j < i; j++) {
+ info_array_final[j] = info_array[j];
+ }
+ info_array_final[i] = NULL;
+
+ if (info_array[0] != NULL) {
+ ED_region_info_draw_multiline(ar, info_array_final, fill_color, true);
+ }
+}
+
+#undef MAX_INFO_LINES
+
+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);
+}
+
+/* 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(const Scene *scene)
+{
+ /* TODO layers */
+ RenderEngineType *type = RE_engines_find(scene->r.engine);
+ if (type->draw_engine != NULL) {
+ use_drw_engine(type->draw_engine);
+ }
+
+ if ((type->flag & RE_INTERNAL) == 0) {
+ DRW_engines_enable_external();
+ }
+}
+
+static void DRW_engines_enable_from_object_mode(void)
+{
+ use_drw_engine(&draw_engine_object_type);
+}
+
+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_CURVE:
+ use_drw_engine(&draw_engine_edit_curve_type);
+ break;
+ case CTX_MODE_EDIT_SURFACE:
+ use_drw_engine(&draw_engine_edit_surface_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_POSE:
+ use_drw_engine(&draw_engine_pose_type);
+ break;
+ case CTX_MODE_SCULPT:
+ use_drw_engine(&draw_engine_sculpt_type);
+ break;
+ case CTX_MODE_PAINT_WEIGHT:
+ use_drw_engine(&draw_engine_pose_type);
+ 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;
+ case CTX_MODE_PARTICLE:
+ use_drw_engine(&draw_engine_particle_type);
+ break;
+ case CTX_MODE_OBJECT:
+ break;
+ default:
+ BLI_assert(!"Draw mode invalid");
+ break;
+ }
+}
+
+/**
+ * Use for select and depth-drawing.
+ */
+static void DRW_engines_enable_basic(void)
+{
+ use_drw_engine(DRW_engine_viewport_basic_type.draw_engine);
+}
+
+/**
+ * Use for external render engines.
+ */
+static void DRW_engines_enable_external(void)
+{
+ use_drw_engine(DRW_engine_viewport_external_type.draw_engine);
+}
+
+static void DRW_engines_enable(const Scene *scene, SceneLayer *sl)
+{
+ Object *obact = OBACT_NEW;
+ const int mode = CTX_data_mode_enum_ex(scene->obedit, obact);
+ DRW_engines_enable_from_engine(scene);
+
+ if (DRW_state_draw_support()) {
+ DRW_engines_enable_from_object_mode();
+ DRW_engines_enable_from_mode(mode);
+ }
+}
+
+static void DRW_engines_disable(void)
+{
+ BLI_freelistN(&DST.enabled_engines);
+}
+
+static unsigned int DRW_engines_get_hash(void)
+{
+ unsigned int 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;
+}
+
+static void draw_stat(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);
+}
+
+/* CPU stats */
+static void DRW_debug_cpu_stats(void)
+{
+ int u, v;
+ double cache_tot_time = 0.0, init_tot_time = 0.0, background_tot_time = 0.0, render_tot_time = 0.0, tot_time = 0.0;
+ /* local coordinate visible rect inside region, to accomodate overlapping ui */
+ rcti rect;
+ struct ARegion *ar = DST.draw_ctx.ar;
+ ED_region_visible_rect(ar, &rect);
+
+ UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
+
+ /* row by row */
+ v = 0; u = 0;
+ /* Label row */
+ char col_label[32];
+ sprintf(col_label, "Engine");
+ draw_stat(&rect, u++, v, col_label, sizeof(col_label));
+ sprintf(col_label, "Cache");
+ draw_stat(&rect, u++, v, col_label, sizeof(col_label));
+ sprintf(col_label, "Init");
+ draw_stat(&rect, u++, v, col_label, sizeof(col_label));
+ sprintf(col_label, "Background");
+ draw_stat(&rect, u++, v, col_label, sizeof(col_label));
+ sprintf(col_label, "Render");
+ draw_stat(&rect, u++, v, col_label, sizeof(col_label));
+ sprintf(col_label, "Total (w/o cache)");
+ draw_stat(&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_get(engine);
+
+ draw_stat(&rect, u++, v, engine->idname, sizeof(engine->idname));
+
+ cache_tot_time += data->cache_time;
+ sprintf(time_to_txt, "%.2fms", data->cache_time);
+ draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt));
+
+ init_tot_time += data->init_time;
+ sprintf(time_to_txt, "%.2fms", data->init_time);
+ draw_stat(&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(&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(&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(&rect, u++, v, time_to_txt, sizeof(time_to_txt));
+ v++;
+ }
+
+ /* Totals row */
+ u = 0;
+ sprintf(col_label, "Sub Total");
+ draw_stat(&rect, u++, v, col_label, sizeof(col_label));
+ sprintf(time_to_txt, "%.2fms", cache_tot_time);
+ draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt));
+ sprintf(time_to_txt, "%.2fms", init_tot_time);
+ draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt));
+ sprintf(time_to_txt, "%.2fms", background_tot_time);
+ draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt));
+ sprintf(time_to_txt, "%.2fms", render_tot_time);
+ draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt));
+ sprintf(time_to_txt, "%.2fms", tot_time);
+ draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt));
+}
+
+/* Display GPU time for each passes */
+static void DRW_debug_gpu_stats(void)
+{
+ /* local coordinate visible rect inside region, to accomodate overlapping ui */
+ rcti rect;
+ struct ARegion *ar = DST.draw_ctx.ar;
+ ED_region_visible_rect(ar, &rect);
+
+ UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
+
+ char time_to_txt[16];
+ char pass_name[MAX_PASS_NAME + 16];
+ int v = BLI_listbase_count(&DST.enabled_engines) + 3;
+ GLuint64 tot_time = 0;
+
+ if (G.debug_value > 666) {
+ for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ GLuint64 engine_time = 0;
+ DrawEngineType *engine = link->data;
+ ViewportEngineData *data = DRW_viewport_engine_data_get(engine);
+ int vsta = v;
+
+ draw_stat(&rect, 0, v, engine->idname, sizeof(engine->idname));
+ v++;
+
+ for (int i = 0; i < engine->vedata_size->psl_len; ++i) {
+ DRWPass *pass = data->psl->passes[i];
+ if (pass != NULL && pass->wasdrawn) {
+ GLuint64 time;
+ glGetQueryObjectui64v(pass->timer_queries[pass->front_idx], GL_QUERY_RESULT, &time);
+
+ sprintf(pass_name, " |--> %s", pass->name);
+ draw_stat(&rect, 0, v, pass_name, sizeof(pass_name));
+
+ sprintf(time_to_txt, "%.2fms", time / 1000000.0);
+ engine_time += time;
+ tot_time += time;
+
+ draw_stat(&rect, 2, v++, time_to_txt, sizeof(time_to_txt));
+
+ pass->wasdrawn = false;
+ }
+ }
+ /* engine total time */
+ sprintf(time_to_txt, "%.2fms", engine_time / 1000000.0);
+ draw_stat(&rect, 2, vsta, time_to_txt, sizeof(time_to_txt));
+ v++;
+ }
+
+ sprintf(pass_name, "Total GPU time %.2fms (%.1f fps)", tot_time / 1000000.0, 1000000000.0 / tot_time);
+ draw_stat(&rect, 0, v++, pass_name, sizeof(pass_name));
+ v++;
+ }
+
+ /* Memory Stats */
+ unsigned int tex_mem = GPU_texture_memory_usage_get();
+ unsigned int vbo_mem = GWN_vertbuf_get_memory_usage();
+
+ sprintf(pass_name, "GPU Memory");
+ draw_stat(&rect, 0, v, pass_name, sizeof(pass_name));
+ sprintf(pass_name, "%.2fMB", (float)(tex_mem + vbo_mem) / 1000000.0);
+ draw_stat(&rect, 1, v++, pass_name, sizeof(pass_name));
+ sprintf(pass_name, " |--> Textures");
+ draw_stat(&rect, 0, v, pass_name, sizeof(pass_name));
+ sprintf(pass_name, "%.2fMB", (float)tex_mem / 1000000.0);
+ draw_stat(&rect, 1, v++, pass_name, sizeof(pass_name));
+ sprintf(pass_name, " |--> Meshes");
+ draw_stat(&rect, 0, v, pass_name, sizeof(pass_name));
+ sprintf(pass_name, "%.2fMB", (float)vbo_mem / 1000000.0);
+ draw_stat(&rect, 1, v++, pass_name, sizeof(pass_name));
+}
+
+
+/* -------------------------------------------------------------------- */
+
+/** \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)
+{
+ struct Depsgraph *graph = CTX_data_depsgraph(C);
+ ARegion *ar = CTX_wm_region(C);
+ View3D *v3d = CTX_wm_view3d(C);
+
+ /* Reset before using it. */
+ memset(&DST, 0x0, sizeof(DST));
+ DRW_draw_render_loop_ex(graph, ar, v3d, 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 *graph,
+ ARegion *ar, View3D *v3d,
+ const bContext *evil_C)
+{
+ Scene *scene = DEG_get_evaluated_scene(graph);
+ SceneLayer *sl = DEG_get_evaluated_scene_layer(graph);
+ RegionView3D *rv3d = ar->regiondata;
+
+ DST.draw_ctx.evil_C = evil_C;
+
+ bool cache_is_dirty;
+ DST.viewport = rv3d->viewport;
+ v3d->zbuf = true;
+
+ /* Setup viewport */
+ cache_is_dirty = GPU_viewport_cache_validate(DST.viewport, DRW_engines_get_hash());
+
+ DST.draw_ctx = (DRWContextState){
+ ar, rv3d, v3d, scene, sl, OBACT_NEW,
+ /* reuse if caller sets */
+ DST.draw_ctx.evil_C,
+ };
+
+ DRW_viewport_var_init();
+
+ /* Get list of enabled engines */
+ DRW_engines_enable(scene, sl);
+
+ /* Update ubos */
+ DRW_globals_update();
+
+ /* Init engines */
+ DRW_engines_init();
+
+ /* TODO : tag to refresh by the deps graph */
+ /* ideally only refresh when objects are added/removed */
+ /* or render properties / materials change */
+ if (cache_is_dirty) {
+ DRW_engines_cache_init();
+
+ DEG_OBJECT_ITER(graph, ob, DEG_OBJECT_ITER_FLAG_ALL);
+ {
+ DRW_engines_cache_populate(ob);
+ /* XXX find a better place for this. maybe Depsgraph? */
+ ob->deg_update_flag = 0;
+ }
+ DEG_OBJECT_ITER_END
+
+ DRW_engines_cache_finish();
+ }
+
+ /* Start Drawing */
+ DRW_state_reset();
+ DRW_engines_draw_background();
+
+ 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();
+
+ 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_engines_draw_text();
+
+ if (DST.draw_ctx.evil_C) {
+ /* needed so manipulator isn't obscured */
+ glDisable(GL_DEPTH_TEST);
+
+ DRW_draw_manipulator();
+ glEnable(GL_DEPTH_TEST);
+
+ DRW_draw_region_info();
+ }
+
+ if (G.debug_value > 20) {
+ DRW_debug_cpu_stats();
+ DRW_debug_gpu_stats();
+ }
+
+ DRW_state_reset();
+ DRW_engines_disable();
+
+#ifdef DEBUG
+ /* Avoid accidental reuse. */
+ memset(&DST, 0xFF, sizeof(DST));
+#endif
+}
+
+void DRW_draw_render_loop(
+ struct Depsgraph *graph,
+ ARegion *ar, View3D *v3d)
+{
+ /* Reset before using it. */
+ memset(&DST, 0x0, sizeof(DST));
+ DRW_draw_render_loop_ex(graph, ar, v3d, NULL);
+}
+
+void DRW_draw_render_loop_offscreen(
+ struct Depsgraph *graph,
+ ARegion *ar, View3D *v3d, GPUOffScreen *ofs)
+{
+ RegionView3D *rv3d = ar->regiondata;
+
+ /* backup */
+ void *backup_viewport = rv3d->viewport;
+ {
+ /* backup (_never_ use rv3d->viewport) */
+ rv3d->viewport = GPU_viewport_create_from_offscreen(ofs);
+ }
+
+ /* Reset before using it. */
+ memset(&DST, 0x0, sizeof(DST));
+ DST.options.is_image_render = true;
+ DRW_draw_render_loop_ex(graph, ar, v3d, NULL);
+
+ /* restore */
+ {
+ /* don't free data owned by 'ofs' */
+ GPU_viewport_clear_from_offscreen(rv3d->viewport);
+ GPU_viewport_free(rv3d->viewport);
+ MEM_freeN(rv3d->viewport);
+
+ rv3d->viewport = backup_viewport;
+ }
+
+ /* we need to re-bind (annoying!) */
+ GPU_offscreen_bind(ofs, false);
+}
+
+/**
+ * object mode select-loop, see: ED_view3d_draw_select_loop (legacy drawing).
+ */
+void DRW_draw_select_loop(
+ struct Depsgraph *graph,
+ ARegion *ar, View3D *v3d,
+ bool UNUSED(use_obedit_skip), bool UNUSED(use_nearest), const rcti *rect)
+{
+ Scene *scene = DEG_get_evaluated_scene(graph);
+ SceneLayer *sl = DEG_get_evaluated_scene_layer(graph);
+#ifndef USE_GPU_SELECT
+ UNUSED_VARS(vc, scene, sl, v3d, ar, rect);
+#else
+ RegionView3D *rv3d = ar->regiondata;
+
+ /* Reset before using it. */
+ memset(&DST, 0x0, sizeof(DST));
+
+ /* backup (_never_ use rv3d->viewport) */
+ void *backup_viewport = rv3d->viewport;
+ rv3d->viewport = NULL;
+
+ bool use_obedit = false;
+ int obedit_mode = 0;
+ if (scene->obedit && scene->obedit->type == OB_MBALL) {
+ use_obedit = true;
+ DRW_engines_cache_populate(scene->obedit);
+ obedit_mode = CTX_MODE_EDIT_METABALL;
+ }
+ else if ((scene->obedit && scene->obedit->type == OB_ARMATURE)) {
+ /* if not drawing sketch, draw bones */
+ // if (!BDR_drawSketchNames(vc))
+ {
+ use_obedit = true;
+ obedit_mode = CTX_MODE_EDIT_ARMATURE;
+ }
+ }
+
+ struct GPUViewport *viewport = GPU_viewport_create();
+ GPU_viewport_size_set(viewport, (const int[2]){BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)});
+
+ bool cache_is_dirty;
+ DST.viewport = viewport;
+ v3d->zbuf = true;
+
+ DST.options.is_select = true;
+
+ /* Get list of enabled engines */
+ if (use_obedit) {
+ DRW_engines_enable_from_mode(obedit_mode);
+ }
+ else {
+ DRW_engines_enable_basic();
+ DRW_engines_enable_from_object_mode();
+ }
+
+ /* Setup viewport */
+ cache_is_dirty = true;
+
+ /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */
+ DST.draw_ctx = (DRWContextState){
+ ar, rv3d, v3d, scene, sl, OBACT_NEW, (bContext *)NULL,
+ };
+
+ DRW_viewport_var_init();
+
+ /* Update ubos */
+ DRW_globals_update();
+
+ /* Init engines */
+ DRW_engines_init();
+
+ /* TODO : tag to refresh by the deps graph */
+ /* ideally only refresh when objects are added/removed */
+ /* or render properties / materials change */
+ if (cache_is_dirty) {
+
+ DRW_engines_cache_init();
+
+ if (use_obedit) {
+ DRW_engines_cache_populate(scene->obedit);
+ }
+ else {
+ DEG_OBJECT_ITER(graph, ob, DEG_OBJECT_ITER_FLAG_DUPLI)
+ {
+ if ((ob->base_flag & BASE_SELECTABLED) != 0) {
+ DRW_select_load_id(ob->select_color);
+ DRW_engines_cache_populate(ob);
+ }
+ }
+ DEG_OBJECT_ITER_END
+ }
+
+ DRW_engines_cache_finish();
+ }
+
+ /* Start Drawing */
+ DRW_state_reset();
+ 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. */
+ memset(&DST, 0xFF, sizeof(DST));
+#endif
+
+ /* Cleanup for selection state */
+ GPU_viewport_free(viewport);
+ MEM_freeN(viewport);
+
+ /* restore */
+ rv3d->viewport = backup_viewport;
+#endif /* USE_GPU_SELECT */
+}
+
+/**
+ * object mode select-loop, see: ED_view3d_draw_depth_loop (legacy drawing).
+ */
+void DRW_draw_depth_loop(
+ Depsgraph *graph,
+ ARegion *ar, View3D *v3d)
+{
+ Scene *scene = DEG_get_evaluated_scene(graph);
+ SceneLayer *sl = DEG_get_evaluated_scene_layer(graph);
+ RegionView3D *rv3d = ar->regiondata;
+
+ /* backup (_never_ use rv3d->viewport) */
+ void *backup_viewport = rv3d->viewport;
+ rv3d->viewport = NULL;
+
+ /* Reset before using it. */
+ memset(&DST, 0x0, sizeof(DST));
+
+ struct GPUViewport *viewport = GPU_viewport_create();
+ GPU_viewport_size_set(viewport, (const int[2]){ar->winx, ar->winy});
+
+ bool cache_is_dirty;
+ DST.viewport = viewport;
+ v3d->zbuf = true;
+
+ DST.options.is_depth = true;
+
+ /* Get list of enabled engines */
+ {
+ DRW_engines_enable_basic();
+ DRW_engines_enable_from_object_mode();
+ }
+
+ /* Setup viewport */
+ cache_is_dirty = true;
+
+ /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */
+ DST.draw_ctx = (DRWContextState){
+ ar, rv3d, v3d, scene, sl, OBACT_NEW, (bContext *)NULL,
+ };
+
+ DRW_viewport_var_init();
+
+ /* Update ubos */
+ DRW_globals_update();
+
+ /* Init engines */
+ DRW_engines_init();
+
+ /* TODO : tag to refresh by the deps graph */
+ /* ideally only refresh when objects are added/removed */
+ /* or render properties / materials change */
+ if (cache_is_dirty) {
+
+ DRW_engines_cache_init();
+
+ DEG_OBJECT_ITER(graph, ob, DEG_OBJECT_ITER_FLAG_ALL)
+ {
+ DRW_engines_cache_populate(ob);
+ }
+ DEG_OBJECT_ITER_END
+
+ DRW_engines_cache_finish();
+ }
+
+ /* Start Drawing */
+ DRW_state_reset();
+ 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. */
+ memset(&DST, 0xFF, sizeof(DST));
+#endif
+
+ /* Cleanup for selection state */
+ GPU_viewport_free(viewport);
+ MEM_freeN(viewport);
+
+ /* restore */
+ rv3d->viewport = backup_viewport;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \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);
+}
+
+/**
+ * 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;
+}
+
+/**
+ * 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;
+}
+
+/**
+ * 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);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Context State (DRW_context_state)
+ * \{ */
+
+const DRWContextState *DRW_context_state_get(void)
+{
+ return &DST.draw_ctx;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Init/Exit (DRW_engines)
+ * \{ */
+
+void DRW_engine_register(DrawEngineType *draw_engine_type)
+{
+ BLI_addtail(&DRW_engines, draw_engine_type);
+}
+
+void DRW_engines_register(void)
+{
+#ifdef WITH_CLAY_ENGINE
+ RE_engines_register(NULL, &DRW_engine_viewport_clay_type);
+#endif
+ RE_engines_register(NULL, &DRW_engine_viewport_eevee_type);
+
+ 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_surface_type);
+ DRW_engine_register(&draw_engine_edit_text_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);
+
+ /* setup callbacks */
+ {
+ /* BKE: curve.c */
+ extern void *BKE_curve_batch_cache_dirty_cb;
+ extern void *BKE_curve_batch_cache_free_cb;
+ /* BKE: mesh.c */
+ extern void *BKE_mesh_batch_cache_dirty_cb;
+ extern void *BKE_mesh_batch_cache_free_cb;
+ /* BKE: lattice.c */
+ extern void *BKE_lattice_batch_cache_dirty_cb;
+ extern void *BKE_lattice_batch_cache_free_cb;
+ /* BKE: particle.c */
+ extern void *BKE_particle_batch_cache_dirty_cb;
+ extern void *BKE_particle_batch_cache_free_cb;
+
+ BKE_curve_batch_cache_dirty_cb = DRW_curve_batch_cache_dirty;
+ BKE_curve_batch_cache_free_cb = DRW_curve_batch_cache_free;
+
+ BKE_mesh_batch_cache_dirty_cb = DRW_mesh_batch_cache_dirty;
+ BKE_mesh_batch_cache_free_cb = DRW_mesh_batch_cache_free;
+
+ BKE_lattice_batch_cache_dirty_cb = DRW_lattice_batch_cache_dirty;
+ BKE_lattice_batch_cache_free_cb = DRW_lattice_batch_cache_free;
+
+ BKE_particle_batch_cache_dirty_cb = DRW_particle_batch_cache_dirty;
+ BKE_particle_batch_cache_free_cb = DRW_particle_batch_cache_free;
+ }
+}
+
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+extern struct GPUTexture *globals_ramp; /* draw_common.c */
+void DRW_engines_free(void)
+{
+ DRW_shape_cache_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();
+ }
+ }
+
+ if (globals_ubo)
+ GPU_uniformbuffer_free(globals_ubo);
+
+ if (globals_ramp)
+ GPU_texture_free(globals_ramp);
+
+#ifdef WITH_CLAY_ENGINE
+ BLI_remlink(&R_engines, &DRW_engine_viewport_clay_type);
+#endif
+}
+
+/** \} */
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..56255af98ce
--- /dev/null
+++ b/source/blender/draw/intern/draw_manager_text.c
@@ -0,0 +1,199 @@
+/*
+ * 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 {
+ 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;
+
+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 flag,
+ const unsigned char 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->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,
+ View3D *v3d, ARegion *ar, bool depth_write)
+{
+ 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];
+ gpuGetProjectionMatrix(original_proj);
+ wmOrtho2_region_pixelspace(ar);
+
+ gpuPushMatrix();
+ gpuLoadIdentity();
+
+ if (depth_write) {
+ if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
+ }
+ else {
+ glDepthMask(GL_FALSE);
+ }
+
+ 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]), (depth_write) ? 0.0f : 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);
+ }
+ }
+
+ if (depth_write) {
+ if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
+ }
+ else {
+ glDepthMask(GL_TRUE);
+ }
+
+ gpuPopMatrix();
+ gpuLoadProjectionMatrix(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..a58e167be0d
--- /dev/null
+++ b/source/blender/draw/intern/draw_manager_text.h
@@ -0,0 +1,54 @@
+/*
+ * 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 flag,
+ const unsigned char col[4]);
+
+void DRW_text_cache_draw(
+ struct DRWTextStore *dt,
+ struct View3D *v3d, struct ARegion *ar, bool depth_write);
+
+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_view.c b/source/blender/draw/intern/draw_view.c
new file mode 100644
index 00000000000..37c44f33915
--- /dev/null
+++ b/source/blender/draw/intern/draw_view.c
@@ -0,0 +1,732 @@
+/*
+ * 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_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;
+ int offset;
+
+ DRW_draw_cursor();
+
+ offset = DRW_draw_region_engine_info_offset();
+
+ view3d_draw_region_info(draw_ctx->evil_C, ar, offset);
+
+ if (offset > 0) {
+ DRW_draw_region_engine_info();
+ }
+}
+
+/* ************************* Grid ************************** */
+
+static void gridline_range(double x0, double dx, double max, int *r_first, int *r_count)
+{
+ /* determine range of gridlines that appear in this Area -- similar calc but separate ranges for x & y
+ * x0 is gridline 0, the axis in screen space
+ * Area covers [0 .. max) pixels */
+
+ int first = (int)ceil(-x0 / dx);
+ int last = (int)floor((max - x0) / dx);
+
+ if (first <= last) {
+ *r_first = first;
+ *r_count = last - first + 1;
+ }
+ else {
+ *r_first = 0;
+ *r_count = 0;
+ }
+}
+
+static int gridline_count(ARegion *ar, double x0, double y0, double dx)
+{
+ /* x0 & y0 establish the "phase" of the grid within this 2D region
+ * dx is the frequency, shared by x & y directions
+ * pass in dx of smallest (highest precision) grid we want to draw */
+
+ int first, x_ct, y_ct;
+
+ gridline_range(x0, dx, ar->winx, &first, &x_ct);
+ gridline_range(y0, dx, ar->winy, &first, &y_ct);
+
+ int total_ct = x_ct + y_ct;
+
+ return total_ct;
+}
+
+static bool drawgrid_draw(
+ ARegion *ar, double x0, double y0, double dx, int skip_mod,
+ unsigned pos, unsigned col, GLubyte col_value[3])
+{
+ /* skip every skip_mod lines relative to each axis; they will be overlaid by another drawgrid_draw
+ * always skip exact x0 & y0 axes; they will be drawn later in color
+ *
+ * set grid color once, just before the first line is drawn
+ * it's harmless to set same color for every line, or every vertex
+ * but if no lines are drawn, color must not be set! */
+
+ const float x_max = (float)ar->winx;
+ const float y_max = (float)ar->winy;
+
+ int first, ct;
+ int x_ct = 0, y_ct = 0; /* count of lines actually drawn */
+ int lines_skipped_for_next_unit = 0;
+
+ /* draw vertical lines */
+ gridline_range(x0, dx, x_max, &first, &ct);
+
+ for (int i = first; i < first + ct; ++i) {
+ if (i == 0)
+ continue;
+ else if (skip_mod && (i % skip_mod) == 0) {
+ ++lines_skipped_for_next_unit;
+ continue;
+ }
+
+ if (x_ct == 0)
+ immAttrib3ub(col, col_value[0], col_value[1], col_value[2]);
+
+ float x = (float)(x0 + i * dx);
+ immVertex2f(pos, x, 0.0f);
+ immVertex2f(pos, x, y_max);
+ ++x_ct;
+ }
+
+ /* draw horizontal lines */
+ gridline_range(y0, dx, y_max, &first, &ct);
+
+ for (int i = first; i < first + ct; ++i) {
+ if (i == 0)
+ continue;
+ else if (skip_mod && (i % skip_mod) == 0) {
+ ++lines_skipped_for_next_unit;
+ continue;
+ }
+
+ if (x_ct + y_ct == 0)
+ immAttrib3ub(col, col_value[0], col_value[1], col_value[2]);
+
+ float y = (float)(y0 + i * dx);
+ immVertex2f(pos, 0.0f, y);
+ immVertex2f(pos, x_max, y);
+ ++y_ct;
+ }
+
+ return lines_skipped_for_next_unit > 0;
+}
+
+#define GRID_MIN_PX_D 6.0
+#define GRID_MIN_PX_F 6.0f
+
+static void drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **grid_unit)
+{
+ RegionView3D *rv3d = ar->regiondata;
+
+ double fx = rv3d->persmat[3][0];
+ double fy = rv3d->persmat[3][1];
+ double fw = rv3d->persmat[3][3];
+
+ const double wx = 0.5 * ar->winx; /* use double precision to avoid rounding errors */
+ const double wy = 0.5 * ar->winy;
+
+ double x = wx * fx / fw;
+ double y = wy * fy / fw;
+
+ double vec4[4] = { v3d->grid, v3d->grid, 0.0, 1.0 };
+ mul_m4_v4d(rv3d->persmat, vec4);
+ fx = vec4[0];
+ fy = vec4[1];
+ fw = vec4[3];
+
+ double dx = fabs(x - wx * fx / fw);
+ if (dx == 0) dx = fabs(y - wy * fy / fw);
+
+ x += wx;
+ y += wy;
+
+ /* now x, y, and dx have their final values
+ * (x,y) is the world origin (0,0,0) mapped to Area-relative screen space
+ * dx is the distance in pixels between grid lines -- same for horiz or vert grid lines */
+
+ glLineWidth(1.0f);
+
+#if 0 /* TODO: write to UI/widget depth buffer, not scene depth */
+ glDepthMask(GL_FALSE); /* disable write in zbuffer */
+#endif
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+
+ unsigned char col[3], col2[3];
+ UI_GetThemeColor3ubv(TH_GRID, col);
+
+ if (unit->system) {
+ const void *usys;
+ int len;
+
+ bUnit_GetSystem(unit->system, B_UNIT_LENGTH, &usys, &len);
+
+ bool first = true;
+
+ if (usys) {
+ int i = len;
+ while (i--) {
+ double scalar = bUnit_GetScaler(usys, i);
+
+ double dx_scalar = dx * scalar / (double)unit->scale_length;
+ if (dx_scalar < (GRID_MIN_PX_D * 2.0)) {
+ /* very very small grid items are less useful when dealing with units */
+ continue;
+ }
+
+ if (first) {
+ first = false;
+
+ /* Store the smallest drawn grid size units name so users know how big each grid cell is */
+ *grid_unit = bUnit_GetNameDisplay(usys, i);
+ rv3d->gridview = (float)((scalar * (double)v3d->grid) / (double)unit->scale_length);
+
+ int gridline_ct = gridline_count(ar, x, y, dx_scalar);
+ if (gridline_ct == 0)
+ goto drawgrid_cleanup; /* nothing to draw */
+
+ immBegin(GWN_PRIM_LINES, gridline_ct * 2);
+ }
+
+ float 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_GetThemeColorBlend3ubv(TH_HIGH_GRAD, TH_GRID, blend_fac, col2);
+
+ const int skip_mod = (i == 0) ? 0 : (int)round(bUnit_GetScaler(usys, i - 1) / scalar);
+ if (!drawgrid_draw(ar, x, y, dx_scalar, skip_mod, pos, color, col2))
+ break;
+ }
+ }
+ }
+ else {
+ const double sublines = v3d->gridsubdiv;
+ const float sublines_fl = v3d->gridsubdiv;
+
+ int grids_to_draw = 2; /* first the faint fine grid, then the bold coarse grid */
+
+ 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;
+ grids_to_draw = (dx < GRID_MIN_PX_D) ? 0 : 1;
+ }
+ }
+ }
+ 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)) {
+ grids_to_draw = 1;
+ }
+ }
+ }
+ }
+
+ int gridline_ct = gridline_count(ar, x, y, dx);
+ if (gridline_ct == 0)
+ goto drawgrid_cleanup; /* nothing to draw */
+
+ immBegin(GWN_PRIM_LINES, gridline_ct * 2);
+
+ if (grids_to_draw == 2) {
+ UI_GetThemeColorBlend3ubv(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0), col2);
+ if (drawgrid_draw(ar, x, y, dx, v3d->gridsubdiv, pos, color, col2)) {
+ drawgrid_draw(ar, x, y, dx * sublines, 0, pos, color, col);
+ }
+ }
+ else if (grids_to_draw == 1) {
+ drawgrid_draw(ar, x, y, dx, 0, pos, color, col);
+ }
+ }
+
+ /* draw visible axes */
+ /* horizontal line */
+ if (0 <= y && y < ar->winy) {
+ UI_make_axis_color(col, col2, ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT) ? 'Y' : 'X');
+ immAttrib3ub(color, col2[0], col2[1], col2[2]);
+ immVertex2f(pos, 0.0f, y);
+ immVertex2f(pos, (float)ar->winx, y);
+ }
+
+ /* vertical line */
+ if (0 <= x && x < ar->winx) {
+ UI_make_axis_color(col, col2, ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM) ? 'Y' : 'Z');
+ immAttrib3ub(color, col2[0], col2[1], col2[2]);
+ immVertex2f(pos, x, 0.0f);
+ immVertex2f(pos, x, (float)ar->winy);
+ }
+
+ immEnd();
+
+drawgrid_cleanup:
+ immUnbindProgram();
+
+#if 0 /* depth write is left enabled above */
+ glDepthMask(GL_TRUE); /* enable write in zbuffer */
+#endif
+}
+
+#undef DEBUG_GRID
+#undef GRID_MIN_PX_D
+#undef GRID_MIN_PX_F
+
+static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit)
+{
+ /* draw only if there is something to draw */
+ if (v3d->gridflag & (V3D_SHOW_FLOOR | V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_Z)) {
+ /* draw how many lines?
+ * trunc(v3d->gridlines / 2) * 4
+ * + 2 for xy axes (possibly with special colors)
+ * + 1 for z axis (the only line not in xy plane)
+ * even v3d->gridlines are honored, odd rounded down */
+ const int gridlines = v3d->gridlines / 2;
+ const float grid_scale = ED_view3d_grid_scale(scene, v3d, grid_unit);
+ const float grid = gridlines * grid_scale;
+
+ const bool show_floor = (v3d->gridflag & V3D_SHOW_FLOOR) && gridlines >= 1;
+
+ bool show_axis_x = (v3d->gridflag & V3D_SHOW_X) != 0;
+ bool show_axis_y = (v3d->gridflag & V3D_SHOW_Y) != 0;
+ bool show_axis_z = (v3d->gridflag & V3D_SHOW_Z) != 0;
+
+ unsigned char col_grid[3], col_axis[3];
+
+ glLineWidth(1.0f);
+
+ UI_GetThemeColor3ubv(TH_GRID, col_grid);
+
+ if (show_floor) {
+ const unsigned vertex_ct = 2 * (gridlines * 4 + 2);
+ const int sublines = v3d->gridsubdiv;
+
+ unsigned char col_bg[3], col_grid_emphasise[3], col_grid_light[3];
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
+
+ immBegin(GWN_PRIM_LINES, vertex_ct);
+
+ /* draw normal grid lines */
+ UI_GetColorPtrShade3ubv(col_grid, col_grid_light, 10);
+
+ for (int a = 1; a <= gridlines; a++) {
+ /* skip emphasised divider lines */
+ if (a % sublines != 0) {
+ const float line = a * grid_scale;
+
+ immAttrib3ubv(color, col_grid_light);
+
+ immVertex2f(pos, -grid, -line);
+ immVertex2f(pos, +grid, -line);
+ immVertex2f(pos, -grid, +line);
+ immVertex2f(pos, +grid, +line);
+
+ immVertex2f(pos, -line, -grid);
+ immVertex2f(pos, -line, +grid);
+ immVertex2f(pos, +line, -grid);
+ immVertex2f(pos, +line, +grid);
+ }
+ }
+
+ /* draw emphasised grid lines */
+ 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_emphasise,
+ (col_grid[0] + col_grid[1] + col_grid[2] + 30 >
+ col_bg[0] + col_bg[1] + col_bg[2]) ? 20 : -10);
+
+ if (sublines <= gridlines) {
+ immAttrib3ubv(color, col_grid_emphasise);
+
+ for (int a = sublines; a <= gridlines; a += sublines) {
+ const float line = a * grid_scale;
+
+ immVertex2f(pos, -grid, -line);
+ immVertex2f(pos, +grid, -line);
+ immVertex2f(pos, -grid, +line);
+ immVertex2f(pos, +grid, +line);
+
+ immVertex2f(pos, -line, -grid);
+ immVertex2f(pos, -line, +grid);
+ immVertex2f(pos, +line, -grid);
+ immVertex2f(pos, +line, +grid);
+ }
+ }
+
+ /* draw X axis */
+ if (show_axis_x) {
+ show_axis_x = false; /* drawing now, won't need to draw later */
+ UI_make_axis_color(col_grid, col_axis, 'X');
+ immAttrib3ubv(color, col_axis);
+ }
+ else
+ immAttrib3ubv(color, col_grid_emphasise);
+
+ immVertex2f(pos, -grid, 0.0f);
+ immVertex2f(pos, +grid, 0.0f);
+
+ /* draw Y axis */
+ if (show_axis_y) {
+ show_axis_y = false; /* drawing now, won't need to draw later */
+ UI_make_axis_color(col_grid, col_axis, 'Y');
+ immAttrib3ubv(color, col_axis);
+ }
+ else
+ immAttrib3ubv(color, col_grid_emphasise);
+
+ immVertex2f(pos, 0.0f, -grid);
+ immVertex2f(pos, 0.0f, +grid);
+
+ immEnd();
+ immUnbindProgram();
+
+ /* done with XY plane */
+ }
+
+ if (show_axis_x || show_axis_y || show_axis_z) {
+ /* draw axis lines -- sometimes grid floor is off, other times we still need to draw the Z axis */
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
+ immBegin(GWN_PRIM_LINES, (show_axis_x + show_axis_y + show_axis_z) * 2);
+
+ if (show_axis_x) {
+ UI_make_axis_color(col_grid, col_axis, 'X');
+ immAttrib3ubv(color, col_axis);
+ immVertex3f(pos, -grid, 0.0f, 0.0f);
+ immVertex3f(pos, +grid, 0.0f, 0.0f);
+ }
+
+ if (show_axis_y) {
+ UI_make_axis_color(col_grid, col_axis, 'Y');
+ immAttrib3ubv(color, col_axis);
+ immVertex3f(pos, 0.0f, -grid, 0.0f);
+ immVertex3f(pos, 0.0f, +grid, 0.0f);
+ }
+
+ if (show_axis_z) {
+ UI_make_axis_color(col_grid, col_axis, 'Z');
+ immAttrib3ubv(color, col_axis);
+ immVertex3f(pos, 0.0f, 0.0f, -grid);
+ immVertex3f(pos, 0.0f, 0.0f, +grid);
+ }
+
+ immEnd();
+ immUnbindProgram();
+ }
+ }
+}
+
+void DRW_draw_grid(void)
+{
+ /* TODO viewport
+ * Missing is the flags to check whether to draw it
+ * for now now we are using the flags in v3d itself.
+ *
+ * Also for now always assume depth is there, so we
+ * draw on top of it.
+ */
+ /**
+ * 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.
+ */
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ View3D *v3d = draw_ctx->v3d;
+ ARegion *ar = draw_ctx->ar;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+
+ const bool draw_floor = (rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO);
+ const char *grid_unit = NULL;
+
+ /* ortho grid goes first, does not write to depth buffer and doesn't need depth test so it will override
+ * objects if done last
+ * 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);
+
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+
+ if (!draw_floor) {
+ /* Do not get in front of overlays */
+ glDepthMask(GL_FALSE);
+
+ ED_region_pixelspace(ar);
+ *(&grid_unit) = NULL; /* drawgrid need this to detect/affect smallest valid unit... */
+ drawgrid(&scene->unit, ar, v3d, &grid_unit);
+
+ gpuLoadProjectionMatrix(rv3d->winmat);
+ gpuLoadMatrix(rv3d->viewmat);
+ }
+ else {
+ glDepthMask(GL_TRUE);
+ drawfloor(scene, v3d, &grid_unit);
+ }
+}
+
+/* ************************* 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);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ unsigned char col_hi[3], col_lo[3];
+
+ gpuPushMatrix();
+ gpuLoadIdentity();
+ gpuLoadProjectionMatrix(m);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+
+ UI_GetThemeColor3ubv(TH_LOW_GRAD, col_lo);
+ UI_GetThemeColor3ubv(TH_HIGH_GRAD, col_hi);
+
+ immBegin(GWN_PRIM_TRI_FAN, 4);
+ immAttrib3ubv(color, col_lo);
+ immVertex2f(pos, -1.0f, -1.0f);
+ immVertex2f(pos, 1.0f, -1.0f);
+
+ immAttrib3ubv(color, col_hi);
+ immVertex2f(pos, 1.0f, 1.0f);
+ immVertex2f(pos, -1.0f, 1.0f);
+ immEnd();
+
+ immUnbindProgram();
+
+ gpuPopMatrix();
+
+ 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(Scene *scene, SceneLayer *sl)
+{
+ Object *ob = OBACT_NEW;
+
+ /* 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, sl);
+
+ 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;
+}
+
+void DRW_draw_cursor(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ Scene *scene = draw_ctx->scene;
+ SceneLayer *sl = draw_ctx->scene_layer;
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDepthMask(GL_FALSE);
+ glDisable(GL_DEPTH_TEST);
+ glLineWidth(1.0f);
+
+ if (is_cursor_visible(scene, sl)) {
+ float *co = ED_view3d_cursor3d_get(scene, v3d);
+ unsigned char crosshair_color[3];
+
+ const float f5 = 0.25f;
+ const float f10 = 0.5f;
+ const float f20 = 1.0f;
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ unsigned int wpos = GWN_vertformat_attr_add(format, "world_pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ /* XXX Using instance shader without instance */
+ immBindBuiltinProgram(GPU_SHADER_3D_SCREENSPACE_VARIYING_COLOR);
+ immUniform1f("size", U.widget_unit);
+ immUniform1f("pixel_size", *DRW_viewport_pixelsize_get());
+ immUniformArray3fv("screen_vecs", DRW_viewport_screenvecs_get(), 2);
+ immUniformMatrix4fv("ViewProjectionMatrix", rv3d->persmat);
+
+ const int segments = 16;
+
+ immBegin(GWN_PRIM_LINE_LOOP, segments);
+ immAttrib3fv(wpos, co);
+
+ for (int i = 0; i < segments; ++i) {
+ float angle = 2 * M_PI * ((float)i / (float)segments);
+ float x = f10 * cosf(angle);
+ float y = f10 * sinf(angle);
+
+ if (i % 2 == 0)
+ immAttrib3ub(color, 255, 0, 0);
+ else
+ immAttrib3ub(color, 255, 255, 255);
+
+ immVertex2f(pos, x, y);
+ }
+ immEnd();
+
+ UI_GetThemeColor3ubv(TH_VIEW_OVERLAY, crosshair_color);
+
+ immBegin(GWN_PRIM_LINES, 8);
+ immAttrib3ubv(color, crosshair_color);
+ immAttrib3fv(wpos, co);
+
+ immVertex2f(pos, -f20, 0);
+ immVertex2f(pos, -f5, 0);
+ immVertex2f(pos, +f5, 0);
+ immVertex2f(pos, +f20, 0);
+ immVertex2f(pos, 0, -f20);
+ immVertex2f(pos, 0, -f5);
+ immVertex2f(pos, 0, +f5);
+ immVertex2f(pos, 0, +f20);
+ immEnd();
+
+ immUnbindProgram();
+ }
+}
+
+/* **************************** 3D Manipulator ******************************** */
+
+void DRW_draw_manipulator(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ v3d->zbuf = false;
+ ARegion *ar = draw_ctx->ar;
+
+
+ /* TODO, only draws 3D manipulators right now, need to see how 2D drawing will work in new viewport */
+
+ /* draw depth culled manipulators - manipulators need to be updated *after* view matrix was set up */
+ /* TODO depth culling manipulators is not yet supported, just drawing _3D here, should
+ * later become _IN_SCENE (and draw _3D separate) */
+ WM_manipulatormap_draw(ar->manipulator_map, draw_ctx->evil_C, WM_MANIPULATORMAP_DRAWSTEP_3D);
+}
diff --git a/source/blender/draw/intern/draw_view.h b/source/blender/draw/intern/draw_view.h
new file mode 100644
index 00000000000..b400ceeffa2
--- /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_grid(void);
+void DRW_draw_region_info(void);
+void DRW_draw_background(void);
+void DRW_draw_cursor(void);
+void DRW_draw_manipulator(void);
+
+#endif /* __DRAW_VIEW_H__ */ \ No newline at end of file
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..23fedbba5a5
--- /dev/null
+++ b/source/blender/draw/modes/draw_mode_engines.h
@@ -0,0 +1,44 @@
+/*
+ * 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_surface_type;
+extern DrawEngineType draw_engine_edit_text_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;
+
+#endif /* __DRAW_MODE_ENGINES_H__ */ \ No newline at end of file
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..61a56dab244
--- /dev/null
+++ b/source/blender/draw/modes/edit_armature_mode.c
@@ -0,0 +1,151 @@
+/*
+ * 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 "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+extern GlobalsUboStorage ts;
+
+/* *********** LISTS *********** */
+typedef struct EDIT_ARMATURE_PassList {
+ struct DRWPass *bone_solid;
+ struct DRWPass *bone_wire;
+ struct DRWPass *bone_envelope;
+ struct DRWPass *relationship;
+} 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 {
+ DRWShadingGroup *relationship_lines;
+} 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;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ {
+ /* Solid bones */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS;
+ psl->bone_solid = DRW_pass_create("Bone Solid Pass", state);
+ }
+
+ {
+ /* Wire bones */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND;
+ psl->bone_wire = DRW_pass_create("Bone Wire Pass", state);
+ }
+
+ {
+ /* distance outline around envelope bones */
+ DRWState state = DRW_STATE_ADDITIVE | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND;
+ psl->bone_envelope = DRW_pass_create("Bone Envelope Outline Pass", state);
+ }
+
+ {
+ /* Non Meshes Pass (Camera, empties, lamps ...) */
+ DRWState state =
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS |
+ DRW_STATE_BLEND | DRW_STATE_WIRE;
+ psl->relationship = DRW_pass_create("Bone Relationship Pass", state);
+
+ /* Relationship Lines */
+ stl->g_data->relationship_lines = shgroup_dynlines_uniform_color(psl->relationship, ts.colorWire);
+ DRW_shgroup_state_enable(stl->g_data->relationship_lines, DRW_STATE_STIPPLE_3);
+ }
+}
+
+static void EDIT_ARMATURE_cache_populate(void *vedata, Object *ob)
+{
+ bArmature *arm = ob->data;
+ EDIT_ARMATURE_PassList *psl = ((EDIT_ARMATURE_Data *)vedata)->psl;
+ EDIT_ARMATURE_StorageList *stl = ((EDIT_ARMATURE_Data *)vedata)->stl;
+
+ if (ob->type == OB_ARMATURE) {
+ if (arm->edbo) {
+ DRW_shgroup_armature_edit(
+ ob, psl->bone_solid, psl->bone_wire, psl->bone_envelope, stl->g_data->relationship_lines);
+ }
+ }
+}
+
+static void EDIT_ARMATURE_draw_scene(void *vedata)
+{
+ EDIT_ARMATURE_PassList *psl = ((EDIT_ARMATURE_Data *)vedata)->psl;
+
+ DRW_draw_pass(psl->bone_envelope);
+ DRW_draw_pass(psl->bone_solid);
+ DRW_draw_pass(psl->bone_wire);
+ DRW_draw_pass(psl->relationship);
+}
+
+#if 0
+void EDIT_ARMATURE_collection_settings_create(CollectionEngineSettings *ces)
+{
+ BLI_assert(ces);
+ //BKE_collection_engine_property_add_int(ces, "show_occlude_wire", false);
+}
+#endif
+
+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
+};
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..dc81725d19a
--- /dev/null
+++ b/source/blender/draw/modes/edit_curve_mode.c
@@ -0,0 +1,329 @@
+/*
+ * 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"
+
+/* 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_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_CURVE_engine_init() to
+ * initialize most of them and EDIT_CURVE_cache_init()
+ * for EDIT_CURVE_PassList */
+
+typedef struct EDIT_CURVE_PassList {
+ /* Declare all passes here and init them in
+ * EDIT_CURVE_cache_init().
+ * Only contains (DRWPass *) */
+ struct DRWPass *wire_pass;
+ struct DRWPass *overlay_edge_pass;
+ struct DRWPass *overlay_vert_pass;
+} EDIT_CURVE_PassList;
+
+typedef struct EDIT_CURVE_FramebufferList {
+ /* Contains all framebuffer objects needed by this engine.
+ * Only contains (GPUFrameBuffer *) */
+ struct GPUFrameBuffer *fb;
+} EDIT_CURVE_FramebufferList;
+
+typedef struct EDIT_CURVE_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_CURVE_TextureList;
+
+typedef struct EDIT_CURVE_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_CURVE_PrivateData *g_data;
+} EDIT_CURVE_StorageList;
+
+typedef struct EDIT_CURVE_Data {
+ /* Struct returned by DRW_viewport_engine_data_get.
+ * If you don't use one of these, just make it a (void *) */
+ // void *fbl;
+ void *engine_type; /* Required */
+ EDIT_CURVE_FramebufferList *fbl;
+ EDIT_CURVE_TextureList *txl;
+ EDIT_CURVE_PassList *psl;
+ EDIT_CURVE_StorageList *stl;
+} EDIT_CURVE_Data;
+
+/* *********** STATIC *********** */
+
+static struct {
+ /* Custom shaders :
+ * Add sources to source/blender/draw/modes/shaders
+ * init in EDIT_CURVE_engine_init();
+ * free in EDIT_CURVE_engine_free(); */
+
+ 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 {
+ /* This keeps the references of the shading groups for
+ * easy access in EDIT_CURVE_cache_populate() */
+
+ /* resulting curve as 'wire' for curves (and optionally normals) */
+ DRWShadingGroup *wire_shgrp;
+
+ DRWShadingGroup *overlay_edge_shgrp;
+ DRWShadingGroup *overlay_vert_shgrp;
+} 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 *vedata)
+{
+ EDIT_CURVE_TextureList *txl = ((EDIT_CURVE_Data *)vedata)->txl;
+ EDIT_CURVE_FramebufferList *fbl = ((EDIT_CURVE_Data *)vedata)->fbl;
+ EDIT_CURVE_StorageList *stl = ((EDIT_CURVE_Data *)vedata)->stl;
+
+ UNUSED_VARS(txl, fbl, stl);
+
+ /* Init Framebuffers like this: order is attachment order (for color texs) */
+ /*
+ * DRWFboTexture tex[2] = {{&txl->depth, DRW_TEX_DEPTH_24, 0},
+ * {&txl->color, DRW_TEX_RGBA_8, 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_edge_sh) {
+ e_data.overlay_edge_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+
+ 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_edit_curve_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_CURVE_cache_init(void *vedata)
+{
+ EDIT_CURVE_PassList *psl = ((EDIT_CURVE_Data *)vedata)->psl;
+ EDIT_CURVE_StorageList *stl = ((EDIT_CURVE_Data *)vedata)->stl;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ {
+ /* Center-Line (wire) */
+ psl->wire_pass = DRW_pass_create(
+ "Curve Wire",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_WIRE);
+ stl->g_data->wire_shgrp = DRW_shgroup_create(e_data.wire_sh, psl->wire_pass);
+
+
+ /* TODO: following handle theme colors,
+ * For now use overlay vert shader for handles (we want them colored):
+ * TH_NURB_ULINE, TH_NURB_SEL_ULINE, TH_HANDLE_* */
+ psl->overlay_edge_pass = DRW_pass_create(
+ "Curve Handle Overlay",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_WIRE);
+ /* TODO: following handle theme colors,
+ * For now use overlay vert shader for handles (we want them colored) */
+ stl->g_data->overlay_edge_shgrp = DRW_shgroup_create(e_data.overlay_vert_sh, psl->overlay_edge_pass);
+
+ psl->overlay_vert_pass = DRW_pass_create(
+ "Curve Vert Overlay",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_POINT);
+ stl->g_data->overlay_vert_shgrp = DRW_shgroup_create(e_data.overlay_vert_sh, psl->overlay_vert_pass);
+ }
+
+}
+
+/* Add geometry to shadingGroups. Execute for each objects */
+static void EDIT_CURVE_cache_populate(void *vedata, Object *ob)
+{
+ 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();
+ const Scene *scene = draw_ctx->scene;
+ const Object *obedit = scene->obedit;
+
+ UNUSED_VARS(psl, stl);
+
+ if (ob->type == OB_CURVE) {
+ if (ob == obedit) {
+ Curve *cu = ob->data;
+ /* Get geometry cache */
+ struct Gwn_Batch *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) && (cu->drawflag & CU_HIDE_NORMALS) == 0) {
+ geom = DRW_cache_curve_edge_normal_get(ob, scene->toolsettings->normalsize);
+ DRW_shgroup_call_add(stl->g_data->wire_shgrp, geom, ob->obmat);
+ }
+
+ /* Add geom to a shading group */
+ 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);
+ DRW_shgroup_call_add(stl->g_data->overlay_vert_shgrp, geom, ob->obmat);
+ }
+ }
+}
+
+/* Optional: Post-cache_populate callback */
+static void EDIT_CURVE_cache_finish(void *vedata)
+{
+ EDIT_CURVE_PassList *psl = ((EDIT_CURVE_Data *)vedata)->psl;
+ EDIT_CURVE_StorageList *stl = ((EDIT_CURVE_Data *)vedata)->stl;
+
+ /* Do something here! dependant on the objects gathered */
+ UNUSED_VARS(psl, stl);
+}
+
+/* Draw time ! Control rendering pipeline from here */
+static void EDIT_CURVE_draw_scene(void *vedata)
+{
+ EDIT_CURVE_PassList *psl = ((EDIT_CURVE_Data *)vedata)->psl;
+ EDIT_CURVE_FramebufferList *fbl = ((EDIT_CURVE_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->wire_pass);
+ DRW_draw_pass(psl->overlay_edge_pass);
+ DRW_draw_pass(psl->overlay_vert_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_CURVE_engine_free(void)
+{
+ // DRW_SHADER_FREE_SAFE(custom_shader);
+}
+
+/* Create collection settings here.
+ *
+ * Be sure to add this function there :
+ * source/blender/draw/DRW_engine.h
+ * source/blender/blenkernel/intern/layer.c
+ * source/blenderplayer/bad_level_call_stubs/stubs.c
+ *
+ * And relevant collection settings to :
+ * source/blender/makesrna/intern/rna_scene.c
+ * source/blender/blenkernel/intern/layer.c
+ */
+#if 0
+void EDIT_CURVE_collection_settings_create(CollectionEngineSettings *ces)
+{
+ BLI_assert(ces);
+ // BKE_collection_engine_property_add_int(ces, "my_bool_prop", false);
+ // BKE_collection_engine_property_add_int(ces, "my_int_prop", 0);
+ // BKE_collection_engine_property_add_float(ces, "my_float_prop", 0.0f);
+}
+#endif
+
+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,
+ &EDIT_CURVE_cache_finish,
+ NULL, /* draw_background but not needed by mode engines */
+ &EDIT_CURVE_draw_scene
+};
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..722010148ff
--- /dev/null
+++ b/source/blender/draw/modes/edit_lattice_mode.c
@@ -0,0 +1,292 @@
+/*
+ * 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"
+
+/* 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_get.
+ * 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, DRW_TEX_DEPTH_24, 0},
+ * {&txl->color, DRW_TEX_RGBA_8, 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 | 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();
+ Scene *scene = draw_ctx->scene;
+ Object *obedit = scene->obedit;
+
+ UNUSED_VARS(psl);
+
+ if (ob->type == OB_LATTICE) {
+ if (ob == obedit) {
+ /* Get geometry cache */
+ struct Gwn_Batch *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! dependant 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, 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);
+
+ /* 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);
+}
+
+/* Create collection settings here.
+ *
+ * Be sure to add this function there :
+ * source/blender/draw/DRW_engine.h
+ * source/blender/blenkernel/intern/layer.c
+ * source/blenderplayer/bad_level_call_stubs/stubs.c
+ *
+ * And relevant collection settings to :
+ * source/blender/makesrna/intern/rna_scene.c
+ * source/blender/blenkernel/intern/layer.c
+ */
+#if 0
+void EDIT_LATTICE_collection_settings_create(CollectionEngineSettings *ces)
+{
+ BLI_assert(ces);
+ // BKE_collection_engine_property_add_int(ces, "my_bool_prop", false);
+ // BKE_collection_engine_property_add_int(ces, "my_int_prop", 0);
+ // BKE_collection_engine_property_add_float(ces, "my_float_prop", 0.0f);
+}
+#endif
+
+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
+};
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..c06a2976ac7
--- /dev/null
+++ b/source/blender/draw/modes/edit_mesh_mode.c
@@ -0,0 +1,584 @@
+/*
+ * 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_view3d_types.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+extern struct GlobalsUboStorage ts; /* draw_common.c */
+
+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_loosevert_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_mix_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[];
+
+/* *********** LISTS *********** */
+typedef struct EDIT_MESH_PassList {
+ struct DRWPass *vcolor_faces;
+ struct DRWPass *depth_hidden_wire;
+ 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;
+} 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 *********** */
+
+static struct {
+ /* weight/vert-color */
+ GPUShader *vcolor_face_shader;
+ GPUShader *overlay_tri_sh;
+ GPUShader *overlay_tri_fast_sh;
+ GPUShader *overlay_tri_vcol_sh;
+ GPUShader *overlay_tri_vcol_fast_sh;
+ GPUShader *overlay_edge_sh;
+ GPUShader *overlay_edge_vcol_sh;
+ GPUShader *overlay_vert_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;
+ /* 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/vert-color */
+ DRWShadingGroup *fvcolor_shgrp;
+ DRWShadingGroup *depth_shgrp_hidden_wire;
+
+ DRWShadingGroup *fnormals_shgrp;
+ DRWShadingGroup *vnormals_shgrp;
+ DRWShadingGroup *lnormals_shgrp;
+
+ DRWShadingGroup *face_overlay_shgrp;
+ DRWShadingGroup *ledges_overlay_shgrp;
+ DRWShadingGroup *lverts_overlay_shgrp;
+ DRWShadingGroup *facedot_overlay_shgrp;
+
+ DRWShadingGroup *face_occluded_shgrp;
+ DRWShadingGroup *ledges_occluded_shgrp;
+ DRWShadingGroup *lverts_occluded_shgrp;
+ DRWShadingGroup *facedot_occluded_shgrp;
+ DRWShadingGroup *facefill_occluded_shgrp;
+
+} EDIT_MESH_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+
+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();
+
+ DRWFboTexture tex[2] = {{
+ &e_data.occlude_wire_depth_tx, DRW_TEX_DEPTH_24, DRW_TEX_TEMP},
+ {&e_data.occlude_wire_color_tx, DRW_TEX_RGBA_8, DRW_TEX_FILTER | DRW_TEX_TEMP}
+ };
+ DRW_framebuffer_init(
+ &fbl->occlude_wire_fb, &draw_engine_edit_mesh_type,
+ (int)viewport_size[0], (int)viewport_size[1],
+ tex, ARRAY_SIZE(tex));
+
+ if (!e_data.vcolor_face_shader) {
+ e_data.vcolor_face_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR_ALPHA);
+ }
+
+ if (!e_data.overlay_tri_sh) {
+ e_data.overlay_tri_sh = DRW_shader_create_with_lib(
+ datatoc_edit_mesh_overlay_vert_glsl,
+ datatoc_edit_mesh_overlay_geom_tri_glsl,
+ datatoc_edit_mesh_overlay_frag_glsl,
+ datatoc_common_globals_lib_glsl, "#define EDGE_FIX\n");
+ }
+ if (!e_data.overlay_tri_fast_sh) {
+ e_data.overlay_tri_fast_sh = DRW_shader_create_with_lib(
+ datatoc_edit_mesh_overlay_vert_glsl,
+ datatoc_edit_mesh_overlay_geom_tri_glsl,
+ datatoc_edit_mesh_overlay_frag_glsl,
+ datatoc_common_globals_lib_glsl, NULL);
+ }
+ if (!e_data.overlay_tri_vcol_sh) {
+ e_data.overlay_tri_vcol_sh = DRW_shader_create_with_lib(
+ datatoc_edit_mesh_overlay_vert_glsl,
+ datatoc_edit_mesh_overlay_geom_tri_glsl,
+ datatoc_edit_mesh_overlay_frag_glsl,
+ datatoc_common_globals_lib_glsl,
+ "#define EDGE_FIX\n"
+ "#define VERTEX_SELECTION\n");
+ }
+ if (!e_data.overlay_tri_vcol_fast_sh) {
+ e_data.overlay_tri_vcol_fast_sh = DRW_shader_create_with_lib(
+ datatoc_edit_mesh_overlay_vert_glsl,
+ datatoc_edit_mesh_overlay_geom_tri_glsl,
+ datatoc_edit_mesh_overlay_frag_glsl,
+ datatoc_common_globals_lib_glsl,
+ "#define VERTEX_SELECTION\n");
+ }
+ if (!e_data.overlay_edge_sh) {
+ e_data.overlay_edge_sh = DRW_shader_create_with_lib(
+ datatoc_edit_mesh_overlay_vert_glsl,
+ datatoc_edit_mesh_overlay_geom_edge_glsl,
+ datatoc_edit_mesh_overlay_frag_glsl,
+ datatoc_common_globals_lib_glsl, NULL);
+ }
+ if (!e_data.overlay_edge_vcol_sh) {
+ e_data.overlay_edge_vcol_sh = DRW_shader_create_with_lib(
+ datatoc_edit_mesh_overlay_vert_glsl,
+ datatoc_edit_mesh_overlay_geom_edge_glsl,
+ datatoc_edit_mesh_overlay_frag_glsl,
+ datatoc_common_globals_lib_glsl,
+ "#define VERTEX_SELECTION\n");
+ }
+ if (!e_data.overlay_vert_sh) {
+ e_data.overlay_vert_sh = DRW_shader_create_with_lib(
+ datatoc_edit_mesh_overlay_loosevert_vert_glsl, NULL,
+ datatoc_edit_mesh_overlay_frag_glsl,
+ datatoc_common_globals_lib_glsl,
+ "#define VERTEX_SELECTION\n");
+ }
+ 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, NULL);
+ }
+ 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();
+ }
+}
+
+static DRWPass *edit_mesh_create_overlay_pass(
+ float *faceAlpha, DRWState statemod,
+ DRWShadingGroup **r_face_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;
+
+ if ((tsettings->selectmode & SCE_SELECT_VERTEX) != 0) {
+ ledge_sh = e_data.overlay_edge_vcol_sh;
+
+ if ((rv3d->rflag & RV3D_NAVIGATING) != 0)
+ tri_sh = e_data.overlay_tri_vcol_fast_sh;
+ else
+ tri_sh = e_data.overlay_tri_vcol_sh;
+ }
+ else {
+ ledge_sh = e_data.overlay_edge_sh;
+
+ if ((rv3d->rflag & RV3D_NAVIGATING) != 0)
+ tri_sh = e_data.overlay_tri_fast_sh;
+ else
+ tri_sh = e_data.overlay_tri_sh;
+ }
+
+ DRWPass *pass = DRW_pass_create(
+ "Edit Mesh Face Overlay Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_POINT | statemod);
+
+ *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", faceAlpha, 1);
+
+ *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);
+
+ if ((tsettings->selectmode & (SCE_SELECT_VERTEX)) != 0) {
+ *r_lverts_shgrp = DRW_shgroup_create(e_data.overlay_vert_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);
+ }
+
+ 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);
+ }
+
+ 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;
+
+ bool do_zbufclip = ((v3d->flag & V3D_ZBUF_SELECT) == 0);
+
+ static float zero = 0.0f;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ {
+ psl->vcolor_faces = DRW_pass_create(
+ "Vert Color Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
+
+ stl->g_data->fvcolor_shgrp = DRW_shgroup_create(e_data.vcolor_face_shader, psl->vcolor_faces);
+
+ static float light[3] = {-0.3f, 0.5f, 1.0f};
+ static float alpha = 1.0f;
+ static float world_light = 1.0f; /* XXX, see: paint_vertex_mode.c */
+ DRW_shgroup_uniform_vec3(stl->g_data->fvcolor_shgrp, "light", light, 1);
+ DRW_shgroup_uniform_float(stl->g_data->fvcolor_shgrp, "alpha", &alpha, 1);
+ DRW_shgroup_uniform_float(stl->g_data->fvcolor_shgrp, "global", &world_light, 1);
+ }
+
+ {
+ /* Complementary Depth Pass */
+ psl->depth_hidden_wire = DRW_pass_create(
+ "Depth Pass Hidden Wire",
+ DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_CULL_BACK);
+ stl->g_data->depth_shgrp_hidden_wire = DRW_shgroup_create(e_data.depth_sh, psl->depth_hidden_wire);
+ }
+
+ {
+ /* Normals */
+ psl->normals = DRW_pass_create(
+ "Edit Mesh Normals Pass",
+ DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS);
+
+ 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 (!do_zbufclip) {
+ psl->edit_face_overlay = edit_mesh_create_overlay_pass(
+ &face_mod, DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_DEPTH | DRW_STATE_BLEND,
+ &stl->g_data->face_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, DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_DEPTH,
+ &stl->g_data->face_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 | 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);
+
+ /* we need a full screen pass to combine the result */
+ struct Gwn_Batch *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_buffer(mix_shgrp, "wireColor", &e_data.occlude_wire_color_tx);
+ DRW_shgroup_uniform_buffer(mix_shgrp, "wireDepth", &e_data.occlude_wire_depth_tx);
+ DRW_shgroup_uniform_buffer(mix_shgrp, "sceneDepth", &dtxl->depth);
+ }
+}
+
+static void edit_mesh_add_ob_to_pass(
+ Scene *scene, Object *ob, DRWShadingGroup *face_shgrp, DRWShadingGroup *ledges_shgrp,
+ DRWShadingGroup *lverts_shgrp, DRWShadingGroup *facedot_shgrp, DRWShadingGroup *facefill_shgrp)
+{
+ struct Gwn_Batch *geo_ovl_tris, *geo_ovl_ledges, *geo_ovl_lverts, *geo_ovl_fcenter;
+ ToolSettings *tsettings = scene->toolsettings;
+
+ DRW_cache_mesh_wire_overlay_get(ob, &geo_ovl_tris, &geo_ovl_ledges, &geo_ovl_lverts);
+ 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) {
+ DRW_shgroup_call_add(lverts_shgrp, geo_ovl_lverts, ob->obmat);
+ }
+
+ if ((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;
+ Object *obedit = scene->obedit;
+ struct Gwn_Batch *geom;
+
+ if (ob->type == OB_MESH) {
+ if (ob == obedit) {
+ IDProperty *ces_mode_ed = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_EDIT, "");
+ bool do_occlude_wire = BKE_collection_engine_property_value_get_bool(ces_mode_ed, "show_occlude_wire");
+ bool do_show_weight = BKE_collection_engine_property_value_get_bool(ces_mode_ed, "show_weight");
+
+ /* Updating uniform */
+ backwire_opacity = BKE_collection_engine_property_value_get_float(ces_mode_ed, "backwire_opacity");
+
+ bool fnormals_do = BKE_collection_engine_property_value_get_bool(ces_mode_ed, "face_normals_show");
+ bool vnormals_do = BKE_collection_engine_property_value_get_bool(ces_mode_ed, "vert_normals_show");
+ bool lnormals_do = BKE_collection_engine_property_value_get_bool(ces_mode_ed, "loop_normals_show");
+ /* Updating uniform */
+ size_normal = BKE_collection_engine_property_value_get_float(ces_mode_ed, "normals_length");
+
+ face_mod = (do_occlude_wire) ? 0.0f : 1.0f;
+
+ if (do_show_weight) {
+ geom = DRW_cache_mesh_surface_weights_get(ob);
+ DRW_shgroup_call_add(stl->g_data->fvcolor_shgrp, geom, ob->obmat);
+ }
+
+ if (do_occlude_wire) {
+ geom = DRW_cache_mesh_surface_get(ob);
+ 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 Gwn_Batch *geo_ovl_tris, *geo_ovl_ledges, *geo_ovl_lverts;
+ DRW_cache_mesh_normals_overlay_get(ob, &geo_ovl_tris, &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_tris, ob->obmat);
+ }
+ }
+
+ if ((v3d->flag & V3D_ZBUF_SELECT) == 0) {
+ edit_mesh_add_ob_to_pass(
+ scene, ob, stl->g_data->face_occluded_shgrp, stl->g_data->ledges_occluded_shgrp,
+ stl->g_data->lverts_occluded_shgrp, stl->g_data->facedot_occluded_shgrp,
+ stl->g_data->facefill_occluded_shgrp);
+ }
+ else {
+ edit_mesh_add_ob_to_pass(
+ scene, ob, stl->g_data->face_overlay_shgrp, stl->g_data->ledges_overlay_shgrp,
+ stl->g_data->lverts_overlay_shgrp, stl->g_data->facedot_overlay_shgrp, NULL);
+ }
+ }
+ }
+}
+
+static void EDIT_MESH_draw_scene(void *vedata)
+{
+ EDIT_MESH_PassList *psl = ((EDIT_MESH_Data *)vedata)->psl;
+ 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->vcolor_faces);
+
+ DRW_draw_pass(psl->depth_hidden_wire);
+
+ if (psl->edit_face_occluded) {
+ float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ /* render facefill */
+ DRW_draw_pass(psl->facefill_occlude);
+
+ /* attach temp textures */
+ DRW_framebuffer_texture_attach(fbl->occlude_wire_fb, e_data.occlude_wire_depth_tx, 0, 0);
+ DRW_framebuffer_texture_attach(fbl->occlude_wire_fb, e_data.occlude_wire_color_tx, 0, 0);
+
+ /* Render wires on a separate framebuffer */
+ DRW_framebuffer_bind(fbl->occlude_wire_fb);
+ DRW_framebuffer_clear(true, true, false, clearcol, 1.0f);
+ DRW_draw_pass(psl->normals);
+ DRW_draw_pass(psl->edit_face_occluded);
+
+ /* detach textures */
+ DRW_framebuffer_texture_detach(dtxl->depth);
+
+ /* Combine with scene buffer */
+ DRW_framebuffer_bind(dfbl->default_fb);
+ DRW_draw_pass(psl->mix_occlude);
+
+ /* detach temp textures */
+ DRW_framebuffer_texture_detach(e_data.occlude_wire_depth_tx);
+ DRW_framebuffer_texture_detach(e_data.occlude_wire_color_tx);
+
+ /* reattach */
+ DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0);
+ }
+ else {
+ DRW_draw_pass(psl->normals);
+ DRW_draw_pass(psl->edit_face_overlay);
+ }
+}
+
+void EDIT_MESH_collection_settings_create(IDProperty *properties)
+{
+ BLI_assert(properties &&
+ properties->type == IDP_GROUP &&
+ properties->subtype == IDP_GROUP_SUB_MODE_EDIT);
+ BKE_collection_engine_property_add_int(properties, "show_occlude_wire", false);
+ BKE_collection_engine_property_add_int(properties, "show_weight", false);
+ BKE_collection_engine_property_add_int(properties, "face_normals_show", false);
+ BKE_collection_engine_property_add_int(properties, "vert_normals_show", false);
+ BKE_collection_engine_property_add_int(properties, "loop_normals_show", false);
+ BKE_collection_engine_property_add_float(properties, "normals_length", 0.1);
+ BKE_collection_engine_property_add_float(properties, "backwire_opacity", 0.5);
+}
+
+static void EDIT_MESH_engine_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.overlay_tri_sh);
+ DRW_SHADER_FREE_SAFE(e_data.overlay_tri_fast_sh);
+ DRW_SHADER_FREE_SAFE(e_data.overlay_tri_vcol_sh);
+ DRW_SHADER_FREE_SAFE(e_data.overlay_tri_vcol_fast_sh);
+ DRW_SHADER_FREE_SAFE(e_data.overlay_edge_sh);
+ DRW_SHADER_FREE_SAFE(e_data.overlay_edge_vcol_sh);
+ DRW_SHADER_FREE_SAFE(e_data.overlay_vert_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);
+}
+
+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
+};
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..4e9e1cb5b56
--- /dev/null
+++ b/source/blender/draw/modes/edit_metaball_mode.c
@@ -0,0 +1,268 @@
+/*
+ * 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"
+
+/* 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 */
+
+/* *********** 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_get.
+ * 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 *********** */
+
+static struct {
+ /* Custom shaders :
+ * Add sources to source/blender/draw/modes/shaders
+ * init in EDIT_METABALL_engine_init();
+ * free in EDIT_METABALL_engine_free(); */
+ struct GPUShader *custom_shader;
+} e_data = {NULL}; /* Engine data */
+
+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 *********** */
+
+/* Init Textures, Framebuffers, Storage and Shaders.
+ * It is called for every frames.
+ * (Optional) */
+static void EDIT_METABALL_engine_init(void *vedata)
+{
+ EDIT_METABALL_TextureList *txl = ((EDIT_METABALL_Data *)vedata)->txl;
+ EDIT_METABALL_FramebufferList *fbl = ((EDIT_METABALL_Data *)vedata)->fbl;
+ EDIT_METABALL_StorageList *stl = ((EDIT_METABALL_Data *)vedata)->stl;
+
+ UNUSED_VARS(txl, fbl, stl);
+
+ /* Init Framebuffers like this: order is attachment order (for color texs) */
+ /*
+ * DRWFboTexture tex[2] = {{&txl->depth, DRW_TEX_DEPTH_24, 0},
+ * {&txl->color, DRW_TEX_RGBA_8, 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.custom_shader) {
+ e_data.custom_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 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 | 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_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 = DRW_shgroup_create(e_data.custom_shader, psl->pass);
+
+ /* 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] = {0.0f, 1.0f, 0.0f, 1.0};
+ DRW_shgroup_uniform_vec4(stl->g_data->group, "color", color, 1);
+ }
+
+}
+
+/* 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;
+
+ UNUSED_VARS(psl, stl);
+
+ if (ob->type == OB_MESH) {
+ /* Get geometry cache */
+ struct Gwn_Batch *geom = DRW_cache_mesh_surface_get(ob);
+
+ /* Add geom to a shading group */
+ DRW_shgroup_call_add(stl->g_data->group, geom, ob->obmat);
+ }
+}
+
+/* Optional: Post-cache_populate callback */
+static void EDIT_METABALL_cache_finish(void *vedata)
+{
+ EDIT_METABALL_PassList *psl = ((EDIT_METABALL_Data *)vedata)->psl;
+ EDIT_METABALL_StorageList *stl = ((EDIT_METABALL_Data *)vedata)->stl;
+
+ /* Do something here! dependant on the objects gathered */
+ UNUSED_VARS(psl, stl);
+}
+
+/* Draw time ! Control rendering pipeline from here */
+static void EDIT_METABALL_draw_scene(void *vedata)
+{
+ EDIT_METABALL_PassList *psl = ((EDIT_METABALL_Data *)vedata)->psl;
+ EDIT_METABALL_FramebufferList *fbl = ((EDIT_METABALL_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 EDIT_METABALL_engine_free(void)
+{
+ // DRW_SHADER_FREE_SAFE(custom_shader);
+}
+
+/* Create collection settings here.
+ *
+ * Be sure to add this function there :
+ * source/blender/draw/DRW_engine.h
+ * source/blender/blenkernel/intern/layer.c
+ * source/blenderplayer/bad_level_call_stubs/stubs.c
+ *
+ * And relevant collection settings to :
+ * source/blender/makesrna/intern/rna_scene.c
+ * source/blender/blenkernel/intern/layer.c
+ */
+#if 0
+void EDIT_METABALL_collection_settings_create(CollectionEngineSettings *ces)
+{
+ BLI_assert(ces);
+ // BKE_collection_engine_property_add_int(ces, "my_bool_prop", false);
+ // BKE_collection_engine_property_add_int(ces, "my_int_prop", 0);
+ // BKE_collection_engine_property_add_float(ces, "my_float_prop", 0.0f);
+}
+#endif
+
+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,
+ &EDIT_METABALL_engine_init,
+ &EDIT_METABALL_engine_free,
+ &EDIT_METABALL_cache_init,
+ &EDIT_METABALL_cache_populate,
+ &EDIT_METABALL_cache_finish,
+ NULL, /* draw_background but not needed by mode engines */
+ &EDIT_METABALL_draw_scene
+};
diff --git a/source/blender/draw/modes/edit_surface_mode.c b/source/blender/draw/modes/edit_surface_mode.c
new file mode 100644
index 00000000000..c8dbbd90754
--- /dev/null
+++ b/source/blender/draw/modes/edit_surface_mode.c
@@ -0,0 +1,268 @@
+/*
+ * 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_surface_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"
+
+/* 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_SURFACE_engine_init() to
+ * initialize most of them and EDIT_SURFACE_cache_init()
+ * for EDIT_SURFACE_PassList */
+
+typedef struct EDIT_SURFACE_PassList {
+ /* Declare all passes here and init them in
+ * EDIT_SURFACE_cache_init().
+ * Only contains (DRWPass *) */
+ struct DRWPass *pass;
+} EDIT_SURFACE_PassList;
+
+typedef struct EDIT_SURFACE_FramebufferList {
+ /* Contains all framebuffer objects needed by this engine.
+ * Only contains (GPUFrameBuffer *) */
+ struct GPUFrameBuffer *fb;
+} EDIT_SURFACE_FramebufferList;
+
+typedef struct EDIT_SURFACE_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_SURFACE_TextureList;
+
+typedef struct EDIT_SURFACE_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_SURFACE_PrivateData *g_data;
+} EDIT_SURFACE_StorageList;
+
+typedef struct EDIT_SURFACE_Data {
+ /* Struct returned by DRW_viewport_engine_data_get.
+ * If you don't use one of these, just make it a (void *) */
+ // void *fbl;
+ void *engine_type; /* Required */
+ EDIT_SURFACE_FramebufferList *fbl;
+ EDIT_SURFACE_TextureList *txl;
+ EDIT_SURFACE_PassList *psl;
+ EDIT_SURFACE_StorageList *stl;
+} EDIT_SURFACE_Data;
+
+/* *********** STATIC *********** */
+
+static struct {
+ /* Custom shaders :
+ * Add sources to source/blender/draw/modes/shaders
+ * init in EDIT_SURFACE_engine_init();
+ * free in EDIT_SURFACE_engine_free(); */
+ struct GPUShader *custom_shader;
+} e_data = {NULL}; /* Engine data */
+
+typedef struct EDIT_SURFACE_PrivateData {
+ /* This keeps the references of the shading groups for
+ * easy access in EDIT_SURFACE_cache_populate() */
+ DRWShadingGroup *group;
+} EDIT_SURFACE_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+
+/* Init Textures, Framebuffers, Storage and Shaders.
+ * It is called for every frames.
+ * (Optional) */
+static void EDIT_SURFACE_engine_init(void *vedata)
+{
+ EDIT_SURFACE_TextureList *txl = ((EDIT_SURFACE_Data *)vedata)->txl;
+ EDIT_SURFACE_FramebufferList *fbl = ((EDIT_SURFACE_Data *)vedata)->fbl;
+ EDIT_SURFACE_StorageList *stl = ((EDIT_SURFACE_Data *)vedata)->stl;
+
+ UNUSED_VARS(txl, fbl, stl);
+
+ /* Init Framebuffers like this: order is attachment order (for color texs) */
+ /*
+ * DRWFboTexture tex[2] = {{&txl->depth, DRW_TEX_DEPTH_24, 0},
+ * {&txl->color, DRW_TEX_RGBA_8, 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.custom_shader) {
+ e_data.custom_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 EDIT_SURFACE_cache_init(void *vedata)
+{
+ EDIT_SURFACE_PassList *psl = ((EDIT_SURFACE_Data *)vedata)->psl;
+ EDIT_SURFACE_StorageList *stl = ((EDIT_SURFACE_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 | 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_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 = DRW_shgroup_create(e_data.custom_shader, psl->pass);
+
+ /* 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] = {0.0f, 0.0f, 1.0f, 1.0};
+ DRW_shgroup_uniform_vec4(stl->g_data->group, "color", color, 1);
+ }
+
+}
+
+/* Add geometry to shadingGroups. Execute for each objects */
+static void EDIT_SURFACE_cache_populate(void *vedata, Object *ob)
+{
+ EDIT_SURFACE_PassList *psl = ((EDIT_SURFACE_Data *)vedata)->psl;
+ EDIT_SURFACE_StorageList *stl = ((EDIT_SURFACE_Data *)vedata)->stl;
+
+ UNUSED_VARS(psl, stl);
+
+ if (ob->type == OB_MESH) {
+ /* Get geometry cache */
+ struct Gwn_Batch *geom = DRW_cache_mesh_surface_get(ob);
+
+ /* Add geom to a shading group */
+ DRW_shgroup_call_add(stl->g_data->group, geom, ob->obmat);
+ }
+}
+
+/* Optional: Post-cache_populate callback */
+static void EDIT_SURFACE_cache_finish(void *vedata)
+{
+ EDIT_SURFACE_PassList *psl = ((EDIT_SURFACE_Data *)vedata)->psl;
+ EDIT_SURFACE_StorageList *stl = ((EDIT_SURFACE_Data *)vedata)->stl;
+
+ /* Do something here! dependant on the objects gathered */
+ UNUSED_VARS(psl, stl);
+}
+
+/* Draw time ! Control rendering pipeline from here */
+static void EDIT_SURFACE_draw_scene(void *vedata)
+{
+ EDIT_SURFACE_PassList *psl = ((EDIT_SURFACE_Data *)vedata)->psl;
+ EDIT_SURFACE_FramebufferList *fbl = ((EDIT_SURFACE_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 EDIT_SURFACE_engine_free(void)
+{
+ // DRW_SHADER_FREE_SAFE(custom_shader);
+}
+
+/* Create collection settings here.
+ *
+ * Be sure to add this function there :
+ * source/blender/draw/DRW_engine.h
+ * source/blender/blenkernel/intern/layer.c
+ * source/blenderplayer/bad_level_call_stubs/stubs.c
+ *
+ * And relevant collection settings to :
+ * source/blender/makesrna/intern/rna_scene.c
+ * source/blender/blenkernel/intern/layer.c
+ */
+#if 0
+void EDIT_SURFACE_collection_settings_create(CollectionEngineSettings *ces)
+{
+ BLI_assert(ces);
+ // BKE_collection_engine_property_add_int(ces, "my_bool_prop", false);
+ // BKE_collection_engine_property_add_int(ces, "my_int_prop", 0);
+ // BKE_collection_engine_property_add_float(ces, "my_float_prop", 0.0f);
+}
+#endif
+
+static const DrawEngineDataSize EDIT_SURFACE_data_size = DRW_VIEWPORT_DATA_SIZE(EDIT_SURFACE_Data);
+
+DrawEngineType draw_engine_edit_surface_type = {
+ NULL, NULL,
+ N_("EditSurfaceMode"),
+ &EDIT_SURFACE_data_size,
+ &EDIT_SURFACE_engine_init,
+ &EDIT_SURFACE_engine_free,
+ &EDIT_SURFACE_cache_init,
+ &EDIT_SURFACE_cache_populate,
+ &EDIT_SURFACE_cache_finish,
+ NULL, /* draw_background but not needed by mode engines */
+ &EDIT_SURFACE_draw_scene
+};
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..938ab2f3fbc
--- /dev/null
+++ b/source/blender/draw/modes/edit_text_mode.c
@@ -0,0 +1,311 @@
+/*
+ * 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;
+} 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_get.
+ * 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;
+} 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, DRW_TEX_DEPTH_24, 0},
+ * {&txl->color, DRW_TEX_RGBA_8, 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 | 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);
+ }
+}
+
+/* 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();
+ Scene *scene = draw_ctx->scene;
+ Object *obedit = scene->obedit;
+
+ UNUSED_VARS(psl, stl);
+
+ if (ob->type == OB_FONT) {
+ if (ob == obedit) {
+ const Curve *cu = ob->data;
+ /* Get geometry cache */
+ struct Gwn_Batch *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);
+ }
+ }
+ }
+}
+
+/* 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! dependant 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);
+
+ 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);
+}
+
+/* Create collection settings here.
+ *
+ * Be sure to add this function there :
+ * source/blender/draw/DRW_engine.h
+ * source/blender/blenkernel/intern/layer.c
+ * source/blenderplayer/bad_level_call_stubs/stubs.c
+ *
+ * And relevant collection settings to :
+ * source/blender/makesrna/intern/rna_scene.c
+ * source/blender/blenkernel/intern/layer.c
+ */
+#if 0
+void EDIT_TEXT_collection_settings_create(CollectionEngineSettings *ces)
+{
+ BLI_assert(ces);
+ // BKE_collection_engine_property_add_int(ces, "my_bool_prop", false);
+ // BKE_collection_engine_property_add_int(ces, "my_int_prop", 0);
+ // BKE_collection_engine_property_add_float(ces, "my_float_prop", 0.0f);
+}
+#endif
+
+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
+};
diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c
new file mode 100644
index 00000000000..173580adaef
--- /dev/null
+++ b/source/blender/draw/modes/object_mode.c
@@ -0,0 +1,1908 @@
+/*
+ * 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_camera_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_object_force.h"
+#include "DNA_lightprobe_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_world_types.h"
+
+#include "BIF_gl.h"
+
+#include "BKE_anim.h"
+#include "BKE_camera.h"
+#include "BKE_curve.h"
+#include "BKE_global.h"
+#include "BKE_particle.h"
+#include "BKE_image.h"
+#include "BKE_texture.h"
+
+#include "ED_view3d.h"
+#include "ED_view3d.h"
+
+#include "GPU_shader.h"
+#include "GPU_texture.h"
+
+#include "UI_resources.h"
+
+#include "draw_mode_engines.h"
+#include "draw_manager_text.h"
+#include "draw_common.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_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_particle_prim_vert_glsl[];
+extern char datatoc_object_particle_prim_frag_glsl[];
+extern char datatoc_object_particle_dot_vert_glsl[];
+extern char datatoc_object_particle_dot_frag_glsl[];
+extern char datatoc_common_globals_lib_glsl[];
+
+/* *********** LISTS *********** */
+typedef struct OBJECT_PassList {
+ struct DRWPass *non_meshes;
+ struct DRWPass *ob_center;
+ struct DRWPass *outlines;
+ struct DRWPass *outlines_search;
+ struct DRWPass *outlines_expand;
+ struct DRWPass *outlines_fade1;
+ struct DRWPass *outlines_fade2;
+ struct DRWPass *outlines_fade3;
+ struct DRWPass *outlines_fade4;
+ struct DRWPass *outlines_fade5;
+ struct DRWPass *outlines_resolve;
+ struct DRWPass *grid;
+ struct DRWPass *bone_solid;
+ struct DRWPass *bone_wire;
+ struct DRWPass *bone_envelope;
+ struct DRWPass *particle;
+ /* use for empty/background images */
+ struct DRWPass *reference_image;
+} OBJECT_PassList;
+
+typedef struct OBJECT_FramebufferList {
+ struct GPUFrameBuffer *outlines;
+ struct GPUFrameBuffer *blur;
+} 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_PrivateData{
+ /* Empties */
+ DRWShadingGroup *plain_axes;
+ DRWShadingGroup *cube;
+ DRWShadingGroup *circle;
+ DRWShadingGroup *sphere;
+ DRWShadingGroup *cone;
+ DRWShadingGroup *single_arrow;
+ DRWShadingGroup *single_arrow_line;
+ DRWShadingGroup *arrows;
+ DRWShadingGroup *axis_names;
+ /* GPUTexture -> EmptyImageShadingGroupData */
+ GHash *image_plane_map;
+
+ /* 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;
+
+ /* Speaker */
+ DRWShadingGroup *speaker;
+
+ /* Probe */
+ DRWShadingGroup *probe_cube;
+ DRWShadingGroup *probe_planar;
+ DRWShadingGroup *probe_grid;
+
+ /* Lamps */
+ DRWShadingGroup *lamp_center;
+ DRWShadingGroup *lamp_center_group;
+ 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;
+ DRWShadingGroup *lamp_hemi;
+ DRWShadingGroup *lamp_spot_cone;
+ DRWShadingGroup *lamp_spot_blend;
+ DRWShadingGroup *lamp_spot_pyramid;
+ DRWShadingGroup *lamp_spot_blend_rect;
+
+ /* Helpers */
+ DRWShadingGroup *relationship_lines;
+
+ /* Objects Centers */
+ DRWShadingGroup *center_active;
+ DRWShadingGroup *center_selected;
+ DRWShadingGroup *center_deselected;
+ DRWShadingGroup *center_selected_lib;
+ DRWShadingGroup *center_deselected_lib;
+
+ /* Camera */
+ DRWShadingGroup *camera;
+ DRWShadingGroup *camera_tria;
+ DRWShadingGroup *camera_focus;
+ DRWShadingGroup *camera_clip;
+ DRWShadingGroup *camera_clip_points;
+ DRWShadingGroup *camera_mist;
+ DRWShadingGroup *camera_mist_points;
+
+ /* Outlines */
+ DRWShadingGroup *outlines_active;
+ DRWShadingGroup *outlines_active_group;
+ DRWShadingGroup *outlines_select;
+ DRWShadingGroup *outlines_select_group;
+ DRWShadingGroup *outlines_transform;
+
+ /* Wire */
+ DRWShadingGroup *wire;
+ DRWShadingGroup *wire_active;
+ DRWShadingGroup *wire_active_group;
+ DRWShadingGroup *wire_select;
+ DRWShadingGroup *wire_select_group;
+ DRWShadingGroup *wire_transform;
+} OBJECT_PrivateData; /* Transient data */
+
+static struct {
+ /* fullscreen shaders */
+ GPUShader *outline_resolve_sh;
+ GPUShader *outline_detect_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;
+ float camera_pos[3];
+ float screenvecs[3][4];
+ float grid_settings[5];
+ float grid_mat[4][4];
+ 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];
+ bool draw_grid;
+ /* Temp buffer textures */
+ struct GPUTexture *outlines_depth_tx;
+ struct GPUTexture *outlines_color_tx;
+ struct GPUTexture *outlines_blur_tx;
+} 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),
+};
+
+/* *********** FUNCTIONS *********** */
+
+static void OBJECT_engine_init(void *vedata)
+{
+ OBJECT_FramebufferList *fbl = ((OBJECT_Data *)vedata)->fbl;
+
+ const float *viewport_size = DRW_viewport_size_get();
+
+ if (DRW_state_is_fbo()) {
+ DRWFboTexture tex[2] = {
+ {&e_data.outlines_depth_tx, DRW_TEX_DEPTH_24, DRW_TEX_TEMP},
+ {&e_data.outlines_color_tx, DRW_TEX_RGBA_8, DRW_TEX_FILTER | DRW_TEX_TEMP},
+ };
+
+ DRW_framebuffer_init(
+ &fbl->outlines, &draw_engine_object_type,
+ (int)viewport_size[0], (int)viewport_size[1],
+ tex, 2);
+
+ DRWFboTexture blur_tex = {&e_data.outlines_blur_tx, DRW_TEX_RGBA_8, DRW_TEX_FILTER | DRW_TEX_TEMP};
+ DRW_framebuffer_init(
+ &fbl->blur, &draw_engine_object_type,
+ (int)viewport_size[0], (int)viewport_size[1],
+ &blur_tex, 1);
+ }
+
+ if (!e_data.outline_resolve_sh) {
+ e_data.outline_resolve_sh = DRW_shader_create_fullscreen(datatoc_object_outline_resolve_frag_glsl, NULL);
+ }
+
+ if (!e_data.outline_detect_sh) {
+ e_data.outline_detect_sh = DRW_shader_create_fullscreen(datatoc_object_outline_detect_frag_glsl, NULL);
+ }
+
+ if (!e_data.outline_fade_sh) {
+ e_data.outline_fade_sh = DRW_shader_create_fullscreen(datatoc_object_outline_expand_frag_glsl, NULL);
+ }
+
+ if (!e_data.object_empty_image_sh) {
+ e_data.object_empty_image_sh = DRW_shader_create_with_lib(
+ datatoc_object_empty_image_vert_glsl, NULL,
+ datatoc_object_empty_image_frag_glsl,
+ datatoc_common_globals_lib_glsl, NULL);
+ }
+
+ if (!e_data.object_empty_image_wire_sh) {
+ e_data.object_empty_image_wire_sh = DRW_shader_create_with_lib(
+ datatoc_object_empty_image_vert_glsl, NULL,
+ datatoc_object_empty_image_frag_glsl,
+ datatoc_common_globals_lib_glsl,
+ "#define USE_WIRE\n");
+ }
+
+ if (!e_data.grid_sh) {
+ 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);
+ }
+
+ if (!e_data.part_prim_sh) {
+ e_data.part_prim_sh = DRW_shader_create(
+ datatoc_object_particle_prim_vert_glsl, NULL, datatoc_object_particle_prim_frag_glsl, NULL);
+ }
+
+ if (!e_data.part_axis_sh) {
+ e_data.part_axis_sh = DRW_shader_create(
+ datatoc_object_particle_prim_vert_glsl, NULL, datatoc_object_particle_prim_frag_glsl,
+ "#define USE_AXIS\n");
+ }
+
+ if (!e_data.part_dot_sh) {
+ e_data.part_dot_sh = DRW_shader_create(
+ datatoc_object_particle_dot_vert_glsl, NULL, datatoc_object_particle_dot_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, offs;
+
+ 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;
+
+ /* Grid matrix polygon offset (fix depth fighting) */
+ /* see ED_view3d_polygon_offset */
+ offs = winmat[3][2] * -0.0025f;
+
+ 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 {
+ float viewdist = 1.0f / max_ff(fabsf(winmat[0][0]), fabsf(winmat[1][1]));
+ grid_res = viewdist / grid_scale;
+
+ /* Grid matrix polygon offset (fix depth fighting) */
+ /* see ED_view3d_polygon_offset */
+ offs = 0.00001f * viewdist;
+ if (ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT)) {
+ e_data.grid_flag = PLANE_YZ;
+ e_data.grid_flag |= SHOW_AXIS_Y;
+ e_data.grid_flag |= SHOW_AXIS_Z;
+ e_data.grid_flag |= SHOW_GRID;
+ }
+ else if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) {
+ e_data.grid_flag = PLANE_XY;
+ e_data.grid_flag |= SHOW_AXIS_X;
+ e_data.grid_flag |= SHOW_AXIS_Y;
+ e_data.grid_flag |= SHOW_GRID;
+ }
+ else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) {
+ e_data.grid_flag = PLANE_XZ;
+ e_data.grid_flag |= SHOW_AXIS_X;
+ e_data.grid_flag |= SHOW_AXIS_Z;
+ e_data.grid_flag |= SHOW_GRID;
+ }
+ 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;
+ }
+
+ winmat[3][2] -= offs;
+ mul_m4_m4m4(e_data.grid_mat, winmat, viewmat);
+
+ float dist = (rv3d->persp == RV3D_CAMOB && v3d->camera)
+ ? ((Camera *)v3d->camera)->clipend : 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 / log(v3d->gridsubdiv) : 0.0; /* 1/log(gridSubdiv) */
+ }
+}
+
+static void OBJECT_engine_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.outline_resolve_sh);
+ DRW_SHADER_FREE_SAFE(e_data.outline_detect_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);
+}
+
+static DRWShadingGroup *shgroup_outline(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_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;
+}
+
+static DRWShadingGroup *shgroup_theme_id_to_outline_or(
+ OBJECT_StorageList *stl, int theme_id, DRWShadingGroup *fallback)
+{
+ switch (theme_id) {
+ case TH_ACTIVE:
+ return stl->g_data->outlines_active;
+ case TH_SELECT:
+ return stl->g_data->outlines_select;
+ case TH_GROUP_ACTIVE:
+ return stl->g_data->outlines_select_group;
+ case TH_TRANSFORM:
+ return stl->g_data->outlines_transform;
+ default:
+ return fallback;
+ }
+}
+
+static DRWShadingGroup *shgroup_theme_id_to_wire_or(
+ OBJECT_StorageList *stl, int theme_id, DRWShadingGroup *fallback)
+{
+ switch (theme_id) {
+ case TH_ACTIVE:
+ return stl->g_data->wire_active;
+ case TH_SELECT:
+ return stl->g_data->wire_select;
+ case TH_GROUP_ACTIVE:
+ return stl->g_data->wire_select_group;
+ case TH_TRANSFORM:
+ return stl->g_data->wire_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;
+ }
+}
+
+/* per-image shading groups for image-type empty objects */
+struct EmptyImageShadingGroupData {
+ DRWShadingGroup *shgrp_image;
+ DRWShadingGroup *shgrp_wire;
+ float image_aspect[2];
+};
+
+static void DRW_shgroup_empty_image(
+ OBJECT_StorageList *stl, OBJECT_PassList *psl, Object *ob, const float color[3])
+{
+ /* TODO: 'StereoViews', see draw_empty_image. */
+
+ if (stl->g_data->image_plane_map == NULL) {
+ stl->g_data->image_plane_map = BLI_ghash_ptr_new(__func__);
+ }
+
+ struct EmptyImageShadingGroupData *empty_image_data;
+
+ GPUTexture *tex = ob->data ?
+ GPU_texture_from_blender(ob->data, ob->iuser, GL_TEXTURE_2D, false, false, false) : NULL;
+ void **val_p;
+
+ /* Create on demand, 'tex' may be NULL. */
+ if (BLI_ghash_ensure_p(stl->g_data->image_plane_map, tex, &val_p)) {
+ empty_image_data = *val_p;
+ }
+ else {
+ empty_image_data = MEM_mallocN(sizeof(*empty_image_data), __func__);
+
+ image_calc_aspect(ob->data, ob->iuser, empty_image_data->image_aspect);
+
+ if (tex) {
+ struct Gwn_Batch *geom = DRW_cache_image_plane_get();
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(
+ e_data.object_empty_image_sh, psl->non_meshes, geom);
+ DRW_shgroup_attrib_float(grp, "objectColor", 4);
+ DRW_shgroup_attrib_float(grp, "size", 1);
+ DRW_shgroup_attrib_float(grp, "offset", 2);
+ DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16);
+
+ DRW_shgroup_uniform_texture(grp, "image", tex);
+ DRW_shgroup_uniform_vec2(grp, "aspect", empty_image_data->image_aspect, 1);
+
+ empty_image_data->shgrp_image = grp;
+ }
+ else {
+ empty_image_data->shgrp_image = NULL;
+ }
+
+ {
+ struct Gwn_Batch *geom = DRW_cache_image_plane_wire_get();
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(
+ e_data.object_empty_image_wire_sh, psl->non_meshes, geom);
+ DRW_shgroup_attrib_float(grp, "color", 3);
+ DRW_shgroup_attrib_float(grp, "size", 1);
+ DRW_shgroup_attrib_float(grp, "offset", 2);
+ DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16);
+
+ DRW_shgroup_uniform_vec2(grp, "aspect", empty_image_data->image_aspect, 1);
+
+ empty_image_data->shgrp_wire = grp;
+ }
+
+ *val_p = empty_image_data;
+ }
+
+ if (empty_image_data->shgrp_image != NULL) {
+ DRW_shgroup_call_dynamic_add(
+ empty_image_data->shgrp_image,
+ ob->col,
+ &ob->empty_drawsize,
+ ob->ima_ofs,
+ ob->obmat);
+ }
+
+ DRW_shgroup_call_dynamic_add(
+ empty_image_data->shgrp_wire,
+ color,
+ &ob->empty_drawsize,
+ ob->ima_ofs,
+ 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();
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_WIRE;
+ psl->outlines = DRW_pass_create("Outlines Pass", state);
+
+ GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ /* Select */
+ stl->g_data->outlines_select = shgroup_outline(psl->outlines, ts.colorSelect, sh);
+ stl->g_data->outlines_select_group = shgroup_outline(psl->outlines, ts.colorGroupActive, sh);
+
+ /* Transform */
+ stl->g_data->outlines_transform = shgroup_outline(psl->outlines, ts.colorTransform, sh);
+
+ /* Active */
+ stl->g_data->outlines_active = shgroup_outline(psl->outlines, ts.colorActive, sh);
+ stl->g_data->outlines_active_group = shgroup_outline(psl->outlines, ts.colorGroupActive, sh);
+ }
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR;
+ struct Gwn_Batch *quad = DRW_cache_fullscreen_quad_get();
+ static float alphaOcclu = 0.35f;
+ static float one = 1.0f;
+ static float alpha1 = 5.0f / 6.0f;
+ static float alpha2 = 4.0f / 5.0f;
+ static float alpha3 = 3.0f / 4.0f;
+ static float alpha4 = 2.0f / 3.0f;
+ static float alpha5 = 1.0f / 2.0f;
+ static bool bTrue = true;
+ static bool bFalse = false;
+
+ psl->outlines_search = DRW_pass_create("Outlines Expand Pass", state);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.outline_detect_sh, psl->outlines_search);
+ DRW_shgroup_uniform_buffer(grp, "outlineColor", &e_data.outlines_color_tx);
+ DRW_shgroup_uniform_buffer(grp, "outlineDepth", &e_data.outlines_depth_tx);
+ DRW_shgroup_uniform_buffer(grp, "sceneDepth", &dtxl->depth);
+ DRW_shgroup_uniform_float(grp, "alphaOcclu", &alphaOcclu, 1);
+ 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_buffer(grp, "outlineColor", &e_data.outlines_blur_tx);
+ DRW_shgroup_uniform_buffer(grp, "outlineDepth", &e_data.outlines_depth_tx);
+ DRW_shgroup_uniform_float(grp, "alpha", &one, 1);
+ DRW_shgroup_uniform_bool(grp, "doExpand", &bTrue, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ psl->outlines_fade1 = DRW_pass_create("Outlines Fade 1 Pass", state);
+
+ grp = DRW_shgroup_create(e_data.outline_fade_sh, psl->outlines_fade1);
+ DRW_shgroup_uniform_buffer(grp, "outlineColor", &e_data.outlines_color_tx);
+ DRW_shgroup_uniform_buffer(grp, "outlineDepth", &e_data.outlines_depth_tx);
+ DRW_shgroup_uniform_float(grp, "alpha", &alpha1, 1);
+ DRW_shgroup_uniform_bool(grp, "doExpand", &bFalse, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ psl->outlines_fade2 = DRW_pass_create("Outlines Fade 2 Pass", state);
+
+ grp = DRW_shgroup_create(e_data.outline_fade_sh, psl->outlines_fade2);
+ DRW_shgroup_uniform_buffer(grp, "outlineColor", &e_data.outlines_blur_tx);
+ DRW_shgroup_uniform_buffer(grp, "outlineDepth", &e_data.outlines_depth_tx);
+ DRW_shgroup_uniform_float(grp, "alpha", &alpha2, 1);
+ DRW_shgroup_uniform_bool(grp, "doExpand", &bFalse, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ psl->outlines_fade3 = DRW_pass_create("Outlines Fade 3 Pass", state);
+
+ grp = DRW_shgroup_create(e_data.outline_fade_sh, psl->outlines_fade3);
+ DRW_shgroup_uniform_buffer(grp, "outlineColor", &e_data.outlines_color_tx);
+ DRW_shgroup_uniform_buffer(grp, "outlineDepth", &e_data.outlines_depth_tx);
+ DRW_shgroup_uniform_float(grp, "alpha", &alpha3, 1);
+ DRW_shgroup_uniform_bool(grp, "doExpand", &bFalse, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ psl->outlines_fade4 = DRW_pass_create("Outlines Fade 4 Pass", state);
+
+ grp = DRW_shgroup_create(e_data.outline_fade_sh, psl->outlines_fade4);
+ DRW_shgroup_uniform_buffer(grp, "outlineColor", &e_data.outlines_blur_tx);
+ DRW_shgroup_uniform_buffer(grp, "outlineDepth", &e_data.outlines_depth_tx);
+ DRW_shgroup_uniform_float(grp, "alpha", &alpha4, 1);
+ DRW_shgroup_uniform_bool(grp, "doExpand", &bFalse, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ psl->outlines_fade5 = DRW_pass_create("Outlines Fade 5 Pass", state);
+
+ grp = DRW_shgroup_create(e_data.outline_fade_sh, psl->outlines_fade5);
+ DRW_shgroup_uniform_buffer(grp, "outlineColor", &e_data.outlines_color_tx);
+ DRW_shgroup_uniform_buffer(grp, "outlineDepth", &e_data.outlines_depth_tx);
+ DRW_shgroup_uniform_float(grp, "alpha", &alpha5, 1);
+ 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 Gwn_Batch *quad = DRW_cache_fullscreen_quad_get();
+
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.outline_resolve_sh, psl->outlines_resolve);
+ DRW_shgroup_uniform_buffer(grp, "outlineBluredColor", &e_data.outlines_blur_tx);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+
+ {
+ /* Grid pass */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND;
+ psl->grid = DRW_pass_create("Infinite Grid Pass", state);
+
+ struct Gwn_Batch *quad = DRW_cache_fullscreen_quad_get();
+ 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_mat4(grp, "ViewProjectionOffsetMatrix", (float *)e_data.grid_mat);
+ 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(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_call_add(grp, quad, 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_call_add(grp, quad, 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_call_add(grp, quad, mat);
+ }
+
+ {
+ /* Solid bones */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS;
+ psl->bone_solid = DRW_pass_create("Bone Solid Pass", state);
+ }
+
+ {
+ /* Wire bones */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND;
+ psl->bone_wire = DRW_pass_create("Bone Wire Pass", state);
+ }
+
+ {
+ /* distance outline around envelope bones */
+ DRWState state = DRW_STATE_ADDITIVE | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND;
+ psl->bone_envelope = DRW_pass_create("Bone Envelope Outline Pass", state);
+ }
+
+ {
+ /* Non Meshes Pass (Camera, empties, lamps ...) */
+ struct Gwn_Batch *geom;
+
+ DRWState state =
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
+ DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND | DRW_STATE_POINT;
+ state |= DRW_STATE_WIRE;
+ psl->non_meshes = DRW_pass_create("Non Meshes Pass", state);
+
+ /* Empties */
+ geom = DRW_cache_plain_axes_get();
+ stl->g_data->plain_axes = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_cube_get();
+ stl->g_data->cube = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_circle_get();
+ stl->g_data->circle = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_empty_sphere_get();
+ stl->g_data->sphere = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_empty_cone_get();
+ stl->g_data->cone = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_single_arrow_get();
+ stl->g_data->single_arrow = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_single_line_get();
+ stl->g_data->single_arrow_line = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_arrows_get();
+ stl->g_data->arrows = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_axis_names_get();
+ stl->g_data->axis_names = shgroup_instance_axis_names(psl->non_meshes, geom);
+
+ /* initialize on first use */
+ stl->g_data->image_plane_map = NULL;
+
+ /* Force Field */
+ geom = DRW_cache_field_wind_get();
+ stl->g_data->field_wind = shgroup_instance_scaled(psl->non_meshes, geom);
+
+ geom = DRW_cache_field_force_get();
+ stl->g_data->field_force = shgroup_instance_screen_aligned(psl->non_meshes, geom);
+
+ geom = DRW_cache_field_vortex_get();
+ stl->g_data->field_vortex = shgroup_instance_scaled(psl->non_meshes, geom);
+
+ geom = DRW_cache_screenspace_circle_get();
+ stl->g_data->field_curve_sta = shgroup_instance_screen_aligned(psl->non_meshes, geom);
+
+ /* Speaker */
+ geom = DRW_cache_speaker_get();
+ stl->g_data->speaker = shgroup_instance(psl->non_meshes, geom);
+
+ /* Probe */
+ static float probeSize = 14.0f;
+ geom = DRW_cache_lightprobe_cube_get();
+ stl->g_data->probe_cube = shgroup_instance_screenspace(psl->non_meshes, geom, &probeSize);
+
+ geom = DRW_cache_lightprobe_grid_get();
+ stl->g_data->probe_grid = shgroup_instance_screenspace(psl->non_meshes, geom, &probeSize);
+
+ static float probePlanarSize = 20.0f;
+ geom = DRW_cache_lightprobe_planar_get();
+ stl->g_data->probe_planar = shgroup_instance_screenspace(psl->non_meshes, geom, &probePlanarSize);
+
+ /* Camera */
+ geom = DRW_cache_camera_get();
+ stl->g_data->camera = shgroup_camera_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_camera_tria_get();
+ stl->g_data->camera_tria = shgroup_camera_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_plain_axes_get();
+ stl->g_data->camera_focus = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_single_line_get();
+ stl->g_data->camera_clip = shgroup_distance_lines_instance(psl->non_meshes, geom);
+ stl->g_data->camera_mist = shgroup_distance_lines_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_single_line_endpoints_get();
+ stl->g_data->camera_clip_points = shgroup_distance_lines_instance(psl->non_meshes, geom);
+ stl->g_data->camera_mist_points = shgroup_distance_lines_instance(psl->non_meshes, geom);
+
+ }
+
+ {
+ GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ /* Unselected */
+ stl->g_data->wire = shgroup_wire(psl->non_meshes, ts.colorWire, sh);
+
+ /* Select */
+ stl->g_data->wire_select = shgroup_wire(psl->non_meshes, ts.colorSelect, sh);
+ stl->g_data->wire_select_group = shgroup_wire(psl->non_meshes, ts.colorGroupActive, sh);
+
+ /* Transform */
+ stl->g_data->wire_transform = shgroup_wire(psl->non_meshes, ts.colorTransform, sh);
+
+ /* Active */
+ stl->g_data->wire_active = shgroup_wire(psl->non_meshes, ts.colorActive, sh);
+ stl->g_data->wire_active_group = shgroup_wire(psl->non_meshes, ts.colorGroupActive, sh);
+ }
+
+ {
+ /* Lamps */
+ /* TODO
+ * for now we create multiple times the same VBO with only lamp center coordinates
+ * but ideally we would only create it once */
+ struct Gwn_Batch *geom;
+
+ /* start with buflimit because we don't want stipples */
+ geom = DRW_cache_single_line_get();
+ stl->g_data->lamp_buflimit = shgroup_distance_lines_instance(psl->non_meshes, geom);
+
+ stl->g_data->lamp_center = shgroup_dynpoints_uniform_color(psl->non_meshes, ts.colorLampNoAlpha, &ts.sizeLampCenter);
+ stl->g_data->lamp_center_group = shgroup_dynpoints_uniform_color(psl->non_meshes, ts.colorGroup, &ts.sizeLampCenter);
+
+ geom = DRW_cache_lamp_get();
+ stl->g_data->lamp_circle = shgroup_instance_screenspace(psl->non_meshes, geom, &ts.sizeLampCircle);
+ stl->g_data->lamp_circle_shadow = shgroup_instance_screenspace(psl->non_meshes, geom, &ts.sizeLampCircleShadow);
+
+ geom = DRW_cache_lamp_sunrays_get();
+ stl->g_data->lamp_sunrays = shgroup_instance_screenspace(psl->non_meshes, geom, &ts.sizeLampCircle);
+
+ stl->g_data->lamp_groundline = shgroup_groundlines_uniform_color(psl->non_meshes, ts.colorLamp);
+ stl->g_data->lamp_groundpoint = shgroup_groundpoints_uniform_color(psl->non_meshes, ts.colorLamp);
+
+ geom = DRW_cache_lamp_area_get();
+ stl->g_data->lamp_area = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_lamp_hemi_get();
+ stl->g_data->lamp_hemi = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_single_line_get();
+ stl->g_data->lamp_distance = shgroup_distance_lines_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_single_line_endpoints_get();
+ stl->g_data->lamp_buflimit_points = shgroup_distance_lines_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_lamp_spot_get();
+ stl->g_data->lamp_spot_cone = shgroup_spot_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_circle_get();
+ stl->g_data->lamp_spot_blend = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_lamp_spot_square_get();
+ stl->g_data->lamp_spot_pyramid = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_square_get();
+ stl->g_data->lamp_spot_blend_rect = shgroup_instance(psl->non_meshes, geom);
+ }
+
+ {
+ /* -------- STIPPLES ------- */
+ /* TODO port to shader stipple */
+ struct Gwn_Batch *geom;
+
+ /* Relationship Lines */
+ stl->g_data->relationship_lines = shgroup_dynlines_uniform_color(psl->non_meshes, ts.colorWire);
+ DRW_shgroup_state_enable(stl->g_data->relationship_lines, DRW_STATE_STIPPLE_3);
+
+ /* Force Field Curve Guide End (here because of stipple) */
+ geom = DRW_cache_screenspace_circle_get();
+ stl->g_data->field_curve_end = shgroup_instance_screen_aligned(psl->non_meshes, geom);
+
+ /* Force Field Limits */
+ geom = DRW_cache_field_tube_limit_get();
+ stl->g_data->field_tube_limit = shgroup_instance_scaled(psl->non_meshes, geom);
+
+ geom = DRW_cache_field_cone_limit_get();
+ stl->g_data->field_cone_limit = shgroup_instance_scaled(psl->non_meshes, geom);
+ }
+
+ {
+ /* 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 |
+ DRW_STATE_POINT | DRW_STATE_BLEND);
+ }
+
+ {
+ /* Empty/Background Image Pass */
+ psl->reference_image = DRW_pass_create(
+ "Refrence Image Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND);
+ }
+}
+
+static void DRW_shgroup_lamp(OBJECT_StorageList *stl, Object *ob, SceneLayer *sl)
+{
+ Lamp *la = ob->data;
+ float *color;
+ int theme_id = DRW_object_wire_theme_get(ob, sl, &color);
+ static float zero = 0.0f;
+
+ float **la_mats = (float **)DRW_object_engine_data_get(ob, &draw_engine_object_type, NULL);
+ if (*la_mats == NULL) {
+ /* we need 2 matrices */
+ *la_mats = MEM_mallocN(sizeof(float) * 16 * 2, "Lamp Object Mode Matrices");
+ }
+
+ float (*shapemat)[4], (*spotblendmat)[4];
+ shapemat = (float (*)[4])(*la_mats);
+ spotblendmat = (float (*)[4])(*la_mats + 16);
+
+ /* Don't draw the center if it's selected or active */
+ if (theme_id == TH_GROUP)
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_center_group, ob->obmat[3]);
+ else if (theme_id == TH_LAMP)
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_center, ob->obmat[3]);
+
+ /* First circle */
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_circle, ob->obmat[3], color);
+
+ /* 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))) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_circle_shadow, ob->obmat[3], color);
+ }
+ }
+
+ /* Distance */
+ if (ELEM(la->type, LA_HEMI, LA_SUN, LA_AREA)) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_distance, color, &zero, &la->dist, ob->obmat);
+ }
+
+ copy_m4_m4(shapemat, ob->obmat);
+
+ if (la->type == LA_SUN) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_sunrays, ob->obmat[3], color);
+ }
+ else if (la->type == LA_SPOT) {
+ float size[3], sizemat[4][4];
+ static float one = 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', M_PI / 2.0f);
+ mul_m4_m4m4(spotblendmat, shapemat, sizemat);
+
+ if (la->mode & LA_SQUARE) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->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(stl->g_data->lamp_spot_blend_rect, color, &one, spotblendmat);
+ }
+ }
+ else {
+ DRW_shgroup_call_dynamic_add(stl->g_data->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(stl->g_data->lamp_spot_blend, color, &one, spotblendmat);
+ }
+ }
+
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_buflimit, color, &la->clipsta, &la->clipend, ob->obmat);
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_buflimit_points, color, &la->clipsta, &la->clipend, ob->obmat);
+ }
+ else if (la->type == LA_HEMI) {
+ static float hemisize = 2.0f;
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_hemi, color, &hemisize, shapemat);
+ }
+ else if (la->type == LA_AREA) {
+ float size[3] = {1.0f, 1.0f, 1.0f}, sizemat[4][4];
+
+ if (la->area_shape == LA_AREA_RECT) {
+ size[1] = la->area_sizey / la->area_size;
+ size_to_mat4(sizemat, size);
+ mul_m4_m4m4(shapemat, shapemat, sizemat);
+ }
+
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_area, color, &la->area_size, shapemat);
+ }
+
+ /* Line and point going to the ground */
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_groundline, ob->obmat[3]);
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_groundpoint, ob->obmat[3]);
+}
+
+static void DRW_shgroup_camera(OBJECT_StorageList *stl, Object *ob, SceneLayer *sl)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ Scene *scene = draw_ctx->scene;
+
+ Camera *cam = ob->data;
+ const bool is_active = (ob == v3d->camera);
+ float *color;
+ DRW_object_wire_theme_get(ob, sl, &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]);
+
+ DRW_shgroup_call_dynamic_add(stl->g_data->camera, color, cam->drwcorners, &cam->drwdepth, cam->drwtria, ob->obmat);
+
+ /* Active cam */
+ if (is_active) {
+ DRW_shgroup_call_dynamic_add(
+ stl->g_data->camera_tria, color,
+ cam->drwcorners, &cam->drwdepth, cam->drwtria, ob->obmat);
+ }
+
+ /* draw the rest in normalize object space */
+ copy_m4_m4(cam->drwnormalmat, ob->obmat);
+ normalize_m4(cam->drwnormalmat);
+
+ 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(
+ stl->g_data->camera_focus, (is_active ? col_hi : col),
+ &cam->drawsize, cam->drwfocusmat);
+
+ DRW_shgroup_call_dynamic_add(
+ stl->g_data->camera_clip, color,
+ &cam->clipsta, &cam->clipend, cam->drwnormalmat);
+ DRW_shgroup_call_dynamic_add(
+ stl->g_data->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(
+ stl->g_data->camera_mist, color,
+ &world->miststa, &world->mistend, cam->drwnormalmat);
+ DRW_shgroup_call_dynamic_add(
+ stl->g_data->camera_mist_points, (is_active ? col_hi : col),
+ &world->miststa, &world->mistend, cam->drwnormalmat);
+ }
+ }
+}
+
+static void DRW_shgroup_empty(OBJECT_StorageList *stl, OBJECT_PassList *psl, Object *ob, SceneLayer *sl)
+{
+ float *color;
+ DRW_object_wire_theme_get(ob, sl, &color);
+
+ switch (ob->empty_drawtype) {
+ case OB_PLAINAXES:
+ DRW_shgroup_call_dynamic_add(stl->g_data->plain_axes, color, &ob->empty_drawsize, ob->obmat);
+ break;
+ case OB_SINGLE_ARROW:
+ DRW_shgroup_call_dynamic_add(stl->g_data->single_arrow, color, &ob->empty_drawsize, ob->obmat);
+ DRW_shgroup_call_dynamic_add(stl->g_data->single_arrow_line, color, &ob->empty_drawsize, ob->obmat);
+ break;
+ case OB_CUBE:
+ DRW_shgroup_call_dynamic_add(stl->g_data->cube, color, &ob->empty_drawsize, ob->obmat);
+ break;
+ case OB_CIRCLE:
+ DRW_shgroup_call_dynamic_add(stl->g_data->circle, color, &ob->empty_drawsize, ob->obmat);
+ break;
+ case OB_EMPTY_SPHERE:
+ DRW_shgroup_call_dynamic_add(stl->g_data->sphere, color, &ob->empty_drawsize, ob->obmat);
+ break;
+ case OB_EMPTY_CONE:
+ DRW_shgroup_call_dynamic_add(stl->g_data->cone, color, &ob->empty_drawsize, ob->obmat);
+ break;
+ case OB_ARROWS:
+ DRW_shgroup_call_dynamic_add(stl->g_data->arrows, color, &ob->empty_drawsize, ob->obmat);
+ DRW_shgroup_call_dynamic_add(stl->g_data->axis_names, color, &ob->empty_drawsize, ob->obmat);
+ break;
+ case OB_EMPTY_IMAGE:
+ DRW_shgroup_empty_image(stl, psl, ob, color);
+ break;
+ }
+}
+
+static void DRW_shgroup_forcefield(OBJECT_StorageList *stl, Object *ob, SceneLayer *sl)
+{
+ int theme_id = DRW_object_wire_theme_get(ob, sl, 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->curve_cache->path && ob->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(stl->g_data->field_wind, color, &pd->drawvec1, ob->obmat);
+ break;
+ case PFIELD_FORCE:
+ DRW_shgroup_call_dynamic_add(stl->g_data->field_force, color, &pd->drawvec1, ob->obmat);
+ break;
+ case PFIELD_VORTEX:
+ DRW_shgroup_call_dynamic_add(stl->g_data->field_vortex, color, &pd->drawvec1, ob->obmat);
+ break;
+ case PFIELD_GUIDE:
+ if (cu && (cu->flag & CU_PATH) && ob->curve_cache->path && ob->curve_cache->path->data) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->field_curve_sta, color, &pd->f_strength, ob->obmat);
+ DRW_shgroup_call_dynamic_add(stl->g_data->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(stl->g_data->field_curve_end, color, &pd->maxdist, ob->obmat);
+ }
+
+ if ((pd->flag & PFIELD_USEMIN) != 0) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->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(stl->g_data->field_tube_limit, color, &pd->drawvec_falloff_max, ob->obmat);
+ }
+
+ if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR)) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->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(stl->g_data->field_cone_limit, color, &pd->drawvec_falloff_max, ob->obmat);
+ }
+
+ if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR)) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->field_cone_limit, color, &pd->drawvec_falloff_min, ob->obmat);
+ }
+ }
+}
+
+static void DRW_shgroup_speaker(OBJECT_StorageList *stl, Object *ob, SceneLayer *sl)
+{
+ float *color;
+ static float one = 1.0f;
+ DRW_object_wire_theme_get(ob, sl, &color);
+
+ DRW_shgroup_call_dynamic_add(stl->g_data->speaker, color, &one, ob->obmat);
+}
+
+static void DRW_shgroup_lightprobe(OBJECT_StorageList *stl, Object *ob, SceneLayer *sl)
+{
+ float *color;
+ static float one = 1.0f;
+ LightProbe *prb = (LightProbe *)ob->data;
+ DRW_object_wire_theme_get(ob, sl, &color);
+
+ switch (prb->type) {
+ case LIGHTPROBE_TYPE_PLANAR:
+ DRW_shgroup_call_dynamic_add(stl->g_data->probe_planar, ob->obmat[3], color);
+ break;
+ case LIGHTPROBE_TYPE_GRID:
+ DRW_shgroup_call_dynamic_add(stl->g_data->probe_grid, ob->obmat[3], color);
+ break;
+ case LIGHTPROBE_TYPE_CUBE:
+ default:
+ DRW_shgroup_call_dynamic_add(stl->g_data->probe_cube, ob->obmat[3], color);
+ break;
+ }
+
+ float **prb_mats = (float **)DRW_object_engine_data_get(ob, &draw_engine_object_type, NULL);
+ if (*prb_mats == NULL) {
+ /* we need 6 matrices */
+ *prb_mats = MEM_mallocN(sizeof(float) * 16 * 6, "Probe Clip distances Matrices");
+ }
+
+ if (prb->type == LIGHTPROBE_TYPE_PLANAR) {
+ float (*mat)[4];
+ mat = (float (*)[4])(*prb_mats);
+ copy_m4_m4(mat, ob->obmat);
+ normalize_m4(mat);
+
+ DRW_shgroup_call_dynamic_add(stl->g_data->single_arrow, color, &ob->empty_drawsize, mat);
+ DRW_shgroup_call_dynamic_add(stl->g_data->single_arrow_line, color, &ob->empty_drawsize, mat);
+
+ mat = (float (*)[4])(*prb_mats + 16);
+ copy_m4_m4(mat, ob->obmat);
+ zero_v3(mat[2]);
+
+ DRW_shgroup_call_dynamic_add(stl->g_data->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(stl->g_data->cube, color, &prb->distgridinf, ob->obmat);
+ DRW_shgroup_call_dynamic_add(stl->g_data->cube, color, &prb->distfalloff, ob->obmat);
+ }
+ else if (prb->type == LIGHTPROBE_TYPE_PLANAR) {
+ float (*rangemat)[4];
+ rangemat = (float (*)[4])(*prb_mats + 32);
+ copy_m4_m4(rangemat, ob->obmat);
+ normalize_v3(rangemat[2]);
+ mul_v3_fl(rangemat[2], prb->distinf);
+
+ DRW_shgroup_call_dynamic_add(stl->g_data->cube, color, &one, rangemat);
+
+ rangemat = (float (*)[4])(*prb_mats + 64);
+ copy_m4_m4(rangemat, ob->obmat);
+ normalize_v3(rangemat[2]);
+ mul_v3_fl(rangemat[2], prb->distfalloff);
+
+ DRW_shgroup_call_dynamic_add(stl->g_data->cube, color, &one, rangemat);
+ }
+ else {
+ DRW_shgroup_call_dynamic_add(stl->g_data->sphere, color, &prb->distgridinf, ob->obmat);
+ DRW_shgroup_call_dynamic_add(stl->g_data->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(stl->g_data->cube, color, &dist, obmat);
+ }
+ else {
+ DRW_shgroup_call_dynamic_add(stl->g_data->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];
+ clipmat = (float (*)[4])(*prb_mats + 16 * i);
+
+ normalize_m4_m4(clipmat, ob->obmat);
+ mul_m4_m4m4(clipmat, clipmat, cubefacemat[i]);
+
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_buflimit, color, &prb->clipsta, &prb->clipend, clipmat);
+ DRW_shgroup_call_dynamic_add(stl->g_data->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(stl->g_data->lamp_groundline, ob->obmat[3]);
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_groundpoint, ob->obmat[3]);
+ }
+}
+
+static void DRW_shgroup_relationship_lines(OBJECT_StorageList *stl, Object *ob)
+{
+ if (ob->parent && ((ob->parent->base_flag & BASE_VISIBLED) != 0)) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->relationship_lines, ob->obmat[3]);
+ DRW_shgroup_call_dynamic_add(stl->g_data->relationship_lines, ob->parent->obmat[3]);
+ }
+}
+
+static void DRW_shgroup_object_center(OBJECT_StorageList *stl, Object *ob, SceneLayer *sl, View3D *v3d)
+{
+ const bool is_library = ob->id.us > 1 || ID_IS_LINKED_DATABLOCK(ob);
+ DRWShadingGroup *shgroup;
+
+ if (ob == OBACT_NEW) {
+ 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 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)) {
+ ParticleSettings *part = psys->part;
+ int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
+
+ if (draw_as == PART_DRAW_PATH && !psys->pathcache && !psys->childcache) {
+ draw_as = PART_DRAW_DOT;
+ }
+
+ static float mat[4][4];
+ unit_m4(mat);
+
+ if (draw_as != PART_DRAW_PATH) {
+ struct Gwn_Batch *geom = DRW_cache_particles_get_dots(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};
+
+ 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));
+ 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));
+ 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));
+ 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;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ SceneLayer *sl = draw_ctx->scene_layer;
+ View3D *v3d = draw_ctx->v3d;
+ int theme_id = TH_UNDEFINED;
+
+ //CollectionEngineSettings *ces_mode_ob = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_OBJECT, "");
+
+ //bool do_wire = BKE_collection_engine_property_value_get_bool(ces_mode_ob, "show_wire");
+ bool do_outlines = ((ob->base_flag & BASE_SELECTED) != 0);
+
+ if (do_outlines) {
+ Object *obedit = scene->obedit;
+ if (ob != obedit && !((ob == draw_ctx->obact) && (ob->mode & OB_MODE_ALL_PAINT))) {
+ struct Gwn_Batch *geom = DRW_cache_object_surface_get(ob);
+ if (geom) {
+ theme_id = DRW_object_wire_theme_get(ob, sl, NULL);
+ DRWShadingGroup *shgroup = shgroup_theme_id_to_outline_or(stl, theme_id, NULL);
+ if (shgroup != NULL) {
+ DRW_shgroup_call_add(shgroup, geom, ob->obmat);
+ }
+ }
+ }
+ }
+
+ switch (ob->type) {
+ case OB_MESH:
+ {
+ Mesh *me = ob->data;
+ if (me->totpoly == 0) {
+ Object *obedit = scene->obedit;
+ if (ob != obedit) {
+ struct Gwn_Batch *geom = DRW_cache_mesh_edges_get(ob);
+ if (geom) {
+ if (theme_id == TH_UNDEFINED) {
+ theme_id = DRW_object_wire_theme_get(ob, sl, NULL);
+ }
+
+ DRWShadingGroup *shgroup = shgroup_theme_id_to_wire_or(stl, theme_id, stl->g_data->wire);
+ DRW_shgroup_call_add(shgroup, geom, ob->obmat);
+ }
+ }
+ }
+
+ OBJECT_cache_populate_particles(ob, psl);
+ break;
+ }
+ case OB_SURF:
+ break;
+ case OB_LATTICE:
+ {
+ Object *obedit = scene->obedit;
+ if (ob != obedit) {
+ struct Gwn_Batch *geom = DRW_cache_lattice_wire_get(ob, false);
+ if (theme_id == TH_UNDEFINED) {
+ theme_id = DRW_object_wire_theme_get(ob, sl, NULL);
+ }
+
+ DRWShadingGroup *shgroup = shgroup_theme_id_to_wire_or(stl, theme_id, stl->g_data->wire);
+ DRW_shgroup_call_add(shgroup, geom, ob->obmat);
+ }
+ break;
+ }
+
+ case OB_CURVE:
+ {
+ Object *obedit = scene->obedit;
+ if (ob != obedit) {
+ struct Gwn_Batch *geom = DRW_cache_curve_edge_wire_get(ob);
+ if (theme_id == TH_UNDEFINED) {
+ theme_id = DRW_object_wire_theme_get(ob, sl, NULL);
+ }
+ DRWShadingGroup *shgroup = shgroup_theme_id_to_wire_or(stl, theme_id, stl->g_data->wire);
+ DRW_shgroup_call_add(shgroup, geom, ob->obmat);
+ }
+ break;
+ }
+ case OB_LAMP:
+ DRW_shgroup_lamp(stl, ob, sl);
+ break;
+ case OB_CAMERA:
+ DRW_shgroup_camera(stl, ob, sl);
+ break;
+ case OB_EMPTY:
+ DRW_shgroup_empty(stl, psl, ob, sl);
+ break;
+ case OB_SPEAKER:
+ DRW_shgroup_speaker(stl, ob, sl);
+ break;
+ case OB_LIGHTPROBE:
+ DRW_shgroup_lightprobe(stl, ob, sl);
+ break;
+ case OB_ARMATURE:
+ {
+ bArmature *arm = ob->data;
+ if (arm->edbo == NULL) {
+ if (DRW_state_is_select() || !DRW_pose_mode_armature(ob, draw_ctx->obact)) {
+ DRW_shgroup_armature_object(
+ ob, sl, psl->bone_solid, psl->bone_wire, psl->bone_envelope,
+ stl->g_data->relationship_lines);
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (ob->pd && ob->pd->forcefield) {
+ DRW_shgroup_forcefield(stl, ob, sl);
+ }
+
+ /* don't show object extras in set's */
+ if ((ob->base_flag & (BASE_FROM_SET | BASE_FROMDUPLI)) == 0) {
+
+ DRW_shgroup_object_center(stl, ob, sl, v3d);
+
+ DRW_shgroup_relationship_lines(stl, ob);
+
+ if ((ob->dtx & OB_DRAWNAME) && DRW_state_show_text()) {
+ struct DRWTextStore *dt = DRW_text_cache_ensure();
+ if (theme_id == TH_UNDEFINED) {
+ theme_id = DRW_object_wire_theme_get(ob, sl, NULL);
+ }
+
+ unsigned char 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, DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR, color);
+ }
+ }
+}
+
+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;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+ if (DRW_state_is_fbo()) {
+ /* attach temp textures */
+ DRW_framebuffer_texture_attach(fbl->outlines, e_data.outlines_depth_tx, 0, 0);
+ DRW_framebuffer_texture_attach(fbl->outlines, e_data.outlines_color_tx, 0, 0);
+ DRW_framebuffer_texture_attach(fbl->blur, e_data.outlines_blur_tx, 0, 0);
+
+ /* Render filled polygon on a separate framebuffer */
+ DRW_framebuffer_bind(fbl->outlines);
+ DRW_framebuffer_clear(true, true, false, clearcol, 1.0f);
+ DRW_draw_pass(psl->outlines);
+
+ /* detach textures */
+ DRW_framebuffer_texture_detach(e_data.outlines_depth_tx);
+
+ /* Search outline pixels */
+ DRW_framebuffer_bind(fbl->blur);
+ DRW_draw_pass(psl->outlines_search);
+
+ /* Expand and fade gradually */
+ DRW_framebuffer_bind(fbl->outlines);
+ DRW_draw_pass(psl->outlines_expand);
+
+ DRW_framebuffer_bind(fbl->blur);
+ DRW_draw_pass(psl->outlines_fade1);
+
+ DRW_framebuffer_bind(fbl->outlines);
+ DRW_draw_pass(psl->outlines_fade2);
+
+ DRW_framebuffer_bind(fbl->blur);
+ DRW_draw_pass(psl->outlines_fade3);
+
+ DRW_framebuffer_bind(fbl->outlines);
+ DRW_draw_pass(psl->outlines_fade4);
+
+ DRW_framebuffer_bind(fbl->blur);
+ DRW_draw_pass(psl->outlines_fade5);
+
+ /* detach temp textures */
+ DRW_framebuffer_texture_detach(e_data.outlines_color_tx);
+ DRW_framebuffer_texture_detach(e_data.outlines_blur_tx);
+
+ /* restore main framebuffer */
+ DRW_framebuffer_bind(dfbl->default_fb);
+ }
+
+ /* This needs to be drawn after the oultine */
+// DRW_draw_pass(psl->bone_envelope); /* Never drawn in Object mode currently. */
+ DRW_draw_pass(psl->bone_wire);
+ DRW_draw_pass(psl->bone_solid);
+ DRW_draw_pass(psl->non_meshes);
+ DRW_draw_pass(psl->ob_center);
+ DRW_draw_pass(psl->particle);
+ DRW_draw_pass(psl->reference_image);
+
+ if (!DRW_state_is_select()) {
+ if (e_data.draw_grid) {
+ DRW_draw_pass(psl->grid);
+ }
+
+ /* Combine with scene buffer last */
+ DRW_draw_pass(psl->outlines_resolve);
+ }
+
+ /* This has to be freed only after drawing empties! */
+ if (stl->g_data->image_plane_map) {
+ BLI_ghash_free(stl->g_data->image_plane_map, NULL, MEM_freeN);
+ }
+}
+
+void OBJECT_collection_settings_create(IDProperty *props)
+{
+ BLI_assert(props &&
+ props->type == IDP_GROUP &&
+ props->subtype == IDP_GROUP_SUB_MODE_OBJECT);
+ BKE_collection_engine_property_add_int(props, "show_wire", false);
+ BKE_collection_engine_property_add_int(props, "show_backface_culling", false);
+}
+
+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,
+ NULL,
+ NULL,
+ &OBJECT_draw_scene
+};
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..65ab9fd9286
--- /dev/null
+++ b/source/blender/draw/modes/paint_texture_mode.c
@@ -0,0 +1,416 @@
+/*
+ * 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_get.
+ * 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, DRW_TEX_DEPTH_24, 0},
+ * {&txl->color, DRW_TEX_RGBA_8, 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_WRITE_DEPTH | DRW_STATE_DEPTH_LESS |
+ DRW_STATE_BLEND | DRW_STATE_WIRE;
+ 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, false, false) : NULL;
+
+ if (tex) {
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.image_sh, psl->image_faces);
+ DRW_shgroup_uniform_texture(grp, "image", tex);
+ 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, false, false) : NULL;
+
+ if (tex) {
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.image_sh, psl->image_faces);
+ DRW_shgroup_uniform_texture(grp, "image", tex);
+ 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);
+
+ stl->g_data->lwire_shgrp = DRW_shgroup_create(e_data.wire_overlay_shader, psl->wire_overlay);
+ }
+
+ {
+ psl->face_overlay = DRW_pass_create(
+ "Face Mask Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | 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 = DRW_object_is_mode_shade(ob) == true;
+ const bool use_material_slots = (scene->toolsettings->imapaint.mode == IMAGEPAINT_MODE_MATERIAL);
+ bool ok = false;
+
+ if (use_surface) {
+ if (me->mloopuv != NULL) {
+ if (use_material_slots) {
+ struct Gwn_Batch **geom_array = me->totcol ? DRW_cache_mesh_surface_texpaint_get(ob) : NULL;
+ if ((me->totcol == 0) || (geom_array == NULL)) {
+ struct Gwn_Batch *geom = DRW_cache_mesh_surface_get(ob);
+ DRW_shgroup_call_add(stl->g_data->shgroup_fallback, geom, ob->obmat);
+ ok = true;
+ }
+ else {
+ for (int i = 0; i < me->totcol; i++) {
+ if (stl->g_data->shgroup_image_array[i]) {
+ DRW_shgroup_call_add(stl->g_data->shgroup_image_array[i], geom_array[i], ob->obmat);
+ }
+ else {
+ DRW_shgroup_call_add(stl->g_data->shgroup_fallback, geom_array[i], ob->obmat);
+ }
+ ok = true;
+ }
+ }
+ }
+ else {
+ struct Gwn_Batch *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 Gwn_Batch *geom = DRW_cache_mesh_surface_get(ob);
+ DRW_shgroup_call_add(stl->g_data->shgroup_fallback, geom, ob->obmat);
+ }
+ }
+
+ /* Face Mask */
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ if (use_face_sel) {
+ struct Gwn_Batch *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! dependant 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);
+}
+
+/* Create collection settings here.
+ *
+ * Be sure to add this function there :
+ * source/blender/draw/DRW_engine.h
+ * source/blender/blenkernel/intern/layer.c
+ * source/blenderplayer/bad_level_call_stubs/stubs.c
+ *
+ * And relevant collection settings to :
+ * source/blender/makesrna/intern/rna_scene.c
+ * source/blender/blenkernel/intern/layer.c
+ */
+#if 0
+void PAINT_TEXTURE_collection_settings_create(CollectionEngineSettings *ces)
+{
+ BLI_assert(ces);
+ // BKE_collection_engine_property_add_int(ces, "my_bool_prop", false);
+ // BKE_collection_engine_property_add_int(ces, "my_int_prop", 0);
+ // BKE_collection_engine_property_add_float(ces, "my_float_prop", 0.0f);
+}
+#endif
+
+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
+};
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..68bdf6d1304
--- /dev/null
+++ b/source/blender/draw/modes/paint_vertex_mode.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 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"
+
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+extern struct GlobalsUboStorage ts; /* draw_common.c */
+
+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 = GPU_shader_get_builtin_shader(GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR_ALPHA);
+ }
+
+ 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);
+ }
+}
+
+static float world_light;
+
+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;
+
+ 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_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
+
+ stl->g_data->fvcolor_shgrp = DRW_shgroup_create(e_data.vcolor_face_shader, psl->vcolor_faces);
+
+ static float light[3] = {-0.3f, 0.5f, 1.0f};
+ static float alpha = 1.0f;
+ DRW_shgroup_uniform_vec3(stl->g_data->fvcolor_shgrp, "light", light, 1);
+ DRW_shgroup_uniform_float(stl->g_data->fvcolor_shgrp, "alpha", &alpha, 1);
+ DRW_shgroup_uniform_float(stl->g_data->fvcolor_shgrp, "global", &world_light, 1);
+ }
+
+ {
+ psl->wire_overlay = DRW_pass_create(
+ "Wire Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
+
+ stl->g_data->lwire_shgrp = DRW_shgroup_create(e_data.wire_overlay_shader, psl->wire_overlay);
+ }
+
+ {
+ psl->face_overlay = DRW_pass_create(
+ "Face Mask Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | 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();
+
+ if ((ob->type == OB_MESH) && (ob == draw_ctx->obact)) {
+ IDProperty *ces_mode_pw = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_PAINT_VERTEX, "");
+ const Mesh *me = ob->data;
+ const bool use_wire = BKE_collection_engine_property_value_get_bool(ces_mode_pw, "use_wire");
+ const bool use_surface = DRW_object_is_mode_shade(ob) == true;
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ struct Gwn_Batch *geom;
+
+ world_light = BKE_collection_engine_property_value_get_bool(ces_mode_pw, "use_shading") ? 0.5f : 1.0f;
+
+ 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.wire_overlay_shader);
+}
+
+void PAINT_VERTEX_collection_settings_create(IDProperty *properties)
+{
+ BLI_assert(properties &&
+ properties->type == IDP_GROUP &&
+ properties->subtype == IDP_GROUP_SUB_MODE_PAINT_VERTEX);
+
+ BKE_collection_engine_property_add_bool(properties, "use_shading", true);
+ BKE_collection_engine_property_add_bool(properties, "use_wire", false);
+}
+
+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
+};
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..809be5ef8b1
--- /dev/null
+++ b/source/blender/draw/modes/paint_weight_mode.c
@@ -0,0 +1,253 @@
+/*
+ * 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 "BKE_mesh.h"
+
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+extern struct GlobalsUboStorage ts; /* draw_common.c */
+
+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))
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ if (e_data.actdef != draw_ctx->obact->actdef) {
+ e_data.actdef = draw_ctx->obact->actdef;
+
+ BKE_mesh_batch_cache_dirty(draw_ctx->obact->data, BKE_MESH_BATCH_DIRTY_NOCHECK);
+ }
+
+ if (!e_data.weight_face_shader) {
+ e_data.weight_face_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR_ALPHA);
+ }
+
+ 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 float world_light;
+
+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;
+
+ 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_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
+
+ stl->g_data->fweights_shgrp = DRW_shgroup_create(e_data.weight_face_shader, psl->weight_faces);
+
+ static float light[3] = {-0.3f, 0.5f, 1.0f};
+ static float alpha = 1.0f;
+ DRW_shgroup_uniform_vec3(stl->g_data->fweights_shgrp, "light", light, 1);
+ DRW_shgroup_uniform_float(stl->g_data->fweights_shgrp, "alpha", &alpha, 1);
+ DRW_shgroup_uniform_float(stl->g_data->fweights_shgrp, "global", &world_light, 1);
+ }
+
+ {
+ psl->wire_overlay = DRW_pass_create(
+ "Wire Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
+
+ stl->g_data->lwire_shgrp = DRW_shgroup_create(e_data.wire_overlay_shader, psl->wire_overlay);
+ }
+
+ {
+ psl->face_overlay = DRW_pass_create(
+ "Face Mask Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | 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);
+
+ stl->g_data->vert_shgrp = DRW_shgroup_create(e_data.vert_overlay_shader, psl->vert_overlay);
+ }
+}
+
+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();
+
+ if ((ob->type == OB_MESH) && (ob == draw_ctx->obact)) {
+ IDProperty *ces_mode_pw = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_PAINT_WEIGHT, "");
+ const Mesh *me = ob->data;
+ const bool use_wire = BKE_collection_engine_property_value_get_bool(ces_mode_pw, "use_wire");
+ const bool use_surface = DRW_object_is_mode_shade(ob) == true;
+ 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 Gwn_Batch *geom;
+
+ world_light = BKE_collection_engine_property_value_get_bool(ces_mode_pw, "use_shading") ? 0.5f : 1.0f;
+
+ if (use_surface) {
+ geom = DRW_cache_mesh_surface_weights_get(ob);
+ 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.wire_overlay_shader);
+ DRW_SHADER_FREE_SAFE(e_data.vert_overlay_shader);
+}
+
+void PAINT_WEIGHT_collection_settings_create(IDProperty *properties)
+{
+ BLI_assert(properties &&
+ properties->type == IDP_GROUP &&
+ properties->subtype == IDP_GROUP_SUB_MODE_PAINT_WEIGHT);
+
+ BKE_collection_engine_property_add_bool(properties, "use_shading", true);
+ BKE_collection_engine_property_add_bool(properties, "use_wire", false);
+}
+
+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
+};
diff --git a/source/blender/draw/modes/particle_mode.c b/source/blender/draw/modes/particle_mode.c
new file mode 100644
index 00000000000..dd22a5c6d8f
--- /dev/null
+++ b/source/blender/draw/modes/particle_mode.c
@@ -0,0 +1,263 @@
+/*
+ * 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"
+
+/* If builtin shaders are needed */
+#include "GPU_shader.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+/* *********** LISTS *********** */
+/* All lists are per viewport specific datas.
+ * They are all free when viewport changes engines
+ * or is free itself. Use PARTICLE_engine_init() to
+ * initialize most of them and PARTICLE_cache_init()
+ * for PARTICLE_PassList */
+
+typedef struct PARTICLE_PassList {
+ /* Declare all passes here and init them in
+ * PARTICLE_cache_init().
+ * Only contains (DRWPass *) */
+ struct DRWPass *pass;
+} PARTICLE_PassList;
+
+typedef struct PARTICLE_FramebufferList {
+ /* Contains all framebuffer objects needed by this engine.
+ * Only contains (GPUFrameBuffer *) */
+ struct GPUFrameBuffer *fb;
+} PARTICLE_FramebufferList;
+
+typedef struct PARTICLE_TextureList {
+ /* Contains all framebuffer textures / utility textures
+ * needed by this engine. Only viewport specific textures
+ * (not per object). Only contains (GPUTexture *) */
+ struct GPUTexture *texture;
+} PARTICLE_TextureList;
+
+typedef struct PARTICLE_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 PARTICLE_PrivateData *g_data;
+} PARTICLE_StorageList;
+
+typedef struct PARTICLE_Data {
+ /* Struct returned by DRW_viewport_engine_data_get.
+ * If you don't use one of these, just make it a (void *) */
+ // void *fbl;
+ void *engine_type; /* Required */
+ PARTICLE_FramebufferList *fbl;
+ PARTICLE_TextureList *txl;
+ PARTICLE_PassList *psl;
+ PARTICLE_StorageList *stl;
+} PARTICLE_Data;
+
+/* *********** STATIC *********** */
+
+static struct {
+ /* Custom shaders :
+ * Add sources to source/blender/draw/modes/shaders
+ * init in PARTICLE_engine_init();
+ * free in PARTICLE_engine_free(); */
+ struct GPUShader *custom_shader;
+} e_data = {NULL}; /* Engine data */
+
+typedef struct PARTICLE_PrivateData {
+ /* This keeps the references of the shading groups for
+ * easy access in PARTICLE_cache_populate() */
+ DRWShadingGroup *group;
+} PARTICLE_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+
+/* Init Textures, Framebuffers, Storage and Shaders.
+ * It is called for every frames.
+ * (Optional) */
+static void PARTICLE_engine_init(void *vedata)
+{
+ PARTICLE_TextureList *txl = ((PARTICLE_Data *)vedata)->txl;
+ PARTICLE_FramebufferList *fbl = ((PARTICLE_Data *)vedata)->fbl;
+ PARTICLE_StorageList *stl = ((PARTICLE_Data *)vedata)->stl;
+
+ UNUSED_VARS(txl, fbl, stl);
+
+ /* Init Framebuffers like this: order is attachment order (for color texs) */
+ /*
+ * DRWFboTexture tex[2] = {{&txl->depth, DRW_TEX_DEPTH_24, 0},
+ * {&txl->color, DRW_TEX_RGBA_8, 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.custom_shader) {
+ e_data.custom_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 PARTICLE_cache_init(void *vedata)
+{
+ PARTICLE_PassList *psl = ((PARTICLE_Data *)vedata)->psl;
+ PARTICLE_StorageList *stl = ((PARTICLE_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 | 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_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 = DRW_shgroup_create(e_data.custom_shader, psl->pass);
+
+ /* 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] = {0.2f, 0.5f, 0.3f, 1.0};
+ DRW_shgroup_uniform_vec4(stl->g_data->group, "color", color, 1);
+ }
+
+}
+
+/* Add geometry to shadingGroups. Execute for each objects */
+static void PARTICLE_cache_populate(void *vedata, Object *ob)
+{
+ PARTICLE_PassList *psl = ((PARTICLE_Data *)vedata)->psl;
+ PARTICLE_StorageList *stl = ((PARTICLE_Data *)vedata)->stl;
+
+ UNUSED_VARS(psl, stl);
+
+ if (ob->type == OB_MESH) {
+ /* Get geometry cache */
+ struct Gwn_Batch *geom = DRW_cache_mesh_surface_get(ob);
+
+ /* Add geom to a shading group */
+ DRW_shgroup_call_add(stl->g_data->group, geom, ob->obmat);
+ }
+}
+
+/* Optional: Post-cache_populate callback */
+static void PARTICLE_cache_finish(void *vedata)
+{
+ PARTICLE_PassList *psl = ((PARTICLE_Data *)vedata)->psl;
+ PARTICLE_StorageList *stl = ((PARTICLE_Data *)vedata)->stl;
+
+ /* Do something here! dependant on the objects gathered */
+ UNUSED_VARS(psl, stl);
+}
+
+/* Draw time ! Control rendering pipeline from here */
+static void PARTICLE_draw_scene(void *vedata)
+{
+
+ PARTICLE_PassList *psl = ((PARTICLE_Data *)vedata)->psl;
+ PARTICLE_FramebufferList *fbl = ((PARTICLE_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 PARTICLE_engine_free(void)
+{
+ // DRW_SHADER_FREE_SAFE(custom_shader);
+}
+
+/* Create collection settings here.
+ *
+ * Be sure to add this function there :
+ * source/blender/draw/DRW_engine.h
+ * source/blender/blenkernel/intern/layer.c
+ * source/blenderplayer/bad_level_call_stubs/stubs.c
+ *
+ * And relevant collection settings to :
+ * source/blender/makesrna/intern/rna_scene.c
+ * source/blender/blenkernel/intern/layer.c
+ */
+#if 0
+void PARTICLE_collection_settings_create(CollectionEngineSettings *ces)
+{
+ BLI_assert(ces);
+ // BKE_collection_engine_property_add_int(ces, "my_bool_prop", false);
+ // BKE_collection_engine_property_add_int(ces, "my_int_prop", 0);
+ // BKE_collection_engine_property_add_float(ces, "my_float_prop", 0.0f);
+}
+#endif
+
+static const DrawEngineDataSize PARTICLE_data_size = DRW_VIEWPORT_DATA_SIZE(PARTICLE_Data);
+
+DrawEngineType draw_engine_particle_type = {
+ NULL, NULL,
+ N_("ParticleMode"),
+ &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
+};
diff --git a/source/blender/draw/modes/pose_mode.c b/source/blender/draw/modes/pose_mode.c
new file mode 100644
index 00000000000..77688f9156c
--- /dev/null
+++ b/source/blender/draw/modes/pose_mode.c
@@ -0,0 +1,197 @@
+/*
+ * 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 "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;
+ struct DRWPass *bone_wire;
+ struct DRWPass *bone_envelope;
+ struct DRWPass *relationship;
+} 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 *relationship_lines;
+} POSE_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+
+/* 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;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ {
+ /* Solid bones */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS;
+ psl->bone_solid = DRW_pass_create("Bone Solid Pass", state);
+ }
+
+ {
+ /* Wire bones */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND;
+ psl->bone_wire = DRW_pass_create("Bone Wire Pass", state);
+ }
+
+ {
+ /* distance outline around envelope bones */
+ DRWState state = DRW_STATE_ADDITIVE | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND;
+ psl->bone_envelope = DRW_pass_create("Bone Envelope Outline Pass", state);
+ }
+
+ {
+ /* Non Meshes Pass (Camera, empties, lamps ...) */
+ DRWState state =
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS |
+ DRW_STATE_BLEND | DRW_STATE_WIRE;
+ psl->relationship = DRW_pass_create("Bone Relationship Pass", state);
+
+ /* Relationship Lines */
+ stl->g_data->relationship_lines = shgroup_dynlines_uniform_color(psl->relationship, ts.colorWire);
+ DRW_shgroup_state_enable(stl->g_data->relationship_lines, DRW_STATE_STIPPLE_3);
+ }
+}
+
+/* Add geometry to shadingGroups. Execute for each objects */
+static void POSE_cache_populate(void *vedata, Object *ob)
+{
+ POSE_PassList *psl = ((POSE_Data *)vedata)->psl;
+ POSE_StorageList *stl = ((POSE_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ /* In the future this will allow us to implement face manipulators,
+ * and similar functionalities. For now we handle only pose bones. */
+
+ if (ob->type == OB_ARMATURE) {
+ if (DRW_pose_mode_armature(ob, draw_ctx->obact)) {
+ DRW_shgroup_armature_pose(
+ ob, psl->bone_solid, psl->bone_wire, psl->bone_envelope,
+ stl->g_data->relationship_lines);
+ }
+ }
+}
+
+/**
+ * Return true if armature should be handled by the pose mode engine.
+ */
+bool DRW_pose_mode_armature(Object *ob, Object *active_ob)
+{
+ /* Pode armature is handled by pose mode engine. */
+ if ((ob == active_ob) && ((ob->mode & OB_MODE_POSE) != 0)) {
+ return true;
+ }
+
+ /* Armature parent is also handled by pose mode engine. */
+ if ((active_ob != NULL) && ((active_ob->mode & OB_MODE_WEIGHT_PAINT) != 0)) {
+ if (active_ob->parent == ob) {
+ 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;
+
+ DRW_draw_pass(psl->bone_envelope);
+ DRW_draw_pass(psl->bone_wire);
+ DRW_draw_pass(psl->bone_solid);
+ DRW_draw_pass(psl->relationship);
+}
+
+/* Create collection settings here.
+ *
+ * Be sure to add this function there :
+ * source/blender/draw/DRW_engine.h
+ * source/blender/blenkernel/intern/layer.c
+ * source/blenderplayer/bad_level_call_stubs/stubs.c
+ *
+ * And relevant collection settings to :
+ * source/blender/makesrna/intern/rna_scene.c
+ * source/blender/blenkernel/intern/layer.c
+ */
+#if 0
+void POSE_collection_settings_create(CollectionEngineSettings *ces)
+{
+ BLI_assert(ces);
+ // BKE_collection_engine_property_add_int(ces, "foo", 37);
+}
+#endif
+
+static const DrawEngineDataSize POSE_data_size = DRW_VIEWPORT_DATA_SIZE(POSE_Data);
+
+DrawEngineType draw_engine_pose_type = {
+ NULL, NULL,
+ N_("PoseMode"),
+ &POSE_data_size,
+ NULL,
+ NULL,
+ &POSE_cache_init,
+ &POSE_cache_populate,
+ NULL,
+ NULL,
+ &POSE_draw_scene
+};
diff --git a/source/blender/draw/modes/sculpt_mode.c b/source/blender/draw/modes/sculpt_mode.c
new file mode 100644
index 00000000000..a3f29b5bb8f
--- /dev/null
+++ b/source/blender/draw/modes/sculpt_mode.c
@@ -0,0 +1,299 @@
+/*
+ * 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"
+
+/* If builtin shaders are needed */
+#include "GPU_shader.h"
+#include "GPU_matrix.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+/* *********** 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_get.
+ * 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);
+
+ /* Init Framebuffers like this: order is attachment order (for color texs) */
+ /*
+ * DRWFboTexture tex[2] = {{&txl->depth, DRW_TEX_DEPTH_24, 0},
+ * {&txl->color, DRW_TEX_RGBA_8, 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.shader_flat) {
+ e_data.shader_flat = GPU_shader_get_builtin_shader(GPU_SHADER_3D_FLAT_COLOR);
+ }
+ if (!e_data.shader_smooth) {
+ e_data.shader_smooth = GPU_shader_get_builtin_shader(GPU_SHADER_3D_SMOOTH_COLOR);
+ }
+}
+
+/* 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;
+ }
+}
+
+/* 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(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;
+
+ /* Add geom to a shading group */
+ DRW_shgroup_call_sculpt_add(shgroup, 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! dependant 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(custom_shader);
+}
+
+/* Create collection settings here.
+ *
+ * Be sure to add this function there :
+ * source/blender/draw/DRW_engine.h
+ * source/blender/blenkernel/intern/layer.c
+ * source/blenderplayer/bad_level_call_stubs/stubs.c
+ *
+ * And relevant collection settings to :
+ * source/blender/makesrna/intern/rna_scene.c
+ * source/blender/blenkernel/intern/layer.c
+ */
+#if 0
+void SCULPT_collection_settings_create(CollectionEngineSettings *ces)
+{
+ BLI_assert(ces);
+ // BKE_collection_engine_property_add_int(ces, "my_bool_prop", false);
+ // BKE_collection_engine_property_add_int(ces, "my_int_prop", 0);
+ // BKE_collection_engine_property_add_float(ces, "my_float_prop", 0.0f);
+}
+#endif
+
+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
+};
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..dc36d252926
--- /dev/null
+++ b/source/blender/draw/modes/shaders/common_globals_lib.glsl
@@ -0,0 +1,58 @@
+
+/* keep in sync with GlobalsUboStorage */
+layout(std140) uniform globalsBlock {
+ vec4 colorWire;
+ vec4 colorWireEdit;
+ vec4 colorActive;
+ vec4 colorSelect;
+ vec4 colorTransform;
+ vec4 colorGroupActive;
+ vec4 colorGroupSelect;
+ vec4 colorGroup;
+ vec4 colorLibrarySelect;
+ vec4 colorLibrary;
+ vec4 colorLamp;
+ vec4 colorSpeaker;
+ vec4 colorCamera;
+ vec4 colorEmpty;
+ vec4 colorVertex;
+ vec4 colorVertexSelect;
+ vec4 colorEditMeshActive;
+ vec4 colorEdgeSelect;
+ vec4 colorEdgeSeam;
+ vec4 colorEdgeSharp;
+ vec4 colorEdgeCrease;
+ vec4 colorEdgeBWeight;
+ vec4 colorEdgeFaceSelect;
+ vec4 colorFace;
+ vec4 colorFaceSelect;
+ vec4 colorNormal;
+ vec4 colorVNormal;
+ vec4 colorLNormal;
+ vec4 colorFaceDot;
+
+ vec4 colorDeselect;
+ vec4 colorOutline;
+ vec4 colorLampNoAlpha;
+
+ vec4 colorBackground;
+
+ 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;
+};
diff --git a/source/blender/draw/modes/shaders/edit_curve_overlay_frag.glsl b/source/blender/draw/modes/shaders/edit_curve_overlay_frag.glsl
new file mode 100644
index 00000000000..e78462b6915
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_curve_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_curve_overlay_loosevert_vert.glsl b/source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl
new file mode 100644
index 00000000000..9150ef8cd63
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl
@@ -0,0 +1,39 @@
+
+/* Draw Curve 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_Position = pPos;
+ gl_PointSize = sizeVertex;
+}
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_facedot_frag.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_frag.glsl
new file mode 100644
index 00000000000..9b3fe6286e8
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_frag.glsl
@@ -0,0 +1,12 @@
+
+flat in int isSelected;
+
+out vec4 FragColor;
+
+void main()
+{
+ if (isSelected != 0)
+ FragColor = colorFaceDot;
+ else
+ FragColor = colorWireEdit;
+}
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..2e541fa75e6
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_vert.glsl
@@ -0,0 +1,14 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in vec4 norAndFlag;
+
+flat out int isSelected;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ gl_PointSize = sizeFaceDot;
+ isSelected = int(norAndFlag.w);
+}
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..049333c8e4f
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl
@@ -0,0 +1,29 @@
+
+/* Solid Wirefram implementation
+ * Mike Erwin, Clément Foucault */
+
+/* This shader follows the principles of
+ * http://developer.download.nvidia.com/SDK/10/direct3d/Source/SolidWireframe/Doc/SolidWireframe.pdf */
+
+flat in vec4 faceColor;
+flat in int faceActive;
+
+out vec4 FragColor;
+
+const mat4 stipple_matrix = mat4(
+ vec4(1.0, 0.0, 0.0, 0.0),
+ vec4(0.0, 0.0, 0.0, 0.0),
+ vec4(0.0, 0.0, 1.0, 0.0),
+ vec4(0.0, 0.0, 0.0, 0.0)
+);
+
+void main()
+{
+ FragColor = faceColor;
+
+ if (faceActive == 1) {
+ int x = int(gl_FragCoord.x) & 0x3; /* mod 4 */
+ int y = int(gl_FragCoord.y) & 0x3; /* mod 4 */
+ FragColor *= stipple_matrix[x][y];
+ }
+}
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..3b9aa77306f
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_vert.glsl
@@ -0,0 +1,29 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in ivec4 data;
+
+flat out vec4 faceColor;
+flat out int faceActive;
+
+#define FACE_ACTIVE (1 << 2)
+#define FACE_SELECTED (1 << 3)
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+
+ if ((data.x & FACE_ACTIVE) != 0) {
+ faceColor = colorEditMeshActive;
+ faceActive = 1;
+ }
+ else if ((data.x & FACE_SELECTED) != 0) {
+ faceColor = colorFaceSelect;
+ faceActive = 0;
+ }
+ else {
+ faceColor = colorFace;
+ faceActive = 0;
+ }
+}
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..a8f74ac3e0f
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl
@@ -0,0 +1,187 @@
+
+/* Solid Wirefram implementation
+ * Mike Erwin, Clément Foucault */
+
+/* This shader follows the principles of
+ * http://developer.download.nvidia.com/SDK/10/direct3d/Source/SolidWireframe/Doc/SolidWireframe.pdf */
+
+uniform float faceAlphaMod;
+
+flat in vec3 edgesCrease;
+flat in vec3 edgesBweight;
+flat in ivec3 flag;
+flat in vec4 faceColor;
+flat in int clipCase;
+#ifdef VERTEX_SELECTION
+in vec3 vertexColor;
+#endif
+
+/* We use a vec4[2] interface to pass edge data
+ * (without fragmenting memory accesses)
+ *
+ * There are 2 cases :
+ *
+ * - Simple case : geometry shader return edge distances
+ * in the first 2 components of the first vec4.
+ * This needs noperspective interpolation.
+ * The rest is filled with vertex screen positions.
+ * eData1.zw actually contain v2
+ * eData2.xy actually contain v1
+ * eData2.zw actually contain v0
+ *
+ * - Hard case : two 2d edge corner are described by each
+ * vec4 as origin and direction. This is constant over
+ * the triangle and use to detect the correct case. */
+
+noperspective in vec4 eData1;
+flat in vec4 eData2;
+
+out vec4 FragColor;
+
+#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)
+/* Vertex flag is shifted and combined with the edge flag */
+#define VERTEX_ACTIVE (1 << (0 + 8))
+#define VERTEX_SELECTED (1 << (1 + 8))
+#define FACE_ACTIVE (1 << (2 + 8))
+
+/* Style Parameters in pixel */
+
+/* Array to retrieve vert/edge indices */
+const ivec3 clipEdgeIdx[6] = ivec3[6](
+ ivec3(1, 0, 2),
+ ivec3(2, 0, 1),
+ ivec3(2, 1, 0),
+ ivec3(2, 1, 0),
+ ivec3(2, 0, 1),
+ ivec3(1, 0, 2)
+);
+
+const ivec3 clipPointIdx[6] = ivec3[6](
+ ivec3(0, 1, 2),
+ ivec3(0, 2, 1),
+ ivec3(0, 2, 1),
+ ivec3(1, 2, 0),
+ ivec3(1, 2, 0),
+ ivec3(2, 1, 0)
+);
+
+const mat4 stipple_matrix = mat4(
+ vec4(1.0, 0.0, 0.0, 0.0),
+ vec4(0.0, 0.0, 0.0, 0.0),
+ vec4(0.0, 0.0, 1.0, 0.0),
+ vec4(0.0, 0.0, 0.0, 0.0)
+);
+
+void colorDist(vec4 color, float dist)
+{
+ FragColor = (dist < 0) ? color : FragColor;
+}
+
+float distToEdge(vec2 o, vec2 dir)
+{
+ vec2 af = gl_FragCoord.xy - o;
+ float daf = dot(dir, af);
+ return sqrt(abs(dot(af, af) - daf * daf));
+}
+
+void main()
+{
+ vec3 e, p;
+
+ /* Step 1 : Computing Distances */
+
+ if (clipCase == 0) {
+ e.xy = eData1.xy;
+
+ /* computing missing distance */
+ vec2 dir = normalize(eData2.zw - eData2.xy);
+ e.z = distToEdge(eData2.zw, dir);
+
+ p.x = distance(eData2.zw, gl_FragCoord.xy);
+ p.y = distance(eData2.xy, gl_FragCoord.xy);
+ p.z = distance(eData1.zw, gl_FragCoord.xy);
+ }
+ else {
+ ivec3 eidxs = clipEdgeIdx[clipCase - 1];
+ ivec3 pidxs = clipPointIdx[clipCase - 1];
+
+ e[eidxs.x] = distToEdge(eData1.xy, eData1.zw);
+ e[eidxs.y] = distToEdge(eData2.xy, eData2.zw);
+
+ /* Three edges visible cases */
+ if (clipCase == 1 || clipCase == 2 || clipCase == 4) {
+ e[eidxs.z] = distToEdge(eData1.xy, normalize(eData2.xy - eData1.xy));
+ p[pidxs.y] = distance(eData2.xy, gl_FragCoord.xy);
+ }
+ else {
+ e[eidxs.z] = 1e10; /* off screen */
+ p[pidxs.y] = 1e10; /* off screen */
+ }
+
+ p[pidxs.x] = distance(eData1.xy, gl_FragCoord.xy);
+ p[pidxs.z] = 1e10; /* off screen */
+ }
+
+ /* Step 2 : coloring (order dependant) */
+
+ /* First */
+ FragColor = faceColor;
+
+ if ((flag[0] & FACE_ACTIVE) != 0) {
+ int x = int(gl_FragCoord.x) & 0x3; /* mod 4 */
+ int y = int(gl_FragCoord.y) & 0x3; /* mod 4 */
+ FragColor *= stipple_matrix[x][y];
+ }
+ else {
+ FragColor.a *= faceAlphaMod;
+ }
+
+ /* Edges */
+ for (int v = 0; v < 3; ++v) {
+ if ((flag[v] & EDGE_EXISTS) != 0) {
+ float largeEdge = e[v] - sizeEdge * 2.0;
+ float innerEdge = e[v] - sizeEdge;
+
+ if ((flag[v] & EDGE_SEAM) != 0)
+ colorDist(colorEdgeSeam, largeEdge);
+ else if (edgesBweight[v] > 0.0)
+ colorDist(vec4(colorEdgeBWeight.rgb, edgesBweight[v]), largeEdge);
+ else if (edgesCrease[v] > 0.0)
+ colorDist(vec4(colorEdgeCrease.rgb, edgesCrease[v]), largeEdge);
+ else if ((flag[v] & EDGE_SHARP) != 0)
+ colorDist(colorEdgeSharp, largeEdge);
+#ifndef VERTEX_SELECTION
+ else
+ colorDist(colorWireEdit, innerEdge);
+
+ if ((flag[v] & EDGE_ACTIVE) != 0)
+ colorDist(vec4(colorEditMeshActive.xyz, 1.0), innerEdge);
+ else if ((flag[v] & EDGE_SELECTED) != 0)
+ colorDist(colorEdgeSelect, innerEdge);
+#else
+ colorDist(vec4(vertexColor, 1.0), innerEdge);
+#endif
+ }
+ }
+
+ /* Points */
+#ifdef VERTEX_SELECTION
+ for (int v = 0; v < 3; ++v) {
+ float size = p[v] - sizeVertex;
+
+ if ((flag[v] & VERTEX_ACTIVE) != 0)
+ colorDist(vec4(colorEditMeshActive.xyz, 1.0), size);
+ else if ((flag[v] & VERTEX_SELECTED) != 0)
+ colorDist(colorVertexSelect, size);
+ else
+ colorDist(colorVertex, size);
+ }
+#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..5e3ecd59cb4
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_edge.glsl
@@ -0,0 +1,143 @@
+
+/* Solid Wirefram implementation
+ * Mike Erwin, Clément Foucault */
+
+/* This shader follows the principles of
+ * http://developer.download.nvidia.com/SDK/10/direct3d/Source/SolidWireframe/Doc/SolidWireframe.pdf */
+
+layout(lines) in;
+layout(triangle_strip, max_vertices=6) out;
+
+uniform mat4 ProjectionMatrix;
+uniform vec2 viewportSize;
+
+in vec4 vPos[];
+in vec4 pPos[];
+in ivec4 vData[];
+
+/* these are the same for all vertices
+ * and does not need interpolation */
+flat out vec3 edgesCrease;
+flat out vec3 edgesBweight;
+flat out ivec3 flag;
+flat out vec4 faceColor;
+flat out int clipCase;
+#ifdef VERTEX_SELECTION
+out vec3 vertexColor;
+#endif
+
+/* See fragment shader */
+noperspective out vec4 eData1;
+flat out vec4 eData2;
+
+#define VERTEX_ACTIVE (1 << 0)
+#define VERTEX_SELECTED (1 << 1)
+
+#define FACE_ACTIVE (1 << 2)
+#define FACE_SELECTED (1 << 3)
+
+/* Table 1. Triangle Projection Cases */
+const ivec4 clipPointsIdx[6] = ivec4[6](
+ ivec4(0, 1, 2, 2),
+ ivec4(0, 2, 1, 1),
+ ivec4(0, 0, 1, 2),
+ ivec4(1, 2, 0, 0),
+ ivec4(1, 1, 0, 2),
+ ivec4(2, 2, 0, 1)
+);
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+}
+
+float dist(vec2 pos[3], vec2 vpos, int v)
+{
+ /* endpoints of opposite edge */
+ vec2 e1 = pos[(v + 1) % 3];
+ vec2 e2 = pos[(v + 2) % 3];
+ /* Edge normalized vector */
+ vec2 dir = normalize(e2 - e1);
+ /* perpendicular to dir */
+ vec2 orthogonal = vec2(-dir.y, dir.x);
+
+ return abs(dot(vpos - e1, orthogonal));
+}
+
+vec3 getVertexColor(int v)
+{
+ if ((vData[v].x & (VERTEX_ACTIVE | VERTEX_SELECTED)) != 0)
+ return colorEdgeSelect.rgb;
+ else
+ return colorWireEdit.rgb;
+}
+
+void doVertex(int v, vec4 pos)
+{
+#ifdef VERTEX_SELECTION
+ vertexColor = getVertexColor(v);
+#endif
+
+ gl_Position = pos;
+
+ EmitVertex();
+}
+
+void main()
+{
+ clipCase = 0;
+
+ /* 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) {
+ /* vPos[i].z is negative and we don't want
+ * our fixvec to be flipped */
+ dirs1 *= -vPos[0].z;
+ dirs2 *= -vPos[1].z;
+ }
+
+ /* Edge / Vert data */
+ eData1 = vec4(1e10);
+ eData2.zw = pos[0];
+ eData2.xy = pos[1];
+ flag[0] = (vData[0].x << 8);
+ flag[1] = (vData[1].x << 8);
+ flag[2] = 0;
+
+ doVertex(0, pPos[0] + vec4(-dirs1.xy, 0.0, 0.0));
+ 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 | (vData[0].x << 8);
+ 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));
+
+ flag[2] = 0;
+ doVertex(1, pPos[1] + vec4( dirs2.xy, 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..64809a37d11
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl
@@ -0,0 +1,277 @@
+
+/* Solid Wirefram implementation
+ * Mike Erwin, Clément Foucault */
+
+/* This shader follows the principles of
+ * http://developer.download.nvidia.com/SDK/10/direct3d/Source/SolidWireframe/Doc/SolidWireframe.pdf */
+
+layout(triangles) in;
+
+#ifdef EDGE_FIX
+/* To fix the edge artifacts, we render
+ * an outline strip around the screenspace
+ * triangle. Order is important.
+ * TODO diagram
+ */
+
+#ifdef VERTEX_SELECTION
+layout(triangle_strip, max_vertices=23) out;
+#else
+layout(triangle_strip, max_vertices=17) out;
+#endif
+#else
+layout(triangle_strip, max_vertices=3) out;
+#endif
+
+uniform mat4 ProjectionMatrix;
+uniform vec2 viewportSize;
+
+in vec4 vPos[];
+in vec4 pPos[];
+in ivec4 vData[];
+
+/* these are the same for all vertices
+ * and does not need interpolation */
+flat out vec3 edgesCrease;
+flat out vec3 edgesBweight;
+flat out ivec3 flag;
+flat out vec4 faceColor;
+flat out int clipCase;
+#ifdef VERTEX_SELECTION
+out vec3 vertexColor;
+#endif
+
+/* See fragment shader */
+noperspective out vec4 eData1;
+flat out vec4 eData2;
+
+
+#define VERTEX_ACTIVE (1 << 0)
+#define VERTEX_SELECTED (1 << 1)
+
+#define FACE_ACTIVE (1 << 2)
+#define FACE_SELECTED (1 << 3)
+
+/* Table 1. Triangle Projection Cases */
+const ivec4 clipPointsIdx[6] = ivec4[6](
+ ivec4(0, 1, 2, 2),
+ ivec4(0, 2, 1, 1),
+ ivec4(0, 0, 1, 2),
+ ivec4(1, 2, 0, 0),
+ ivec4(1, 1, 0, 2),
+ ivec4(2, 2, 0, 1)
+);
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+}
+
+float dist(vec2 pos[3], vec2 vpos, int v)
+{
+ /* endpoints of opposite edge */
+ vec2 e1 = pos[(v + 1) % 3];
+ vec2 e2 = pos[(v + 2) % 3];
+ /* Edge normalized vector */
+ vec2 dir = normalize(e2 - e1);
+ /* perpendicular to dir */
+ vec2 orthogonal = vec2(-dir.y, dir.x);
+
+ return abs(dot(vpos - e1, orthogonal));
+}
+
+vec3 getVertexColor(int v)
+{
+ if ((vData[v].x & (VERTEX_ACTIVE | VERTEX_SELECTED)) != 0)
+ return colorEdgeSelect.rgb;
+ else
+ return colorWireEdit.rgb;
+}
+
+vec4 getClipData(vec2 pos[3], ivec2 vidx)
+{
+ vec2 A = pos[vidx.x];
+ vec2 Adir = normalize(A - pos[vidx.y]);
+
+ return vec4(A, Adir);
+}
+
+void doVertex(int v, vec4 pos)
+{
+#ifdef VERTEX_SELECTION
+ vertexColor = getVertexColor(v);
+#endif
+
+ gl_Position = pos;
+
+ EmitVertex();
+}
+
+void main()
+{
+ /* First we detect which case we are in */
+ clipCase = 0;
+
+ /* if perspective */
+ if (ProjectionMatrix[3][3] == 0.0) {
+ /* See Table 1. Triangle Projection Cases */
+ clipCase += int(pPos[0].z / pPos[0].w < -1 || vPos[0].z > 0.0) * 4;
+ clipCase += int(pPos[1].z / pPos[1].w < -1 || vPos[1].z > 0.0) * 2;
+ clipCase += int(pPos[2].z / pPos[2].w < -1 || vPos[2].z > 0.0) * 1;
+ }
+
+ /* If triangle is behind nearplane, early out */
+ if (clipCase == 7)
+ return;
+
+ /* Edge */
+ ivec3 eflag; vec3 ecrease, ebweight;
+ for (int v = 0; v < 3; ++v) {
+ flag[v] = eflag[v] = vData[v].y | (vData[v].x << 8);
+ edgesCrease[v] = ecrease[v] = vData[v].z / 255.0;
+ edgesBweight[v] = ebweight[v] = vData[v].w / 255.0;
+ }
+
+ /* Face */
+ if ((vData[0].x & FACE_ACTIVE) != 0)
+ faceColor = colorEditMeshActive;
+ else if ((vData[0].x & FACE_SELECTED) != 0)
+ faceColor = colorFaceSelect;
+ else
+ faceColor = colorFace;
+
+ /* Vertex */
+ vec2 pos[3] = vec2[3](proj(pPos[0]), proj(pPos[1]), proj(pPos[2]));
+
+ /* Simple case : compute edge distances in geometry shader */
+ if (clipCase == 0) {
+
+ /* Packing screen positions and 2 distances */
+ eData1 = vec4(0.0, 0.0, pos[2]);
+ eData2 = vec4(pos[1], pos[0]);
+
+ /* Only pass the first 2 distances */
+ for (int v = 0; v < 2; ++v) {
+ eData1[v] = dist(pos, pos[v], v);
+ doVertex(v, pPos[v]);
+ eData1[v] = 0.0;
+ }
+
+ /* and the last vertex */
+ doVertex(2, pPos[2]);
+
+#ifdef EDGE_FIX
+ vec2 fixvec[6];
+ vec2 fixvecaf[6];
+ vec2 cornervec[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)
+ );
+
+ for (int i = 0; i < 3; ++i) {
+ int i1 = (i + 1) % 3;
+ int i2 = (i + 2) % 3;
+
+ vec2 v1 = pos[i] + bias[i];
+ vec2 v2 = pos[i1] + bias[i1];
+ vec2 v3 = pos[i2] + bias[i2];
+
+ /* Edge normalized vector */
+ vec2 dir = normalize(v2 - v1);
+ vec2 dir2 = normalize(v3 - v1);
+
+ cornervec[i] = -normalize(dir + dir2);
+
+ /* perpendicular to dir */
+ vec2 perp = vec2(-dir.y, dir.x);
+
+ /* Backface case */
+ if (dot(perp, dir2) > 0) {
+ perp = -perp;
+ }
+
+ /* Make it view independent */
+ perp *= sizeEdgeFix / viewportSize;
+ cornervec[i] *= sizeEdgeFix / viewportSize;
+ fixvec[i] = fixvecaf[i] = perp;
+
+ /* Perspective */
+ if (ProjectionMatrix[3][3] == 0.0) {
+ /* vPos[i].z is negative and we don't want
+ * our fixvec to be flipped */
+ fixvec[i] *= -vPos[i].z;
+ fixvecaf[i] *= -vPos[i1].z;
+ cornervec[i] *= -vPos[i].z;
+ }
+ }
+
+ /* to not let face color bleed */
+ faceColor = vec4(0.0);
+
+ /* we don't want other edges : make them far */
+ eData1 = vec4(1e10);
+
+ /* Start with the same last vertex to create a
+ * degenerate triangle in order to "create"
+ * a new triangle strip */
+ for (int i = 2; i < 5; ++i) {
+ int vbe = (i - 1) % 3;
+ int vaf = (i + 1) % 3;
+ int v = i % 3;
+
+ /* Position of the "hidden" third vertex */
+ eData1.zw = pos[vbe];
+
+ doVertex(v, pPos[v]);
+ doVertex(v, pPos[v] + vec4(fixvec[v], 0.0, 0.0));
+
+ /* Now one triangle only shade one edge
+ * so we use the edge distance calculated
+ * in the fragment shader, the third edge;
+ * we do this because we need flat interp to
+ * draw a continuous triangle strip */
+ eData2.xy = pos[vaf];
+ eData2.zw = pos[v];
+ flag[0] = (vData[v].x << 8);
+ flag[1] = (vData[vaf].x << 8);
+ flag[2] = eflag[vbe];
+ edgesCrease[2] = ecrease[vbe];
+ edgesBweight[2] = ebweight[vbe];
+
+ doVertex(vaf, pPos[vaf]);
+ doVertex(vaf, pPos[vaf] + vec4(fixvecaf[v], 0.0, 0.0));
+
+ /* corner vertices should not draw edges but draw point only */
+ flag[2] = (vData[vbe].x << 8);
+#ifdef VERTEX_SELECTION
+ doVertex(vaf, pPos[vaf]);
+ doVertex(vaf, pPos[vaf] + vec4(cornervec[vaf], 0.0, 0.0));
+#endif
+ }
+
+ /* finish the loop strip */
+ doVertex(2, pPos[2]);
+ doVertex(2, pPos[2] + vec4(fixvec[2], 0.0, 0.0));
+#endif
+ }
+ /* Harder case : compute visible edges vectors */
+ else {
+ ivec4 vindices = clipPointsIdx[clipCase - 1];
+
+ eData1 = getClipData(pos, vindices.xz);
+ eData2 = getClipData(pos, vindices.yw);
+
+ for (int v = 0; v < 3; ++v)
+ doVertex(v, pPos[v]);
+ }
+
+ EndPrimitive();
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_loosevert_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_loosevert_vert.glsl
new file mode 100644
index 00000000000..0a396a5325f
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_loosevert_vert.glsl
@@ -0,0 +1,59 @@
+
+/* Solid Wirefram implementation
+ * Mike Erwin, Clément Foucault */
+
+/* This shader follows the principles of
+ * http://developer.download.nvidia.com/SDK/10/direct3d/Source/SolidWireframe/Doc/SolidWireframe.pdf */
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec2 viewportSize;
+
+in vec3 pos;
+in ivec4 data;
+
+/* these are the same for all vertices
+ * and does not need interpolation */
+flat out vec3 edgesCrease;
+flat out vec3 edgesBweight;
+flat out ivec3 flag;
+flat out vec4 faceColor;
+flat out int clipCase;
+#ifdef VERTEX_SELECTION
+out vec3 vertexColor;
+#endif
+
+/* 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;
+ edgesCrease = vec3(0.0);
+ edgesBweight = vec3(0.0);
+
+ vec4 pPos = ModelViewProjectionMatrix * vec4(pos, 1.0);
+
+ /* there is no face */
+ faceColor = vec4(0.0);
+
+#ifdef VERTEX_SELECTION
+ vertexColor = vec3(0.0);
+#endif
+
+ /* only vertex position 0 is used */
+ eData1 = eData2 = vec4(1e10);
+ eData2.zw = proj(pPos);
+
+ flag = ivec3(0);
+ flag[0] = (data.x << 8);
+
+ gl_PointSize = sizeEdgeFix;
+ gl_Position = pPos;
+}
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..f567a3a5cbd
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_mix_frag.glsl
@@ -0,0 +1,24 @@
+
+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;
+
+ /* this works because not rendered depth is 1.0 and the
+ * following test is always true even when no wires */
+ if ((wire_depth > scene_depth) && (wire_color.a > 0)) {
+ /* Note : Using wire_color.a * alpha produce unwanted result */
+ FragColor.a = alpha;
+ }
+}
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..5bc9a8bef85
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl
@@ -0,0 +1,23 @@
+
+/* Solid Wirefram implementation
+ * Mike Erwin, Clément Foucault */
+
+/* This shader follows the principles of
+ * http://developer.download.nvidia.com/SDK/10/direct3d/Source/SolidWireframe/Doc/SolidWireframe.pdf */
+
+uniform mat4 ModelViewMatrix;
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in ivec4 data;
+
+out vec4 vPos;
+out vec4 pPos;
+out ivec4 vData;
+
+void main()
+{
+ vPos = ModelViewMatrix * vec4(pos, 1.0);
+ pPos = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ vData = data;
+}
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_image_frag.glsl b/source/blender/draw/modes/shaders/object_empty_image_frag.glsl
new file mode 100644
index 00000000000..eab107354d1
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_empty_image_frag.glsl
@@ -0,0 +1,21 @@
+
+flat in vec4 finalColor;
+
+#ifndef USE_WIRE
+in vec2 texCoord_interp;
+#endif
+
+out vec4 fragColor;
+
+#ifndef USE_WIRE
+uniform sampler2D image;
+#endif
+
+void main()
+{
+#ifdef USE_WIRE
+ fragColor = finalColor;
+#else
+ fragColor = finalColor * texture(image, texCoord_interp);
+#endif
+}
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..c629fdcb7ef
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_empty_image_vert.glsl
@@ -0,0 +1,38 @@
+
+uniform mat4 ViewProjectionMatrix;
+uniform vec2 aspect;
+
+/* ---- Instanciated Attribs ---- */
+in vec2 texCoord;
+in vec2 pos;
+/* ---- Per instance Attribs ---- */
+in mat4 InstanceModelMatrix;
+
+#ifdef USE_WIRE
+in vec3 color;
+#else
+in vec4 objectColor;
+#endif
+
+in float size;
+in vec2 offset;
+
+flat out vec4 finalColor;
+
+#ifndef USE_WIRE
+out vec2 texCoord_interp;
+#endif
+
+void main()
+{
+ gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(
+ (pos[0] + offset[0]) * (size * aspect[0]),
+ (pos[1] + offset[1]) * (size * aspect[1]),
+ 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..0196b1a6f98
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_grid_frag.glsl
@@ -0,0 +1,189 @@
+
+/* Infinite grid
+ * 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 gridOneOverLogSubdiv;
+
+#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_LINE_SMOOTH 1.15
+
+float get_grid(vec3 co, vec3 fwidthCos, float grid_size)
+{
+ float half_size = grid_size / 2.0;
+ /* triangular wave pattern, amplitude is [0, grid_size] */
+ vec3 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 and normalize */
+ grid_domain.x = min(grid_domain.x, min(grid_domain.y, grid_domain.z)) / grid_size;
+
+ return 1.0 - smoothstep(0.0, GRID_LINE_SMOOTH / grid_size, grid_domain.x);
+}
+
+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(0.0, GRID_LINE_SMOOTH, axes_domain - line_size);
+}
+
+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 p = -dot(planeNormal, camera_pos) / dot(planeNormal, 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 dependant.
+ * 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);
+ 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);
+ fade *= 1.0 - angle * angle * angle;
+ dist = 1.0 + angle * 2.0;
+ }
+ }
+
+ 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));
+
+ float gridA = get_grid(wPos, fwidthPos, scaleA);
+ float gridB = get_grid(wPos, fwidthPos, scaleB);
+ float gridC = get_grid(wPos, fwidthPos, scaleC);
+
+ FragColor = vec4(colorGrid.rgb, gridA * blend);
+ FragColor = mix(FragColor, vec4(mix(colorGrid.rgb, colorGridEmphasise.rgb, blend), 1.0), gridB);
+ FragColor = mix(FragColor, vec4(colorGridEmphasise.rgb, 1.0), 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 = mix(FragColor, colorGridAxisX, axes.x);
+ }
+ if ((gridFlag & AXIS_Y) > 0) {
+ FragColor = mix(FragColor, colorGridAxisY, axes.y);
+ }
+ if ((gridFlag & AXIS_Z) > 0) {
+ FragColor = mix(FragColor, colorGridAxisZ, axes.z);
+ }
+ }
+
+ FragColor.a *= fade;
+} \ No newline at end of file
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..2ecbfa8e11f
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_grid_vert.glsl
@@ -0,0 +1,63 @@
+
+/* Infinite grid
+ * Clément Foucault */
+
+uniform mat4 ViewProjectionOffsetMatrix;
+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 = ViewProjectionOffsetMatrix * vec4(realPos, 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..5565a0f1e09
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl
@@ -0,0 +1,61 @@
+
+in vec4 uvcoordsvar;
+
+out vec4 FragColor;
+
+uniform sampler2D outlineColor;
+uniform sampler2D outlineDepth;
+uniform sampler2D sceneDepth;
+
+uniform float alphaOcclu;
+uniform vec2 viewportSize;
+
+void search_outline(ivec2 uv, vec4 ref_col, inout bool ref_occlu, inout bool outline)
+{
+ if (!outline) {
+ vec4 color = texelFetch(outlineColor, uv, 0).rgba;
+ if (color != ref_col) {
+ outline = true;
+ }
+ else {
+ float depth = texelFetch(outlineDepth, uv, 0).r;
+ float scene_depth = texelFetch(sceneDepth, uv, 0).r;
+ bool occlu = (depth > scene_depth);
+
+ if (occlu != ref_occlu && !ref_occlu) {
+ outline = true;
+ }
+ }
+ }
+}
+
+void main()
+{
+ ivec2 uv = ivec2(gl_FragCoord.xy);
+ vec4 ref_col = texelFetch(outlineColor, uv, 0).rgba;
+
+ float depth = texelFetch(outlineDepth, uv, 0).r;
+ /* Modulate color if occluded */
+ float scene_depth = texelFetch(sceneDepth, uv, 0).r;
+
+ bool ref_occlu = (depth > scene_depth);
+
+ bool outline = false;
+
+ search_outline(uv + ivec2( 1, 0), ref_col, ref_occlu, outline);
+ search_outline(uv + ivec2( 0, 1), ref_col, ref_occlu, outline);
+ search_outline(uv + ivec2(-1, 0), ref_col, ref_occlu, outline);
+ search_outline(uv + ivec2( 0, -1), ref_col, ref_occlu, outline);
+
+ FragColor = ref_col;
+
+ /* We Hit something ! */
+ if (outline) {
+ if (ref_occlu) {
+ FragColor.a *= alphaOcclu;
+ }
+ }
+ else {
+ 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..e0568d1157a
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_outline_expand_frag.glsl
@@ -0,0 +1,45 @@
+
+in vec4 uvcoordsvar;
+
+out vec4 FragColor;
+
+uniform sampler2D outlineColor;
+uniform sampler2D outlineDepth;
+
+uniform float alpha;
+uniform bool doExpand;
+
+void search_outline(ivec2 uv, inout bool found_edge)
+{
+ if (!found_edge) {
+ vec4 color = texelFetch(outlineColor, uv, 0).rgba;
+ if (color.a != 0.0) {
+ if (doExpand || color.a != 1.0) {
+ FragColor = color;
+ found_edge = true;
+ }
+ }
+ }
+}
+
+void main()
+{
+ ivec2 uv = ivec2(gl_FragCoord.xy);
+ FragColor = texelFetch(outlineColor, uv, 0).rgba;
+ float depth = texelFetch(outlineDepth, uv, 0).r;
+
+ if (FragColor.a != 0.0 || (depth == 1.0 && !doExpand))
+ return;
+
+ bool found_edge = false;
+ search_outline(uv + ivec2( 1, 0), found_edge);
+ search_outline(uv + ivec2( 0, 1), found_edge);
+ search_outline(uv + ivec2(-1, 0), found_edge);
+ search_outline(uv + ivec2( 0, -1), found_edge);
+
+ /* We Hit something ! */
+ if (found_edge) {
+ /* only change alpha */
+ FragColor.a *= alpha;
+ }
+}
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..3937828eca2
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_outline_resolve_frag.glsl
@@ -0,0 +1,11 @@
+
+in vec4 uvcoordsvar;
+
+out vec4 FragColor;
+
+uniform sampler2D outlineBluredColor;
+
+void main()
+{
+ FragColor = texture(outlineBluredColor, uvcoordsvar.st).rgba;
+}
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_frag.glsl b/source/blender/draw/modes/shaders/object_particle_prim_frag.glsl
new file mode 100644
index 00000000000..aa455a85cf0
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_particle_prim_frag.glsl
@@ -0,0 +1,9 @@
+
+flat in vec4 finalColor;
+
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = finalColor;
+}
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..a950a9b86ba
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_particle_prim_vert.glsl
@@ -0,0 +1,54 @@
+
+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
+ finalColor.rgb = vec3(0.0);
+ finalColor[axis] = 1.0;
+#else
+ if (val < 0.0) {
+ finalColor.rgb = color;
+ }
+ else {
+ finalColor.rgb = texture(ramp, val).rgb;
+ }
+#endif
+
+ finalColor.a = 1.0;
+}
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..18c58a54dca
--- /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;
+
+
+void main()
+{
+ fragColor = texture(image, uv_interp);
+}
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..c22e1c04b96
--- /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.5, 0.5, 0.5, 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_wire_frag.glsl b/source/blender/draw/modes/shaders/paint_wire_frag.glsl
new file mode 100644
index 00000000000..e4214a4c6d1
--- /dev/null
+++ b/source/blender/draw/modes/shaders/paint_wire_frag.glsl
@@ -0,0 +1,24 @@
+
+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;
+ }
+
+#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
+
+ const vec4 colUnsel = vec4(0.5, 0.5, 0.5, 1.0);
+
+ fragColor = bool(finalFlag & VERTEX_SELECTED) ? colSel : colUnsel;
+}
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/editors/CMakeLists.txt b/source/blender/editors/CMakeLists.txt
index ec9ae775ad0..b419ca7eede 100644
--- a/source/blender/editors/CMakeLists.txt
+++ b/source/blender/editors/CMakeLists.txt
@@ -19,6 +19,10 @@
# ***** END GPL LICENSE BLOCK *****
if(WITH_BLENDER)
+ if(WITH_INPUT_NDOF)
+ add_definitions(-DWITH_INPUT_NDOF)
+ endif()
+
add_subdirectory(animation)
add_subdirectory(armature)
add_subdirectory(curve)
@@ -26,13 +30,14 @@ if(WITH_BLENDER)
add_subdirectory(hair)
add_subdirectory(interface)
add_subdirectory(io)
+ add_subdirectory(manipulator_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)
@@ -57,6 +62,7 @@ if(WITH_BLENDER)
add_subdirectory(transform)
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 3085e383909..69e8f708e3d 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -68,6 +68,8 @@
#include "BKE_nla.h"
#include "BKE_context.h"
+#include "GPU_immediate.h"
+
#include "UI_interface.h"
#include "UI_interface_icons.h"
#include "UI_resources.h"
@@ -76,7 +78,6 @@
#include "ED_keyframing.h"
#include "BIF_gl.h"
-#include "BIF_glutil.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -119,11 +120,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);
}
@@ -141,13 +141,19 @@ static void acf_generic_dataexpand_backdrop(bAnimContext *ac, bAnimListElem *ale
View2D *v2d = &ac->ar->v2d;
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
float color[3];
-
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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 */
@@ -224,13 +230,19 @@ static void acf_generic_channel_backdrop(bAnimContext *ac, bAnimListElem *ale, f
View2D *v2d = &ac->ar->v2d;
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
float color[3];
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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 ------------------------------------------- */
@@ -390,7 +402,10 @@ static bool acf_generic_dataexpand_setting_valid(bAnimContext *ac, bAnimListElem
/* select is ok for most "ds*" channels (e.g. dsmat) */
case ACHANNEL_SETTING_SELECT:
return true;
-
+
+ case ACHANNEL_SETTING_ALWAYS_VISIBLE:
+ return true;
+
/* other flags are never supported */
default:
return false;
@@ -418,14 +433,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 */
@@ -529,7 +543,10 @@ static bool acf_scene_setting_valid(bAnimContext *ac, bAnimListElem *UNUSED(ale)
case ACHANNEL_SETTING_SELECT:
case ACHANNEL_SETTING_EXPAND:
return true;
-
+
+ case ACHANNEL_SETTING_ALWAYS_VISIBLE:
+ return false;
+
default:
return false;
}
@@ -555,7 +572,7 @@ static int acf_scene_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Setting
case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */
*neg = true;
return ADT_CURVES_NOT_VISIBLE;
-
+
default: /* unsupported */
return 0;
}
@@ -611,7 +628,7 @@ static bAnimChannelType ACF_SCENE =
static int acf_object_icon(bAnimListElem *ale)
{
- Base *base = (Base *)ale->data;
+ BaseLegacy *base = (BaseLegacy *)ale->data;
Object *ob = base->object;
/* icon depends on object-type */
@@ -646,7 +663,7 @@ static int acf_object_icon(bAnimListElem *ale)
/* name for object */
static void acf_object_name(bAnimListElem *ale, char *name)
{
- Base *base = (Base *)ale->data;
+ BaseLegacy *base = (BaseLegacy *)ale->data;
Object *ob = base->object;
/* just copy the name... */
@@ -666,7 +683,7 @@ static bool acf_object_name_prop(bAnimListElem *ale, PointerRNA *ptr, PropertyRN
/* check if some setting exists for this channel */
static bool acf_object_setting_valid(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting)
{
- Base *base = (Base *)ale->data;
+ BaseLegacy *base = (BaseLegacy *)ale->data;
Object *ob = base->object;
switch (setting) {
@@ -682,7 +699,10 @@ static bool acf_object_setting_valid(bAnimContext *ac, bAnimListElem *ale, eAnim
case ACHANNEL_SETTING_SELECT:
case ACHANNEL_SETTING_EXPAND:
return true;
-
+
+ case ACHANNEL_SETTING_ALWAYS_VISIBLE:
+ return ((ac) && (ac->spacetype == SPACE_IPO) && (ob->adt));
+
default:
return false;
}
@@ -708,7 +728,10 @@ static int acf_object_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settin
case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */
*neg = true;
return ADT_CURVES_NOT_VISIBLE;
-
+
+ case ACHANNEL_SETTING_ALWAYS_VISIBLE:
+ return ADT_CURVES_ALWAYS_VISIBLE;
+
default: /* unsupported */
return 0;
}
@@ -717,7 +740,7 @@ static int acf_object_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settin
/* get pointer to the setting */
static void *acf_object_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type)
{
- Base *base = (Base *)ale->data;
+ BaseLegacy *base = (BaseLegacy *)ale->data;
Object *ob = base->object;
/* clear extra return data first */
@@ -732,6 +755,7 @@ static void *acf_object_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings se
case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */
case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */
+ case ACHANNEL_SETTING_ALWAYS_VISIBLE:
if (ob->adt)
return GET_ACF_FLAG_PTR(ob->adt->flag, type);
return NULL;
@@ -801,11 +825,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 */
@@ -839,7 +862,10 @@ static bool acf_group_setting_valid(bAnimContext *ac, bAnimListElem *UNUSED(ale)
/* conditionally supported */
case ACHANNEL_SETTING_VISIBLE: /* Only available in Graph Editor */
return (ac->spacetype == SPACE_IPO);
-
+
+ case ACHANNEL_SETTING_ALWAYS_VISIBLE:
+ return (ac->spacetype == SPACE_IPO);
+
default: /* always supported */
return true;
}
@@ -879,7 +905,10 @@ static int acf_group_setting_flag(bAnimContext *ac, eAnimChannel_Settings settin
case ACHANNEL_SETTING_VISIBLE: /* visibility - graph editor */
*neg = 1;
return AGRP_NOTVISIBLE;
-
+
+ case ACHANNEL_SETTING_ALWAYS_VISIBLE:
+ return ADT_CURVES_ALWAYS_VISIBLE;
+
default:
/* this shouldn't happen */
return 0;
@@ -965,7 +994,10 @@ static bool acf_fcurve_setting_valid(bAnimContext *ac, bAnimListElem *ale, eAnim
case ACHANNEL_SETTING_VISIBLE: /* Only available in Graph Editor */
return (ac->spacetype == SPACE_IPO);
-
+
+ case ACHANNEL_SETTING_ALWAYS_VISIBLE:
+ return false;
+
/* always available */
default:
return true;
@@ -1049,11 +1081,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 */
+ /* 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 */
@@ -1685,7 +1716,10 @@ static int acf_dscam_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Setting
case ACHANNEL_SETTING_SELECT: /* selected */
return ADT_UI_SELECTED;
-
+
+ case ACHANNEL_SETTING_ALWAYS_VISIBLE:
+ return ADT_CURVES_ALWAYS_VISIBLE;
+
default: /* unsupported */
return 0;
}
@@ -1706,6 +1740,7 @@ static void *acf_dscam_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings set
case ACHANNEL_SETTING_SELECT: /* selected */
case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */
case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */
+ case ACHANNEL_SETTING_ALWAYS_VISIBLE:
if (ca->adt)
return GET_ACF_FLAG_PTR(ca->adt->flag, type);
return NULL;
@@ -1992,7 +2027,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;
@@ -2010,22 +2045,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 */
@@ -2680,6 +2711,84 @@ static bAnimChannelType ACF_DSGPENCIL =
acf_dsgpencil_setting_ptr /* pointer for setting */
};
+/* World Expander ------------------------------------------- */
+
+// TODO: just get this from RNA?
+static int acf_dsmclip_icon(bAnimListElem *UNUSED(ale))
+{
+ return ICON_SEQUENCE;
+}
+
+/* get the appropriate flag(s) for the setting when it is valid */
+static int acf_dsmclip_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg)
+{
+ /* clear extra return data first */
+ *neg = false;
+
+ switch (setting) {
+ case ACHANNEL_SETTING_EXPAND: /* expanded */
+ return MCLIP_DATA_EXPAND;
+
+ case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */
+ return ADT_NLA_EVAL_OFF;
+
+ case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */
+ *neg = true;
+ return ADT_CURVES_NOT_VISIBLE;
+
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ return ADT_UI_SELECTED;
+
+ default: /* unsupported */
+ return 0;
+ }
+}
+
+/* get pointer to the setting */
+static void *acf_dsmclip_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type)
+{
+ MovieClip *clip = (MovieClip *)ale->data;
+
+ /* clear extra return data first */
+ *type = 0;
+
+ switch (setting) {
+ case ACHANNEL_SETTING_EXPAND: /* expanded */
+ return GET_ACF_FLAG_PTR(clip->flag, type);
+
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */
+ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */
+ if (clip->adt != NULL) {
+ return GET_ACF_FLAG_PTR(clip->adt->flag, type);
+ }
+ return NULL;
+
+ default: /* unsupported */
+ return NULL;
+ }
+}
+
+/* world expander type define */
+static bAnimChannelType ACF_DSMCLIP =
+{
+ "Movieclip Expander", /* type name */
+ ACHANNEL_ROLE_EXPANDER, /* role */
+
+ acf_generic_dataexpand_color, /* backdrop color */
+ acf_generic_dataexpand_backdrop, /* backdrop */
+ acf_generic_indention_1, /* indent level */
+ acf_generic_basic_offset, /* offset */
+
+ acf_generic_idblock_name, /* name */
+ acf_generic_idfill_name_prop, /* name prop */
+ acf_dsmclip_icon, /* icon */
+
+ acf_generic_dataexpand_setting_valid, /* has setting */
+ acf_dsmclip_setting_flag, /* flag for setting */
+ acf_dsmclip_setting_ptr /* pointer for setting */
+};
+
/* ShapeKey Entry ------------------------------------------- */
/* name for ShapeKey */
@@ -3316,24 +3425,20 @@ 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);
- }
-
- /* only on top left corner, to show that this channel sits on top of the preceding ones
+ 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
*/
UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT);
-
+
/* 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 */
@@ -3485,6 +3590,7 @@ static void ANIM_init_channel_typeinfo_data(void)
animchannelTypeInfo[type++] = &ACF_DSLINESTYLE; /* LineStyle Channel */
animchannelTypeInfo[type++] = &ACF_DSSPK; /* Speaker Channel */
animchannelTypeInfo[type++] = &ACF_DSGPENCIL; /* GreasePencil Channel */
+ animchannelTypeInfo[type++] = &ACF_DSMCLIP; /* MovieClip Channel */
animchannelTypeInfo[type++] = &ACF_SHAPEKEY; /* ShapeKey */
@@ -3749,23 +3855,35 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
* - in Grease Pencil mode, color swatches for layer color
*/
if (ac->sl) {
- if ((ac->spacetype == SPACE_IPO) && acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) {
+ if ((ac->spacetype == SPACE_IPO) &&
+ (acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE) ||
+ acf->has_setting(ac, ale, ACHANNEL_SETTING_ALWAYS_VISIBLE)))
+ {
/* for F-Curves, draw color-preview of curve behind checkbox */
if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
FCurve *fcu = (FCurve *)ale->data;
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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... */
- offset += ICON_WIDTH;
+ if (acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) {
+ offset += ICON_WIDTH;
+ }
+ if (acf->has_setting(ac, ale, ACHANNEL_SETTING_ALWAYS_VISIBLE)) {
+ offset += ICON_WIDTH;
+ }
}
else if ((ac->spacetype == SPACE_NLA) && acf->has_setting(ac, ale, ACHANNEL_SETTING_SOLO)) {
/* just skip - drawn as widget now */
@@ -3782,27 +3900,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)) {
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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);
+
+ glLineWidth(2.0f);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2f(pos, (float)offset, yminc);
+ immVertex2f(pos, (float)v2d->cur.xmax, yminc);
+ immEnd();
+
+ immUnbindProgram();
}
}
@@ -3816,10 +3946,13 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
short draw_sliders = 0;
float ymin_ofs = 0.0f;
float color[3];
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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)) {
@@ -3877,7 +4010,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();
}
}
@@ -3901,7 +4036,12 @@ static void achannel_setting_flush_widget_cb(bContext *C, void *ale_npoin, void
/* send notifiers before doing anything else... */
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
-
+
+ /* verify that we have a channel to operate on. */
+ if (!ale_setting) {
+ return;
+ }
+
if (ale_setting->type == ANIMTYPE_GPLAYER)
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
@@ -3909,17 +4049,13 @@ static void achannel_setting_flush_widget_cb(bContext *C, void *ale_npoin, void
if (ANIM_animdata_get_context(C, &ac) == 0)
return;
- /* verify that we have a channel to operate on, and that it has all we need */
- if (ale_setting) {
- /* check if the setting is on... */
- on = ANIM_channel_setting_get(&ac, ale_setting, setting);
-
- /* on == -1 means setting not found... */
- if (on == -1)
- return;
- }
- else
+ /* check if the setting is on... */
+ on = ANIM_channel_setting_get(&ac, ale_setting, setting);
+
+ /* on == -1 means setting not found... */
+ if (on == -1) {
return;
+ }
/* get all channels that can possibly be chosen - but ignore hierarchy */
filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS;
@@ -4109,6 +4245,11 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, const bAni
tooltip = TIP_("Channels are visible in Graph Editor for editing");
break;
+ case ACHANNEL_SETTING_ALWAYS_VISIBLE:
+ icon = ICON_UNPINNED;
+ tooltip = TIP_("Channels are visible in Graph Editor for editing");
+ break;
+
case ACHANNEL_SETTING_MOD_OFF: /* modifiers disabled */
icon = ICON_MODIFIER;
usetoggle = false;
@@ -4124,7 +4265,7 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, const bAni
case ACHANNEL_SETTING_SOLO: /* NLA Tracks only */
//icon = ((enabled) ? ICON_SOLO_OFF : ICON_SOLO_ON);
icon = ICON_SOLO_OFF;
- tooltip = TIP_("NLA Track is the only one evaluated in this Animation Data block, with all others muted");
+ tooltip = TIP_("NLA Track is the only one evaluated in this animation data-block, with all others muted");
break;
/* --- */
@@ -4218,6 +4359,7 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, const bAni
case ACHANNEL_SETTING_MUTE: /* General - muting flags */
case ACHANNEL_SETTING_PINNED: /* NLA Actions - 'map/nomap' */
case ACHANNEL_SETTING_MOD_OFF:
+ case ACHANNEL_SETTING_ALWAYS_VISIBLE:
UI_but_funcN_set(but, achannel_setting_flush_widget_cb, MEM_dupallocN(ale), SET_INT_IN_POINTER(setting));
break;
@@ -4281,10 +4423,20 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle
* - in Grease Pencil mode, color swatches for layer color
*/
if (ac->sl) {
- if ((ac->spacetype == SPACE_IPO) && acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) {
+ if ((ac->spacetype == SPACE_IPO) &&
+ (acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE) ||
+ acf->has_setting(ac, ale, ACHANNEL_SETTING_ALWAYS_VISIBLE)))
+ {
+ /* pin toggle */
+ if (acf->has_setting(ac, ale, ACHANNEL_SETTING_ALWAYS_VISIBLE)) {
+ draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_ALWAYS_VISIBLE);
+ offset += ICON_WIDTH;
+ }
/* visibility toggle */
- draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_VISIBLE);
- offset += ICON_WIDTH;
+ if (acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) {
+ draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_VISIBLE);
+ offset += ICON_WIDTH;
+ }
}
else if ((ac->spacetype == SPACE_NLA) && acf->has_setting(ac, ale, ACHANNEL_SETTING_SOLO)) {
/* 'solo' setting for NLA Tracks */
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index cb65a9aecad..01575bff3c2 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -34,7 +34,6 @@
#include "MEM_guardedalloc.h"
-#include "BKE_depsgraph.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
@@ -57,6 +56,9 @@
#include "BKE_context.h"
#include "BKE_mask.h"
#include "BKE_global.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph_build.h"
#include "UI_view2d.h"
@@ -133,6 +135,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
case ANIMTYPE_DSLINESTYLE:
case ANIMTYPE_DSSPK:
case ANIMTYPE_DSGPENCIL:
+ case ANIMTYPE_DSMCLIP:
{
/* need to verify that this data is valid for now */
if (ale->adt) {
@@ -190,6 +193,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
case ANIMTYPE_DSNTREE:
case ANIMTYPE_DSTEX:
case ANIMTYPE_DSGPENCIL:
+ case ANIMTYPE_DSMCLIP:
{
/* need to verify that this data is valid for now */
if (ale && ale->adt) {
@@ -291,6 +295,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
case ANIMTYPE_DSLINESTYLE:
case ANIMTYPE_DSSPK:
case ANIMTYPE_DSGPENCIL:
+ case ANIMTYPE_DSMCLIP:
{
if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED))
sel = ACHANNEL_SETFLAG_CLEAR;
@@ -387,6 +392,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
case ANIMTYPE_DSLINESTYLE:
case ANIMTYPE_DSSPK:
case ANIMTYPE_DSGPENCIL:
+ case ANIMTYPE_DSMCLIP:
{
/* need to verify that this data is valid for now */
if (ale->adt) {
@@ -435,7 +441,11 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAn
/* sanity check */
if (ELEM(NULL, anim_data, anim_data->first))
return;
-
+
+ if (setting == ACHANNEL_SETTING_ALWAYS_VISIBLE) {
+ return;
+ }
+
/* find the channel that got changed */
for (ale = anim_data->first; ale; ale = ale->next) {
/* compare data, and type as main way of identifying the channel */
@@ -1712,7 +1722,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;
}
@@ -2141,7 +2151,7 @@ static void ANIM_OT_channels_clean_empty(wmOperatorType *ot)
/* identifiers */
ot->name = "Remove Empty Animation Data";
ot->idname = "ANIM_OT_channels_clean_empty";
- ot->description = "Delete all empty animation data containers from visible datablocks";
+ ot->description = "Delete all empty animation data containers from visible data-blocks";
/* api callbacks */
ot->exec = animchannels_clean_empty_exec;
@@ -2674,31 +2684,31 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
{
bDopeSheet *ads = (bDopeSheet *)ac->data;
Scene *sce = (Scene *)ads->source;
- Base *base = (Base *)ale->data;
+ BaseLegacy *base = (BaseLegacy *)ale->data;
Object *ob = base->object;
AnimData *adt = ob->adt;
/* set selection status */
if (selectmode == SELECT_INVERT) {
/* swap select */
- base->flag ^= SELECT;
- ob->flag = base->flag;
+ base->flag_legacy ^= SELECT;
+ BKE_scene_base_flag_sync_from_base(base);
if (adt) adt->flag ^= ADT_UI_SELECTED;
}
else {
- Base *b;
+ BaseLegacy *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;
+ b->flag_legacy &= ~SELECT;
+ BKE_scene_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;
+ base->flag_legacy |= SELECT;
ob->flag |= SELECT;
if (adt) adt->flag |= ADT_UI_SELECTED;
}
@@ -2734,6 +2744,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
case ANIMTYPE_DSLINESTYLE:
case ANIMTYPE_DSSPK:
case ANIMTYPE_DSGPENCIL:
+ case ANIMTYPE_DSMCLIP:
{
/* sanity checking... */
if (ale->adt) {
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index 437dd2b2de2..abdc6450abd 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -49,11 +49,12 @@
#include "BKE_fcurve.h"
#include "BKE_gpencil.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.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,7 @@ void ANIM_list_elem_update(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);
}
/* update data */
@@ -98,7 +99,7 @@ void ANIM_list_elem_update(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?
}
}
@@ -114,7 +115,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(id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); // XXX or do we want something more restrictive?
}
}
@@ -309,6 +310,28 @@ static void animchan_sync_fcurve(bAnimContext *ac, bAnimListElem *ale, FCurve **
}
}
+/* perform syncing updates for GPencil Layers */
+static void animchan_sync_gplayer(bAnimContext *UNUSED(ac), bAnimListElem *ale)
+{
+ bGPDlayer *gpl = (bGPDlayer *)ale->data;
+
+ /* Make sure the selection flags agree with the "active" flag.
+ * The selection flags are used in the Dopesheet only, whereas
+ * the active flag is used everywhere else. Hence, we try to
+ * sync these here so that it all seems to be have as the user
+ * expects - T50184
+ *
+ * Assume that we only really do this when the active status changes.
+ * (NOTE: This may prove annoying if it means selection is always lost)
+ */
+ if (gpl->flag & GP_LAYER_ACTIVE) {
+ gpl->flag |= GP_LAYER_SELECT;
+ }
+ else {
+ gpl->flag &= ~GP_LAYER_SELECT;
+ }
+}
+
/* ---------------- */
/* Main call to be exported to animation editors */
@@ -343,6 +366,10 @@ void ANIM_sync_animchannels_to_data(const bContext *C)
case ANIMTYPE_FCURVE:
animchan_sync_fcurve(&ac, ale, &active_fcurve);
break;
+
+ case ANIMTYPE_GPLAYER:
+ animchan_sync_gplayer(&ac, ale);
+ break;
}
}
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index dbc9c8b4f23..08851cebf51 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -46,6 +46,8 @@
#include "BLI_dlrbTree.h"
#include "BKE_context.h"
+#include "BKE_curve.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_nla.h"
#include "BKE_mask.h"
@@ -56,12 +58,13 @@
#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"
+
/* *************************************************** */
/* CURRENT FRAME DRAWING */
@@ -69,13 +72,17 @@
static void draw_cfra_number(Scene *scene, View2D *v2d, const float cfra, const bool time)
{
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
- float xscale, yscale, x, y;
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned char col[4];
+ float xscale, x, y;
char numstr[32] = " t"; /* t is the character to start replacing from */
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);
+ gpuPushMatrix();
+ gpuScale2f(1.0f / xscale, 1.0f);
/* get timecode string
* - padding on str-buf passed so that it doesn't sit on the frame indicator
@@ -94,17 +101,21 @@ static void draw_cfra_number(Scene *scene, View2D *v2d, const float cfra, const
/* get starting coordinates for drawing */
x = cfra * xscale;
y = 0.9f * U.widget_unit;
-
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
/* 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);
-
+ immUniformThemeColorShade(TH_CFRAME, 0);
+
+ immRectf(pos, x, y, x + slen, y + 0.75f * U.widget_unit);
+ immUnbindProgram();
+
+ /* draw current frame number */
+ UI_GetThemeColor4ubv(TH_TEXT, col);
+ UI_fontstyle_draw_simple(fstyle, x - 0.25f * U.widget_unit, y + 0.15f * U.widget_unit, numstr, col);
+
/* restore view transform */
- glScalef(xscale, 1.0, 1.0);
+ gpuPopMatrix();
}
/* General call for drawing current frame indicator in animation editor */
@@ -112,17 +123,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 x = (float)(scene->r.cfra * scene->r.framelen);
+ 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);
- glBegin(GL_LINES);
- glVertex2f(x, v2d->cur.ymin - 500.0f); /* XXX arbitrary... want it go to bottom */
- glVertex2f(x, v2d->cur.ymax);
- glEnd();
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ /* Draw a light green line to indicate current frame */
+ immUniformThemeColor(TH_CFRAME);
+
+ immBegin(GWN_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();
/* Draw current frame number in a little box */
if (flag & DRAWCFRA_SHOW_NUMBOX) {
@@ -144,17 +162,24 @@ void ANIM_draw_previewrange(const bContext *C, View2D *v2d, int end_frame_width)
if (PRVRANGEON) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
- glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
-
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f);
+
/* 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);
}
-
+
+ immUnbindProgram();
+
glDisable(GL_BLEND);
}
}
@@ -308,7 +333,8 @@ static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, flo
fcu->prev_norm_factor = 1.0f;
if (fcu->bezt) {
- BezTriple *bezt;
+ const bool use_preview_only = PRVRANGEON;
+ const BezTriple *bezt;
int i;
float max_coord = -FLT_MAX;
float min_coord = FLT_MAX;
@@ -318,37 +344,91 @@ static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, flo
return 1.0f;
}
- if (PRVRANGEON) {
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- if (IN_RANGE_INCL(bezt->vec[1][0], scene->r.psfra, scene->r.pefra)) {
- max_coord = max_ff(max_coord, bezt->vec[0][1]);
- max_coord = max_ff(max_coord, bezt->vec[1][1]);
- max_coord = max_ff(max_coord, bezt->vec[2][1]);
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (use_preview_only && !IN_RANGE_INCL(bezt->vec[1][0],
+ scene->r.psfra,
+ scene->r.pefra))
+ {
+ continue;
+ }
- min_coord = min_ff(min_coord, bezt->vec[0][1]);
+ if (i == 0) {
+ /* We ignore extrapolation flags and handle here, and use the
+ * control point position only. so we normalize "interesting"
+ * part of the curve.
+ *
+ * Here we handle left extrapolation.
+ */
+ max_coord = max_ff(max_coord, bezt->vec[1][1]);
+
+ min_coord = min_ff(min_coord, bezt->vec[1][1]);
+ }
+ else {
+ const BezTriple *prev_bezt = bezt - 1;
+ if (prev_bezt->ipo == BEZT_IPO_CONST) {
+ /* Constant interpolation: previous CV value is used up
+ * to the current keyframe.
+ */
+ max_coord = max_ff(max_coord, bezt->vec[1][1]);
min_coord = min_ff(min_coord, bezt->vec[1][1]);
- min_coord = min_ff(min_coord, bezt->vec[2][1]);
+ }
+ else if (prev_bezt->ipo == BEZT_IPO_LIN) {
+ /* Linear interpolation: min/max using both previous and
+ * and current CV.
+ */
+ max_coord = max_ff(max_coord, bezt->vec[1][1]);
+ min_coord = min_ff(min_coord, bezt->vec[1][1]);
+ max_coord = max_ff(max_coord, prev_bezt->vec[1][1]);
+ min_coord = min_ff(min_coord, prev_bezt->vec[1][1]);
+ }
+ else if (prev_bezt->ipo == BEZT_IPO_BEZ) {
+ const int resol = fcu->driver
+ ? 32
+ : min_ii((int)(5.0f * len_v2v2(bezt->vec[1], prev_bezt->vec[1])), 32);
+ if (resol < 2) {
+ max_coord = max_ff(max_coord, prev_bezt->vec[1][1]);
+ min_coord = min_ff(min_coord, prev_bezt->vec[1][1]);
+ }
+ else {
+ float data[120];
+ float v1[2], v2[2], v3[2], v4[2];
+
+ v1[0] = prev_bezt->vec[1][0];
+ v1[1] = prev_bezt->vec[1][1];
+ v2[0] = prev_bezt->vec[2][0];
+ v2[1] = prev_bezt->vec[2][1];
+
+ v3[0] = bezt->vec[0][0];
+ v3[1] = bezt->vec[0][1];
+ v4[0] = bezt->vec[1][0];
+ v4[1] = bezt->vec[1][1];
+
+ correct_bezpart(v1, v2, v3, v4);
+
+ 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 (int j = 0; j <= resol; ++j) {
+ const float *fp = &data[j * 3];
+ max_coord = max_ff(max_coord, fp[1]);
+ min_coord = min_ff(min_coord, fp[1]);
+ }
+ }
}
}
}
- else {
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- max_coord = max_ff(max_coord, bezt->vec[0][1]);
- max_coord = max_ff(max_coord, bezt->vec[1][1]);
- max_coord = max_ff(max_coord, bezt->vec[2][1]);
- min_coord = min_ff(min_coord, bezt->vec[0][1]);
- min_coord = min_ff(min_coord, bezt->vec[1][1]);
- min_coord = min_ff(min_coord, bezt->vec[2][1]);
+ if (max_coord > min_coord) {
+ range = max_coord - min_coord;
+ if (range > FLT_EPSILON) {
+ factor = 2.0f / range;
}
+ offset = -min_coord - range / 2.0f;
}
-
- range = max_coord - min_coord;
-
- if (range > FLT_EPSILON) {
- factor = 2.0f / range;
+ else if (max_coord == min_coord) {
+ factor = 1.0f;
+ offset = -min_coord;
}
- offset = -min_coord - range / 2.0f;
}
BLI_assert(factor != 0.0f);
if (r_offset) {
@@ -521,6 +601,7 @@ void ANIM_center_frame(struct bContext *C, int smooth_viewtx)
break;
}
/* else drop through, keep range instead */
+ ATTR_FALLTHROUGH;
case ZOOM_FRAME_MODE_KEEP_RANGE:
default:
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index 5cd305f69f5..5b7ae216c55 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -62,6 +62,7 @@
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
+#include "DNA_movieclip_types.h"
#include "DNA_node_types.h"
#include "DNA_particle_types.h"
#include "DNA_space_types.h"
@@ -73,6 +74,7 @@
#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
#include "DNA_userdef_types.h"
+#include "DNA_layer_types.h"
#include "MEM_guardedalloc.h"
@@ -89,6 +91,7 @@
#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"
@@ -129,11 +132,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;
+ SceneLayer *sl = ac->scene_layer;
Object *ob;
Key *key;
- ob = OBACT;
+ ob = OBACT_NEW;
if (ob == NULL)
return NULL;
@@ -377,8 +380,9 @@ 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->scene_layer = CTX_data_scene_layer(C);
+ ac->obact = (ac->scene_layer->basact) ? ac->scene_layer->basact->object : NULL;
ac->sa = sa;
ac->ar = ar;
ac->sl = sl;
@@ -842,6 +846,19 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne
ale->adt = BKE_animdata_from_id(data);
break;
}
+ case ANIMTYPE_DSMCLIP:
+ {
+ MovieClip *clip = (MovieClip *)data;
+ AnimData *adt = clip->adt;
+
+ ale->flag = EXPANDED_MCLIP(clip);
+
+ ale->key_data = (adt) ? adt->action : NULL;
+ ale->datatype = ALE_ACT;
+
+ ale->adt = BKE_animdata_from_id(data);
+ break;
+ }
case ANIMTYPE_NLACONTROLS:
{
AnimData *adt = (AnimData *)data;
@@ -952,6 +969,9 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne
*/
static bool skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id, int filter_mode)
{
+ if (fcu->grp != NULL && fcu->grp->flag & ADT_CURVES_ALWAYS_VISIBLE) {
+ return false;
+ }
/* hidden items should be skipped if we only care about visible data, but we aren't interested in hidden stuff */
const bool skip_hidden = (filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN);
@@ -1666,15 +1686,16 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, ListBase *anim_data, voi
if (ads->filterflag & ADS_FILTER_GP_3DONLY) {
Scene *scene = (Scene *)ads->source;
+ SceneLayer *sl = (SceneLayer *)ac->scene_layer;
Base *base;
-
+
/* Active scene's GPencil block first - No parent item needed... */
if (scene->gpd) {
items += animdata_filter_gpencil_data(anim_data, ads, scene->gpd, filter_mode);
}
/* Objects in the scene */
- for (base = scene->base.first; base; base = base->next) {
+ for (base = sl->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) {
Object *ob = base->object;
@@ -1690,14 +1711,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_VISIBLED) == 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;
}
@@ -2206,7 +2227,7 @@ typedef struct tAnimFilterModifiersContext {
/* dependency walker callback for modifier dependencies */
-static void animfilter_modifier_idpoin_cb(void *afm_ptr, Object *ob, ID **idpoin, int UNUSED(cd_flag))
+static void animfilter_modifier_idpoin_cb(void *afm_ptr, Object *ob, ID **idpoin, int UNUSED(cb_flag))
{
tAnimFilterModifiersContext *afm = (tAnimFilterModifiersContext *)afm_ptr;
ID *owner_id = &ob->id;
@@ -2612,7 +2633,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);
@@ -2790,9 +2811,53 @@ static size_t animdata_filter_dopesheet_scene(bAnimContext *ac, ListBase *anim_d
return items;
}
+static size_t animdata_filter_ds_movieclip(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, MovieClip *clip, int filter_mode)
+{
+ ListBase tmp_data = {NULL, NULL};
+ size_t tmp_items = 0;
+ size_t items = 0;
+ /* add world animation channels */
+ BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_MCLIP(clip))
+ {
+ /* animation data filtering */
+ tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)clip, filter_mode);
+ }
+ END_ANIMFILTER_SUBCHANNELS;
+ /* did we find anything? */
+ if (tmp_items) {
+ /* include data-expand widget first */
+ if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
+ /* check if filtering by active status */
+ if (ANIMCHANNEL_ACTIVEOK(clip)) {
+ ANIMCHANNEL_NEW_CHANNEL(clip, ANIMTYPE_DSMCLIP, clip);
+ }
+ }
+ /* now add the list of collected channels */
+ BLI_movelisttolist(anim_data, &tmp_data);
+ BLI_assert(BLI_listbase_is_empty(&tmp_data));
+ items += tmp_items;
+ }
+ /* return the number of items added to the list */
+ return items;
+}
+
+static size_t animdata_filter_dopesheet_movieclips(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, int filter_mode)
+{
+ size_t items = 0;
+ MovieClip *clip;
+ for (clip = G.main->movieclip.first; clip != NULL; clip = clip->id.next) {
+ /* only show if gpd is used by something... */
+ if (ID_REAL_USERS(clip) < 1) {
+ continue;
+ }
+ items += animdata_filter_ds_movieclip(ac, anim_data, ads, clip, filter_mode);
+ }
+ /* return the number of items added to the list */
+ return items;
+}
/* 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;
@@ -2810,7 +2875,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_VISIBLED) == 0)
return false;
/* outliner restrict-flag */
@@ -2825,9 +2890,27 @@ static bool animdata_filter_base_is_ok(bDopeSheet *ads, Scene *scene, Base *base
if ((ob->adt) && (ob->adt->flag & ADT_CURVES_NOT_VISIBLE))
return false;
}
-
+
+ /* Pinned curves are visible regardless of selection flags. */
+ if ((ob->adt) && (ob->adt->flag & ADT_CURVES_ALWAYS_VISIBLE)) {
+ return true;
+ }
+
+ /* Special case.
+ * We don't do recursive checks for pin, but we need to deal with tricky
+ * setup like animated camera lens without animated camera location.
+ * Without such special handle here we wouldn't be able to bin such
+ * camera data only animation to the editor.
+ */
+ if (ob->adt == NULL && ob->data != NULL) {
+ AnimData *data_adt = BKE_animdata_from_id(ob->data);
+ if (data_adt != NULL && (data_adt->flag & ADT_CURVES_ALWAYS_VISIBLE)) {
+ return true;
+ }
+ }
+
/* 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;
}
@@ -2855,15 +2938,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, SceneLayer *sl, 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(&sl->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 = sl->object_bases.first; base; base = base->next) {
+ if (animdata_filter_base_is_ok(ads, base, filter_mode)) {
sorted_bases[num_bases++] = base;
}
}
@@ -2881,8 +2964,9 @@ 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;
+ SceneLayer *sl = (SceneLayer *)ac->scene_layer;
size_t items = 0;
-
+
/* check that we do indeed have a scene */
if ((ads->source == NULL) || (GS(ads->source->name) != ID_SCE)) {
printf("Dope Sheet Error: No scene!\n");
@@ -2905,9 +2989,12 @@ static size_t animdata_filter_dopesheet(bAnimContext *ac, ListBase *anim_data, b
items += animdata_filter_ds_cachefile(ac, anim_data, ads, cache_file, filter_mode);
}
+ /* movie clip's animation */
+ items += animdata_filter_dopesheet_movieclips(ac, anim_data, ads, filter_mode);
+
/* scene-linked animation - e.g. world, compositing nodes, scene anim (including sequencer currently) */
items += animdata_filter_dopesheet_scene(ac, anim_data, ads, scene, filter_mode);
-
+
/* If filtering for channel drawing, we want the objects in alphabetical order,
* to make it easier to predict where items are in the hierarchy
* - This order only really matters if we need to show all channels in the list (e.g. for drawing)
@@ -2916,14 +3003,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))
+ (sl->object_bases.first != sl->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, sl, filter_mode, &num_bases);
if (sorted_bases) {
/* Add the necessary channels for these bases... */
for (size_t i = 0; i < num_bases; i++) {
@@ -2940,8 +3027,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 = sl->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);
}
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 823cde75334..e563d3f8cf0 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,11 @@
#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 "UI_interface.h"
#include "UI_interface_icons.h"
#include "UI_view2d.h"
@@ -348,19 +351,30 @@ static void draw_marker(
if (flag & DRAW_MARKERS_LINES)
#endif
{
- setlinestyle(3);
-
- if (marker->flag & SELECT)
- glColor4ub(255, 255, 255, 96);
- else
- glColor4ub(0, 0, 0, 96);
-
- glBegin(GL_LINES);
- glVertex2f(xpos + 0.5f, 12.0f);
- glVertex2f(xpos + 0.5f, (v2d->cur.ymax + 12.0f) * yscale);
- glEnd();
-
- setlinestyle(0);
+ Gwn_VertFormat *format = immVertexFormat();
+ uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_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] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ if (marker->flag & SELECT) {
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.38f);
+ }
+ else {
+ immUniformColor4f(0.0f, 0.0f, 0.0f, 0.38f);
+ }
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2f(pos, xpos + 0.5f, 12.0f);
+ immVertex2f(pos, xpos + 0.5f, (v2d->cur.ymax + 12.0f) * yscale);
+ immEnd();
+
+ immUnbindProgram();
}
/* 5 px to offset icon to align properly, space / pixels corrects for zoom */
@@ -380,19 +394,20 @@ static void draw_marker(
/* and the marker name too, shifted slightly to the top-right */
if (marker->name[0]) {
+ 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_ThemeColor(TH_TEXT_HI);
+ 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_ThemeColor(TH_TEXT);
+ 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;
@@ -406,14 +421,11 @@ static void draw_marker(
#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);
+ text_col[3] = 100;
}
#endif
- UI_fontstyle_draw_simple(fstyle, x, y, marker->name);
+ UI_fontstyle_draw_simple(fstyle, x, y, marker->name, text_col);
}
}
@@ -440,21 +452,27 @@ void ED_markers_draw(const bContext *C, int flag)
v2d = UI_view2d_fromcontext(C);
if (flag & DRAW_MARKERS_MARGIN) {
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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);
- 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);
+
+ 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);
+ gpuPushMatrix();
+ gpuScale2f(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;
@@ -477,7 +495,7 @@ void ED_markers_draw(const bContext *C, int flag)
}
}
- glScalef(xscale, 1.0f, 1.0f);
+ gpuPopMatrix();
}
/* ************************ Marker Wrappers API ********************* */
@@ -841,7 +859,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
@@ -888,7 +906,8 @@ static int ed_marker_move_modal(bContext *C, wmOperator *op, const wmEvent *even
ed_marker_move_cancel(C, op);
return OPERATOR_CANCELLED;
}
- /* else continue; <--- see if release event should be caught for tweak-end */
+ /* else continue; <--- see if release event should be caught for tweak-end */
+ ATTR_FALLTHROUGH;
case RETKEY:
case PADENTER:
@@ -1124,6 +1143,7 @@ static int ed_marker_select(bContext *C, const wmEvent *event, bool extend, bool
if (camera) {
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Base *base;
TimeMarker *marker;
int sel = 0;
@@ -1141,11 +1161,11 @@ 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_scene_layer_base_find(sl, 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);
}
}
}
@@ -1530,7 +1550,7 @@ static int ed_marker_camera_bind_exec(bContext *C, wmOperator *UNUSED(op))
/* 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);
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index 262ce0b9e23..0eb6508f7b2 100644
--- a/source/blender/editors/animation/anim_ops.c
+++ b/source/blender/editors/animation/anim_ops.c
@@ -57,6 +57,7 @@
#include "ED_anim_api.h"
#include "ED_screen.h"
#include "ED_sequencer.h"
+#include "ED_util.h"
#include "anim_intern.h"
@@ -94,7 +95,7 @@ static void change_frame_apply(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- int frame = RNA_int_get(op->ptr, "frame");
+ float frame = RNA_float_get(op->ptr, "frame");
bool do_snap = RNA_boolean_get(op->ptr, "snap");
if (do_snap && CTX_wm_space_seq(C)) {
@@ -102,10 +103,16 @@ static void change_frame_apply(bContext *C, wmOperator *op)
}
/* set the new frame number */
- CFRA = frame;
+ if (scene->r.flag & SCER_SHOW_SUBFRAME) {
+ CFRA = (int)frame;
+ SUBFRA = frame - (int)frame;
+ }
+ else {
+ CFRA = iroundf(frame);
+ SUBFRA = 0.0f;
+ }
FRAMENUMBER_MIN_CLAMP(CFRA);
- SUBFRA = 0.0f;
-
+
/* do updates */
BKE_sound_seek_scene(bmain, scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
@@ -124,19 +131,16 @@ static int change_frame_exec(bContext *C, wmOperator *op)
/* ---- */
/* Get frame from mouse coordinates */
-static int frame_from_event(bContext *C, const wmEvent *event)
+static float frame_from_event(bContext *C, const wmEvent *event)
{
ARegion *region = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
- float viewx;
- int frame;
+ float frame;
/* convert from region coordinates to View2D 'tot' space */
- viewx = UI_view2d_region_to_view_x(&region->v2d, event->mval[0]);
-
- /* round result to nearest int (frames are ints!) */
- frame = iroundf(viewx);
+ frame = UI_view2d_region_to_view_x(&region->v2d, event->mval[0]);
+ /* respect preview range restrictions (if only allowed to move around within that range) */
if (scene->r.flag & SCER_LOCK_FRAME_SELECTION) {
CLAMP(frame, PSFRA, PEFRA);
}
@@ -186,7 +190,7 @@ static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event
* as user could click on a single frame (jump to frame) as well as
* click-dragging over a range (modal scrubbing).
*/
- RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
+ RNA_float_set(op->ptr, "frame", frame_from_event(C, event));
change_frame_seq_preview_begin(C, event);
@@ -214,7 +218,7 @@ static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
break;
case MOUSEMOVE:
- RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
+ RNA_float_set(op->ptr, "frame", frame_from_event(C, event));
change_frame_apply(C, op);
break;
@@ -263,10 +267,11 @@ static void ANIM_OT_change_frame(wmOperatorType *ot)
ot->poll = change_frame_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_UNDO_GROUPED;
+ ot->undo_group = "FRAME_CHANGE";
/* rna */
- ot->prop = RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
+ ot->prop = RNA_def_float(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
prop = RNA_def_boolean(ot->srna, "snap", false, "Snap", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index 21c25f829b1..7bda7f0522c 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -43,11 +43,12 @@
#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_build.h"
+
#include "ED_keyframing.h"
#include "UI_interface.h"
@@ -841,7 +842,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;
@@ -939,7 +940,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
}
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index 5f675e690b9..97e5597326e 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -52,7 +52,8 @@
#include "BKE_fcurve.h"
-#include "BIF_gl.h"
+#include "GPU_draw.h"
+#include "GPU_immediate.h"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -463,49 +464,15 @@ bool actkeyblock_is_valid(ActKeyBlock *ab, DLRBT_Tree *keys)
/* *************************** 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)
{
- 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();
- }
-
- /* tweak size of keyframe shape according to type of keyframe
+ 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
*/
switch (key_type) {
@@ -513,120 +480,93 @@ 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.5f * 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];
+
/* 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 */
+ if (sel) UI_GetThemeColorShade3ubv(TH_STRIP_SELECT, 35, fill_col);
+ else UI_GetThemeColorShade3ubv(TH_STRIP, 50, fill_col);
+ fill_col[3] = 255; /* full opacity, to avoid problems with visual glitches */
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);
-
- border_col[3] *= alpha;
- glColor4fv(border_col);
-
- glCallList(displist1);
+ 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;
+ }
}
-
- glDisable(GL_LINE_SMOOTH);
-
- /* restore view transform */
- glScalef(xscale / hsize, 1.0f / hsize, 1.0f);
- glTranslatef(-x, -y, 0.0f);
+
+ immAttrib1f(size_id, size);
+ immAttrib4ubv(color_id, fill_col);
+ immAttrib4ubv(outline_color_id, outline_col);
+ immVertex2f(pos_id, x, y);
}
static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, float ypos, float yscale_fac, bool channelLocked)
{
- 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;
glEnable(GL_BLEND);
- /* get View2D scaling factor */
- UI_view2d_scale_get(v2d, &xscale, NULL);
-
/* 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;
/* draw keyblocks */
if (blocks) {
@@ -644,45 +584,59 @@ static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, floa
sel_mhcol[3] *= 0.8f;
copy_v4_v4(unsel_mhcol, unsel_color);
unsel_mhcol[3] *= 0.8f;
-
+
+ unsigned int pos_id = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* 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) {
+ for (ActKeyBlock *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);
+ immUniformColor4fv(ab->sel ? sel_mhcol : unsel_mhcol);
+ immRectf(pos_id, ab->start, ypos - smaller_sz, ab->end, ypos + smaller_sz);
}
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);
+ immUniformColor4fv(ab->sel ? sel_color : unsel_color);
+ immRectf(pos_id, ab->start, ypos - half_icon_sz, ab->end, ypos + half_icon_sz);
}
}
}
+ immUnbindProgram();
}
- /* draw keys */
if (keys) {
- for (ak = keys->first; ak; ak = ak->next) {
+ /* count keys */
+ unsigned int key_ct = 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;
-
- /* 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 (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax))
+ key_ct++;
+ }
+
+ if (key_ct > 0) {
+ /* draw keys */
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos_id = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int size_id = GWN_vertformat_attr_add(format, "size", GWN_COMP_F32, 1, GWN_FETCH_FLOAT);
+ unsigned int color_id = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ unsigned int outline_color_id = GWN_vertformat_attr_add(format, "outlineColor", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND);
+ GPU_enable_program_point_size();
+ immBegin(GWN_PRIM_POINTS, key_ct);
+
+ for (ActKeyColumn *ak = keys->first; ak; ak = ak->next) {
+ if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax)) {
+ 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);
+ }
+ }
+
+ immEnd();
+ GPU_disable_program_point_size();
+ immUnbindProgram();
}
}
@@ -938,7 +892,7 @@ void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys, DLRBT_Tree *bl
int filter;
bAnimListElem dummychan = {NULL};
- Base dummybase = {NULL};
+ BaseLegacy dummybase = {NULL};
if (ob == NULL)
return;
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index 4571df0f077..5d1366e03f8 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -193,7 +193,7 @@ static short ob_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, Object *o
int ret = 0;
bAnimListElem dummychan = {NULL};
- Base dummybase = {NULL};
+ BaseLegacy dummybase = {NULL};
if (ob == NULL)
return 0;
@@ -452,7 +452,7 @@ void ANIM_editkeyframes_refresh(bAnimContext *ac)
ok |= KEYFRAME_OK_H2; \
} \
} (void)0
-
+
/* ------------------------ */
static short ok_bezier_frame(KeyframeEditData *ked, BezTriple *bezt)
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index 1703210f0b6..c1e82583521 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -37,6 +37,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_string_utils.h"
#include "DNA_anim_types.h"
#include "DNA_object_types.h"
@@ -668,7 +669,7 @@ static void flip_names(tAnimCopybufItem *aci, char **name)
/* more ninja stuff, temporary substitute with NULL terminator */
str_start[length] = 0;
- BKE_deform_flip_side_name(bname_new, str_start, false);
+ BLI_string_flip_side_name(bname_new, str_start, false, sizeof(bname_new));
str_start[length] = '\"';
str_iter = *name = MEM_mallocN(sizeof(char) * (prefix_l + postfix_l + length + 1), "flipped_path");
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 98be77b491f..d29c0d722b5 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -56,7 +56,6 @@
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_armature.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_idcode.h"
#include "BKE_nla.h"
@@ -66,6 +65,9 @@
#include "BKE_key.h"
#include "BKE_material.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "ED_anim_api.h"
#include "ED_keyframing.h"
#include "ED_keyframes_edit.h"
@@ -155,7 +157,7 @@ bAction *verify_adt_action(ID *id, short add)
/* 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(G.main);
+ DEG_relations_tag_update(G.main);
}
/* return the action */
@@ -1616,7 +1618,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;
}
}
@@ -1723,7 +1725,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;
@@ -1771,8 +1773,10 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
flag = ANIM_get_keyframing_flags(scene, 1);
/* try to insert keyframe using property retrieved from UI */
- but = UI_context_active_but_get(C);
- UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+ if (!(but = UI_context_active_but_prop_get(C, &ptr, &prop, &index))) {
+ /* pass event on if no active button found */
+ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
+ }
if ((ptr.id.data && ptr.data && prop) && RNA_property_animateable(&ptr, prop)) {
if (ptr.type == &RNA_NlaStrip) {
@@ -1873,7 +1877,10 @@ static int delete_key_button_exec(bContext *C, wmOperator *op)
const bool all = RNA_boolean_get(op->ptr, "all");
/* try to insert keyframe using property retrieved from UI */
- UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+ if (!UI_context_active_but_prop_get(C, &ptr, &prop, &index)) {
+ /* pass event on if no active button found */
+ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
+ }
if (ptr.id.data && ptr.data && prop) {
if (ptr.type == &RNA_NlaStrip) {
@@ -1973,7 +1980,10 @@ static int clear_key_button_exec(bContext *C, wmOperator *op)
const bool all = RNA_boolean_get(op->ptr, "all");
/* try to insert keyframe using property retrieved from UI */
- UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+ if (!UI_context_active_but_prop_get(C, &ptr, &prop, &index)) {
+ /* pass event on if no active button found */
+ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
+ }
if (ptr.id.data && ptr.data && prop) {
path = RNA_path_from_ID_to_property(&ptr, prop);
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index b907ad150aa..fd73a27c9f6 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"
@@ -296,6 +297,12 @@ static int add_keyingset_button_exec(bContext *C, wmOperator *op)
int index = 0, pflag = 0;
const bool all = RNA_boolean_get(op->ptr, "all");
+ /* try to add to keyingset using property retrieved from UI */
+ if (!UI_context_active_but_prop_get(C, &ptr, &prop, &index)) {
+ /* pass event on if no active button found */
+ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
+ }
+
/* verify the Keying Set to use:
* - use the active one for now (more control over this can be added later)
* - add a new one if it doesn't exist
@@ -326,9 +333,6 @@ static int add_keyingset_button_exec(bContext *C, wmOperator *op)
ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1);
}
- /* try to add to keyingset using property retrieved from UI */
- UI_context_active_but_prop_get(C, &ptr, &prop, &index);
-
/* check if property is able to be added */
if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
path = RNA_path_from_ID_to_property(&ptr, prop);
@@ -396,6 +400,12 @@ static int remove_keyingset_button_exec(bContext *C, wmOperator *op)
short success = 0;
int index = 0;
+ /* try to add to keyingset using property retrieved from UI */
+ if (UI_context_active_but_prop_get(C, &ptr, &prop, &index)) {
+ /* pass event on if no active button found */
+ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
+ }
+
/* verify the Keying Set to use:
* - use the active one for now (more control over this can be added later)
* - return error if it doesn't exist
@@ -412,9 +422,6 @@ static int remove_keyingset_button_exec(bContext *C, wmOperator *op)
ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1);
}
- /* try to add to keyingset using property retrieved from UI */
- UI_context_active_but_prop_get(C, &ptr, &prop, &index);
-
if (ptr.id.data && ptr.data && prop) {
path = RNA_path_from_ID_to_property(&ptr, prop);
@@ -1043,7 +1050,7 @@ 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 | OB_RECALC_TIME);
break;
}
}
diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt
index b213aca478f..5348298f57e 100644
--- a/source/blender/editors/armature/CMakeLists.txt
+++ b/source/blender/editors/armature/CMakeLists.txt
@@ -23,6 +23,7 @@ set(INC
../../blenkernel
../../blenlib
../../blentranslation
+ ../../depsgraph
../../gpu
../../makesdna
../../makesrna
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index 559d93c7eb1..bbc81f522fa 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -39,6 +39,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_ghash.h"
+#include "BLI_string_utils.h"
#include "BKE_action.h"
#include "BKE_constraint.h"
@@ -231,7 +232,7 @@ static int armature_click_extrude_invoke(bContext *C, wmOperator *op, const wmEv
copy_v3_v3(oldcurs, fp);
VECCOPY2D(mval_f, event->mval);
- ED_view3d_win_to_3d(ar, fp, mval_f, tvec);
+ ED_view3d_win_to_3d(v3d, ar, fp, mval_f, tvec);
copy_v3_v3(fp, tvec);
/* extrude to the where new cursor is and store the operation result */
@@ -619,9 +620,9 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
if (EBONE_VISIBLE(arm, ebone_iter) &&
(ebone_iter->flag & BONE_SELECTED))
{
- char name_flip[MAX_VGROUP_NAME];
+ char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, ebone_iter->name, false);
+ BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip));
if (STREQ(name_flip, ebone_iter->name)) {
/* if the name matches, we don't have the potential to be mirrored, just skip */
@@ -679,9 +680,9 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
/* will be set if the mirror bone already exists (no need to make a new one) */
(ebone_iter->temp.ebone == NULL))
{
- char name_flip[MAX_VGROUP_NAME];
+ char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, ebone_iter->name, false);
+ 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)) {
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index 354b748e129..47e73f9b777 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -410,6 +410,7 @@ static int armature_calc_roll_exec(bContext *C, wmOperator *op)
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);
@@ -1327,6 +1328,7 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
ED_armature_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);
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index 02aefce3464..8c1083dc290 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -37,7 +37,7 @@ struct wmOperatorType;
struct bContext;
struct Scene;
struct Object;
-struct Base;
+struct BaseLegacy;
struct bAction;
struct bPoseChannel;
@@ -201,6 +201,7 @@ void POSELIB_OT_action_sanitize(struct wmOperatorType *ot);
void POSELIB_OT_pose_add(struct wmOperatorType *ot);
void POSELIB_OT_pose_remove(struct wmOperatorType *ot);
void POSELIB_OT_pose_rename(struct wmOperatorType *ot);
+void POSELIB_OT_pose_move(struct wmOperatorType *ot);
void POSELIB_OT_browse_interactive(struct wmOperatorType *ot);
void POSELIB_OT_apply_pose(struct wmOperatorType *ot);
@@ -246,8 +247,10 @@ 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, short findunsel, int x, int y);
-void *get_bone_from_selectbuffer(struct Scene *scene, struct Base *base, unsigned int *buffer, short hits, short findunsel, bool do_nearest);
+void *get_nearest_bone(struct bContext *C, const int xy[2], bool findunsel);
+void *get_bone_from_selectbuffer(
+ struct Scene *scene, struct Base *base, const unsigned int *buffer, short hits,
+ bool findunsel, bool do_nearest);
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 56dbdb3a639..712689396ae 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -37,6 +37,8 @@
#include "BLI_blenlib.h"
#include "BLI_ghash.h"
+#include "BLI_string_utils.h"
+#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -46,11 +48,12 @@
#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
@@ -297,6 +300,55 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n
}
}
+typedef struct BoneFlipNameData {
+ struct BoneFlipNameData *next, *prev;
+ char *name;
+ char name_flip[MAXBONENAME];
+} BoneFlipNameData;
+
+/**
+ * Renames (by flipping) all selected bones at once.
+ *
+ * This way if we are flipping related bones (e.g., Bone.L, Bone.R) at the same time
+ * all the bones are safely renamed, without conflicting with each other.
+ *
+ * \param arm: Armature the bones belong to
+ * \param bones_names: List of BoneConflict elems.
+ */
+void ED_armature_bones_flip_names(bArmature *arm, ListBase *bones_names)
+{
+ ListBase bones_names_conflicts = {NULL};
+ BoneFlipNameData *bfn;
+
+ /* First pass: generate flip names, and blindly rename.
+ * If rename did not yield expected result, store both bone's name and expected flipped one into temp list
+ * for second pass. */
+ for (LinkData *link = bones_names->first; link; link = link->next) {
+ char name_flip[MAXBONENAME];
+ char *name = link->data;
+
+ /* Do not strip numbers, otherwise we'll end up with completely mismatched names in cases like
+ * Bone.R, Bone.R.001, Bone.R.002, etc. */
+ BLI_string_flip_side_name(name_flip, name, false, sizeof(name_flip));
+
+ ED_armature_bone_rename(arm, name, name_flip);
+
+ if (!STREQ(name, name_flip)) {
+ bfn = alloca(sizeof(BoneFlipNameData));
+ bfn->name = name;
+ BLI_strncpy(bfn->name_flip, name_flip, sizeof(bfn->name_flip));
+ BLI_addtail(&bones_names_conflicts, bfn);
+ }
+ }
+
+ /* Second pass to handle the bones that have naming conflicts with other bones.
+ * Note that if the other bone was not selected, its name was not flipped, so conflict remains and that second
+ * rename simply generates a new numbered alternative name. */
+ for (bfn = bones_names_conflicts.first; bfn; bfn = bfn->next) {
+ ED_armature_bone_rename(arm, bfn->name, bfn->name_flip);
+ }
+}
+
/* ************************************************** */
/* Bone Renaming - EditMode */
@@ -304,23 +356,27 @@ static int armature_flip_names_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = CTX_data_edit_object(C);
bArmature *arm;
-
+
/* paranoia checks */
- if (ELEM(NULL, ob, ob->pose))
+ if (ELEM(NULL, ob, ob->pose))
return OPERATOR_CANCELLED;
+
arm = ob->data;
-
- /* loop through selected bones, auto-naming them */
+
+ ListBase bones_names = {NULL};
+
CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
{
- char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, ebone->name, true);
- ED_armature_bone_rename(arm, ebone->name, name_flip);
+ BLI_addtail(&bones_names, BLI_genericNodeN(ebone->name));
}
CTX_DATA_END;
+
+ ED_armature_bones_flip_names(arm, &bones_names);
+
+ BLI_freelistN(&bones_names);
/* since we renamed stuff... */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
/* copied from #rna_Bone_update_renamed */
/* redraw view */
@@ -370,7 +426,7 @@ static int armature_autoside_names_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* since we renamed stuff... */
- 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);
diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c
index ed5f96a5829..5622cd0437d 100644
--- a/source/blender/editors/armature/armature_ops.c
+++ b/source/blender/editors/armature/armature_ops.c
@@ -151,6 +151,7 @@ void ED_operatortypes_armature(void)
WM_operatortype_append(POSELIB_OT_pose_add);
WM_operatortype_append(POSELIB_OT_pose_remove);
WM_operatortype_append(POSELIB_OT_pose_rename);
+ WM_operatortype_append(POSELIB_OT_pose_move);
WM_operatortype_append(POSELIB_OT_new);
WM_operatortype_append(POSELIB_OT_unlink);
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index 1c342657eec..a6f63548c96 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"
@@ -400,12 +403,12 @@ int join_armature_exec(bContext *C, wmOperator *op)
}
/* Free the old object data */
- ED_base_object_free_and_unlink(bmain, scene, base);
+ ED_base_object_free_and_unlink(bmain, scene, base->object);
}
}
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(arm);
ED_armature_edit_free(arm);
@@ -579,6 +582,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *obedit = CTX_data_edit_object(C);
Object *oldob, *newob;
Base *oldbase, *newbase;
@@ -602,14 +606,18 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
/* 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;
+ if (base->object == obedit) {
+ ED_object_base_select(base, BA_SELECT);
+ }
+ else {
+ ED_object_base_select(base, BA_DESELECT);
+ }
}
CTX_DATA_END;
/* 1) store starting settings and exit editmode */
oldob = obedit;
- oldbase = BASACT;
+ oldbase = sl->basact;
oldob->mode &= ~OB_MODE_POSE;
//oldbase->flag &= ~OB_POSEMODE;
@@ -617,13 +625,13 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
ED_armature_edit_free(obedit->data);
/* 2) duplicate base */
- newbase = ED_object_add_duplicate(bmain, scene, oldbase, USER_DUP_ARM); /* only duplicate linked armature */
- DAG_relations_tag_update(bmain);
+ newbase = ED_object_add_duplicate(bmain, scene, sl, oldbase, USER_DUP_ARM); /* only duplicate linked armature */
+ DEG_relations_tag_update(bmain);
newob = newbase->object;
- newbase->flag &= ~SELECT;
-
-
+ newbase->flag &= ~BASE_SELECTED;
+
+
/* 3) remove bones that shouldn't still be around on both armatures */
separate_armature_bones(oldob, 1);
separate_armature_bones(newob, 0);
@@ -632,8 +640,8 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
/* 4) fix links before depsgraph flushes */ // err... or after?
separated_armature_fix_links(oldob, newob);
- 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 */
+ 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 */
/* 5) restore original conditions */
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index 5a70a45fad4..17dc8eac38c 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -35,9 +35,10 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BKE_context.h"
-#include "BKE_deform.h"
+//#include "BKE_deform.h"
#include "BKE_report.h"
#include "BIF_gl.h"
@@ -73,7 +74,9 @@ Bone *get_indexed_bone(Object *ob, int index)
/* 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, unsigned int *buffer, short hits, short findunsel, bool do_nearest)
+void *get_bone_from_selectbuffer(
+ Scene *scene, Base *base, const unsigned int *buffer, short hits,
+ bool findunsel, bool do_nearest)
{
Object *obedit = scene->obedit; // XXX get from context
Bone *bone;
@@ -95,15 +98,15 @@ void *get_bone_from_selectbuffer(Scene *scene, Base *base, unsigned int *buffer,
/* 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)) {
+ if (base->object->select_color == (hitresult & 0xFFFF)) {
bone = get_indexed_bone(base->object, hitresult);
if (findunsel)
sel = (bone->flag & BONE_SELECTED);
else
sel = !(bone->flag & BONE_SELECTED);
-
- data = bone;
+
+ data = bone;
}
else {
data = NULL;
@@ -161,7 +164,7 @@ void *get_bone_from_selectbuffer(Scene *scene, Base *base, unsigned int *buffer,
/* used by posemode as well editmode */
/* only checks scene->basact! */
/* x and y are mouse coords (area space) */
-void *get_nearest_bone(bContext *C, short findunsel, int x, int y)
+void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel)
{
ViewContext vc;
rcti rect;
@@ -171,13 +174,13 @@ void *get_nearest_bone(bContext *C, short findunsel, int x, int y)
view3d_set_viewcontext(C, &vc);
// rect.xmin = ... mouseco!
- rect.xmin = rect.xmax = x;
- rect.ymin = rect.ymax = y;
+ rect.xmin = rect.xmax = xy[0];
+ rect.ymin = rect.ymax = xy[1];
- hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true);
+ hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST);
if (hits > 0)
- return get_bone_from_selectbuffer(vc.scene, vc.scene->basact, buffer, hits, findunsel, true);
+ return get_bone_from_selectbuffer(vc.scene, vc.scene_layer->basact, buffer, hits, findunsel, true);
return NULL;
}
@@ -196,10 +199,7 @@ static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEv
view3d_operator_needs_opengl(C);
- if (extend)
- bone = get_nearest_bone(C, 0, event->mval[0], event->mval[1]);
- else
- bone = get_nearest_bone(C, 1, event->mval[0], event->mval[1]);
+ bone = get_nearest_bone(C, event->mval, !extend);
if (!bone)
return OPERATOR_CANCELLED;
@@ -275,10 +275,24 @@ void ARMATURE_OT_select_linked(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first");
}
+/* utility function for get_nearest_editbonepoint */
+static int selectbuffer_ret_hits_12(unsigned int *UNUSED(buffer), const int hits12)
+{
+ return hits12;
+}
+
+static int selectbuffer_ret_hits_5(unsigned int *buffer, const int hits12, const int hits5)
+{
+ const int offs = 4 * hits12;
+ memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(unsigned int));
+ return hits5;
+}
+
/* does bones and points */
/* note that BONE ROOT only gets drawn for root bones (or without IK) */
-static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2],
- ListBase *edbo, int findunsel, int *selmask)
+static EditBone *get_nearest_editbonepoint(
+ ViewContext *vc, const int mval[2],
+ ListBase *edbo, bool findunsel, bool use_cycle, int *r_selmask)
{
bArmature *arm = (bArmature *)vc->obedit->data;
EditBone *ebone_next_act = arm->act_edbone;
@@ -288,7 +302,9 @@ static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2],
unsigned int buffer[MAXPICKBUF];
unsigned int hitresult, besthitresult = BONESEL_NOSEL;
int i, mindep = 5;
- short hits;
+ int hits12, hits5 = 0;
+
+ static int last_mval[2] = {-100, -100};
/* 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. */
@@ -302,22 +318,59 @@ static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2],
ebone_next_act = NULL;
}
- rect.xmin = mval[0] - 5;
- rect.xmax = mval[0] + 5;
- rect.ymin = mval[1] - 5;
- rect.ymax = mval[1] + 5;
-
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, true);
- if (hits == 0) {
- rect.xmin = mval[0] - 12;
- rect.xmax = mval[0] + 12;
- rect.ymin = mval[1] - 12;
- rect.ymax = mval[1] + 12;
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, true);
+ bool do_nearest = false;
+
+ /* define if we use solid nearest select or not */
+ if (use_cycle) {
+ if (vc->v3d->drawtype > OB_WIRE) {
+ do_nearest = true;
+ if (len_manhattan_v2v2_int(mval, last_mval) < 3) {
+ do_nearest = false;
+ }
+ }
+ copy_v2_v2_int(last_mval, mval);
+ }
+ else {
+ if (vc->v3d->drawtype > 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, 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, 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);
+ 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();
+
/* See if there are any selected bones in this group */
if (hits > 0) {
-
+
if (hits == 1) {
if (!(buffer[3] & BONESEL_NOSEL))
besthitresult = buffer[3];
@@ -374,17 +427,17 @@ static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2],
ebone = BLI_findlink(edbo, besthitresult & ~BONESEL_ANY);
- *selmask = 0;
+ *r_selmask = 0;
if (besthitresult & BONESEL_ROOT)
- *selmask |= BONE_ROOTSEL;
+ *r_selmask |= BONE_ROOTSEL;
if (besthitresult & BONESEL_TIP)
- *selmask |= BONE_TIPSEL;
+ *r_selmask |= BONE_TIPSEL;
if (besthitresult & BONESEL_BONE)
- *selmask |= BONE_SELECTED;
+ *r_selmask |= BONE_SELECTED;
return ebone;
}
}
- *selmask = 0;
+ *r_selmask = 0;
return NULL;
}
@@ -438,8 +491,8 @@ bool ED_armature_select_pick(bContext *C, const int mval[2], bool extend, bool d
if (BIF_sk_selectStroke(C, mval, extend)) {
return true;
}
-
- nearBone = get_nearest_editbonepoint(&vc, mval, arm->edbo, 1, &selmask);
+
+ nearBone = get_nearest_editbonepoint(&vc, mval, arm->edbo, true, true, &selmask);
if (nearBone) {
if (!extend && !deselect && !toggle) {
@@ -817,10 +870,10 @@ static void select_similar_prefix(bArmature *arm, EditBone *ebone_act)
{
EditBone *ebone;
- char body_tmp[MAX_VGROUP_NAME];
- char prefix_act[MAX_VGROUP_NAME];
+ char body_tmp[MAXBONENAME];
+ char prefix_act[MAXBONENAME];
- BKE_deform_split_prefix(ebone_act->name, prefix_act, body_tmp);
+ BLI_string_split_prefix(ebone_act->name, prefix_act, body_tmp, sizeof(ebone_act->name));
if (prefix_act[0] == '\0')
return;
@@ -828,8 +881,8 @@ static void select_similar_prefix(bArmature *arm, EditBone *ebone_act)
/* Find matches */
for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
if (EBONE_SELECTABLE(arm, ebone)) {
- char prefix_other[MAX_VGROUP_NAME];
- BKE_deform_split_prefix(ebone->name, prefix_other, body_tmp);
+ 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);
}
@@ -841,10 +894,10 @@ static void select_similar_suffix(bArmature *arm, EditBone *ebone_act)
{
EditBone *ebone;
- char body_tmp[MAX_VGROUP_NAME];
- char suffix_act[MAX_VGROUP_NAME];
+ char body_tmp[MAXBONENAME];
+ char suffix_act[MAXBONENAME];
- BKE_deform_split_suffix(ebone_act->name, body_tmp, suffix_act);
+ BLI_string_split_suffix(ebone_act->name, body_tmp, suffix_act, sizeof(ebone_act->name));
if (suffix_act[0] == '\0')
return;
@@ -852,8 +905,8 @@ static void select_similar_suffix(bArmature *arm, EditBone *ebone_act)
/* Find matches */
for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
if (EBONE_SELECTABLE(arm, ebone)) {
- char suffix_other[MAX_VGROUP_NAME];
- BKE_deform_split_suffix(ebone->name, body_tmp, suffix_other);
+ 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);
}
@@ -1201,7 +1254,7 @@ static int armature_shortest_path_pick_invoke(bContext *C, wmOperator *op, const
view3d_operator_needs_opengl(C);
ebone_src = arm->act_edbone;
- ebone_dst = get_nearest_bone(C, 0, event->mval[0], event->mval[1]);
+ ebone_dst = get_nearest_bone(C, event->mval, false);
/* fallback to object selection */
if (ELEM(NULL, ebone_src, ebone_dst) || (ebone_src == ebone_dst)) {
diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c
index 28fddbab796..e8d41f722d7 100644
--- a/source/blender/editors/armature/armature_skinning.c
+++ b/source/blender/editors/armature/armature_skinning.c
@@ -39,6 +39,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BKE_action.h"
#include "BKE_armature.h"
@@ -360,7 +361,7 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob,
if (dgroup && mirror) {
char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, dgroup->name, false);
+ BLI_string_flip_side_name(name_flip, dgroup->name, false, sizeof(name_flip));
dgroupflip[j] = defgroup_find_name(ob, name_flip);
}
}
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index 1d1772b919d..d94c580dcfb 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -34,15 +34,17 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#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"
@@ -262,7 +264,7 @@ EditBone *ED_armature_bone_get_mirrored(const ListBase *edbo, EditBone *ebo)
if (ebo == NULL)
return NULL;
- BKE_deform_flip_side_name(name_flip, ebo->name, false);
+ BLI_string_flip_side_name(name_flip, ebo->name, false, sizeof(name_flip));
if (!STREQ(name_flip, ebo->name)) {
return ED_armature_bone_find_name(edbo, name_flip);
@@ -671,7 +673,7 @@ void ED_armature_from_edit(bArmature *arm)
}
}
- DAG_id_tag_update(&arm->id, 0);
+ DEG_id_tag_update(&arm->id, 0);
}
void ED_armature_edit_free(struct bArmature *arm)
diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c
index cc4c1809fbc..20fb7b5e693 100644
--- a/source/blender/editors/armature/editarmature_sketch.c
+++ b/source/blender/editors/armature/editarmature_sketch.c
@@ -33,6 +33,7 @@
#include "BKE_context.h"
#include "BKE_sketch.h"
+#include "BKE_layer.h"
#include "RNA_define.h"
#include "RNA_access.h"
@@ -53,6 +54,10 @@
#include "WM_types.h"
#include "GPU_select.h"
+#include "GPU_matrix.h"
+#include "GPU_batch.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
typedef int (*GestureDetectFct)(bContext *, SK_Gesture *, SK_Sketch *);
typedef void (*GestureApplyFct)(bContext *, SK_Gesture *, SK_Sketch *);
@@ -140,9 +145,8 @@ static RigGraph *TEMPLATE_RIGG = NULL;
void BIF_makeListTemplates(const bContext *C)
{
Object *obedit = CTX_data_edit_object(C);
- Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
ToolSettings *ts = CTX_data_tool_settings(C);
- Base *base;
int index = 0;
if (TEMPLATES_HASH != NULL) {
@@ -152,9 +156,8 @@ void BIF_makeListTemplates(const bContext *C)
TEMPLATES_HASH = BLI_ghash_int_new("makeListTemplates gh");
TEMPLATES_CURRENT = 0;
- for (base = FIRSTBASE; base; base = base->next) {
- Object *ob = base->object;
-
+ FOREACH_OBJECT(sl, ob)
+ {
if (ob != obedit && ob->type == OB_ARMATURE) {
index++;
BLI_ghash_insert(TEMPLATES_HASH, SET_INT_IN_POINTER(index), ob);
@@ -164,6 +167,7 @@ void BIF_makeListTemplates(const bContext *C)
}
}
}
+ FOREACH_OBJECT_END
}
#if 0 /* UNUSED */
@@ -420,7 +424,6 @@ static void sk_retargetStroke(bContext *C, SK_Stroke *stk)
}
/**************************************************************/
-
static void sk_cancelStroke(SK_Sketch *sketch)
{
if (sketch->active_stroke != NULL) {
@@ -435,17 +438,33 @@ 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)
+static void sk_drawPoint(SK_Point *pt, float size, float color[4])
{
- glTranslate3fv(pt->p);
- gluSphere(quad, sk_clampPointSize(pt, size), 8, 8);
+ Gwn_Batch *batch = NULL;
+
+ gpuTranslate3fv(pt->p);
+
+ gpuPushMatrix();
+
+ gpuScaleUniform(sk_clampPointSize(pt, size));
+
+ batch = Batch_get_sphere(0);
+ Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR);
+ GWN_batch_uniform_4fv(batch, "color", color);
+
+ GWN_batch_draw(batch);
+
+ gpuPopMatrix();
}
-static void sk_drawEdge(GLUquadric *quad, SK_Point *pt0, SK_Point *pt1, float size)
+static void sk_drawEdge(SK_Point *pt0, SK_Point *pt1, float size, float color[4])
{
- float vec1[3], vec2[3] = {0, 0, 1}, axis[3];
+ float vec1[3], vec2[3] = { 0, 0, 1 }, axis[3];
float angle, length;
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
sub_v3_v3v3(vec1, pt1->p, pt0->p);
length = normalize_v3(vec1);
cross_v3_v3v3(axis, vec2, vec1);
@@ -454,19 +473,26 @@ static void sk_drawEdge(GLUquadric *quad, SK_Point *pt0, SK_Point *pt1, float si
axis[1] = 1;
}
- angle = angle_normalized_v3v3(vec2, vec1);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor4fv(color);
- glRotate3fv(angle * (float)(180.0 / M_PI) + 180.0f, axis);
+ angle = angle_normalized_v3v3(vec2, vec1);
+ gpuRotate3fv(angle * (float)(180.0 / M_PI) + 180.0f, axis);
+ imm_draw_cylinder_fill_3d(pos, sk_clampPointSize(pt1, size), sk_clampPointSize(pt0, size), length, 8, 8);
- gluCylinder(quad, sk_clampPointSize(pt1, size), sk_clampPointSize(pt0, size), length, 8, 8);
+ immUnbindProgram();
}
-static void sk_drawNormal(GLUquadric *quad, SK_Point *pt, float size, float height)
+static void sk_drawNormal(SK_Point *pt, float size, float height)
{
- float vec2[3] = {0, 0, 1}, axis[3];
+ float vec2[3] = { 0, 0, 1 }, axis[3];
float angle;
-
- glPushMatrix();
+ float color[3] = { 0.0f, 1.0f, 1.0f };
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ gpuPushMatrix();
cross_v3_v3v3(axis, vec2, pt->no);
@@ -474,41 +500,44 @@ static void sk_drawNormal(GLUquadric *quad, SK_Point *pt, float size, float heig
axis[1] = 1;
}
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor4fv(color);
+
angle = angle_normalized_v3v3(vec2, pt->no);
+ gpuRotate3fv(angle * (float)(180.0 / M_PI), axis);
- glRotate3fv(angle * (float)(180.0 / M_PI), axis);
+ imm_draw_cylinder_fill_3d(pos, sk_clampPointSize(pt, size), 0, sk_clampPointSize(pt, height), 10, 2);
- glColor3f(0, 1, 1);
- gluCylinder(quad, sk_clampPointSize(pt, size), 0, sk_clampPointSize(pt, height), 10, 2);
+ immUnbindProgram();
- glPopMatrix();
+ gpuPopMatrix();
}
static void sk_drawStroke(SK_Stroke *stk, int id, float color[3], int start, int end)
{
float rgb[3];
+ float zero_color[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
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();
+ gpuPushMatrix();
- sk_drawPoint(quad, stk->points + i, 0.1);
+ sk_drawPoint(stk->points + i, 0.1, zero_color);
if (i > 0) {
- sk_drawEdge(quad, stk->points + i - 1, stk->points + i, 0.1);
+ sk_drawEdge(stk->points + i - 1, stk->points + i, 0.1, zero_color);
}
- glPopMatrix();
+ gpuPopMatrix();
}
}
else {
- float d_rgb[3] = {1, 1, 1};
+ float d_rgb[3] = { 1, 1, 1 };
+ float tmp_color[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
copy_v3_v3(rgb, color);
sub_v3_v3(d_rgb, rgb);
@@ -517,48 +546,44 @@ static void sk_drawStroke(SK_Stroke *stk, int id, float color[3], int start, int
for (i = 0; i < stk->nb_points; i++) {
SK_Point *pt = stk->points + i;
- glPushMatrix();
+ gpuPushMatrix();
if (pt->type == PT_EXACT) {
- glColor3f(0, 0, 0);
- sk_drawPoint(quad, pt, 0.15);
- sk_drawNormal(quad, pt, 0.05, 0.9);
+ sk_drawPoint(pt, 0.15, zero_color);
+ sk_drawNormal(pt, 0.05, 0.9);
}
if (i >= start && i <= end) {
- glColor3f(0.3, 0.3, 0.3);
+ copy_v4_fl4(tmp_color, 0.3f, 0.3f, 0.3f, 1.0f);
}
else {
- glColor3fv(rgb);
+ copy_v4_fl4(tmp_color, rgb[0], rgb[1], rgb[2], 1.0f);
}
if (pt->type != PT_EXACT) {
-
- sk_drawPoint(quad, pt, 0.1);
+ sk_drawPoint(pt, 0.1, tmp_color);
}
if (i > 0) {
- sk_drawEdge(quad, pt - 1, pt, 0.1);
+ sk_drawEdge(pt - 1, pt, 0.1, tmp_color);
}
- glPopMatrix();
+ gpuPopMatrix();
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];
+ float color[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
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);
@@ -567,22 +592,19 @@ static void drawSubdividedStrokeBy(ToolSettings *toolsettings, BArcIterator *ite
while (index != -1) {
SK_Point *pt = stk->points + index;
- glPushMatrix();
+ gpuPushMatrix();
- glColor3f(0, 1, 0);
- sk_drawPoint(quad, pt, 0.15);
+ sk_drawPoint(pt, 0.15, color);
- sk_drawNormal(quad, pt, 0.05, 0.9);
+ sk_drawNormal(pt, 0.05, 0.9);
- glPopMatrix();
+ gpuPopMatrix();
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)
@@ -970,8 +992,11 @@ static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, S
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_data_main(C), CTX_data_scene(C), CTX_data_scene_layer(C), 0,
CTX_wm_region(C), CTX_wm_view3d(C));
float mvalf[2] = {UNPACK2(dd->mval)};
@@ -1038,6 +1063,8 @@ static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, S
}
}
+ /* 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;
}
@@ -1902,12 +1929,9 @@ static bool sk_selectStroke(bContext *C, SK_Sketch *sketch, const int mval[2], c
view3d_set_viewcontext(C, &vc);
- rect.xmin = mval[0] - 5;
- rect.xmax = mval[0] + 5;
- rect.ymin = mval[1] - 5;
- rect.ymax = mval[1] + 5;
+ BLI_rcti_init_pt_radius(&rect, mval, 5);
- hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true);
+ hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST);
if (hits > 0) {
int besthitresult = -1;
@@ -1973,9 +1997,9 @@ static void sk_drawSketch(Scene *scene, View3D *UNUSED(v3d), SK_Sketch *sketch,
GPU_select_load_id(-1);
}
else {
- float selected_rgb[3] = {1, 0, 0};
- float unselected_rgb[3] = {1, 0.5, 0};
-
+ float selected_rgb[3] = { 1, 0, 0 };
+ float unselected_rgb[3] = { 1, 0.5, 0 };
+ float tmp_color[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
for (stk = sketch->strokes.first; stk; stk = stk->next) {
int start = -1;
int end = -1;
@@ -1999,75 +2023,37 @@ static void sk_drawSketch(Scene *scene, View3D *UNUSED(v3d), SK_Sketch *sketch,
}
if (last != NULL) {
- GLUquadric *quad = gluNewQuadric();
- gluQuadricNormals(quad, GLU_SMOOTH);
-
- glPushMatrix();
+ gpuPushMatrix();
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;
+ case PT_SNAP:
+ copy_v4_fl4(tmp_color, 0.0f, 1.0f, 0.0f, 1.0f);
+ break;
+ case PT_PROJECT:
+ copy_v4_fl4(tmp_color, 0.0f, 0.0f, 0.0f, 1.0f);
+ break;
}
- sk_drawPoint(quad, &sketch->next_point, 0.1);
+ sk_drawPoint(&sketch->next_point, 0.1, tmp_color);
- glColor4f(selected_rgb[0], selected_rgb[1], selected_rgb[2], 0.3);
-
- sk_drawEdge(quad, last, &sketch->next_point, 0.1);
+ copy_v4_fl4(tmp_color, selected_rgb[0], selected_rgb[1], selected_rgb[2], 0.3);
+ sk_drawEdge(last, &sketch->next_point, 0.1f, tmp_color);
glDisable(GL_BLEND);
- glPopMatrix();
-
- gluDeleteQuadric(quad);
+ gpuPopMatrix();
}
}
}
-#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 = GET_INT_FROM_POINTER(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};
+ float gesture_rgb[3] = { 0, 0.5, 1 };
sk_drawStroke(sketch->gesture, -1, gesture_rgb, -1, -1);
}
}
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 5015829f868..736329d29bf 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -43,10 +43,11 @@
#include "BKE_armature.h"
#include "BKE_context.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.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"
@@ -580,7 +581,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");
@@ -593,23 +594,27 @@ static int pose_flip_names_exec(bContext *C, wmOperator *UNUSED(op))
{
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;
+
arm = ob->data;
-
- /* loop through selected bones, auto-naming them */
+
+ ListBase bones_names = {NULL};
+
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
{
- char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, pchan->name, true);
- ED_armature_bone_rename(arm, pchan->name, name_flip);
+ BLI_addtail(&bones_names, BLI_genericNodeN(pchan->name));
}
CTX_DATA_END;
+
+ ED_armature_bones_flip_names(arm, &bones_names);
+
+ BLI_freelistN(&bones_names);
/* since we renamed stuff... */
- 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);
@@ -626,7 +631,7 @@ void POSE_OT_flip_names(wmOperatorType *ot)
/* api callbacks */
ot->exec = pose_flip_names_exec;
- ot->poll = ED_operator_posemode;
+ ot->poll = ED_operator_posemode_local;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -656,7 +661,7 @@ static int pose_autoside_names_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* since we renamed stuff... */
- 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);
@@ -705,7 +710,7 @@ static int pose_bone_rotmode_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* notifiers and updates */
- DAG_id_tag_update((ID *)ob, OB_RECALC_DATA);
+ DEG_id_tag_update((ID *)ob, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
return OPERATOR_FINISHED;
@@ -1162,7 +1167,7 @@ static int pose_flip_quats_exec(bContext *C, wmOperator *UNUSED(op))
CTX_DATA_END;
/* notifiers and updates */
- 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);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c
index 4d9df06f33f..c492772b282 100644
--- a/source/blender/editors/armature/pose_group.c
+++ b/source/blender/editors/armature/pose_group.c
@@ -292,7 +292,6 @@ static int group_move_exec(bContext *C, wmOperator *op)
bPoseChannel *pchan;
bActionGroup *grp;
int dir = RNA_enum_get(op->ptr, "direction");
- int grpIndexA, grpIndexB;
if (ELEM(NULL, ob, pose))
return OPERATOR_CANCELLED;
@@ -305,51 +304,33 @@ static int group_move_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
/* move bone group */
- grpIndexA = pose->active_group;
- if (dir == 1) { /* up */
- void *prev = grp->prev;
-
- if (prev == NULL)
- return OPERATOR_FINISHED;
-
- BLI_remlink(&pose->agroups, grp);
- BLI_insertlinkbefore(&pose->agroups, prev, grp);
-
- grpIndexB = grpIndexA - 1;
- pose->active_group--;
- }
- else { /* down */
- void *next = grp->next;
-
- if (next == NULL)
- return OPERATOR_FINISHED;
-
- BLI_remlink(&pose->agroups, grp);
- BLI_insertlinkafter(&pose->agroups, next, grp);
-
- grpIndexB = grpIndexA + 1;
- pose->active_group++;
- }
+ if (BLI_listbase_link_move(&pose->agroups, grp, dir)) {
+ int grpIndexA = pose->active_group;
+ int grpIndexB = grpIndexA + dir;
+
+ pose->active_group += dir;
+ /* fix changed bone group indices in bones (swap grpIndexA with grpIndexB) */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->agrp_index == grpIndexB) {
+ pchan->agrp_index = grpIndexA;
+ }
+ else if (pchan->agrp_index == grpIndexA) {
+ pchan->agrp_index = grpIndexB;
+ }
+ }
- /* fix changed bone group indices in bones (swap grpIndexA with grpIndexB) */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->agrp_index == grpIndexB)
- pchan->agrp_index = grpIndexA;
- else if (pchan->agrp_index == grpIndexA)
- pchan->agrp_index = grpIndexB;
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
}
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
return OPERATOR_FINISHED;
}
void POSE_OT_group_move(wmOperatorType *ot)
{
static EnumPropertyItem group_slot_move[] = {
- {1, "UP", 0, "Up", ""},
- {-1, "DOWN", 0, "Down", ""},
+ {-1, "UP", 0, "Up", ""},
+ {1, "DOWN", 0, "Down", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -365,7 +346,8 @@ void POSE_OT_group_move(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_enum(ot->srna, "direction", group_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
+ RNA_def_enum(ot->srna, "direction", group_slot_move, 0, "Direction",
+ "Direction to move the active Bone Group towards");
}
/* bone group sort element */
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index d9a3efa765c..71142c292a6 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -34,6 +34,7 @@
#include "BLI_blenlib.h"
#include "BLI_dlrbTree.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -45,7 +46,6 @@
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_armature.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_library.h"
@@ -54,6 +54,8 @@
#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"
@@ -327,7 +329,7 @@ static int poselib_sanitize_exec(bContext *C, wmOperator *op)
/* add pose to poselib */
marker = MEM_callocN(sizeof(TimeMarker), "ActionMarker");
- BLI_strncpy(marker->name, "Pose", sizeof(marker->name));
+ BLI_snprintf(marker->name, sizeof(marker->name), "F%d Pose", (int)ak->cfra);
marker->frame = (int)ak->cfra;
marker->flag = -1;
@@ -461,7 +463,7 @@ static int poselib_add_exec(bContext *C, wmOperator *op)
bAction *act = poselib_validate(ob);
bPose *pose = (ob) ? ob->pose : NULL;
TimeMarker *marker;
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_WHOLE_CHARACTER_ID); /* this includes custom props :)*/
+ KeyingSet *ks;
int frame = RNA_int_get(op->ptr, "frame");
char name[64];
@@ -495,8 +497,7 @@ static int poselib_add_exec(bContext *C, wmOperator *op)
BLI_uniquename(&act->markers, marker, DATA_("Pose"), '.', offsetof(TimeMarker, name), sizeof(marker->name));
/* use Keying Set to determine what to store for the pose */
- /* FIXME: in the past, the Keying Set respected selections (LocRotScale), but the current one doesn't
- * (WholeCharacter) so perhaps we need either a new Keying Set, or just to add overrides here... */
+ ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_WHOLE_CHARACTER_SELECTED_ID); /* this includes custom props :)*/
ANIM_apply_keyingset(C, NULL, act, ks, MODIFYKEY_MODE_INSERT, (float)frame);
/* store new 'active' pose number */
@@ -733,6 +734,89 @@ void POSELIB_OT_pose_rename(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
}
+static int poselib_move_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = get_poselib_object(C);
+ bAction *act = (ob) ? ob->poselib : NULL;
+ TimeMarker *marker;
+ int marker_index;
+ int dir;
+ PropertyRNA *prop;
+
+ /* check if valid poselib */
+ if (act == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Object does not have pose lib data");
+ return OPERATOR_CANCELLED;
+ }
+
+ prop = RNA_struct_find_property(op->ptr, "pose");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ marker_index = RNA_property_enum_get(op->ptr, prop);
+ }
+ else {
+ marker_index = act->active_marker - 1;
+ }
+
+ /* get index (and pointer) of pose to remove */
+ marker = BLI_findlink(&act->markers, marker_index);
+ if (marker == NULL) {
+ BKE_reportf(op->reports, RPT_ERROR, "Invalid pose specified %d", marker_index);
+ return OPERATOR_CANCELLED;
+ }
+
+ dir = RNA_enum_get(op->ptr, "direction");
+
+ /* move pose */
+ if (BLI_listbase_link_move(&act->markers, marker, dir)) {
+ act->active_marker = marker_index + dir + 1;
+
+ /* send notifiers for this - using keyframe editing notifiers, since action
+ * may be being shown in anim editors as active action
+ */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* done */
+ return OPERATOR_FINISHED;
+}
+
+void POSELIB_OT_pose_move(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+ static EnumPropertyItem pose_lib_pose_move[] = {
+ {-1, "UP", 0, "Up", ""},
+ {1, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "PoseLib Move Pose";
+ ot->idname = "POSELIB_OT_pose_move";
+ ot->description = "Move the pose up or down in the active Pose Library";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = poselib_move_exec;
+ ot->poll = has_poselib_pose_data_for_editing_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_enum(ot->srna, "pose", DummyRNA_NULL_items, 0, "Pose", "The pose to move");
+ RNA_def_enum_funcs(prop, poselib_stored_pose_itemf);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
+ ot->prop = prop;
+
+ RNA_def_enum(ot->srna, "direction", pose_lib_pose_move, 0, "Direction",
+ "Direction to move the chosen pose towards");
+}
+
+
+
/* ************************************************************* */
/* Pose-Lib Browsing/Previewing Operator */
@@ -1007,7 +1091,7 @@ 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);
}
@@ -1515,7 +1599,7 @@ 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);
}
@@ -1528,7 +1612,7 @@ 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)) {
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index 44470c1f827..0d1752e07a1 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -43,10 +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 "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
@@ -122,7 +123,7 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
* (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);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
/* send necessary notifiers */
@@ -132,8 +133,9 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
/* called from editview.c, for mode-less pose selection */
/* assumes scene obact and basact is still on old situation */
-int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, short hits,
- bool extend, bool deselect, bool toggle, bool do_nearest)
+bool ED_do_pose_selectbuffer(
+ Scene *scene, SceneLayer *sl, Base *base, const unsigned int *buffer, short hits,
+ bool extend, bool deselect, bool toggle, bool do_nearest)
{
Object *ob = base->object;
Bone *nearBone;
@@ -144,7 +146,7 @@ int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, shor
/* if the bone cannot be affected, don't do anything */
if ((nearBone) && !(nearBone->flag & BONE_UNSELECTABLE)) {
- Object *ob_act = OBACT;
+ Object *ob_act = OBACT_NEW;
bArmature *arm = ob->data;
/* since we do unified select, we don't shift+select a bone if the
@@ -196,7 +198,7 @@ int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, shor
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
@@ -206,7 +208,7 @@ int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, shor
/* 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);
}
}
}
@@ -280,12 +282,9 @@ static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEve
const bool extend = RNA_boolean_get(op->ptr, "extend");
view3d_operator_needs_opengl(C);
-
- if (extend)
- bone = get_nearest_bone(C, 0, event->mval[0], event->mval[1]);
- else
- bone = get_nearest_bone(C, 1, event->mval[0], event->mval[1]);
-
+
+ bone = get_nearest_bone(C, event->mval, !extend);
+
if (!bone)
return OPERATOR_CANCELLED;
@@ -316,7 +315,7 @@ static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEve
if (arm->flag & ARM_HAS_VIZ_DEPS) {
/* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
return OPERATOR_FINISHED;
@@ -372,7 +371,7 @@ static int pose_de_select_all_exec(bContext *C, wmOperator *op)
/* weightpaint or mask modifiers need depsgraph updates */
if (multipaint || (arm->flag & ARM_HAS_VIZ_DEPS)) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
return OPERATOR_FINISHED;
@@ -424,7 +423,7 @@ static int pose_select_parent_exec(bContext *C, wmOperator *UNUSED(op))
if (arm->flag & ARM_HAS_VIZ_DEPS) {
/* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
return OPERATOR_FINISHED;
@@ -491,7 +490,7 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op
if (arm->flag & ARM_HAS_VIZ_DEPS) {
/* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
return OPERATOR_FINISHED;
@@ -585,7 +584,7 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
if (arm->flag & ARM_HAS_VIZ_DEPS) {
/* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
return OPERATOR_FINISHED;
@@ -830,7 +829,7 @@ static int pose_select_grouped_exec(bContext *C, wmOperator *op)
if (arm->flag & ARM_HAS_VIZ_DEPS) {
/* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
/* report done status */
@@ -923,7 +922,7 @@ static int pose_select_mirror_exec(bContext *C, wmOperator *op)
/* 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);
+ DEG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
}
}
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index cd0ea23e2d3..8dfcd5acab8 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -98,8 +98,11 @@ typedef struct tPoseSlideOp {
int prevFrame; /* frame before current frame (blend-from) */
int nextFrame; /* frame after current frame (blend-to) */
- int mode; /* sliding mode (ePoseSlide_Modes) */
- int flag; /* unused for now, but can later get used for storing runtime settings.... */
+ short mode; /* sliding mode (ePoseSlide_Modes) */
+ short flag; /* unused for now, but can later get used for storing runtime settings.... */
+
+ short channels; /* which transforms/channels are affected (ePoseSlide_Channels) */
+ short axislock; /* axis-limits for transforms (ePoseSlide_AxisLock) */
float percentage; /* 0-1 value for determining the influence of whatever is relevant */
@@ -113,6 +116,49 @@ typedef enum ePoseSlide_Modes {
POSESLIDE_BREAKDOWN, /* slide between the endpoint poses, finding a 'soft' spot */
} ePoseSlide_Modes;
+
+/* Transforms/Channels to Affect */
+typedef enum ePoseSlide_Channels {
+ PS_TFM_ALL = 0, /* All transforms and properties */
+
+ PS_TFM_LOC, /* Loc/Rot/Scale */
+ PS_TFM_ROT,
+ PS_TFM_SIZE,
+
+ PS_TFM_BBONE_SHAPE, /* Bendy Bones */
+
+ PS_TFM_PROPS /* Custom Properties */
+} ePoseSlide_Channels;
+
+/* Property enum for ePoseSlide_Channels */
+static EnumPropertyItem prop_channels_types[] = {
+ {PS_TFM_ALL, "ALL", 0, "All Properties",
+ "All properties, including transforms, bendy bone shape, and custom properties"},
+ {PS_TFM_LOC, "LOC", 0, "Location", "Location only"},
+ {PS_TFM_ROT, "ROT", 0, "Rotation", "Rotation only"},
+ {PS_TFM_SIZE, "SIZE", 0, "Scale", "Scale only"},
+ {PS_TFM_BBONE_SHAPE, "BBONE", 0, "Bendy Bone", "Bendy Bone shape properties"},
+ {PS_TFM_PROPS, "CUSTOM", 0, "Custom Properties", "Custom properties"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+/* Axis Locks */
+typedef enum ePoseSlide_AxisLock {
+ PS_LOCK_X = (1 << 0),
+ PS_LOCK_Y = (1 << 1),
+ PS_LOCK_Z = (1 << 2)
+} ePoseSlide_AxisLock;
+
+/* Property enum for ePoseSlide_AxisLock */
+static EnumPropertyItem prop_axis_lock_types[] = {
+ {0, "FREE", 0, "Free", "All axes are affected"},
+ {PS_LOCK_X, "X", 0, "X", "Only X-axis transforms are affected"},
+ {PS_LOCK_Y, "Y", 0, "Y", "Only Y-axis transforms are affected"},
+ {PS_LOCK_Z, "Z", 0, "Z", "Only Z-axis transforms are affected"},
+ /* TODO: Combinations? */
+ {0, NULL, 0, NULL, NULL}
+};
+
/* ------------------------------------ */
/* operator init */
@@ -139,6 +185,10 @@ static int pose_slide_init(bContext *C, wmOperator *op, short mode)
pso->prevFrame = RNA_int_get(op->ptr, "prev_frame");
pso->nextFrame = RNA_int_get(op->ptr, "next_frame");
+ /* get the set of properties/axes that can be operated on */
+ pso->channels = RNA_enum_get(op->ptr, "channels");
+ pso->axislock = RNA_enum_get(op->ptr, "axis_lock");
+
/* check the settings from the context */
if (ELEM(NULL, pso->ob, pso->arm, pso->ob->adt, pso->ob->adt->action))
return 0;
@@ -293,10 +343,20 @@ static void pose_slide_apply_vec3(tPoseSlideOp *pso, tPChanFCurveLink *pfl, floa
/* using this path, find each matching F-Curve for the variables we're interested in */
while ( (ld = poseAnim_mapping_getNextFCurve(&pfl->fcurves, ld, path)) ) {
FCurve *fcu = (FCurve *)ld->data;
-
- /* just work on these channels one by one... there's no interaction between values */
+ const int idx = fcu->array_index;
+ const int lock = pso->axislock;
+
+ /* check if this F-Curve is ok given the current axis locks */
BLI_assert(fcu->array_index < 3);
- pose_slide_apply_val(pso, fcu, &vec[fcu->array_index]);
+
+ if ((lock == 0) ||
+ ((lock & PS_LOCK_X) && (idx == 0)) ||
+ ((lock & PS_LOCK_Y) && (idx == 1)) ||
+ ((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]);
+ }
}
/* free the temp path we got */
@@ -494,17 +554,17 @@ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso)
*/
bPoseChannel *pchan = pfl->pchan;
- if (pchan->flag & POSE_LOC) {
+ if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_LOC) && (pchan->flag & POSE_LOC)) {
/* calculate these for the 'location' vector, and use location curves */
pose_slide_apply_vec3(pso, pfl, pchan->loc, "location");
}
- if (pchan->flag & POSE_SIZE) {
+ if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_SIZE) && (pchan->flag & POSE_SIZE)) {
/* calculate these for the 'scale' vector, and use scale curves */
pose_slide_apply_vec3(pso, pfl, pchan->size, "scale");
}
- if (pchan->flag & POSE_ROT) {
+ if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_ROT) && (pchan->flag & POSE_ROT)) {
/* everything depends on the rotation mode */
if (pchan->rotmode > 0) {
/* eulers - so calculate these for the 'eul' vector, and use euler_rotation curves */
@@ -519,12 +579,12 @@ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso)
}
}
- if (pchan->flag & POSE_BBONE_SHAPE) {
+ if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_BBONE_SHAPE) && (pchan->flag & POSE_BBONE_SHAPE)) {
/* bbone properties - they all start a "bbone_" prefix */
pose_slide_apply_props(pso, pfl, "bbone_");
}
- if (pfl->oldprops) {
+ if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_PROPS) && (pfl->oldprops)) {
/* not strictly a transform, but custom properties contribute to the pose produced in many rigs
* (e.g. the facial rigs used in Sintel)
*/
@@ -553,9 +613,12 @@ static void pose_slide_reset(tPoseSlideOp *pso)
/* ------------------------------------ */
/* draw percentage indicator in header */
+// TODO: Include hints about locks here...
static void pose_slide_draw_status(tPoseSlideOp *pso)
{
char status_str[UI_MAX_DRAW_STR];
+ char limits_str[UI_MAX_DRAW_STR];
+ char axis_str[50];
char mode_str[32];
switch (pso->mode) {
@@ -575,16 +638,58 @@ static void pose_slide_draw_status(tPoseSlideOp *pso)
break;
}
+ switch (pso->axislock) {
+ case PS_LOCK_X:
+ BLI_strncpy(axis_str, "[X]/Y/Z axis only (X to clear)", sizeof(axis_str));
+ break;
+ case PS_LOCK_Y:
+ BLI_strncpy(axis_str, "X/[Y]/Z axis only (Y to clear)", sizeof(axis_str));
+ break;
+ case PS_LOCK_Z:
+ BLI_strncpy(axis_str, "X/Y/[Z] axis only (Z to clear)", sizeof(axis_str));
+ break;
+
+ default:
+ if (ELEM(pso->channels, PS_TFM_LOC, PS_TFM_ROT, PS_TFM_SIZE)) {
+ BLI_strncpy(axis_str, "X/Y/Z = Axis Constraint", sizeof(axis_str));
+ }
+ else {
+ axis_str[0] = '\0';
+ }
+ break;
+ }
+
+ switch (pso->channels) {
+ case PS_TFM_LOC:
+ BLI_snprintf(limits_str, sizeof(limits_str), "[G]/R/S/B/C - Location only (G to clear) | %s", axis_str);
+ break;
+ case PS_TFM_ROT:
+ BLI_snprintf(limits_str, sizeof(limits_str), "G/[R]/S/B/C - Rotation only (R to clear) | %s", axis_str);
+ break;
+ case PS_TFM_SIZE:
+ BLI_snprintf(limits_str, sizeof(limits_str), "G/R/[S]/B/C - Scale only (S to clear) | %s", axis_str);
+ break;
+ case PS_TFM_BBONE_SHAPE:
+ BLI_strncpy(limits_str, "G/R/S/[B]/C - Bendy Bone properties only (B to clear) | %s", sizeof(limits_str));
+ break;
+ case PS_TFM_PROPS:
+ BLI_strncpy(limits_str, "G/R/S/B/[C] - Custom Properties only (C to clear) | %s", sizeof(limits_str));
+ break;
+ default:
+ BLI_strncpy(limits_str, "G/R/S/B/C - Limit to Transform/Property Set", sizeof(limits_str));
+ break;
+ }
+
if (hasNumInput(&pso->num)) {
Scene *scene = pso->scene;
char str_offs[NUM_STR_REP_LEN];
outputNumInput(&pso->num, str_offs, &scene->unit);
- BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_offs);
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s | %s", mode_str, str_offs, limits_str);
}
else {
- BLI_snprintf(status_str, sizeof(status_str), "%s: %d %%", mode_str, (int)(pso->percentage * 100.0f));
+ 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);
@@ -675,16 +780,64 @@ static void pose_slide_mouse_update_percentage(tPoseSlideOp *pso, wmOperator *op
RNA_float_set(op->ptr, "percentage", pso->percentage);
}
+/* handle an event to toggle channels mode */
+static void pose_slide_toggle_channels_mode(wmOperator *op, tPoseSlideOp *pso, ePoseSlide_Channels channel)
+{
+ /* Turn channel on or off? */
+ if (pso->channels == channel) {
+ /* Already limiting to transform only, so pressing this again turns it off */
+ pso->channels = PS_TFM_ALL;
+ }
+ else {
+ /* Only this set of channels */
+ pso->channels = channel;
+ }
+ RNA_enum_set(op->ptr, "channels", pso->channels);
+
+
+ /* Reset axis limits too for good measure */
+ pso->axislock = 0;
+ RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
+}
+
+/* handle an event to toggle axis locks - returns whether any change in state is needed */
+static bool pose_slide_toggle_axis_locks(wmOperator *op, tPoseSlideOp *pso, ePoseSlide_AxisLock axis)
+{
+ /* Axis can only be set when a transform is set - it doesn't make sense otherwise */
+ if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_BBONE_SHAPE, PS_TFM_PROPS)) {
+ pso->axislock = 0;
+ RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
+ return false;
+ }
+
+ /* Turn on or off? */
+ if (pso->axislock == axis) {
+ /* Already limiting on this axis, so turn off */
+ pso->axislock = 0;
+ }
+ else {
+ /* Only this axis */
+ pso->axislock = axis;
+ }
+ RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
+
+ /* Setting changed, so pose update is needed */
+ return true;
+}
+
/* common code for modal() */
static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
tPoseSlideOp *pso = op->customdata;
wmWindow *win = CTX_wm_window(C);
+ bool do_pose_update = false;
+
const bool has_numinput = hasNumInput(&pso->num);
switch (event->type) {
case LEFTMOUSE: /* confirm */
case RETKEY:
+ case PADENTER:
{
/* return to normal cursor and header status */
ED_area_headerprint(pso->sa, NULL);
@@ -717,7 +870,8 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* canceled! */
return OPERATOR_CANCELLED;
}
-
+
+ /* Percentage Chane... */
case MOUSEMOVE: /* calculate new position */
{
/* only handle mousemove if not doing numinput */
@@ -725,18 +879,13 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* update percentage based on position of mouse */
pose_slide_mouse_update_percentage(pso, op, event);
- /* update percentage indicator in header */
- pose_slide_draw_status(pso);
-
- /* reset transforms (to avoid accumulation errors) */
- pose_slide_reset(pso);
-
- /* apply... */
- pose_slide_apply(C, pso);
+ /* update pose to reflect the new values (see below) */
+ do_pose_update = true;
}
break;
}
default:
+ {
if ((event->val == KM_PRESS) && handleNumInput(C, &pso->num, event)) {
float value;
@@ -750,21 +899,94 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
CLAMP(pso->percentage, 0.0f, 1.0f);
RNA_float_set(op->ptr, "percentage", pso->percentage);
- /* update percentage indicator in header */
- pose_slide_draw_status(pso);
-
- /* reset transforms (to avoid accumulation errors) */
- pose_slide_reset(pso);
-
- /* apply... */
- pose_slide_apply(C, pso);
+ /* Update pose to reflect the new values (see below) */
+ do_pose_update = true;
break;
}
+ else if (event->val == KM_PRESS) {
+ switch (event->type) {
+ /* Transform Channel Limits */
+ /* XXX: Replace these hardcoded hotkeys with a modalmap that can be customised */
+ case GKEY: /* Location */
+ {
+ pose_slide_toggle_channels_mode(op, pso, PS_TFM_LOC);
+ do_pose_update = true;
+ break;
+ }
+ case RKEY: /* Rotation */
+ {
+ pose_slide_toggle_channels_mode(op, pso, PS_TFM_ROT);
+ do_pose_update = true;
+ break;
+ }
+ case SKEY: /* Scale */
+ {
+ pose_slide_toggle_channels_mode(op, pso, PS_TFM_SIZE);
+ do_pose_update = true;
+ break;
+ }
+ case BKEY: /* Bendy Bones */
+ {
+ pose_slide_toggle_channels_mode(op, pso, PS_TFM_BBONE_SHAPE);
+ do_pose_update = true;
+ break;
+ }
+ case CKEY: /* Custom Properties */
+ {
+ pose_slide_toggle_channels_mode(op, pso, PS_TFM_PROPS);
+ do_pose_update = true;
+ break;
+ }
+
+
+ /* Axis Locks */
+ /* XXX: Hardcoded... */
+ case XKEY:
+ {
+ if (pose_slide_toggle_axis_locks(op, pso, PS_LOCK_X)) {
+ do_pose_update = true;
+ }
+ break;
+ }
+ case YKEY:
+ {
+ if (pose_slide_toggle_axis_locks(op, pso, PS_LOCK_Y)) {
+ do_pose_update = true;
+ }
+ break;
+ }
+ case ZKEY:
+ {
+ if (pose_slide_toggle_axis_locks(op, pso, PS_LOCK_Z)) {
+ do_pose_update = true;
+ }
+ break;
+ }
+
+
+ default: /* Some other unhandled key... */
+ break;
+ }
+ }
else {
/* unhandled event - maybe it was some view manip? */
/* allow to pass through */
return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
}
+ }
+ }
+
+
+ /* perform pose updates - in response to some user action (e.g. pressing a key or moving the mouse) */
+ if (do_pose_update) {
+ /* update percentage indicator in header */
+ pose_slide_draw_status(pso);
+
+ /* reset transforms (to avoid accumulation errors) */
+ pose_slide_reset(pso);
+
+ /* apply... */
+ pose_slide_apply(C, pso);
}
/* still running... */
@@ -794,11 +1016,16 @@ static int pose_slide_exec_common(bContext *C, wmOperator *op, tPoseSlideOp *pso
}
/* common code for defining RNA properties */
+/* TODO: Skip save on these? */
static void pose_slide_opdef_properties(wmOperatorType *ot)
{
+ RNA_def_float_percentage(ot->srna, "percentage", 0.5f, 0.0f, 1.0f, "Percentage", "Weighting factor for which keyframe is favored more", 0.3, 0.7);
+
RNA_def_int(ot->srna, "prev_frame", 0, MINAFRAME, MAXFRAME, "Previous Keyframe", "Frame number of keyframe immediately before the current frame", 0, 50);
RNA_def_int(ot->srna, "next_frame", 0, MINAFRAME, MAXFRAME, "Next Keyframe", "Frame number of keyframe immediately after the current frame", 0, 50);
- RNA_def_float_percentage(ot->srna, "percentage", 0.5f, 0.0f, 1.0f, "Percentage", "Weighting factor for the sliding operation", 0.3, 0.7);
+
+ RNA_def_enum(ot->srna, "channels", prop_channels_types, PS_TFM_ALL, "Channels", "Set of properties that are affected");
+ RNA_def_enum(ot->srna, "axis_lock", prop_axis_lock_types, 0, "Axis Lock", "Transform axis to restrict effects to");
}
/* ------------------------------------ */
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index df906a3638a..c2f66db63f8 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -36,19 +36,23 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BKE_animsys.h"
#include "BKE_action.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_main.h"
#include "BKE_object.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
@@ -222,7 +226,7 @@ static int pose_visual_transform_apply_exec(bContext *C, wmOperator *UNUSED(op))
}
CTX_DATA_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);
@@ -248,29 +252,6 @@ void POSE_OT_visual_transform_apply(wmOperatorType *ot)
/* ********************************************** */
/* Copy/Paste */
-/* Global copy/paste buffer for pose - cleared on start/end session + before every copy operation */
-static bPose *g_posebuf = NULL;
-
-void ED_clipboard_posebuf_free(void)
-{
- if (g_posebuf) {
- bPoseChannel *pchan;
-
- for (pchan = g_posebuf->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->prop) {
- IDP_FreeProperty(pchan->prop);
- MEM_freeN(pchan->prop);
- }
- }
-
- /* was copied without constraints */
- BLI_freelistN(&g_posebuf->chanbase);
- MEM_freeN(g_posebuf);
- }
-
- g_posebuf = NULL;
-}
-
/* This function is used to indicate that a bone is selected
* and needs to be included in copy buffer (used to be for inserting keys)
*/
@@ -307,7 +288,7 @@ static bPoseChannel *pose_bone_do_paste(Object *ob, bPoseChannel *chan, const bo
/* get the name - if flipping, we must flip this first */
if (flip)
- BKE_deform_flip_side_name(name, chan->name, false);
+ BLI_string_flip_side_name(name, chan->name, false, sizeof(name));
else
BLI_strncpy(name, chan->name, sizeof(name));
@@ -436,21 +417,45 @@ static bPoseChannel *pose_bone_do_paste(Object *ob, bPoseChannel *chan, const bo
static int pose_copy_exec(bContext *C, wmOperator *op)
{
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
-
- /* sanity checking */
+ char str[FILE_MAX];
+ /* Sanity checking. */
if (ELEM(NULL, ob, ob->pose)) {
BKE_report(op->reports, RPT_ERROR, "No pose to copy");
return OPERATOR_CANCELLED;
}
-
- /* free existing pose buffer */
- ED_clipboard_posebuf_free();
-
- /* sets chan->flag to POSE_KEY if bone selected, then copy those bones to the buffer */
- set_pose_keys(ob);
- BKE_pose_copy_data(&g_posebuf, ob->pose, 0);
-
-
+ /* Sets chan->flag to POSE_KEY if bone selected. */
+ set_pose_keys(ob);
+ /* Construct a local bmain and only put object and it's data into it,
+ * o this way we don't expand any other objects into the copy buffer
+ * file.
+ *
+ * TODO(sergey): Find an easier way to tell copy buffer to only store
+ * data we are actually interested in. Maybe pass it a flag to skip
+ * any datablock expansion?
+ */
+ Main *temp_bmain = BKE_main_new();
+ Object ob_copy = *ob;
+ bArmature arm_copy = *((bArmature *)ob->data);
+ ob_copy.data = &arm_copy;
+ BLI_addtail(&temp_bmain->object, &ob_copy);
+ BLI_addtail(&temp_bmain->armature, &arm_copy);
+ /* begin copy buffer on a temp bmain. */
+ BKE_copybuffer_begin(temp_bmain);
+ /* Store the whole object to the copy buffer because pose can't be
+ * existing on it's own.
+ */
+ BKE_copybuffer_tag_ID(&ob_copy.id);
+ BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer_pose.blend");
+ BKE_copybuffer_save(temp_bmain, str, op->reports);
+ /* We clear the lists so no datablocks gets freed,
+ * This is required because objects in temp bmain shares same pointers
+ * as the real ones.
+ */
+ BLI_listbase_clear(&temp_bmain->object);
+ BLI_listbase_clear(&temp_bmain->armature);
+ BKE_main_free(temp_bmain);
+ /* We are all done! */
+ BKE_report(op->reports, RPT_INFO, "Copied pose to buffer");
return OPERATOR_FINISHED;
}
@@ -478,44 +483,60 @@ static int pose_paste_exec(bContext *C, wmOperator *op)
bPoseChannel *chan;
const bool flip = RNA_boolean_get(op->ptr, "flipped");
bool selOnly = RNA_boolean_get(op->ptr, "selected_mask");
-
- /* get KeyingSet to use */
+ /* Get KeyingSet to use. */
KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID);
-
- /* sanity checks */
- if (ELEM(NULL, ob, ob->pose))
+ /* Sanity checks. */
+ if (ELEM(NULL, ob, ob->pose)) {
return OPERATOR_CANCELLED;
-
- if (g_posebuf == NULL) {
+ }
+ /* Read copy buffer .blend file. */
+ char str[FILE_MAX];
+ Main *tmp_bmain = BKE_main_new();
+ BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer_pose.blend");
+ if (!BKE_copybuffer_read(tmp_bmain, str, op->reports)) {
BKE_report(op->reports, RPT_ERROR, "Copy buffer is empty");
+ BKE_main_free(tmp_bmain);
return OPERATOR_CANCELLED;
}
-
- /* if selOnly option is enabled, if user hasn't selected any bones,
- * just go back to default behavior to be more in line with other pose tools
+ /* Make sure data from this file is usable for pose paste. */
+ if (BLI_listbase_count_ex(&tmp_bmain->object, 2) != 1) {
+ BKE_report(op->reports, RPT_ERROR, "Copy buffer is not from pose mode");
+ BKE_main_free(tmp_bmain);
+ return OPERATOR_CANCELLED;
+ }
+ Object *object_from = tmp_bmain->object.first;
+ bPose *pose_from = object_from->pose;
+ if (pose_from == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Copy buffer has no pose");
+ BKE_main_free(tmp_bmain);
+ return OPERATOR_CANCELLED;
+ }
+ /* If selOnly option is enabled, if user hasn't selected any bones,
+ * just go back to default behavior to be more in line with other
+ * pose tools.
*/
if (selOnly) {
- if (CTX_DATA_COUNT(C, selected_pose_bones) == 0)
- selOnly = 0;
+ if (CTX_DATA_COUNT(C, selected_pose_bones) == 0) {
+ selOnly = false;
+ }
}
-
- /* Safely merge all of the channels in the buffer pose into any existing pose */
- for (chan = g_posebuf->chanbase.first; chan; chan = chan->next) {
+ /* Safely merge all of the channels in the buffer pose into any
+ * existing pose.
+ */
+ for (chan = pose_from->chanbase.first; chan; chan = chan->next) {
if (chan->flag & POSE_KEY) {
- /* try to perform paste on this bone */
+ /* Try to perform paste on this bone. */
bPoseChannel *pchan = pose_bone_do_paste(ob, chan, selOnly, flip);
-
- if (pchan) {
- /* keyframing tagging for successful paste */
+ if (pchan != NULL) {
+ /* Keyframing tagging for successful paste, */
ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
}
}
}
-
- /* Update event for pose and deformation children */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-
- /* notifiers for updates */
+ BKE_main_free(tmp_bmain);
+ /* Update event for pose and deformation children. */
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ /* Notifiers for updates, */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
return OPERATOR_FINISHED;
@@ -740,7 +761,7 @@ static int pose_clear_transform_generic_exec(bContext *C, wmOperator *op,
ED_pose_recalculate_paths(scene, ob);
}
- 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_TRANSFORM, ob);
@@ -887,7 +908,7 @@ static int pose_clear_user_transforms_exec(bContext *C, wmOperator *op)
}
/* notifiers and updates */
- 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);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c
index b960bec3603..124cf24f12b 100644
--- a/source/blender/editors/armature/pose_utils.c
+++ b/source/blender/editors/armature/pose_utils.c
@@ -39,11 +39,12 @@
#include "BKE_action.h"
#include "BKE_armature.h"
-#include "BKE_depsgraph.h"
#include "BKE_idprop.h"
#include "BKE_context.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "WM_api.h"
@@ -187,7 +188,7 @@ 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);
diff --git a/source/blender/editors/armature/reeb.c b/source/blender/editors/armature/reeb.c
index 661a8e1de9f..0eb44085bae 100644
--- a/source/blender/editors/armature/reeb.c
+++ b/source/blender/editors/armature/reeb.c
@@ -2240,9 +2240,9 @@ static void glueByMergeSort(ReebGraph *rg, ReebArc *a0, ReebArc *a1, ReebEdge *e
else {
a1 = nextArcMappedToEdge(a1, e1);
}
+ }
}
}
-}
static void mergePaths(ReebGraph *rg, ReebEdge *e0, ReebEdge *e1, ReebEdge *e2)
{
@@ -3199,237 +3199,3 @@ ReebGraph *BIF_ReebGraphMultiFromEditMesh(bContext *C)
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/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt
index 2f5b2ab6e87..ae5c0a13ced 100644
--- a/source/blender/editors/curve/CMakeLists.txt
+++ b/source/blender/editors/curve/CMakeLists.txt
@@ -23,6 +23,7 @@ set(INC
../../blenkernel
../../blenlib
../../blentranslation
+ ../../depsgraph
../../gpu
../../makesdna
../../makesrna
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index b58e1b0b322..10d1fe303e9 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -45,11 +45,11 @@
#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"
@@ -57,6 +57,9 @@
#include "BKE_action.h"
#include "BKE_modifier.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -91,14 +94,6 @@ typedef struct {
int flag;
} UndoCurve;
-/* Definitions needed for shape keys */
-typedef struct {
- void *orig_cv;
- int key_index, nu_index, pt_index, vertex_index;
- bool switched;
- Nurb *orig_nu;
-} CVKeyIndex;
-
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);
@@ -138,9 +133,9 @@ void printknots(Object *obedit)
/* ********************* Shape keys *************** */
-static CVKeyIndex *init_cvKeyIndex(void *cv, int key_index, int nu_index, int pt_index, int vertex_index, Nurb *orig_nu)
+static CVKeyIndex *init_cvKeyIndex(void *cv, int key_index, int nu_index, int pt_index, int vertex_index)
{
- CVKeyIndex *cvIndex = MEM_callocN(sizeof(CVKeyIndex), "init_cvKeyIndex");
+ CVKeyIndex *cvIndex = MEM_callocN(sizeof(CVKeyIndex), __func__);
cvIndex->orig_cv = cv;
cvIndex->key_index = key_index;
@@ -148,7 +143,6 @@ static CVKeyIndex *init_cvKeyIndex(void *cv, int key_index, int nu_index, int pt
cvIndex->pt_index = pt_index;
cvIndex->vertex_index = vertex_index;
cvIndex->switched = false;
- cvIndex->orig_nu = orig_nu;
return cvIndex;
}
@@ -174,7 +168,12 @@ static void init_editNurb_keyIndex(EditNurb *editnurb, ListBase *origBase)
origbezt = orignu->bezt;
pt_index = 0;
while (a--) {
- keyIndex = init_cvKeyIndex(origbezt, key_index, nu_index, pt_index, vertex_index, orignu);
+ /* We cannot keep *any* reference to curve obdata,
+ * it might be replaced and freed while editcurve remain in use (in viewport render case e.g.).
+ * Note that we could use a pool to avoid lots of malloc's here, but... not really a problem for now. */
+ BezTriple *origbezt_cpy = MEM_mallocN(sizeof(*origbezt), __func__);
+ *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;
vertex_index += 3;
@@ -189,7 +188,12 @@ static void init_editNurb_keyIndex(EditNurb *editnurb, ListBase *origBase)
origbp = orignu->bp;
pt_index = 0;
while (a--) {
- keyIndex = init_cvKeyIndex(origbp, key_index, nu_index, pt_index, vertex_index, orignu);
+ /* We cannot keep *any* reference to curve obdata,
+ * it might be replaced and freed while editcurve remain in use (in viewport render case e.g.).
+ * Note that we could use a pool to avoid lots of malloc's here, but... not really a problem for now. */
+ BPoint *origbp_cpy = MEM_mallocN(sizeof(*origbp_cpy), __func__);
+ *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;
bp++;
@@ -250,23 +254,22 @@ static int getKeyIndexOrig_keyIndex(EditNurb *editnurb, void *cv)
return index->key_index;
}
-static void keyIndex_delCV(EditNurb *editnurb, const void *cv)
+static void keyIndex_delBezt(EditNurb *editnurb, BezTriple *bezt)
{
if (!editnurb->keyindex) {
return;
}
- BLI_ghash_remove(editnurb->keyindex, cv, NULL, MEM_freeN);
-}
-
-static void keyIndex_delBezt(EditNurb *editnurb, BezTriple *bezt)
-{
- keyIndex_delCV(editnurb, bezt);
+ BKE_curve_editNurb_keyIndex_delCV(editnurb->keyindex, bezt);
}
static void keyIndex_delBP(EditNurb *editnurb, BPoint *bp)
{
- keyIndex_delCV(editnurb, bp);
+ if (!editnurb->keyindex) {
+ return;
+ }
+
+ BKE_curve_editNurb_keyIndex_delCV(editnurb->keyindex, bp);
}
static void keyIndex_delNurb(EditNurb *editnurb, Nurb *nu)
@@ -282,7 +285,7 @@ static void keyIndex_delNurb(EditNurb *editnurb, Nurb *nu)
a = nu->pntsu;
while (a--) {
- BLI_ghash_remove(editnurb->keyindex, bezt, NULL, MEM_freeN);
+ BKE_curve_editNurb_keyIndex_delCV(editnurb->keyindex, bezt);
bezt++;
}
}
@@ -291,7 +294,7 @@ static void keyIndex_delNurb(EditNurb *editnurb, Nurb *nu)
a = nu->pntsu * nu->pntsv;
while (a--) {
- BLI_ghash_remove(editnurb->keyindex, bp, NULL, MEM_freeN);
+ BKE_curve_editNurb_keyIndex_delCV(editnurb->keyindex, bp);
bp++;
}
}
@@ -535,6 +538,7 @@ static GHash *dupli_keyIndexHash(GHash *keyindex)
CVKeyIndex *newIndex = MEM_mallocN(sizeof(CVKeyIndex), "dupli_keyIndexHash index");
memcpy(newIndex, index, sizeof(CVKeyIndex));
+ newIndex->orig_cv = MEM_dupallocN(index->orig_cv);
BLI_ghash_insert(gh, cv, newIndex);
}
@@ -624,7 +628,7 @@ static void calc_keyHandles(ListBase *nurb, float *key)
}
}
-static void calc_shapeKeys(Object *obedit)
+static void calc_shapeKeys(Object *obedit, ListBase *newnurbs)
{
Curve *cu = (Curve *)obedit->data;
@@ -636,7 +640,7 @@ static void calc_shapeKeys(Object *obedit)
KeyBlock *actkey = BLI_findlink(&cu->key->block, editnurb->shapenr - 1);
BezTriple *bezt, *oldbezt;
BPoint *bp, *oldbp;
- Nurb *nu;
+ Nurb *nu, *newnu;
int totvert = BKE_nurbList_verts_count(&editnurb->nurbs);
float (*ofs)[3] = NULL;
@@ -706,20 +710,25 @@ static void calc_shapeKeys(Object *obedit)
currkey = cu->key->block.first;
while (currkey) {
- int apply_offset = (ofs && (currkey != actkey) && (editnurb->shapenr - 1 == currkey->relative));
+ const bool apply_offset = (ofs && (currkey != actkey) && (editnurb->shapenr - 1 == currkey->relative));
float *fp = newkey = MEM_callocN(cu->key->elemsize * totvert, "currkey->data");
ofp = oldkey = currkey->data;
nu = editnurb->nurbs.first;
+ /* We need to restore to original curve into newnurb, *not* editcurve's nurbs.
+ * Otherwise, in case we update obdata *without* leaving editmode (e.g. viewport render), we would
+ * invalidate editcurve. */
+ newnu = newnurbs->first;
i = 0;
while (nu) {
if (currkey == actkey) {
- int restore = actkey != cu->key->refkey;
+ const bool restore = actkey != cu->key->refkey;
if (nu->bezt) {
bezt = nu->bezt;
a = nu->pntsu;
+ BezTriple *newbezt = newnu->bezt;
while (a--) {
int j;
oldbezt = getKeyIndexOrig_bezt(editnurb, bezt);
@@ -728,7 +737,7 @@ static void calc_shapeKeys(Object *obedit)
copy_v3_v3(fp, bezt->vec[j]);
if (restore && oldbezt) {
- copy_v3_v3(bezt->vec[j], oldbezt->vec[j]);
+ copy_v3_v3(newbezt->vec[j], oldbezt->vec[j]);
}
fp += 3;
@@ -736,16 +745,18 @@ static void calc_shapeKeys(Object *obedit)
fp[0] = bezt->alfa;
if (restore && oldbezt) {
- bezt->alfa = oldbezt->alfa;
+ newbezt->alfa = oldbezt->alfa;
}
fp += 3; ++i; /* alphas */
bezt++;
+ newbezt++;
}
}
else {
bp = nu->bp;
a = nu->pntsu * nu->pntsv;
+ BPoint *newbp = newnu->bp;
while (a--) {
oldbp = getKeyIndexOrig_bp(editnurb, bp);
@@ -754,12 +765,13 @@ static void calc_shapeKeys(Object *obedit)
fp[3] = bp->alfa;
if (restore && oldbp) {
- copy_v3_v3(bp->vec, oldbp->vec);
- bp->alfa = oldbp->alfa;
+ copy_v3_v3(newbp->vec, oldbp->vec);
+ newbp->alfa = oldbp->alfa;
}
fp += 4;
bp++;
+ newbp++;
i += 2;
}
}
@@ -1204,9 +1216,13 @@ void ED_curve_editnurb_load(Object *obedit)
}
}
+ /* We have to pass also new copied nurbs, since we want to restore original curve (without edited shapekey)
+ * on obdata, but *not* on editcurve itself (ED_curve_editnurb_load call does not always implies freeing
+ * of editcurve, e.g. when called to generate render data...). */
+ calc_shapeKeys(obedit, &newnurb);
+
cu->nurb = newnurb;
- calc_shapeKeys(obedit);
ED_curve_updateAnimPaths(obedit->data);
BKE_nurbList_free(&oldnurb);
@@ -1227,13 +1243,11 @@ void ED_curve_editnurb_make(Object *obedit)
if (actkey) {
// XXX strcpy(G.editModeTitleExtra, "(Key) ");
undo_editmode_clear();
- BKE_keyblock_convert_to_curve(actkey, cu, &cu->nurb);
}
if (editnurb) {
BKE_nurbList_free(&editnurb->nurbs);
- BKE_curve_editNurb_keyIndex_free(editnurb);
- editnurb->keyindex = NULL;
+ BKE_curve_editNurb_keyIndex_free(&editnurb->keyindex);
}
else {
editnurb = MEM_callocN(sizeof(EditNurb), "editnurb");
@@ -1248,12 +1262,16 @@ void ED_curve_editnurb_make(Object *obedit)
nu = nu->next;
}
- if (actkey)
- editnurb->shapenr = obedit->shapenr;
-
/* animation could be added in editmode even if there was no animdata in
* object mode hence we always need CVs index be created */
init_editNurb_keyIndex(editnurb, &cu->nurb);
+
+ if (actkey) {
+ editnurb->shapenr = obedit->shapenr;
+ /* Apply shapekey to new nurbs of editnurb, not those of original curve (and *after* we generated keyIndex),
+ * else we do not have valid 'original' data to properly restore curve when leaving editmode. */
+ BKE_keyblock_convert_to_curve(actkey, cu, &editnurb->nurbs);
+ }
}
}
@@ -1270,6 +1288,7 @@ static int separate_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *oldob, *newob;
Base *oldbase, *newbase;
Curve *oldcu, *newcu;
@@ -1297,8 +1316,8 @@ static int separate_exec(bContext *C, wmOperator *op)
}
/* 2. duplicate the object and data */
- newbase = ED_object_add_duplicate(bmain, scene, oldbase, 0); /* 0 = fully linked */
- DAG_relations_tag_update(bmain);
+ newbase = ED_object_add_duplicate(bmain, scene, sl, oldbase, 0); /* 0 = fully linked */
+ DEG_relations_tag_update(bmain);
newob = newbase->object;
newcu = newob->data = BKE_curve_copy(bmain, oldcu);
@@ -1309,8 +1328,7 @@ static int separate_exec(bContext *C, wmOperator *op)
ED_curve_editnurb_make(newob);
newedit = newcu->editnurb;
BKE_nurbList_free(&newedit->nurbs);
- BKE_curve_editNurb_keyIndex_free(newedit);
- newedit->keyindex = NULL;
+ BKE_curve_editNurb_keyIndex_free(&newedit->keyindex);
BLI_movelisttolist(&newedit->nurbs, &newnurb);
/* 4. put old object out of editmode and delete separated geometry */
@@ -1318,8 +1336,8 @@ static int separate_exec(bContext *C, wmOperator *op)
ED_curve_editnurb_free(newob);
curve_delete_segments(oldob, true);
- 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 */
+ 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);
@@ -1367,7 +1385,7 @@ static int curve_split_exec(bContext *C, wmOperator *op)
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);
}
else {
BKE_report(op->reports, RPT_ERROR, "Cannot split current selection");
@@ -2313,7 +2331,7 @@ static int switch_direction_exec(bContext *C, wmOperator *UNUSED(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);
return OPERATOR_FINISHED;
@@ -2361,7 +2379,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;
@@ -2414,7 +2432,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;
}
@@ -2566,7 +2584,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;
}
@@ -2757,7 +2775,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;
}
@@ -2785,7 +2803,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;
}
@@ -2813,7 +2831,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;
}
@@ -2885,7 +2903,7 @@ static int hide_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_SELECT, obedit->data);
BKE_curve_nurb_vert_active_validate(obedit->data);
@@ -2947,7 +2965,7 @@ static int reveal_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
@@ -3366,7 +3384,7 @@ static int subdivide_exec(bContext *C, wmOperator *op)
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;
}
@@ -3561,7 +3579,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) {
@@ -3615,7 +3633,7 @@ static int set_handle_type_exec(bContext *C, wmOperator *op)
BKE_nurbList_handles_set(editnurb, RNA_enum_get(op->ptr, "type"));
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;
}
@@ -3660,7 +3678,7 @@ static int curve_normals_make_consistent_exec(bContext *C, wmOperator *op)
BKE_nurbList_handles_recalculate(editnurb, calc_length, SELECT);
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;
}
@@ -4048,7 +4066,7 @@ static int merge_nurb(bContext *C, wmOperator *op)
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);
+ DEG_id_tag_update(obedit->data, 0);
return OPERATOR_FINISHED;
}
@@ -4146,7 +4164,7 @@ static int make_segment_exec(bContext *C, wmOperator *op)
*/
bp = nu->bp;
- if (bp[nu->pntsu - 1].f1 & SELECT) {
+ if (bp[nu->pntsu - 1].f1 & SELECT) {
if (nu2 == NULL) {
nu2 = nu;
}
@@ -4255,7 +4273,7 @@ static int make_segment_exec(bContext *C, wmOperator *op)
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;
}
@@ -4499,7 +4517,7 @@ static int spin_exec(bContext *C, wmOperator *op)
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;
}
@@ -4954,7 +4972,7 @@ static int add_vertex_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;
}
@@ -4993,13 +5011,13 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
copy_v3_v3(location, ED_view3d_cursor3d_get(vc.scene, vc.v3d));
}
- ED_view3d_win_to_3d_int(vc.ar, location, event->mval, location);
+ ED_view3d_win_to_3d_int(vc.v3d, vc.ar, location, event->mval, location);
if (use_proj) {
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,
+ CTX_data_main(C), vc.scene, vc.scene_layer, 0,
vc.ar, vc.v3d);
ED_transform_snap_object_project_view3d_mixed(
@@ -5109,7 +5127,7 @@ static int curve_extrude_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;
@@ -5208,7 +5226,7 @@ static int toggle_cyclic_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;
}
@@ -5726,7 +5744,7 @@ static int curve_delete_exec(bContext *C, wmOperator *op)
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 retval;
}
@@ -5836,6 +5854,7 @@ static int curve_dissolve_exec(bContext *C, wmOperator *UNUSED(op))
BLI_assert(points_stride + dims == points + (points_len * dims));
float tan_l[3], tan_r[3], error_sq_dummy;
+ unsigned int error_index_dummy;
sub_v3_v3v3(tan_l, bezt_prev->vec[1], bezt_prev->vec[2]);
normalize_v3(tan_l);
@@ -5846,7 +5865,7 @@ static int curve_dissolve_exec(bContext *C, wmOperator *UNUSED(op))
points, points_len, NULL, dims, FLT_EPSILON,
tan_l, tan_r,
bezt_prev->vec[2], bezt_next->vec[0],
- &error_sq_dummy);
+ &error_sq_dummy, &error_index_dummy);
if (!ELEM(bezt_prev->h2, HD_FREE, HD_ALIGN)) {
bezt_prev->h2 = (bezt_prev->h2 == HD_VECT) ? HD_FREE : HD_ALIGN;
@@ -5869,7 +5888,7 @@ static int curve_dissolve_exec(bContext *C, wmOperator *UNUSED(op))
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;
@@ -5910,7 +5929,7 @@ static int shade_smooth_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;
}
@@ -6024,7 +6043,7 @@ int join_curve_exec(bContext *C, wmOperator *op)
}
}
- ED_base_object_free_and_unlink(bmain, scene, base);
+ ED_base_object_free_and_unlink(bmain, scene, base->object);
}
}
}
@@ -6033,9 +6052,12 @@ int join_curve_exec(bContext *C, wmOperator *op)
cu = ob->data;
BLI_movelisttolist(&cu->nurb, &tempbase);
- DAG_relations_tag_update(bmain); // because we removed object(s), call before editmode!
+ /* Account for mixed 2D/3D curves when joining */
+ BKE_curve_curve_dimension_update(cu);
+
+ 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->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
@@ -6075,7 +6097,7 @@ static int clear_tilt_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;
}
@@ -6110,7 +6132,7 @@ static void undoCurve_to_editCurve(void *ucu, void *UNUSED(edata), void *cu_v)
BKE_nurbList_free(editbase);
if (undoCurve->undoIndex) {
- BLI_ghash_free(editnurb->keyindex, NULL, MEM_freeN);
+ BKE_curve_editNurb_keyIndex_free(&editnurb->keyindex);
editnurb->keyindex = dupli_keyIndexHash(undoCurve->undoIndex);
}
@@ -6188,8 +6210,7 @@ static void free_undoCurve(void *ucv)
BKE_nurbList_free(&undoCurve->nubase);
- if (undoCurve->undoIndex)
- BLI_ghash_free(undoCurve->undoIndex, NULL, MEM_freeN);
+ BKE_curve_editNurb_keyIndex_free(&undoCurve->undoIndex);
free_fcurves(&undoCurve->fcurves);
free_fcurves(&undoCurve->drivers);
diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c
index cc8e272d4f7..281f6c3c22e 100644
--- a/source/blender/editors/curve/editcurve_add.c
+++ b/source/blender/editors/curve/editcurve_add.c
@@ -42,9 +42,10 @@
#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_library.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "WM_api.h"
@@ -502,7 +503,7 @@ 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 */
@@ -512,7 +513,7 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
newob = true;
}
else {
- DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
}
}
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index 2d8fc76ee7e..6d29d2def97 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -33,10 +33,11 @@
#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -46,7 +47,11 @@
#include "ED_curve.h"
#include "BIF_gl.h"
-#include "BIF_glutil.h"
+
+#include "GPU_batch.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
#include "curve_intern.h"
@@ -88,25 +93,17 @@ static float depth_read_zbuf(const ViewContext *vc, int x, int y)
}
static bool 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);
}
static bool depth_read_normal(
- const ViewContext *vc, const bglMats *mats, const int mval[2],
+ const ViewContext *vc, const int mval[2],
float r_normal[3])
{
/* pixels surrounding */
@@ -122,7 +119,7 @@ static bool depth_read_normal(
const double depth = (double)depth_read_zbuf(vc, mval_ofs[0], mval_ofs[1]);
if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
- if (depth_unproject(ar, mats, mval_ofs, depth, coords[i])) {
+ if (depth_unproject(ar, mval_ofs, depth, coords[i])) {
depths_valid[i] = true;
}
}
@@ -224,7 +221,6 @@ struct CurveDrawData {
} prev;
ViewContext vc;
- bglMats mats;
enum {
CURVE_DRAW_IDLE = 0,
CURVE_DRAW_PAINTING = 1,
@@ -310,7 +306,7 @@ static bool stroke_elem_project(
{
const double depth = (double)depth_read_zbuf(&cdd->vc, mval_i[0], mval_i[1]);
if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
- if (depth_unproject(ar, &cdd->mats, mval_i, depth, r_location_world)) {
+ if (depth_unproject(ar, mval_i, depth, r_location_world)) {
is_location_world_set = true;
if (r_normal_world) {
zero_v3(r_normal_world);
@@ -319,7 +315,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 (depth_read_normal(&cdd->vc, &cdd->mats, mval_i, normal)) {
+ if (depth_read_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);
@@ -353,7 +349,7 @@ static bool stroke_elem_project_fallback(
surface_offset, radius,
r_location_world, r_normal_world);
if (is_depth_found == false) {
- ED_view3d_win_to_3d(cdd->vc.ar, location_fallback_depth, mval_fl, r_location_world);
+ ED_view3d_win_to_3d(cdd->vc.v3d, cdd->vc.ar, location_fallback_depth, mval_fl, r_location_world);
zero_v3(r_normal_local);
}
mul_v3_m4v3(r_location_local, cdd->vc.obedit->imat, r_location_world);
@@ -465,39 +461,43 @@ static void curve_draw_stroke_3d(const struct bContext *UNUSED(C), ARegion *UNUS
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);
+
+ Gwn_Batch *sphere = Batch_get_sphere(0);
+ Batch_set_builtin_program(sphere, GPU_SHADER_3D_UNIFORM_COLOR);
+ GWN_batch_uniform_3fv(sphere, "color", color);
+
/* scale to edit-mode space */
- glPushMatrix();
- glMultMatrixf(obedit->obmat);
+ gpuPushMatrix();
+ gpuMultMatrix(obedit->obmat);
BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
- glTranslatef(
+ gpuTranslate3f(
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);
+
+ gpuPushMatrix();
+ gpuScaleUniform(radius);
+ GWN_batch_draw(sphere);
+ gpuPopMatrix();
location_prev = selem->location_local;
}
- glPopMatrix();
-
- gluDeleteQuadric(qobj);
+ gpuPopMatrix();
}
if (stroke_len > 1) {
@@ -514,30 +514,45 @@ static void curve_draw_stroke_3d(const struct bContext *UNUSED(C), ARegion *UNUS
}
{
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, coord_array);
-
- cpack(0x0);
+ imm_cpack(0x0);
+ immBegin(GWN_PRIM_LINE_STRIP, stroke_len);
glLineWidth(3.0f);
- glDrawArrays(GL_LINE_STRIP, 0, stroke_len);
- if (v3d->zbuf)
+ if (v3d->zbuf) {
glDisable(GL_DEPTH_TEST);
+ }
- cpack(0xffffffff);
+ for (int i = 0; i < stroke_len; i++) {
+ immVertex3fv(pos, coord_array[i]);
+ }
+
+ immEnd();
+
+ imm_cpack(0xffffffff);
+ immBegin(GWN_PRIM_LINE_STRIP, stroke_len);
glLineWidth(1.0f);
- glDrawArrays(GL_LINE_STRIP, 0, stroke_len);
- if (v3d->zbuf)
- glEnable(GL_DEPTH_TEST);
+ for (int i = 0; i < stroke_len; i++) {
+ immVertex3fv(pos, coord_array[i]);
+ }
+
+ immEnd();
- glDisableClientState(GL_VERTEX_ARRAY);
+ if (v3d->zbuf) {
+ glEnable(GL_DEPTH_TEST);
+ }
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
+
+ immUnbindProgram();
}
MEM_freeN(coord_array);
@@ -627,7 +642,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 (depth_read_normal(&cdd->vc, &cdd->mats, event->mval, normal)) {
+ if (depth_read_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);
@@ -685,7 +700,9 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke)
}
}
else {
+ cdd->vc.depsgraph = CTX_data_depsgraph(C);
cdd->vc.scene = CTX_data_scene(C);
+ cdd->vc.scene_layer = CTX_data_scene_layer(C);
cdd->vc.obedit = CTX_data_edit_object(C);
}
@@ -1107,7 +1124,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);
@@ -1135,7 +1152,7 @@ static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
const float mval_fl[2] = {UNPACK2(event->mval)};
float center[3];
negate_v3_v3(center, cdd->vc.rv3d->ofs);
- ED_view3d_win_to_3d(cdd->vc.ar, center, mval_fl, cdd->prev.location_world);
+ ED_view3d_win_to_3d(cdd->vc.v3d, cdd->vc.ar, center, mval_fl, cdd->prev.location_world);
copy_v3_v3(cdd->prev.location_world_valid, cdd->prev.location_world);
}
@@ -1162,12 +1179,10 @@ static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if ((cps->depth_mode == CURVE_PAINT_PROJECT_SURFACE) &&
(v3d->drawtype > 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.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;
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index b40b51e337f..c18f1408387 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -49,13 +49,14 @@
#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 "RNA_access.h"
#include "RNA_define.h"
@@ -254,7 +255,7 @@ 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 */
@@ -273,6 +274,8 @@ static void text_update_edited(bContext *C, Object *obedit, int mode)
}
}
+ BKE_curve_batch_cache_dirty(cu, BKE_CURVE_BATCH_DIRTY_SELECT);
+
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
}
@@ -420,6 +423,7 @@ static void txt_add_object(bContext *C, TextLine *firstline, int totline, const
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Curve *cu;
Object *obedit;
Base *base;
@@ -429,8 +433,8 @@ 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, sl, OB_FONT, NULL);
+ base = sl->basact;
/* seems to assume view align ? TODO - look into this, could be an operator option */
ED_object_base_init_transform(C, base, NULL, rot);
@@ -582,7 +586,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;
@@ -1788,7 +1792,7 @@ void FONT_OT_unlink(wmOperatorType *ot)
/* identifiers */
ot->name = "Unlink";
ot->idname = "FONT_OT_unlink";
- ot->description = "Unlink active font data block";
+ ot->description = "Unlink active font data-block";
/* api callbacks */
ot->exec = font_unlink_exec;
diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt
index 6604d595573..587c25031ab 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
@@ -44,6 +45,7 @@ set(SRC
gpencil_convert.c
gpencil_data.c
gpencil_edit.c
+ gpencil_interpolate.c
gpencil_ops.c
gpencil_paint.c
gpencil_select.c
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 4ef76f5ee25..96f9959af02 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -60,12 +60,15 @@
#include "WM_api.h"
-#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_immediate.h"
+#include "GPU_draw.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"
@@ -74,7 +77,6 @@
/* GREASE PENCIL DRAWING */
/* ----- General Defines ------ */
-
/* flags for sflag */
typedef enum eDrawStrokeFlags {
GP_DRAWDATA_NOSTATUS = (1 << 0), /* don't draw status info */
@@ -92,99 +94,194 @@ typedef enum 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) (unsigned char)(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], unsigned attrib_id)
{
float alpha = ink[3] * pt->strength;
CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
- glColor4f(ink[0], ink[1], ink[2], alpha);
+ immAttrib4ub(attrib_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], unsigned attrib_id)
{
- gp_set_tpoint_color(pt, ink);
- glVertex2iv(&pt->x);
+ float alpha = ink[3] * pt->strength;
+ CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
+ immAttrib4ub(attrib_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 */
+ unsigned int(*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, (unsigned int)totpoints, 0, (unsigned int(*)[3])tmp_triangles);
+
+ /* draw triangulation data */
+ if (tot_triangles > 0) {
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+
+ /* Draw all triangles for filling the polygon */
+ immBegin(GWN_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))
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;
+ }
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_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! */
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR);
+ immBegin(GWN_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);
-
glLineWidth(max_ff(oldpressure * thickness, 1.0));
- glBegin(GL_LINE_STRIP);
-
- for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+ immBeginAtMost(GWN_PRIM_LINE_STRIP, totpoints);
+
+ /* TODO: implement this with a geometry shader to draw one continuous tapered stroke */
+
+ 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();
+ /* 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;
+
glLineWidth(max_ff(pt->pressure * thickness, 1.0f));
- glBegin(GL_LINE_STRIP);
-
+ immBeginAtMost(GWN_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;
}
- glEnd();
+ /* 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);
+ }
+ }
- 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,203 +307,141 @@ 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;
-
+
/* check if buffer can be drawn */
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;
-
- glLoadMatrixf((float *)modelview);
-
- /* draw the disk using the current state... */
- gp_set_tpoint_color(pt, ink);
- gluDisk(qobj, 0.0, pt->pressure * thickness, 32, 1);
-
-
- modelview[3][0] = modelview[3][1] = 0.0f;
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int size = GWN_vertformat_attr_add(format, "size", GWN_COMP_F32, 1, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR);
+ GPU_enable_program_point_size();
+ immBegin(GWN_PRIM_POINTS, totpoints);
+
+ const tGPspoint *pt = points;
+ for (int i = 0; i < totpoints; i++, pt++) {
+ gp_set_tpoint_varying_color(pt, ink, color);
+ immAttrib1f(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,
+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,
- float diff_mat[4][4], float ink[4])
+ 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 */
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int size = GWN_vertformat_attr_add(format, "size", GWN_COMP_F32, 1, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR);
+ GPU_enable_program_point_size();
+ immBegin(GWN_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);
+ immAttrib1f(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);
-
- /* 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]);
-
- /* 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);
-
- /* draw the disk using the current state... */
- gluDisk(qobj, 0.0, pt->pressure * thickness, 32, 1);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ unsigned int size = GWN_vertformat_attr_add(format, "size", GWN_COMP_F32, 1, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR);
+ GPU_enable_program_point_size();
+ immBegin(GWN_PRIM_POINTS, totpoints);
+
+ const bGPDspoint *pt = points;
+ for (int i = 0; i < totpoints && pt; i++, pt++) {
+ gp_set_point_varying_color(pt, ink, color);
+ immAttrib1f(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! */
}
-
- glPopMatrix();
- gluDeleteQuadric(qobj);
+
+ immEnd();
+ immUnbindProgram();
+ GPU_disable_program_point_size();
}
/* --------------- Stroke Fills ----------------- */
/* 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];
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++) {
- bGPDspoint *pt = &points[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];
}
@@ -416,14 +451,14 @@ static void gp_stroke_2d_flat(bGPDspoint *points, int totpoints, float(*points2d
static void gp_triangulate_stroke_fill(bGPDstroke *gps)
{
BLI_assert(gps->totpoints >= 3);
-
+
/* allocate memory for temporary areas */
gps->tot_triangles = gps->totpoints - 2;
unsigned int (*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, "GP Stroke temp triangulation");
float (*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints, "GP Stroke temp 2d points");
-
+
int direction = 0;
-
+
/* convert to 2d and triangulate */
gp_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction);
BLI_polyfill_calc((const float(*)[2])points2d, (unsigned int)gps->totpoints, direction, (unsigned int(*)[3])tmp_triangles);
@@ -438,7 +473,7 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps)
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];
stroke_triangle->v1 = tmp_triangles[i][0];
@@ -450,15 +485,15 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps)
/* 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 */
if (tmp_triangles) MEM_freeN(tmp_triangles);
if (points2d) MEM_freeN(points2d);
@@ -468,42 +503,55 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps)
/* 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])
+ int offsx, int offsy, int winx, int winy, const float diff_mat[4][4], const float color[4])
{
- bGPDpalettecolor *palcolor;
- int i;
float fpt[3];
BLI_assert(gps->totpoints >= 3);
- palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
+ bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
/* Triangulation fill if high quality flag is enabled */
if (palcolor->flag & PC_COLOR_HQ_FILL) {
- bGPDtriangle *stroke_triangle;
- bGPDspoint *pt;
-
/* 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);
- for (i = 0, stroke_triangle = gps->triangles; i < gps->tot_triangles; i++, stroke_triangle++) {
+
+ unsigned int pos;
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+ else {
+ pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ }
+
+ immUniformColor4fv(color);
+
+ /* Draw all triangles for filling the polygon (cache must be calculated before) */
+ immBegin(GWN_PRIM_TRIS, gps->tot_triangles * 3);
+ /* TODO: use batch instead of immediate mode, to share vertices */
+
+ bGPDtriangle *stroke_triangle = gps->triangles;
+ bGPDspoint *pt;
+
+ for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) {
if (gps->flag & GP_STROKE_3DSPACE) {
/* vertex 1 */
pt = &gps->points[stroke_triangle->v1];
mul_v3_m4v3(fpt, diff_mat, &pt->x);
- glVertex3fv(fpt);
+ immVertex3fv(pos, fpt);
/* vertex 2 */
pt = &gps->points[stroke_triangle->v2];
mul_v3_m4v3(fpt, diff_mat, &pt->x);
- glVertex3fv(fpt);
+ immVertex3fv(pos, fpt);
/* vertex 3 */
pt = &gps->points[stroke_triangle->v3];
mul_v3_m4v3(fpt, diff_mat, &pt->x);
- glVertex3fv(fpt);
+ immVertex3fv(pos, fpt);
}
else {
float co[2];
@@ -511,49 +559,22 @@ static void gp_draw_stroke_fill(
pt = &gps->points[stroke_triangle->v1];
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);
/* vertex 2 */
pt = &gps->points[stroke_triangle->v2];
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);
/* vertex 3 */
pt = &gps->points[stroke_triangle->v3];
mul_v3_m4v3(fpt, diff_mat, &pt->x);
gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
- glVertex2fv(co);
- }
- }
- glEnd();
- }
- 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;
-
- 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);
+ immVertex2fv(pos, co);
}
}
- glEnd();
+ immEnd();
+ immUnbindProgram();
}
}
@@ -561,179 +582,189 @@ static void gp_draw_stroke_fill(
/* 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);
+ const bGPDspoint *pt = points;
- /* set point thickness (since there's only one of these) */
- glPointSize((float)(thickness + 2) * points->pressure);
-
/* get final position using parent matrix */
+ float fpt[3];
mul_v3_m4v3(fpt, diff_mat, &pt->x);
- /* draw point */
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_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];
-
- /* get coordinates of point */
+ 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);
-
- /* 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);
-
- /* 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);
-
- gluDeleteQuadric(qobj);
- }
+ copy_v3_v3(fpt, co);
}
+
+ gp_set_point_uniform_color(pt, ink);
+ /* set point thickness (since there's only one of these) */
+ immUniform1f("size", (float)(thickness + 2) * pt->pressure);
+
+ immBegin(GWN_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(bGPDspoint *points, int totpoints, short thickness, bool debug,
- short UNUSED(sflag), float diff_mat[4][4], float ink[4], bool cyclic)
+static void gp_draw_stroke_3d(const bGPDspoint *points, int totpoints, short thickness, bool UNUSED(debug),
+ short UNUSED(sflag), const float diff_mat[4][4], const float ink[4], bool cyclic)
{
- bGPDspoint *pt, *pt2;
float curpressure = points[0].pressure;
- int i;
float fpt[3];
float cyclic_fpt[3];
+ int draw_points = 0;
+
+ /* if cyclic needs one vertex more */
+ int cyclic_add = 0;
+ if (cyclic) {
+ ++cyclic_add;
+ }
+
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR);
+
+ /* TODO: implement this with a geometry shader to draw one continuous tapered stroke */
/* 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);
+ immBeginAtMost(GWN_PRIM_LINE_STRIP, totpoints + cyclic_add);
+ const bGPDspoint *pt = points;
+ for (int i = 0; i < totpoints; i++, pt++) {
+ gp_set_point_varying_color(pt, ink, color);
/* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
* and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP)
* Note: we want more visible levels of pressures when thickness is bigger.
*/
if (fabsf(pt->pressure - curpressure) > 0.2f / (float)thickness) {
- glEnd();
+ /* if the pressure changes before get at least 2 vertices, need to repeat last point to avoid assert in immEnd() */
+ if (draw_points < 2) {
+ const bGPDspoint *pt2 = pt - 1;
+ mul_v3_m4v3(fpt, diff_mat, &pt2->x);
+ immVertex3fv(pos, fpt);
+ }
+ immEnd();
+ draw_points = 0;
+
curpressure = pt->pressure;
glLineWidth(max_ff(curpressure * thickness, 1.0f));
- glBegin(GL_LINE_STRIP);
-
+ immBeginAtMost(GWN_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) {
- pt2 = pt - 1;
+ const bGPDspoint *pt2 = pt - 1;
mul_v3_m4v3(fpt, diff_mat, &pt2->x);
- glVertex3fv(fpt);
+ gp_set_point_varying_color(pt2, ink, color);
+ immVertex3fv(pos, fpt);
+ ++draw_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 */
- if (i == 0) {
+
+ /* now the point we want */
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ immVertex3fv(pos, fpt);
+ ++draw_points;
+
+ if (cyclic && i == 0) {
+ /* save first point to use in cyclic */
copy_v3_v3(cyclic_fpt, fpt);
}
}
- /* if cyclic draw line to first point */
+
if (cyclic) {
- glVertex3fv(cyclic_fpt);
+ /* draw line to first point to complete the cycle */
+ immVertex3fv(pos, cyclic_fpt);
+ ++draw_points;
}
- glEnd();
-
- /* 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));
-
- 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 less of two points, need to repeat last point to avoid assert in immEnd() */
+ if (draw_points < 2) {
+ const bGPDspoint *pt2 = pt - 1;
+ mul_v3_m4v3(fpt, diff_mat, &pt2->x);
+ gp_set_point_varying_color(pt2, ink, color);
+ immVertex3fv(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;
-
+
/* 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 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;
- float pm[2];
+ 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);
-
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBegin(GWN_PRIM_TRI_STRIP, totpoints * 2 + 4);
+
+ /* get x and y coordinates from first point */
+ mul_v3_m4v3(fpt, diff_mat, &points->x);
+ gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s0);
+
for (i = 0, pt1 = points, pt2 = points + 1; i < (totpoints - 1); i++, pt1++, pt2++) {
- float s0[2], s1[2]; /* segment 'center' points */
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 points */
- mul_v3_m4v3(fpt, diff_mat, &pt1->x);
- gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s0);
-
+ /* get x and y coordinates from point2 (point1 has already been computed in previous iteration). */
mul_v3_m4v3(fpt, diff_mat, &pt2->x);
gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s1);
-
+
/* calculate gradient and normal - 'angle'=(ny/nx) */
m1[1] = s1[1] - s0[1];
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);
-
+
/* color of point */
- gp_set_point_color(pt1, ink);
+ gp_set_point_varying_color(pt1, ink, color);
/* if the first segment, start of segment is segment's normal */
if (i == 0) {
@@ -744,40 +775,39 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
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];
-
- glVertex2fv(t0);
- glVertex2fv(t1);
-
+
+ /* 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];
-
- /* 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(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
@@ -786,49 +816,44 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
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];
-
- /* 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(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);
-
+
/* color of point */
- gp_set_point_color(pt2, ink);
+ gp_set_point_varying_color(pt2, ink, color);
/* 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];
-
- /* 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(pos, t0);
+ immVertex2fv(pos, t1);
+
/* draw end cap as last step
* - make points slightly closer to center (about halfway across)
*/
@@ -836,40 +861,25 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
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];
-
- glVertex2fv(t1);
- glVertex2fv(t0);
+
+ /* 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);
}
-
- 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,41 +894,41 @@ static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag)
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 *gpd, bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag,
+ bGPdata *gpd, const bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag,
bool debug, short lthick, const float opacity, const float tintcolor[4],
- const bool onion, const bool custonion, float diff_mat[4][4])
+ const bool onion, const bool custonion, const float diff_mat[4][4])
{
- bGPDstroke *gps;
float tcolor[4];
float tfill[4];
short sthickness;
float ink[4];
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ 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;
@@ -936,6 +946,10 @@ static void gp_draw_strokes(
/* calculate thickness */
sthickness = gps->thickness + 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);
@@ -949,10 +963,6 @@ static void gp_draw_strokes(
/* 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 */
@@ -962,19 +972,20 @@ static void gp_draw_strokes(
interp_v3_v3v3(tfill, palcolor->fill, tintcolor, tintcolor[3]);
tfill[3] = palcolor->fill[3] * opacity;
if (tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) {
+ const float *color;
if (!onion) {
- glColor4fv(tfill);
+ color = tfill;
}
else {
if (custonion) {
- glColor4fv(tintcolor);
+ color = tintcolor;
}
else {
ARRAY_SET_ITEMS(tfill, UNPACK3(palcolor->fill), tintcolor[3]);
- glColor4fv(tfill);
+ color = tfill;
}
}
- gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat);
+ gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat, color);
}
}
@@ -996,7 +1007,7 @@ static void gp_draw_strokes(
}
if (palcolor->flag & PC_COLOR_VOLUMETRIC) {
/* volumetric stroke drawing */
- gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, sthickness, dflag, gps->flag, diff_mat, ink);
+ gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, sthickness, ink);
}
else {
/* 3D Lines - OpenGL primitives-based */
@@ -1014,10 +1025,6 @@ static void gp_draw_strokes(
glDisable(GL_DEPTH_TEST);
bglPolygonOffset(0.0, 0.0);
-#if 0
- glDisable(GL_POLYGON_OFFSET_LINE);
- glPolygonOffset(0, 0);
-#endif
}
}
else {
@@ -1027,20 +1034,21 @@ static void gp_draw_strokes(
interp_v3_v3v3(tfill, palcolor->fill, tintcolor, tintcolor[3]);
tfill[3] = palcolor->fill[3] * opacity;
if (tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) {
+ const float *color;
if (!onion) {
- glColor4fv(tfill);
+ color = tfill;
}
else {
if (custonion) {
- glColor4fv(tintcolor);
+ color = tintcolor;
}
else {
ARRAY_SET_ITEMS(tfill, palcolor->fill[0], palcolor->fill[1], palcolor->fill[2],
tintcolor[3]);
- glColor4fv(tfill);
+ color = tfill;
}
}
- gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat);
+ gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat, color);
}
}
@@ -1078,15 +1086,15 @@ static void gp_draw_strokes(
}
}
}
+
+ 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;
@@ -1100,36 +1108,28 @@ static void gp_draw_strokes_edit(
glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
glDepthMask(0);
glEnable(GL_DEPTH_TEST);
-
+
/* first arg is normally rv3d->dist, but this isn't
* available here and seems to work quite well without */
bglPolygonOffset(1.0f, 1.0f);
-#if 0
- glEnable(GL_POLYGON_OFFSET_LINE);
- glPolygonOffset(-1.0f, -1.0f);
-#endif
}
}
-
-
- /* draw stroke verts */
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- bGPDspoint *pt;
- float vsize, bsize;
- int i;
- float fpt[3];
+ 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;
-
+
/* verify palette color lock */
{
bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
@@ -1148,7 +1148,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;
@@ -1156,89 +1157,83 @@ static void gp_draw_strokes_edit(
else {
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);
- glPointSize(bsize);
-
- glBegin(GL_POINTS);
- for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
+ float selectColor[4];
+ UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor);
+ selectColor[3] = alpha;
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos; /* specified later */
+ unsigned int size = GWN_vertformat_attr_add(format, "size", GWN_COMP_F32, 1, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR);
+ }
+ else {
+ pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR);
+ }
+
+ immBegin(GWN_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;
+ 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 */
+ immAttrib3f(color, 0.0f, 1.0f, 0.0f);
+ immAttrib1f(size, vsize + 4);
+ }
+ else if (show_direction_hint && (i == gps->totpoints - 1)) {
+ /* end point in red smaller */
+ immAttrib3f(color, 1.0f, 0.0f, 0.0f);
+ immAttrib1f(size, vsize + 1);
+ }
+ else if (pt->flag & GP_SPOINT_SELECT) {
+ immAttrib3fv(color, selectColor);
+ immAttrib1f(size, vsize);
+ }
+ else {
+ immAttrib3fv(color, palcolor->color);
+ immAttrib1f(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);
-
+
bglPolygonOffset(0.0, 0.0);
#if 0
glDisable(GL_POLYGON_OFFSET_LINE);
@@ -1252,8 +1247,8 @@ static void gp_draw_strokes_edit(
/* 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])
+ bGPdata *gpd, const bGPDlayer *gpl, const bGPDframe *gpf, int offsx, int offsy, int winx, int winy,
+ int UNUSED(cfra), int dflag, bool debug, const float diff_mat[4][4])
{
const float default_color[3] = {UNPACK3(U.gpencil_new_layer_col)};
const float alpha = 1.0f;
@@ -1266,17 +1261,14 @@ static void gp_draw_onionskins(
else {
copy_v3_v3(color, default_color);
}
-
+
if (gpl->gstep > 0) {
- bGPDframe *gf;
- float fac;
-
/* draw previous frames first */
- for (gf = gpf->prev; gf; gf = gf->prev) {
+ for (bGPDframe *gf = gpf->prev; gf; gf = gf->prev) {
/* check if frame is drawable */
if ((gpf->framenum - gf->framenum) <= gpl->gstep) {
/* alpha decreases with distance from curframe index */
- fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1));
+ float fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1));
color[3] = alpha * fac * 0.66f;
gp_draw_strokes(gpd, gf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
true, gpl->flag & GP_LAYER_GHOST_PREVCOL, diff_mat);
@@ -1296,8 +1288,7 @@ static void gp_draw_onionskins(
else {
/* don't draw - disabled */
}
-
-
+
/* 2) Now draw next frames */
if (gpl->flag & GP_LAYER_GHOST_NEXTCOL) {
copy_v3_v3(color, gpl->gcolor_next);
@@ -1305,17 +1296,14 @@ static void gp_draw_onionskins(
else {
copy_v3_v3(color, default_color);
}
-
+
if (gpl->gstep_next > 0) {
- bGPDframe *gf;
- float fac;
-
/* now draw next frames */
- for (gf = gpf->next; gf; gf = gf->next) {
+ for (bGPDframe *gf = gpf->next; gf; gf = gf->next) {
/* check if frame is drawable */
if ((gf->framenum - gpf->framenum) <= gpl->gstep_next) {
/* alpha decreases with distance from curframe index */
- fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep_next + 1));
+ float fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep_next + 1));
color[3] = alpha * fac * 0.66f;
gp_draw_strokes(gpd, gf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
true, gpl->flag & GP_LAYER_GHOST_NEXTCOL, diff_mat);
@@ -1335,34 +1323,64 @@ static void gp_draw_onionskins(
else {
/* don't draw - disabled */
}
-
+}
+
+/* draw interpolate strokes (used only while operator is running) */
+void ED_gp_draw_interpolation(tGPDinterpolate *tgpi, const int type)
+{
+ tGPDinterpolate_layer *tgpil;
+ float diff_mat[4][4];
+ float color[4];
+
+ int offsx = 0;
+ int offsy = 0;
+ int winx = tgpi->ar->winx;
+ int winy = tgpi->ar->winy;
+
+ 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);
+ }
+
+ /* 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);
+ }
+ }
+ glDisable(GL_BLEND);
}
/* loop over gpencil data layers, drawing them */
static void gp_draw_data_layers(
- bGPDbrush *brush, float alpha, bGPdata *gpd,
+ const bGPDbrush *brush, float alpha, bGPdata *gpd,
int offsx, int offsy, int winx, int winy, int cfra, int dflag)
{
- bGPDlayer *gpl;
float diff_mat[4][4];
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- bGPDframe *gpf;
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* calculate parent position */
ED_gpencil_parent_location(gpl, diff_mat);
- bool debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? true : false;
+ bool debug = (gpl->flag & GP_LAYER_DRAWDEBUG);
short lthick = brush->thickness + gpl->thickness;
-
+
/* 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, 0);
if (gpf == NULL)
continue;
-
+
/* set basic stroke thickness */
glLineWidth(lthick);
@@ -1374,10 +1392,10 @@ static void gp_draw_data_layers(
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);
-
+
/* volumetric strokes... */
GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_VOLUMETRIC), GP_DRAWDATA_VOLUMETRIC);
@@ -1386,18 +1404,26 @@ static void gp_draw_data_layers(
#undef GP_DRAWFLAG_APPLY
- /* draw 'onionskins' (frame left + right) */
- if ((gpl->flag & GP_LAYER_ONIONSKIN) && !(dflag & GP_DRAWDATA_NO_ONIONS)) {
+ /* 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);
}
-
+
/* 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);
-
+
/* 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
@@ -1412,16 +1438,13 @@ static void gp_draw_data_layers(
{
gp_draw_strokes_edit(gpd, gpf, offsx, offsy, winx, winy, dflag, gpl->flag, diff_mat, alpha);
}
-
+
/* Check if may need to draw the active stroke cache, only if this layer is the active layer
* 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))
{
- /* 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.
*
@@ -1430,89 +1453,84 @@ static void gp_draw_data_layers(
*/
if (gpd->sflag & PC_COLOR_VOLUMETRIC) {
gp_draw_stroke_volumetric_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick,
- dflag, gpd->sbuffer_sflag, gpd->scolor);
+ dflag, gpd->scolor);
}
else {
- gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag, gpd->scolor);
+ gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag, gpd->scolor, gpd->sfill);
}
}
}
}
/* draw a short status message in the top-right corner */
-static void gp_draw_status_text(bGPdata *gpd, ARegion *ar)
+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 xco, yco;
-
- BLF_width_and_height_default(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 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_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
BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
#endif
-
+
/* grease pencil icon... */
// XXX: is this too intrusive?
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
-
+
xco -= U.widget_unit;
yco -= (int)printable_size[1] / 2;
UI_icon_draw(xco, yco, ICON_GREASEPENCIL);
-
+
glDisable(GL_BLEND);
}
}
/* draw grease-pencil datablock */
static void gp_draw_data(
- bGPDbrush *brush, float alpha, bGPdata *gpd,
+ const bGPDbrush *brush, float alpha, bGPdata *gpd,
int offsx, int offsy, int winx, int winy, int cfra, int dflag)
{
- /* reset line drawing style (in case previous user didn't reset) */
- setlinestyle(0);
-
/* turn on smooth lines (i.e. anti-aliasing) */
glEnable(GL_LINE_SMOOTH);
-
+
/* 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
* creating internal white rays due to the ways it accumulates stuff
*/
-
+
/* turn on alpha-blending */
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
-
+
/* draw! */
gp_draw_data_layers(brush, alpha, gpd, offsx, offsy, winx, winy, cfra, dflag);
-
+
/* turn off alpha blending, then smooth lines */
glDisable(GL_BLEND); // alpha blending
glDisable(GL_LINE_SMOOTH); // smooth lines
-
- /* restore initial gl conditions */
- glColor4f(0, 0, 0, 1);
}
/* if we have strokes for scenes (3d view)/clips (movie clip editor)
@@ -1521,8 +1539,17 @@ static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, i
int cfra, int dflag, const char spacetype)
{
bGPdata *gpd_source = NULL;
-
+ ToolSettings *ts;
+ bGPDbrush *brush = NULL;
if (scene) {
+ ts = scene->toolsettings;
+ brush = BKE_gpencil_brush_getactive(ts);
+ /* if no brushes, create default set */
+ if (brush == NULL) {
+ BKE_gpencil_brush_init_presets(ts);
+ brush = BKE_gpencil_brush_getactive(ts);
+ }
+
if (spacetype == SPACE_VIEW3D) {
gpd_source = (scene->gpd ? scene->gpd : NULL);
}
@@ -1530,23 +1557,18 @@ static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, i
/* 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) {
- ToolSettings *ts = scene->toolsettings;
- bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
if (brush != NULL) {
gp_draw_data(brush, ts->gp_sculpt.alpha, gpd_source,
offsx, offsy, winx, winy, cfra, dflag);
}
-
}
}
-
+
/* scene/clip data has already been drawn, only object/track data is drawn here
* if gpd_source == gpd, we don't have any object/track data and we can skip */
if (gpd_source == NULL || (gpd_source && gpd_source != gpd)) {
- ToolSettings *ts = scene->toolsettings;
- bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
if (brush != NULL) {
gp_draw_data(brush, ts->gp_sculpt.alpha, gpd,
offsx, offsy, winx, winy, cfra, dflag);
@@ -1569,28 +1591,27 @@ void ED_gpencil_draw_2dimage(const bContext *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;
-
- gpd = ED_gpencil_data_get_active(C); // XXX
+
+ 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;
}
@@ -1601,7 +1622,7 @@ void ED_gpencil_draw_2dimage(const bContext *C)
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
*/
@@ -1613,77 +1634,74 @@ void ED_gpencil_draw_2dimage(const bContext *C)
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=1 to draw 'canvas' strokes,
- * second time with onlyv2d=0 for screen-aligned strokes */
+ * 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);
- 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
+ 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 == false) {
+ if (!onlyv2d) {
gp_draw_status_text(gpd, ar);
}
}
/* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly
- * Note: this gets called twice - first time with only3d=1 to draw 3d-strokes,
- * second time with only3d=0 for screen-aligned strokes */
+ * 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, View3D *v3d, ARegion *ar, bool only3d)
{
- bGPdata *gpd;
int dflag = 0;
RegionView3D *rv3d = ar->regiondata;
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 = ED_gpencil_data_get_active_v3d(scene, v3d);
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 */
-
+
offsx = iroundf(rectf.xmin);
offsy = iroundf(rectf.ymin);
winx = iroundf(rectf.xmax - rectf.xmin);
@@ -1695,7 +1713,7 @@ void ED_gpencil_draw_view3d(wmWindowManager *wm, Scene *scene, View3D *v3d, AReg
winx = ar->winx;
winy = ar->winy;
}
-
+
/* set flags */
if (only3d) {
/* 3D strokes/3D space:
@@ -1704,28 +1722,27 @@ void ED_gpencil_draw_view3d(wmWindowManager *wm, Scene *scene, View3D *v3d, AReg
*/
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;
}
-
+
if ((wm == NULL) || ED_screen_animation_playing(wm)) {
/* don't show onionskins during animation playback/scrub (i.e. it obscures the poses)
* OpenGL Renders (i.e. final output), or depth buffer (i.e. not real strokes)
*/
dflag |= GP_DRAWDATA_NO_ONIONS;
}
-
+
/* draw it! */
- gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype);
-
+ gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype);
}
void ED_gpencil_draw_ex(Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype)
{
int dflag = GP_DRAWDATA_NOSTATUS | GP_DRAWDATA_ONLYV2D;
-
+
gp_draw_data_all(scene, gpd, 0, 0, winx, winy, cfra, dflag, spacetype);
}
diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c
index fcb2ce02bde..f478596deec 100644
--- a/source/blender/editors/gpencil/gpencil_brush.c
+++ b/source/blender/editors/gpencil/gpencil_brush.c
@@ -75,8 +75,8 @@
#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 "gpencil_intern.h"
@@ -297,9 +297,9 @@ static bool gp_brush_strength_apply(
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
- */
+ * - We divide the strength by 10, so that users can set "sane" values.
+ * Otherwise, good default values are in the range of 0.093
+ */
inf = gp_brush_influence_calc(gso, radius, co) / 10.0f;
/* apply */
@@ -773,6 +773,9 @@ typedef struct tGPSB_CloneBrushData {
/* for "stamp" mode, the currently pasted brushes */
bGPDstroke **new_strokes;
+
+ /* mapping from colors referenced per stroke, to the new colours in the "pasted" strokes */
+ GHash *new_colors;
} tGPSB_CloneBrushData;
/* Initialise "clone" brush data */
@@ -816,6 +819,11 @@ static void gp_brush_clone_init(bContext *C, tGP_BrushEditData *gso)
if (1 /*gso->brush->mode == GP_EDITBRUSH_CLONE_MODE_STAMP*/) {
data->new_strokes = MEM_callocN(sizeof(bGPDstroke *) * data->totitems, "cloned strokes ptr array");
}
+
+ /* 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);
}
/* Free custom data used for "clone" brush */
@@ -829,6 +837,12 @@ static void gp_brush_clone_free(tGP_BrushEditData *gso)
data->new_strokes = NULL;
}
+ /* free copybuf colormap */
+ if (data->new_colors) {
+ BLI_ghash_free(data->new_colors, NULL, NULL);
+ data->new_colors = NULL;
+ }
+
/* free the customdata itself */
MEM_freeN(data);
gso->customdata = NULL;
@@ -869,6 +883,13 @@ static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso)
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));
+
/* Adjust all the stroke's points, so that the strokes
* get pasted relative to where the cursor is now
*/
@@ -958,28 +979,28 @@ static bool gpsculpt_brush_apply_clone(bContext *C, tGP_BrushEditData *gso)
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);
-
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
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);
-
+ immUniformColor4ub(255, 255, 255, 200);
+ imm_draw_circle_wire(pos, x, y, 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);
-
+ immUniformColor3ub(30, 30, 30);
+ imm_draw_circle_wire(pos, x, y, brush->size + 1, 40);
+
+ immUnbindProgram();
+
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
-
- glPopMatrix();
}
}
@@ -1350,6 +1371,10 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
{
+ bGPDframe *gpf = gpl->actframe;
+ if (gpf == NULL)
+ continue;
+
/* calculate difference matrix if parent object */
if (gpl->parent != NULL) {
ED_gpencil_parent_location(gpl, diff_mat);
@@ -1358,10 +1383,8 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
else {
parented = false;
}
-
- bGPDframe *gpf = gpl->actframe;
- bGPDstroke *gps;
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false)
continue;
@@ -1796,6 +1819,12 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even
case UPARROWKEY:
case DOWNARROWKEY:
return OPERATOR_PASS_THROUGH;
+
+ /* Camera/View Manipulations - Allowed */
+ /* (See rationale in gpencil_paint.c -> gpencil_draw_modal()) */
+ case PAD0: case PAD1: case PAD2: case PAD3: case PAD4:
+ case PAD5: case PAD6: case PAD7: case PAD8: case PAD9:
+ return OPERATOR_PASS_THROUGH;
/* Unhandled event */
default:
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index c502ed1aa83..a4e5a908531 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -56,12 +56,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_layer.h"
#include "BKE_library.h"
#include "BKE_object.h"
#include "BKE_report.h"
@@ -69,6 +70,8 @@
#include "BKE_screen.h"
#include "BKE_tracking.h"
+#include "DEG_depsgraph.h"
+
#include "UI_interface.h"
#include "WM_api.h"
@@ -191,7 +194,7 @@ static void gp_strokepoint_convertcoords(
}
}
- ED_view3d_win_to_3d(ar, fp, mvalf, p3d);
+ ED_view3d_win_to_3d(v3d, ar, fp, mvalf, p3d);
}
}
@@ -546,7 +549,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
@@ -1121,14 +1124,15 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG
const bool norm_weights, const float rad_fac, const bool link_strokes, tGpTimingData *gtd)
{
struct Main *bmain = CTX_data_main(C);
- View3D *v3d = CTX_wm_view3d(C); /* may be NULL */
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ SceneCollection *sc = CTX_data_scene_collection(C);
bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0);
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 */
@@ -1152,7 +1156,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(scene, sc, ob);
+ base_new = BKE_scene_layer_base_find(sl, ob);
cu->flag |= CU_3D;
@@ -1216,8 +1221,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);
}
/* --- */
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index 876f873e5fa..6980ad46241 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -42,6 +42,7 @@
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -75,9 +76,6 @@
#include "gpencil_intern.h"
-/* maximum sizes of gp-session buffer */
-#define GP_STROKE_BUFFER_MAX 5000
-
/* ************************************************ */
/* Datablock Operators */
@@ -87,7 +85,8 @@
static int gp_data_add_exec(bContext *C, wmOperator *op)
{
bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
-
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
if (gpd_ptr == NULL) {
BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
return OPERATOR_CANCELLED;
@@ -98,6 +97,15 @@ static int gp_data_add_exec(bContext *C, wmOperator *op)
id_us_min(&gpd->id);
*gpd_ptr = BKE_gpencil_data_addnew(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);
+ }
+ }
+
}
/* notifiers */
@@ -111,7 +119,7 @@ void GPENCIL_OT_data_add(wmOperatorType *ot)
/* identifiers */
ot->name = "Grease Pencil Add New";
ot->idname = "GPENCIL_OT_data_add";
- ot->description = "Add new Grease Pencil datablock";
+ ot->description = "Add new Grease Pencil data-block";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* callbacks */
@@ -159,7 +167,7 @@ void GPENCIL_OT_data_unlink(wmOperatorType *ot)
/* identifiers */
ot->name = "Grease Pencil Unlink";
ot->idname = "GPENCIL_OT_data_unlink";
- ot->description = "Unlink active Grease Pencil datablock";
+ ot->description = "Unlink active Grease Pencil data-block";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* callbacks */
@@ -177,7 +185,8 @@ void GPENCIL_OT_data_unlink(wmOperatorType *ot)
static int gp_layer_add_exec(bContext *C, wmOperator *op)
{
bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
-
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
/* if there's no existing Grease-Pencil data there, add some */
if (gpd_ptr == NULL) {
BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
@@ -186,6 +195,14 @@ static int gp_layer_add_exec(bContext *C, wmOperator *op)
if (*gpd_ptr == NULL)
*gpd_ptr = BKE_gpencil_data_addnew(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);
+ }
+ }
+
/* add new layer now */
BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true);
@@ -200,7 +217,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 datablock";
+ ot->description = "Add new Grease Pencil layer for the active Grease Pencil data-block";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -275,21 +292,11 @@ static int gp_layer_move_exec(bContext *C, wmOperator *op)
if (ELEM(NULL, gpd, gpl))
return OPERATOR_CANCELLED;
- /* up or down? */
- if (direction == GP_LAYER_MOVE_UP) {
- /* up */
- BLI_remlink(&gpd->layers, gpl);
- BLI_insertlinkbefore(&gpd->layers, gpl->prev, gpl);
- }
- else {
- /* down */
- BLI_remlink(&gpd->layers, gpl);
- BLI_insertlinkafter(&gpd->layers, gpl->next, gpl);
+ BLI_assert(ELEM(direction, -1, 0, 1)); /* we use value below */
+ if (BLI_listbase_link_move(&gpd->layers, gpl, direction)) {
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
return OPERATOR_FINISHED;
}
@@ -764,14 +771,12 @@ static int gp_stroke_arrange_exec(bContext *C, wmOperator *op)
/* some stroke is already at front*/
if ((direction == GP_STROKE_MOVE_TOP) || (direction == GP_STROKE_MOVE_UP)) {
if (gps == gpf->strokes.last) {
- BKE_report(op->reports, RPT_ERROR, "Some selected stroke is already on top");
return OPERATOR_CANCELLED;
}
}
/* some stroke is already at botom */
if ((direction == GP_STROKE_MOVE_BOTTOM) || (direction == GP_STROKE_MOVE_DOWN)) {
if (gps == gpf->strokes.first) {
- BKE_report(op->reports, RPT_ERROR, "Some selected stroke is already on bottom");
return OPERATOR_CANCELLED;
}
}
@@ -787,23 +792,21 @@ static int gp_stroke_arrange_exec(bContext *C, wmOperator *op)
for (LinkData *link = selected.first; link; link = link->next) {
gps = link->data;
BLI_remlink(&gpf->strokes, gps);
- BLI_insertlinkafter(&gpf->strokes, gpf->strokes.last, gps);
+ 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_remlink(&gpf->strokes, gps);
- BLI_insertlinkafter(&gpf->strokes, gps->next, gps);
+ BLI_listbase_link_move(&gpf->strokes, gps, 1);
}
break;
- /* Send Backward */
+ /* Send Backward */
case GP_STROKE_MOVE_DOWN:
for (LinkData *link = selected.first; link; link = link->next) {
gps = link->data;
- BLI_remlink(&gpf->strokes, gps);
- BLI_insertlinkbefore(&gpf->strokes, gps->prev, gps);
+ BLI_listbase_link_move(&gpf->strokes, gps, -1);
}
break;
/* Send to Back */
@@ -811,13 +814,15 @@ static int gp_stroke_arrange_exec(bContext *C, wmOperator *op)
for (LinkData *link = selected.last; link; link = link->prev) {
gps = link->data;
BLI_remlink(&gpf->strokes, gps);
- BLI_insertlinkbefore(&gpf->strokes, gpf->strokes.first, gps);
+ BLI_addhead(&gpf->strokes, gps);
}
break;
default:
BLI_assert(0);
break;
}
+ BLI_freelistN(&selected);
+
/* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -882,9 +887,9 @@ static int gp_stroke_change_color_exec(bContext *C, wmOperator *UNUSED(op))
continue;
/* asign new color (only if different) */
- if (STREQ(gps->colorname, color->info) == false) {
- strcpy(gps->colorname, color->info);
- gps->flag |= GP_STROKE_RECALC_COLOR;
+ if ((STREQ(gps->colorname, color->info) == false) || (gps->palcolor != color)) {
+ BLI_strncpy(gps->colorname, color->info, sizeof(gps->colorname));
+ gps->palcolor = color;
}
}
}
@@ -965,431 +970,6 @@ void GPENCIL_OT_stroke_lock_color(wmOperatorType *ot)
ot->poll = gp_active_layer_poll;
}
-/* ******************* Apply layer thickness change to Strokes ************************** */
-
-static int gp_stroke_apply_thickness_exec(bContext *C, wmOperator *UNUSED(op))
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
-
- /* sanity checks */
- if (ELEM(NULL, gpd, gpl, gpl->frames.first))
- return OPERATOR_CANCELLED;
-
- /* loop all strokes */
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- /* Apply thickness */
- gps->thickness = gps->thickness + gpl->thickness;
- }
- }
- /* clear value */
- gpl->thickness = 0.0f;
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GPENCIL_OT_stroke_apply_thickness(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Apply Stroke Thickness";
- ot->idname = "GPENCIL_OT_stroke_apply_thickness";
- ot->description = "Apply the thickness change of the layer to its strokes";
-
- /* api callbacks */
- ot->exec = gp_stroke_apply_thickness_exec;
- ot->poll = gp_active_layer_poll;
-}
-
-/* ******************* Close Strokes ************************** */
-
-enum {
- GP_STROKE_CYCLIC_CLOSE = 1,
- GP_STROKE_CYCLIC_OPEN = 2,
- GP_STROKE_CYCLIC_TOGGLE = 3
-};
-
-static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- const int type = RNA_enum_get(op->ptr, "type");
-
- /* sanity checks */
- if (ELEM(NULL, gpd))
- return OPERATOR_CANCELLED;
-
- /* loop all selected strokes */
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
- bGPDpalettecolor *palcolor = gps->palcolor;
-
- /* skip strokes that are not selected or invalid for current view */
- if (((gps->flag & GP_STROKE_SELECT) == 0) || ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
- /* skip hidden or locked colors */
- if (!palcolor || (palcolor->flag & PC_COLOR_HIDE) || (palcolor->flag & PC_COLOR_LOCKED))
- continue;
-
- switch (type) {
- case GP_STROKE_CYCLIC_CLOSE:
- /* Close all (enable) */
- gps->flag |= GP_STROKE_CYCLIC;
- break;
- case GP_STROKE_CYCLIC_OPEN:
- /* Open all (disable) */
- gps->flag &= ~GP_STROKE_CYCLIC;
- break;
- case GP_STROKE_CYCLIC_TOGGLE:
- /* Just toggle flag... */
- gps->flag ^= GP_STROKE_CYCLIC;
- break;
- default:
- BLI_assert(0);
- break;
- }
- }
- }
- CTX_DATA_END;
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-/**
- * Similar to #CURVE_OT_cyclic_toggle or #MASK_OT_cyclic_toggle, but with
- * option to force opened/closed strokes instead of just toggle behavior.
- */
-void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot)
-{
- static EnumPropertyItem cyclic_type[] = {
- {GP_STROKE_CYCLIC_CLOSE, "CLOSE", 0, "Close all", ""},
- {GP_STROKE_CYCLIC_OPEN, "OPEN", 0, "Open all", ""},
- {GP_STROKE_CYCLIC_TOGGLE, "TOGGLE", 0, "Toggle", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Set Cyclical State";
- ot->idname = "GPENCIL_OT_stroke_cyclical_set";
- ot->description = "Close or open the selected stroke adding an edge from last to first point";
-
- /* api callbacks */
- ot->exec = gp_stroke_cyclical_set_exec;
- ot->poll = gp_active_layer_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- ot->prop = RNA_def_enum(ot->srna, "type", cyclic_type, GP_STROKE_CYCLIC_TOGGLE, "Type", "");
-}
-
-/* ******************* Stroke join ************************** */
-
-/* Helper: flip stroke */
-static void gpencil_flip_stroke(bGPDstroke *gps)
-{
- bGPDspoint pt, *point, *point2;
- int end = gps->totpoints - 1;
-
- for (int i = 0; i < gps->totpoints / 2; i++) {
- /* save first point */
- point = &gps->points[i];
- pt.x = point->x;
- pt.y = point->y;
- pt.z = point->z;
- pt.flag = point->flag;
- pt.pressure = point->pressure;
- pt.strength = point->strength;
- pt.time = point->time;
-
- /* replace first point with last point */
- point2 = &gps->points[end];
- point->x = point2->x;
- point->y = point2->y;
- point->z = point2->z;
- point->flag = point2->flag;
- point->pressure = point2->pressure;
- point->strength = point2->strength;
- point->time = point2->time;
-
- /* replace last point with first saved before */
- point = &gps->points[end];
- point->x = pt.x;
- point->y = pt.y;
- point->z = pt.z;
- point->flag = pt.flag;
- point->pressure = pt.pressure;
- point->strength = pt.strength;
- point->time = pt.time;
-
- end--;
- }
-}
-
-/* Helper: copy point between strokes */
-static void gpencil_stroke_copy_point(bGPDstroke *gps, bGPDspoint *point, float delta[3],
- float pressure, float strength, float deltatime)
-{
- bGPDspoint *newpoint;
-
- gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
- gps->totpoints++;
-
- newpoint = &gps->points[gps->totpoints - 1];
- newpoint->x = point->x * delta[0];
- newpoint->y = point->y * delta[1];
- newpoint->z = point->z * delta[2];
- newpoint->flag = point->flag;
- newpoint->pressure = pressure;
- newpoint->strength = strength;
- newpoint->time = point->time + deltatime;
-}
-
-/* Helper: join two strokes using the shortest distance (reorder stroke if necessary ) */
-static void gpencil_stroke_join_strokes(bGPDstroke *gps_a, bGPDstroke *gps_b, const bool leave_gaps)
-{
- bGPDspoint point, *pt;
- int i;
- float delta[3] = {1.0f, 1.0f, 1.0f};
- float deltatime = 0.0f;
-
- /* sanity checks */
- if (ELEM(NULL, gps_a, gps_b))
- return;
-
- if ((gps_a->totpoints == 0) || (gps_b->totpoints == 0))
- return;
-
- /* define start and end points of each stroke */
- float sa[3], sb[3], ea[3], eb[3];
- pt = &gps_a->points[0];
- copy_v3_v3(sa, &pt->x);
-
- pt = &gps_a->points[gps_a->totpoints - 1];
- copy_v3_v3(ea, &pt->x);
-
- pt = &gps_b->points[0];
- copy_v3_v3(sb, &pt->x);
-
- pt = &gps_b->points[gps_b->totpoints - 1];
- copy_v3_v3(eb, &pt->x);
-
- /* review if need flip stroke B */
- float ea_sb = len_squared_v3v3(ea, sb);
- float ea_eb = len_squared_v3v3(ea, eb);
- /* flip if distance to end point is shorter */
- if (ea_eb < ea_sb) {
- gpencil_flip_stroke(gps_b);
- }
-
- /* don't visibly link the first and last points? */
- if (leave_gaps) {
- /* 1st: add one tail point to start invisible area */
- point = gps_a->points[gps_a->totpoints - 1];
- deltatime = point.time;
- gpencil_stroke_copy_point(gps_a, &point, delta, 0.0f, 0.0f, 0.0f);
-
- /* 2nd: add one head point to finish invisible area */
- point = gps_b->points[0];
- gpencil_stroke_copy_point(gps_a, &point, delta, 0.0f, 0.0f, deltatime);
- }
-
- /* 3rd: add all points */
- for (i = 0, pt = gps_b->points; i < gps_b->totpoints && pt; i++, pt++) {
- /* check if still room in buffer */
- if (gps_a->totpoints <= GP_STROKE_BUFFER_MAX - 2) {
- gpencil_stroke_copy_point(gps_a, pt, delta, pt->pressure, pt->strength, deltatime);
- }
- }
-}
-
-static int gp_stroke_join_exec(bContext *C, wmOperator *op)
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *activegpl = BKE_gpencil_layer_getactive(gpd);
- bGPDstroke *gps, *gpsn;
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
- bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
-
- bGPDframe *gpf_a = NULL;
- bGPDstroke *stroke_a = NULL;
- bGPDstroke *stroke_b = NULL;
- bGPDstroke *new_stroke = NULL;
-
- const int type = RNA_enum_get(op->ptr, "type");
- const bool leave_gaps = RNA_boolean_get(op->ptr, "leave_gaps");
-
- /* sanity checks */
- if (ELEM(NULL, gpd))
- return OPERATOR_CANCELLED;
-
- if (activegpl->flag & GP_LAYER_LOCKED)
- return OPERATOR_CANCELLED;
-
- BLI_assert(ELEM(type, GP_STROKE_JOIN, GP_STROKE_JOINCOPY));
-
-
- /* read all selected strokes */
- bool first = false;
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *gpf = gpl->actframe;
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
- if (gps->flag & GP_STROKE_SELECT) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
- continue;
- }
- /* to join strokes, cyclic must be disabled */
- gps->flag &= ~GP_STROKE_CYCLIC;
- /* saves first frame and stroke */
- if (!first) {
- first = true;
- gpf_a = gpf;
- stroke_a = gps;
- }
- else {
- stroke_b = gps;
- /* create a new stroke if was not created before (only created if something to join) */
- if (new_stroke == NULL) {
- new_stroke = MEM_dupallocN(stroke_a);
- new_stroke->points = MEM_dupallocN(stroke_a->points);
- new_stroke->triangles = NULL;
- new_stroke->tot_triangles = 0;
- new_stroke->flag |= GP_STROKE_RECALC_CACHES;
- /* if new, set current color */
- if (type == GP_STROKE_JOINCOPY) {
- new_stroke->palcolor = palcolor;
- strcpy(new_stroke->colorname, palcolor->info);
- new_stroke->flag |= GP_STROKE_RECALC_COLOR;
- }
- }
- /* join new_stroke and stroke B. New stroke will contain all the previous data */
- gpencil_stroke_join_strokes(new_stroke, stroke_b, leave_gaps);
-
- /* if join only, delete old strokes */
- if (type == GP_STROKE_JOIN) {
- if (stroke_a) {
- BLI_insertlinkbefore(&gpf_a->strokes, stroke_a, new_stroke);
- BLI_remlink(&gpf->strokes, stroke_a);
- BKE_gpencil_free_stroke(stroke_a);
- stroke_a = NULL;
- }
- if (stroke_b) {
- BLI_remlink(&gpf->strokes, stroke_b);
- BKE_gpencil_free_stroke(stroke_b);
- stroke_b = NULL;
- }
- }
- }
- }
- }
- }
- CTX_DATA_END;
- /* add new stroke if was not added before */
- if (type == GP_STROKE_JOINCOPY) {
- if (new_stroke) {
- /* Add a new frame if needed */
- if (activegpl->actframe == NULL)
- activegpl->actframe = BKE_gpencil_frame_addnew(activegpl, gpf_a->framenum);
-
- BLI_addtail(&activegpl->actframe->strokes, new_stroke);
- }
- }
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GPENCIL_OT_stroke_join(wmOperatorType *ot)
-{
- static EnumPropertyItem join_type[] = {
- {GP_STROKE_JOIN, "JOIN", 0, "Join", ""},
- {GP_STROKE_JOINCOPY, "JOINCOPY", 0, "Join and Copy", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Join Strokes";
- ot->idname = "GPENCIL_OT_stroke_join";
- ot->description = "Join selected strokes (optionally as new stroke)";
-
- /* api callbacks */
- ot->exec = gp_stroke_join_exec;
- ot->poll = gp_active_layer_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- ot->prop = RNA_def_enum(ot->srna, "type", join_type, GP_STROKE_JOIN, "Type", "");
- RNA_def_boolean(ot->srna, "leave_gaps", false, "Leave Gaps", "Leave gaps between joined strokes instead of linking them");
-}
-
-/* ******************* Stroke flip ************************** */
-
-static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op))
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
-
- /* sanity checks */
- if (ELEM(NULL, gpd))
- return OPERATOR_CANCELLED;
-
- /* read all selected strokes */
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *gpf = gpl->actframe;
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- if (gps->flag & GP_STROKE_SELECT) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
- continue;
- }
- /* flip stroke */
- gpencil_flip_stroke(gps);
- }
- }
- }
- CTX_DATA_END;
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GPENCIL_OT_stroke_flip(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Flip Stroke";
- ot->idname = "GPENCIL_OT_stroke_flip";
- ot->description = "Change direction of the points of the selected strokes";
-
- /* api callbacks */
- ot->exec = gp_stroke_flip_exec;
- ot->poll = gp_active_layer_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
/* ************************************************ */
/* Drawing Brushes Operators */
@@ -1419,7 +999,7 @@ void GPENCIL_OT_brush_add(wmOperatorType *ot)
/* identifiers */
ot->name = "Add Brush";
ot->idname = "GPENCIL_OT_brush_add";
- ot->description = "Add new Grease Pencil drawing brush for the active Grease Pencil datablock";
+ ot->description = "Add new Grease Pencil drawing brush for the active Grease Pencil data-block";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1439,8 +1019,8 @@ static int gp_brush_remove_exec(bContext *C, wmOperator *op)
if (ELEM(NULL, ts, brush))
return OPERATOR_CANCELLED;
- if (BLI_listbase_count(&ts->gp_brushes) < 2) {
- BKE_report(op->reports, RPT_ERROR, "Grease Pencil needs a brush. Unable to delete brush");
+ if (BLI_listbase_count_ex(&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;
}
@@ -1466,7 +1046,7 @@ static int gp_brush_remove_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_brush_remove(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Remove brush";
+ ot->name = "Remove Brush";
ot->idname = "GPENCIL_OT_brush_remove";
ot->description = "Remove active Grease Pencil drawing brush";
@@ -1777,7 +1357,7 @@ void GPENCIL_OT_palette_add(wmOperatorType *ot)
/* identifiers */
ot->name = "Add Palette";
ot->idname = "GPENCIL_OT_palette_add";
- ot->description = "Add new Grease Pencil palette for the active Grease Pencil datablock";
+ ot->description = "Add new Grease Pencil palette for the active Grease Pencil data-block";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1797,8 +1377,8 @@ static int gp_palette_remove_exec(bContext *C, wmOperator *op)
if (ELEM(NULL, gpd, palette))
return OPERATOR_CANCELLED;
- if (BLI_listbase_count(&gpd->palettes) < 2) {
- BKE_report(op->reports, RPT_ERROR, "Grease Pencil needs a palette. Unable to delete palette");
+ if (BLI_listbase_count_ex(&gpd->palettes, 2) < 2) {
+ BKE_report(op->reports, RPT_ERROR, "Grease Pencil needs a palette, unable to delete the last one");
return OPERATOR_CANCELLED;
}
@@ -1994,7 +1574,7 @@ void GPENCIL_OT_palettecolor_add(wmOperatorType *ot)
/* identifiers */
ot->name = "Add Palette Color";
ot->idname = "GPENCIL_OT_palettecolor_add";
- ot->description = "Add new Grease Pencil palette color for the active Grease Pencil datablock";
+ ot->description = "Add new Grease Pencil palette color for the active Grease Pencil data-block";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index b298769c6dc..6310cab9e4e 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -18,7 +18,7 @@
* The Original Code is Copyright (C) 2008, Blender Foundation, Joshua Leung
* This is a new part of Blender
*
- * Contributor(s): Joshua Leung
+ * Contributor(s): Joshua Leung, Antonio Vazquez
*
* ***** END GPL LICENSE BLOCK *****
*
@@ -38,8 +38,11 @@
#include "MEM_guardedalloc.h"
-#include "BLI_math.h"
#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -72,7 +75,9 @@
#include "ED_gpencil.h"
#include "ED_object.h"
+#include "ED_screen.h"
#include "ED_view3d.h"
+#include "ED_space_api.h"
#include "gpencil_intern.h"
@@ -93,7 +98,11 @@ static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *UNUSED(op))
/* 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);
+ }
+
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL);
WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
@@ -207,7 +216,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);
- strcpy(gpsd->tmp_layerinfo, layername); /* saves original layer name */
+ BLI_strncpy(gpsd->tmp_layerinfo, layername, sizeof(gpsd->tmp_layerinfo)); /* saves original layer name */
/* initialize triangle memory - will be calculated on next redraw */
gpsd->triangles = NULL;
@@ -266,7 +275,7 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op)
/* make direct copies of the stroke and its points */
gpsd = MEM_dupallocN(gps);
- strcpy(gpsd->tmp_layerinfo, gpl->info);
+ BLI_strncpy(gpsd->tmp_layerinfo, gpl->info, sizeof(gpsd->tmp_layerinfo));
gpsd->points = MEM_dupallocN(gps->points);
/* triangle information - will be calculated on next redraw */
@@ -329,11 +338,27 @@ void GPENCIL_OT_duplicate(wmOperatorType *ot)
/* NOTE: is exposed within the editors/gpencil module so that other tools can use it too */
ListBase gp_strokes_copypastebuf = {NULL, NULL};
+/* Hash for hanging on to all the palette colors used by strokes in the buffer
+ *
+ * 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).
+ */
+GHash *gp_strokes_copypastebuf_colors = 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
+ */
+ if (gp_strokes_copypastebuf_colors) {
+ BLI_ghash_free(gp_strokes_copypastebuf_colors, NULL, MEM_freeN);
+ gp_strokes_copypastebuf_colors = NULL;
+ }
+
+ /* Free the stroke buffer */
for (gps = gp_strokes_copypastebuf.first; gps; gps = gpsn) {
gpsn = gps->next;
@@ -346,6 +371,46 @@ void ED_gpencil_strokes_copybuf_free(void)
gp_strokes_copypastebuf.first = gp_strokes_copypastebuf.last = NULL;
}
+/* 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 *new_colors = BLI_ghash_str_new("GPencil Paste Dst Colors");
+ GHashIterator gh_iter;
+
+ /* If there's no active palette yet (i.e. new datablock), add one */
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+ if (palette == NULL) {
+ palette = BKE_gpencil_palette_addnew(gpd, "Pasted Palette", true);
+ }
+
+ /* For each color, figure out what to map to... */
+ GHASH_ITER(gh_iter, gp_strokes_copypastebuf_colors) {
+ bGPDpalettecolor *palcolor;
+ char *name = BLI_ghashIterator_getKey(&gh_iter);
+
+ /* Look for existing color to map to */
+ /* XXX: What to do if same name but different color? Behaviour here should depend on a property? */
+ palcolor = BKE_gpencil_palettecolor_getbyname(palette, name);
+ if (palcolor == NULL) {
+ /* Doesn't Exist - Create new matching color for this palette */
+ /* XXX: This still doesn't fix the pasting across file boundaries problem... */
+ bGPDpalettecolor *src_color = BLI_ghashIterator_getValue(&gh_iter);
+
+ palcolor = MEM_dupallocN(src_color);
+ BLI_addtail(&palette->colors, palcolor);
+
+ BLI_uniquename(&palette->colors, palcolor, DATA_("GP Color"), '.', offsetof(bGPDpalettecolor, info), sizeof(palcolor->info));
+ }
+
+ /* Store this mapping (for use later when pasting) */
+ BLI_ghash_insert(new_colors, name, palcolor);
+ }
+
+ return new_colors;
+}
+
/* --------------------- */
/* Copy selected strokes */
@@ -386,7 +451,7 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
/* make direct copies of the stroke and its points */
gpsd = MEM_dupallocN(gps);
- strcpy(gpsd->tmp_layerinfo, gpl->info); /* saves original layer name */
+ BLI_strncpy(gpsd->tmp_layerinfo, gpl->info, sizeof(gpsd->tmp_layerinfo)); /* saves original layer name */
gpsd->points = MEM_dupallocN(gps->points);
/* triangles cache - will be recalculated on next redraw */
@@ -407,7 +472,26 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- /* done - no updates needed */
+ /* Build up hash of colors used in these strokes, making copies of these to protect against dangling pointers */
+ if (gp_strokes_copypastebuf.first) {
+ gp_strokes_copypastebuf_colors = BLI_ghash_str_new("GPencil CopyBuf Colors");
+
+ 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;
+ }
+ }
+ }
+ }
+
+ /* updates (to ensure operator buttons are refreshed, when used via hotkeys) */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL); // XXX?
+
+ /* done */
return OPERATOR_FINISHED;
}
@@ -431,16 +515,18 @@ void GPENCIL_OT_copy(wmOperatorType *ot)
static int gp_strokes_paste_poll(bContext *C)
{
- /* 1) Must have GP layer to paste to...
+ /* 1) Must have GP datablock to paste to
+ * - We don't need to have an active layer though, as that can easily get added
+ * - If the active layer is locked, we can't paste there, but that should prompt a warning instead
* 2) Copy buffer must at least have something (though it may be the wrong sort...)
*/
- return (CTX_data_active_gpencil_layer(C) != NULL) && (!BLI_listbase_is_empty(&gp_strokes_copypastebuf));
+ return (ED_gpencil_data_get_active(C) != NULL) && (!BLI_listbase_is_empty(&gp_strokes_copypastebuf));
}
-enum {
+typedef enum eGP_PasteMode {
GP_COPY_ONLY = -1,
GP_COPY_MERGE = 1
-};
+} eGP_PasteMode;
static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
{
@@ -448,9 +534,10 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
bGPdata *gpd = ED_gpencil_data_get_active(C);
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); /* only use active for copy merge */
bGPDframe *gpf;
-
- int type = RNA_enum_get(op->ptr, "type");
-
+
+ eGP_PasteMode type = RNA_enum_get(op->ptr, "type");
+ GHash *new_colors;
+
/* check for various error conditions */
if (gpd == NULL) {
BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
@@ -507,39 +594,54 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- /* Ensure we have a frame to draw into
- * NOTE: Since this is an op which creates strokes,
- * we are obliged to add a new frame if one
- * doesn't exist already
- */
-
- bGPDstroke *gps;
- /* Copy each stroke into the layer */
- for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
- if (ED_gpencil_stroke_can_use(C, gps)) {
- /* need to verify if layer exist nad frame */
- if (type != GP_COPY_MERGE) {
- gpl = BLI_findstring(&gpd->layers, gps->tmp_layerinfo, offsetof(bGPDlayer, info));
- if (gpl == NULL) {
- /* no layer - use active (only if layer deleted before paste) */
- gpl = CTX_data_active_gpencil_layer(C);
- }
- }
- gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true);
- if (gpf) {
- bGPDstroke *new_stroke = MEM_dupallocN(gps);
- new_stroke->tmp_layerinfo[0] = '\0';
-
- new_stroke->points = MEM_dupallocN(gps->points);
-
- new_stroke->flag |= GP_STROKE_RECALC_CACHES;
- new_stroke->triangles = NULL;
-
- new_stroke->next = new_stroke->prev = NULL;
- BLI_addtail(&gpf->strokes, new_stroke);
+ /* Ensure that all the necessary colors exist */
+ new_colors = gp_copybuf_validate_colormap(gpd);
+
+ /* 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));
+ if (gpl == NULL) {
+ /* no layer - use active (only if layer deleted before paste) */
+ gpl = CTX_data_active_gpencil_layer(C);
}
}
+
+ /* Ensure we have a frame to draw into
+ * NOTE: Since this is an op which creates strokes,
+ * we are obliged to add a new frame if one
+ * doesn't exist already
+ */
+ gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true);
+ if (gpf) {
+ /* Create new stroke */
+ bGPDstroke *new_stroke = MEM_dupallocN(gps);
+ new_stroke->tmp_layerinfo[0] = '\0';
+
+ new_stroke->points = MEM_dupallocN(gps->points);
+
+ new_stroke->flag |= GP_STROKE_RECALC_CACHES;
+ new_stroke->triangles = NULL;
+
+ new_stroke->next = new_stroke->prev = NULL;
+ BLI_addtail(&gpf->strokes, new_stroke);
+
+ /* 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));
+
+ /*new_stroke->flag |= GP_STROKE_RECALC_COLOR; */
+ }
}
+ }
+
+ /* free temp data */
+ BLI_ghash_free(new_colors, NULL, NULL);
/* updates */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -554,7 +656,7 @@ void GPENCIL_OT_paste(wmOperatorType *ot)
{GP_COPY_MERGE, "MERGE", 0, "Merge", ""},
{0, NULL, 0, NULL, NULL}
};
-
+
/* identifiers */
ot->name = "Paste Strokes";
ot->idname = "GPENCIL_OT_paste";
@@ -566,7 +668,8 @@ void GPENCIL_OT_paste(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
+ /* properties */
ot->prop = RNA_def_enum(ot->srna, "type", copy_type, 0, "Type", "");
}
@@ -674,6 +777,87 @@ void GPENCIL_OT_move_to_layer(wmOperatorType *ot)
RNA_def_enum_funcs(ot->prop, ED_gpencil_layers_with_new_enum_itemf);
}
+/* ********************* Add Blank Frame *************************** */
+
+/* Basically the same as the drawing op */
+static int UNUSED_FUNCTION(gp_blank_frame_add_poll)(bContext *C)
+{
+ if (ED_operator_regionactive(C)) {
+ /* check if current context can support GPencil data */
+ if (ED_gpencil_data_get_pointers(C, NULL) != NULL) {
+ return 1;
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Failed to find Grease Pencil data to draw into");
+ }
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Active region not set");
+ }
+
+ return 0;
+}
+
+static int gp_blank_frame_add_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *active_gpl = BKE_gpencil_layer_getactive(gpd);
+
+ const bool all_layers = RNA_boolean_get(op->ptr, "all_layers");
+
+ /* Initialise datablock and an active layer if nothing exists yet */
+ if (ELEM(NULL, gpd, active_gpl)) {
+ /* let's just be lazy, and call the "Add New Layer" operator, which sets everything up as required */
+ WM_operator_name_call(C, "GPENCIL_OT_layer_add", WM_OP_EXEC_DEFAULT, NULL);
+ }
+
+ /* Go through each layer, adding a frame after the active one
+ * and/or shunting all the others out of the way
+ */
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ if ((all_layers == false) && (gpl != active_gpl)) {
+ continue;
+ }
+
+ /* 1) Check for an existing frame on the current frame */
+ bGPDframe *gpf = BKE_gpencil_layer_find_frame(gpl, CFRA);
+ if (gpf) {
+ /* Shunt all frames after (and including) the existing one later by 1-frame */
+ for (; gpf; gpf = gpf->next) {
+ gpf->framenum += 1;
+ }
+ }
+
+ /* 2) Now add a new frame, with nothing in it */
+ gpl->actframe = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_NEW);
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_blank_frame_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ 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)";
+
+ /* callbacks */
+ ot->exec = gp_blank_frame_add_exec;
+ ot->poll = gp_add_poll;
+
+ /* properties */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ RNA_def_boolean(ot->srna, "all_layers", false, "All Layers", "Create blank frame in all layers, not only active");
+}
+
/* ******************* Delete Active Frame ************************ */
static int gp_actframe_delete_poll(bContext *C)
@@ -864,6 +1048,9 @@ static int gp_dissolve_selected_points(bContext *C)
/* 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 (gps->flag & GP_STROKE_SELECT) {
bGPDspoint *pt;
@@ -1076,6 +1263,9 @@ static int gp_delete_selected_points(bContext *C)
/* 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 (gps->flag & GP_STROKE_SELECT) {
@@ -1115,7 +1305,7 @@ static int gp_delete_exec(bContext *C, wmOperator *op)
case GP_DELETEOP_POINTS: /* selected points (breaks the stroke into segments) */
result = gp_delete_selected_points(C);
break;
-
+
case GP_DELETEOP_FRAME: /* active frame */
result = gp_actframe_delete_exec(C, op);
break;
@@ -1188,40 +1378,35 @@ static int 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;
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- float diff_mat[4][4];
-
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* only editable and visible layers are considered */
if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
-
+ 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);
}
-
- bGPDframe *gpf = gpl->actframe;
- bGPDstroke *gps;
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *pt;
+ int i;
+
/* 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) {
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false)
continue;
- }
-
- bGPDspoint *pt;
- int i;
-
- // TOOD: if entire stroke is selected, offset entire stroke by same amount?
-
+
+ // 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.. */
+ /* only if point is selected */
if (pt->flag & GP_SPOINT_SELECT) {
if (gpl->parent == NULL) {
pt->x = gridf * floorf(0.5f + pt->x / gridf);
@@ -1232,19 +1417,17 @@ static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op))
/* apply parent transformations */
float fpt[3];
mul_v3_m4v3(fpt, diff_mat, &pt->x);
-
+
fpt[0] = gridf * floorf(0.5f + fpt[0] / gridf);
fpt[1] = gridf * floorf(0.5f + fpt[1] / gridf);
fpt[2] = gridf * floorf(0.5f + fpt[2] / gridf);
-
+
/* return data */
copy_v3_v3(&pt->x, fpt);
gp_apply_parent_point(gpl, pt);
}
-
}
}
-
}
}
}
@@ -1272,49 +1455,46 @@ void GPENCIL_OT_snap_to_grid(wmOperatorType *ot)
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);
-
+
const bool use_offset = RNA_boolean_get(op->ptr, "use_offset");
const float *cursor_global = ED_view3d_cursor3d_get(scene, v3d);
-
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- float diff_mat[4][4];
-
+
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* only editable and visible layers are considered */
if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
-
+ 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);
}
-
- bGPDframe *gpf = gpl->actframe;
- bGPDstroke *gps;
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *pt;
+ int i;
+
/* 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) {
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false)
continue;
- }
-
- bGPDspoint *pt;
- int i;
-
/* only continue if this stroke is selected (editable doesn't guarantee this)... */
if ((gps->flag & GP_STROKE_SELECT) == 0)
continue;
-
+
if (use_offset) {
float offset[3];
-
+
/* compute offset from first point of stroke to cursor */
/* TODO: Allow using midpoint instead? */
sub_v3_v3v3(offset, cursor_global, &gps->points->x);
-
+
/* apply offset to all points in the stroke */
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
add_v3_v3(&pt->x, offset);
@@ -1331,9 +1511,8 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op)
}
}
}
-
-
}
+
}
}
@@ -1364,6 +1543,8 @@ void GPENCIL_OT_snap_to_cursor(wmOperatorType *ot)
static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -1375,36 +1556,31 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
INIT_MINMAX(min, max);
/* calculate midpoints from selected points */
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- float diff_mat[4][4];
-
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* only editable and visible layers are considered */
if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
-
+ 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);
}
-
- bGPDframe *gpf = gpl->actframe;
- bGPDstroke *gps;
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *pt;
+ int i;
+
/* 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) {
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false)
continue;
- }
-
- bGPDspoint *pt;
- int i;
-
/* only continue if this stroke is selected (editable doesn't guarantee this)... */
if ((gps->flag & GP_STROKE_SELECT) == 0)
continue;
-
+
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if (pt->flag & GP_SPOINT_SELECT) {
if (gpl->parent == NULL) {
@@ -1415,14 +1591,14 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
/* apply parent transformations */
float fpt[3];
mul_v3_m4v3(fpt, diff_mat, &pt->x);
-
+
add_v3_v3(centroid, fpt);
minmax_v3v3_v3(min, max, fpt);
}
count++;
}
}
-
+
}
}
}
@@ -1455,5 +1631,704 @@ void GPENCIL_OT_snap_cursor_to_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/* ******************* Apply layer thickness change to strokes ************************** */
-/* ************************************************ */
+static int gp_stroke_apply_thickness_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl, gpl->frames.first))
+ return OPERATOR_CANCELLED;
+
+ /* loop all strokes */
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* Apply thickness */
+ gps->thickness = gps->thickness + gpl->thickness;
+ }
+ }
+ /* clear value */
+ gpl->thickness = 0.0f;
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_apply_thickness(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Apply Stroke Thickness";
+ ot->idname = "GPENCIL_OT_stroke_apply_thickness";
+ ot->description = "Apply the thickness change of the layer to its strokes";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_apply_thickness_exec;
+ ot->poll = gp_active_layer_poll;
+}
+
+/* ******************* Close Strokes ************************** */
+
+enum {
+ GP_STROKE_CYCLIC_CLOSE = 1,
+ GP_STROKE_CYCLIC_OPEN = 2,
+ GP_STROKE_CYCLIC_TOGGLE = 3
+};
+
+static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ const int type = RNA_enum_get(op->ptr, "type");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ /* loop all selected strokes */
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ if (gpl->actframe == NULL)
+ continue;
+
+ for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
+ bGPDpalettecolor *palcolor = gps->palcolor;
+
+ /* skip strokes that are not selected or invalid for current view */
+ if (((gps->flag & GP_STROKE_SELECT) == 0) || ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+ /* skip hidden or locked colors */
+ if (!palcolor || (palcolor->flag & PC_COLOR_HIDE) || (palcolor->flag & PC_COLOR_LOCKED))
+ continue;
+
+ switch (type) {
+ case GP_STROKE_CYCLIC_CLOSE:
+ /* Close all (enable) */
+ gps->flag |= GP_STROKE_CYCLIC;
+ break;
+ case GP_STROKE_CYCLIC_OPEN:
+ /* Open all (disable) */
+ gps->flag &= ~GP_STROKE_CYCLIC;
+ break;
+ case GP_STROKE_CYCLIC_TOGGLE:
+ /* Just toggle flag... */
+ gps->flag ^= GP_STROKE_CYCLIC;
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+/**
+ * Similar to #CURVE_OT_cyclic_toggle or #MASK_OT_cyclic_toggle, but with
+ * option to force opened/closed strokes instead of just toggle behavior.
+ */
+void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot)
+{
+ static EnumPropertyItem cyclic_type[] = {
+ {GP_STROKE_CYCLIC_CLOSE, "CLOSE", 0, "Close all", ""},
+ {GP_STROKE_CYCLIC_OPEN, "OPEN", 0, "Open all", ""},
+ {GP_STROKE_CYCLIC_TOGGLE, "TOGGLE", 0, "Toggle", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Set Cyclical State";
+ ot->idname = "GPENCIL_OT_stroke_cyclical_set";
+ ot->description = "Close or open the selected stroke adding an edge from last to first point";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_cyclical_set_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", cyclic_type, GP_STROKE_CYCLIC_TOGGLE, "Type", "");
+}
+
+/* ******************* Stroke join ************************** */
+
+/* Helper: flip stroke */
+static void gpencil_flip_stroke(bGPDstroke *gps)
+{
+ int end = gps->totpoints - 1;
+
+ for (int i = 0; i < gps->totpoints / 2; i++) {
+ bGPDspoint *point, *point2;
+ bGPDspoint pt;
+
+ /* save first point */
+ point = &gps->points[i];
+ pt.x = point->x;
+ pt.y = point->y;
+ pt.z = point->z;
+ pt.flag = point->flag;
+ pt.pressure = point->pressure;
+ pt.strength = point->strength;
+ pt.time = point->time;
+
+ /* replace first point with last point */
+ point2 = &gps->points[end];
+ point->x = point2->x;
+ point->y = point2->y;
+ point->z = point2->z;
+ point->flag = point2->flag;
+ point->pressure = point2->pressure;
+ point->strength = point2->strength;
+ point->time = point2->time;
+
+ /* replace last point with first saved before */
+ point = &gps->points[end];
+ point->x = pt.x;
+ point->y = pt.y;
+ point->z = pt.z;
+ point->flag = pt.flag;
+ point->pressure = pt.pressure;
+ point->strength = pt.strength;
+ point->time = pt.time;
+
+ end--;
+ }
+}
+
+/* Helper: copy point between strokes */
+static void gpencil_stroke_copy_point(bGPDstroke *gps, bGPDspoint *point, float delta[3],
+ float pressure, float strength, float deltatime)
+{
+ bGPDspoint *newpoint;
+
+ gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
+ gps->totpoints++;
+
+ newpoint = &gps->points[gps->totpoints - 1];
+ newpoint->x = point->x * delta[0];
+ newpoint->y = point->y * delta[1];
+ newpoint->z = point->z * delta[2];
+ newpoint->flag = point->flag;
+ newpoint->pressure = pressure;
+ newpoint->strength = strength;
+ newpoint->time = point->time + deltatime;
+}
+
+/* Helper: join two strokes using the shortest distance (reorder stroke if necessary ) */
+static void gpencil_stroke_join_strokes(bGPDstroke *gps_a, bGPDstroke *gps_b, const bool leave_gaps)
+{
+ bGPDspoint point;
+ bGPDspoint *pt;
+ int i;
+ float delta[3] = {1.0f, 1.0f, 1.0f};
+ float deltatime = 0.0f;
+
+ /* sanity checks */
+ if (ELEM(NULL, gps_a, gps_b))
+ return;
+
+ if ((gps_a->totpoints == 0) || (gps_b->totpoints == 0))
+ return;
+
+ /* define start and end points of each stroke */
+ float sa[3], sb[3], ea[3], eb[3];
+ pt = &gps_a->points[0];
+ copy_v3_v3(sa, &pt->x);
+
+ pt = &gps_a->points[gps_a->totpoints - 1];
+ copy_v3_v3(ea, &pt->x);
+
+ pt = &gps_b->points[0];
+ copy_v3_v3(sb, &pt->x);
+
+ pt = &gps_b->points[gps_b->totpoints - 1];
+ copy_v3_v3(eb, &pt->x);
+
+ /* review if need flip stroke B */
+ float ea_sb = len_squared_v3v3(ea, sb);
+ float ea_eb = len_squared_v3v3(ea, eb);
+ /* flip if distance to end point is shorter */
+ if (ea_eb < ea_sb) {
+ gpencil_flip_stroke(gps_b);
+ }
+
+ /* don't visibly link the first and last points? */
+ if (leave_gaps) {
+ /* 1st: add one tail point to start invisible area */
+ point = gps_a->points[gps_a->totpoints - 1];
+ deltatime = point.time;
+ gpencil_stroke_copy_point(gps_a, &point, delta, 0.0f, 0.0f, 0.0f);
+
+ /* 2nd: add one head point to finish invisible area */
+ point = gps_b->points[0];
+ gpencil_stroke_copy_point(gps_a, &point, delta, 0.0f, 0.0f, deltatime);
+ }
+
+ /* 3rd: add all points */
+ for (i = 0, pt = gps_b->points; i < gps_b->totpoints && pt; i++, pt++) {
+ /* check if still room in buffer */
+ if (gps_a->totpoints <= GP_STROKE_BUFFER_MAX - 2) {
+ gpencil_stroke_copy_point(gps_a, pt, delta, pt->pressure, pt->strength, deltatime);
+ }
+ }
+}
+
+static int gp_stroke_join_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *activegpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDstroke *gps, *gpsn;
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+ bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
+
+ bGPDframe *gpf_a = NULL;
+ bGPDstroke *stroke_a = NULL;
+ bGPDstroke *stroke_b = NULL;
+ bGPDstroke *new_stroke = NULL;
+
+ const int type = RNA_enum_get(op->ptr, "type");
+ const bool leave_gaps = RNA_boolean_get(op->ptr, "leave_gaps");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ if (activegpl->flag & GP_LAYER_LOCKED)
+ return OPERATOR_CANCELLED;
+
+ BLI_assert(ELEM(type, GP_STROKE_JOIN, GP_STROKE_JOINCOPY));
+
+
+ /* read all selected strokes */
+ bool first = false;
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *gpf = gpl->actframe;
+ if (gpf == NULL)
+ continue;
+
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
+ continue;
+ }
+
+ /* to join strokes, cyclic must be disabled */
+ gps->flag &= ~GP_STROKE_CYCLIC;
+
+ /* saves first frame and stroke */
+ if (!first) {
+ first = true;
+ gpf_a = gpf;
+ stroke_a = gps;
+ }
+ else {
+ stroke_b = gps;
+
+ /* create a new stroke if was not created before (only created if something to join) */
+ if (new_stroke == NULL) {
+ new_stroke = MEM_dupallocN(stroke_a);
+ new_stroke->points = MEM_dupallocN(stroke_a->points);
+ new_stroke->triangles = NULL;
+ new_stroke->tot_triangles = 0;
+ new_stroke->flag |= GP_STROKE_RECALC_CACHES;
+
+ /* if new, set current color */
+ if (type == GP_STROKE_JOINCOPY) {
+ new_stroke->palcolor = palcolor;
+ BLI_strncpy(new_stroke->colorname, palcolor->info, sizeof(new_stroke->colorname));
+ new_stroke->flag |= GP_STROKE_RECALC_COLOR;
+ }
+ }
+
+ /* join new_stroke and stroke B. New stroke will contain all the previous data */
+ gpencil_stroke_join_strokes(new_stroke, stroke_b, leave_gaps);
+
+ /* if join only, delete old strokes */
+ if (type == GP_STROKE_JOIN) {
+ if (stroke_a) {
+ BLI_insertlinkbefore(&gpf_a->strokes, stroke_a, new_stroke);
+ BLI_remlink(&gpf->strokes, stroke_a);
+ BKE_gpencil_free_stroke(stroke_a);
+ stroke_a = NULL;
+ }
+ if (stroke_b) {
+ BLI_remlink(&gpf->strokes, stroke_b);
+ BKE_gpencil_free_stroke(stroke_b);
+ stroke_b = NULL;
+ }
+ }
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* add new stroke if was not added before */
+ if (type == GP_STROKE_JOINCOPY) {
+ if (new_stroke) {
+ /* Add a new frame if needed */
+ if (activegpl->actframe == NULL)
+ activegpl->actframe = BKE_gpencil_frame_addnew(activegpl, gpf_a->framenum);
+
+ BLI_addtail(&activegpl->actframe->strokes, new_stroke);
+ }
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_join(wmOperatorType *ot)
+{
+ static EnumPropertyItem join_type[] = {
+ {GP_STROKE_JOIN, "JOIN", 0, "Join", ""},
+ {GP_STROKE_JOINCOPY, "JOINCOPY", 0, "Join and Copy", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Join Strokes";
+ ot->idname = "GPENCIL_OT_stroke_join";
+ ot->description = "Join selected strokes (optionally as new stroke)";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_join_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", join_type, GP_STROKE_JOIN, "Type", "");
+ RNA_def_boolean(ot->srna, "leave_gaps", false, "Leave Gaps", "Leave gaps between joined strokes instead of linking them");
+}
+
+/* ******************* Stroke flip ************************** */
+
+static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ /* read all selected strokes */
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *gpf = gpl->actframe;
+ if (gpf == NULL)
+ continue;
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
+ continue;
+ }
+
+ /* flip stroke */
+ gpencil_flip_stroke(gps);
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_flip(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Flip Stroke";
+ ot->idname = "GPENCIL_OT_stroke_flip";
+ ot->description = "Change direction of the points of the selected strokes";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_flip_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ***************** Reproject Strokes ********************** */
+
+typedef enum eGP_ReprojectModes {
+ /* On same plane, parallel to viewplane */
+ GP_REPROJECT_PLANAR = 0,
+ /* Reprojected on to the scene geometry */
+ GP_REPROJECT_SURFACE,
+} eGP_ReprojectModes;
+
+static int 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)
+{
+ Scene *scene = CTX_data_scene(C);
+ GP_SpaceConversion gsc = {NULL};
+ eGP_ReprojectModes mode = RNA_boolean_get(op->ptr, "type");
+
+ /* init space conversion stuff */
+ gp_point_conversion_init(C, &gsc);
+
+ /* init autodist for geometry projection */
+ if (mode == GP_REPROJECT_SURFACE) {
+ struct Depsgraph *graph = CTX_data_depsgraph(C);
+ view3d_region_operator_needs_opengl(CTX_wm_window(C), gsc.ar);
+ ED_view3d_autodist_init(graph, 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)
+ {
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ int i;
+ float inverse_diff_mat[4][4];
+
+ /* 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);
+ }
+
+ /* Adjust each point */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ float xy[2];
+
+ /* 3D to Screenspace */
+ /* Note: We can't use gp_point_to_xy() here because that uses ints for the screenspace
+ * 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]);
+ }
+
+ /* Project screenspace back to 3D space (from current perspective)
+ * so that all points have been treated the same way
+ */
+ if (mode == GP_REPROJECT_PLANAR) {
+ /* Planar - All on same plane parallel to the viewplane */
+ gp_point_xy_to_3d(&gsc, scene, xy, &pt->x);
+ }
+ else {
+ /* Geometry - Snap to surfaces of visible geometry */
+ /* XXX: There will be precision loss (possible stairstep artifacts) from this conversion to satisfy the API's */
+ const int screen_co[2] = {(int)xy[0], (int)xy[1]};
+
+ int depth_margin = 0; // XXX: 4 for strokes, 0 for normal
+ float depth;
+
+ /* XXX: The proper procedure computes the depths into an array, to have smooth transitions when all else fails... */
+ if (ED_view3d_autodist_depth(gsc.ar, screen_co, depth_margin, &depth)) {
+ ED_view3d_autodist_simple(gsc.ar, screen_co, &pt->x, 0, &depth);
+ }
+ else {
+ /* Default to planar */
+ gp_point_xy_to_3d(&gsc, scene, xy, &pt->x);
+ }
+ }
+
+ /* Unapply parent corrections */
+ if (gpl->parent) {
+ mul_m4_v3(inverse_diff_mat, &pt->x);
+ }
+ }
+ }
+ }
+ GP_EDITABLE_STROKES_END;
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_reproject(wmOperatorType *ot)
+{
+ static EnumPropertyItem reproject_type[] = {
+ {GP_REPROJECT_PLANAR, "PLANAR", 0, "Planar",
+ "Reproject the strokes to end up on the same plane, as if drawn from the current viewpoint "
+ "using 'Cursor' Stroke Placement"},
+ {GP_REPROJECT_SURFACE, "SURFACE", 0, "Surface",
+ "Reproject the strokes on to the scene geometry, as if drawn using 'Surface' placement"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ 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)";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = gp_strokes_reproject_exec;
+ ot->poll = gp_strokes_reproject_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", reproject_type, GP_REPROJECT_PLANAR, "Projection Type", "");
+}
+
+/* ******************* Stroke subdivide ************************** */
+
+/* helper: Count how many points need to be inserted */
+static int gp_count_subdivision_cuts(bGPDstroke *gps)
+{
+ bGPDspoint *pt;
+ int i;
+ int totnewpoints = 0;
+ for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ if (i + 1 < gps->totpoints) {
+ if (gps->points[i + 1].flag & GP_SPOINT_SELECT) {
+ ++totnewpoints;
+ }
+ }
+ }
+ }
+
+ return totnewpoints;
+}
+static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDspoint *temp_points;
+ const int cuts = RNA_int_get(op->ptr, "number_cuts");
+
+ int totnewpoints, oldtotpoints;
+ int i2;
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ /* Go through each editable + selected stroke */
+ GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
+ {
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* loop as many times as cuts */
+ for (int s = 0; s < cuts; s++) {
+ totnewpoints = gp_count_subdivision_cuts(gps);
+ if (totnewpoints == 0) {
+ continue;
+ }
+ /* duplicate points in a temp area */
+ temp_points = MEM_dupallocN(gps->points);
+ oldtotpoints = gps->totpoints;
+
+ /* resize the points arrys */
+ gps->totpoints += totnewpoints;
+ gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+
+ /* loop and interpolate */
+ i2 = 0;
+ for (int i = 0; i < oldtotpoints; i++) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *pt_final = &gps->points[i2];
+
+ /* copy current point */
+ copy_v3_v3(&pt_final->x, &pt->x);
+ pt_final->pressure = pt->pressure;
+ pt_final->strength = pt->strength;
+ pt_final->time = pt->time;
+ pt_final->flag = pt->flag;
+ ++i2;
+
+ /* 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];
+ /* Interpolate all values */
+ bGPDspoint *next = &temp_points[i + 1];
+ 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->flag |= GP_SPOINT_SELECT;
+ ++i2;
+ }
+ }
+ }
+ }
+ /* free temp memory */
+ MEM_freeN(temp_points);
+ }
+ }
+ }
+ GP_EDITABLE_STROKES_END;
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_subdivide(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Subdivide Stroke";
+ ot->idname = "GPENCIL_OT_stroke_subdivide";
+ ot->description = "Subdivide between continuous selected points of the stroke adding a point half way between them";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_subdivide_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* properties */
+ prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 10, "Number of Cuts", "", 1, 5);
+ /* avoid re-using last var because it can cause _very_ high value and annoy users */
+ 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 f37fba4212d..a3734c56c59 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -40,6 +40,8 @@ struct bGPdata;
struct bGPDstroke;
struct bGPDspoint;
+struct GHash;
+
struct ARegion;
struct View2D;
struct wmOperatorType;
@@ -69,63 +71,23 @@ typedef struct GP_SpaceConversion {
float mat[4][4]; /* transform matrix on the strokes (introduced in [b770964]) */
} GP_SpaceConversion;
-
-/**
- * Check whether a given stroke segment is inside a circular brush
- *
- * \param mval The current screen-space coordinates (midpoint) of the brush
- * \param mvalo The previous screen-space coordinates (midpoint) of the brush (NOT CURRENTLY USED)
- * \param rad The radius of the brush
- *
- * \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);
-
-/**
- * Init settings for stroke point space conversions
- *
- * \param[out] r_gsc The space conversion settings struct, populated with necessary params
- */
void gp_point_conversion_init(struct bContext *C, GP_SpaceConversion *r_gsc);
-/**
- * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D)
- *
- * \param[out] r_x The screen-space x-coordinate of the point
- * \param[out] r_y The screen-space y-coordinate of the point
- */
void gp_point_to_xy(GP_SpaceConversion *settings, struct bGPDstroke *gps, struct bGPDspoint *pt,
int *r_x, int *r_y);
-/**
- * Convert point to parent space
- *
- * \param pt Original point
- * \param diff_mat Matrix with the difference between original parent matrix
- * \param[out] r_pt Pointer to new point after apply matrix
- */
+void gp_point_to_xy_fl(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
+ float *r_x, float *r_y);
+
void gp_point_to_parent_space(bGPDspoint *pt, float diff_mat[4][4], bGPDspoint *r_pt);
-/**
- * Change points position relative to parent object
- */
+
void gp_apply_parent(bGPDlayer *gpl, bGPDstroke *gps);
-/**
- * Change point position relative to parent object
- */
+
void gp_apply_parent_point(bGPDlayer *gpl, bGPDspoint *pt);
-/**
- * Convert a screenspace point to a 3D Grease Pencil coordinate.
- *
- * For use with editing tools where it is easier to perform the operations in 2D,
- * and then later convert the transformed points back to 3D.
- *
- * \param screeN_co The screenspace 2D coordinates to convert to
- * \param[out] r_out The resulting 3D coordinates of the input point
- */
bool gp_point_xy_to_3d(GP_SpaceConversion *gsc, struct Scene *scene, const float screen_co[2], float r_out[3]);
/* Poll Callbacks ------------------------------------ */
@@ -143,48 +105,18 @@ int 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);
+
/* Stroke Editing ------------------------------------ */
void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *next_stroke, int tag_flags);
-/**
- * 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?
- */
bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure);
-
-/**
-* Apply smooth for strength to stroke point
-* \param gps Stroke to smooth
-* \param i Point index
-* \param inf Amount of smoothing to apply
-*/
bool gp_smooth_stroke_strength(bGPDstroke *gps, int i, float inf);
-
-/**
-* Apply smooth for thickness to stroke point (use pressure)
-* \param gps Stroke to smooth
-* \param i Point index
-* \param inf Amount of smoothing to apply
-*/
bool gp_smooth_stroke_thickness(bGPDstroke *gps, int i, float inf);
-
-/**
- * Subdivide a stroke once, by adding points at the midpoint between each pair of points
- * \param gps Stroke data
- * \param new_totpoints Total number of points (after subdividing)
- */
void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints);
-
-/**
-* Add randomness to stroke
-* \param gps Stroke data
-* \param brsuh Brush data
-*/
void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush);
/* Layers Enums -------------------------------------- */
@@ -199,6 +131,7 @@ EnumPropertyItem *ED_gpencil_brushes_enum_itemf(bContext *C, PointerRNA *UNUSED(
/* Enums of GP palettes */
EnumPropertyItem *ED_gpencil_palettes_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
bool *r_free);
+
/* ***************************************************** */
/* Operator Defines */
@@ -214,6 +147,9 @@ typedef enum eGPencil_PaintModes {
GP_PAINTMODE_DRAW_POLY
} eGPencil_PaintModes;
+/* maximum sizes of gp-session buffer */
+#define GP_STROKE_BUFFER_MAX 5000
+
/* stroke editing ----- */
void GPENCIL_OT_editmode_toggle(struct wmOperatorType *ot);
@@ -246,6 +182,7 @@ void GPENCIL_OT_snap_to_cursor(struct wmOperatorType *ot);
void GPENCIL_OT_snap_cursor_to_selected(struct wmOperatorType *ot);
void GPENCIL_OT_snap_cursor_to_center(struct wmOperatorType *ot);
+void GPENCIL_OT_reproject(struct wmOperatorType *ot);
/* stroke sculpting -- */
@@ -270,6 +207,8 @@ void GPENCIL_OT_unlock_all(struct wmOperatorType *ot);
void GPENCIL_OT_layer_isolate(struct wmOperatorType *ot);
void GPENCIL_OT_layer_merge(struct wmOperatorType *ot);
+void GPENCIL_OT_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);
@@ -287,6 +226,7 @@ void GPENCIL_OT_stroke_apply_thickness(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_cyclical_set(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_join(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_flip(struct wmOperatorType *ot);
+void GPENCIL_OT_stroke_subdivide(struct wmOperatorType *ot);
void GPENCIL_OT_brush_add(struct wmOperatorType *ot);
void GPENCIL_OT_brush_remove(struct wmOperatorType *ot);
@@ -300,10 +240,10 @@ 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);
@@ -318,7 +258,13 @@ void gpencil_undo_init(struct bGPdata *gpd);
void gpencil_undo_push(struct bGPdata *gpd);
void gpencil_undo_finish(void);
-/******************************************************* */
+/* interpolation ---------- */
+
+void GPENCIL_OT_interpolate(struct wmOperatorType *ot);
+void GPENCIL_OT_interpolate_sequence(struct wmOperatorType *ot);
+void GPENCIL_OT_interpolate_reverse(struct wmOperatorType *ot);
+
+/* ****************************************************** */
/* FILTERED ACTION DATA - TYPES ---> XXX DEPRECEATED OLD ANIM SYSTEM CODE! */
/* XXX - TODO: replace this with the modern bAnimListElem... */
@@ -340,7 +286,7 @@ typedef struct bActListElem {
short ownertype; /* type of owner */
} bActListElem;
-/******************************************************* */
+/* ****************************************************** */
/* FILTER ACTION DATA - METHODS/TYPES */
/* filtering flags - under what circumstances should a channel be added */
@@ -363,6 +309,9 @@ typedef enum ACTCONT_TYPES {
ACTCONT_GPENCIL
} ACTCONT_TYPES;
+/* ****************************************************** */
+/* Stroke Iteration Utilities */
+
/**
* Iterate over all editable strokes in the current context,
* stopping on each usable layer + stroke pair (i.e. gpl and gps)
@@ -398,4 +347,6 @@ typedef enum ACTCONT_TYPES {
CTX_DATA_END; \
} (void)0
+/* ****************************************************** */
+
#endif /* __GPENCIL_INTERN_H__ */
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
new file mode 100644
index 00000000000..59b5b41f114
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -0,0 +1,1137 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez, Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Operators for interpolating new Grease Pencil frames from existing strokes
+ */
+
+/** \file blender/editors/gpencil/gpencil_interpolate.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_easing.h"
+#include "BLI_math.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_color_types.h"
+#include "DNA_gpencil_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_colortools.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_library.h"
+#include "BKE_report.h"
+#include "BKE_screen.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "UI_view2d.h"
+
+#include "ED_gpencil.h"
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "ED_space_api.h"
+
+#include "gpencil_intern.h"
+
+/* ************************************************ */
+/* Core/Shared Utilities */
+
+/* Poll callback for interpolation operators */
+static int gpencil_view3d_poll(bContext *C)
+{
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+
+ /* only 3D view */
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype != SPACE_VIEW3D) {
+ return 0;
+ }
+
+ /* need data to interpolate */
+ if (ELEM(NULL, gpd, gpl)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Perform interpolation */
+static void gp_interpolate_update_points(bGPDstroke *gps_from, 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];
+
+ /* Interpolate all values */
+ interp_v3_v3v3(&pt->x, &prev->x, &next->x, factor);
+ pt->pressure = interpf(prev->pressure, next->pressure, factor);
+ pt->strength = interpf(prev->strength, next->strength, factor);
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ }
+}
+
+/* ****************** Interpolate Interactive *********************** */
+
+/* Helper: Update all strokes interpolated */
+static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi)
+{
+ tGPDinterpolate_layer *tgpil;
+ const float shift = tgpi->shift;
+
+ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
+ bGPDstroke *new_stroke;
+ const float factor = tgpil->factor + shift;
+
+ for (new_stroke = tgpil->interFrame->strokes.first; new_stroke; new_stroke = new_stroke->next) {
+ bGPDstroke *gps_from, *gps_to;
+ int stroke_idx;
+
+ if (new_stroke->totpoints == 0) {
+ continue;
+ }
+
+ /* get strokes to interpolate */
+ stroke_idx = BLI_findindex(&tgpil->interFrame->strokes, new_stroke);
+
+ gps_from = BLI_findlink(&tgpil->prevFrame->strokes, stroke_idx);
+ gps_to = BLI_findlink(&tgpil->nextFrame->strokes, stroke_idx);
+
+ /* update points position */
+ if ((gps_from) && (gps_to)) {
+ gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor);
+ }
+ }
+ }
+
+ 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)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ eGP_Interpolate_SettingsFlag flag = ts->gp_interpolate.flag;
+
+ /* get layers */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* all layers or only active */
+ if (!(flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) && !(gpl->flag & GP_LAYER_ACTIVE)) {
+ continue;
+ }
+ /* only editable and visible layers are considered */
+ if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
+ continue;
+ }
+
+ /* read strokes */
+ for (bGPDstroke *gps_from = gpl->actframe->strokes.first; gps_from; gps_from = gps_from->next) {
+ bGPDstroke *gps_to;
+ int fFrame;
+
+ /* only selected */
+ if ((flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
+ continue;
+ }
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps_from) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) {
+ continue;
+ }
+
+ /* get final stroke to interpolate */
+ fFrame = BLI_findindex(&gpl->actframe->strokes, gps_from);
+ gps_to = BLI_findlink(&gpl->actframe->next->strokes, fFrame);
+ if (gps_to == NULL) {
+ continue;
+ }
+
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Helper: Create internal strokes interpolated */
+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;
+
+ /* save initial factor for active layer to define shift limits */
+ tgpi->init_factor = (float)(tgpi->cframe - actframe->framenum) / (actframe->next->framenum - actframe->framenum + 1);
+
+ /* limits are 100% below 0 and 100% over the 100% */
+ tgpi->low_limit = -1.0f - tgpi->init_factor;
+ tgpi->high_limit = 2.0f - tgpi->init_factor;
+
+ /* set layers */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ tGPDinterpolate_layer *tgpil;
+
+ /* all layers or only active */
+ if (!(tgpi->flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) && (gpl != active_gpl)) {
+ continue;
+ }
+ /* only editable and visible layers are considered */
+ if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
+ continue;
+ }
+
+ /* create temp data for each layer */
+ tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer");
+
+ tgpil->gpl = gpl;
+ tgpil->prevFrame = gpl->actframe;
+ tgpil->nextFrame = gpl->actframe->next;
+
+ BLI_addtail(&tgpi->ilayers, tgpil);
+
+ /* create a new temporary frame */
+ tgpil->interFrame = MEM_callocN(sizeof(bGPDframe), "bGPDframe");
+ tgpil->interFrame->framenum = tgpi->cframe;
+
+ /* get interpolation factor by layer (usually must be equal for all layers, but not sure) */
+ tgpil->factor = (float)(tgpi->cframe - tgpil->prevFrame->framenum) / (tgpil->nextFrame->framenum - tgpil->prevFrame->framenum + 1);
+
+ /* create new strokes data with interpolated points reading original stroke */
+ for (bGPDstroke *gps_from = tgpil->prevFrame->strokes.first; gps_from; gps_from = gps_from->next) {
+ bGPDstroke *gps_to;
+ int fFrame;
+
+ bGPDstroke *new_stroke;
+ bool valid = true;
+
+
+ /* only selected */
+ if ((tgpi->flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
+ valid = false;
+ }
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps_from) == false) {
+ valid = false;
+ }
+
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(tgpil->gpl, gps_from) == false) {
+ valid = false;
+ }
+
+ /* get final stroke to interpolate */
+ fFrame = BLI_findindex(&tgpil->prevFrame->strokes, gps_from);
+ gps_to = BLI_findlink(&tgpil->nextFrame->strokes, fFrame);
+ if (gps_to == NULL) {
+ valid = false;
+ }
+
+ /* 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);
+
+ if (valid) {
+ /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
+ if (gps_from->totpoints > gps_to->totpoints) {
+ new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints);
+ new_stroke->totpoints = gps_to->totpoints;
+ new_stroke->tot_triangles = 0;
+ new_stroke->flag |= GP_STROKE_RECALC_CACHES;
+ }
+ /* update points position */
+ gp_interpolate_update_points(gps_from, gps_to, new_stroke, tgpil->factor);
+ }
+ else {
+ /* need an empty stroke to keep index correct for lookup, but resize to smallest size */
+ new_stroke->totpoints = 0;
+ new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points));
+ new_stroke->tot_triangles = 0;
+ new_stroke->triangles = MEM_recallocN(new_stroke->triangles, sizeof(*new_stroke->triangles));
+ }
+
+ /* add to strokes */
+ BLI_addtail(&tgpil->interFrame->strokes, new_stroke);
+ }
+ }
+}
+
+/* ----------------------- */
+/* 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)
+{
+ tGPDinterpolate *tgpi = (tGPDinterpolate *)arg;
+ ED_gp_draw_interpolation(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)
+{
+ tGPDinterpolate *tgpi = (tGPDinterpolate *)arg;
+ ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_VIEW);
+}
+
+/* ----------------------- */
+
+/* Helper: calculate shift based on position of mouse (we only use x-axis for now.
+ * since this is more convenient for users to do), and store new shift value
+ */
+static void gpencil_mouse_update_shift(tGPDinterpolate *tgpi, wmOperator *op, const wmEvent *event)
+{
+ float mid = (float)(tgpi->ar->winx - tgpi->ar->winrct.xmin) / 2.0f;
+ float mpos = event->x - tgpi->ar->winrct.xmin;
+
+ if (mpos >= mid) {
+ tgpi->shift = ((mpos - mid) * tgpi->high_limit) / mid;
+ }
+ else {
+ tgpi->shift = tgpi->low_limit - ((mpos * tgpi->low_limit) / mid);
+ }
+
+ CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
+ RNA_float_set(op->ptr, "shift", tgpi->shift);
+}
+
+/* Helper: Draw status message while the user is running the operator */
+static void gpencil_interpolate_status_indicators(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);
+
+ 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);
+ }
+ else {
+ 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);
+}
+
+/* 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);
+ /* apply... */
+ tgpi->shift = RNA_float_get(op->ptr, "shift");
+ /* update points position */
+ gp_interpolate_update_strokes(C, tgpi);
+}
+
+/* ----------------------- */
+
+/* Exit and free memory */
+static void gpencil_interpolate_exit(bContext *C, wmOperator *op)
+{
+ tGPDinterpolate *tgpi = op->customdata;
+ tGPDinterpolate_layer *tgpil;
+
+ /* don't assume that operator data exists at all */
+ if (tgpi) {
+ /* remove drawing handler */
+ if (tgpi->draw_handle_screen) {
+ ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_screen);
+ }
+ if (tgpi->draw_handle_3d) {
+ ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_3d);
+ }
+
+ /* clear status message area */
+ ED_area_headerprint(tgpi->sa, NULL);
+
+ /* finally, free memory used by temp data */
+ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
+ BKE_gpencil_free_strokes(tgpil->interFrame);
+ MEM_freeN(tgpil->interFrame);
+ }
+
+ BLI_freelistN(&tgpi->ilayers);
+ MEM_freeN(tgpi);
+ }
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+
+ /* clear pointer */
+ op->customdata = NULL;
+}
+
+/* Init new temporary interpolation data */
+static bool gp_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinterpolate *tgpi)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+
+ /* set current scene and window */
+ tgpi->scene = CTX_data_scene(C);
+ tgpi->sa = CTX_wm_area(C);
+ tgpi->ar = CTX_wm_region(C);
+ tgpi->flag = ts->gp_interpolate.flag;
+
+ /* set current frame number */
+ tgpi->cframe = tgpi->scene->r.cfra;
+
+ /* set GP datablock */
+ tgpi->gpd = gpd;
+
+ /* set interpolation weight */
+ tgpi->shift = RNA_float_get(op->ptr, "shift");
+ /* set layers */
+ gp_interpolate_set_points(C, tgpi);
+
+ return 1;
+}
+
+/* Allocate memory and initialize values */
+static tGPDinterpolate *gp_session_init_interpolation(bContext *C, wmOperator *op)
+{
+ tGPDinterpolate *tgpi = MEM_callocN(sizeof(tGPDinterpolate), "GPencil Interpolate Data");
+
+ /* define initial values */
+ gp_interpolate_set_init_values(C, op, tgpi);
+
+ /* return context data for running operator */
+ return tgpi;
+}
+
+/* Init interpolation: Allocate memory and set init values */
+static int gpencil_interpolate_init(bContext *C, wmOperator *op)
+{
+ tGPDinterpolate *tgpi;
+
+ /* check context */
+ tgpi = op->customdata = gp_session_init_interpolation(C, op);
+ if (tgpi == NULL) {
+ /* something wasn't set correctly in context */
+ gpencil_interpolate_exit(C, op);
+ return 0;
+ }
+
+ /* everything is now setup ok */
+ return 1;
+}
+
+/* ----------------------- */
+
+/* Invoke handler: Initialize the operator */
+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);
+ bGPDframe *actframe = gpl->actframe;
+ tGPDinterpolate *tgpi = NULL;
+
+ /* cannot interpolate if not between 2 frames */
+ if (ELEM(NULL, actframe, actframe->next)) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot find a pair of grease pencil frames to interpolate between in active layer");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* cannot interpolate in extremes */
+ if (ELEM(CFRA, 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;
+ }
+
+ /* need editable strokes */
+ if (!gp_interpolate_check_todo(C, gpd)) {
+ BKE_report(op->reports, RPT_ERROR, "Interpolation requires some editable strokes");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* try to initialize context data needed */
+ if (!gpencil_interpolate_init(C, op)) {
+ if (op->customdata)
+ MEM_freeN(op->customdata);
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ tgpi = op->customdata;
+ }
+
+ /* Enable custom drawing handlers
+ * It needs 2 handlers because strokes can in 3d space and screen space
+ * and each handler use different coord system
+ */
+ tgpi->draw_handle_screen = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_screen, tgpi, REGION_DRAW_POST_PIXEL);
+ tgpi->draw_handle_3d = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_3d, tgpi, REGION_DRAW_POST_VIEW);
+
+ /* set cursor to indicate modal */
+ WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR);
+
+ /* update shift indicator in header */
+ gpencil_interpolate_status_indicators(tgpi);
+ 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;
+}
+
+/* Modal handler: Events handling during interactive part */
+static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ tGPDinterpolate *tgpi = op->customdata;
+ wmWindow *win = CTX_wm_window(C);
+ bGPDframe *gpf_dst;
+ bGPDstroke *gps_src, *gps_dst;
+ tGPDinterpolate_layer *tgpil;
+ const bool has_numinput = hasNumInput(&tgpi->num);
+
+ switch (event->type) {
+ case LEFTMOUSE: /* confirm */
+ case RETKEY:
+ {
+ /* return to normal cursor and header status */
+ ED_area_headerprint(tgpi->sa, NULL);
+ WM_cursor_modal_restore(win);
+
+ /* insert keyframes as required... */
+ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
+ gpf_dst = BKE_gpencil_layer_getframe(tgpil->gpl, tgpi->cframe, GP_GETFRAME_ADD_NEW);
+ gpf_dst->key_type = BEZT_KEYTYPE_BREAKDOWN;
+
+ /* copy strokes */
+ BLI_listbase_clear(&gpf_dst->strokes);
+ for (gps_src = tgpil->interFrame->strokes.first; gps_src; gps_src = gps_src->next) {
+ if (gps_src->totpoints == 0) {
+ continue;
+ }
+
+ /* make copy of source stroke, then adjust pointer to points too */
+ gps_dst = MEM_dupallocN(gps_src);
+ gps_dst->points = MEM_dupallocN(gps_src->points);
+ gps_dst->triangles = MEM_dupallocN(gps_src->triangles);
+ gps_dst->flag |= GP_STROKE_RECALC_CACHES;
+ BLI_addtail(&gpf_dst->strokes, gps_dst);
+ }
+ }
+
+ /* clean up temp data */
+ gpencil_interpolate_exit(C, op);
+
+ /* done! */
+ return OPERATOR_FINISHED;
+ }
+
+ case ESCKEY: /* cancel */
+ case RIGHTMOUSE:
+ {
+ /* return to normal cursor and header status */
+ ED_area_headerprint(tgpi->sa, NULL);
+ WM_cursor_modal_restore(win);
+
+ /* clean up temp data */
+ gpencil_interpolate_exit(C, op);
+
+ /* canceled! */
+ return OPERATOR_CANCELLED;
+ }
+
+ case WHEELUPMOUSE:
+ {
+ tgpi->shift = tgpi->shift + 0.01f;
+ CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
+ RNA_float_set(op->ptr, "shift", tgpi->shift);
+
+ /* update screen */
+ gpencil_interpolate_update(C, op, tgpi);
+ break;
+ }
+ case WHEELDOWNMOUSE:
+ {
+ tgpi->shift = tgpi->shift - 0.01f;
+ CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
+ RNA_float_set(op->ptr, "shift", tgpi->shift);
+
+ /* update screen */
+ gpencil_interpolate_update(C, op, tgpi);
+ break;
+ }
+ case MOUSEMOVE: /* calculate new position */
+ {
+ /* only handle mousemove if not doing numinput */
+ if (has_numinput == false) {
+ /* update shift based on position of mouse */
+ gpencil_mouse_update_shift(tgpi, op, event);
+
+ /* update screen */
+ gpencil_interpolate_update(C, op, tgpi);
+ }
+ break;
+ }
+ default:
+ {
+ if ((event->val == KM_PRESS) && handleNumInput(C, &tgpi->num, event)) {
+ const float factor = tgpi->init_factor;
+ float value;
+
+ /* Grab shift from numeric input, and store this new value (the user see an int) */
+ value = (factor + tgpi->shift) * 100.0f;
+ applyNumInput(&tgpi->num, &value);
+ tgpi->shift = value / 100.0f;
+
+ /* recalculate the shift to get the right value in the frame scale */
+ tgpi->shift = tgpi->shift - factor;
+
+ CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
+ RNA_float_set(op->ptr, "shift", tgpi->shift);
+
+ /* update screen */
+ gpencil_interpolate_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_interpolate_cancel(bContext *C, wmOperator *op)
+{
+ /* this is just a wrapper around exit() */
+ gpencil_interpolate_exit(C, op);
+}
+
+void GPENCIL_OT_interpolate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Grease Pencil Interpolation";
+ ot->idname = "GPENCIL_OT_interpolate";
+ ot->description = "Interpolate grease pencil strokes between frames";
+
+ /* callbacks */
+ ot->invoke = gpencil_interpolate_invoke;
+ ot->modal = gpencil_interpolate_modal;
+ ot->cancel = gpencil_interpolate_cancel;
+ ot->poll = gpencil_view3d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* properties */
+ RNA_def_float_percentage(ot->srna, "shift", 0.0f, -1.0f, 1.0f, "Shift", "Bias factor for which frame has more influence on the interpolated strokes", -0.9f, 0.9f);
+}
+
+/* ****************** Interpolate Sequence *********************** */
+
+/* Helper: Perform easing equation calculations for GP interpolation operator */
+static float gp_interpolate_seq_easing_calc(GP_Interpolate_Settings *ipo_settings, float time)
+{
+ const float begin = 0.0f;
+ const float change = 1.0f;
+ const float duration = 1.0f;
+
+ const float back = ipo_settings->back;
+ const float amplitude = ipo_settings->amplitude;
+ const float period = ipo_settings->period;
+
+ eBezTriple_Easing easing = ipo_settings->easing;
+ float result = time;
+
+ switch (ipo_settings->type) {
+ case GP_IPO_BACK:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_back_ease_in(time, begin, change, duration, back);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_back_ease_out(time, begin, change, duration, back);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_back_ease_in_out(time, begin, change, duration, back);
+ break;
+
+ default: /* default/auto: same as ease out */
+ result = BLI_easing_back_ease_out(time, begin, change, duration, back);
+ break;
+ }
+ break;
+
+ case GP_IPO_BOUNCE:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_bounce_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_bounce_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_bounce_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease out */
+ result = BLI_easing_bounce_ease_out(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_CIRC:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_circ_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_circ_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_circ_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_circ_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_CUBIC:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_cubic_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_cubic_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_cubic_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_cubic_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_ELASTIC:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_elastic_ease_in(time, begin, change, duration, amplitude, period);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_elastic_ease_in_out(time, begin, change, duration, amplitude, period);
+ break;
+
+ default: /* default/auto: same as ease out */
+ result = BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
+ break;
+ }
+ break;
+
+ case GP_IPO_EXPO:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_expo_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_expo_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_expo_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_expo_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_QUAD:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_quad_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_quad_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_quad_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_quad_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_QUART:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_quart_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_quart_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_quart_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_quart_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_QUINT:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_quint_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_quint_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_quint_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_quint_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case GP_IPO_SINE:
+ switch (easing) {
+ case BEZT_IPO_EASE_IN:
+ result = BLI_easing_sine_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ result = BLI_easing_sine_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ result = BLI_easing_sine_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ result = BLI_easing_sine_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ default:
+ printf("%s: Unknown interpolation type - %d\n", __func__, ipo_settings->type);
+ break;
+ }
+
+ return result;
+}
+
+static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C);
+ bGPDframe *actframe = active_gpl->actframe;
+
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ GP_Interpolate_Settings *ipo_settings = &ts->gp_interpolate;
+ eGP_Interpolate_SettingsFlag flag = ipo_settings->flag;
+
+ /* cannot interpolate if not between 2 frames */
+ if (ELEM(NULL, actframe, actframe->next)) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot find a pair of grease pencil frames to interpolate between in active layer");
+ return OPERATOR_CANCELLED;
+ }
+ /* cannot interpolate in extremes */
+ if (ELEM(CFRA, 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;
+ }
+
+ /* loop all layer to check if need interpolation */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ bGPDframe *prevFrame, *nextFrame;
+ bGPDstroke *gps_from, *gps_to;
+ int cframe, fFrame;
+
+ /* all layers or only active */
+ if (((flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) {
+ continue;
+ }
+ /* only editable and visible layers are considered */
+ if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
+ continue;
+ }
+
+ /* store extremes */
+ prevFrame = gpl->actframe;
+ nextFrame = gpl->actframe->next;
+
+ /* Loop over intermediary frames and create the interpolation */
+ for (cframe = prevFrame->framenum + 1; cframe < nextFrame->framenum; cframe++) {
+ bGPDframe *interFrame = NULL;
+ float factor;
+
+ /* get interpolation factor */
+ factor = (float)(cframe - prevFrame->framenum) / (nextFrame->framenum - prevFrame->framenum + 1);
+
+ if (ipo_settings->type == GP_IPO_CURVEMAP) {
+ /* custom curvemap */
+ if (ipo_settings->custom_ipo) {
+ factor = curvemapping_evaluateF(ipo_settings->custom_ipo, 0, factor);
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "Custom interpolation curve does not exist");
+ }
+ }
+ else if (ipo_settings->type >= GP_IPO_BACK) {
+ /* easing equation... */
+ factor = gp_interpolate_seq_easing_calc(ipo_settings, factor);
+ }
+
+ /* 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;
+
+ /* only selected */
+ if ((flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
+ continue;
+ }
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps_from) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) {
+ continue;
+ }
+
+ /* get final stroke to interpolate */
+ fFrame = BLI_findindex(&prevFrame->strokes, gps_from);
+ gps_to = BLI_findlink(&nextFrame->strokes, fFrame);
+ if (gps_to == NULL) {
+ continue;
+ }
+
+ /* create a new frame if needed */
+ if (interFrame == NULL) {
+ interFrame = BKE_gpencil_layer_getframe(gpl, cframe, GP_GETFRAME_ADD_NEW);
+ interFrame->key_type = BEZT_KEYTYPE_BREAKDOWN;
+ }
+
+ /* 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);
+
+ /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
+ if (gps_from->totpoints > gps_to->totpoints) {
+ new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints);
+ new_stroke->totpoints = gps_to->totpoints;
+ new_stroke->tot_triangles = 0;
+ new_stroke->flag |= GP_STROKE_RECALC_CACHES;
+ }
+
+ /* update points position */
+ gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor);
+
+ /* add to strokes */
+ BLI_addtail(&interFrame->strokes, new_stroke);
+ }
+ }
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Interpolate Sequence";
+ ot->idname = "GPENCIL_OT_interpolate_sequence";
+ ot->description = "Generate 'in-betweens' to smoothly interpolate between Grease Pencil frames";
+
+ /* api callbacks */
+ ot->exec = gpencil_interpolate_seq_exec;
+ ot->poll = gpencil_view3d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ******************** Remove Breakdowns ************************ */
+
+static int gpencil_interpolate_reverse_poll(bContext *C)
+{
+ if (!gpencil_view3d_poll(C)) {
+ return 0;
+ }
+
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+
+ /* need to be on a breakdown frame */
+ if ((gpl->actframe == NULL) || (gpl->actframe->key_type != BEZT_KEYTYPE_BREAKDOWN)) {
+ CTX_wm_operator_poll_msg_set(C, "Expected current frame to be a breakdown");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int gpencil_interpolate_reverse_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ /* Go through each layer, deleting the breakdowns around the current frame,
+ * but only if there is a keyframe nearby to stop at
+ */
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *start_key = NULL;
+ bGPDframe *end_key = NULL;
+ bGPDframe *gpf, *gpfn;
+
+ /* Only continue if we're currently on a breakdown keyframe */
+ if ((gpl->actframe == NULL) || (gpl->actframe->key_type != BEZT_KEYTYPE_BREAKDOWN))
+ continue;
+
+ /* Search left for "start_key" (i.e. the first breakdown to remove) */
+ gpf = gpl->actframe;
+ while (gpf) {
+ if (gpf->key_type == BEZT_KEYTYPE_BREAKDOWN) {
+ /* A breakdown... keep going left */
+ start_key = gpf;
+ gpf = gpf->prev;
+ }
+ else {
+ /* Not a breakdown (may be a key, or an extreme, or something else that wasn't generated)... stop */
+ break;
+ }
+ }
+
+ /* Search right for "end_key" (i.e. the last breakdown to remove) */
+ gpf = gpl->actframe;
+ while (gpf) {
+ if (gpf->key_type == BEZT_KEYTYPE_BREAKDOWN) {
+ /* A breakdown... keep going right */
+ end_key = gpf;
+ gpf = gpf->next;
+ }
+ else {
+ /* Not a breakdown... stop */
+ break;
+ }
+ }
+
+ /* Did we find anything? */
+ /* NOTE: We should only proceed if there's something before/after these extents...
+ * Otherwise, there's just an extent of breakdowns with no keys to interpolate between
+ */
+ if ((start_key && end_key) &&
+ ELEM(NULL, start_key->prev, end_key->next) == false)
+ {
+ /* Set actframe to the key before start_key, since the keys have been removed now */
+ gpl->actframe = start_key->prev;
+
+ /* Free each frame we're removing (except the last one) */
+ for (gpf = start_key; gpf && gpf != end_key; gpf = gpfn) {
+ gpfn = gpf->next;
+
+ /* free strokes and their associated memory */
+ BKE_gpencil_free_strokes(gpf);
+ BLI_freelinkN(&gpl->frames, gpf);
+ }
+
+ /* Now free the last one... */
+ BKE_gpencil_free_strokes(end_key);
+ BLI_freelinkN(&gpl->frames, end_key);
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_interpolate_reverse(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Breakdowns";
+ ot->idname = "GPENCIL_OT_interpolate_reverse";
+ ot->description = "Remove breakdown frames generated by interpolating between two Grease Pencil frames";
+
+ /* callbacks */
+ ot->exec = gpencil_interpolate_reverse_exec;
+ ot->poll = gpencil_interpolate_reverse_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 50f4e795d70..78e1a0dda36 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -79,7 +79,6 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf)
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!
@@ -103,6 +102,10 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf)
WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_tool_palette", QKEY, KM_PRESS, 0, DKEY);
WM_keymap_add_menu_pie(keymap, "GPENCIL_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);
@@ -144,7 +147,10 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
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:
@@ -240,6 +246,9 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, KM_SHIFT, 0);
+ /* 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);
@@ -375,6 +384,8 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_snap_to_cursor);
WM_operatortype_append(GPENCIL_OT_snap_cursor_to_selected);
+ WM_operatortype_append(GPENCIL_OT_reproject);
+
WM_operatortype_append(GPENCIL_OT_brush_paint);
/* Editing (Buttons) ------------ */
@@ -394,6 +405,8 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_layer_isolate);
WM_operatortype_append(GPENCIL_OT_layer_merge);
+ WM_operatortype_append(GPENCIL_OT_blank_frame_add);
+
WM_operatortype_append(GPENCIL_OT_active_frame_delete);
WM_operatortype_append(GPENCIL_OT_active_frames_delete_all);
@@ -406,6 +419,7 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_stroke_cyclical_set);
WM_operatortype_append(GPENCIL_OT_stroke_join);
WM_operatortype_append(GPENCIL_OT_stroke_flip);
+ WM_operatortype_append(GPENCIL_OT_stroke_subdivide);
WM_operatortype_append(GPENCIL_OT_palette_add);
WM_operatortype_append(GPENCIL_OT_palette_remove);
@@ -431,6 +445,11 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_brush_select);
/* Editing (Time) --------------- */
+
+ /* Interpolation */
+ WM_operatortype_append(GPENCIL_OT_interpolate);
+ WM_operatortype_append(GPENCIL_OT_interpolate_sequence);
+ WM_operatortype_append(GPENCIL_OT_interpolate_reverse);
}
void ED_operatormacros_gpencil(void)
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index e7e39a85792..9b639ac42e4 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -40,6 +40,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_rand.h"
+#include "BLI_math_geom.h"
#include "BLT_translation.h"
@@ -68,9 +69,11 @@
#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 "RNA_access.h"
#include "RNA_define.h"
@@ -112,6 +115,7 @@ typedef enum eGPencil_PaintFlags {
*/
typedef struct tGPsdata {
Scene *scene; /* current scene from context */
+ struct Depsgraph *graph;
wmWindow *win; /* window where painting originated */
ScrArea *sa; /* area where painting originated */
@@ -160,13 +164,13 @@ typedef struct tGPsdata {
bGPDpalettecolor *palettecolor; /* current palette color */
bGPDbrush *brush; /* current drawing brush */
short straight[2]; /* 1: line horizontal, 2: line vertical, other: not defined, second element position */
+ int lock_axis; /* lock drawing to one axis */
+
+ short keymodifier; /* key used for invoking the operator */
} tGPsdata;
/* ------ */
-/* maximum sizes of gp-session buffer */
-#define GP_STROKE_BUFFER_MAX 5000
-
/* Macros for accessing sensitivity thresholds... */
/* minimum number of pixels mouse should move before new point created */
#define MIN_MANHATTEN_PX (U.gp_manhattendist)
@@ -281,6 +285,64 @@ 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;
+ 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) {
+ return;
+ }
+ if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) {
+ return;
+ }
+ if ((*p->align_flag & GP_PROJECT_DEPTH_VIEW) || (*p->align_flag & GP_PROJECT_DEPTH_STROKE)) {
+ return;
+ }
+
+ /* get 3d cursor and set origin for locked axis only. Uses axis-1 because the enum for XYZ start with 1 */
+ gp_get_3d_reference(p, cursor);
+ zero_v3(origin);
+ origin[p->lock_axis - 1] = cursor[p->lock_axis - 1];
+
+ gp_project_points_to_plane(rv3d, gps, origin, p->lock_axis - 1);
+}
+
/* convert screen-coordinates to buffer-coordinates */
/* XXX this method needs a total overhaul! */
static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3], float *depth)
@@ -427,7 +489,8 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
bGPdata *gpd = p->gpd;
bGPDbrush *brush = p->brush;
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 */
@@ -579,11 +642,16 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
View3D *v3d = p->sa->spacedata.first;
view3d_region_operator_needs_opengl(p->win, p->ar);
- ED_view3d_autodist_init(p->scene, p->ar, v3d, (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 1 : 0);
+ ED_view3d_autodist_init(
+ p->graph, 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);
+ }
/* if parented change position relative to parent object */
if (gpl->parent != NULL) {
gp_apply_parent_point(gpl, pts);
@@ -682,7 +750,6 @@ static void gp_stroke_simplify(tGPsdata *p)
MEM_freeN(old_points);
}
-
/* make a new stroke from the buffer data */
static void gp_stroke_newfrombuffer(tGPsdata *p)
{
@@ -696,7 +763,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
int i, totelem;
/* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
- int depth_margin = (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 4 : 0;
+ int depth_margin = (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0;
/* get total number of points to allocate space for
* - drawing straight-lines only requires the endpoints
@@ -759,6 +826,10 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ /* if 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);
@@ -778,6 +849,10 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ /* if 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);
@@ -796,6 +871,10 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ /* if 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);
@@ -808,18 +887,18 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
}
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 mval[2], mval_prev[2] = { 0 };
int interp_depth = 0;
int found_depth = 0;
-
+
depth_arr = MEM_mallocN(sizeof(float) * gpd->sbuffer_size, "depth_points");
-
+
for (i = 0, ptc = gpd->sbuffer; i < gpd->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)))
{
@@ -828,68 +907,68 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
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->sbuffer_size - 1; i >= 0; i--)
depth_arr[i] = 0.9999f;
}
else {
- if (p->gpd->flag & GP_DATA_DEPTH_STROKE_ENDPOINTS) {
+ if (ts->gpencil_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->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;
}
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);
}
}
}
-
-
+
+
pt = gps->points;
-
+
/* convert all points (normal behavior) */
for (i = 0, ptc = gpd->sbuffer; i < gpd->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;
}
-
+
/* subdivide the stroke */
if (sublevel > 0) {
int totpoints = gps->totpoints;
for (i = 0; i < sublevel; i++) {
/* we're adding one new point between each pair of verts on each step */
totpoints += totpoints - 1;
-
+
gp_subdivide_stroke(gps, totpoints);
}
}
@@ -898,8 +977,8 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
gp_randomize_stroke(gps, brush);
}
- /* smooth stroke after subdiv - only if there's something to do
- * for each iteration, the factor is reduced to get a better smoothing without changing too much
+ /* 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) {
@@ -912,6 +991,11 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
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);
@@ -924,12 +1008,12 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
bGPDpalette *palette = BKE_gpencil_palette_getactive(p->gpd);
bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
gps->palcolor = palcolor;
- strcpy(gps->colorname, palcolor->info);
+ BLI_strncpy(gps->colorname, palcolor->info, sizeof(gps->colorname));
/* add stroke to frame, usually on tail of the listbase, but if on back is enabled the stroke is added on listbase head
- * because the drawing order is inverse and the head stroke is the first to draw. This is very useful for artist
- * when drawing the background
- */
+ * because the drawing order is inverse and the head stroke is the first to draw. This is very useful for artist
+ * when drawing the background
+ */
if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode != GP_PAINTMODE_DRAW_POLY)) {
BLI_addhead(&p->gpf->strokes, gps);
}
@@ -1159,9 +1243,8 @@ static void gp_stroke_doeraser(tGPsdata *p)
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->scene, p->ar, v3d, 0);
+ ED_view3d_autodist_init(p->graph, p->ar, v3d, 0);
}
}
@@ -1315,6 +1398,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
/* pass on current scene and window */
p->scene = CTX_data_scene(C);
+ p->graph = CTX_data_depsgraph(C);
p->win = CTX_wm_window(C);
unit_m4(p->imat);
@@ -1469,7 +1553,10 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
bGPDpalettecolor *palcolor = p->palettecolor;
bGPdata *pdata = p->gpd;
copy_v4_v4(pdata->scolor, palcolor->color);
+ copy_v4_v4(pdata->sfill, palcolor->fill);
pdata->sflag = palcolor->flag;
+ /* lock axis */
+ p->lock_axis = ts->gp_sculpt.lock_axis;
return 1;
}
@@ -1544,16 +1631,24 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
* 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)
*/
- bGPDlayer *gpl;
- for (gpl = p->gpd->layers.first; gpl; gpl = gpl->next) {
+ bool has_layer_to_erase = false;
+
+ for (bGPDlayer *gpl = p->gpd->layers.first; gpl; gpl = gpl->next) {
/* Skip if layer not editable */
if (gpencil_layer_is_editable(gpl) == false)
continue;
/* Add a new frame if needed (and based off the active frame,
* as we need some existing strokes to erase)
+ *
+ * Note: We don't add a new frame if there's nothing there now, so
+ * -> If there are no frames at all, don't add one
+ * -> If there are no strokes in that frame, don't add a new empty frame
*/
- gpl->actframe = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_COPY);
+ if (gpl->actframe && gpl->actframe->strokes.first) {
+ gpl->actframe = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_COPY);
+ has_layer_to_erase = true;
+ }
/* XXX: we omit GP_FRAME_PAINT here for now,
* as it is only really useful for doing
@@ -1573,10 +1668,10 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
}
}
- if (p->gpf == NULL) {
+ if (has_layer_to_erase == false) {
p->status = GP_STATUS_ERROR;
//if (G.debug & G_DEBUG)
- printf("Error: No frame created (gpencil_paint_init)\n");
+ printf("Error: Eraser will not be affecting anything (gpencil_paint_init)\n");
return;
}
}
@@ -1707,6 +1802,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
/* 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...
*/
@@ -1715,7 +1811,7 @@ 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->scene, p->ar, v3d, (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 1 : 0);
+ ED_view3d_autodist_init(p->graph, p->ar, v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
}
/* check if doing eraser or not */
@@ -1753,28 +1849,41 @@ static void gp_paint_cleanup(tGPsdata *p)
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();
-
- glTranslatef((float)x, (float)y, 0.0f);
-
+ Gwn_VertFormat *format = immVertexFormat();
+ const uint shdr_pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
-
- glColor4ub(255, 100, 100, 20);
- glutil_draw_filled_arc(0.0, M_PI * 2.0, p->radius, 40);
-
- setlinestyle(6);
-
- glColor4ub(255, 100, 100, 200);
- glutil_draw_lined_arc(0.0, M_PI * 2.0, p->radius, 40);
-
- setlinestyle(0);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ immUniformColor4ub(255, 100, 100, 20);
+ imm_draw_circle_fill(shdr_pos, x, y, p->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("num_colors", 0); /* "simple" mode */
+ immUniform1f("dash_width", 12.0f);
+ immUniform1f("dash_factor", 0.5f);
+
+ imm_draw_circle_wire(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();
+
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
-
- glPopMatrix();
}
}
@@ -1851,7 +1960,7 @@ static void gpencil_draw_cancel(bContext *C, wmOperator *op)
/* ------------------------------- */
-static int gpencil_draw_init(bContext *C, wmOperator *op)
+static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event)
{
tGPsdata *p;
eGPencil_PaintModes paintmode = RNA_enum_get(op->ptr, "mode");
@@ -1870,6 +1979,13 @@ static int gpencil_draw_init(bContext *C, wmOperator *op)
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;
@@ -2111,7 +2227,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op)
/* printf("GPencil - Starting Re-Drawing\n"); */
/* try to initialize context data needed while drawing */
- if (!gpencil_draw_init(C, op)) {
+ if (!gpencil_draw_init(C, op, NULL)) {
if (op->customdata) MEM_freeN(op->customdata);
/* printf("\tGP - no valid data\n"); */
return OPERATOR_CANCELLED;
@@ -2186,7 +2302,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
printf("GPencil - Starting Drawing\n");
/* try to initialize context data needed while drawing */
- if (!gpencil_draw_init(C, op)) {
+ if (!gpencil_draw_init(C, op, event)) {
if (op->customdata)
MEM_freeN(op->customdata);
if (G.debug & G_DEBUG)
@@ -2313,6 +2429,7 @@ static void gpencil_move_last_stroke_to_back(bContext *C)
static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
tGPsdata *p = op->customdata;
+ ToolSettings *ts = CTX_data_tool_settings(C);
int estate = OPERATOR_PASS_THROUGH; /* default exit state - pass through to support MMB view nav, etc. */
/* if (event->type == NDOF_MOTION)
@@ -2348,10 +2465,18 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
* is essential for ensuring that they can quickly return to that view
*/
}
- else if ((ELEM(event->type, DKEY)) && (event->val == KM_RELEASE)) {
+ 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
+ */
+ WM_operator_name_call(C, "GPENCIL_OT_blank_frame_add", WM_OP_EXEC_DEFAULT, NULL);
+ estate = OPERATOR_RUNNING_MODAL;
+ }
else {
estate = OPERATOR_RUNNING_MODAL;
}
@@ -2366,9 +2491,11 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* exit() ends the current stroke before cleaning up */
/* printf("\t\tGP - end of paint op + end of stroke\n"); */
/* if drawing polygon and enable on back, must move stroke */
- if ((p->scene->toolsettings->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
- if (p->flags & GP_PAINTFLAG_STROKEADDED) {
- gpencil_move_last_stroke_to_back(C);
+ if (ts) {
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
+ if (p->flags & GP_PAINTFLAG_STROKEADDED) {
+ gpencil_move_last_stroke_to_back(C);
+ }
}
}
p->status = GP_STATUS_DONE;
@@ -2428,9 +2555,11 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
else {
/* printf("\t\tGP - end of stroke + op\n"); */
/* if drawing polygon and enable on back, must move stroke */
- if ((p->scene->toolsettings->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
- if (p->flags & GP_PAINTFLAG_STROKEADDED) {
- gpencil_move_last_stroke_to_back(C);
+ if (ts) {
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
+ if (p->flags & GP_PAINTFLAG_STROKEADDED) {
+ gpencil_move_last_stroke_to_back(C);
+ }
}
}
p->status = GP_STATUS_DONE;
@@ -2510,13 +2639,15 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
else if (p->status != GP_STATUS_ERROR) {
/* User clicked outside bounds of window while idling, so exit paintmode
- * NOTE: Don't eter this case if an error occurred while finding the
+ * 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 ((p->scene->toolsettings->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
- if (p->flags & GP_PAINTFLAG_STROKEADDED) {
- gpencil_move_last_stroke_to_back(C);
+ if (ts) {
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
+ if (p->flags & GP_PAINTFLAG_STROKEADDED) {
+ gpencil_move_last_stroke_to_back(C);
+ }
}
}
p->status = GP_STATUS_DONE;
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index 4cb966c6378..2912a1ac4eb 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -36,6 +36,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
#include "BLI_lasso.h"
#include "BLI_utildefines.h"
#include "BLI_math_vector.h"
@@ -253,6 +254,9 @@ 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,
+
/* 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 ? */
} eGP_SelectGrouped;
@@ -302,6 +306,43 @@ static void gp_select_same_layer(bContext *C)
CTX_DATA_END;
}
+/* Select all strokes with same colors as selected ones */
+static void gp_select_same_color(bContext *C)
+{
+ /* First, build set containing all the colors of selected strokes
+ * - We use the palette names, so that we can select all strokes with one
+ * (potentially missing) color, and remap them to something else
+ */
+ GSet *selected_colors = BLI_gset_str_new("GP Selected Colors");
+
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* add instead of insert here, otherwise the uniqueness check gets skipped,
+ * and we get many duplicate entries...
+ */
+ BLI_gset_add(selected_colors, gps->colorname);
+ }
+ }
+ CTX_DATA_END;
+
+ /* 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)) {
+ /* select this stroke */
+ 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;
+}
/* ----------------------------------- */
@@ -314,6 +355,9 @@ static int gpencil_select_grouped_exec(bContext *C, wmOperator *op)
case GP_SEL_SAME_LAYER:
gp_select_same_layer(C);
break;
+ case GP_SEL_SAME_COLOR:
+ gp_select_same_color(C);
+ break;
default:
BLI_assert(!"unhandled select grouped gpencil mode");
@@ -329,6 +373,7 @@ void GPENCIL_OT_select_grouped(wmOperatorType *ot)
{
static EnumPropertyItem prop_select_grouped_types[] = {
{GP_SEL_SAME_LAYER, "LAYER", 0, "Layer", "Shared layers"},
+ {GP_SEL_SAME_COLOR, "COLOR", 0, "Color", "Shared colors"},
{0, NULL, 0, NULL, NULL}
};
@@ -338,7 +383,7 @@ void GPENCIL_OT_select_grouped(wmOperatorType *ot)
ot->description = "Select all strokes with similar characteristics";
/* callbacks */
- //ot->invoke = WM_menu_invoke;
+ ot->invoke = WM_menu_invoke;
ot->exec = gpencil_select_grouped_exec;
ot->poll = gpencil_select_poll;
@@ -967,7 +1012,7 @@ static int gpencil_lasso_select_exec(bContext *C, wmOperator *op)
}
/* test if in lasso boundbox + within the lasso noose */
if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&rect, x0, y0) &&
- BLI_lasso_is_point_inside(mcords, mcords_tot, x0, y0, INT_MAX))
+ BLI_lasso_is_point_inside(mcords, mcords_tot, x0, y0, INT_MAX))
{
if (select) {
pt->flag |= GP_SPOINT_SELECT;
diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c
index 793ed2a07d0..7a9ad2b32c0 100644
--- a/source/blender/editors/gpencil/gpencil_undo.c
+++ b/source/blender/editors/gpencil/gpencil_undo.c
@@ -124,6 +124,17 @@ void gpencil_undo_init(bGPdata *gpd)
gpencil_undo_push(gpd);
}
+static void gpencil_undo_free_node(bGPundonode *undo_node)
+{
+ /* HACK: animdata wasn't duplicated, so it shouldn't be freed here,
+ * or else the real copy will segfault when accessed
+ */
+ undo_node->gpd->adt = NULL;
+
+ BKE_gpencil_free(undo_node->gpd, false);
+ MEM_freeN(undo_node->gpd);
+}
+
void gpencil_undo_push(bGPdata *gpd)
{
bGPundonode *undo_node;
@@ -137,20 +148,36 @@ void gpencil_undo_push(bGPdata *gpd)
while (undo_node) {
bGPundonode *next_node = undo_node->next;
- /* HACK: animdata wasn't duplicated, so it shouldn't be freed here,
- * or else the real copy will segfault when accessed
- */
- undo_node->gpd->adt = NULL;
-
- BKE_gpencil_free(undo_node->gpd, false);
- MEM_freeN(undo_node->gpd);
-
+ gpencil_undo_free_node(undo_node);
BLI_freelinkN(&undo_nodes, undo_node);
undo_node = next_node;
}
}
+ /* limit number of undo steps to the maximum undo steps
+ * - to prevent running out of memory during **really**
+ * long drawing sessions (triggering swapping)
+ */
+ /* TODO: Undo-memory constraint is not respected yet, but can be added if we have any need for it */
+ if (U.undosteps && !BLI_listbase_is_empty(&undo_nodes)) {
+ /* remove anything older than n-steps before cur_node */
+ int steps = 0;
+
+ undo_node = (cur_node) ? cur_node : undo_nodes.last;
+ while (undo_node) {
+ bGPundonode *prev_node = undo_node->prev;
+
+ if (steps >= U.undosteps) {
+ gpencil_undo_free_node(undo_node);
+ BLI_freelinkN(&undo_nodes, undo_node);
+ }
+
+ steps++;
+ undo_node = prev_node;
+ }
+ }
+
/* create new undo node */
undo_node = MEM_callocN(sizeof(bGPundonode), "gpencil undo node");
undo_node->gpd = BKE_gpencil_data_duplicate(G.main, gpd, true);
@@ -165,14 +192,7 @@ void gpencil_undo_finish(void)
bGPundonode *undo_node = undo_nodes.first;
while (undo_node) {
- /* HACK: animdata wasn't duplicated, so it shouldn't be freed here,
- * or else the real copy will segfault when accessed
- */
- undo_node->gpd->adt = NULL;
-
- BKE_gpencil_free(undo_node->gpd, false);
- MEM_freeN(undo_node->gpd);
-
+ gpencil_undo_free_node(undo_node);
undo_node = undo_node->next;
}
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index ed9a591dcbe..82892561daa 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -204,7 +204,7 @@ bGPdata *ED_gpencil_data_get_active(const bContext *C)
// XXX: this should be removed... We really shouldn't duplicate logic like this!
bGPdata *ED_gpencil_data_get_active_v3d(Scene *scene, View3D *v3d)
{
- Base *base = scene->basact;
+ BaseLegacy *base = scene->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.
@@ -391,7 +391,16 @@ EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C, PointerRNA
/* ******************************************************** */
/* Brush Tool Core */
-/* Check if part of stroke occurs within last segment drawn by eraser */
+/**
+ * Check whether a given stroke segment is inside a circular brush
+ *
+ * \param mval The current screen-space coordinates (midpoint) of the brush
+ * \param mvalo The previous screen-space coordinates (midpoint) of the brush (NOT CURRENTLY USED)
+ * \param rad The radius of the brush
+ *
+ * \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)
{
@@ -502,7 +511,11 @@ bGPDpalettecolor *ED_gpencil_stroke_getcolor(bGPdata *gpd, bGPDstroke *gps)
/* ******************************************************** */
/* Space Conversion */
-/* Init handling for space-conversion function (from passed-in parameters) */
+/**
+ * Init settings for stroke point space conversions
+ *
+ * \param r_gsc: [out] The space conversion settings struct, populated with necessary params
+ */
void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
{
ScrArea *sa = CTX_wm_area(C);
@@ -521,6 +534,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 *graph = CTX_data_depsgraph(C);
View3D *v3d = (View3D *)CTX_wm_space_data(C);
RegionView3D *rv3d = ar->regiondata;
@@ -528,7 +542,7 @@ 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(scene, ar, v3d, 0);
+ ED_view3d_autodist_init(graph, ar, v3d, 0);
/* for camera view set the subrect */
if (rv3d->persp == RV3D_CAMOB) {
@@ -538,7 +552,13 @@ void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
}
}
-/* convert point to parent space */
+/**
+ * Convert point to parent space
+ *
+ * \param pt Original point
+ * \param diff_mat Matrix with the difference between original parent matrix
+ * \param[out] r_pt Pointer to new point after apply matrix
+ */
void gp_point_to_parent_space(bGPDspoint *pt, float diff_mat[4][4], bGPDspoint *r_pt)
{
float fpt[3];
@@ -547,7 +567,9 @@ void gp_point_to_parent_space(bGPDspoint *pt, float diff_mat[4][4], bGPDspoint *
copy_v3_v3(&r_pt->x, fpt);
}
-/* Change position relative to parent object */
+/**
+ * Change points position relative to parent object
+ */
void gp_apply_parent(bGPDlayer *gpl, bGPDstroke *gps)
{
bGPDspoint *pt;
@@ -568,7 +590,9 @@ void gp_apply_parent(bGPDlayer *gpl, bGPDstroke *gps)
}
}
-/* Change point position relative to parent object */
+/**
+ * Change point position relative to parent object
+ */
void gp_apply_parent_point(bGPDlayer *gpl, bGPDspoint *pt)
{
/* undo matrix */
@@ -583,8 +607,13 @@ void gp_apply_parent_point(bGPDlayer *gpl, bGPDspoint *pt)
copy_v3_v3(&pt->x, fpt);
}
-/* Convert Grease Pencil points to screen-space values
- * WARNING: This assumes that the caller has already checked whether the stroke in question can be drawn
+/**
+ * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D)
+ *
+ * \param[out] r_x The screen-space x-coordinate of the point
+ * \param[out] r_y The screen-space y-coordinate of the point
+ *
+ * \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)
@@ -629,8 +658,79 @@ void gp_point_to_xy(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
}
/**
+ * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D)
+ *
+ * Just like gp_point_to_xy(), except the resulting coordinates are floats not ints.
+ * Use this version to solve "stair-step" artifacts which may arise when roundtripping the calculations.
+ *
+ * \param r_x: [out] The screen-space x-coordinate of the point
+ * \param r_y: [out] The screen-space y-coordinate of the point
+ *
+ * \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)
+{
+ ARegion *ar = gsc->ar;
+ View2D *v2d = gsc->v2d;
+ rctf *subrect = gsc->subrect;
+ float xyval[2];
+
+ /* sanity checks */
+ BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->sa->spacetype == SPACE_VIEW3D));
+ BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->sa->spacetype != SPACE_VIEW3D));
+
+
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ if (ED_view3d_project_float_global(ar, &pt->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+ *r_x = xyval[0];
+ *r_y = xyval[1];
+ }
+ else {
+ *r_x = 0.0f;
+ *r_y = 0.0f;
+ }
+ }
+ else if (gps->flag & GP_STROKE_2DSPACE) {
+ float vec[3] = {pt->x, pt->y, 0.0f};
+ int t_x, t_y;
+
+ mul_m4_v3(gsc->mat, vec);
+ UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], &t_x, &t_y);
+
+ if ((t_x == t_y) && (t_x == V2D_IS_CLIPPED)) {
+ /* XXX: Or should we just always use the values as-is? */
+ *r_x = 0.0f;
+ *r_y = 0.0f;
+ }
+ else {
+ *r_x = (float)t_x;
+ *r_y = (float)t_y;
+ }
+ }
+ else {
+ if (subrect == NULL) {
+ /* normal 3D view (or view space) */
+ *r_x = (pt->x / 100.0f * ar->winx);
+ *r_y = (pt->y / 100.0f * ar->winy);
+ }
+ else {
+ /* camera view, use subrect */
+ *r_x = ((pt->x / 100.0f) * BLI_rctf_size_x(subrect)) + subrect->xmin;
+ *r_y = ((pt->y / 100.0f) * BLI_rctf_size_y(subrect)) + subrect->ymin;
+ }
+ }
+}
+
+/**
* Project screenspace coordinates to 3D-space
*
+ * For use with editing tools where it is easier to perform the operations in 2D,
+ * and then later convert the transformed points back to 3D.
+ *
+ * \param screen_co: The screenspace 2D coordinates to convert to
+ * \param r_out: The resulting 3D coordinates of the input point
+ *
* \note We include this as a utility function, since the standard method
* involves quite a few steps, which are invariably always the same
* for all GPencil operations. So, it's nicer to just centralize these.
@@ -665,7 +765,7 @@ bool gp_point_xy_to_3d(GP_SpaceConversion *gsc, Scene *scene, const float screen
}
/**
- * Apply smooth to stroke point
+ * Apply smooth to stroke point
* \param gps Stroke to smooth
* \param i Point index
* \param inf Amount of smoothing to apply
@@ -773,8 +873,8 @@ bool gp_smooth_stroke_strength(bGPDstroke *gps, int i, float inf)
ptc = &gps->points[after];
/* the optimal value is the corresponding to the interpolation of the strength
- * at the distance of point b
- */
+ * 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;
@@ -811,8 +911,8 @@ bool gp_smooth_stroke_thickness(bGPDstroke *gps, int i, float inf)
ptc = &gps->points[after];
/* the optimal value is the corresponding to the interpolation of the pressure
- * at the distance of point b
- */
+ * 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;
@@ -858,7 +958,7 @@ void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints)
/**
* Add randomness to stroke
* \param gps Stroke data
- * \param brsuh Brush data
+ * \param brush Brush data
*/
void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush)
{
@@ -883,10 +983,12 @@ void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush)
float normal[3];
cross_v3_v3v3(normal, v1, v2);
normalize_v3(normal);
+
/* get orthogonal vector to plane to rotate random effect */
float ortho[3];
cross_v3_v3v3(ortho, v1, normal);
normalize_v3(ortho);
+
/* Read all points and apply shift vector (first and last point not modified) */
for (int i = 1; i < gps->totpoints - 1; ++i) {
bGPDspoint *pt = &gps->points[i];
@@ -938,6 +1040,46 @@ 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)
+{
+ bGPDspoint *pt;
+ int i;
+ float diff_mat[4][4];
+ float cur_mat[4][4];
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl->parent != NULL) {
+ /* calculate new matrix */
+ if ((gpl->partype == PAROBJECT) || (gpl->partype == PARSKEL)) {
+ invert_m4_m4(cur_mat, gpl->parent->obmat);
+ }
+ else if (gpl->partype == PARBONE) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(gpl->parent->pose, gpl->parsubstr);
+ if (pchan) {
+ float tmp_mat[4][4];
+ mul_m4_m4m4(tmp_mat, gpl->parent->obmat, pchan->pose_mat);
+ invert_m4_m4(cur_mat, tmp_mat);
+ }
+ }
+
+ /* only redo if any change */
+ if (!equals_m4m4(gpl->inverse, cur_mat)) {
+ /* first apply current transformation to all strokes */
+ 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);
+ }
+ }
+ }
+ /* set new parent matrix */
+ copy_m4_m4(gpl->inverse, cur_mat);
+ }
+ }
+ }
+}
/* ******************************************************** */
bool ED_gpencil_stroke_minmax(
const bGPDstroke *gps, const bool use_select,
@@ -955,8 +1097,8 @@ bool ED_gpencil_stroke_minmax(
}
return changed;
}
-/* Dynamic Enums of GP Brushes */
+/* Dynamic Enums of GP Brushes */
EnumPropertyItem *ED_gpencil_brushes_enum_itemf(
bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
bool *r_free)
@@ -990,8 +1132,8 @@ EnumPropertyItem *ED_gpencil_brushes_enum_itemf(
return item;
}
-/* Dynamic Enums of GP Palettes */
+/* Dynamic Enums of GP Palettes */
EnumPropertyItem *ED_gpencil_palettes_enum_itemf(
bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
bool *r_free)
diff --git a/source/blender/editors/hair/CMakeLists.txt b/source/blender/editors/hair/CMakeLists.txt
index 3f9785be7a7..97c18009560 100644
--- a/source/blender/editors/hair/CMakeLists.txt
+++ b/source/blender/editors/hair/CMakeLists.txt
@@ -25,6 +25,7 @@ set(INC
../../blenkernel
../../blenlib
../../bmesh
+ ../../depsgraph
../../gpu
../../makesdna
../../makesrna
diff --git a/source/blender/editors/hair/hair_cursor.c b/source/blender/editors/hair/hair_cursor.c
index dadd0cf114e..a3905db2f80 100644
--- a/source/blender/editors/hair/hair_cursor.c
+++ b/source/blender/editors/hair/hair_cursor.c
@@ -42,6 +42,9 @@
#include "BKE_brush.h"
#include "BKE_context.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -58,45 +61,31 @@ static void hair_draw_cursor(bContext *C, int x, int y, void *UNUSED(customdata)
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
HairEditSettings *settings = &scene->toolsettings->hair_edit;
Brush *brush = settings->brush;
-
- float final_radius;
- float translation[2];
- float outline_alpha, *outline_col;
-
if (!brush)
return;
-
- final_radius = BKE_brush_size_get(scene, brush);
-
+
+ float final_radius = BKE_brush_size_get(scene, brush);
+ float col[4];
+
/* set various defaults */
- translation[0] = x;
- translation[1] = y;
- outline_alpha = 0.5;
- outline_col = brush->add_col;
+ copy_v3_v3(col, brush->add_col);
+ col[3] = 0.5f;
- /* make lines pretty */
- glEnable(GL_BLEND);
- glEnable(GL_LINE_SMOOTH);
+ Gwn_VertFormat *format = immVertexFormat();
+ uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
- /* set brush color */
- glColor4f(outline_col[0], outline_col[1], outline_col[2], outline_alpha);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
- /* draw brush outline */
- glTranslatef(translation[0], translation[1], 0);
+ immUniformColor4fv(col);
/* 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.0f, final_radius * ups->size_pressure_value, 40);
+ imm_draw_circle_wire(pos, x, y, 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(col, col[3]*0.5f);
}
- glutil_draw_lined_arc(0.0, M_PI*2.0f, final_radius, 40);
- glTranslatef(-translation[0], -translation[1], 0);
-
- /* restore GL state */
- glDisable(GL_BLEND);
- glDisable(GL_LINE_SMOOTH);
+ imm_draw_circle_wire(pos, x, y, final_radius, 40);
}
void hair_edit_cursor_start(bContext *C, int (*poll)(bContext *C))
diff --git a/source/blender/editors/hair/hair_edit.c b/source/blender/editors/hair/hair_edit.c
index 7869052f755..b211df74654 100644
--- a/source/blender/editors/hair/hair_edit.c
+++ b/source/blender/editors/hair/hair_edit.c
@@ -46,11 +46,12 @@
#include "BKE_brush.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_editstrands.h"
#include "BKE_paint.h"
+#include "DEG_depsgraph.h"
+
#include "bmesh.h"
#include "RNA_access.h"
@@ -191,7 +192,7 @@ static int hair_edit_toggle_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_HAIR, NULL);
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
return OPERATOR_FINISHED;
}
@@ -214,28 +215,26 @@ void HAIR_OT_hair_edit_toggle(wmOperatorType *ot)
/* ==== brush stroke ==== */
-void hair_init_viewdata(bContext *C, HairViewData *viewdata)
+void hair_init_viewcontext(bContext *C, ViewContext *vc)
{
View3D *v3d;
bool has_zbuf;
- view3d_set_viewcontext(C, &viewdata->vc);
+ view3d_set_viewcontext(C, vc);
- v3d = viewdata->vc.v3d;
+ v3d = vc->v3d;
has_zbuf = (v3d->drawtype > OB_WIRE) && (v3d->flag & V3D_ZBUF_SELECT);
- view3d_get_transformation(viewdata->vc.ar, viewdata->vc.rv3d, NULL, &viewdata->mats);
-
if (has_zbuf) {
if (v3d->flag & V3D_INVALID_BACKBUF) {
/* needed or else the draw matrix can be incorrect */
view3d_operator_needs_opengl(C);
- ED_view3d_backbuf_validate(&viewdata->vc);
+ ED_view3d_backbuf_validate(vc);
/* we may need to force an update here by setting the rv3d as dirty
* for now it seems ok, but take care!:
* rv3d->depths->dirty = 1; */
- ED_view3d_depth_update(viewdata->vc.ar);
+ ED_view3d_depth_update(vc->ar);
}
}
}
@@ -314,7 +313,7 @@ static bool hair_stroke_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
/* low-pass filter to smooth out jittery pixel increments in the direction */
interp_v2_v2v2(stroke->smoothdir, mdelta, stroke->smoothdir, smoothfac);
- hair_init_viewdata(C, &tool_data.viewdata);
+ hair_init_viewcontext(C, &tool_data.vc);
tool_data.scene = scene;
tool_data.ob = ob;
tool_data.edit = edit;
@@ -325,7 +324,7 @@ static bool hair_stroke_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
tool_data.mdepth = stroke->zfac;
zvec[0] = 0.0f; zvec[1] = 0.0f; zvec[2] = stroke->zfac;
- ED_view3d_win_to_3d(ar, zvec, mouse, tool_data.loc);
+ ED_view3d_win_to_3d(tool_data.vc.v3d, ar, zvec, mouse, tool_data.loc);
ED_view3d_win_to_delta(ar, stroke->smoothdir, tool_data.delta, stroke->zfac);
/* tools work in object space */
mul_m4_v3(tool_data.imat, tool_data.loc);
@@ -368,7 +367,7 @@ static int hair_stroke_exec(bContext *C, wmOperator *op)
RNA_END;
if (updated) {
- 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);
}
@@ -398,7 +397,7 @@ static void hair_stroke_apply_event(bContext *C, wmOperator *op, const wmEvent *
updated |= hair_stroke_apply(C, op, &itemptr);
if (updated) {
- 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 {
diff --git a/source/blender/editors/hair/hair_intern.h b/source/blender/editors/hair/hair_intern.h
index afecc27e989..178671c1c60 100644
--- a/source/blender/editors/hair/hair_intern.h
+++ b/source/blender/editors/hair/hair_intern.h
@@ -71,20 +71,15 @@ bool ED_hair_object_apply_particle_edit(struct Object *ob);
/* ==== Hair Brush ==== */
-typedef struct HairViewData {
- ViewContext vc;
- bglMats mats;
-} HairViewData;
-
-void hair_init_viewdata(struct bContext *C, struct HairViewData *viewdata);
+void hair_init_viewcontext(struct bContext *C, struct ViewContext *vc);
-bool hair_test_depth(struct HairViewData *viewdata, const float co[3], const int screen_co[2]);
-bool hair_test_vertex_inside_circle(struct HairViewData *viewdata, const float mval[2], float radsq,
+bool hair_test_depth(struct ViewContext *vc, const float co[3], const int screen_co[2]);
+bool hair_test_vertex_inside_circle(struct ViewContext *vc, const float mval[2], float radsq,
struct BMVert *v, float *r_dist);
-bool hair_test_edge_inside_circle(struct HairViewData *viewdata, const float mval[2], float radsq,
+bool hair_test_edge_inside_circle(struct ViewContext *vc, const float mval[2], float radsq,
struct BMVert *v1, struct BMVert *v2, float *r_dist, float *r_lambda);
-bool hair_test_vertex_inside_rect(struct HairViewData *viewdata, struct rcti *rect, struct BMVert *v);
-bool hair_test_vertex_inside_lasso(struct HairViewData *viewdata, const int mcoords[][2], short moves, struct BMVert *v);
+bool hair_test_vertex_inside_rect(struct ViewContext *vc, struct rcti *rect, struct BMVert *v);
+bool hair_test_vertex_inside_lasso(struct ViewContext *vc, const int mcoords[][2], short moves, struct BMVert *v);
typedef struct HairToolData {
/* context */
@@ -92,7 +87,7 @@ typedef struct HairToolData {
struct Object *ob;
struct BMEditStrands *edit;
struct HairEditSettings *settings;
- HairViewData viewdata;
+ ViewContext vc;
/* view space */
float mval[2]; /* mouse coordinates */
diff --git a/source/blender/editors/hair/hair_select.c b/source/blender/editors/hair/hair_select.c
index 501b8581ec0..12b32fc510b 100644
--- a/source/blender/editors/hair/hair_select.c
+++ b/source/blender/editors/hair/hair_select.c
@@ -43,9 +43,10 @@
#include "DNA_view3d_types.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_editstrands.h"
+#include "DEG_depsgraph.h"
+
#include "bmesh.h"
#include "RNA_access.h"
@@ -254,7 +255,7 @@ void HAIR_OT_select_all(wmOperatorType *ot)
/************************ mouse select operator ************************/
typedef struct DistanceVertexCirleData {
- HairViewData viewdata;
+ ViewContext vc;
float mval[2];
float radsq;
} DistanceVertexCirleData;
@@ -263,7 +264,7 @@ static bool distance_vertex_circle(void *userdata, struct BMVert *v, float *dist
{
DistanceVertexCirleData *data = userdata;
- return hair_test_vertex_inside_circle(&data->viewdata, data->mval, data->radsq, v, dist);
+ return hair_test_vertex_inside_circle(&data->vc, data->mval, data->radsq, v, dist);
}
static void closest_vertex_select(void *UNUSED(userdata), struct BMVert *v, int action)
@@ -286,7 +287,7 @@ int ED_hair_mouse_select(bContext *C, const int mval[2], bool extend, bool desel
hair_deselect_all(edit);
}
- hair_init_viewdata(C, &data.viewdata);
+ hair_init_viewcontext(C, &data.vc);
data.mval[0] = mval[0];
data.mval[1] = mval[1];
data.radsq = select_radius * select_radius;
@@ -333,7 +334,7 @@ static int select_linked_exec(bContext *C, wmOperator *op)
RNA_int_get_array(op->ptr, "location", location);
- hair_init_viewdata(C, &data.viewdata);
+ hair_init_viewcontext(C, &data.vc);
data.mval[0] = location[0];
data.mval[1] = location[1];
data.radsq = select_radius * select_radius;
@@ -376,7 +377,7 @@ void HAIR_OT_select_linked(wmOperatorType *ot)
/************************ border select operator ************************/
typedef struct PollVertexRectData {
- HairViewData viewdata;
+ ViewContext vc;
rcti rect;
} PollVertexRectData;
@@ -384,7 +385,7 @@ static bool poll_vertex_inside_rect(void *userdata, struct BMVert *v)
{
PollVertexRectData *data = userdata;
- return hair_test_vertex_inside_rect(&data->viewdata, &data->rect, v);
+ return hair_test_vertex_inside_rect(&data->vc, &data->rect, v);
}
int ED_hair_border_select(bContext *C, rcti *rect, bool select, bool extend)
@@ -400,7 +401,7 @@ int ED_hair_border_select(bContext *C, rcti *rect, bool select, bool extend)
if (!extend && select)
hair_deselect_all(edit);
- hair_init_viewdata(C, &data.viewdata);
+ hair_init_viewcontext(C, &data.vc);
data.rect = *rect;
if (extend)
@@ -420,7 +421,7 @@ int ED_hair_border_select(bContext *C, rcti *rect, bool select, bool extend)
/************************ circle select operator ************************/
typedef struct PollVertexCirleData {
- HairViewData viewdata;
+ ViewContext vc;
float mval[2];
float radsq;
} PollVertexCirleData;
@@ -430,7 +431,7 @@ static bool poll_vertex_inside_circle(void *userdata, struct BMVert *v)
PollVertexCirleData *data = userdata;
float dist;
- return hair_test_vertex_inside_circle(&data->viewdata, data->mval, data->radsq, v, &dist);
+ return hair_test_vertex_inside_circle(&data->vc, data->mval, data->radsq, v, &dist);
}
int ED_hair_circle_select(bContext *C, bool select, const int mval[2], float radius)
@@ -447,7 +448,7 @@ int ED_hair_circle_select(bContext *C, bool select, const int mval[2], float rad
if (!edit)
return 0;
- hair_init_viewdata(C, &data.viewdata);
+ hair_init_viewcontext(C, &data.vc);
data.mval[0] = mval[0];
data.mval[1] = mval[1];
data.radsq = radius * radius;
@@ -460,7 +461,7 @@ int ED_hair_circle_select(bContext *C, bool select, const int mval[2], float rad
/************************ lasso select operator ************************/
typedef struct PollVertexLassoData {
- HairViewData viewdata;
+ ViewContext vc;
const int (*mcoords)[2];
short moves;
} PollVertexLassoData;
@@ -469,7 +470,7 @@ static bool poll_vertex_inside_lasso(void *userdata, struct BMVert *v)
{
PollVertexLassoData *data = userdata;
- return hair_test_vertex_inside_lasso(&data->viewdata, data->mcoords, data->moves, v);
+ return hair_test_vertex_inside_lasso(&data->vc, data->mcoords, data->moves, v);
}
int ED_hair_lasso_select(bContext *C, const int mcoords[][2], const short moves, bool extend, bool select)
@@ -485,7 +486,7 @@ int ED_hair_lasso_select(bContext *C, const int mcoords[][2], const short moves,
if (!extend && select)
hair_deselect_all(edit);
- hair_init_viewdata(C, &data.viewdata);
+ hair_init_viewcontext(C, &data.vc);
data.mcoords = mcoords;
data.moves = moves;
diff --git a/source/blender/editors/hair/hair_stroke.c b/source/blender/editors/hair/hair_stroke.c
index 935f5d9ca59..c18ef56bf6f 100644
--- a/source/blender/editors/hair/hair_stroke.c
+++ b/source/blender/editors/hair/hair_stroke.c
@@ -61,22 +61,20 @@
#include "hair_intern.h"
-bool hair_test_depth(HairViewData *viewdata, const float co[3], const int screen_co[2])
+bool hair_test_depth(ViewContext *vc, const float co[3], const int screen_co[2])
{
- View3D *v3d = viewdata->vc.v3d;
- ViewDepths *vd = viewdata->vc.rv3d->depths;
+ View3D *v3d = vc->v3d;
+ ViewDepths *vd = vc->rv3d->depths;
const bool has_zbuf = (v3d->drawtype > OB_WIRE) && (v3d->flag & V3D_ZBUF_SELECT);
- double ux, uy, uz;
+ float uco[3];
float depth;
/* nothing to do */
if (!has_zbuf)
return true;
- gluProject(co[0], co[1], co[2],
- viewdata->mats.modelview, viewdata->mats.projection, viewdata->mats.viewport,
- &ux, &uy, &uz);
+ ED_view3d_project(vc->ar, co, uco);
/* 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) {
@@ -84,15 +82,15 @@ bool hair_test_depth(HairViewData *viewdata, const float co[3], const int screen
/* we know its not clipped */
depth = vd->depths[screen_co[1] * vd->w + screen_co[0]];
- return ((float)uz - 0.00001f <= depth);
+ return ((float)uco[2] - 0.00001f <= depth);
}
return false;
}
-bool hair_test_vertex_inside_circle(HairViewData *viewdata, const float mval[2], float radsq, BMVert *v, float *r_dist)
+bool hair_test_vertex_inside_circle(ViewContext *vc, const float mval[2], float radsq, BMVert *v, float *r_dist)
{
- float (*obmat)[4] = viewdata->vc.obact->obmat;
+ float (*obmat)[4] = vc->obact->obmat;
float co_world[3];
float dx, dy, distsq;
int screen_co[2];
@@ -100,7 +98,7 @@ bool hair_test_vertex_inside_circle(HairViewData *viewdata, const float mval[2],
mul_v3_m4v3(co_world, obmat, v->co);
/* TODO, should this check V3D_PROJ_TEST_CLIP_BB too? */
- if (ED_view3d_project_int_global(viewdata->vc.ar, co_world, screen_co, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_OK)
+ if (ED_view3d_project_int_global(vc->ar, co_world, screen_co, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_OK)
return false;
dx = mval[0] - (float)screen_co[0];
@@ -110,7 +108,7 @@ bool hair_test_vertex_inside_circle(HairViewData *viewdata, const float mval[2],
if (distsq > radsq)
return false;
- if (hair_test_depth(viewdata, v->co, screen_co)) {
+ if (hair_test_depth(vc, v->co, screen_co)) {
*r_dist = sqrtf(distsq);
return true;
}
@@ -118,9 +116,9 @@ bool hair_test_vertex_inside_circle(HairViewData *viewdata, const float mval[2],
return false;
}
-bool hair_test_edge_inside_circle(HairViewData *viewdata, const float mval[2], float radsq, BMVert *v1, BMVert *v2, float *r_dist, float *r_lambda)
+bool hair_test_edge_inside_circle(ViewContext *vc, const float mval[2], float radsq, BMVert *v1, BMVert *v2, float *r_dist, float *r_lambda)
{
- float (*obmat)[4] = viewdata->vc.obact->obmat;
+ float (*obmat)[4] = vc->obact->obmat;
float world_co1[3], world_co2[3];
float dx, dy, distsq;
int screen_co1[2], screen_co2[2], screen_cp[2];
@@ -130,9 +128,9 @@ bool hair_test_edge_inside_circle(HairViewData *viewdata, const float mval[2], f
mul_v3_m4v3(world_co2, obmat, v2->co);
/* TODO, should this check V3D_PROJ_TEST_CLIP_BB too? */
- if (ED_view3d_project_int_global(viewdata->vc.ar, world_co1, screen_co1, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_OK)
+ if (ED_view3d_project_int_global(vc->ar, world_co1, screen_co1, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_OK)
return false;
- if (ED_view3d_project_int_global(viewdata->vc.ar, world_co2, screen_co2, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_OK)
+ if (ED_view3d_project_int_global(vc->ar, world_co2, screen_co2, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_OK)
return false;
screen_co1f[0] = screen_co1[0];
@@ -156,7 +154,7 @@ bool hair_test_edge_inside_circle(HairViewData *viewdata, const float mval[2], f
screen_cp[0] = screen_cpf[0];
screen_cp[1] = screen_cpf[1];
- if (hair_test_depth(viewdata, world_cp, screen_cp)) {
+ if (hair_test_depth(vc, world_cp, screen_cp)) {
*r_dist = sqrtf(distsq);
*r_lambda = lambda;
return true;
@@ -165,43 +163,43 @@ bool hair_test_edge_inside_circle(HairViewData *viewdata, const float mval[2], f
return false;
}
-bool hair_test_vertex_inside_rect(HairViewData *viewdata, rcti *rect, BMVert *v)
+bool hair_test_vertex_inside_rect(ViewContext *vc, rcti *rect, BMVert *v)
{
- float (*obmat)[4] = viewdata->vc.obact->obmat;
+ float (*obmat)[4] = vc->obact->obmat;
float co_world[3];
int screen_co[2];
mul_v3_m4v3(co_world, obmat, v->co);
/* TODO, should this check V3D_PROJ_TEST_CLIP_BB too? */
- if (ED_view3d_project_int_global(viewdata->vc.ar, co_world, screen_co, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_OK)
+ if (ED_view3d_project_int_global(vc->ar, co_world, screen_co, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_OK)
return false;
if (!BLI_rcti_isect_pt_v(rect, screen_co))
return false;
- if (hair_test_depth(viewdata, v->co, screen_co))
+ if (hair_test_depth(vc, v->co, screen_co))
return true;
else
return false;
}
-bool hair_test_vertex_inside_lasso(HairViewData *viewdata, const int mcoords[][2], short moves, BMVert *v)
+bool hair_test_vertex_inside_lasso(ViewContext *vc, const int mcoords[][2], short moves, BMVert *v)
{
- float (*obmat)[4] = viewdata->vc.obact->obmat;
+ float (*obmat)[4] = vc->obact->obmat;
float co_world[3];
int screen_co[2];
mul_v3_m4v3(co_world, obmat, v->co);
/* TODO, should this check V3D_PROJ_TEST_CLIP_BB too? */
- if (ED_view3d_project_int_global(viewdata->vc.ar, co_world, screen_co, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_OK)
+ if (ED_view3d_project_int_global(vc->ar, co_world, screen_co, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_OK)
return false;
if (!BLI_lasso_is_point_inside(mcoords, moves, screen_co[0], screen_co[1], IS_CLIPPED))
return false;
- if (hair_test_depth(viewdata, v->co, screen_co))
+ if (hair_test_depth(vc, v->co, screen_co))
return true;
else
return false;
@@ -231,7 +229,7 @@ static int UNUSED_FUNCTION(hair_tool_apply_vertex)(HairToolData *data, VertexToo
ED_strands_mirror_cache_begin(data->edit, 0, false, false, hair_use_mirror_topology(data->ob));
BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) {
- if (!hair_test_vertex_inside_circle(&data->viewdata, data->mval, radsq, v, &dist))
+ if (!hair_test_vertex_inside_circle(&data->vc, data->mval, radsq, v, &dist))
continue;
factor = 1.0f - dist / rad;
@@ -279,7 +277,7 @@ static int hair_tool_apply_strand_edges(HairToolData *data, EdgeToolCb cb, void
if (k > 0) {
float dist, lambda;
- if (hair_test_edge_inside_circle(&data->viewdata, data->mval, radsq, vprev, v, &dist, &lambda)) {
+ if (hair_test_edge_inside_circle(&data->vc, data->mval, radsq, vprev, v, &dist, &lambda)) {
float factor = 1.0f - dist / rad;
if (factor > threshold) {
cb(data, userdata, vprev, v, factor, lambda);
@@ -426,7 +424,7 @@ static void grow_hair(BMEditStrands *edit, MeshSample *sample)
static bool hair_add_ray_cb(void *vdata, float ray_start[3], float ray_end[3])
{
HairToolData *data = vdata;
- ViewContext *vc = &data->viewdata.vc;
+ ViewContext *vc = &data->vc;
ED_view3d_win_to_segment(vc->ar, vc->v3d, data->mval, ray_start, ray_end, true);
diff --git a/source/blender/editors/include/BIF_gl.h b/source/blender/editors/include/BIF_gl.h
index e264d9e16a3..f91e7d42bca 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,19 +47,5 @@ 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 d3d2c465d46..3184ebee4d9 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,58 +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);
-
+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]);
/* 2D Drawing Assistance */
/** Define a 2D area (viewport, scissor, matrices) for OpenGL rendering.
@@ -176,12 +122,13 @@ void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h, int
*/
void glaDefine2DArea(struct rcti *screen_rect);
-typedef struct gla2DDrawInfo gla2DDrawInfo;
+/* TODO(merwin): put the following 2D code to use, or build new 2D code inspired & informd by it */
+
+#if 0 /* UNUSED */
-/* UNUSED */
-#if 0
+typedef struct gla2DDrawInfo gla2DDrawInfo;
-gla2DDrawInfo *glaBegin2DDraw(struct rcti *screen_rect, struct rctf *world_rect);
+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]);
@@ -190,7 +137,8 @@ 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
+
+#endif /* UNUSED */
void set_inverted_drawing(int enable);
void setlinestyle(int nr);
@@ -198,37 +146,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 bfd89e90fce..a65c6eec6ae 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -82,6 +82,7 @@ typedef struct bAnimContext {
struct bDopeSheet *ads; /* dopesheet data for editor (or which is being used) */
struct Scene *scene; /* active scene */
+ struct SceneLayer *scene_layer; /* active scene layer */
struct Object *obact; /* active object */
ListBase *markers; /* active set of markers */
@@ -170,6 +171,7 @@ typedef enum eAnim_ChannelType {
ANIMTYPE_DSLINESTYLE,
ANIMTYPE_DSSPK,
ANIMTYPE_DSGPENCIL,
+ ANIMTYPE_DSMCLIP,
ANIMTYPE_SHAPEKEY,
@@ -329,6 +331,8 @@ typedef enum eAnimFilter_Flags {
#define SEL_NLT(nlt) (nlt->flag & NLATRACK_SELECTED)
#define EDITABLE_NLT(nlt) ((nlt->flag & NLATRACK_PROTECTED) == 0)
+/* Movie clip only */
+#define EXPANDED_MCLIP(clip) (clip->flag & MCLIP_DATA_EXPAND)
/* AnimData - NLA mostly... */
#define SEL_ANIMDATA(adt) (adt->flag & ADT_UI_SELECTED)
@@ -417,7 +421,8 @@ typedef enum eAnimChannel_Settings {
ACHANNEL_SETTING_VISIBLE = 4, /* only for Graph Editor */
ACHANNEL_SETTING_SOLO = 5, /* only for NLA Tracks */
ACHANNEL_SETTING_PINNED = 6, /* only for NLA Actions */
- ACHANNEL_SETTING_MOD_OFF = 7
+ ACHANNEL_SETTING_MOD_OFF = 7,
+ ACHANNEL_SETTING_ALWAYS_VISIBLE = 8, /* channel is pinned and always visible */
} eAnimChannel_Settings;
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 904132b8876..7866bed8666 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -35,7 +35,7 @@ extern "C" {
#endif
struct bArmature;
-struct Base;
+struct BaseLegacy;
struct bContext;
struct Bone;
struct bPoseChannel;
@@ -44,8 +44,10 @@ struct ListBase;
struct MeshDeformModifierData;
struct DerivedMesh;
struct Object;
+struct Base;
struct ReportList;
struct Scene;
+struct SceneLayer;
struct ViewContext;
struct wmKeyConfig;
struct wmOperator;
@@ -82,6 +84,12 @@ typedef struct EditBone {
short segments;
+ /* 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 */
+
/* Used to store temporary data */
union {
struct EditBone *ebone;
@@ -130,8 +138,9 @@ void ED_armature_ebone_listbase_temp_clear(struct ListBase *lb);
void ED_armature_deselect_all(struct Object *obedit);
void ED_armature_deselect_all_visible(struct Object *obedit);
-int ED_do_pose_selectbuffer(struct Scene *scene, struct Base *base, unsigned int *buffer,
- short hits, bool extend, bool deselect, bool toggle, bool do_nearest);
+bool ED_do_pose_selectbuffer(
+ struct Scene *scene, struct SceneLayer *sl, struct Base *base, const unsigned int *buffer, short hits,
+ bool extend, bool deselect, bool toggle, bool do_nearest);
bool ED_armature_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 *get_indexed_bone(struct Object *ob, int index);
@@ -171,6 +180,7 @@ void create_vgroups_from_armature(struct ReportList *reports, struct Scene *scen
/* if bone is already in list, pass it as param to ignore it */
void unique_editbone_name(struct ListBase *ebones, char *name, EditBone *bone);
void ED_armature_bone_rename(struct bArmature *arm, const char *oldnamep, const char *newnamep);
+void ED_armature_bones_flip_names(struct bArmature *arm, struct ListBase *bones_names);
void undo_push_armature(struct bContext *C, const char *name);
diff --git a/source/blender/editors/include/ED_clip.h b/source/blender/editors/include/ED_clip.h
index 5f8ebd87d19..91f8b39f7b9 100644
--- a/source/blender/editors/include/ED_clip.h
+++ b/source/blender/editors/include/ED_clip.h
@@ -63,7 +63,7 @@ int ED_space_clip_get_clip_frame_number(struct SpaceClip *sc);
struct ImBuf *ED_space_clip_get_buffer(struct SpaceClip *sc);
struct ImBuf *ED_space_clip_get_stable_buffer(struct SpaceClip *sc, float loc[2], float *scale, float *angle);
-bool ED_space_clip_color_sample(struct Scene *scene, struct SpaceClip *sc, struct ARegion *ar, int mval[2], float r_col[3]);
+bool ED_space_clip_color_sample(struct SpaceClip *sc, struct ARegion *ar, int mval[2], float r_col[3]);
void ED_clip_update_frame(const struct Main *mainp, int cfra);
bool ED_clip_view_selection(const struct bContext *C, struct ARegion *ar, bool fit);
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index d526b0841cc..74d9ad0886d 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -30,6 +30,8 @@
#ifndef __ED_GPENCIL_H__
#define __ED_GPENCIL_H__
+#include "ED_numinput.h"
+
struct ID;
struct ListBase;
struct bContext;
@@ -51,6 +53,36 @@ struct wmKeyConfig;
/* ------------- Grease-Pencil Helpers ---------------- */
+typedef struct tGPDinterpolate_layer {
+ struct tGPDinterpolate_layer *next, *prev;
+
+ struct bGPDlayer *gpl; /* layer */
+ struct bGPDframe *prevFrame; /* frame before current frame (interpolate-from) */
+ struct bGPDframe *nextFrame; /* frame after current frame (interpolate-to) */
+ struct bGPDframe *interFrame; /* interpolated frame */
+ float factor; /* interpolate factor */
+
+} tGPDinterpolate_layer;
+
+/* 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 */
+
+ 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 'Stroke Point' data
*
@@ -118,6 +150,7 @@ 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);
/* ----------- Grease-Pencil AnimEdit API ------------------ */
bool ED_gplayer_frames_looper(struct bGPDlayer *gpl, struct Scene *scene,
@@ -152,6 +185,8 @@ int ED_undo_gpencil_step(struct bContext *C, int step, const char *name);
/* get difference matrix using parent */
void ED_gpencil_parent_location(struct bGPDlayer *gpl, float diff_mat[4][4]);
+/* reset parent matrix for all layers */
+void ED_gpencil_reset_layers_parent(struct bGPdata *gpd);
#endif /* __ED_GPENCIL_H__ */
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index 283113f93d6..00e58785373 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -39,6 +39,7 @@ struct ToolSettings;
struct wmWindowManager;
struct ARegion;
struct Scene;
+struct SceneLayer;
/* image_edit.c, exported for transform */
struct Image *ED_space_image(struct SpaceImage *sima);
@@ -46,7 +47,7 @@ void ED_space_image_set(struct SpaceImage *sima, struct Scene *scene, s
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);
-bool ED_space_image_color_sample(struct Scene *scene, struct SpaceImage *sima, struct ARegion *ar, int mval[2], float r_col[3]);
+bool ED_space_image_color_sample(struct SpaceImage *sima, struct ARegion *ar, int mval[2], float r_col[3]);
struct ImBuf *ED_space_image_acquire_buffer(struct SpaceImage *sima, void **r_lock);
void ED_space_image_release_buffer(struct SpaceImage *sima, struct ImBuf *ibuf, void *lock);
bool ED_space_image_has_buffer(struct SpaceImage *sima);
@@ -74,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 SceneLayer *sl, struct SpaceImage *sima);
int ED_space_image_maskedit_poll(struct bContext *C);
int 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..fe570fef83d 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 SceneLayer *sl);
+const char *ED_info_stats_string(struct Scene *scene, struct SceneLayer *sl);
#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 c478a8b17e5..62f1a617fcb 100644
--- a/source/blender/editors/include/ED_keyframes_draw.h
+++ b/source/blender/editors/include/ED_keyframes_draw.h
@@ -108,8 +108,10 @@ 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);
+/* draw simple diamond-shape keyframe */
+/* caller should set up vertex format, bind GPU_SHADER_KEYFRAME_DIAMOND, immBegin(GWN_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);
/* ******************************* Methods ****************************** */
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 602e203a381..07cdff687a3 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -389,6 +389,7 @@ bool ED_autokeyframe_pchan(struct bContext *C, struct Scene *scene, struct Objec
#define ANIM_KS_LOC_ROT_SCALE_ID "LocRotScale"
#define ANIM_KS_AVAILABLE_ID "Available"
#define ANIM_KS_WHOLE_CHARACTER_ID "WholeCharacter"
+#define ANIM_KS_WHOLE_CHARACTER_SELECTED_ID "WholeCharacterSelected"
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_manipulator_library.h b/source/blender/editors/include/ED_manipulator_library.h
new file mode 100644
index 00000000000..b1970a7bab3
--- /dev/null
+++ b/source/blender/editors/include/ED_manipulator_library.h
@@ -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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file ED_manipulator_library.h
+ * \ingroup wm
+ *
+ * \name Generic Manipulators.
+ *
+ * This is exposes pre-defined manipulators for re-use.
+ */
+
+
+#ifndef __ED_MANIPULATOR_LIBRARY_H__
+#define __ED_MANIPULATOR_LIBRARY_H__
+
+/* initialize manipulators */
+void ED_manipulatortypes_arrow_2d(void);
+void ED_manipulatortypes_arrow_3d(void);
+void ED_manipulatortypes_cage_2d(void);
+void ED_manipulatortypes_dial_3d(void);
+void ED_manipulatortypes_grab_3d(void);
+void ED_manipulatortypes_facemap_3d(void);
+void ED_manipulatortypes_primitive_3d(void);
+
+struct wmManipulator;
+struct wmManipulatorGroup;
+
+
+/* -------------------------------------------------------------------- */
+/* Shape Presets
+ *
+ * Intended to be called by custom draw functions.
+ */
+
+/* manipulator_library_presets.c */
+void ED_manipulator_draw_preset_box(
+ const struct wmManipulator *mpr, float mat[4][4], int select_id);
+void ED_manipulator_draw_preset_arrow(
+ const struct wmManipulator *mpr, float mat[4][4], int axis, int select_id);
+void ED_manipulator_draw_preset_circle(
+ const struct wmManipulator *mpr, float mat[4][4], int axis, int select_id);
+void ED_manipulator_draw_preset_facemap(
+ const struct wmManipulator *mpr, struct Scene *scene, struct Object *ob, const int facemap, int select_id);
+
+
+/* -------------------------------------------------------------------- */
+/* 3D Arrow Manipulator */
+
+enum {
+ ED_MANIPULATOR_ARROW_STYLE_NORMAL = 0,
+ ED_MANIPULATOR_ARROW_STYLE_CROSS = 1,
+ ED_MANIPULATOR_ARROW_STYLE_BOX = 2,
+ ED_MANIPULATOR_ARROW_STYLE_CONE = 3,
+};
+
+enum {
+ /* inverted offset during interaction - if set it also sets constrained below */
+ ED_MANIPULATOR_ARROW_STYLE_INVERTED = (1 << 3),
+ /* clamp arrow interaction to property width */
+ ED_MANIPULATOR_ARROW_STYLE_CONSTRAINED = (1 << 4),
+};
+
+void ED_manipulator_arrow3d_set_ui_range(struct wmManipulator *mpr, const float min, const float max);
+void ED_manipulator_arrow3d_set_range_fac(struct wmManipulator *mpr, const float range_fac);
+
+/* -------------------------------------------------------------------- */
+/* 2D Arrow Manipulator */
+
+/* none */
+
+/* -------------------------------------------------------------------- */
+/* Cage Manipulator */
+
+enum {
+ ED_MANIPULATOR_RECT_TRANSFORM_FLAG_TRANSLATE = (1 << 0), /* Manipulator translates */
+ ED_MANIPULATOR_RECT_TRANSFORM_FLAG_ROTATE = (1 << 1), /* Manipulator rotates */
+ ED_MANIPULATOR_RECT_TRANSFORM_FLAG_SCALE = (1 << 2), /* Manipulator scales */
+ ED_MANIPULATOR_RECT_TRANSFORM_FLAG_SCALE_UNIFORM = (1 << 3), /* Manipulator scales uniformly */
+};
+
+/* -------------------------------------------------------------------- */
+/* Dial Manipulator */
+
+/* draw_options */
+enum {
+ ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP = 0,
+ ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP = (1 << 0),
+ ED_MANIPULATOR_DIAL_DRAW_FLAG_FILL = (1 << 1),
+ ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_MIRROR = (1 << 2),
+ ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_START_Y = (1 << 3),
+};
+
+/* -------------------------------------------------------------------- */
+/* Grab Manipulator */
+
+/* draw_options */
+enum {
+ ED_MANIPULATOR_GRAB_DRAW_FLAG_NOP = 0,
+ ED_MANIPULATOR_GRAB_DRAW_FLAG_FILL = (1 << 0),
+};
+
+enum {
+ ED_MANIPULATOR_GRAB_STYLE_RING = 0,
+};
+
+
+/* -------------------------------------------------------------------- */
+/* Primitive Manipulator */
+
+enum {
+ ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE = 0,
+};
+
+#endif /* __ED_MANIPULATOR_LIBRARY_H__ */
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index de798b1fce2..0ee60471357 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -113,8 +113,8 @@ struct UvElementMap *BM_uv_element_map_create(
void BM_uv_element_map_free(struct UvElementMap *vmap);
struct UvElement *BM_uv_element_get(struct UvElementMap *map, struct BMFace *efa, struct BMLoop *l);
-bool EDBM_mtexpoly_check(struct BMEditMesh *em);
-struct MTexPoly *EDBM_mtexpoly_active_get(struct BMEditMesh *em, struct BMFace **r_act_efa, const bool sloppy, const bool selected);
+bool EDBM_uv_check(struct BMEditMesh *em);
+struct BMFace *EDBM_uv_active_face_get(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);
@@ -259,7 +259,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);
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index f7b9d6b4f9e..20363c69fa0 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);
@@ -107,7 +107,7 @@ void ED_node_composite_job(const struct bContext *C, struct bNodeTree *nodetree,
void ED_operatormacros_node(void);
/* node_view.c */
-bool ED_space_node_color_sample(struct Scene *scene, struct SpaceNode *snode, struct ARegion *ar, int mval[2], float r_col[3]);
+bool ED_space_node_color_sample(struct SpaceNode *snode, struct ARegion *ar, int mval[2], float r_col[3]);
#endif /* __ED_NODE_H__ */
diff --git a/source/blender/editors/include/ED_numinput.h b/source/blender/editors/include/ED_numinput.h
index f9a22429fc2..00558a3a787 100644
--- a/source/blender/editors/include/ED_numinput.h
+++ b/source/blender/editors/include/ED_numinput.h
@@ -30,6 +30,8 @@
#define NUM_STR_REP_LEN 64
#define NUM_MAX_ELEMENTS 3
+struct wmEvent;
+
typedef struct NumInput {
short idx_max; /* idx_max < NUM_MAX_ELEMENTS */
int unit_sys;
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 04ff5692717..9e5d55dd031 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -35,14 +35,17 @@
extern "C" {
#endif
-struct Base;
+struct bFaceMap;
+struct BaseLegacy;
struct EnumPropertyItem;
struct ID;
struct Main;
struct ModifierData;
struct Object;
+struct Base;
struct ReportList;
struct Scene;
+struct SceneLayer;
struct bConstraint;
struct bContext;
struct bPoseChannel;
@@ -89,7 +92,6 @@ bool ED_object_parent_set(struct ReportList *reports, struct Main *bmain, struct
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);
@@ -98,14 +100,20 @@ void ED_keymap_proportional_editmode(struct wmKeyConfig *keyconf, struct wmKeyMa
const bool do_connected);
/* send your own notifier for select! */
-void ED_base_object_select(struct Base *base, short mode);
+void ED_base_object_select(struct BaseLegacy *base, short mode);
/* includes notifier */
-void ED_base_object_activate(struct bContext *C, struct Base *base);
+void ED_base_object_activate(struct bContext *C, struct BaseLegacy *base);
+
+void ED_object_base_select(struct Base *base, short mode);
+void ED_object_base_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_base_object_free_and_unlink(struct Main *bmain, struct Scene *scene, struct Object *ob);
+
+void ED_base_object_sync_from_base(struct BaseLegacy *base, struct Object *ob);
+void ED_base_object_sync_from_object(struct BaseLegacy *base, struct Object *ob);
/* 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 SceneLayer *sl, struct Base *base, int dupflag);
void ED_object_parent(struct Object *ob, struct Object *parent, const int type, const char *substr);
@@ -191,7 +199,7 @@ void ED_object_modifier_clear(struct Main *bmain, struct Object *ob);
int ED_object_modifier_move_down(struct ReportList *reports, struct Object *ob, struct ModifierData *md);
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);
+ struct SceneLayer *sl, struct Object *ob, struct ModifierData *md);
int ED_object_modifier_apply(struct ReportList *reports, 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);
@@ -214,6 +222,10 @@ struct EnumPropertyItem *ED_object_vgroup_selection_itemf_helper(
void ED_object_check_force_modifiers(struct Main *bmain, struct Scene *scene, struct Object *object);
+/* 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_particle.h b/source/blender/editors/include/ED_particle.h
index 6cb8c0cfb19..41c746aa421 100644
--- a/source/blender/editors/include/ED_particle.h
+++ b/source/blender/editors/include/ED_particle.h
@@ -38,21 +38,22 @@ struct ParticleEditSettings;
struct rcti;
struct PTCacheEdit;
struct Scene;
+struct SceneLayer;
/* particle edit mode */
void PE_free_ptcache_edit(struct PTCacheEdit *edit);
int PE_start_edit(struct PTCacheEdit *edit);
/* access */
-struct PTCacheEdit *PE_get_current(struct Scene *scene, struct Object *ob);
+struct PTCacheEdit *PE_get_current(struct Scene *scene, struct SceneLayer *sl, struct Object *ob);
struct PTCacheEdit *PE_create_current(struct Scene *scene, struct Object *ob);
void PE_current_changed(struct Scene *scene, struct Object *ob);
-int PE_minmax(struct Scene *scene, float min[3], float max[3]);
+int PE_minmax(struct Scene *scene, struct SceneLayer *sl, 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 Scene *scene, struct Object *ob, int useflag);
+void PE_update_object(struct Scene *scene, struct SceneLayer *sl, struct Object *ob, int useflag);
/* selection tools */
int PE_mouse_particles(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
@@ -62,13 +63,13 @@ int PE_lasso_select(struct bContext *C, const int mcords[][2], const short moves
void PE_deselect_all_visible(struct PTCacheEdit *edit);
/* undo */
-void PE_undo_push(struct Scene *scene, const char *str);
-void PE_undo_step(struct Scene *scene, int step);
-void PE_undo(struct Scene *scene);
-void PE_redo(struct Scene *scene);
-bool PE_undo_is_valid(struct Scene *scene);
-void PE_undo_number(struct Scene *scene, int nr);
-const char *PE_undo_get_name(struct Scene *scene, int nr, bool *r_active);
+void PE_undo_push(struct Scene *scene, struct SceneLayer *sl, const char *str);
+void PE_undo_step(struct Scene *scene, struct SceneLayer *sl, int step);
+void PE_undo(struct Scene *scene, struct SceneLayer *sl);
+void PE_redo(struct Scene *scene, struct SceneLayer *sl);
+bool PE_undo_is_valid(struct Scene *scene, struct SceneLayer *sl);
+void PE_undo_number(struct Scene *scene, struct SceneLayer *sl, int nr);
+const char *PE_undo_get_name(struct Scene *scene, struct SceneLayer *sl, int nr, bool *r_active);
#endif /* __ED_PARTICLE_H__ */
diff --git a/source/blender/editors/include/ED_scene.h b/source/blender/editors/include/ED_scene.h
new file mode 100644
index 00000000000..6a4ebf68d3d
--- /dev/null
+++ b/source/blender/editors/include/ED_scene.h
@@ -0,0 +1,43 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_exit(struct bContext *C) ATTR_NONNULL();
+void ED_scene_changed_update(struct Main *bmain, struct bContext *C, struct Scene *scene_new,
+ const struct bScreen *active_screen) ATTR_NONNULL();
+bool ED_scene_render_layer_delete(
+ struct Main *bmain, struct Scene *scene, struct SceneLayer *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 6a558d1c185..524ee01c30f 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -36,20 +36,27 @@
#include "DNA_view2d_types.h"
#include "DNA_view3d_types.h"
+#include "BLI_compiler_attrs.h"
+
struct wmWindowManager;
struct wmWindow;
struct wmNotifier;
struct wmEvent;
struct wmKeyConfig;
+struct WorkSpace;
+struct WorkSpaceInstanceHook;
struct bContext;
struct Scene;
struct bScreen;
struct ARegion;
struct uiBlock;
struct rcti;
+struct Main;
/* regions */
-void ED_region_do_listen(struct bScreen *sc, struct ScrArea *sa, struct ARegion *ar, struct wmNotifier *note);
+void ED_region_do_listen(
+ struct bScreen *sc, struct ScrArea *sa, struct ARegion *ar,
+ struct wmNotifier *note, const Scene *scene);
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);
@@ -70,6 +77,7 @@ void ED_region_header(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_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);
@@ -84,7 +92,7 @@ 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_area_do_listen(struct bScreen *sc, ScrArea *sa, struct wmNotifier *note, const Scene *scene);
void ED_area_tag_redraw(ScrArea *sa);
void ED_area_tag_redraw_regiontype(ScrArea *sa, int type);
void ED_area_tag_refresh(ScrArea *sa);
@@ -101,12 +109,8 @@ void ED_screens_initialize(struct wmWindowManager *wm);
void ED_screen_draw(struct wmWindow *win);
void ED_screen_refresh(struct wmWindowManager *wm, struct wmWindow *win);
void ED_screen_do_listen(struct bContext *C, struct wmNotifier *note);
-bScreen *ED_screen_duplicate(struct wmWindow *win, struct bScreen *sc);
-bScreen *ED_screen_add(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);
+bool ED_screen_change(struct bContext *C, struct bScreen *sc);
+void ED_screen_update_after_scene_change(const struct bScreen *screen, struct Scene *scene_new);
void ED_screen_set_subwinactive(struct bContext *C, struct wmEvent *event);
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);
@@ -117,7 +121,43 @@ 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);
+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);
+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,
+ SceneLayer *act_render_layer) 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, struct wmWindow *win) ATTR_NONNULL();
+void ED_workspace_scene_data_sync(
+ struct WorkSpaceInstanceHook *hook, Scene *scene) ATTR_NONNULL();
+void ED_workspace_render_layer_unset(
+ const struct Main *bmain, const SceneLayer *layer_unset, SceneLayer *layer_new) ATTR_NONNULL(1, 2);
+struct WorkSpaceLayout *ED_workspace_layout_add(
+ struct WorkSpace *workspace,
+ struct wmWindow *win,
+ const char *name) ATTR_NONNULL();
+struct WorkSpaceLayout *ED_workspace_layout_duplicate(
+ 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();
/* anim */
void ED_update_for_newframe(struct Main *bmain, struct Scene *scene, int mute);
@@ -130,6 +170,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 */
int ED_operator_screenactive(struct bContext *C);
@@ -183,6 +225,7 @@ int ED_operator_uvmap(struct bContext *C);
int ED_operator_posemode_exclusive(struct bContext *C);
int ED_operator_posemode_context(struct bContext *C);
int ED_operator_posemode(struct bContext *C);
+int ED_operator_posemode_local(struct bContext *C);
int ED_operator_mask(struct bContext *C);
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index 6daaac5bb42..a81d63d9f25 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -39,8 +39,7 @@ struct rcti;
/* 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);
+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, bool extend);
#endif /* __ED_SCULPT_H__ */
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index ebd2a3dcb7a..483caf7c475 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -43,6 +43,7 @@ struct wmEvent;
struct wmKeyConfig;
struct wmKeyMap;
struct wmOperatorType;
+struct WorkSpace;
struct Main;
struct SnapObjectContext;
struct SnapObjectParams;
@@ -109,9 +110,11 @@ enum TfmMode {
bool calculateTransformCenter(struct bContext *C, int centerMode, float cent3d[3], float cent2d[2]);
struct TransInfo;
-struct Base;
+struct BaseLegacy;
struct Scene;
struct Object;
+struct wmManipulatorGroup;
+struct wmManipulatorGroupType;
struct wmOperator;
/* UNUSED */
@@ -128,7 +131,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 View3D *v3d, int orientation);
void ED_getTransformOrientationMatrix(const struct bContext *C, float orientation_mat[3][3], const short around);
@@ -152,10 +155,15 @@ int BIF_countTransformOrientation(const struct bContext *C);
void Transform_Properties(struct wmOperatorType *ot, int flags);
-/* view3d manipulators */
+/* transform manipulators */
+
+void TRANSFORM_WGT_manipulator(struct wmManipulatorGroupType *wgt);
+
+bool ED_widgetgroup_manipulator2d_poll(const struct bContext *C, struct wmManipulatorGroupType *wgt);
+void ED_widgetgroup_manipulator2d_setup(const struct bContext *C, struct wmManipulatorGroup *mgroup);
+void ED_widgetgroup_manipulator2d_refresh(const struct bContext *C, struct wmManipulatorGroup *mgroup);
+void ED_widgetgroup_manipulator2d_draw_prepare(const struct bContext *C, struct wmManipulatorGroup *mgroup);
-int BIF_do_manipulator(struct bContext *C, const struct wmEvent *event, struct wmOperator *op);
-void BIF_draw_manipulator(const struct bContext *C);
/* Snapping */
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 7944b434057..1bc22e79625 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -31,6 +31,7 @@ struct BMFace;
struct ListBase;
struct Scene;
+struct SceneLayer;
struct Main;
struct Object;
struct ARegion;
@@ -65,15 +66,11 @@ struct SnapObjectParams {
unsigned int use_object_edit_cage : 1;
};
-enum {
- SNAP_OBJECT_USE_CACHE = (1 << 0),
-};
-
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 SceneLayer *sl, 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 SceneLayer *sl, int flag,
/* extra args for view3d */
const struct ARegion *ar, const struct View3D *v3d);
void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx);
@@ -88,7 +85,6 @@ void ED_transform_snap_object_context_set_editmesh_callbacks(
bool ED_transform_snap_object_project_ray_ex(
struct SnapObjectContext *sctx,
- const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3], float *ray_depth,
/* return args */
@@ -102,7 +98,6 @@ bool ED_transform_snap_object_project_ray(
bool ED_transform_snap_object_project_ray_all(
SnapObjectContext *sctx,
- const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3],
float ray_depth, bool sort,
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index 4c54542b7b1..70075767c9a 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -54,12 +54,15 @@ void ED_OT_flush_edits(struct wmOperatorType *ot);
/* undo.c */
void ED_undo_push(struct bContext *C, const char *str);
void ED_undo_push_op(struct bContext *C, struct wmOperator *op);
+void ED_undo_grouped_push(struct bContext *C, const char *str);
+void ED_undo_grouped_push_op(struct bContext *C, struct wmOperator *op);
void ED_undo_pop_op(struct bContext *C, struct wmOperator *op);
void ED_undo_pop(struct bContext *C);
void ED_undo_redo(struct bContext *C);
void ED_OT_undo(struct wmOperatorType *ot);
void ED_OT_undo_push(struct wmOperatorType *ot);
void ED_OT_redo(struct wmOperatorType *ot);
+void ED_OT_undo_redo(struct wmOperatorType *ot);
void ED_OT_undo_history(struct wmOperatorType *ot);
int ED_undo_operator_repeat(struct bContext *C, struct wmOperator *op);
@@ -81,9 +84,6 @@ void undo_editmode_push(struct bContext *C, const char *name,
void undo_editmode_clear(void);
-/* cut-paste buffer free */
-void ED_clipboard_posebuf_free(void);
-
/* ************** XXX OLD CRUFT WARNING ************* */
void apply_keyb_grid(int shift, int ctrl, float *val, float fac1, float fac2, float fac3, int invert);
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 535683823bf..918489b1159 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -35,12 +35,13 @@ struct BMesh;
struct BMEditMesh;
struct BMFace;
struct BMLoop;
+struct Depsgraph;
struct Image;
struct ImageUser;
-struct MTexPoly;
struct Main;
struct Object;
struct Scene;
+struct SceneLayer;
struct SpaceImage;
struct bNode;
struct wmKeyConfig;
@@ -51,6 +52,7 @@ 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_object_get_active_image(struct Object *ob, int mat_nr,
@@ -60,7 +62,7 @@ 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 Image *ima, struct BMFace *efa);
bool uvedit_face_select_test(struct Scene *scene, struct BMFace *efa,
const int cd_loop_uv_offset);
bool uvedit_edge_select_test(struct Scene *scene, struct BMLoop *l,
@@ -109,7 +111,7 @@ void ED_unwrap_lscm(struct Scene *scene, struct Object *obedit, const short sel)
/* uvedit_draw.c */
void ED_image_draw_cursor(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);
+void ED_uvedit_draw_main(struct SpaceImage *sima, struct ARegion *ar, struct Scene *scene, struct SceneLayer *sl, 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 48c1e2d1996..19bb55742d5 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -37,9 +37,10 @@ struct BMEdge;
struct BMFace;
struct BMVert;
struct BPoint;
-struct Base;
+struct BaseLegacy;
struct BezTriple;
struct BoundBox;
+struct Depsgraph;
struct EditBone;
struct ImBuf;
struct MVert;
@@ -47,15 +48,16 @@ struct Main;
struct MetaElem;
struct Nurb;
struct Object;
+struct RV3DMatrixStore;
struct RegionView3D;
struct Scene;
+struct SceneLayer;
struct ScrArea;
struct View3D;
struct ViewContext;
struct bContext;
struct bPoseChannel;
struct bScreen;
-struct bglMats;
struct rctf;
struct rcti;
struct wmOperator;
@@ -69,7 +71,9 @@ enum eGPUFXFlags;
/* for derivedmesh drawing callbacks, for view3d_select, .... */
typedef struct ViewContext {
+ struct Depsgraph *depsgraph;
struct Scene *scene;
+ struct SceneLayer *scene_layer;
struct Object *obact;
struct Object *obedit;
struct ARegion *ar;
@@ -187,7 +191,7 @@ void pose_foreachScreenBone(
void ED_view3d_project_float_v2_m4(const struct ARegion *ar, const float co[3], float r_co[2], float mat[4][4]);
void ED_view3d_project_float_v3_m4(const struct ARegion *ar, const float co[3], float r_co[3], float mat[4][4]);
-eV3DProjStatus ED_view3d_project_base(const struct ARegion *ar, struct Base *base);
+eV3DProjStatus ED_view3d_project_base(const struct ARegion *ar, struct BaseLegacy *base);
/* *** short *** */
eV3DProjStatus ED_view3d_project_short_ex(const struct ARegion *ar, float perspmat[4][4], const bool is_local,
@@ -216,8 +220,14 @@ bool ED_view3d_win_to_ray_ex(
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_global_to_vector(const struct RegionView3D *rv3d, const float coord[3], float vec[3]);
-void ED_view3d_win_to_3d(const struct ARegion *ar, const float depth_pt[3], const float mval[2], float out[3]);
-void ED_view3d_win_to_3d_int(const struct ARegion *ar, const float depth_pt[3], const int mval[2], float out[3]);
+void ED_view3d_win_to_3d(
+ const struct View3D *v3d, const struct ARegion *ar,
+ const float depth_pt[3], const float mval[2],
+ float r_out[3]);
+void ED_view3d_win_to_3d_int(
+ const struct View3D *v3d, const struct ARegion *ar,
+ const float depth_pt[3], const int mval[2],
+ float r_out[3]);
void ED_view3d_win_to_delta(const struct ARegion *ar, const float mval[2], float out[3], const float zfac);
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]);
@@ -225,7 +235,9 @@ bool ED_view3d_win_to_segment(const struct ARegion *ar, struct View3D *v3d, cons
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 */
@@ -250,11 +262,13 @@ void ED_view3d_calc_camera_border_size(
const struct Scene *scene, const struct ARegion *ar,
const struct View3D *v3d, const struct RegionView3D *rv3d,
float r_size[2]);
-bool ED_view3d_calc_render_border(struct Scene *scene, struct View3D *v3d,
- struct ARegion *ar, struct rcti *rect);
+bool ED_view3d_calc_render_border(
+ const struct Scene *scene, 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);
@@ -270,7 +284,7 @@ float ED_view3d_radius_to_dist(
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(struct ViewContext *vc);
@@ -282,12 +296,12 @@ int ED_view3d_backbuf_sample_size_clamp(struct ARegion *ar, const float
unsigned int ED_view3d_backbuf_sample(struct ViewContext *vc, int x, int y);
bool ED_view3d_autodist(
- struct Scene *scene, struct ARegion *ar, struct View3D *v3d,
+ struct Depsgraph *graph, 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 Scene *scene, struct ARegion *ar, struct View3D *v3d, int mode);
+void ED_view3d_autodist_init(struct Depsgraph *graph, 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);
@@ -295,7 +309,22 @@ bool ED_view3d_autodist_depth_seg(struct ARegion *ar, const int mval_sta[2], con
/* select */
#define MAXPICKELEMS 2500
#define MAXPICKBUF (4 * MAXPICKELEMS)
-short view3d_opengl_select(struct ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const struct rcti *input, bool do_nearest);
+
+typedef enum {
+ /* all elements in the region, ignore depth */
+ VIEW3D_SELECT_ALL = 0,
+ /* pick also depth sorts (only for small regions!) */
+ VIEW3D_SELECT_PICK_ALL = 1,
+ /* sorts and only returns visible objects (only for small regions!) */
+ VIEW3D_SELECT_PICK_NEAREST = 2,
+} eV3DSelectMode;
+
+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);
/* view3d_select.c */
float ED_view3d_select_dist_px(void);
@@ -303,7 +332,6 @@ void view3d_set_viewcontext(struct bContext *C, struct ViewContext *vc);
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]);
@@ -324,31 +352,38 @@ void ED_view3d_check_mats_rv3d(struct RegionView3D *rv3d);
#endif
int ED_view3d_scene_layer_set(int lay, const int *values, int *active);
-void *ED_view3d_mats_rv3d_backup(struct RegionView3D *rv3d);
-void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, void *rv3dmat_pt);
+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 Scene *scene, struct Object *ob, const float col[4], const int facemap);
bool ED_view3d_context_activate(struct bContext *C);
-void ED_view3d_draw_offscreen_init(struct Scene *scene, struct View3D *v3d);
+void ED_view3d_draw_offscreen_init(struct Scene *scene, struct SceneLayer *sl, struct View3D *v3d);
void ED_view3d_draw_offscreen(
- struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int winx, int winy, float viewmat[4][4],
+ struct Scene *scene, struct SceneLayer *sl, 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);
+void ED_view3d_draw_setup_view(
+ struct wmWindow *win, struct Scene *scene, struct ARegion *ar, struct View3D *v3d,
+ float viewmat[4][4], float winmat[4][4], const struct rcti *rect);
struct ImBuf *ED_view3d_draw_offscreen_imbuf(
- struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int sizex, int sizey,
+ struct Scene *scene, struct SceneLayer *sl, struct View3D *v3d, struct ARegion *ar, int sizex, int sizey,
unsigned int flag, bool draw_background,
int alpha_mode, int samples, bool full_samples, const char *viewname,
struct GPUFX *fx, struct GPUOffScreen *ofs, char err_out[256]);
struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(
- struct Scene *scene, struct Object *camera, int width, int height,
+ struct Scene *scene, struct SceneLayer *sl, struct Object *camera, int width, int height,
unsigned int flag, int drawtype, bool use_solid_tex, bool use_gpencil, bool draw_background,
int alpha_mode, int samples, bool full_samples, const char *viewname,
struct GPUFX *fx, struct GPUOffScreen *ofs, char err_out[256]);
-struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
+struct BaseLegacy *ED_view3d_give_base_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, float viewmat[4][4], float winmat[4][4]);
+void ED_view3d_update_viewmat(
+ 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);
char ED_view3d_lock_view_from_index(int index);
@@ -356,7 +391,7 @@ 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);
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index 4f23dbdd94d..9d889f71051 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -313,9 +313,9 @@ 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(BLANK120)
- DEF_ICON(BLANK121)
DEF_ICON(BLANK122)
DEF_ICON(BLANK123)
DEF_ICON(BLANK124)
@@ -653,9 +653,9 @@ DEF_ICON(IPO_BACK)
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(BLANK203)
DEF_ICON(BLANK204)
DEF_ICON(BLANK205)
DEF_ICON(BLANK206)
@@ -1012,15 +1012,6 @@ DEF_ICON(MATCAP_23)
DEF_ICON(MATCAP_24)
/* vector icons, VICO_ prefix added */
-DEF_VICO(VIEW3D_VEC)
-DEF_VICO(EDIT_VEC)
-DEF_VICO(EDITMODE_VEC_DEHLT)
-DEF_VICO(EDITMODE_VEC_HLT)
-DEF_VICO(DISCLOSURE_TRI_RIGHT_VEC)
-DEF_VICO(DISCLOSURE_TRI_DOWN_VEC)
-DEF_VICO(MOVE_UP_VEC)
-DEF_VICO(MOVE_DOWN_VEC)
-DEF_VICO(X_VEC)
DEF_VICO(SMALL_TRI_RIGHT_VEC)
DEF_VICO(KEYTYPE_KEYFRAME_VEC)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 1f053c806b0..42386c7ecac 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -161,13 +161,13 @@ enum {
UI_BUT_NODE_LINK = (1 << 8),
UI_BUT_NODE_ACTIVE = (1 << 9),
UI_BUT_DRAG_LOCK = (1 << 10),
- UI_BUT_DISABLED = (1 << 11),
+ UI_BUT_DISABLED = (1 << 11), /* grayed out and uneditable */
UI_BUT_COLOR_LOCK = (1 << 12),
UI_BUT_ANIMATED = (1 << 13),
UI_BUT_ANIMATED_KEY = (1 << 14),
UI_BUT_DRIVEN = (1 << 15),
UI_BUT_REDALERT = (1 << 16),
- UI_BUT_INACTIVE = (1 << 17),
+ UI_BUT_INACTIVE = (1 << 17), /* grayed out but still editable */
UI_BUT_LAST_ACTIVE = (1 << 18),
UI_BUT_UNDO = (1 << 19),
UI_BUT_IMMEDIATE = (1 << 20),
@@ -181,7 +181,7 @@ enum {
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_SEARCH_UNLINK = (1 << 30), /* show unlink for search button */
+ UI_BUT_VALUE_CLEAR = (1 << 30), /* show 'x' icon to clear/unlink value of text or search button */
};
#define UI_PANEL_WIDTH 340
@@ -217,7 +217,6 @@ enum {
/* scale fixed button widths by this to account for DPI */
#define UI_DPI_FAC ((U.pixelsize * (float)U.dpi) / 72.0f)
-#define UI_DPI_WINDOW_FAC (((float)U.dpi) / 72.0f)
/* 16 to copy ICON_DEFAULT_HEIGHT */
#define UI_DPI_ICON_SIZE ((float)16 * UI_DPI_FAC)
@@ -256,6 +255,7 @@ 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_SCROLL = (18 << 9),
UI_BTYPE_BLOCK = (19 << 9),
UI_BTYPE_LABEL = (20 << 9),
@@ -308,18 +308,22 @@ 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_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 */
@@ -393,6 +397,8 @@ struct uiLayout *UI_popup_menu_layout(uiPopupMenu *head);
void UI_popup_menu_reports(struct bContext *C, struct ReportList *reports) ATTR_NONNULL();
int UI_popup_menu_invoke(struct bContext *C, const char *idname, struct ReportList *reports) ATTR_NONNULL(1, 2);
+void UI_popup_menu_retval_set(const uiBlock *block, const int retval, const bool enable);
+
/* Pie menus */
typedef struct uiPieMenu uiPieMenu;
@@ -419,7 +425,7 @@ typedef void (*uiBlockCancelFunc)(struct bContext *C, void *arg1);
void UI_popup_block_invoke(struct bContext *C, uiBlockCreateFunc func, void *arg);
void UI_popup_block_invoke_ex(struct bContext *C, uiBlockCreateFunc func, void *arg, const char *opname, int opcontext);
-void UI_popup_block_ex(struct bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, uiBlockCancelFunc cancel_func, void *arg);
+void UI_popup_block_ex(struct bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, uiBlockCancelFunc cancel_func, void *arg, struct wmOperator *op);
/* void uiPupBlockOperator(struct bContext *C, uiBlockCreateFunc func, struct wmOperator *op, int opcontext); */ /* UNUSED */
void UI_popup_block_close(struct bContext *C, struct wmWindow *win, uiBlock *block);
@@ -785,7 +791,6 @@ void UI_popup_handlers_remove_all(struct bContext *C, struct ListBase *handlers)
void UI_init(void);
void UI_init_userdef(void);
void UI_reinit_font(void);
-void UI_reinit_gl_state(void);
void UI_exit(void);
/* Layout
@@ -850,9 +855,6 @@ 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);
@@ -910,6 +912,17 @@ void uiTemplateIDPreview(uiLayout *layout, struct bContext *C, struct PointerRNA
const char *newop, const char *openop, const char *unlinkop, int rows, int cols);
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);
@@ -943,6 +956,11 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C);
void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C);
void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C);
void uiTemplateKeymapItemProperties(uiLayout *layout, struct PointerRNA *ptr);
+void uiTemplateOverrideProperty(
+ uiLayout *layout, struct PointerRNA *collection_props_ptr, struct PointerRNA *scene_props_ptr,
+ const char *propname,
+ const char *name, const char *text_ctxt, int translate, int icon,
+ const char *custom_template);
void uiTemplateComponentMenu(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name);
void uiTemplateNodeSocket(uiLayout *layout, struct bContext *C, float *color);
void uiTemplateCacheFile(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname);
@@ -1025,7 +1043,7 @@ bool UI_context_copy_to_selected_list(
/* Helpers for Operators */
uiBut *UI_context_active_but_get(const struct bContext *C);
-void UI_context_active_but_prop_get(
+uiBut *UI_context_active_but_prop_get(
const struct bContext *C,
struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index);
void UI_context_active_but_prop_handle(struct bContext *C);
@@ -1040,20 +1058,22 @@ void UI_context_active_but_prop_get_templateID(
/* Styled text draw */
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);
+void UI_fontstyle_draw_ex(const struct uiFontStyle *fs, const struct rcti *rect, 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 */
diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h
index 945ac1b6db9..cee68ed361c 100644
--- a/source/blender/editors/include/UI_interface_icons.h
+++ b/source/blender/editors/include/UI_interface_icons.h
@@ -66,6 +66,7 @@ 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);
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index a81221ed54b..ac657a4ac73 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -298,7 +298,10 @@ enum {
TH_V3D_CLIPPING_BORDER,
TH_METADATA_BG,
- TH_METADATA_TEXT
+ TH_METADATA_TEXT,
+
+ TH_EDGE_BEVEL,
+ TH_VERTEX_BEVEL
};
/* XXX WARNING: previous is saved in file, so do not change order! */
@@ -317,13 +320,13 @@ struct bThemeState {
void UI_ThemeColor(int colorid);
// sets the color plus alpha
-void UI_ThemeColor4(int colorid);
+void UI_ThemeColor4(int colorid);
// sets color plus offset for shade
-void UI_ThemeColorShade(int colorid, int offset);
+void UI_ThemeColorShade(int colorid, int offset);
// sets color plus offset for alpha
-void UI_ThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset);
+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);
@@ -341,14 +344,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]);
@@ -366,6 +382,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/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index c57f8d5c7a8..748849f1aa5 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../blenkernel
../../blenlib
../../blentranslation
+ ../../depsgraph
../../gpu
../../imbuf
../../makesdna
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index cbe8654ceb6..d8812b85c19 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -56,7 +56,7 @@
#include "BKE_screen.h"
#include "BKE_idprop.h"
-#include "BIF_gl.h"
+#include "GPU_matrix.h"
#include "BLF_api.h"
#include "BLT_translation.h"
@@ -499,6 +499,7 @@ static int ui_but_calc_float_precision(uiBut *but, double value)
static void ui_draw_linkline(uiLinkLine *line, int highlightActiveLines, int dashInactiveLines)
{
rcti rect;
+ float color[4] = {1.0f};
if (line->from == NULL || line->to == NULL) return;
@@ -508,15 +509,15 @@ static void ui_draw_linkline(uiLinkLine *line, int highlightActiveLines, int das
rect.ymax = BLI_rctf_cent_y(&line->to->rect);
if (dashInactiveLines)
- UI_ThemeColor(TH_GRID);
+ UI_GetThemeColor4fv(TH_GRID, color);
else if (line->flag & UI_SELECT)
- glColor3ub(100, 100, 100);
+ rgba_float_args_set_ch(color, 100, 100, 100, 255);
else if (highlightActiveLines && ((line->from->flag & UI_ACTIVE) || (line->to->flag & UI_ACTIVE)))
- UI_ThemeColor(TH_TEXT_HI);
+ UI_GetThemeColor4fv(TH_TEXT_HI, color);
else
- glColor3ub(0, 0, 0);
+ rgba_float_args_set_ch(color, 0, 0, 0, 255);
- ui_draw_link_bezier(&rect);
+ ui_draw_link_bezier(&rect, color);
}
static void ui_draw_links(uiBlock *block)
@@ -1247,7 +1248,6 @@ void UI_block_end_ex(const bContext *C, uiBlock *block, const int xy[2])
if (ot == NULL || WM_operator_poll_context((bContext *)C, ot, but->opcontext) == 0) {
but->flag |= UI_BUT_DISABLED;
- but->lock = true;
}
if (but->context)
@@ -1338,7 +1338,7 @@ static void ui_but_to_pixelrect(rcti *rect, const ARegion *ar, uiBlock *block, u
rctf rectf;
ui_block_to_window_rctf(ar, block, &rectf, (but) ? &but->rect : &block->rect);
- BLI_rcti_rctf_copy_floor(rect, &rectf);
+ BLI_rcti_rctf_copy_round(rect, &rectf);
BLI_rcti_translate(rect, -ar->winrct.xmin, -ar->winrct.ymin);
}
@@ -1377,11 +1377,9 @@ 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();
+ gpuPushProjectionMatrix();
+ gpuPushMatrix();
+ gpuLoadIdentity();
wmOrtho2_region_pixelspace(ar);
@@ -1406,10 +1404,8 @@ void UI_block_draw(const bContext *C, uiBlock *block)
}
/* restore matrix */
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
+ gpuPopProjectionMatrix();
+ gpuPopMatrix();
if (multisample_enabled)
glEnable(GL_MULTISAMPLE);
@@ -1463,6 +1459,7 @@ int ui_but_is_pushed_ex(uiBut *but, double *value)
break;
case UI_BTYPE_ROW:
case UI_BTYPE_LISTROW:
+ case UI_BTYPE_TAB:
UI_GET_BUT_VALUE_INIT(but, *value);
/* support for rna enum buts */
if (but->rnaprop && (RNA_property_flag(but->rnaprop) & PROP_ENUM_FLAG)) {
@@ -1988,22 +1985,29 @@ uiBut *ui_but_drag_multi_edit_get(uiBut *but)
/** \name Check to show extra icons
*
* Extra icons are shown on the right hand side of buttons.
+ * This could (should!) definitely become more generic, but for now this is good enough.
* \{ */
+static bool ui_but_icon_extra_is_visible_text_clear(const uiBut *but)
+{
+ BLI_assert(but->type == UI_BTYPE_TEXT);
+ return ((but->flag & UI_BUT_VALUE_CLEAR) && but->drawstr[0]);
+}
+
static bool ui_but_icon_extra_is_visible_search_unlink(const uiBut *but)
{
BLI_assert(but->type == UI_BTYPE_SEARCH_MENU);
return ((but->editstr == NULL) &&
(but->drawstr[0] != '\0') &&
- (but->flag & UI_BUT_SEARCH_UNLINK));
+ (but->flag & UI_BUT_VALUE_CLEAR));
}
-static bool ui_but_icon_extra_is_visible_eyedropper(uiBut *but)
+static bool ui_but_icon_extra_is_visible_search_eyedropper(uiBut *but)
{
StructRNA *type;
short idcode;
- BLI_assert(but->type == UI_BTYPE_SEARCH_MENU && (but->flag & UI_BUT_SEARCH_UNLINK));
+ BLI_assert(but->type == UI_BTYPE_SEARCH_MENU && (but->flag & UI_BUT_VALUE_CLEAR));
if (but->rnaprop == NULL) {
return false;
@@ -2012,21 +2016,31 @@ static bool ui_but_icon_extra_is_visible_eyedropper(uiBut *but)
type = RNA_property_pointer_type(&but->rnapoin, but->rnaprop);
idcode = RNA_type_to_ID_code(type);
-
return ((but->editstr == NULL) &&
(idcode == ID_OB || OB_DATA_SUPPORT_ID(idcode)));
}
uiButExtraIconType ui_but_icon_extra_get(uiBut *but)
{
- if ((but->flag & UI_BUT_SEARCH_UNLINK) == 0) {
- /* pass */
- }
- else if (ui_but_icon_extra_is_visible_search_unlink(but)) {
- return UI_BUT_ICONEXTRA_UNLINK;
- }
- else if (ui_but_icon_extra_is_visible_eyedropper(but)) {
- return UI_BUT_ICONEXTRA_EYEDROPPER;
+ switch (but->type) {
+ case UI_BTYPE_TEXT:
+ if (ui_but_icon_extra_is_visible_text_clear(but)) {
+ return UI_BUT_ICONEXTRA_CLEAR;
+ }
+ break;
+ case UI_BTYPE_SEARCH_MENU:
+ if ((but->flag & UI_BUT_VALUE_CLEAR) == 0) {
+ /* pass */
+ }
+ else if (ui_but_icon_extra_is_visible_search_unlink(but)) {
+ return UI_BUT_ICONEXTRA_CLEAR;
+ }
+ else if (ui_but_icon_extra_is_visible_search_eyedropper(but)) {
+ return UI_BUT_ICONEXTRA_EYEDROPPER;
+ }
+ break;
+ default:
+ break;
}
return UI_BUT_ICONEXTRA_NONE;
@@ -2272,7 +2286,7 @@ char *ui_but_string_get_dynamic(uiBut *but, int *r_str_size)
#ifdef WITH_PYTHON
-static bool ui_set_but_string_eval_num_unit(bContext *C, uiBut *but, const char *str, double *value)
+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);
@@ -2284,13 +2298,13 @@ static bool ui_set_but_string_eval_num_unit(bContext *C, uiBut *but, const char
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, str_unit_convert, value, true);
+ return BPY_execute_string_as_number(C, str_unit_convert, true, r_value);
}
#endif /* WITH_PYTHON */
-bool ui_but_string_set_eval_num(bContext *C, uiBut *but, const char *str, double *value)
+bool ui_but_string_set_eval_num(bContext *C, uiBut *but, const char *str, double *r_value)
{
bool ok = false;
@@ -2299,13 +2313,13 @@ bool ui_but_string_set_eval_num(bContext *C, uiBut *but, const char *str, double
if (str[0] != '\0') {
bool is_unit_but = (ui_but_is_float(but) && ui_but_is_unit(but));
/* only enable verbose if we won't run again with units */
- if (BPY_execute_string_as_number(C, str, value, is_unit_but == false)) {
+ if (BPY_execute_string_as_number(C, str, is_unit_but == false, r_value)) {
/* if the value parsed ok without unit conversion this button may still need a unit multiplier */
if (is_unit_but) {
char str_new[128];
- BLI_snprintf(str_new, sizeof(str_new), "%f", *value);
- ok = ui_set_but_string_eval_num_unit(C, but, str_new, value);
+ BLI_snprintf(str_new, sizeof(str_new), "%f", *r_value);
+ ok = ui_set_but_string_eval_num_unit(C, but, str_new, r_value);
}
else {
ok = true; /* parse normal string via py (no unit conversion needed) */
@@ -2313,17 +2327,16 @@ bool ui_but_string_set_eval_num(bContext *C, uiBut *but, const char *str, double
}
else if (is_unit_but) {
/* parse failed, this is a unit but so run replacements and parse again */
- ok = ui_set_but_string_eval_num_unit(C, but, str, value);
+ ok = ui_set_but_string_eval_num_unit(C, but, str, r_value);
}
}
#else /* WITH_PYTHON */
- *value = atof(str);
+ *r_value = atof(str);
ok = true;
- (void)C;
- (void)but;
+ UNUSED_VARS(C, but);
#endif /* WITH_PYTHON */
@@ -2359,7 +2372,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;
@@ -2406,8 +2419,15 @@ bool ui_but_string_set(bContext *C, uiBut *but, const char *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;
}
@@ -2613,6 +2633,10 @@ static void ui_but_free(const bContext *C, uiBut *but)
MEM_freeN(but->tip_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
@@ -2765,11 +2789,13 @@ uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, sh
block->aspect = 2.0f / fabsf(getsizex * block->winmat[0][0]);
}
else {
+ const bScreen *screen = WM_window_get_active_screen(window);
+
/* 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);
+ wm_subwindow_matrix_get(window, screen->mainwin, block->winmat);
+ wm_subwindow_size_get(window, screen->mainwin, &getsizex, &getsizey);
block->aspect = 2.0f / fabsf(getsizex * block->winmat[0][0]);
block->auto_open = true;
@@ -3122,8 +3148,7 @@ static uiBut *ui_def_but(
but->a2 = a2;
but->tip = tip;
- but->lock = block->lock;
- but->lockstr = block->lockstr;
+ but->disabled_info = block->lockstr;
but->dt = block->dt;
but->pie_dir = UI_RADIAL_NONE;
@@ -3153,7 +3178,9 @@ static uiBut *ui_def_but(
}
if (block->flag & UI_BLOCK_RADIAL) {
- but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT);
+ but->drawflag |= UI_BUT_TEXT_LEFT;
+ if (but->str && but->str[0])
+ but->drawflag |= UI_BUT_ICON_LEFT;
}
else if ((block->flag & UI_BLOCK_LOOP) ||
ELEM(but->type,
@@ -3171,10 +3198,8 @@ static uiBut *ui_def_but(
but->drawflag |= (block->flag & UI_BUT_ALIGN);
- if (but->lock == true) {
- if (but->lockstr) {
- but->flag |= UI_BUT_DISABLED;
- }
+ if (block->lock == true) {
+ but->flag |= UI_BUT_DISABLED;
}
/* keep track of UI_interface.h */
@@ -3219,11 +3244,10 @@ void ui_def_but_icon(uiBut *but, const int icon, const int flag)
}
}
-static void ui_def_but_rna__disable(uiBut *but)
+static void ui_def_but_rna__disable(uiBut *but, const char *info)
{
but->flag |= UI_BUT_DISABLED;
- but->lock = true;
- but->lockstr = "";
+ but->disabled_info = info;
}
static void ui_def_but_rna__menu(bContext *UNUSED(C), uiLayout *layout, void *but_p)
@@ -3488,8 +3512,9 @@ static uiBut *ui_def_but_rna(
but->flag |= UI_BUT_ICON_SUBMENU;
}
- if (!RNA_property_editable(&but->rnapoin, prop)) {
- ui_def_but_rna__disable(but);
+ const char *info;
+ if (but->rnapoin.data && !RNA_property_editable_info(&but->rnapoin, prop, &info)) {
+ ui_def_but_rna__disable(but, info);
}
if (but->flag & UI_BUT_UNDO && (ui_but_is_rna_undo(but) == false)) {
@@ -3520,7 +3545,7 @@ static uiBut *ui_def_but_rna_propname(uiBlock *block, int type, int retval, cons
else {
but = ui_def_but(block, type, retval, propname, x, y, width, height, NULL, min, max, a1, a2, tip);
- ui_def_but_rna__disable(but);
+ ui_def_but_rna__disable(but, "Unknown Property.");
}
return but;
@@ -3548,8 +3573,7 @@ static uiBut *ui_def_but_operator_ptr(uiBlock *block, int type, wmOperatorType *
if (!ot) {
but->flag |= UI_BUT_DISABLED;
- but->lock = true;
- but->lockstr = "";
+ but->disabled_info = "";
}
return but;
@@ -3901,6 +3925,8 @@ uiBut *uiDefIconTextButO_ptr(uiBlock *block, int type, wmOperatorType *ot, int o
uiBut *uiDefIconTextButO(uiBlock *block, int type, const char *opname, int opcontext, int icon, const char *str, int x, int y, short width, short height, const char *tip)
{
wmOperatorType *ot = WM_operatortype_find(opname, 0);
+ if (str && str[0] == '\0')
+ return uiDefIconButO_ptr(block, type, ot, opcontext, icon, x, y, width, height, tip);
return uiDefIconTextButO_ptr(block, type, ot, opcontext, icon, str, x, y, width, height, tip);
}
@@ -4386,7 +4412,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, SET_INT_IN_POINTER(item->value), 0))
+ if (false == UI_search_item_add(items, item->name, SET_INT_IN_POINTER(item->value), item->icon))
break;
}
}
@@ -4510,7 +4536,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);
@@ -4605,7 +4631,10 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
if (ptr && prop) {
if (!item) {
int i;
-
+
+ /* so the context is passed to itemf functions */
+ WM_operator_properties_sanitize(ptr, false);
+
RNA_property_enum_items_gettexted(C, ptr, prop, &items, &totitems, &free_items);
for (i = 0, item = items; i < totitems; i++, item++) {
if (item->identifier[0] && item->value == value)
diff --git a/source/blender/editors/interface/interface_align.c b/source/blender/editors/interface/interface_align.c
index 500744c366d..9aeb685a907 100644
--- a/source/blender/editors/interface/interface_align.c
+++ b/source/blender/editors/interface/interface_align.c
@@ -110,9 +110,9 @@ 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);
+ return (btype_can_align && (BLI_rctf_size_x(&but->rect) > 0.0f) && (BLI_rctf_size_y(&but->rect) > 0.0f));
}
/**
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index 88924495ae5..812f4ef0747 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -43,6 +43,8 @@
#include "BKE_global.h"
#include "BKE_nla.h"
+#include "DEG_depsgraph_build.h"
+
#include "ED_keyframing.h"
#include "UI_interface.h"
@@ -99,6 +101,10 @@ void ui_but_anim_flag(uiBut *but, float cfra)
}
}
+/**
+ * \a str can be NULL to only perform check if \a but has an expression at all.
+ * \return if button has an expression.
+ */
bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen)
{
FCurve *fcu;
@@ -111,7 +117,9 @@ bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen)
driver = fcu->driver;
if (driver && driver->type == DRIVER_TYPE_PYTHON) {
- BLI_strncpy(str, driver->expression, maxlen);
+ if (str) {
+ BLI_strncpy(str, driver->expression, maxlen);
+ }
return true;
}
}
@@ -179,7 +187,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str)
id = (ID *)but->rnapoin.id.data;
if ((id == NULL) || (GS(id->name) == ID_MA) || (GS(id->name) == ID_TE)) {
if (G.debug & G_DEBUG)
- printf("ERROR: create expression failed - invalid id-datablock for adding drivers (%p)\n", id);
+ printf("ERROR: create expression failed - invalid data-block for adding drivers (%p)\n", id);
return false;
}
@@ -204,6 +212,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str)
/* updates */
driver->flag |= DRIVER_FLAG_RECOMPILE;
+ DEG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME, NULL);
ok = true;
}
@@ -272,36 +281,6 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
}
}
-void ui_but_anim_insert_keyframe(bContext *C)
-{
- /* this operator calls UI_context_active_but_prop_get */
- WM_operator_name_call(C, "ANIM_OT_keyframe_insert_button", WM_OP_INVOKE_DEFAULT, NULL);
-}
-
-void ui_but_anim_delete_keyframe(bContext *C)
-{
- /* this operator calls UI_context_active_but_prop_get */
- WM_operator_name_call(C, "ANIM_OT_keyframe_delete_button", WM_OP_INVOKE_DEFAULT, NULL);
-}
-
-void ui_but_anim_clear_keyframe(bContext *C)
-{
- /* this operator calls UI_context_active_but_prop_get */
- WM_operator_name_call(C, "ANIM_OT_keyframe_clear_button", WM_OP_INVOKE_DEFAULT, NULL);
-}
-
-void ui_but_anim_add_driver(bContext *C)
-{
- /* this operator calls UI_context_active_but_prop_get */
- WM_operator_name_call(C, "ANIM_OT_driver_button_add", WM_OP_INVOKE_DEFAULT, NULL);
-}
-
-void ui_but_anim_remove_driver(bContext *C)
-{
- /* this operator calls UI_context_active_but_prop_get */
- WM_operator_name_call(C, "ANIM_OT_driver_button_remove", WM_OP_INVOKE_DEFAULT, NULL);
-}
-
void ui_but_anim_copy_driver(bContext *C)
{
/* this operator calls UI_context_active_but_prop_get */
@@ -313,15 +292,3 @@ 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_add_keyingset(bContext *C)
-{
- /* this operator calls UI_context_active_but_prop_get */
- WM_operator_name_call(C, "ANIM_OT_keyingset_button_add", WM_OP_INVOKE_DEFAULT, NULL);
-}
-
-void ui_but_anim_remove_keyingset(bContext *C)
-{
- /* this operator calls UI_context_active_but_prop_get */
- WM_operator_name_call(C, "ANIM_OT_keyingset_button_remove", WM_OP_INVOKE_DEFAULT, NULL);
-}
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 9ce863dc8f7..89400bd24a3 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -50,13 +50,14 @@
#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_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
#include "UI_interface.h"
@@ -71,336 +72,462 @@ 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_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])
{
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;
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
/* mult */
for (a = 0; a < 7; a++) {
mul_v2_fl(vec[a], rad);
}
- glBegin(mode);
+ unsigned int vert_ct = 0;
+ vert_ct += (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 9 : 1;
+ vert_ct += (roundboxtype & UI_CNR_TOP_RIGHT) ? 9 : 1;
+ vert_ct += (roundboxtype & UI_CNR_TOP_LEFT) ? 9 : 1;
+ vert_ct += (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 9 : 1;
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4fv(col);
+ immBegin(filled ? GWN_PRIM_TRI_FAN : GWN_PRIM_LINE_LOOP, vert_ct);
/* 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();
}
-static void round_box_shade_col(const float col1[3], float const col2[3], const float fac)
+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);
+ immAttrib4fv(attrib, col);
}
/* 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])
{
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}};
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;
-
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 4, GWN_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 ? GWN_PRIM_TRI_FAN : GWN_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();
}
+#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}};
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);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 4, GWN_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 ? GWN_PRIM_TRI_FAN : GWN_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);
- }
-
- /* set antialias line */
- glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
+ int ofs_y = 4 * U.pixelsize;
- UI_draw_roundbox_gl_mode(GL_LINE_LOOP, minx, miny, maxx, maxy, rad);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
- glDisable(GL_BLEND);
- glDisable(GL_LINE_SMOOTH);
-}
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4fv(color);
-/* (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);
+ immRecti(pos, pos_x, pos_y - ofs_y, pos_x + len, pos_y - ofs_y + (height * U.pixelsize));
+ immUnbindProgram();
}
-void UI_draw_text_underline(int pos_x, int pos_y, int len, int height)
+/* ************** SPECIAL BUTTON DRAWING FUNCTIONS ************* */
+
+/* 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));
-}
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_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(GWN_PRIM_LINE_STRIP, 25);
+
+ immAttrib3ubv(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);
+ }
+
+ immAttrib3ubv(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);
+ }
+
+ immAttrib3ubv(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)
{
@@ -411,15 +538,15 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(w
ImBuf *ibuf = (ImBuf *)but->poin;
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);
@@ -427,16 +554,15 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(w
#endif
glEnable(GL_BLEND);
- glColor4f(0.0, 0.0, 0.0, 0.0);
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);
@@ -451,43 +577,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, GWN_FETCH_FLOAT vertex attrib
+ * \param line_origin is a PRIM_FLOAT, 2, GWN_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;
-
- if (is_first) {
- UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25f, 0);
- is_first = false;
- }
+ float margin_x = safe_areas[i][0] * size_x_half;
+ float margin_y = safe_areas[i][1] * size_y_half;
- 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_line_box(pos, minx, miny, maxx, maxy);
}
}
}
@@ -501,52 +618,60 @@ static void draw_scope_end(const rctf *rect, GLint *scissor)
glBlendFunc(GL_SRC_ALPHA, GL_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)
{
+ float color[4] = {r, g, b, alpha};
+
+ /* that can happen */
+ if (res == 0)
+ return;
+
glEnable(GL_LINE_SMOOTH);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
- glColor4f(r, g, b, alpha);
+
+ immUniformColor4fv(color);
if (is_line) {
/* curve outline */
glLineWidth(1.5);
- glBegin(GL_LINE_STRIP);
+ immBegin(GWN_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(GWN_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);
+ immBegin(GWN_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);
@@ -559,7 +684,7 @@ void ui_draw_but_HISTOGRAM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol)
Histogram *hist = (Histogram *)but->poin;
int res = hist->x_resolution;
const bool is_line = (hist->flag & HISTO_FLAG_LINE) != 0;
-
+
rctf rect = {
.xmin = (float)recti->xmin + 1,
.xmax = (float)recti->xmax - 1,
@@ -573,9 +698,10 @@ void ui_draw_but_HISTOGRAM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol)
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_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];
@@ -585,34 +711,48 @@ void ui_draw_but_HISTOGRAM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol)
(rect.xmax + 1) - (rect.xmin - 1),
(rect.ymax + 1) - (rect.ymin - 1));
- glColor4f(1.f, 1.f, 1.f, 0.08f);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_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(GWN_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);
@@ -620,6 +760,25 @@ void ui_draw_but_HISTOGRAM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol)
#undef HISTOGRAM_TOT_GRID_LINES
+static void waveform_draw_one(float *waveform, int nbr, const float col[3])
+{
+ Gwn_VertFormat format = {0};
+ unsigned int pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, nbr);
+
+ GWN_vertbuf_attr_fill(vbo, pos_id, waveform);
+
+ /* TODO store the Gwn_Batch inside the scope */
+ Gwn_Batch *batch = GWN_batch_create(GWN_PRIM_POINTS, vbo, NULL);
+ Batch_set_builtin_program(batch, GPU_SHADER_2D_UNIFORM_COLOR);
+ GWN_batch_uniform_4f(batch, "color", col[0], col[1], col[2], 1.0f);
+ GWN_batch_draw(batch);
+
+ GWN_batch_discard_all(batch);
+}
+
void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *recti)
{
Scopes *scopes = (Scopes *)but->poin;
@@ -642,7 +801,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 */
@@ -660,9 +819,10 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol),
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_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);
@@ -671,94 +831,119 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol),
(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 */
+ /* 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);
}
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.08f);
+
+ /* draw grid lines here */
+ immBegin(GWN_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(GWN_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(GWN_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(GWN_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(GWN_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);
+ /* 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);
-
- 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);
+ gpuPushMatrix();
+ gpuTranslate2f(rect.xmin, yofs);
+ gpuScale2f(w, h);
+
+ waveform_draw_one(scopes->waveform_1, scopes->waveform_tot, col);
- glDisableClientState(GL_VERTEX_ARRAY);
- glPopMatrix();
+ gpuPopMatrix();
/* 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(GWN_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);
-
- glPushMatrix();
-
- glTranslatef(rect.xmin, yofs, 0.f);
- glScalef(w, h, 0.f);
+ gpuPushMatrix();
+ gpuTranslate2f(rect.xmin, yofs);
+ gpuScale2f(w, h);
- glColor3fv( colors_alpha[0] );
- glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_1);
- glDrawArrays(GL_POINTS, 0, scopes->waveform_tot);
+ 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]);
- 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();
+ gpuPopMatrix();
}
/* PARADE / YCC (3 channels) */
else if (ELEM(scopes->wavefrm_mode,
@@ -770,49 +955,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);
-
- glPushMatrix();
- glEnableClientState(GL_VERTEX_ARRAY);
-
- glTranslatef(rect.xmin, yofs, 0.f);
- glScalef(w3, h, 0.f);
+ gpuPushMatrix();
+ gpuTranslate2f(rect.xmin, yofs);
+ gpuScale2f(w3, h);
- glColor3fv((rgb) ? colors_alpha[0] : colorsycc_alpha[0]);
- glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_1);
- glDrawArrays(GL_POINTS, 0, scopes->waveform_tot);
+ waveform_draw_one(scopes->waveform_1, scopes->waveform_tot, (rgb) ? colors_alpha[0] : colorsycc_alpha[0]);
- 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);
+ gpuTranslate2f(1.0f, 0.0f);
+ waveform_draw_one(scopes->waveform_2, scopes->waveform_tot, (rgb) ? colors_alpha[1] : colorsycc_alpha[1]);
- 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);
+ gpuTranslate2f(1.0f, 0.0f);
+ waveform_draw_one(scopes->waveform_3, scopes->waveform_tot, (rgb) ? colors_alpha[2] : colorsycc_alpha[2]);
- glDisableClientState(GL_VERTEX_ARRAY);
- glPopMatrix();
+ gpuPopMatrix();
}
+
/* 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(GWN_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);
+
+ glDisable(GL_BLEND);
}
static float polar_to_x(float center, float diam, float ampli, float angle)
@@ -825,10 +1008,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);
@@ -840,41 +1023,41 @@ 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(GWN_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(GWN_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(GWN_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(GWN_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(GWN_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)
@@ -895,8 +1078,8 @@ 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;
@@ -904,9 +1087,10 @@ void ui_draw_but_VECTORSCOPE(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wco
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_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];
@@ -916,93 +1100,109 @@ void ui_draw_but_VECTORSCOPE(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wco
(rect.xmax + 1) - (rect.xmin - 1),
(rect.ymax + 1) - (rect.ymin - 1));
- glColor4f(1.f, 1.f, 1.f, 0.08f);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_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(GWN_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(GWN_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(GWN_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 */
+ float col[3] = {alpha, alpha, alpha};
+
glBlendFunc(GL_ONE, GL_ONE);
- glColor3f(alpha, alpha, alpha);
+ glPointSize(1.0);
- glPushMatrix();
- glEnableClientState(GL_VERTEX_ARRAY);
+ gpuPushMatrix();
+ gpuTranslate2f(centerx, centery);
+ gpuScaleUniform(diam);
- glTranslatef(centerx, centery, 0.f);
- glScalef(diam, diam, 0.f);
+ waveform_draw_one(scopes->vecscope, scopes->waveform_tot, col);
- glVertexPointer(2, GL_FLOAT, 0, scopes->vecscope);
- glPointSize(1.0);
- glDrawArrays(GL_POINTS, 0, scopes->waveform_tot);
-
- glDisableClientState(GL_VERTEX_ARRAY);
- glPopMatrix();
+ gpuPopMatrix();
}
+ immUnbindProgram();
+
/* outline */
draw_scope_end(&rect, scissor);
glDisable(GL_BLEND);
}
-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);
- glBegin(GL_LINE_STRIP);
- glVertex2f(x1 + halfwidth, y1);
- glVertex2f(x1, y1 + height);
- glVertex2f(x1 - halfwidth, y1);
- glEnd();
+ immBegin(GWN_PRIM_LINE_STRIP, 3);
+ immVertex2f(pos, x1 + halfwidth, y1);
+ immVertex2f(pos, x1, y1 + height);
+ immVertex2f(pos, x1 - halfwidth, y1);
+ immEnd();
glDisable(GL_LINE_SMOOTH);
}
-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 ? GWN_PRIM_TRIS : GWN_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 ? GWN_PRIM_TRI_FAN : GWN_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)
{
@@ -1021,18 +1221,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];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniform1i("num_colors", 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(GWN_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) {
@@ -1043,45 +1251,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);
- 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);
- 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;
+ unsigned int position, color;
ColorBand *coba = (ColorBand *)(but->editcoba ? but->editcoba : but->poin);
if (coba == NULL) return;
@@ -1092,20 +1301,25 @@ 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);
+ Gwn_VertFormat *format = immVertexFormat();
+ position = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_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(position, x1, y1, x1 + sizex, rect->ymax);
+ immUnbindProgram();
+
+ /* New format */
+ format = immVertexFormat();
+ position = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 4, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
/* layer: color ramp */
glEnable(GL_BLEND);
@@ -1118,7 +1332,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(GWN_PRIM_TRI_STRIP, (sizex + 1) * 2);
for (int a = 0; a <= sizex; a++) {
float pos = ((float)a) / sizex;
do_colorband(coba, pos, colf);
@@ -1127,17 +1341,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);
+ immAttrib4fv(color, colf);
+ immVertex2fv(position, v1);
+ immVertex2fv(position, 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(GWN_PRIM_TRI_STRIP, (sizex + 1) * 2);
for (int a = 0; a <= sizex; a++) {
float pos = ((float)a) / sizex;
do_colorband(coba, pos, colf);
@@ -1146,31 +1360,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);
+ immAttrib4f(color, colf[0], colf[1], colf[2], 1.0f);
+ immVertex2fv(position, v1);
+ immVertex2fv(position, v2);
}
- glEnd();
+ immEnd();
+
+ immUnbindProgram();
glDisable(GL_BLEND);
+ /* New format */
+ format = immVertexFormat();
+ position = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_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_line_box(position, 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);
+ immUniformColor4f(0.0f, 0.0f, 0.0f, 0.5f);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2f(position, x1, y1);
+ immVertex2f(position, x1 + sizex, y1);
+ immEnd();
+
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.25f);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2f(position, x1, y1 - 1);
+ immVertex2f(position, x1 + sizex, y1 - 1);
+ immEnd();
+
glDisable(GL_BLEND);
/* 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(position, rect, pos, &cbd->r, display, false);
}
}
@@ -1178,114 +1409,100 @@ 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(position, 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);
+ gpuPushMatrix();
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;
+ size = 0.5f * BLI_rcti_size_y(rect);
- glScalef(size, size, MIN2(size, 1.0f));
-
- if (displist == 0) {
- GLUquadricObj *qobj;
-
- displist = glGenLists(1);
- glNewList(displist, GL_COMPILE);
-
- qobj = gluNewQuadric();
- gluQuadricDrawStyle(qobj, GLU_FILL);
- GPU_basic_shader_bind(GPU_basic_shader_bound_options());
- gluSphere(qobj, 100.0, 32, 24);
- gluDeleteQuadric(qobj);
-
- glEndList();
- }
+ gpuTranslate2f(rect->xmin + 0.5f * BLI_rcti_size_x(rect), rect->ymin + 0.5f * BLI_rcti_size_y(rect));
+ gpuScaleUniform(size);
- glCallList(displist);
+ Gwn_Batch *sphere = Batch_get_sphere(2);
+ Batch_set_builtin_program(sphere, GPU_SHADER_SIMPLE_LIGHTING);
+ GWN_batch_uniform_4f(sphere, "color", diffuse[0], diffuse[1], diffuse[2], 1.0f);
+ GWN_batch_uniform_3fv(sphere, "light", light);
+ GWN_batch_draw(sphere);
/* restore */
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- GPU_default_lights();
glDisable(GL_CULL_FACE);
/* AA circle */
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3ubv((unsigned char *)wcol->inner);
+
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);
+ imm_draw_circle_wire(pos, 0.0f, 0.0f, 1.0f, 32);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
/* matrix after circle */
- glPopMatrix();
+ gpuPopMatrix();
+
+ 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(GWN_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)
@@ -1321,10 +1538,8 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti
float zoomy = (BLI_rcti_size_y(rect) - 2.0f) / BLI_rctf_size_y(&cumap->curr);
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 */
@@ -1337,96 +1552,105 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti
};
ui_draw_gradient(&grid, col, UI_GRAD_H, 1.0f);
+ }
+ glLineWidth(1.0f);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_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);
+ immUniformColor4ub(0, 0, 0, 48);
+ ui_draw_but_curve_grid(pos, rect, zoomx, zoomy, offsx, offsy, 0.1666666f);
glDisable(GL_BLEND);
}
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(GWN_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(GWN_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(GWN_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();
}
/* the curve */
- glColor3ubv((unsigned char *)wcol->item);
+ immUniformColor3ubv((unsigned char *)wcol->item);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
- glBegin(GL_LINE_STRIP);
+ immBegin(GWN_PRIM_LINE_STRIP, (CM_TABLE+1) + 2);
if (cuma->table == NULL)
curvemapping_changed(cumap, false);
@@ -1435,52 +1659,67 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti
/* first point */
if ((cuma->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) {
- glVertex2f(rect->xmin, rect->ymin + zoomy * (cmp[0].y - offsy));
+ immVertex2f(pos, rect->xmin, 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);
+ immVertex2f(pos, fx, fy);
}
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);
+ immVertex2f(pos, fx, fy);
}
/* last point */
if ((cuma->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) {
- glVertex2f(rect->xmax, rect->ymin + zoomy * (cmp[CM_TABLE].y - offsy));
+ immVertex2f(pos, rect->xmax, 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);
+ immVertex2f(pos, fx, fy);
}
- glEnd();
+ immEnd();
glDisable(GL_LINE_SMOOTH);
glDisable(GL_BLEND);
+ immUnbindProgram();
/* the points, use aspect to make them visible on edges */
+ format = immVertexFormat();
+ pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int col = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 4, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+
cmp = cuma->curve;
glPointSize(3.0f);
- glBegin(GL_POINTS);
+ immBegin(GWN_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);
+ immAttrib4fv(col, color);
+ immVertex2f(pos, fx, fy);
}
- glEnd();
+ immEnd();
+ immUnbindProgram();
/* restore scissortest */
glScissor(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 = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor3ubv((unsigned char *)wcol->outline);
+ imm_draw_line_box(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)
@@ -1510,9 +1749,9 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc
(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;
}
@@ -1539,62 +1778,72 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc
}
if (!ok && scopes->track_preview) {
- glPushMatrix();
+ gpuPushMatrix();
/* draw content of pattern area */
glScissor(ar->winrct.xmin + rect.xmin, ar->winrct.ymin + 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);
+ gpuTranslate2f(rect.xmin + scopes->track_pos[0], rect.ymin + scopes->track_pos[1]);
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);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int col = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 4, GWN_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(GWN_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)
+ immAttrib4fv(col, col_sel);
+ else
+ immAttrib4fv(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();
+ gpuPopMatrix();
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 */
@@ -1640,26 +1889,31 @@ void ui_draw_but_NODESOCKET(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol
BLI_rcti_size_x(&scissor_new),
BLI_rcti_size_y(&scissor_new));
- glColor4ubv(but->col);
-
float x = 0.5f * (recti->xmin + recti->xmax);
float y = 0.5f * (recti->ymin + recti->ymax);
-
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4ubv(but->col);
+
glEnable(GL_BLEND);
- glBegin(GL_POLYGON);
+ immBegin(GWN_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);
+ immUniformColor4ub(0, 0, 0, 150);
glLineWidth(1);
glEnable(GL_LINE_SMOOTH);
- glBegin(GL_LINE_LOOP);
+ immBegin(GWN_PRIM_LINE_LOOP, 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();
glDisable(GL_LINE_SMOOTH);
glDisable(GL_BLEND);
+
+ immUnbindProgram();
/* restore scissortest */
glScissor(scissor[0], scissor[1], scissor[2], scissor[3]);
@@ -1667,47 +1921,91 @@ void ui_draw_but_NODESOCKET(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol
/* ****************************************************** */
+/* 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)
{
+ /* v1-_
+ * | -_v2
+ * | |
+ * | |
+ * | |
+ * v7_______v3____v4
+ * \ | /
+ * \ | _v5
+ * v8______v6_-
+ */
+ 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);
-
+ immAttrib4ub(color, 0, 0, 0, alpha);
+ immVertex2fv(pos, v3);
+ immVertex2fv(pos, v1);
+ immAttrib4ub(color, 0, 0, 0, 0);
+ immVertex2fv(pos, v2);
+
+ immVertex2fv(pos, v2);
+ immVertex2fv(pos, v4);
+ immAttrib4ub(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);
-
+ /* immAttrib4ub(color, 0, 0, 0, alpha); */ /* Not needed, done above in previous tri */
+ immVertex2fv(pos, v3);
+ immAttrib4ub(color, 0, 0, 0, 0);
+ immVertex2fv(pos, v4);
+ immVertex2fv(pos, v5);
+
+ immVertex2fv(pos, v5);
+ immVertex2fv(pos, v6);
+ immAttrib4ub(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);
+ /* immAttrib4ub(color, 0, 0, 0, alpha); */ /* Not needed, done above in previous tri */
+ immVertex2fv(pos, v3);
+ immAttrib4ub(color, 0, 0, 0, 0);
+ immVertex2fv(pos, v6);
+ immVertex2fv(pos, v8);
+
+ immVertex2fv(pos, v8);
+ immAttrib4ub(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);
-
- glBegin(GL_QUADS);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+
+ immBegin(GWN_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);
-
- glEnd();
+ 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();
+
+ immUnbindProgram();
+
glDisable(GL_BLEND);
}
@@ -1716,8 +2014,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;
@@ -1738,29 +2036,16 @@ void ui_draw_dropshadow(const rctf *rct, float radius, float aspect, float alpha
float calpha = dalpha;
for (; i--; a -= aspect) {
/* alpha ranges from 2 to 20 or so */
- glColor4f(0.0f, 0.0f, 0.0f, calpha);
+ 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);
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);
+ 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);
glDisable(GL_LINE_SMOOTH);
glDisable(GL_BLEND);
}
-
-/**
- * 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);
-}
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index ac7b6428217..a1ba937d925 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -43,10 +43,12 @@
#include "BKE_screen.h"
#include "BKE_report.h"
#include "BKE_animsys.h"
-#include "BKE_depsgraph.h"
#include "BKE_idcode.h"
#include "BKE_unit.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
@@ -139,8 +141,8 @@ static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, c
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') ||
@@ -154,7 +156,7 @@ static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, c
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);
}
@@ -169,8 +171,8 @@ static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, c
*/
static 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);
@@ -225,7 +227,7 @@ static bool eyedropper_init(bContext *C, wmOperator *op)
return false;
}
- if (RNA_property_subtype(eye->prop) == PROP_COLOR) {
+ if (RNA_property_subtype(eye->prop) != PROP_COLOR) {
const char *display_device;
float col[4];
@@ -235,7 +237,7 @@ static bool eyedropper_init(bContext *C, wmOperator *op)
/* store inital color */
RNA_property_float_get_array(&eye->ptr, eye->prop, col);
if (eye->display) {
- IMB_colormanagement_scene_linear_to_display_v3(col, eye->display);
+ IMB_colormanagement_display_to_scene_linear_v3(col, eye->display);
}
copy_v3_v3(eye->init_col, col);
}
@@ -262,10 +264,11 @@ static void eyedropper_exit(bContext *C, wmOperator *op)
*/
static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int mx, int my, float r_col[3])
{
-
/* we could use some clever */
- 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);
if (sa) {
if (sa->spacetype == SPACE_IMAGE) {
@@ -275,7 +278,7 @@ static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int
int mval[2] = {mx - ar->winrct.xmin,
my - ar->winrct.ymin};
- if (ED_space_image_color_sample(CTX_data_scene(C), sima, ar, mval, r_col)) {
+ if (ED_space_image_color_sample(sima, ar, mval, r_col)) {
return;
}
}
@@ -287,7 +290,7 @@ static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int
int mval[2] = {mx - ar->winrct.xmin,
my - ar->winrct.ymin};
- if (ED_space_node_color_sample(CTX_data_scene(C), snode, ar, mval, r_col)) {
+ if (ED_space_node_color_sample(snode, ar, mval, r_col)) {
return;
}
}
@@ -299,7 +302,7 @@ static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int
int mval[2] = {mx - ar->winrct.xmin,
my - ar->winrct.ymin};
- if (ED_space_clip_color_sample(CTX_data_scene(C), sc, ar, mval, r_col)) {
+ if (ED_space_clip_color_sample(sc, ar, mval, r_col)) {
return;
}
}
@@ -310,6 +313,8 @@ static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int
glReadBuffer(GL_FRONT);
glReadPixels(mx, my, 1, 1, GL_RGB, GL_FLOAT, r_col);
glReadBuffer(GL_BACK);
+
+ IMB_colormanagement_display_to_scene_linear_v3(r_col, display);
}
/* sets the sample color RGB, maintaining A */
@@ -320,10 +325,10 @@ static void eyedropper_color_set(bContext *C, Eyedropper *eye, const float col[3
/* to maintain alpha */
RNA_property_float_get_array(&eye->ptr, eye->prop, col_conv);
- /* convert from display space to linear rgb space */
+ /* convert from linear rgb space to display space */
if (eye->display) {
copy_v3_v3(col_conv, col);
- IMB_colormanagement_display_to_scene_linear_v3(col_conv, eye->display);
+ IMB_colormanagement_scene_linear_to_display_v3(col_conv, eye->display);
}
else {
copy_v3_v3(col_conv, col);
@@ -448,8 +453,20 @@ static int eyedropper_exec(bContext *C, wmOperator *op)
static int eyedropper_poll(bContext *C)
{
- if (!CTX_wm_window(C)) return 0;
- else return 1;
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index_dummy;
+ uiBut *but;
+
+ /* Only color buttons */
+ if ((CTX_wm_window(C) != NULL) &&
+ (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
+ (but->type == UI_BTYPE_COLOR))
+ {
+ return 1;
+ }
+
+ return 0;
}
void UI_OT_eyedropper_color(wmOperatorType *ot)
@@ -570,8 +587,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);
@@ -585,7 +602,7 @@ static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int
const int mval[2] = {
mx - ar->winrct.xmin,
my - ar->winrct.ymin};
- Base *base;
+ BaseLegacy *base;
CTX_wm_area_set(C, sa);
CTX_wm_region_set(C, ar);
@@ -727,16 +744,35 @@ static int datadropper_exec(bContext *C, wmOperator *op)
static int datadropper_poll(bContext *C)
{
- if (!CTX_wm_window(C)) return 0;
- else return 1;
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index_dummy;
+ uiBut *but;
+
+ /* data dropper only supports object data */
+ if ((CTX_wm_window(C) != NULL) &&
+ (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
+ (but->type == UI_BTYPE_SEARCH_MENU) &&
+ (but->flag & UI_BUT_VALUE_CLEAR))
+ {
+ if (prop && RNA_property_type(prop) == PROP_POINTER) {
+ StructRNA *type = RNA_property_pointer_type(&ptr, prop);
+ const short idcode = RNA_type_to_ID_code(type);
+ if ((idcode == ID_OB) || OB_DATA_SUPPORT_ID(idcode)) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
}
void UI_OT_eyedropper_id(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Eyedropper Datablock";
+ ot->name = "Eyedropper Data-Block";
ot->idname = "UI_OT_eyedropper_id";
- ot->description = "Sample a datablock from the 3D View to store in a property";
+ ot->description = "Sample a data-block from the 3D View to store in a property";
/* api callbacks */
ot->invoke = datadropper_invoke;
@@ -851,11 +887,10 @@ 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 */
- 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;
+ 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);
UnitSettings *unit = &scene->unit;
const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0;
@@ -868,6 +903,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 *graph = CTX_data_depsgraph(C);
View3D *v3d = sa->spacedata.first;
RegionView3D *rv3d = ar->regiondata;
/* weak, we could pass in some reference point */
@@ -885,14 +921,14 @@ static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx,
view3d_operator_needs_opengl(C);
- if (ED_view3d_autodist(scene, ar, v3d, mval, co, true, NULL)) {
+ if (ED_view3d_autodist(graph, ar, v3d, mval, co, true, NULL)) {
const float mval_center_fl[2] = {
(float)ar->winx / 2,
(float)ar->winy / 2};
float co_align[3];
/* quick way to get view-center aligned point */
- ED_view3d_win_to_3d(ar, co, mval_center_fl, co_align);
+ ED_view3d_win_to_3d(v3d, ar, co, mval_center_fl, co_align);
*r_depth = len_v3v3(view_co, co_align);
@@ -1034,8 +1070,35 @@ static int depthdropper_exec(bContext *C, wmOperator *op)
static int depthdropper_poll(bContext *C)
{
- if (!CTX_wm_window(C)) return 0;
- else return 1;
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index_dummy;
+ uiBut *but;
+
+ /* check if there's an active button taking depth value */
+ if ((CTX_wm_window(C) != NULL) &&
+ (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
+ (but->type == UI_BTYPE_NUM) &&
+ (prop != NULL))
+ {
+ if ((RNA_property_type(prop) == PROP_FLOAT) &&
+ (RNA_property_subtype(prop) & PROP_UNIT_LENGTH) &&
+ (RNA_property_array_check(prop) == false))
+ {
+ return 1;
+ }
+ }
+ else {
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if (rv3d && rv3d->persp == RV3D_CAMOB) {
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->camera && v3d->camera->data && !ID_IS_LINKED_DATABLOCK(v3d->camera->data)) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
}
void UI_OT_eyedropper_depth(wmOperatorType *ot)
@@ -1084,12 +1147,11 @@ static bool driverdropper_init(bContext *C, wmOperator *op)
{
DriverDropper *ddr;
uiBut *but;
-
+
op->customdata = ddr = MEM_callocN(sizeof(DriverDropper), "DriverDropper");
-
- UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &ddr->index);
- but = UI_context_active_but_get(C);
-
+
+ but = UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &ddr->index);
+
if ((ddr->ptr.data == NULL) ||
(ddr->prop == NULL) ||
(RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
@@ -1145,8 +1207,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 79831cefde6..59064ec332e 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -50,6 +50,7 @@
#include "BLI_math.h"
#include "BLI_listbase.h"
#include "BLI_linklist.h"
+#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "BLI_string_cursor_utf8.h"
@@ -86,6 +87,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "wm_event_system.h"
#ifdef WITH_INPUT_IME
# include "wm_window.h"
@@ -184,7 +186,6 @@ typedef struct uiSelectContextStore {
uiSelectContextElem *elems;
int elems_len;
bool do_free;
- bool is_enabled;
/* When set, simply copy values (don't apply difference).
* Rules are:
* - dragging numbers uses delta.
@@ -200,7 +201,9 @@ static void ui_selectcontext_apply(
bContext *C, uiBut *but, struct uiSelectContextStore *selctx_data,
const double value, const double value_orig);
+#if 0
#define IS_ALLSELECT_EVENT(event) ((event)->alt != 0)
+#endif
/** just show a tinted color so users know its activated */
#define UI_BUT_IS_SELECT_CONTEXT UI_BUT_NODE_ACTIVE
@@ -379,6 +382,7 @@ typedef struct uiAfterFunc {
void *butm_func_arg;
int a2;
+ wmOperator *popup_op;
wmOperatorType *optype;
int opcontext;
PointerRNA *opptr;
@@ -634,13 +638,24 @@ PointerRNA *ui_handle_afterfunc_add_operator(wmOperatorType *ot, int opcontext,
return ptr;
}
+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);
+ }
+}
+
/**
* Check if a #uiAfterFunc is needed for this button.
*/
static bool ui_afterfunc_check(const uiBlock *block, const uiBut *but)
{
return (but->func || but->funcN || but->rename_func || but->optype || but->rnaprop || block->handle_func ||
- (but->type == UI_BTYPE_BUT_MENU && block->butm_func));
+ (but->type == UI_BTYPE_BUT_MENU && block->butm_func) ||
+ (block->handle && block->handle->popup_op));
}
static void ui_apply_but_func(bContext *C, uiBut *but)
@@ -681,6 +696,9 @@ static void ui_apply_but_func(bContext *C, uiBut *but)
after->butm_func_arg = block->butm_func_arg;
after->a2 = but->a2;
}
+
+ if (block->handle)
+ after->popup_op = block->handle->popup_op;
after->optype = but->optype;
after->opcontext = but->opcontext;
@@ -765,6 +783,9 @@ static void ui_apply_but_funcs_after(bContext *C)
if (after.context)
CTX_store_set(C, after.context);
+ if (after.popup_op)
+ popup_check(C, after.popup_op);
+
if (after.opptr) {
/* free in advance to avoid leak on exit */
opptr = *after.opptr;
@@ -1159,14 +1180,11 @@ static void ui_multibut_states_apply(bContext *C, uiHandleButtonData *data, uiBl
ui_but_execute_begin(C, ar, but, &active_back);
#ifdef USE_ALLSELECT
- if (data->select_others.is_enabled) {
- /* init once! */
- if (mbut_state->select_others.elems_len == 0) {
- ui_selectcontext_begin(C, but, &mbut_state->select_others);
- }
- if (mbut_state->select_others.elems_len == 0) {
- mbut_state->select_others.elems_len = -1;
- }
+ if (mbut_state->select_others.elems_len == 0) {
+ ui_selectcontext_begin(C, but, &mbut_state->select_others);
+ }
+ if (mbut_state->select_others.elems_len == 0) {
+ mbut_state->select_others.elems_len = -1;
}
/* needed so we apply the right deltas */
@@ -1266,6 +1284,10 @@ static bool ui_drag_toggle_set_xy_xy(
}
}
}
+ if (changed) {
+ /* apply now, not on release (or if handlers are cancelled for whatever reason) */
+ ui_apply_but_funcs_after(C);
+ }
return changed;
}
@@ -2050,12 +2072,7 @@ static void ui_apply_but(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
else
# endif
if (data->select_others.elems_len == 0) {
- wmWindow *win = CTX_wm_window(C);
- /* may have been enabled before activating */
- if (data->select_others.is_enabled || IS_ALLSELECT_EVENT(win->eventstate)) {
- ui_selectcontext_begin(C, but, &data->select_others);
- data->select_others.is_enabled = true;
- }
+ ui_selectcontext_begin(C, but, &data->select_others);
}
if (data->select_others.elems_len == 0) {
/* dont check again */
@@ -2096,6 +2113,7 @@ static void ui_apply_but(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
break;
case UI_BTYPE_ROW:
case UI_BTYPE_LISTROW:
+ case UI_BTYPE_TAB:
ui_apply_but_ROW(C, block, but, data);
break;
case UI_BTYPE_SCROLL:
@@ -2214,43 +2232,15 @@ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleB
/* ******************* copy and paste ******************** */
-static void ui_but_copy_data_path(uiBut *but, const bool full_path)
-{
- char *id_path;
-
- if (but->rnapoin.id.data == NULL) {
- return;
- }
-
- if (full_path) {
- if (but->rnaprop) {
- id_path = RNA_path_full_property_py_ex(&but->rnapoin, but->rnaprop, but->rnaindex, true);
- }
- else {
- id_path = RNA_path_full_struct_py(&but->rnapoin);
- }
- }
- else {
- id_path = RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop);
- }
-
- if (id_path) {
- WM_clipboard_text_set(id_path, false);
- MEM_freeN(id_path);
- }
-}
-
/* c = copy, v = paste */
-static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, char mode)
+static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, const char mode, const bool copy_array)
{
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 */
- if (mode == 'v' && but->lock == true) {
- return;
- }
+ BLI_assert((but->flag & UI_BUT_DISABLED) == 0); /* caller should check */
if (mode == 'c') {
/* disallow copying from any passwords */
@@ -2279,6 +2269,46 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
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);
+
+ if (mode == 'c') {
+ char buf_copy[UI_MAX_DRAW_STR];
+
+ 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);
+
+ 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);
+
+ 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];
+
+ 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 */
@@ -2547,6 +2577,18 @@ void ui_but_text_password_hide(char password_str[UI_MAX_PASSWORD_STR], uiBut *bu
}
}
+static void ui_but_text_clear(bContext *C, uiBut *but, uiHandleButtonData *data)
+{
+ /* most likely NULL, but let's check, and give it temp zero string */
+ if (!data->str) {
+ data->str = MEM_callocN(1, "temp str");
+ }
+ data->str[0] = 0;
+
+ ui_apply_but_TEX(C, but, data);
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+}
+
/* ************* in-button text selection/editing ************* */
@@ -2934,7 +2976,7 @@ static bool ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, const in
if (pbuf) {
if (ui_but_is_utf8(but)) {
- buf_len -= BLI_utf8_invalid_strip(pbuf, buf_len);
+ buf_len -= BLI_utf8_invalid_strip(pbuf, (size_t)buf_len);
}
ui_textedit_insert_buf(but, data, pbuf, buf_len);
@@ -3032,11 +3074,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
#ifdef USE_ALLSELECT
if (is_num_but) {
- if (IS_ALLSELECT_EVENT(win->eventstate)) {
- data->select_others.is_enabled = true;
- data->select_others.is_copy = true;
-
- }
+ data->select_others.is_copy = true;
}
#endif
@@ -3051,7 +3089,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
data->str = ui_but_string_get_dynamic(but, &data->maxlen);
}
- if (ui_but_is_float(but) && !ui_but_is_unit(but)) {
+ if (ui_but_is_float(but) && !ui_but_is_unit(but) && !ui_but_anim_expression_get(but, NULL, 0)) {
BLI_str_rstrip_float_zero(data->str, '\0');
}
@@ -3121,6 +3159,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;
@@ -3330,7 +3371,7 @@ static void ui_do_but_textedit(
if (event->type == WHEELDOWNMOUSE) {
break;
}
- /* fall-through */
+ ATTR_FALLTHROUGH;
case ENDKEY:
ui_textedit_move(but, data, STRCUR_DIR_NEXT,
event->shift != 0, STRCUR_JUMP_ALL);
@@ -3348,7 +3389,7 @@ static void ui_do_but_textedit(
if (event->type == WHEELUPMOUSE) {
break;
}
- /* fall-through */
+ ATTR_FALLTHROUGH;
case HOMEKEY:
ui_textedit_move(but, data, STRCUR_DIR_PREV,
event->shift != 0, STRCUR_JUMP_ALL);
@@ -3636,15 +3677,6 @@ static void ui_block_open_begin(bContext *C, uiBut *but, uiHandleButtonData *dat
data->menu->popup = but->block->handle->popup;
}
-#ifdef USE_ALLSELECT
- {
- wmWindow *win = CTX_wm_window(C);
- if (IS_ALLSELECT_EVENT(win->eventstate)) {
- data->select_others.is_enabled = true;
- }
- }
-#endif
-
/* this makes adjacent blocks auto open from now on */
//if (but->block->auto_open == 0) but->block->auto_open = 1;
}
@@ -3826,6 +3858,33 @@ static int ui_do_but_KEYEVT(
return WM_UI_HANDLER_CONTINUE;
}
+static int ui_do_but_TAB(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+{
+ if (data->state == BUTTON_STATE_HIGHLIGHT) {
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_RELEASE) {
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ return WM_UI_HANDLER_CONTINUE;
+ }
+ }
+
+ return WM_UI_HANDLER_CONTINUE;
+}
+
+static bool ui_but_is_mouse_over_icon_extra(const ARegion *region, uiBut *but, const int mouse_xy[2])
+{
+ int x = mouse_xy[0], y = mouse_xy[1];
+ rcti icon_rect;
+
+ BLI_assert(ui_but_icon_extra_get(but) != UI_BUT_ICONEXTRA_NONE);
+
+ ui_window_to_block(region, but->block, &x, &y);
+
+ BLI_rcti_rctf_copy(&icon_rect, &but->rect);
+ icon_rect.xmin = icon_rect.xmax - (BLI_rcti_size_y(&icon_rect));
+
+ return BLI_rcti_isect_pt(&icon_rect, x, y);
+}
+
static int ui_do_but_TEX(
bContext *C, uiBlock *block, uiBut *but,
uiHandleButtonData *data, const wmEvent *event)
@@ -3839,7 +3898,14 @@ static int ui_do_but_TEX(
/* pass */
}
else {
- button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
+ const bool has_icon_extra = ui_but_icon_extra_get(but) == UI_BUT_ICONEXTRA_CLEAR;
+
+ if (has_icon_extra && ui_but_is_mouse_over_icon_extra(data->region, but, &event->x)) {
+ ui_but_text_clear(C, but, data);
+ }
+ else {
+ button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
+ }
return WM_UI_HANDLER_BREAK;
}
}
@@ -3860,47 +3926,29 @@ static int ui_do_but_SEARCH_UNLINK(
bContext *C, uiBlock *block, uiBut *but,
uiHandleButtonData *data, const wmEvent *event)
{
- uiButExtraIconType extra_icon_type;
+ const uiButExtraIconType extra_icon_type = ui_but_icon_extra_get(but);
+ const bool has_icon_extra = (extra_icon_type != UI_BUT_ICONEXTRA_NONE);
/* unlink icon is on right */
if ((ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY)) &&
- ((extra_icon_type = ui_but_icon_extra_get(but)) != UI_BUT_ICONEXTRA_NONE))
+ (has_icon_extra == true) &&
+ (ui_but_is_mouse_over_icon_extra(data->region, but, &event->x) == true))
{
- ARegion *ar = data->region;
- rcti rect;
- int x = event->x, y = event->y;
-
- ui_window_to_block(ar, but->block, &x, &y);
-
- BLI_rcti_rctf_copy(&rect, &but->rect);
-
- rect.xmin = rect.xmax - (BLI_rcti_size_y(&rect));
- /* handle click on unlink/eyedropper icon */
- if (BLI_rcti_isect_pt(&rect, x, y)) {
- /* doing this on KM_PRESS calls eyedropper after clicking unlink icon */
- if (event->val == KM_RELEASE) {
- /* unlink */
- if (extra_icon_type == UI_BUT_ICONEXTRA_UNLINK) {
- /* most likely NULL, but let's check, and give it temp zero string */
- if (data->str == NULL) {
- data->str = MEM_callocN(1, "temp str");
- }
- data->str[0] = 0;
-
- ui_apply_but_TEX(C, but, data);
- button_activate_state(C, but, BUTTON_STATE_EXIT);
- }
- /* eyedropper */
- else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) {
- WM_operator_name_call(C, "UI_OT_eyedropper_id", WM_OP_INVOKE_DEFAULT, NULL);
- }
- else {
- BLI_assert(0);
- }
+ /* doing this on KM_PRESS calls eyedropper after clicking unlink icon */
+ if (event->val == KM_RELEASE) {
+ /* unlink */
+ if (extra_icon_type == UI_BUT_ICONEXTRA_CLEAR) {
+ ui_but_text_clear(C, but, data);
+ }
+ /* eyedropper */
+ else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) {
+ WM_operator_name_call(C, "UI_OT_eyedropper_id", WM_OP_INVOKE_DEFAULT, NULL);
+ }
+ else {
+ BLI_assert(0);
}
-
- return WM_UI_HANDLER_BREAK;
}
+ return WM_UI_HANDLER_BREAK;
}
return ui_do_but_TEX(C, block, but, data, event);
}
@@ -5166,7 +5214,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);
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Paint *paint = BKE_paint_get_active(scene, sl);
Brush *brush = BKE_paint_brush(paint);
if (brush->flag & BRUSH_USE_GRADIENT) {
@@ -5415,6 +5464,7 @@ static bool ui_numedit_but_HSVCUBE(
return changed;
}
+#ifdef WITH_INPUT_NDOF
static void ui_ndofedit_but_HSVCUBE(
uiBut *but, uiHandleButtonData *data,
const wmNDOFMotionData *ndof,
@@ -5487,6 +5537,7 @@ static void ui_ndofedit_but_HSVCUBE(
copy_v3_v3(data->vec, rgb);
ui_but_v3_set(but, data->vec);
}
+#endif /* WITH_INPUT_NDOF */
static int ui_do_but_HSVCUBE(
bContext *C, uiBlock *block, uiBut *but,
@@ -5514,6 +5565,7 @@ static int ui_do_but_HSVCUBE(
return WM_UI_HANDLER_BREAK;
}
+#ifdef WITH_INPUT_NDOF
else if (event->type == NDOF_MOTION) {
const wmNDOFMotionData *ndof = event->customdata;
const enum eSnapType snap = ui_event_to_snap(event);
@@ -5525,6 +5577,7 @@ static int ui_do_but_HSVCUBE(
return WM_UI_HANDLER_BREAK;
}
+#endif /* WITH_INPUT_NDOF */
/* XXX hardcoded keymap check.... */
else if (event->type == BACKSPACEKEY && event->val == KM_PRESS) {
if (ELEM(but->a1, UI_GRAD_V_ALT, UI_GRAD_L_ALT)) {
@@ -5680,6 +5733,7 @@ static bool ui_numedit_but_HSVCIRCLE(
return changed;
}
+#ifdef WITH_INPUT_NDOF
static void ui_ndofedit_but_HSVCIRCLE(
uiBut *but, uiHandleButtonData *data,
const wmNDOFMotionData *ndof,
@@ -5750,7 +5804,7 @@ static void ui_ndofedit_but_HSVCIRCLE(
ui_but_v3_set(but, data->vec);
}
-
+#endif /* WITH_INPUT_NDOF */
static int ui_do_but_HSVCIRCLE(
bContext *C, uiBlock *block, uiBut *but,
@@ -5778,6 +5832,7 @@ static int ui_do_but_HSVCIRCLE(
return WM_UI_HANDLER_BREAK;
}
+#ifdef WITH_INPUT_NDOF
else if (event->type == NDOF_MOTION) {
const enum eSnapType snap = ui_event_to_snap(event);
const wmNDOFMotionData *ndof = event->customdata;
@@ -5789,6 +5844,7 @@ static int ui_do_but_HSVCIRCLE(
return WM_UI_HANDLER_BREAK;
}
+#endif /* WITH_INPUT_NDOF */
/* XXX hardcoded keymap check.... */
else if (event->type == BACKSPACEKEY && event->val == KM_PRESS) {
int len;
@@ -6067,6 +6123,7 @@ static int ui_do_but_CURVE(
int mx, my, a;
bool changed = false;
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
mx = event->x;
my = event->y;
@@ -6195,7 +6252,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, sl, cumap);
}
}
@@ -6625,7 +6682,7 @@ static void remove_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
static void popup_add_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
{
uiBut *but = (uiBut *)arg1;
- UI_popup_block_ex(C, menu_add_shortcut, NULL, menu_add_shortcut_cancel, but);
+ UI_popup_block_ex(C, menu_add_shortcut, NULL, menu_add_shortcut_cancel, but, NULL);
}
/**
@@ -6634,15 +6691,22 @@ static void popup_add_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
void ui_panel_menu(bContext *C, ARegion *ar, Panel *pa)
{
bScreen *sc = CTX_wm_screen(C);
+ const bool has_panel_category = UI_panel_category_is_visible(ar);
+ const bool any_item_visible = has_panel_category;
PointerRNA ptr;
uiPopupMenu *pup;
uiLayout *layout;
+ if (!any_item_visible) {
+ return;
+ }
+
RNA_pointer_create(&sc->id, &RNA_Panel, pa, &ptr);
pup = UI_popup_menu_begin(C, IFACE_("Panel"), ICON_NONE);
layout = UI_popup_menu_layout(pup);
- if (UI_panel_category_is_visible(ar)) {
+
+ if (has_panel_category) {
char tmpstr[80];
BLI_snprintf(tmpstr, sizeof(tmpstr), "%s" UI_SEP_CHAR_S "%s", IFACE_("Pin"), IFACE_("Shift+Left Mouse"));
uiItemR(layout, &ptr, "use_pin", 0, tmpstr, ICON_NONE);
@@ -6653,15 +6717,45 @@ void ui_panel_menu(bContext *C, ARegion *ar, Panel *pa)
uiBut *but = block->buttons.last;
but->flag |= UI_BUT_HAS_SEP_CHAR;
}
-
}
UI_popup_menu_end(C, pup);
}
+static void ui_but_menu_add_path_operators(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop)
+{
+ const PropertySubType subtype = RNA_property_subtype(prop);
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_path_open", true);
+ char filepath[FILE_MAX];
+ char dir[FILE_MAXDIR];
+ char file[FILE_MAXFILE];
+ PointerRNA props_ptr;
+
+ BLI_assert(ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH));
+ UNUSED_VARS_NDEBUG(subtype);
+
+ RNA_property_string_get(ptr, prop, filepath);
+ BLI_split_dirfile(filepath, dir, file, sizeof(dir), sizeof(file));
+
+ if (file[0]) {
+ BLI_assert(subtype == PROP_FILEPATH);
+
+ props_ptr = uiItemFullO_ptr(
+ layout, ot, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Open File Externally"),
+ ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ RNA_string_set(&props_ptr, "filepath", filepath);
+ }
+
+ props_ptr = uiItemFullO_ptr(
+ layout, ot, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Open Location Externally"),
+ ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ RNA_string_set(&props_ptr, "filepath", dir);
+}
+
static bool ui_but_menu(bContext *C, uiBut *but)
{
uiPopupMenu *pup;
uiLayout *layout;
+ MenuType *mt = WM_menutype_find("WM_MT_button_context", true);
bool is_array, is_array_component;
uiStringInfo label = {BUT_GET_LABEL, NULL};
@@ -6686,11 +6780,19 @@ static bool ui_but_menu(bContext *C, uiBut *but)
if (but->rnapoin.data && but->rnaprop) {
PointerRNA *ptr = &but->rnapoin;
PropertyRNA *prop = but->rnaprop;
+ const PropertyType type = RNA_property_type(prop);
+ const PropertySubType subtype = RNA_property_subtype(prop);
bool is_anim = RNA_property_animateable(ptr, prop);
bool is_editable = RNA_property_editable(ptr, prop);
/*bool is_idprop = RNA_property_is_idprop(prop);*/ /* XXX does not work as expected, not strictly needed */
bool is_set = RNA_property_is_set(ptr, prop);
+ /* set the prop and pointer data for python access to the hovered ui element; TODO, index could be supported as well*/
+ PointerRNA temp_ptr;
+ RNA_pointer_create(NULL, &RNA_Property, but->rnaprop, &temp_ptr);
+ uiLayoutSetContextPointer(layout,"button_prop", &temp_ptr);
+ uiLayoutSetContextPointer(layout,"button_pointer", ptr);
+
/* second slower test, saved people finding keyframe items in menus when its not possible */
if (is_anim)
is_anim = RNA_property_path_from_ID_check(&but->rnapoin, but->rnaprop);
@@ -6856,6 +6958,11 @@ static bool ui_but_menu(bContext *C, uiBut *but)
ICON_NONE, "UI_OT_copy_data_path_button");
uiItemS(layout);
+
+ if (type == PROP_STRING && ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH)) {
+ ui_but_menu_add_path_operators(layout, ptr, prop);
+ uiItemS(layout);
+ }
}
/* Operator buttons */
@@ -6901,7 +7008,11 @@ static bool ui_but_menu(bContext *C, uiBut *but)
0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
UI_but_func_set(but2, popup_add_shortcut_func, but, NULL);
}
-
+
+ /* Set the operator pointer for python access */
+ if (but->opptr)
+ uiLayoutSetContextPointer(layout,"button_operator", but->opptr);
+
uiItemS(layout);
}
@@ -6922,20 +7033,17 @@ static bool ui_but_menu(bContext *C, uiBut *but)
uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Manual"),
ICON_URL, "WM_OT_doc_view_manual_ui_context");
- WM_operator_properties_create(&ptr_props, "WM_OT_doc_view");
+ ptr_props = uiItemFullO(layout, "WM_OT_doc_view",
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"),
+ ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr_props, "doc_id", buf);
- uiItemFullO(layout, "WM_OT_doc_view",
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"),
- ICON_NONE, ptr_props.data, WM_OP_EXEC_DEFAULT, 0);
/* XXX inactive option, not for public! */
#if 0
- WM_operator_properties_create(&ptr_props, "WM_OT_doc_edit");
+ ptr_props = uiItemFullO(layout, "WM_OT_doc_edit",
+ "Submit Description", ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr_props, "doc_id", buf);
RNA_string_set(&ptr_props, "doc_new", RNA_property_description(but->rnaprop));
-
- uiItemFullO(layout, "WM_OT_doc_edit",
- "Submit Description", ICON_NONE, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0);
#endif
}
}
@@ -6951,6 +7059,14 @@ static bool ui_but_menu(bContext *C, uiBut *but)
}
uiItemFullO(layout, "UI_OT_edittranslation_init", NULL, ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, 0);
+ mt = WM_menutype_find("WM_MT_button_context", false);
+ if (mt) {
+ Menu menu = {NULL};
+ menu.layout = uiLayoutColumn(layout, false);
+ menu.type = mt;
+ mt->draw(C, &menu);
+ }
+
UI_popup_menu_end(C, pup);
return true;
@@ -6967,10 +7083,16 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
if (but->flag & UI_BUT_DISABLED)
return WM_UI_HANDLER_CONTINUE;
+ /* if but->pointype is set, but->poin should be too */
+ BLI_assert(!but->pointype || but->poin);
+
+ /* Only hard-coded stuff here, button interactions with configurable
+ * 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))
+ 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) {
@@ -6980,105 +7102,13 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
data = but->active;
}
}
-
- /* special case, copy-data-path */
- if ((event->type == CKEY) && event->shift) {
- ui_but_copy_data_path(but, event->alt != 0);
- return WM_UI_HANDLER_BREAK;
- }
-
- ui_but_copy_paste(C, but, data, (event->type == CKEY) ? 'c' : 'v');
+ 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);
}
- /* handle eyedropper */
- else if ((event->type == EKEY) && (event->val == KM_PRESS)) {
- if (IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) {
- /* pass */
- }
- else {
- if (but->type == UI_BTYPE_COLOR) {
- WM_operator_name_call(C, "UI_OT_eyedropper_color", WM_OP_INVOKE_DEFAULT, NULL);
- return WM_UI_HANDLER_BREAK;
- }
- else if ((but->type == UI_BTYPE_SEARCH_MENU) &&
- (but->flag & UI_BUT_SEARCH_UNLINK))
- {
- if (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_POINTER) {
- StructRNA *type = RNA_property_pointer_type(&but->rnapoin, but->rnaprop);
- const short idcode = RNA_type_to_ID_code(type);
- if ((idcode == ID_OB) || OB_DATA_SUPPORT_ID(idcode)) {
- WM_operator_name_call(C, "UI_OT_eyedropper_id", WM_OP_INVOKE_DEFAULT, NULL);
- return WM_UI_HANDLER_BREAK;
- }
- }
- }
- else if (but->type == UI_BTYPE_NUM) {
- if (but->rnaprop &&
- (RNA_property_type(but->rnaprop) == PROP_FLOAT) &&
- (RNA_property_subtype(but->rnaprop) & PROP_UNIT_LENGTH) &&
- (RNA_property_array_check(but->rnaprop) == false))
- {
- WM_operator_name_call(C, "UI_OT_eyedropper_depth", WM_OP_INVOKE_DEFAULT, NULL);
- return WM_UI_HANDLER_BREAK;
- }
- }
- }
- }
- /* handle keyframing */
- else if ((event->type == IKEY) &&
- !IS_EVENT_MOD(event, ctrl, oskey) &&
- (event->val == KM_PRESS))
- {
- if (event->alt) {
- if (event->shift) {
- ui_but_anim_clear_keyframe(C);
- }
- else {
- ui_but_anim_delete_keyframe(C);
- }
- }
- else {
- ui_but_anim_insert_keyframe(C);
- }
-
- ED_region_tag_redraw(data->region);
-
- return WM_UI_HANDLER_BREAK;
- }
- /* handle drivers */
- else if ((event->type == DKEY) &&
- !IS_EVENT_MOD(event, shift, oskey) &&
- (event->val == KM_PRESS))
- {
- /* quick check to prevent this opening within the popup menu its self */
- if (!ELEM(NULL, but->rnapoin.data, but->rnaprop)) {
- if (event->alt)
- ui_but_anim_remove_driver(C);
- else if (event->ctrl)
- ui_but_anim_add_driver(C);
-
- ED_region_tag_redraw(data->region);
- }
- return WM_UI_HANDLER_BREAK;
- }
- /* handle keyingsets */
- else if ((event->type == KKEY) &&
- !IS_EVENT_MOD(event, shift, ctrl, oskey) &&
- (event->val == KM_PRESS))
- {
- if (event->alt)
- ui_but_anim_remove_keyingset(C);
- else
- ui_but_anim_add_keyingset(C);
-
- ED_region_tag_redraw(data->region);
-
- return WM_UI_HANDLER_BREAK;
- }
/* handle menu */
else if ((event->type == RIGHTMOUSE) &&
!IS_EVENT_MOD(event, shift, ctrl, alt, oskey) &&
@@ -7091,24 +7121,6 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
}
}
- /* verify if we can edit this button */
- if (ELEM(event->type, LEFTMOUSE, RETKEY)) {
- /* this should become disabled button .. */
- if (but->lock == true) {
- if (but->lockstr) {
- WM_report(RPT_INFO, but->lockstr);
- button_activate_state(C, but, BUTTON_STATE_EXIT);
- return WM_UI_HANDLER_BREAK;
- }
- }
- else if (but->pointype && but->poin == NULL) {
- /* there's a pointer needed */
- BKE_reportf(NULL, RPT_WARNING, "DoButton pointer error: %s", but->str);
- button_activate_state(C, but, BUTTON_STATE_EXIT);
- return WM_UI_HANDLER_BREAK;
- }
- }
-
switch (but->type) {
case UI_BTYPE_BUT:
retval = ui_do_but_BUT(C, but, data, event);
@@ -7119,6 +7131,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, but, data, event);
+ break;
case UI_BTYPE_BUT_TOGGLE:
case UI_BTYPE_TOGGLE:
case UI_BTYPE_ICON_TOGGLE:
@@ -7166,7 +7181,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
case UI_BTYPE_TEXT:
case UI_BTYPE_SEARCH_MENU:
if ((but->type == UI_BTYPE_SEARCH_MENU) &&
- (but->flag & UI_BUT_SEARCH_UNLINK))
+ (but->flag & UI_BUT_VALUE_CLEAR))
{
retval = ui_do_but_SEARCH_UNLINK(C, block, but, data, event);
if (retval & WM_UI_HANDLER_BREAK) {
@@ -7762,7 +7777,8 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
if (ui_but_is_cursor_warp(but)) {
#ifdef USE_CONT_MOUSE_CORRECT
- if (data->ungrab_mval[0] != FLT_MAX) {
+ /* stereo3d has issues with changing cursor location so rather avoid */
+ if (data->ungrab_mval[0] != FLT_MAX && !WM_stereo3d_enabled(data->window, false)) {
int mouse_ungrab_xy[2];
ui_block_to_window_fl(data->region, but->block, &data->ungrab_mval[0], &data->ungrab_mval[1]);
mouse_ungrab_xy[0] = data->ungrab_mval[0];
@@ -8088,8 +8104,13 @@ uiBut *UI_context_active_but_get(const struct bContext *C)
return ui_context_button_active(C, NULL);
}
-/* helper function for insert keyframe, reset to default, etc operators */
-void UI_context_active_but_prop_get(
+/**
+ * Version of #UI_context_active_but_get that also returns RNA property info.
+ * Helper function for insert keyframe, reset to default, etc operators.
+ *
+ * \return active button, NULL if none found or if it doesn't contain valid RNA data.
+ */
+uiBut *UI_context_active_but_prop_get(
const bContext *C,
struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index)
{
@@ -8105,6 +8126,8 @@ void UI_context_active_but_prop_get(
*r_prop = NULL;
*r_index = 0;
}
+
+ return activebut;
}
void UI_context_active_but_prop_handle(bContext *C)
@@ -8386,7 +8409,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
case MIDDLEMOUSE:
case MOUSEPAN:
UI_but_tooltip_timer_remove(C, but);
- /* fall-through */
+ ATTR_FALLTHROUGH;
default:
/* handle button type specific events */
retval = ui_do_button(C, block, but, event);
@@ -9180,23 +9203,23 @@ static int ui_handle_menu_event(
break;
case ONEKEY: case PAD1:
- act = 1;
+ act = 1; ATTR_FALLTHROUGH;
case TWOKEY: case PAD2:
- if (act == 0) act = 2;
+ if (act == 0) act = 2; ATTR_FALLTHROUGH;
case THREEKEY: case PAD3:
- if (act == 0) act = 3;
+ if (act == 0) act = 3; ATTR_FALLTHROUGH;
case FOURKEY: case PAD4:
- if (act == 0) act = 4;
+ if (act == 0) act = 4; ATTR_FALLTHROUGH;
case FIVEKEY: case PAD5:
- if (act == 0) act = 5;
+ if (act == 0) act = 5; ATTR_FALLTHROUGH;
case SIXKEY: case PAD6:
- if (act == 0) act = 6;
+ if (act == 0) act = 6; ATTR_FALLTHROUGH;
case SEVENKEY: case PAD7:
- if (act == 0) act = 7;
+ if (act == 0) act = 7; ATTR_FALLTHROUGH;
case EIGHTKEY: case PAD8:
- if (act == 0) act = 8;
+ if (act == 0) act = 8; ATTR_FALLTHROUGH;
case NINEKEY: case PAD9:
- if (act == 0) act = 9;
+ if (act == 0) act = 9; ATTR_FALLTHROUGH;
case ZEROKEY: case PAD0:
if (act == 0) act = 10;
@@ -9791,13 +9814,13 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle
case (ZEROKEY + n): case (PAD0 + n): \
{ if (num_dir == UI_RADIAL_NONE) num_dir = d; } (void)0
- CASE_NUM_TO_DIR(1, UI_RADIAL_SW);
- CASE_NUM_TO_DIR(2, UI_RADIAL_S);
- CASE_NUM_TO_DIR(3, UI_RADIAL_SE);
- CASE_NUM_TO_DIR(4, UI_RADIAL_W);
- CASE_NUM_TO_DIR(6, UI_RADIAL_E);
- CASE_NUM_TO_DIR(7, UI_RADIAL_NW);
- CASE_NUM_TO_DIR(8, UI_RADIAL_N);
+ CASE_NUM_TO_DIR(1, UI_RADIAL_SW); ATTR_FALLTHROUGH;
+ CASE_NUM_TO_DIR(2, UI_RADIAL_S); ATTR_FALLTHROUGH;
+ CASE_NUM_TO_DIR(3, UI_RADIAL_SE); ATTR_FALLTHROUGH;
+ CASE_NUM_TO_DIR(4, UI_RADIAL_W); ATTR_FALLTHROUGH;
+ CASE_NUM_TO_DIR(6, UI_RADIAL_E); ATTR_FALLTHROUGH;
+ CASE_NUM_TO_DIR(7, UI_RADIAL_NW); ATTR_FALLTHROUGH;
+ CASE_NUM_TO_DIR(8, UI_RADIAL_N); ATTR_FALLTHROUGH;
CASE_NUM_TO_DIR(9, UI_RADIAL_NE);
{
but = ui_block_pie_dir_activate(block, event, num_dir);
@@ -9914,6 +9937,17 @@ static int ui_handle_menus_recursive(
return retval;
}
+/**
+ * Allow setting menu return value from externals. E.g. WM might need to do this for exiting files correctly.
+ */
+void UI_popup_menu_retval_set(const uiBlock *block, const int retval, const bool enable)
+{
+ uiPopupBlockHandle *menu = block->handle;
+ if (menu) {
+ menu->menuretval = enable ? (menu->menuretval | retval) : (menu->menuretval & retval);
+ }
+}
+
/* *************** UI event handlers **************** */
static int ui_region_handler(bContext *C, const wmEvent *event, void *UNUSED(userdata))
@@ -10156,7 +10190,11 @@ static void ui_popup_handler_remove(bContext *C, void *userdata)
{
uiPopupBlockHandle *menu = userdata;
- if (menu->cancel_func) {
+ /* More correct would be to expect UI_RETURN_CANCEL here, but not wanting to
+ * cancel when removing handlers because of file exit is a rare exception.
+ * So instead of setting cancel flag for all menus before removing handlers,
+ * just explicitly flag menu with UI_RETURN_OK to avoid cancelling it. */
+ if ((menu->menuretval & UI_RETURN_OK) == 0 && menu->cancel_func) {
menu->cancel_func(C, menu->popup_arg);
}
@@ -10180,6 +10218,25 @@ void UI_popup_handlers_add(bContext *C, ListBase *handlers, uiPopupBlockHandle *
void UI_popup_handlers_remove(ListBase *handlers, uiPopupBlockHandle *popup)
{
+ wmEventHandler *handler;
+
+ for (handler = handlers->first; handler; handler = handler->next) {
+ if (handler->ui_handle == ui_popup_handler &&
+ handler->ui_remove == ui_popup_handler_remove &&
+ handler->ui_userdata == popup)
+ {
+ /* tag refresh parent popup */
+ if (handler->next &&
+ handler->next->ui_handle == ui_popup_handler &&
+ handler->next->ui_remove == ui_popup_handler_remove)
+ {
+ uiPopupBlockHandle *parent_popup = handler->next->ui_userdata;
+ ED_region_tag_refresh_ui(parent_popup->region);
+ }
+ break;
+ }
+ }
+
WM_event_remove_ui_handler(handlers, ui_popup_handler, ui_popup_handler_remove, popup, false);
}
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 1529e442b37..42b9e65d5ca 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -33,8 +33,8 @@
#include "MEM_guardedalloc.h"
-#include "GPU_extensions.h"
-#include "GPU_basic_shader.h"
+#include "GPU_draw.h"
+#include "GPU_immediate.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
@@ -59,7 +59,6 @@
#include "IMB_imbuf_types.h"
#include "IMB_thumbs.h"
-#include "BIF_gl.h"
#include "BIF_glutil.h"
#include "ED_datafiles.h"
@@ -213,173 +212,6 @@ static void viconutil_set_point(GLint pt[2], int x, int y)
pt[1] = y;
}
-static void viconutil_draw_tri(GLint(*pts)[2])
-{
- glBegin(GL_TRIANGLES);
- glVertex2iv(pts[0]);
- glVertex2iv(pts[1]);
- glVertex2iv(pts[2]);
- glEnd();
-}
-
-static void viconutil_draw_lineloop(GLint(*pts)[2], int numPoints)
-{
- int i;
-
- glBegin(GL_LINE_LOOP);
- for (i = 0; i < numPoints; i++) {
- glVertex2iv(pts[i]);
- }
- glEnd();
-}
-
-static void viconutil_draw_lineloop_smooth(GLint(*pts)[2], int numPoints)
-{
- glEnable(GL_LINE_SMOOTH);
- viconutil_draw_lineloop(pts, numPoints);
- glDisable(GL_LINE_SMOOTH);
-}
-
-static void viconutil_draw_points(GLint(*pts)[2], int numPoints, int pointSize)
-{
- int i;
-
- glBegin(GL_QUADS);
- for (i = 0; i < numPoints; i++) {
- int x = pts[i][0], y = pts[i][1];
-
- glVertex2i(x - pointSize, y - pointSize);
- glVertex2i(x + pointSize, y - pointSize);
- glVertex2i(x + pointSize, y + pointSize);
- glVertex2i(x - pointSize, y + pointSize);
- }
- glEnd();
-}
-
-/* Drawing functions */
-
-static void vicon_x_draw(int x, int y, int w, int h, float alpha)
-{
- x += 3;
- y += 3;
- w -= 6;
- h -= 6;
-
- glEnable(GL_LINE_SMOOTH);
-
- glLineWidth(2.5);
-
- glColor4f(0.0, 0.0, 0.0, alpha);
- glBegin(GL_LINES);
- glVertex2i(x, y);
- glVertex2i(x + w, y + h);
- glVertex2i(x + w, y);
- glVertex2i(x, y + h);
- glEnd();
-
- glDisable(GL_LINE_SMOOTH);
-}
-
-static void vicon_view3d_draw(int x, int y, int w, int h, float alpha)
-{
- int cx = x + w / 2;
- int cy = y + h / 2;
- int d = MAX2(2, h / 3);
-
- glColor4f(0.5, 0.5, 0.5, alpha);
- glBegin(GL_LINES);
- glVertex2i(x, cy - d);
- glVertex2i(x + w, cy - d);
- glVertex2i(x, cy + d);
- glVertex2i(x + w, cy + d);
-
- glVertex2i(cx - d, y);
- glVertex2i(cx - d, y + h);
- glVertex2i(cx + d, y);
- glVertex2i(cx + d, y + h);
- glEnd();
-
- glColor4f(0.0, 0.0, 0.0, alpha);
- glBegin(GL_LINES);
- glVertex2i(x, cy);
- glVertex2i(x + w, cy);
- glVertex2i(cx, y);
- glVertex2i(cx, y + h);
- glEnd();
-}
-
-static void vicon_edit_draw(int x, int y, int w, int h, float alpha)
-{
- GLint pts[4][2];
-
- viconutil_set_point(pts[0], x + 3, y + 3);
- viconutil_set_point(pts[1], x + w - 3, y + 3);
- viconutil_set_point(pts[2], x + w - 3, y + h - 3);
- viconutil_set_point(pts[3], x + 3, y + h - 3);
-
- glColor4f(0.0, 0.0, 0.0, alpha);
- viconutil_draw_lineloop(pts, 4);
-
- glColor3f(1, 1, 0.0);
- viconutil_draw_points(pts, 4, 1);
-}
-
-static void vicon_editmode_hlt_draw(int x, int y, int w, int h, float alpha)
-{
- GLint pts[3][2];
-
- viconutil_set_point(pts[0], x + w / 2, y + h - 2);
- viconutil_set_point(pts[1], x + 3, y + 4);
- viconutil_set_point(pts[2], x + w - 3, y + 4);
-
- glColor4f(0.5, 0.5, 0.5, alpha);
- viconutil_draw_tri(pts);
-
- glColor4f(0.0, 0.0, 0.0, 1);
- viconutil_draw_lineloop_smooth(pts, 3);
-
- glColor3f(1, 1, 0.0);
- viconutil_draw_points(pts, 3, 1);
-}
-
-static void vicon_editmode_dehlt_draw(int x, int y, int w, int h, float UNUSED(alpha))
-{
- GLint pts[3][2];
-
- viconutil_set_point(pts[0], x + w / 2, y + h - 2);
- viconutil_set_point(pts[1], x + 3, y + 4);
- viconutil_set_point(pts[2], x + w - 3, y + 4);
-
- glColor4f(0.0f, 0.0f, 0.0f, 1);
- viconutil_draw_lineloop_smooth(pts, 3);
-
- glColor3f(0.9f, 0.9f, 0.9f);
- viconutil_draw_points(pts, 3, 1);
-}
-
-static void vicon_disclosure_tri_right_draw(int x, int y, int w, int UNUSED(h), float alpha)
-{
- GLint pts[3][2];
- int cx = x + w / 2;
- int cy = y + w / 2;
- int d = w / 3, d2 = w / 5;
-
- viconutil_set_point(pts[0], cx - d2, cy + d);
- viconutil_set_point(pts[1], cx - d2, cy - d);
- viconutil_set_point(pts[2], cx + d2, cy);
-
- glBegin(GL_TRIANGLES);
- glColor4f(0.8f, 0.8f, 0.8f, alpha);
- glVertex2iv(pts[0]);
- glVertex2iv(pts[1]);
- glColor4f(0.3f, 0.3f, 0.3f, alpha);
- glVertex2iv(pts[2]);
- glEnd();
-
- glColor4f(0.0f, 0.0f, 0.0f, 1);
- viconutil_draw_lineloop_smooth(pts, 3);
-}
-
static void vicon_small_tri_right_draw(int x, int y, int w, int UNUSED(h), float alpha)
{
GLint pts[3][2];
@@ -391,70 +223,17 @@ 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);
-
- glBegin(GL_TRIANGLES);
- glVertex2iv(pts[0]);
- glVertex2iv(pts[1]);
- glVertex2iv(pts[2]);
- glEnd();
-}
-
-static void vicon_disclosure_tri_down_draw(int x, int y, int w, int UNUSED(h), float alpha)
-{
- GLint pts[3][2];
- int cx = x + w / 2;
- int cy = y + w / 2;
- int d = w / 3, d2 = w / 5;
-
- viconutil_set_point(pts[0], cx + d, cy + d2);
- viconutil_set_point(pts[1], cx - d, cy + d2);
- viconutil_set_point(pts[2], cx, cy - d2);
-
- glBegin(GL_TRIANGLES);
- glColor4f(0.8f, 0.8f, 0.8f, alpha);
- glVertex2iv(pts[0]);
- glVertex2iv(pts[1]);
- glColor4f(0.3f, 0.3f, 0.3f, alpha);
- glVertex2iv(pts[2]);
- glEnd();
-
- glColor4f(0.0f, 0.0f, 0.0f, 1);
- viconutil_draw_lineloop_smooth(pts, 3);
-}
-
-static void vicon_move_up_draw(int x, int y, int w, int h, float UNUSED(alpha))
-{
- int d = -2;
-
- glEnable(GL_LINE_SMOOTH);
- glLineWidth(1);
- glColor3f(0.0, 0.0, 0.0);
-
- glBegin(GL_LINE_STRIP);
- glVertex2i(x + w / 2 - d * 2, y + h / 2 + d);
- glVertex2i(x + w / 2, y + h / 2 - d + 1);
- glVertex2i(x + w / 2 + d * 2, y + h / 2 + d);
- glEnd();
-
- glDisable(GL_LINE_SMOOTH);
-}
-
-static void vicon_move_down_draw(int x, int y, int w, int h, float UNUSED(alpha))
-{
- int d = 2;
-
- glEnable(GL_LINE_SMOOTH);
- glLineWidth(1);
- glColor3f(0.0, 0.0, 0.0);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4f(0.2f, 0.2f, 0.2f, alpha);
- glBegin(GL_LINE_STRIP);
- glVertex2i(x + w / 2 - d * 2, y + h / 2 + d);
- glVertex2i(x + w / 2, y + h / 2 - d - 1);
- glVertex2i(x + w / 2 + d * 2, y + h / 2 + d);
- glEnd();
+ immBegin(GWN_PRIM_TRIS, 3);
+ immVertex2iv(pos, pts[0]);
+ immVertex2iv(pos, pts[1]);
+ immVertex2iv(pos, pts[2]);
+ immEnd();
- glDisable(GL_LINE_SMOOTH);
+ immUnbindProgram();
}
static void vicon_keytype_draw_wrapper(int x, int y, int w, int h, float alpha, short key_type)
@@ -463,7 +242,6 @@ static void vicon_keytype_draw_wrapper(int x, int y, int w, int h, float alpha,
* (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);
@@ -472,16 +250,30 @@ 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;
-
+ int xco = x + w / 2;
+ int yco = y + h / 2;
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos_id = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int size_id = GWN_vertformat_attr_add(format, "size", GWN_COMP_F32, 1, GWN_FETCH_FLOAT);
+ unsigned int color_id = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ unsigned int outline_color_id = GWN_vertformat_attr_add(format, "outlineColor", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND);
+ GPU_enable_program_point_size();
+ immBegin(GWN_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!)
+ * - size: 0.6 * h (found out experimentally... dunno why!)
* - sel: true (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);
-
+ draw_keyframe_shape(xco, yco, 0.6f * h, true, key_type, KEYFRAME_SHAPE_BOTH, alpha,
+ pos_id, size_id, color_id, outline_color_id);
+
+ immEnd();
+ GPU_disable_program_point_size();
+ immUnbindProgram();
+
UI_Theme_Restore(&theme_state);
}
@@ -514,7 +306,7 @@ static void vicon_colorset_draw(int index, int x, int y, int w, int h, float UNU
{
bTheme *btheme = UI_GetTheme();
ThemeWireColor *cs = &btheme->tarm[index];
-
+
/* Draw three bands of color: One per color
* x-----a-----b-----c
* | N | S | A |
@@ -523,19 +315,24 @@ static void vicon_colorset_draw(int index, int x, int y, int w, int h, float UNU
const int a = x + w / 3;
const int b = x + w / 3 * 2;
const int c = x + w;
-
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_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) \
@@ -735,8 +532,12 @@ static void init_internal_icons(void)
icongltex.id = 0;
}
+#if 0 /* should be a compile-time check (if needed at all) */
/* we only use a texture for cards with non-power of two */
if (GPU_full_non_power_of_two_support()) {
+#else
+ {
+#endif
glGenTextures(1, &icongltex.id);
if (icongltex.id) {
@@ -764,11 +565,6 @@ static void init_internal_icons(void)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
-
- if (glGetError() == GL_OUT_OF_MEMORY) {
- glDeleteTextures(1, &icongltex.id);
- icongltex.id = 0;
- }
}
}
}
@@ -789,15 +585,6 @@ static void init_internal_icons(void)
}
}
- def_internal_vicon(VICO_VIEW3D_VEC, vicon_view3d_draw);
- def_internal_vicon(VICO_EDIT_VEC, vicon_edit_draw);
- def_internal_vicon(VICO_EDITMODE_VEC_DEHLT, vicon_editmode_dehlt_draw);
- def_internal_vicon(VICO_EDITMODE_VEC_HLT, vicon_editmode_hlt_draw);
- def_internal_vicon(VICO_DISCLOSURE_TRI_RIGHT_VEC, vicon_disclosure_tri_right_draw);
- def_internal_vicon(VICO_DISCLOSURE_TRI_DOWN_VEC, vicon_disclosure_tri_down_draw);
- def_internal_vicon(VICO_MOVE_UP_VEC, vicon_move_up_draw);
- def_internal_vicon(VICO_MOVE_DOWN_VEC, vicon_move_down_draw);
- def_internal_vicon(VICO_X_VEC, vicon_x_draw);
def_internal_vicon(VICO_SMALL_TRI_RIGHT_VEC, vicon_small_tri_right_draw);
def_internal_vicon(VICO_KEYTYPE_KEYFRAME_VEC, vicon_keytype_keyframe_draw);
@@ -1091,12 +878,15 @@ void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool bi
{
ID *id = (icon->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->use_deferred) {
- ui_id_preview_image_render_size(C, NULL, id, prv, size, true);
+ if (id || (prv->tag & PRV_TAG_DEFFERED) != 0) {
+ ui_id_preview_image_render_size(C, NULL, id, prv, size, use_jobs);
}
}
break;
@@ -1176,7 +966,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 bool UNUSED(is_preview))
{
ImBuf *ima = NULL;
int draw_w = w;
@@ -1190,15 +980,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 */
@@ -1224,31 +1012,12 @@ static void icon_draw_rect(float x, float y, int w, int h, float UNUSED(aspect),
}
/* draw */
- if (is_preview) {
- glaDrawPixelsSafe(draw_x, draw_y, draw_w, draw_h, draw_w, GL_RGBA, GL_UNSIGNED_BYTE, rect);
- }
- 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);
-
- GPU_BASIC_SHADER_ENABLE_AND_RESTORE(bound_options);
- }
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
+ 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);
-
- /* restore color */
- if (alpha != 0.0f)
- glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
-
- if (rgb) {
- glPixelTransferf(GL_RED_SCALE, 1.0f);
- glPixelTransferf(GL_GREEN_SCALE, 1.0f);
- glPixelTransferf(GL_BLUE_SCALE, 1.0f);
- }
}
static void icon_draw_texture(
@@ -1257,38 +1026,39 @@ static void icon_draw_texture(
{
float x1, x2, y1, y2;
- if (rgb) glColor4f(rgb[0], rgb[1], rgb[2], alpha);
- else glColor4f(alpha, alpha, alpha, alpha);
-
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);
glBindTexture(GL_TEXTURE_2D, icongltex.id);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int texCoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
- /* sharper downscaling, has no effect when scale matches with a mip level */
- glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, -0.5f);
+ immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR);
+ if (rgb) immUniformColor3fvAlpha(rgb, alpha);
+ else immUniformColor4f(alpha, alpha, alpha, alpha);
- glBegin(GL_QUADS);
- glTexCoord2f(x1, y1);
- glVertex2f(x, y);
+ immUniform1i("image", 0);
- glTexCoord2f(x2, y1);
- glVertex2f(x + w, y);
+ immBegin(GWN_PRIM_TRI_STRIP, 4);
+ immAttrib2f(texCoord, x1, y2);
+ immVertex2f(pos, x, y + h);
- glTexCoord2f(x2, y2);
- glVertex2f(x + w, y + h);
+ immAttrib2f(texCoord, x1, y1);
+ immVertex2f(pos, x, y);
- glTexCoord2f(x1, y2);
- glVertex2f(x, y + h);
- glEnd();
+ immAttrib2f(texCoord, x2, y2);
+ immVertex2f(pos, x + w, y + h);
- glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, 0.0f);
+ immAttrib2f(texCoord, x2, y1);
+ immVertex2f(pos, x + w, y);
+ immEnd();
+
+ immUnbindProgram();
glBindTexture(GL_TEXTURE_2D, 0);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
/* Drawing size for preview images */
@@ -1402,7 +1172,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;
@@ -1414,7 +1184,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;
}
}
@@ -1427,7 +1197,7 @@ 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 {
Object *ob = CTX_data_active_object(C);
@@ -1480,6 +1250,15 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id)
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;
@@ -1498,6 +1277,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;
}
@@ -1590,6 +1372,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_RADIO;
case ID_SCE:
return ICON_SCENE_DATA;
case ID_SPK:
@@ -1634,6 +1418,11 @@ 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);
}
+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);
+}
+
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);
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 8336efa381b..ace3bb5b4f8 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -72,6 +72,7 @@ typedef enum {
UI_WTYPE_NUMBER,
UI_WTYPE_SLIDER,
UI_WTYPE_EXEC,
+ UI_WTYPE_TAB,
UI_WTYPE_TOOLTIP,
/* strings */
@@ -127,7 +128,7 @@ enum {
* (e.g. 'x' icon in search menu) - used with ui_but_icon_extra_get */
typedef enum uiButExtraIconType {
UI_BUT_ICONEXTRA_NONE = 1,
- UI_BUT_ICONEXTRA_UNLINK,
+ UI_BUT_ICONEXTRA_CLEAR,
UI_BUT_ICONEXTRA_EYEDROPPER,
} uiButExtraIconType;
@@ -258,6 +259,7 @@ struct uiBut {
uiButSearchCreateFunc search_create_func;
uiButSearchFunc search_func;
+ bool free_search_arg;
void *search_arg;
uiButHandleRenameFunc rename_func;
@@ -271,13 +273,13 @@ struct uiBut {
uiButToolTipFunc tip_func;
void *tip_argN;
- const char *lockstr;
+ /* info on why button is disabled, displayed in tooltip */
+ const char *disabled_info;
BIFIconID icon;
- bool lock;
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;
@@ -556,6 +558,7 @@ struct uiPopupBlockHandle {
struct uiKeyNavLock keynav_state;
/* for operator popups */
+ struct wmOperator *popup_op;
struct wmOperatorType *optype;
ScrArea *ctx_area;
ARegion *ctx_region;
@@ -639,6 +642,8 @@ extern void ui_draw_dropshadow(const rctf *rct, float radius, float aspect, floa
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);
@@ -681,15 +686,16 @@ 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);
+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_roundbox(int mode, float minx, float miny, float maxx, float maxy,
+ float rad, bool use_alpha, const float color[4]);
void ui_draw_menu_back(struct uiStyle *style, uiBlock *block, rcti *rect);
void ui_draw_pie_center(uiBlock *block);
uiWidgetColors *ui_tooltip_get_theme(void);
void ui_draw_tooltip_background(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);
+void ui_draw_link_bezier(const rcti *rect, const float color[4]);
extern void ui_draw_but(const struct bContext *C, ARegion *ar, struct uiStyle *style, uiBut *but, rcti *rect);
/* theme color init */
@@ -729,15 +735,8 @@ void ui_block_align_calc(uiBlock *block);
/* interface_anim.c */
void ui_but_anim_flag(uiBut *but, float cfra);
-void ui_but_anim_insert_keyframe(struct bContext *C);
-void ui_but_anim_delete_keyframe(struct bContext *C);
-void ui_but_anim_clear_keyframe(struct bContext *C);
-void ui_but_anim_add_driver(struct bContext *C);
-void ui_but_anim_remove_driver(struct bContext *C);
void ui_but_anim_copy_driver(struct bContext *C);
void ui_but_anim_paste_driver(struct bContext *C);
-void ui_but_anim_add_keyingset(struct bContext *C);
-void ui_but_anim_remove_keyingset(struct bContext *C);
bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen);
bool ui_but_anim_expression_set(uiBut *but, const char *str);
bool ui_but_anim_expression_create(uiBut *but, const char *str);
@@ -750,4 +749,20 @@ void UI_OT_eyedropper_id(struct wmOperatorType *ot);
void UI_OT_eyedropper_depth(struct wmOperatorType *ot);
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 e802cf82b8e..0b7f4b00c2d 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -125,6 +125,11 @@ typedef struct uiItem {
int flag;
} uiItem;
+enum {
+ UI_ITEM_FIXED = 1 << 0,
+ UI_ITEM_MIN = 1 << 1,
+};
+
typedef struct uiButtonItem {
uiItem item;
uiBut *but;
@@ -184,11 +189,8 @@ static const char *ui_item_name_add_colon(const char *name, char namestr[UI_MAX_
return name;
}
-static int ui_item_fit(int item, int pos, int all, int available, bool is_last, int alignment, int *offset)
+static int ui_item_fit(int item, int pos, int all, int available, bool is_last, int alignment, float *extra_pixel)
{
- if (offset)
- *offset = 0;
-
/* available == 0 is unlimited */
if (available == 0)
return item;
@@ -197,16 +199,22 @@ static int ui_item_fit(int item, int pos, int all, int available, bool is_last,
/* contents is bigger than available space */
if (is_last)
return available - pos;
- else
- return (item * available) / all;
+ else {
+ float width = *extra_pixel + (item * available) / (float)all;
+ *extra_pixel = width - (int)width;
+ return (int)width;
+ }
}
else {
/* contents is smaller or equal to available space */
if (alignment == UI_LAYOUT_ALIGN_EXPAND) {
if (is_last)
return available - pos;
- else
- return (item * available) / all;
+ else {
+ float width = *extra_pixel + (item * available) / (float)all;
+ *extra_pixel = width - (int)width;
+ return (int)width;
+ }
}
else
return item;
@@ -235,6 +243,7 @@ static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, bool
variable = (ui_layout_vary_direction(layout) == UI_ITEM_VARY_X);
if (variable) {
+ 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)
* but taking margins into account its fine */
@@ -299,6 +308,26 @@ static void ui_item_position(uiItem *item, int x, int y, int w, int h)
}
}
+static void ui_item_move(uiItem *item, int delta_xmin, int delta_xmax)
+{
+ if (item->type == ITEM_BUTTON) {
+ uiButtonItem *bitem = (uiButtonItem *)item;
+
+ bitem->but->rect.xmin += delta_xmin;
+ bitem->but->rect.xmax += delta_xmax;
+
+ ui_but_update(bitem->but); /* for strlen */
+ }
+ else {
+ uiLayout *litem = (uiLayout *)item;
+
+ if (delta_xmin > 0)
+ litem->x += delta_xmin;
+ else
+ litem->w += delta_xmax;
+ }
+}
+
/******************** Special RNA Items *********************/
static int ui_layout_local_dir(uiLayout *layout)
@@ -573,8 +602,16 @@ static void ui_item_enum_expand(
/* we dont want nested rows, cols in menus */
if (radial) {
- layout_radial = uiLayoutRadial(layout);
- UI_block_layout_set_current(block, layout_radial);
+ if (layout->root->layout == layout) {
+ layout_radial = uiLayoutRadial(layout);
+ UI_block_layout_set_current(block, layout_radial);
+ }
+ else {
+ if (layout->item.type == ITEM_LAYOUT_RADIAL) {
+ layout_radial = layout;
+ }
+ UI_block_layout_set_current(block, layout);
+ }
}
else if (layout->root->type != UI_LAYOUT_MENU) {
UI_block_layout_set_current(block, ui_item_local_sublayout(layout, layout, 1));
@@ -585,8 +622,9 @@ static void ui_item_enum_expand(
for (item = item_array; item->identifier; item++) {
if (!item->identifier[0]) {
- if (radial)
+ if (radial && layout_radial) {
uiItemS(layout_radial);
+ }
continue;
}
@@ -745,8 +783,7 @@ static void ui_item_disabled(uiLayout *layout, const char *name)
but = uiDefBut(block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
but->flag |= UI_BUT_DISABLED;
- but->lock = true;
- but->lockstr = "";
+ but->disabled_info = "";
}
/* operator items */
@@ -1234,8 +1271,16 @@ static void ui_item_rna_size(
}
}
- if (!w)
- w = ui_text_icon_width(layout, name, icon, 0);
+ if (!w) {
+ if (type == PROP_ENUM && icon_only) {
+ w = ui_text_icon_width(layout, "", ICON_BLANK1, 0);
+ if (index != RNA_ENUM_VALUE)
+ w += 0.6f * UI_UNIT_X;
+ }
+ else {
+ w = ui_text_icon_width(layout, name, icon, 0);
+ }
+ }
h = UI_UNIT_Y;
/* increase height for arrays */
@@ -1253,7 +1298,7 @@ static void ui_item_rna_size(
else if (ui_layout_vary_direction(layout) == UI_ITEM_VARY_X) {
if (type == PROP_BOOLEAN && name[0])
w += UI_UNIT_X / 5;
- else if (type == PROP_ENUM)
+ else if (type == PROP_ENUM && !icon_only)
w += UI_UNIT_X / 4;
else if (type == PROP_FLOAT || type == PROP_INT)
w += UI_UNIT_X * 3;
@@ -1455,8 +1500,9 @@ void uiItemEnumR_string(uiLayout *layout, struct PointerRNA *ptr, const char *pr
for (a = 0; item[a].identifier; a++) {
if (item[a].value == ivalue) {
const char *item_name = name ? name : CTX_IFACE_(RNA_property_translation_context(prop), item[a].name);
+ const int flag = item_name[0] ? 0 : UI_ITEM_R_ICON_ONLY;
- uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, ivalue, 0, item_name, icon ? icon : item[a].icon);
+ uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, ivalue, flag, item_name, icon ? icon : item[a].icon);
break;
}
}
@@ -1528,95 +1574,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, SET_INT_IN_POINTER(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)
{
StructRNA *srna;
@@ -1657,22 +1614,33 @@ 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;
but->rnasearchprop = searchprop;
but->drawflag |= UI_BUT_ICON_LEFT | UI_BUT_TEXT_LEFT;
if (RNA_property_is_unlink(prop)) {
- but->flag |= UI_BUT_SEARCH_UNLINK;
+ 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;
}
}
@@ -2051,6 +2019,7 @@ static void ui_litem_estimate_row(uiLayout *litem)
{
uiItem *item;
int itemw, itemh;
+ bool min_size_flag = true;
litem->w = 0;
litem->h = 0;
@@ -2058,12 +2027,18 @@ static void ui_litem_estimate_row(uiLayout *litem)
for (item = litem->items.first; item; item = item->next) {
ui_item_size(item, &itemw, &itemh);
+ min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN);
+
litem->w += itemw;
litem->h = MAX2(itemh, litem->h);
if (item->next)
litem->w += litem->space;
}
+
+ if (min_size_flag) {
+ litem->item.flag |= UI_ITEM_MIN;
+ }
}
static int ui_litem_min_width(int itemw)
@@ -2073,9 +2048,10 @@ static int ui_litem_min_width(int itemw)
static void ui_litem_layout_row(uiLayout *litem)
{
- uiItem *item;
+ uiItem *item, *last_free_item = NULL;
int x, y, w, tot, totw, neww, newtotw, itemw, minw, itemh, offset;
int fixedw, freew, fixedx, freex, flag = 0, lastw = 0;
+ float extra_pixel;
/* x = litem->x; */ /* UNUSED */
y = litem->y;
@@ -2102,31 +2078,45 @@ static void ui_litem_layout_row(uiLayout *litem)
x = 0;
flag = 0;
newtotw = totw;
+ extra_pixel = 0.0f;
for (item = litem->items.first; item; item = item->next) {
- if (item->flag)
+ if (item->flag & UI_ITEM_FIXED)
continue;
ui_item_size(item, &itemw, &itemh);
minw = ui_litem_min_width(itemw);
if (w - lastw > 0)
- neww = ui_item_fit(itemw, x, totw, w - lastw, !item->next, litem->alignment, NULL);
+ neww = ui_item_fit(itemw, x, totw, w - lastw, !item->next, litem->alignment, &extra_pixel);
else
neww = 0; /* no space left, all will need clamping to minimum size */
x += neww;
- if ((neww < minw || itemw == minw) && w != 0) {
+ bool min_flag = item->flag & UI_ITEM_MIN;
+ /* ignore min flag for rows with right or center alignment */
+ if (item->type != ITEM_BUTTON &&
+ ELEM(((uiLayout *)item)->alignment, UI_LAYOUT_ALIGN_RIGHT, UI_LAYOUT_ALIGN_CENTER) &&
+ litem->alignment == UI_LAYOUT_ALIGN_EXPAND &&
+ ((uiItem *)litem)->flag & UI_ITEM_MIN)
+ {
+ min_flag = false;
+ }
+
+ if ((neww < minw || min_flag) && w != 0) {
/* fixed size */
- item->flag = 1;
+ item->flag |= UI_ITEM_FIXED;
+ if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_MIN) {
+ minw = itemw;
+ }
fixedw += minw;
flag = 1;
newtotw -= itemw;
}
else {
/* keep free size */
- item->flag = 0;
+ item->flag &= ~UI_ITEM_FIXED;
freew += itemw;
}
}
@@ -2137,21 +2127,26 @@ static void ui_litem_layout_row(uiLayout *litem)
freex = 0;
fixedx = 0;
+ extra_pixel = 0.0f;
x = litem->x;
for (item = litem->items.first; item; item = item->next) {
ui_item_size(item, &itemw, &itemh);
minw = ui_litem_min_width(itemw);
- if (item->flag) {
+ if (item->flag & UI_ITEM_FIXED) {
/* fixed minimum size items */
- itemw = ui_item_fit(minw, fixedx, fixedw, min_ii(w, fixedw), !item->next, litem->alignment, NULL);
+ if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_MIN) {
+ minw = itemw;
+ }
+ itemw = ui_item_fit(minw, fixedx, fixedw, min_ii(w, fixedw), !item->next, litem->alignment, &extra_pixel);
fixedx += itemw;
}
else {
/* free size item */
- itemw = ui_item_fit(itemw, freex, freew, w - fixedw, !item->next, litem->alignment, NULL);
+ itemw = ui_item_fit(itemw, freex, freew, w - fixedw, !item->next, litem->alignment, &extra_pixel);
freex += itemw;
+ last_free_item = item;
}
/* align right/center */
@@ -2173,6 +2168,17 @@ static void ui_litem_layout_row(uiLayout *litem)
x += litem->space;
}
+ /* add extra pixel */
+ uiItem *last_item = litem->items.last;
+ extra_pixel = litem->w - (x - litem->x);
+ if (extra_pixel > 0 && litem->alignment == UI_LAYOUT_ALIGN_EXPAND &&
+ last_free_item && last_item && last_item->flag & UI_ITEM_FIXED)
+ {
+ ui_item_move(last_free_item, 0, extra_pixel);
+ for (item = last_free_item->next; item; item = item->next)
+ ui_item_move(item, extra_pixel, extra_pixel);
+ }
+
litem->w = x - litem->x;
litem->h = litem->y - y;
litem->x = x;
@@ -2180,10 +2186,11 @@ static void ui_litem_layout_row(uiLayout *litem)
}
/* single-column layout */
-static void ui_litem_estimate_column(uiLayout *litem)
+static void ui_litem_estimate_column(uiLayout *litem, bool is_box)
{
uiItem *item;
int itemw, itemh;
+ bool min_size_flag = true;
litem->w = 0;
litem->h = 0;
@@ -2191,15 +2198,21 @@ static void ui_litem_estimate_column(uiLayout *litem)
for (item = litem->items.first; item; item = item->next) {
ui_item_size(item, &itemw, &itemh);
+ min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN);
+
litem->w = MAX2(litem->w, itemw);
litem->h += itemh;
- if (item->next)
+ if (item->next && (!is_box || item != litem->items.first))
litem->h += litem->space;
}
+
+ if (min_size_flag) {
+ litem->item.flag |= UI_ITEM_MIN;
+ }
}
-static void ui_litem_layout_column(uiLayout *litem)
+static void ui_litem_layout_column(uiLayout *litem, bool is_box)
{
uiItem *item;
int itemh, x, y;
@@ -2213,7 +2226,7 @@ static void ui_litem_layout_column(uiLayout *litem)
y -= itemh;
ui_item_position(item, x, y, litem->w, itemh);
- if (item->next)
+ if (item->next && (!is_box || item != litem->items.first))
y -= litem->space;
}
@@ -2305,8 +2318,10 @@ static void ui_litem_layout_radial(uiLayout *litem)
/* add a little bit more here to include number */
bitem->but->rect.xmax += 1.5f * UI_UNIT_X;
/* enable drawing as pie item if supported by widget */
- if (ui_item_is_radial_drawable(bitem))
+ if (ui_item_is_radial_drawable(bitem)) {
bitem->but->dt = UI_EMBOSS_RADIAL;
+ bitem->but->drawflag |= UI_BUT_ICON_LEFT;
+ }
}
ui_item_size(item, &itemw, &itemh);
@@ -2355,7 +2370,7 @@ static void ui_litem_layout_root(uiLayout *litem)
else if (litem->root->type == UI_LAYOUT_PIEMENU)
ui_litem_layout_root_radial(litem);
else
- ui_litem_layout_column(litem);
+ ui_litem_layout_column(litem, false);
}
/* box layout */
@@ -2363,9 +2378,10 @@ static void ui_litem_estimate_box(uiLayout *litem)
{
uiStyle *style = litem->root->style;
- ui_litem_estimate_column(litem);
+ ui_litem_estimate_column(litem, true);
+ litem->item.flag &= ~UI_ITEM_MIN;
litem->w += 2 * style->boxspace;
- litem->h += style->boxspace;
+ litem->h += 2 * style->boxspace;
}
static void ui_litem_layout_box(uiLayout *litem)
@@ -2379,17 +2395,18 @@ static void ui_litem_layout_box(uiLayout *litem)
h = litem->h;
litem->x += style->boxspace;
+ litem->y -= style->boxspace;
if (w != 0) litem->w -= 2 * style->boxspace;
if (h != 0) litem->h -= 2 * style->boxspace;
- ui_litem_layout_column(litem);
+ ui_litem_layout_column(litem, true);
litem->x -= style->boxspace;
litem->y -= style->boxspace;
if (w != 0) litem->w += 2 * style->boxspace;
- if (h != 0) litem->h += style->boxspace;
+ if (h != 0) litem->h += 2 * style->boxspace;
/* roundbox around the sublayout */
but = box->roundbox;
@@ -2470,7 +2487,7 @@ static void ui_litem_layout_column_flow(uiLayout *litem)
uiLayoutItemFlow *flow = (uiLayoutItemFlow *)litem;
uiItem *item;
int col, x, y, w, emh, emy, miny, itemw, itemh;
- int toth, totitem, offset;
+ int toth, totitem;
/* compute max needed width and total height */
toth = 0;
@@ -2492,22 +2509,27 @@ static void ui_litem_layout_column_flow(uiLayout *litem)
/* create column per column */
col = 0;
+ w = (litem->w - (flow->totcol - 1) * style->columnspace) / flow->totcol;
for (item = litem->items.first; item; item = item->next) {
- ui_item_size(item, NULL, &itemh);
- itemw = ui_item_fit(1, x - litem->x, flow->totcol, w, col == flow->totcol - 1, litem->alignment, &offset);
-
+ ui_item_size(item, &itemw, &itemh);
+
+ itemw = (litem->alignment == UI_LAYOUT_ALIGN_EXPAND) ? w : min_ii(w, itemw);
+
y -= itemh;
emy -= itemh;
- ui_item_position(item, x + offset, y, itemw, itemh);
+ ui_item_position(item, x, y, itemw, itemh);
y -= style->buttonspacey;
miny = min_ii(miny, y);
/* decide to go to next one */
if (col < flow->totcol - 1 && emy <= -emh) {
- x += itemw + style->columnspace;
+ x += w + style->columnspace;
y = litem->y;
emy = 0; /* need to reset height again for next column */
col++;
+
+ /* (< remaining width > - < space between remaining columns >) / <remamining columns > */
+ w = ((litem->w - (x - litem->x)) - (flow->totcol - col - 1) * style->columnspace) / (flow->totcol - col);
}
}
@@ -2604,13 +2626,14 @@ static void ui_litem_layout_absolute(uiLayout *litem)
static void ui_litem_estimate_split(uiLayout *litem)
{
ui_litem_estimate_row(litem);
+ litem->item.flag &= ~UI_ITEM_MIN;
}
static void ui_litem_layout_split(uiLayout *litem)
{
uiLayoutItemSplit *split = (uiLayoutItemSplit *)litem;
uiItem *item;
- float percentage;
+ float percentage, extra_pixel = 0.0f;
const int tot = BLI_listbase_count(&litem->items);
int itemh, x, y, w, colw = 0;
@@ -2633,7 +2656,9 @@ static void ui_litem_layout_split(uiLayout *litem)
x += colw;
if (item->next) {
- colw = (w - (int)(w * percentage)) / (tot - 1);
+ const float width = extra_pixel + (w - (int)(w * percentage)) / ((float)tot - 1);
+ extra_pixel = width - (int)width;
+ colw = (int)width;
colw = MAX2(colw, 0);
x += litem->space;
@@ -3034,7 +3059,7 @@ static void ui_item_estimate(uiItem *item)
switch (litem->item.type) {
case ITEM_LAYOUT_COLUMN:
- ui_litem_estimate_column(litem);
+ ui_litem_estimate_column(litem, false);
break;
case ITEM_LAYOUT_COLUMN_FLOW:
ui_litem_estimate_column_flow(litem);
@@ -3089,9 +3114,9 @@ static void ui_item_align(uiLayout *litem, short nr)
}
else if (item->type == ITEM_LAYOUT_BOX) {
box = (uiLayoutItemBx *)item;
- box->roundbox->alignnr = nr;
- BLI_remlink(&litem->root->block->buttons, box->roundbox);
- BLI_addhead(&litem->root->block->buttons, box->roundbox);
+ if (!box->roundbox->alignnr) {
+ box->roundbox->alignnr = nr;
+ }
}
else if (((uiLayout *)item)->align) {
ui_item_align((uiLayout *)item, nr);
@@ -3133,7 +3158,7 @@ static void ui_item_layout(uiItem *item)
switch (litem->item.type) {
case ITEM_LAYOUT_COLUMN:
- ui_litem_layout_column(litem);
+ ui_litem_layout_column(litem, false);
break;
case ITEM_LAYOUT_COLUMN_FLOW:
ui_litem_layout_column_flow(litem);
@@ -3276,6 +3301,14 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but)
bitem = MEM_callocN(sizeof(uiButtonItem), "uiButtonItem");
bitem->item.type = ITEM_BUTTON;
bitem->but = but;
+
+ int w, h;
+ ui_item_size((uiItem *)bitem, &w, &h);
+ /* XXX uiBut hasn't scaled yet
+ * we can flag the button as not expandable, depending on its size */
+ if (w <= 2 * UI_UNIT_X)
+ bitem->item.flag |= UI_ITEM_MIN;
+
BLI_addtail(&layout->items, bitem);
if (layout->context) {
@@ -3469,14 +3502,13 @@ void uiLayoutOperatorButs(
row = uiLayoutRow(layout, true);
uiItemM(row, (bContext *)C, "WM_MT_operator_presets", NULL, ICON_NONE);
- WM_operator_properties_create(&op_ptr, "WM_OT_operator_preset_add");
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_operator_preset_add", false);
+ op_ptr = uiItemFullO_ptr(row, ot, "", ICON_ZOOMIN, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&op_ptr, "operator", op->type->idname);
- uiItemFullO(row, "WM_OT_operator_preset_add", "", ICON_ZOOMIN, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
- WM_operator_properties_create(&op_ptr, "WM_OT_operator_preset_add");
+ op_ptr = uiItemFullO_ptr(row, ot, "", ICON_ZOOMOUT, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&op_ptr, "operator", op->type->idname);
RNA_boolean_set(&op_ptr, "remove_active", true);
- uiItemFullO(row, "WM_OT_operator_preset_add", "", ICON_ZOOMOUT, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
}
if (op->type->ui) {
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 1af6d902b18..e47088d020e 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -42,14 +42,19 @@
#include "BLT_lang.h"
#include "BKE_context.h"
+#include "BKE_idprop.h"
+#include "BKE_layer.h"
#include "BKE_screen.h"
#include "BKE_global.h"
#include "BKE_node.h"
#include "BKE_text.h" /* for UI_OT_reports_to_text */
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_types.h"
#include "UI_interface.h"
@@ -113,19 +118,33 @@ static int copy_data_path_button_poll(bContext *C)
return 0;
}
-static int copy_data_path_button_exec(bContext *C, wmOperator *UNUSED(op))
+static int copy_data_path_button_exec(bContext *C, wmOperator *op)
{
PointerRNA ptr;
PropertyRNA *prop;
char *path;
int index;
+ const bool full_path = RNA_boolean_get(op->ptr, "full_path");
+
/* try to create driver using property retrieved from UI */
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
- if (ptr.id.data && ptr.data && prop) {
- path = RNA_path_from_ID_to_property(&ptr, prop);
-
+ if (ptr.id.data != NULL) {
+
+ if (full_path) {
+
+ if (prop) {
+ path = RNA_path_full_property_py_ex(&ptr, prop, index, true);
+ }
+ else {
+ path = RNA_path_full_struct_py(&ptr);
+ }
+ }
+ else {
+ path = RNA_path_from_ID_to_property(&ptr, prop);
+ }
+
if (path) {
WM_clipboard_text_set(path, false);
MEM_freeN(path);
@@ -138,6 +157,8 @@ static int copy_data_path_button_exec(bContext *C, wmOperator *UNUSED(op))
static void UI_OT_copy_data_path_button(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Copy Data Path";
ot->idname = "UI_OT_copy_data_path_button";
@@ -149,6 +170,10 @@ static void UI_OT_copy_data_path_button(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER;
+
+ /* properties */
+ prop = RNA_def_boolean(ot->srna, "full_path", false, "full_path", "Copy full data path");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
static int copy_python_command_button_poll(bContext *C)
@@ -308,6 +333,125 @@ static void UI_OT_unset_property_button(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO;
}
+/* Use/Unuse Property Button Operator ------------------------ */
+
+static int use_property_button_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ PointerRNA ptr, scene_props_ptr;
+ PropertyRNA *prop;
+ IDProperty *props;
+
+ uiBut *but = UI_context_active_but_get(C);
+
+ prop = but->rnaprop;
+ ptr = but->rnapoin;
+ props = (IDProperty *)ptr.data;
+ /* XXX Using existing data struct to pass another RNAPointer */
+ scene_props_ptr = but->rnasearchpoin;
+
+ const char *identifier = RNA_property_identifier(prop);
+ if (IDP_GetPropertyFromGroup(props, identifier)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ int array_len = RNA_property_array_length(&scene_props_ptr, prop);
+ bool is_array = array_len != 0;
+
+ switch (RNA_property_type(prop)) {
+ case PROP_FLOAT:
+ {
+ if (is_array) {
+ float values[RNA_MAX_ARRAY_LENGTH];
+ RNA_property_float_get_array(&scene_props_ptr, prop, values);
+ BKE_collection_engine_property_add_float_array(props, identifier, values, array_len);
+ }
+ else {
+ float value = RNA_property_float_get(&scene_props_ptr, prop);
+ BKE_collection_engine_property_add_float(props, identifier, value);
+ }
+ break;
+ }
+ case PROP_ENUM:
+ {
+ int value = RNA_enum_get(&scene_props_ptr, identifier);
+ BKE_collection_engine_property_add_int(props, identifier, value);
+ break;
+ }
+ case PROP_INT:
+ {
+ int value = RNA_int_get(&scene_props_ptr, identifier);
+ BKE_collection_engine_property_add_int(props, identifier, value);
+ break;
+ }
+ case PROP_BOOLEAN:
+ {
+ int value = RNA_boolean_get(&scene_props_ptr, identifier);
+ BKE_collection_engine_property_add_bool(props, identifier, value);
+ break;
+ }
+ case PROP_STRING:
+ case PROP_POINTER:
+ case PROP_COLLECTION:
+ default:
+ break;
+ }
+
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update((ID *)CTX_data_scene(C), 0);
+
+ return OPERATOR_FINISHED;
+}
+
+static void UI_OT_use_property_button(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Use property";
+ ot->idname = "UI_OT_use_property_button";
+ ot->description = "Create a property";
+
+ /* callbacks */
+ ot->poll = ED_operator_regionactive;
+ ot->exec = use_property_button_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+}
+
+static int unuse_property_button_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+
+ /* try to unset the nominated property */
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+ const char *identifier = RNA_property_identifier(prop);
+
+ IDProperty *props = (IDProperty *)ptr.data;
+ IDProperty *prop_to_remove = IDP_GetPropertyFromGroup(props, identifier);
+ IDP_FreeFromGroup(props, prop_to_remove);
+
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update((ID *)CTX_data_scene(C), 0);
+
+ return OPERATOR_FINISHED;
+}
+
+static void UI_OT_unuse_property_button(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Unuse property";
+ ot->idname = "UI_OT_unuse_property_button";
+ ot->description = "Remove a property";
+
+ /* callbacks */
+ ot->poll = ED_operator_regionactive;
+ ot->exec = unuse_property_button_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+}
+
/* Copy To Selected Operator ------------------------ */
bool UI_context_copy_to_selected_list(
@@ -719,6 +863,7 @@ static int editsource_text_edit(
if (text == NULL) {
text = BKE_text_load(bmain, filepath, bmain->name);
+ id_us_ensure_real(&text->id);
}
if (text == NULL) {
@@ -1083,7 +1228,6 @@ static void UI_OT_drop_color(wmOperatorType *ot)
}
-
/* ********************************************************* */
/* Registration */
@@ -1094,6 +1238,8 @@ 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_use_property_button);
+ WM_operatortype_append(UI_OT_unuse_property_button);
WM_operatortype_append(UI_OT_copy_to_selected_button);
WM_operatortype_append(UI_OT_reports_to_textblock); /* XXX: temp? */
WM_operatortype_append(UI_OT_drop_color);
@@ -1112,12 +1258,35 @@ void ED_operatortypes_ui(void)
/**
* \brief User Interface Keymap
- *
- * For now only modal maps here, since UI uses special ui-handlers instead of operators.
*/
void ED_keymap_ui(wmKeyConfig *keyconf)
{
- WM_keymap_find(keyconf, "User Interface", 0, 0);
+ wmKeyMap *keymap = WM_keymap_find(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_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);
eyedropper_modal_keymap(keyconf);
}
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 79961eae79d..cc49eeb5b59 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,8 @@
#include "UI_interface_icons.h"
#include "UI_resources.h"
+#include "GPU_immediate.h"
+
#include "interface_intern.h"
/*********************** defines and structs ************************/
@@ -393,54 +392,42 @@ 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;
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)
{
+ float color[4];
+ UI_GetThemeColor3fv(TH_TITLE, color);
+ color[3] = 1.0f;
+
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);
+ ui_draw_anti_tria(rect->xmin, rect->ymin, rect->xmin, rect->ymax, rect->xmax, rect->ymin + half, 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);
+ ui_draw_anti_tria(rect->xmin, rect->ymax, rect->xmax, rect->ymax, rect->xmin + half, rect->ymin, color);
}
}
-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 */
@@ -448,9 +435,16 @@ static void ui_draw_anti_x(float x1, float y1, float x2, float y2)
glEnable(GL_BLEND);
glLineWidth(2.0);
-
- fdrawline(x1, y1, x2, y2);
- fdrawline(x1, y2, x2, y1);
+
+ immBegin(GWN_PRIM_LINES, 4);
+
+ immVertex2f(pos, x1, y1);
+ immVertex2f(pos, x2, y2);
+
+ immVertex2f(pos, x1, y2);
+ immVertex2f(pos, x2, y1);
+
+ immEnd();
glDisable(GL_LINE_SMOOTH);
glDisable(GL_BLEND);
@@ -458,16 +452,16 @@ static void ui_draw_anti_x(float x1, float y1, float x2, float y2)
}
/* 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;
@@ -481,16 +475,33 @@ static void ui_draw_panel_scalewidget(const rcti *rect)
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);
+ immUniformColor4ub(255, 255, 255, 50);
+
+ immBegin(GWN_PRIM_LINES, 4);
+
+ immVertex2f(pos, xmin, ymin);
+ immVertex2f(pos, xmax, ymax);
+
+ immVertex2f(pos, xmin + dx, ymin);
+ immVertex2f(pos, xmax, ymax - dy);
+
+ immEnd();
- glColor4ub(0, 0, 0, 50);
- fdrawline(xmin, ymin + 1, xmax, ymax + 1);
- fdrawline(xmin + dx, ymin + 1, xmax, ymax - dy + 1);
+ immUniformColor4ub(0, 0, 0, 50);
+
+ immBegin(GWN_PRIM_LINES, 4);
+
+ immVertex2f(pos, xmin, ymin + 1);
+ immVertex2f(pos, xmax, ymax + 1);
+
+ immVertex2f(pos, xmin + dx, ymin + 1);
+ immVertex2f(pos, xmax, ymax - dy + 1);
+
+ immEnd();
+
glDisable(GL_BLEND);
}
-static void ui_draw_panel_dragwidget(const rctf *rect)
+static void ui_draw_panel_dragwidget(unsigned int pos, const rctf *rect)
{
unsigned char col_back[3], col_high[3], col_dark[3];
const int col_tint = 84;
@@ -519,10 +530,10 @@ static void ui_draw_panel_dragwidget(const rctf *rect)
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);
+ immUniformColor3ubv(col_dark);
+ immRectf(pos, x_co - box_size, y_co - px_zoom, x_co, (y_co + box_size) - px_zoom);
+ immUniformColor3ubv(col_high);
+ immRectf(pos, x_co - box_size, y_co, x_co, y_co + box_size);
}
}
}
@@ -534,29 +545,30 @@ 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;
+ unsigned char col_title[4];
/* + 0.001f to avoid flirting with float inaccuracy */
if (panel->control & UI_PNL_CLOSE)
pnl_icons = (panel->labelofs + 2 * PNL_ICON + 5) / block->aspect + 0.001f;
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(&style->paneltitle, &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(&style->paneltitle, &hrect, activename, col_title);
}
}
@@ -566,7 +578,7 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
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;
@@ -579,6 +591,9 @@ 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);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
{
float minx = rect->xmin;
float maxx = is_closed_x ? (minx + PNL_HEADER / block->aspect) : rect->xmax;
@@ -588,11 +603,18 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
if (UI_GetThemeValue(TH_PANEL_SHOW_HEADER)) {
/* draw with background color */
- UI_ThemeColor4(TH_PANEL_HEADER);
- glRectf(minx, headrect.ymin + 1, maxx, y);
+ immUniformThemeColor(TH_PANEL_HEADER);
+ immRectf(pos, minx, headrect.ymin + 1, maxx, y);
+
+ immBegin(GWN_PRIM_LINES, 4);
+
+ immVertex2f(pos, minx, y);
+ immVertex2f(pos, maxx, y);
+
+ immVertex2f(pos, minx, y);
+ immVertex2f(pos, maxx, y);
- fdrawline(minx, y, maxx, y);
- fdrawline(minx, y, maxx, y);
+ immEnd();
}
else if (!(panel->runtime_flag & PNL_FIRST)) {
/* draw embossed separator */
@@ -602,15 +624,26 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
maxx -= 5.0f / block->aspect;
}
- 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);
+ immUniformColor4f(0.0f, 0.0f, 0.0f, 0.5f);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2f(pos, minx, y);
+ immVertex2f(pos, maxx, y);
+ immEnd();
+
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.25f);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2f(pos, minx, y - 1);
+ immVertex2f(pos, maxx, y - 1);
+ immEnd();
}
glDisable(GL_BLEND);
}
+ immUnbindProgram();
+
/* draw optional pin icon */
#ifdef USE_PIN_HIDDEN
@@ -626,9 +659,11 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
glDisable(GL_BLEND);
}
+
/* horizontal title */
if (is_closed_x == false) {
ui_draw_aligned_panel_header(style, block, &headrect, 'h');
+ pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
/* itemrect smaller */
itemrect.xmax = headrect.xmax - 5.0f / block->aspect;
@@ -637,7 +672,9 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
itemrect.ymax = headrect.ymax;
BLI_rctf_scale(&itemrect, 0.7f);
- ui_draw_panel_dragwidget(&itemrect);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ ui_draw_panel_dragwidget(pos, &itemrect);
+ immUnbindProgram();
}
/* if the panel is minimized vertically:
@@ -649,6 +686,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 = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
}
/* an open panel */
else {
@@ -657,33 +695,37 @@ 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);
}
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_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);
+ immUniformThemeColor(TH_PANEL_BACK);
+ 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;
@@ -699,8 +741,6 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
ui_draw_tria_rect(&itemrect, 'h');
else
ui_draw_tria_rect(&itemrect, 'v');
-
- (void)ofsx;
}
/************************** panel alignment *************************/
@@ -1513,12 +1553,13 @@ 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 */
+/* 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,
+ bool filled, 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 use_highlight, bool use_shadow,
+ const unsigned char highlight_fade[3],
+ const unsigned char col[3])
{
float vec[4][2] = {
{0.195, 0.02},
@@ -1527,74 +1568,96 @@ static void ui_panel_category_draw_tab(
{0.98, 0.805}};
int a;
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
/* mult */
for (a = 0; a < 4; a++) {
mul_v2_fl(vec[a], rad);
}
- glBegin(mode);
+ unsigned int vert_ct = 0;
+ if (use_highlight) {
+ vert_ct += (roundboxtype & UI_CNR_TOP_RIGHT) ? 6 : 1;
+ vert_ct += (roundboxtype & UI_CNR_TOP_LEFT) ? 6 : 1;
+ }
+ if (use_highlight && !use_shadow) {
+ vert_ct++;
+ }
+ else {
+ vert_ct += (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 6 : 1;
+ vert_ct += (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 6 : 1;
+ }
+
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+
+ immBegin(filled ? GWN_PRIM_TRI_FAN : GWN_PRIM_LINE_STRIP, vert_ct);
+
+ immAttrib3ubv(color, col);
/* start with corner right-top */
if (use_highlight) {
if (roundboxtype & UI_CNR_TOP_RIGHT) {
- glVertex2f(maxx, maxy - rad);
+ immVertex2f(pos, maxx, maxy - rad);
for (a = 0; a < 4; 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 < 4; 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);
}
}
if (use_highlight && !use_shadow) {
if (highlight_fade) {
- glColor3ubv(highlight_fade);
+ immAttrib3ubv(color, highlight_fade);
}
- glVertex2f(minx, miny + rad);
- glEnd();
+ immVertex2f(pos, minx, miny + rad);
+ immEnd();
+ immUnbindProgram();
return;
}
/* corner left-bottom */
if (roundboxtype & UI_CNR_BOTTOM_LEFT) {
- glVertex2f(minx, miny + rad);
+ immVertex2f(pos, minx, miny + rad);
for (a = 0; a < 4; 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);
}
/* corner right-bottom */
-
if (roundboxtype & UI_CNR_BOTTOM_RIGHT) {
- glVertex2f(maxx - rad, miny);
+ immVertex2f(pos, maxx - rad, miny);
for (a = 0; a < 4; 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);
}
- glEnd();
+ immEnd();
+ immUnbindProgram();
}
@@ -1717,21 +1780,26 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
/* begin drawing */
glEnable(GL_LINE_SMOOTH);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
/* draw the background */
if (is_alpha) {
glEnable(GL_BLEND);
- glColor4ubv(theme_col_tab_bg);
+ 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);
+ immRecti(pos, v2d->mask.xmin, v2d->mask.ymin, v2d->mask.xmin + category_tabs_width, v2d->mask.ymax);
if (is_alpha) {
glDisable(GL_BLEND);
}
+ immUnbindProgram();
+
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;
@@ -1754,28 +1822,33 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
if (is_active)
#endif
{
- glColor3ubv(is_active ? theme_col_tab_active : theme_col_tab_inactive);
- ui_panel_category_draw_tab(GL_POLYGON, rct->xmin, rct->ymin, rct->xmax, rct->ymax,
- tab_curve_radius - px, roundboxtype, true, true, NULL);
+ ui_panel_category_draw_tab(true, rct->xmin, rct->ymin, rct->xmax, rct->ymax,
+ tab_curve_radius - px, roundboxtype, true, true, 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);
+ ui_panel_category_draw_tab(false, rct->xmin - px, rct->ymin - px, rct->xmax - px, rct->ymax + px,
+ tab_curve_radius, roundboxtype, true, true, 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,
+ ui_panel_category_draw_tab(false, rct->xmin, rct->ymin, rct->xmax, rct->ymax,
tab_curve_radius, roundboxtype, true, false,
- is_active ? theme_col_back : theme_col_tab_inactive);
+ 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 = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor3ubv(theme_col_tab_divider);
+ immRecti(pos, v2d->mask.xmin + category_tabs_width - px,
+ rct->ymin - tab_v_pad,
+ v2d->mask.xmin + category_tabs_width,
+ rct->ymax + tab_v_pad);
+
+ immUnbindProgram();
}
if (do_scaletabs) {
@@ -1788,7 +1861,7 @@ 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);
@@ -1796,33 +1869,36 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
glDisable(GL_BLEND);
/* tab blackline remaining (last tab) */
+ pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_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, v2d->mask.xmin + category_tabs_width - px,
+ rct->ymax + px,
+ v2d->mask.xmin + category_tabs_width,
+ 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, v2d->mask.xmin + category_tabs_width - px,
+ 0,
+ v2d->mask.xmin + category_tabs_width,
+ 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;
@@ -1841,6 +1917,52 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
#undef USE_FLAT_INACTIVE
}
+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);
+
+ /* if mouse is inside non-tab region, ctrl key is required */
+ if (is_mousewheel && !event->ctrl && !inside_tabregion)
+ return WM_UI_HANDLER_CONTINUE;
+
+
+ if (active_but && ui_but_supports_cycling(active_but)) {
+ /* skip - exception to make cycling buttons
+ * using ctrl+mousewheel work in tabbed regions */
+ }
+ else {
+ const char *category = UI_panel_category_active_get(ar, false);
+ if (LIKELY(category)) {
+ PanelCategoryDyn *pc_dyn = UI_panel_category_find(ar, category);
+ if (LIKELY(pc_dyn)) {
+ if (is_mousewheel) {
+ /* we can probably get rid of this and only allow ctrl+tabbing */
+ pc_dyn = (event->type == WHEELDOWNMOUSE) ? pc_dyn->next : pc_dyn->prev;
+ }
+ else {
+ const bool backwards = event->shift;
+ pc_dyn = backwards ? pc_dyn->prev : pc_dyn->next;
+ if (!pc_dyn) {
+ /* proper cyclic behavior, back to first/last category (only used for ctrl+tab) */
+ pc_dyn = backwards ? ar->panels_category.last : ar->panels_category.first;
+ }
+ }
+
+ if (pc_dyn) {
+ /* intentionally don't reset scroll in this case,
+ * this allows for quick browsing between tabs */
+ UI_panel_category_active_set(ar, pc_dyn->idname);
+ ED_region_tag_redraw(ar);
+ }
+ }
+ }
+ return WM_UI_HANDLER_BREAK;
+ }
+
+ return WM_UI_HANDLER_CONTINUE;
+}
+
/* XXX should become modal keymap */
/* AKey is opening/closing panels, independent of button state now */
@@ -1853,6 +1975,7 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar, cons
retval = WM_UI_HANDLER_CONTINUE;
+ /* handle category tabs */
if (has_category_tabs) {
if (event->val == KM_PRESS) {
if (event->type == LEFTMOUSE) {
@@ -1867,32 +1990,9 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar, cons
retval = WM_UI_HANDLER_BREAK;
}
}
- else if (ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE)) {
- /* mouse wheel cycle tabs */
-
- /* first check if the mouse is in the tab region */
- if (event->ctrl || (event->mval[0] < ((PanelCategoryDyn *)ar->panels_category.first)->rect.xmax)) {
- if (active_but && ui_but_supports_cycling(active_but)) {
- /* skip - exception to make cycling buttons
- * using ctrl+mousewheel work in tabbed regions */
- }
- else {
- const char *category = UI_panel_category_active_get(ar, false);
- if (LIKELY(category)) {
- PanelCategoryDyn *pc_dyn = UI_panel_category_find(ar, category);
- if (LIKELY(pc_dyn)) {
- pc_dyn = (event->type == WHEELDOWNMOUSE) ? pc_dyn->next : pc_dyn->prev;
- if (pc_dyn) {
- /* intentionally don't reset scroll in this case,
- * this allows for quick browsing between tabs */
- UI_panel_category_active_set(ar, pc_dyn->idname);
- ED_region_tag_redraw(ar);
- }
- }
- }
- retval = WM_UI_HANDLER_BREAK;
- }
- }
+ else if ((event->type == TABKEY && event->ctrl) || ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE)) {
+ /* cycle tabs */
+ retval = ui_handle_panel_category_cycling(event, ar, active_but);
}
}
}
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index c621fcf493d..738ebfcc5c2 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -73,38 +73,6 @@
#define MENU_PADDING (int)(0.2f * UI_UNIT_Y)
#define MENU_BORDER (int)(0.3f * U.widget_unit)
-static int rna_property_enum_step(const bContext *C, PointerRNA *ptr, PropertyRNA *prop, int direction)
-{
- EnumPropertyItem *item_array;
- int totitem;
- bool free;
- int value;
- int i, i_init;
- int step = (direction < 0) ? -1 : 1;
- int step_tot = 0;
-
- RNA_property_enum_items((bContext *)C, ptr, prop, &item_array, &totitem, &free);
- value = RNA_property_enum_get(ptr, prop);
- i = RNA_enum_from_value(item_array, value);
- i_init = i;
-
- do {
- i = mod_i(i + step, totitem);
- if (item_array[i].identifier[0]) {
- step_tot += step;
- }
- } while ((i != i_init) && (step_tot != direction));
-
- if (i != i_init) {
- value = item_array[i].value;
- }
-
- if (free) {
- MEM_freeN(item_array);
- }
-
- return value;
-}
bool ui_but_menu_step_poll(const uiBut *but)
{
@@ -122,7 +90,8 @@ int ui_but_menu_step(uiBut *but, int direction)
return but->menu_step_func(but->block->evil_C, direction, but->poin);
}
else {
- return rna_property_enum_step(but->block->evil_C, &but->rnapoin, but->rnaprop, direction);
+ const int curval = RNA_property_enum_get(&but->rnapoin, but->rnaprop);
+ return RNA_property_enum_step(but->block->evil_C, &but->rnapoin, but->rnaprop, curval, direction);
}
}
@@ -148,6 +117,9 @@ static ARegion *ui_region_temp_add(bScreen *sc)
static 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);
@@ -225,6 +197,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];
@@ -291,9 +264,9 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
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, data->header);
+ UI_fontstyle_draw(&fstyle_header, &bbox, data->header, drawcol);
/* offset to the end of the last line */
xofs = data->line_geom[i].x_pos;
@@ -301,9 +274,9 @@ 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]);
+ rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_ACTIVE]);
fstyle_header.shadow = 0;
- UI_fontstyle_draw(&fstyle_header, &bbox, data->active_info);
+ UI_fontstyle_draw(&fstyle_header, &bbox, data->active_info, drawcol);
/* undo offset */
bbox.xmin -= xofs;
@@ -311,14 +284,15 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
}
else if (data->format[i].style == UI_TIP_STYLE_MONO) {
uiFontStyle fstyle_mono = data->fstyle;
+
fstyle_mono.uifont_id = blf_mono_font;
fstyle_mono.word_wrap = true;
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[data->format[i].color_id]);
- UI_fontstyle_draw(&fstyle_mono, &bbox, data->lines[i]);
+ rgb_float_to_uchar(drawcol, tip_colors[data->format[i].color_id]);
+ UI_fontstyle_draw(&fstyle_mono, &bbox, data->lines[i], drawcol);
}
else {
uiFontStyle fstyle_normal = data->fstyle;
@@ -327,8 +301,8 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
/* draw remaining data */
UI_fontstyle_set(&fstyle_normal);
- glColor3fv(tip_colors[data->format[i].color_id]);
- UI_fontstyle_draw(&fstyle_normal, &bbox, data->lines[i]);
+ rgb_float_to_uchar(drawcol, tip_colors[data->format[i].color_id]);
+ UI_fontstyle_draw(&fstyle_normal, &bbox, data->lines[i], drawcol);
}
bbox.ymax -= data->lineh * data->line_geom[i].lines;
@@ -484,20 +458,30 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
}
MEM_freeN(str);
+ }
- /* second check if we are disabled - why */
- if (but->flag & UI_BUT_DISABLED) {
- const char *poll_msg;
+ /* button is disabled, we may be able to tell user why */
+ if (but->flag & UI_BUT_DISABLED) {
+ const char *disabled_msg = NULL;
+
+ /* if operator poll check failed, it can give pretty precise info why */
+ if (but->optype) {
CTX_wm_operator_poll_msg_set(C, NULL);
WM_operator_poll_context(C, but->optype, but->opcontext);
- poll_msg = CTX_wm_operator_poll_msg_get(C);
- if (poll_msg) {
- BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), TIP_("Disabled: %s"), poll_msg);
- data->format[data->totline].color_id = UI_TIP_LC_ALERT;
- data->totline++;
- }
+ disabled_msg = CTX_wm_operator_poll_msg_get(C);
+ }
+ /* alternatively, buttons can store some reasoning too */
+ else if (but->disabled_info) {
+ disabled_msg = TIP_(but->disabled_info);
+ }
+
+ if (disabled_msg && disabled_msg[0]) {
+ BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), TIP_("Disabled: %s"), disabled_msg);
+ data->format[data->totline].color_id = UI_TIP_LC_ALERT;
+ data->totline++;
}
}
+
if ((U.flag & USER_TOOLTIPS_PYTHON) == 0 && !but->optype && rna_struct.strinfo) {
if (rna_prop.strinfo) {
/* Struct and prop */
@@ -829,7 +813,7 @@ int UI_searchbox_size_y(void)
int UI_searchbox_size_x(void)
{
- return 10 * UI_UNIT_X;
+ return 12 * UI_UNIT_X;
}
int UI_search_items_find_index(uiSearchItems *items, const char *name)
@@ -872,7 +856,7 @@ static void ui_searchbox_select(bContext *C, ARegion *ar, uiBut *but, int step)
}
else {
/* only let users step into an 'unset' state for unlink buttons */
- data->active = (but->flag & UI_BUT_SEARCH_UNLINK) ? -1 : 0;
+ data->active = (but->flag & UI_BUT_VALUE_CLEAR) ? -1 : 0;
}
}
@@ -943,8 +927,8 @@ bool ui_searchbox_apply(uiBut *but, ARegion *ar)
return true;
}
- else if (but->flag & UI_BUT_SEARCH_UNLINK) {
- /* It is valid for _UNLINK flavor to have no active element (it's a valid way to unlink). */
+ else if (but->flag & UI_BUT_VALUE_CLEAR) {
+ /* It is valid for _VALUE_CLEAR flavor to have no active element (it's a valid way to unlink). */
but->editstr[0] = '\0';
return true;
@@ -1080,7 +1064,7 @@ 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;
@@ -1098,6 +1082,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 */
@@ -1380,6 +1367,7 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe
rect_pre.xmax = rect_post.xmin = rect.xmin + ((rect.xmax - rect.xmin) / 4);
/* widget itself */
+ /* NOTE: i18n messages extracting tool does the same, please keep it in sync. */
{
wmOperatorType *ot = data->items.pointers[a];
@@ -1400,7 +1388,8 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe
}
rect_pre.xmax += 4; /* sneaky, avoid showing ugly margin */
- ui_draw_menu_item(&data->fstyle, &rect_pre, text_pre, data->items.icons[a], state, false);
+ ui_draw_menu_item(&data->fstyle, &rect_pre, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, text_pre),
+ data->items.icons[a], state, false);
ui_draw_menu_item(&data->fstyle, &rect_post, data->items.names[a], 0, state, data->use_sep);
}
@@ -1711,6 +1700,28 @@ static void ui_block_region_draw(const bContext *C, ARegion *ar)
UI_block_draw(C, block);
}
+/**
+ * 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, const Scene *UNUSED(scene))
+{
+ switch (wmn->category) {
+ case NC_WINDOW:
+ {
+ switch (wmn->action) {
+ case NA_EDITED:
+ {
+ /* window resize */
+ ED_region_tag_refresh_ui(ar);
+ break;
+ }
+ }
+ break;
+ }
+ }
+}
+
static void ui_popup_block_clip(wmWindow *window, uiBlock *block)
{
uiBut *bt;
@@ -2022,6 +2033,11 @@ uiPopupBlockHandle *ui_popup_block_create(
block = ui_popup_block_refresh(C, handle, butregion, but);
handle = block->handle;
+ /* keep centered on window resizing */
+ if ((block->bounds_type == UI_BLOCK_BOUNDS_POPUP_CENTER) && handle->can_refresh) {
+ type.listener = ui_block_region_popup_window_listener;
+ }
+
return handle;
}
@@ -2091,9 +2107,11 @@ static void ui_update_color_picker_buts_rgb(uiBlock *block, ColorPicker *cpicker
continue;
if (bt->rnaprop) {
-
ui_but_v3_set(bt, rgb);
+ /* original button that created the color picker already does undo
+ * push, so disable it on RNA buttons in the color picker block */
+ UI_but_flag_disable(bt, UI_BUT_UNDO);
}
else if (STREQ(bt->str, "Hex: ")) {
float rgb_gamma[3];
@@ -3304,7 +3322,7 @@ void UI_popup_block_invoke(bContext *C, uiBlockCreateFunc func, void *arg)
UI_popup_block_invoke_ex(C, func, arg, NULL, WM_OP_INVOKE_DEFAULT);
}
-void UI_popup_block_ex(bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, uiBlockCancelFunc cancel_func, void *arg)
+void UI_popup_block_ex(bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, uiBlockCancelFunc cancel_func, void *arg, wmOperator *op)
{
wmWindow *window = CTX_wm_window(C);
uiPopupBlockHandle *handle;
@@ -3313,6 +3331,7 @@ void UI_popup_block_ex(bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc po
handle->popup = true;
handle->retvalue = 1;
+ handle->popup_op = op;
handle->popup_arg = arg;
handle->popup_func = popup_func;
handle->cancel_func = cancel_func;
@@ -3347,11 +3366,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_style.c b/source/blender/editors/interface/interface_style.c
index 8b41302b5bb..01456e2e122 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -149,7 +149,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;
@@ -196,6 +196,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 +206,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;
@@ -249,6 +250,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 +277,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 +296,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 +310,19 @@ 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)
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 241da5decc6..e21f09fad61 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -55,9 +55,10 @@
#include "BKE_colortools.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_idcode.h"
+#include "BKE_idprop.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_linestyle.h"
#include "BKE_main.h"
@@ -71,6 +72,9 @@
#include "BKE_screen.h"
#include "BKE_texture.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "ED_screen.h"
#include "ED_object.h"
#include "ED_render.h"
@@ -87,10 +91,126 @@
#include "PIL_time.h"
+/* 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)
+{
+ 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);
+ const bool use_big_size = (region->regiontype != RGN_TYPE_HEADER); /* 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);
+ 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)
+{
+ 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);
+
+ /* preview thumbnails */
+ if (preview_rows > 0 && preview_cols > 0) {
+ const int w = 4 * U.widget_unit * preview_cols;
+ const int h = 5 * U.widget_unit * preview_rows;
+
+ /* 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)
@@ -172,61 +292,16 @@ static void id_search_cb(const bContext *C, void *arg_template, const char *str,
/* ID Search browse menu, open */
static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
{
- static char search[256];
static TemplateID template;
- PointerRNA idptr;
- wmWindow *win = CTX_wm_window(C);
- uiBlock *block;
- uiBut *but;
-
- /* clear initial search string, then all items show */
- search[0] = 0;
+ PointerRNA active_item_ptr;
+
/* arg_litem is malloced, can be freed by parent button */
template = *((TemplateID *)arg_litem);
-
- /* get active id for showing first item */
- idptr = RNA_property_pointer_get(&template.ptr, template.prop);
+ active_item_ptr = RNA_property_pointer_get(&template.ptr, template.prop);
- block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
- UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_SEARCH_MENU);
-
- /* preview thumbnails */
- if (template.prv_rows > 0 && template.prv_cols > 0) {
- int w = 4 * U.widget_unit * template.prv_cols;
- int h = 5 * U.widget_unit * template.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.prv_rows, template.prv_cols, "");
- UI_but_func_search_set(
- but, ui_searchbox_create_generic, id_search_cb,
- &template, 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,
- &template, 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, &template, id_search_call_cb, active_item_ptr.data,
+ template.prv_rows, template.prv_cols);
}
/************************ ID Template ***************************/
@@ -303,7 +378,10 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
break;
case UI_ID_LOCAL:
if (id) {
- if (id_make_local(CTX_data_main(C), id, false, false)) {
+ Main *bmain = CTX_data_main(C);
+ 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->ptr, template->prop);
RNA_property_pointer_set(&template->ptr, template->prop, idptr);
@@ -322,11 +400,13 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
Scene *scene = CTX_data_scene(C);
ED_object_single_user(bmain, scene, (struct Object *)id);
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->ptr, template->prop);
+ DEG_relations_tag_update(bmain);
}
}
}
@@ -338,7 +418,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)) {
@@ -370,6 +450,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");
@@ -399,6 +481,7 @@ static void template_ID(
// ListBase *lb; // UNUSED
ID *id, *idfrom;
const bool editable = RNA_property_editable(&template->ptr, template->prop);
+ const bool use_previews = template->preview = (flag & UI_ID_PREVIEWS) != 0;
idptr = RNA_property_pointer_get(&template->ptr, template->prop);
id = idptr.data;
@@ -411,29 +494,11 @@ static void template_ID(
if (idptr.type)
type = idptr.type;
- if (flag & UI_ID_PREVIEWS) {
- template->preview = true;
-
- but = uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 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), "", 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->ptr, template->prop,
+ id_search_menu, MEM_dupallocN(template), TIP_(template_id_browse_tip(type)),
+ use_previews, editable);
}
/* text button with name */
@@ -443,20 +508,21 @@ 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,
- &idptr, "name", -1, 0, 0, -1, -1, RNA_struct_ui_description(type));
+ but = uiDefButR(
+ 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), SET_INT_IN_POINTER(UI_ID_RENAME));
if (user_alert) UI_but_flag_enable(but, UI_BUT_REDALERT);
if (id->lib) {
if (id->tag & LIB_TAG_INDIRECT) {
but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_LIBRARY_DATA_INDIRECT, 0, 0, UI_UNIT_X, UI_UNIT_Y,
- NULL, 0, 0, 0, 0, TIP_("Indirect library datablock, cannot change"));
+ NULL, 0, 0, 0, 0, TIP_("Indirect library data-block, cannot change"));
UI_but_flag_enable(but, UI_BUT_DISABLED);
}
else {
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 datablock, click to make local"));
+ 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))
UI_but_flag_enable(but, UI_BUT_DISABLED);
}
@@ -489,7 +555,7 @@ 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))) {
+ if (id->lib == NULL && !(ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB, ID_WS))) {
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);
}
}
@@ -523,6 +589,8 @@ static void template_ID(
BLT_I18NCONTEXT_ID_PARTICLESETTINGS,
BLT_I18NCONTEXT_ID_GPENCIL,
BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE,
+ BLT_I18NCONTEXT_ID_WORKSPACE,
+ BLT_I18NCONTEXT_ID_LIGHTPROBE,
);
if (newop) {
@@ -583,7 +651,7 @@ static void template_ID(
else {
if ((RNA_property_flag(template->prop) & PROP_NEVER_UNLINK) == 0) {
but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0,
- TIP_("Unlink datablock "
+ TIP_("Unlink data-block "
"(Shift + Click to set users to zero, data will then not be saved)"));
UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_DELETE));
@@ -730,6 +798,204 @@ 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);
+}
+
+static void template_search_add_button_searchmenu(
+ const bContext *C, uiLayout *layout, uiBlock *block,
+ TemplateSearch *template_search, const bool editable)
+{
+ 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);
+}
+
+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);
+ template_search_add_button_name(block, &active_ptr, type);
+ template_search_add_button_operator(block, newop, WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN, editable);
+ template_search_add_button_operator(block, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, editable);
+
+ 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);
+ 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);
+
+ 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 ********************/
/* ---------- */
@@ -783,7 +1049,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");
}
@@ -1064,7 +1330,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
@@ -1078,8 +1344,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);
}
@@ -1973,6 +2239,7 @@ static void curvemap_tools_dofunc(bContext *C, void *cumap_v, int event)
case UICURVE_FUNC_HANDLE_AUTO_ANIM: /* set auto-clamped */
curvemap_handle_set(cuma, HD_AUTO_ANIM);
curvemapping_changed(cumap, false);
+ break;
case UICURVE_FUNC_EXTEND_HOZ: /* extend horiz */
cuma->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
curvemapping_changed(cumap, false);
@@ -3714,6 +3981,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,
@@ -3730,6 +3998,66 @@ void uiTemplateKeymapItemProperties(uiLayout *layout, PointerRNA *ptr)
}
}
+/********************************* Overrides *************************************/
+
+void uiTemplateOverrideProperty(
+ uiLayout *layout, PointerRNA *collection_props_ptr, PointerRNA *scene_props_ptr, const char *propname,
+ const char *name, const char *text_ctxt, int translate, int icon,
+ const char *custom_template)
+{
+ bool is_set = false;
+ uiLayout *row, *col;
+
+ PointerRNA *ptr;
+ PropertyRNA *prop;
+
+ IDProperty *collection_props = collection_props_ptr->data;
+
+ if (IDP_GetPropertyFromGroup(collection_props, propname)) {
+ prop = RNA_struct_find_property(collection_props_ptr, propname);
+ ptr = collection_props_ptr;
+ is_set = RNA_property_is_set(ptr, prop);
+ }
+ else {
+ /* property doesn't exist yet */
+ prop = RNA_struct_find_property(scene_props_ptr, propname);
+ ptr = scene_props_ptr;
+ }
+
+ /* Get translated name (label). */
+ name = RNA_translate_ui_text(name, text_ctxt, NULL, prop, translate);
+
+ row = uiLayoutRow(layout, false);
+ col = uiLayoutColumn(row, false);
+
+ uiLayoutSetEnabled(col, is_set);
+
+ if (custom_template && STREQ(custom_template, "icon_view")) {
+ uiTemplateIconView(col, ptr, propname, false, 5.0f);
+ }
+ else {
+ uiItemFullR(col, ptr, prop, -1, 0, 0, name, icon);
+ }
+
+ col = uiLayoutColumn(row, false);
+ uiBut *but;
+ uiBlock *block = uiLayoutGetBlock(col);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+
+ if (is_set) {
+ but = uiDefIconButO(block, UI_BTYPE_BUT, "UI_OT_unuse_property_button", WM_OP_EXEC_DEFAULT, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
+ }
+ else {
+ but = uiDefIconButO(block, UI_BTYPE_BUT, "UI_OT_use_property_button", WM_OP_EXEC_DEFAULT, ICON_ZOOMIN, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
+ /* XXX - Using existing data struct to pass another RNAPointer */
+ but->rnasearchpoin = *scene_props_ptr;
+ }
+
+ but->rnapoin = *collection_props_ptr;
+ but->rnaprop = prop;
+ UI_block_emboss_set(block, UI_EMBOSS);
+}
+
/********************************* Color management *************************************/
void uiTemplateColorspaceSettings(uiLayout *layout, PointerRNA *ptr, const char *propname)
@@ -3884,6 +4212,8 @@ void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const c
return;
}
+ SpaceButs *sbuts = CTX_wm_space_buts(C);
+
uiLayout *row = uiLayoutRow(layout, false);
uiBlock *block = uiLayoutGetBlock(row);
uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("File Path:"), 0, 19, 145, 19, NULL, 0, 0, 0, 0, "");
@@ -3909,6 +4239,7 @@ void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const c
uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE);
row = uiLayoutRow(layout, false);
+ uiLayoutSetEnabled(row, (sbuts->mainb == BCONTEXT_CONSTRAINT));
uiItemR(row, &fileptr, "scale", 0, "Scale", ICON_NONE);
/* TODO: unused for now, so no need to expose. */
diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c
index 1d51c0588b6..869be844b05 100644
--- a/source/blender/editors/interface/interface_utils.c
+++ b/source/blender/editors/interface/interface_utils.c
@@ -120,17 +120,17 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind
but = uiDefButR_prop(block, UI_BTYPE_TEXT, 0, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
if (RNA_property_flag(prop) & PROP_TEXTEDIT_UPDATE) {
- UI_but_flag_enable(but, UI_BUT_TEXTEDIT_UPDATE);
+ /* TEXTEDIT_UPDATE is usally used for search buttons. For these we also want
+ * the 'x' icon to clear search string, so setting VALUE_CLEAR flag, too. */
+ UI_but_flag_enable(but, UI_BUT_TEXTEDIT_UPDATE | UI_BUT_VALUE_CLEAR);
}
break;
case PROP_POINTER:
{
- PointerRNA pptr;
-
- pptr = RNA_property_pointer_get(ptr, prop);
- if (!pptr.type)
- pptr.type = RNA_property_pointer_type(ptr, prop);
- icon = RNA_struct_ui_icon(pptr.type);
+ if (icon == 0) {
+ PointerRNA pptr = RNA_property_pointer_get(ptr, prop);
+ icon = RNA_struct_ui_icon(pptr.type ? pptr.type : RNA_property_pointer_type(ptr, prop));
+ }
if (icon == ICON_DOT)
icon = 0;
@@ -215,8 +215,90 @@ int uiDefAutoButsRNA(
return tot;
}
-/***************************** ID Utilities *******************************/
+/* *** 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;
+
+ 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;
+
+ /* 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;
+ }
+
+ name = RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL); /* could use the string length here */
+ iconid = 0;
+ if (itemptr.type && RNA_struct_is_ID(itemptr.type)) {
+ iconid = ui_id_icon_get(C, itemptr.data, false);
+ }
+
+ if (name) {
+ if (skip_filter || BLI_strcasestr(name, str)) {
+ cis = MEM_callocN(sizeof(CollItemSearch), "CollectionItemSearch");
+ cis->data = itemptr.data;
+ 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 (UI_search_item_add(items, cis->name, cis->data, cis->iconid) == false) {
+ break;
+ }
+ }
+
+ for (cis = items_list->first; cis; cis = cis->next) {
+ MEM_freeN(cis->name);
+ }
+ BLI_freelistN(items_list);
+ MEM_freeN(items_list);
+}
+
+/***************************** ID Utilities *******************************/
int UI_icon_from_id(ID *id)
{
Object *ob;
@@ -380,6 +462,17 @@ uiButStore *UI_butstore_create(uiBlock *block)
void UI_butstore_free(uiBlock *block, uiButStore *bs_handle)
{
+ /* Workaround for button store being moved into new block,
+ * which then can't use the previous buttons state ('ui_but_update_from_old_block' fails to find a match),
+ * keeping the active button in the old block holding a reference to the button-state in the new block: see T49034.
+ *
+ * Ideally we would manage moving the 'uiButStore', keeping a correct state.
+ * All things considered this is the most straightforward fix - Campbell.
+ */
+ if (block != bs_handle->block && bs_handle->block != NULL) {
+ block = bs_handle->block;
+ }
+
BLI_freelistN(&bs_handle->items);
BLI_remlink(&block->butstore, bs_handle);
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 02981b543f3..8adcca8c7cd 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -47,9 +47,6 @@
#include "RNA_access.h"
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
-
#include "BLF_api.h"
#include "UI_interface.h"
@@ -58,6 +55,9 @@
#include "interface_intern.h"
#include "GPU_basic_shader.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
#ifdef WITH_INPUT_IME
# include "WM_types.h"
@@ -186,48 +186,58 @@ static const unsigned int check_tria_face[4][3] = {
/* ************************************************* */
-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);
+ draw_color[3] *= 0.125f;
+
glEnable(GL_BLEND);
- glGetFloatv(GL_CURRENT_COLOR, color);
- color[3] *= 0.125f;
- glColor4fv(color);
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(2, GL_FLOAT, 0, tri_arr);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor4fv(draw_color);
+ immBegin(GWN_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);
+ immEnd();
+
+ immUnbindProgram();
+
glDisable(GL_BLEND);
}
-void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, float rad, bool use_alpha)
+/* belongs in interface_draw.c, but needs WIDGET_AA_JITTER from this file */
+void UI_draw_roundbox_aa(bool filled, float minx, float miny, float maxx, float maxy, float rad, 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 (filled) {
+ /* plain antialiased filled box */
+ const float alpha = color[3] * 0.125f;
+
+ for (int j = 0; j < WIDGET_AA_JITTER; j++) {
+ gpuPushMatrix();
+ gpuTranslate2fv(jit[j]);
+ UI_draw_roundbox_3fvAlpha(true, minx, miny, maxx, maxy, rad, color, alpha);
+ gpuPopMatrix();
+ }
}
- color[3] *= 0.125f;
- glColor4fv(color);
-
- 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);
+ else {
+ /* plain antialiased unfilled box */
+ glEnable(GL_LINE_SMOOTH);
+ UI_draw_roundbox_4fv(false, minx, miny, maxx, maxy, rad, color);
+ glDisable(GL_LINE_SMOOTH);
}
glDisable(GL_BLEND);
@@ -537,12 +547,27 @@ static void widget_scroll_circle(uiWidgetTrias *tria, const rcti *rect, float tr
scroll_circle_face, ARRAY_SIZE(scroll_circle_face));
}
-static void widget_trias_draw(uiWidgetTrias *tria)
+static void widget_trias_draw(uiWidgetTrias *tria, unsigned int pos)
{
- 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(GWN_PRIM_TRIS, tria->tot * 3);
+ for (int i = 0; i < tria->tot; ++i)
+ for (int j = 0; j < 3; ++j)
+ immVertex2fv(pos, tria->vec[tria->index[i][j]]);
+ immEnd();
+}
+
+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)
+{
+ immBegin(mode, totvert);
+ for (int i = 0; i < totvert; ++i) {
+ if (quads_col)
+ immAttrib4ubv(col, quads_col[i]);
+ immVertex2fv(pos, quads_pos[i]);
+ }
+ immEnd();
}
static void widget_menu_trias(uiWidgetTrias *tria, const rcti *rect)
@@ -631,21 +656,18 @@ static void widget_verts_to_triangle_strip_open(uiWidgetBase *wtb, const int tot
}
}
-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(uiWidgetBase *wtb, uiWidgetColors *wcol)
{
int j, a;
-
+
glEnable(GL_BLEND);
/* backdrop non AA */
@@ -655,78 +677,76 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
float inner_v_half[WIDGET_SIZE_MAX][2];
float x_mid = 0.0f; /* used for dumb clamping of values */
- /* 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);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_CHECKER);
- /* 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);
+ /* checkers */
+ 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);
- glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v);
- glDrawArrays(GL_POLYGON, 0, wtb->totvert);
+ widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_FAN, wtb->inner_v, NULL, wtb->totvert);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ immUnbindProgram();
/* alpha fill */
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4ubv((unsigned char *)wcol->inner);
- glColor4ubv((unsigned char *)wcol->inner);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
for (a = 0; a < wtb->totvert; a++) {
x_mid += wtb->inner_v[a][0];
}
x_mid /= wtb->totvert;
- glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v);
- glDrawArrays(GL_POLYGON, 0, wtb->totvert);
+ widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_FAN, wtb->inner_v, NULL, wtb->totvert);
/* 1/2 solid color */
- glColor4ub(wcol->inner[0], wcol->inner[1], wcol->inner[2], 255);
+ immUniformColor3ubv((unsigned char *)wcol->inner);
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];
}
- glVertexPointer(2, GL_FLOAT, 0, inner_v_half);
- glDrawArrays(GL_POLYGON, 0, wtb->totvert);
- glDisableClientState(GL_VERTEX_ARRAY);
+ widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_FAN, inner_v_half, NULL, wtb->totvert);
+
+ immUnbindProgram();
}
else {
/* simple fill */
- glColor4ubv((unsigned char *)wcol->inner);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4ubv((unsigned char *)wcol->inner);
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v);
- glDrawArrays(GL_POLYGON, 0, wtb->totvert);
- glDisableClientState(GL_VERTEX_ARRAY);
+ widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_FAN, wtb->inner_v, NULL, wtb->totvert);
+
+ immUnbindProgram();
}
}
else {
char col1[4], col2[4];
- unsigned char col_array[WIDGET_SIZE_MAX * 4];
- unsigned char *col_pt = col_array;
-
+ unsigned char col_array[WIDGET_SIZE_MAX][4];
+ unsigned char *col_pt = &col_array[0][0];
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+
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);
+ widget_draw_vertex_buffer(pos, col, GL_TRIANGLE_FAN, wtb->inner_v, col_array, wtb->totvert);
+ immUnbindProgram();
}
}
-
+
/* for each AA step */
if (wtb->draw_outline) {
float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */
@@ -745,52 +765,55 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss);
}
- glEnableClientState(GL_VERTEX_ARRAY);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
for (j = 0; j < WIDGET_AA_JITTER; j++) {
- glTranslate2fv(jit[j]);
+ gpuTranslate2fv(jit[j]);
/* outline */
- glColor4ubv(tcol);
+ immUniformColor4ubv(tcol);
- glVertexPointer(2, GL_FLOAT, 0, triangle_strip);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, wtb->totvert * 2 + 2);
+ widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_STRIP, triangle_strip, NULL, wtb->totvert * 2 + 2);
/* 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);
+ immUniformColor4ubv(emboss);
+ widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_STRIP, triangle_strip_emboss, NULL, wtb->halfwayvert * 2);
}
}
- glTranslatef(-jit[j][0], -jit[j][1], 0.0f);
+ gpuTranslate2f(-jit[j][0], -jit[j][1]);
}
-
- glDisableClientState(GL_VERTEX_ARRAY);
+ immUnbindProgram();
}
-
+
/* 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);
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4ubv(tcol);
/* for each AA step */
for (j = 0; j < WIDGET_AA_JITTER; j++) {
- glTranslate2fv(jit[j]);
+ gpuTranslate2fv(jit[j]);
if (wtb->tria1.tot)
- widget_trias_draw(&wtb->tria1);
+ widget_trias_draw(&wtb->tria1, pos);
if (wtb->tria2.tot)
- widget_trias_draw(&wtb->tria2);
+ widget_trias_draw(&wtb->tria2, pos);
- glTranslatef(-jit[j][0], -jit[j][1], 0.0f);
+ gpuTranslate2f(-jit[j][0], -jit[j][1]);
}
+
+ immUnbindProgram();
}
glDisable(GL_BLEND);
@@ -874,21 +897,18 @@ static void widget_draw_icon(
float ofs = 1.0f / aspect;
if (but->drawflag & UI_BUT_ICON_LEFT) {
- if (but->block->flag & UI_BLOCK_LOOP) {
- if (but->type == UI_BTYPE_SEARCH_MENU)
- xs = rect->xmin + 4.0f * ofs;
- else
- xs = rect->xmin + ofs;
- }
- else {
+ /* 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')
+ xs = rect->xmin + 2.0f * ofs;
+ else if (but->dt == UI_EMBOSS_NONE || but->type == UI_BTYPE_LABEL)
+ xs = rect->xmin + 2.0f * ofs;
+ else
xs = rect->xmin + 4.0f * ofs;
- }
- ys = (rect->ymin + rect->ymax - height) / 2.0f;
}
else {
xs = (rect->xmin + rect->xmax - height) / 2.0f;
- ys = (rect->ymin + rect->ymax - height) / 2.0f;
}
+ ys = (rect->ymin + rect->ymax - height) / 2.0f;
/* force positions to integers, for zoom levels near 1. draws icons crisp. */
if (aspect > 0.95f && aspect < 1.05f) {
@@ -1249,6 +1269,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) {
@@ -1261,8 +1282,8 @@ static void widget_draw_text_ime_underline(
width = BLF_width(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) {
@@ -1279,7 +1300,7 @@ static void widget_draw_text_ime_underline(
width = BLF_width(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);
}
}
}
@@ -1363,11 +1384,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);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_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();
}
}
@@ -1390,13 +1416,18 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
t = 0;
}
- glColor3f(0.2, 0.6, 0.9);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ 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
@@ -1455,43 +1486,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);
- 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);
+ }
}
}
}
@@ -1501,17 +1535,17 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
if (drawstr_right) {
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, (unsigned char *)wcol->text);
}
}
/* draws text and icons for buttons */
static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, rcti *rect)
{
+ const uiButExtraIconType extra_icon_type = ui_but_icon_extra_get(but);
const bool show_menu_icon = ui_but_draw_menu_icon(but);
float alpha = (float)wcol->text[3] / 255.0f;
char password_str[UI_MAX_DRAW_STR];
- uiButExtraIconType extra_icon_type;
ui_but_text_password_hide(password_str, but, false);
@@ -1554,11 +1588,15 @@ 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_SIZE_FROM_BUTRECT(rect);
+ const float icon_size = ICON_DEFAULT_WIDTH_SCALE;
/* 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_menu(but->block))
+ 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);
@@ -1577,16 +1615,14 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
rect->xmax -= (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect;
}
- /* unlink icon for this button type */
- if ((but->type == UI_BTYPE_SEARCH_MENU) &&
- ((extra_icon_type = ui_but_icon_extra_get(but)) != UI_BUT_ICONEXTRA_NONE))
- {
+ /* extra icons, e.g. 'x' icon to clear text or icon for eyedropper */
+ if (extra_icon_type != UI_BUT_ICONEXTRA_NONE) {
rcti temp = *rect;
temp.xmin = temp.xmax - (BLI_rcti_size_y(rect) * 1.08f);
- if (extra_icon_type == UI_BUT_ICONEXTRA_UNLINK) {
- widget_draw_icon(but, ICON_X, alpha, &temp, false);
+ if (extra_icon_type == UI_BUT_ICONEXTRA_CLEAR) {
+ widget_draw_icon(but, ICON_PANEL_CLOSE, alpha, &temp, false);
}
else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) {
widget_draw_icon(but, ICON_EYEDROPPER, alpha, &temp, false);
@@ -1622,6 +1658,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
@@ -1880,6 +1919,19 @@ static struct uiWidgetColors wcol_list_item = {
0, 0
};
+struct uiWidgetColors wcol_tab = {
+ {255, 255, 255, 255},
+ {83, 83, 83, 255},
+ {114, 114, 114, 255},
+ {90, 90, 90, 255},
+
+ {0, 0, 0, 255},
+ {0, 0, 0, 255},
+
+ 0,
+ 0, 0
+};
+
/* free wcol struct to play with */
static struct uiWidgetColors wcol_tmp = {
{0, 0, 0, 255},
@@ -1902,6 +1954,7 @@ void ui_widget_color_init(ThemeUI *tui)
tui->wcol_tool = wcol_tool;
tui->wcol_text = wcol_text;
tui->wcol_radio = wcol_radio;
+ tui->wcol_tab = wcol_tab;
tui->wcol_option = wcol_option;
tui->wcol_toggle = wcol_toggle;
tui->wcol_num = wcol_num;
@@ -2160,23 +2213,24 @@ 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);
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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)
@@ -2213,20 +2267,21 @@ static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int dir
static void ui_hsv_cursor(float x, float y)
{
- glPushMatrix();
- glTranslatef(x, y, 0.0f);
-
- glColor3f(1.0f, 1.0f, 1.0f);
- glutil_draw_filled_arc(0.0f, M_PI * 2.0, 3.0f * U.pixelsize, 8);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor3f(1.0f, 1.0f, 1.0f);
+ imm_draw_circle_fill(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);
+ immUniformColor3f(0.0f, 0.0f, 0.0f);
+ imm_draw_circle_wire(pos, x, y, 3.0f * U.pixelsize, 12);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
-
- glPopMatrix();
+
+ immUnbindProgram();
}
void ui_hsvcircle_vals_from_pos(float *val_rad, float *val_dist, const rcti *rect,
@@ -2266,18 +2321,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 */
@@ -2308,11 +2362,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);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+
+ immBegin(GWN_PRIM_TRI_FAN, tot + 2);
+ immAttrib3fv(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);
@@ -2320,25 +2381,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);
+ immAttrib3fv(color, col);
+ immVertex2f(pos, centx + co * radius, centy + si * radius);
}
- glEnd();
-
+ immEnd();
+ immUnbindProgram();
+
/* fully rounded outline */
- glPushMatrix();
- glTranslatef(centx, centy, 0.0f);
+ format = immVertexFormat();
+ pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
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);
+
+ immUniformColor3ubv((unsigned char *)wcol->outline);
+ imm_draw_circle_wire(pos, centx, centy, radius, tot);
+
+ immUnbindProgram();
+
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
- glPopMatrix();
/* cursor */
+ float xpos, ypos;
ui_hsvcircle_pos_from_vals(but, rect, hsvo, &xpos, &ypos);
-
ui_hsv_cursor(xpos, ypos);
}
@@ -2348,7 +2416,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;
@@ -2402,9 +2471,14 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
copy_v3_v3(col1[3], col1[2]);
break;
}
-
+
/* old below */
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int col = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 4, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+ immBegin(GWN_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;
@@ -2462,22 +2536,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);
+ immAttrib4f(col, col0[a][0], col0[a][1], col0[a][2], alpha);
+ immVertex2f(pos, sx1, sy);
- glColor4f(col1[a][0], col1[a][1], col1[a][2], alpha);
- glVertex2f(sx2, sy);
+ immAttrib4f(col, col1[a][0], col1[a][1], col1[a][2], alpha);
+ immVertex2f(pos, sx2, sy);
+
+ immAttrib4f(col, col1[a + 1][0], col1[a + 1][1], col1[a + 1][2], alpha);
+ immVertex2f(pos, sx2, sy + dy);
+
+ immAttrib4f(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);
+ immAttrib4f(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);
+ immAttrib4f(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)
@@ -2553,8 +2634,11 @@ 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));
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3ub(0, 0, 0);
+ imm_draw_line_box(pos, (rect->xmin), (rect->ymin), (rect->xmax), (rect->ymax));
+ immUnbindProgram();
}
/* vertical 'value' slider, using new widget code */
@@ -2622,11 +2706,22 @@ static void ui_draw_separator(const rcti *rect, uiWidgetColors *wcol)
wcol->text[2],
30
};
-
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
glEnable(GL_BLEND);
- glColor4ubv(col);
- sdrawline(rect->xmin, y, rect->xmax, y);
+ immUniformColor4ubv(col);
+ glLineWidth(1.0f);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2f(pos, rect->xmin, y);
+ immVertex2f(pos, rect->xmax, y);
+ immEnd();
+
glDisable(GL_BLEND);
+
+ immUnbindProgram();
}
/* ************ button callbacks, draw ***************** */
@@ -2698,11 +2793,14 @@ bool ui_link_bezier_points(const rcti *rect, float coord_array[][2], int resol)
}
#define LINK_RESOL 24
-void ui_draw_link_bezier(const rcti *rect)
+void ui_draw_link_bezier(const rcti *rect, const float color[4])
{
float coord_array[LINK_RESOL + 1][2];
if (ui_link_bezier_points(rect, coord_array, LINK_RESOL)) {
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
#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;
@@ -2710,13 +2808,17 @@ void ui_draw_link_bezier(const rcti *rect)
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);
+ immUniformColor4fv(color);
+
+ immBegin(GWN_PRIM_LINE_STRIP, LINK_RESOL + 1);
+ for (int i = 0; i <= LINK_RESOL; ++i)
+ immVertex2fv(pos, coord_array[i]);
+ immEnd();
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
+
+ immUnbindProgram();
}
}
@@ -2898,15 +3000,16 @@ static void widget_link(uiBut *but, uiWidgetColors *UNUSED(wcol), rcti *rect, in
if (but->flag & UI_SELECT) {
rcti rectlink;
+ float color[4];
- UI_ThemeColor(TH_TEXT_HI);
+ UI_GetThemeColor4fv(TH_TEXT_HI, color);
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);
+ ui_draw_link_bezier(&rectlink, color);
}
}
@@ -3058,13 +3161,18 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
float bw = rgb_to_grayscale(col);
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();
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor3f(bw, bw, bw);
+ immBegin(GWN_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();
}
}
@@ -3360,12 +3468,50 @@ static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state),
widgetbase_draw(&wtb, wcol);
}
+static void widget_tab(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
+{
+ const uiStyle *style = UI_style_get();
+ const float rad = 0.15f * U.widget_unit;
+ const int fontid = style->widget.uifont_id;
+ const bool is_active = (but->flag & UI_SELECT);
+
+ uiWidgetBase wtb;
+ unsigned char theme_col_tab_highlight[3];
+
+ /* 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);
+ }
+
+ widget_init(&wtb);
+
+ /* half rounded */
+ round_box_edges(&wtb, roundboxalign, rect, rad);
+
+ /* draw inner */
+ wtb.draw_outline = 0;
+ widgetbase_draw(&wtb, wcol);
+
+ /* draw outline (3d look) */
+ ui_draw_but_TAB_outline(rect, rad, theme_col_tab_highlight, (unsigned char *)wcol->inner);
+
+ /* text shadow */
+ BLF_enable(fontid, BLF_SHADOW);
+ BLF_shadow(fontid, 3, (const float[4]){1.0f, 1.0f, 1.0f, 0.25f});
+ BLF_shadow_offset(fontid, 0, -1);
+}
+
static void widget_draw_extra_mask(const bContext *C, uiBut *but, uiWidgetType *wt, rcti *rect)
{
uiWidgetBase wtb;
const float rad = 0.25f * U.widget_unit;
unsigned char col[4];
-
+
/* state copy! */
wt->wcol = *(wt->wcol_theme);
@@ -3375,12 +3521,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);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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 */
@@ -3442,6 +3593,11 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
wt.draw = widget_roundbut;
break;
+ case UI_WTYPE_TAB:
+ wt.custom = widget_tab;
+ wt.wcol_theme = &btheme->tui.wcol_tab;
+ break;
+
case UI_WTYPE_TOOLTIP:
wt.wcol_theme = &btheme->tui.wcol_tooltip;
wt.draw = widget_menu_back;
@@ -3696,7 +3852,11 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
if (but->block->flag & UI_BLOCK_LOOP)
wt->wcol_theme = &btheme->tui.wcol_menu_back;
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:
@@ -3889,15 +4049,21 @@ void ui_draw_menu_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect)
wt->draw(&wt->wcol, rect, 0, 0);
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 */
- glColor3ubv((unsigned char *)wt->wcol.text);
- UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymax - 8, 't');
+ 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 */
- glColor3ubv((unsigned char *)wt->wcol.text);
- UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymin + 10, 'v');
+ UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymin + 10, 'v', draw_color);
}
}
}
@@ -3915,33 +4081,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;
-
+ Gwn_VertFormat *format = immVertexFormat();
+ pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_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 = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_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(GWN_PRIM_TRI_STRIP, subd * 2);
+ for (i = 0; i < subd; i++) {
float a;
a = start + ((i) / (float)(subd - 1)) * angle;
@@ -3953,20 +4107,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);
+ immAttrib4ubv(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);
+ immAttrib4ubv(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)
@@ -3985,8 +4139,8 @@ void ui_draw_pie_center(uiBlock *block)
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);
+ gpuPushMatrix();
+ gpuTranslate2f(cx, cy);
glEnable(GL_BLEND);
if (btheme->tui.wcol_pie_menu.shaded) {
@@ -3995,8 +4149,7 @@ void ui_draw_pie_center(uiBlock *block)
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)) {
@@ -4006,25 +4159,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);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4ubv((unsigned char *)btheme->tui.wcol_pie_menu.outline);
+
+ imm_draw_circle_wire(pos, 0.0f, 0.0f, pie_radius_internal, subd);
+ imm_draw_circle_wire(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);
- 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();
+ gpuPopMatrix();
}
@@ -4108,8 +4270,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 */
@@ -4117,7 +4278,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;
}
}
@@ -4175,7 +4336,6 @@ 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 c8ff335f2a0..cf35f4d895b 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -53,6 +53,8 @@
#include "BIF_gl.h"
+#include "BLF_api.h"
+
#include "UI_interface.h"
#include "UI_interface_icons.h"
@@ -305,6 +307,8 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp = ts->vertex; break;
case TH_VERTEX_SELECT:
cp = ts->vertex_select; break;
+ case TH_VERTEX_BEVEL:
+ cp = ts->vertex_bevel; break;
case TH_VERTEX_UNREFERENCED:
cp = ts->vertex_unreferenced; break;
case TH_VERTEX_SIZE:
@@ -321,6 +325,8 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp = ts->edge_sharp; break;
case TH_EDGE_CREASE:
cp = ts->edge_crease; break;
+ case TH_EDGE_BEVEL:
+ cp = ts->edge_bevel; break;
case TH_EDITMESH_ACTIVE:
cp = ts->editmesh_active; break;
case TH_EDGE_FACESEL:
@@ -898,12 +904,14 @@ void ui_theme_init_default(void)
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);
@@ -961,6 +969,10 @@ void ui_theme_init_default(void)
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;
@@ -1041,10 +1053,8 @@ void ui_theme_init_default(void)
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.active, 130, 130, 130, 255); /* selected files */
rgba_char_args_set(btheme->tfile.hilite, 255, 140, 25, 255); /* selected files */
-
- rgba_char_args_set(btheme->tfile.grid, 250, 250, 250, 255);
+
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);
@@ -1150,8 +1160,8 @@ void ui_theme_init_default(void)
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, 1.0);
- rgba_char_args_set(btheme->ttime.time_gp_keyframe, 0xB5, 0xE6, 0x1D, 1.0);
+ 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;
@@ -1264,25 +1274,35 @@ void UI_ThemeColor4(int colorid)
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;
+ unsigned char col[4];
+ UI_GetThemeColorShade4ubv(colorid, offset, col);
+ glColor4ubv(col);
+}
+
+void UI_ThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset)
+{
+ int r, g, b, a;
const unsigned char *cp;
cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
- r = offset + (int) cp[0];
+ r = coloffset + (int) cp[0];
CLAMP(r, 0, 255);
- g = offset + (int) cp[1];
+ g = coloffset + (int) cp[1];
CLAMP(g, 0, 255);
- b = offset + (int) cp[2];
+ b = coloffset + (int) cp[2];
CLAMP(b, 0, 255);
- glColor4ub(r, g, b, cp[3]);
+ a = alphaoffset + (int) cp[3];
+ CLAMP(a, 0, 255);
+
+ glColor4ub(r, g, b, a);
}
-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;
@@ -1296,7 +1316,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])
@@ -1312,6 +1336,19 @@ void UI_GetThemeColorBlend3ubv(int colorid1, int colorid2, float fac, unsigned c
col[2] = floorf((1.0f - fac) * cp1[2] + fac * cp2[2]);
}
+void UI_GetThemeColorBlend3f(int colorid1, int colorid2, float fac, float r_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);
+ 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, and set it */
void UI_ThemeColorBlend(int colorid1, int colorid2, float fac)
{
@@ -1364,6 +1401,12 @@ void UI_ThemeColorBlendShadeAlpha(int colorid1, int colorid2, float fac, int off
glColor4ub(r, g, b, a);
}
+void UI_FontThemeColor(int fontid, int colorid)
+{
+ unsigned char color[4];
+ UI_GetThemeColor4ubv(colorid, color);
+ BLF_color4ubv(fontid, color);
+}
/* get individual values, not scaled */
float UI_GetThemeValuef(int colorid)
@@ -1462,6 +1505,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]);
+
+ F3TOCHAR3(blend, col);
+}
+
+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])
{
@@ -1650,11 +1798,9 @@ void init_userdef_do_versions(void)
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.manipulator_size == 0) {
+ U.manipulator_size = 75;
+ U.manipulator_flag |= USER_MANIPULATOR_DRAW;
}
if (U.pad_rot_angle == 0.0f)
U.pad_rot_angle = 15.0f;
@@ -2492,9 +2638,6 @@ void init_userdef_do_versions(void)
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) {
@@ -2630,8 +2773,8 @@ void init_userdef_do_versions(void)
btheme->tnode.gp_vertex_size = 3;
/* Timeline Keyframe Indicators */
- rgba_char_args_set(btheme->ttime.time_keyframe, 0xDD, 0xD7, 0x00, 1.0);
- rgba_char_args_set(btheme->ttime.time_gp_keyframe, 0xB5, 0xE6, 0x1D, 1.0);
+ 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);
}
}
@@ -2711,8 +2854,8 @@ void init_userdef_do_versions(void)
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, 1.0);
- rgba_char_args_set(btheme->tv3d.time_gp_keyframe, 0xB5, 0xE6, 0x1D, 1.0);
+ 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);
}
}
@@ -2734,12 +2877,48 @@ void init_userdef_do_versions(void)
}
}
+ 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(280, 1)) {
+ /* interface_widgets.c */
+ struct uiWidgetColors wcol_tab = {
+ {255, 255, 255, 255},
+ {83, 83, 83, 255},
+ {114, 114, 114, 255},
+ {90, 90, 90, 255},
+
+ {0, 0, 0, 255},
+ {0, 0, 0, 255},
+
+ 0,
+ 0, 0
+ };
+
+ for (bTheme *btheme = U.themes.first; btheme; btheme = btheme->next) {
+ btheme->tui.wcol_tab = wcol_tab;
+ }
+ }
+
/**
* Include next version bump.
*
* (keep this block even if it becomes empty).
*/
{
+
}
if (U.pixelsize == 0.0f)
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index c78d97ef86f..fb57902d258 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -49,11 +49,11 @@
#include "BKE_screen.h"
#include "BKE_global.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
#include "WM_api.h"
-#include "BIF_gl.h"
-
#include "BLF_api.h"
#include "ED_screen.h"
@@ -1100,9 +1100,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();
}
/**
@@ -1130,9 +1127,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();
}
@@ -1144,7 +1138,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();
+ gpuLoadIdentity();
// ED_region_pixelspace(CTX_wm_region(C));
}
@@ -1298,12 +1292,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;
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBegin(GWN_PRIM_LINES, vertex_count);
/* vertical lines */
if (flag & V2D_VERTICAL_LINES) {
@@ -1313,24 +1340,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);
-
- for (a = 0; a < step; a++) {
- glVertex2fv(vec1);
- glVertex2fv(vec2);
-
- vec2[0] = vec1[0] += grid->dx;
+ step = vertical_minor_step;
+ if (step != 0) {
+ UI_GetThemeColor3ubv(TH_GRID, grid_line_color);
+
+ for (a = 0; a < step; a++) {
+ immSkipAttrib(color);
+ immVertex2fv(pos, vec1);
+ immAttrib3ubv(color, grid_line_color);
+ immVertex2fv(pos, vec2);
+
+ 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);
+ immSkipAttrib(color);
+ immVertex2fv(pos, vec1);
+ immAttrib3ubv(color, grid_line_color);
+ immVertex2fv(pos, vec2);
vec2[0] = vec1[0] -= grid->dx;
}
@@ -1343,12 +1377,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);
-
- UI_ThemeColor(TH_GRID);
+ step = horizontal_major_step;
+
+ UI_GetThemeColor3ubv(TH_GRID, grid_line_color);
+
for (a = 0; a <= step; a++) {
- glVertex2fv(vec1);
- glVertex2fv(vec2);
+ immSkipAttrib(color);
+ immVertex2fv(pos, vec1);
+ immAttrib3ubv(color, grid_line_color);
+ immVertex2fv(pos, vec2);
vec2[1] = vec1[1] += grid->dy;
}
@@ -1358,10 +1395,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);
+ immSkipAttrib(color);
+ immVertex2fv(pos, vec1);
+ immAttrib3ubv(color, grid_line_color);
+ immVertex2fv(pos, vec2);
vec2[1] = vec1[1] -= grid->dy;
}
@@ -1369,7 +1408,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) {
@@ -1377,8 +1416,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);
+ immSkipAttrib(color);
+ immVertex2fv(pos, vec1);
+ immAttrib3ubv(color, grid_line_color);
+ immVertex2fv(pos, vec2);
}
/* vertical axis */
@@ -1387,91 +1428,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);
+ immSkipAttrib(color);
+ immVertex2fv(pos, vec1);
+ immAttrib3ubv(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 start, step = 25.0f;
-
- UI_ThemeColorShade(TH_BACK, -10);
+ float start_x, start_y, step = 25.0f;
+ int count_x, count_y;
- start = v2d->cur.xmin - (float)fmod(v2d->cur.xmin, step);
+ 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));
+
+ if (start_x > v2d->cur.xmax)
+ count_x = 0;
+ else
+ count_x = (v2d->cur.xmax - start_x) / step + 1;
+
+ 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)));
+
+ if (start_y > v2d->cur.ymax)
+ count_y = 0;
+ else
+ count_y = (v2d->cur.ymax - start_y) / step + 1;
- glBegin(GL_LINES);
- for (; start < v2d->cur.xmax; start += step) {
- glVertex2f(start, v2d->cur.ymin);
- glVertex2f(start, v2d->cur.ymax);
- }
+ if (count_x > 0 || count_y > 0) {
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ float theme_color[3];
- 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);
- }
+ UI_GetThemeColorShade3fv(TH_BACK, -10, theme_color);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBegin(GWN_PRIM_LINES, count_x * 2 + count_y * 2 + 4);
+
+ immAttrib3fv(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);
+ }
- /* 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);
+ /* X and Y axis */
+ UI_GetThemeColorShade3fv(TH_BACK, -18, theme_color);
+
+ immAttrib3fv(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);
- glEnd();
+ 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];
+
+ /* 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);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
glLineWidth(1.0f);
- for (level = 0; level < totlevels; ++level) {
- int i;
- float start;
-
- UI_ThemeColorShade(colorid, offset);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBeginAtMost(GWN_PRIM_LINES, vertex_count);
+
+ for (int level = 0; level < totlevels; ++level) {
+ UI_GetThemeColorShade3ubv(colorid, offset, grid_line_color);
- i = (v2d->cur.xmin >= 0.0f ? -(int)(-v2d->cur.xmin / lstep) : (int)(v2d->cur.xmin / lstep));
- start = i * lstep;
+ 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);
+
+ immSkipAttrib(color);
+ immVertex2f(pos, start, v2d->cur.ymin);
+ immAttrib3ubv(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);
+
+ immSkipAttrib(color);
+ immVertex2f(pos, v2d->cur.xmin, start);
+ immAttrib3ubv(color, grid_line_color);
+ immVertex2f(pos, 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();
-
lstep *= level_size;
offset -= 6;
}
+
+ /* X and Y axis */
+ UI_GetThemeColorShade3ubv(colorid, -18 + ((totlevels - 1) * -6) , grid_line_color);
+
+ immSkipAttrib(color);
+ immVertex2f(pos, 0.0f, v2d->cur.ymin);
+ immAttrib3ubv(color, grid_line_color);
+ immVertex2f(pos, 0.0f, v2d->cur.ymax);
+
+ immSkipAttrib(color);
+ immVertex2f(pos, v2d->cur.xmin, 0.0f);
+ immAttrib3ubv(color, grid_line_color);
+ immVertex2f(pos, v2d->cur.xmax, 0.0f);
+
+ immEnd();
+ immUnbindProgram();
}
/* the price we pay for not exposting structs :( */
@@ -1693,6 +1800,10 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v
Scene *scene = CTX_data_scene(C);
rcti vert, hor;
int scroll = view2d_scroll_mapped(v2d->scroll);
+ 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;
@@ -1704,7 +1815,6 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v
uiWidgetColors wcol = btheme->tui.wcol_scroll;
rcti slider;
int state;
- unsigned char col[4];
slider.xmin = vs->hor_min;
slider.xmax = vs->hor_max;
@@ -1728,16 +1838,23 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v
}
/* 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);
+ if (scrollers_back_color[3] == 255) {
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor3ubv(scrollers_back_color);
+ immRecti(pos, v2d->hor.xmin, v2d->hor.ymin, v2d->hor.xmax, v2d->hor.ymax);
+
+ immUnbindProgram();
}
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;
@@ -1752,7 +1869,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 */
@@ -1764,7 +1881,7 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v
}
if (vs->xunits == V2D_UNIT_FRAMES)
grid->powerx = 1;
-
+
/* draw numbers in the appropriate range */
if (dfac > 0.0f) {
float h = 0.1f * UI_UNIT_Y + (float)(hor.ymin);
@@ -1805,7 +1922,6 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v
uiWidgetColors wcol = btheme->tui.wcol_scroll;
rcti slider;
int state;
- unsigned char col[4];
slider.xmin = vert.xmin;
slider.xmax = vert.xmax;
@@ -1829,10 +1945,16 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v
}
/* 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);
+ if (scrollers_back_color[3] == 255) {
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor3ubv(scrollers_back_color);
+ immRecti(pos, v2d->vert.xmin, v2d->vert.ymin, v2d->vert.xmax, v2d->vert.ymax);
+
+ immUnbindProgram();
}
UI_draw_widget_scroll(&wcol, &vert, &slider, state);
@@ -1856,7 +1978,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 */
@@ -1865,9 +1988,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) {
@@ -1878,7 +2000,7 @@ 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);
}
}
}
@@ -2392,7 +2514,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);
@@ -2403,7 +2526,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;
}
@@ -2411,11 +2534,11 @@ void UI_view2d_text_cache_draw(ARegion *ar)
BLF_draw_default((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_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_default(BLF_CLIPPING);
+ BLF_disable(font_id, BLF_CLIPPING);
}
}
g_v2d_strings = NULL;
@@ -2424,11 +2547,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 f60fed398ec..fa2c1f25cfc 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -127,6 +127,7 @@ static int view_pan_init(bContext *C, wmOperator *op)
return 1;
}
+#ifdef WITH_INPUT_NDOF
static int view_pan_poll(bContext *C)
{
ARegion *ar = CTX_wm_region(C);
@@ -144,6 +145,7 @@ static int view_pan_poll(bContext *C)
/* view can pan */
return 1;
}
+#endif
/* apply transform to view (i.e. adjust 'cur' rect) */
static void view_pan_apply_ex(bContext *C, v2dViewPanData *vpd, float dx, float dy)
@@ -445,7 +447,8 @@ static int view_scrolldown_exec(bContext *C, wmOperator *op)
RNA_int_set(op->ptr, "deltax", 0);
RNA_int_set(op->ptr, "deltay", -40);
- if (RNA_boolean_get(op->ptr, "page")) {
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "page");
+ if (RNA_property_is_set(op->ptr, prop) && RNA_property_boolean_get(op->ptr, prop)) {
ARegion *ar = CTX_wm_region(C);
RNA_int_set(op->ptr, "deltay", ar->v2d.mask.ymin - ar->v2d.mask.ymax);
}
@@ -495,7 +498,8 @@ static int view_scrollup_exec(bContext *C, wmOperator *op)
RNA_int_set(op->ptr, "deltax", 0);
RNA_int_set(op->ptr, "deltay", 40);
- if (RNA_boolean_get(op->ptr, "page")) {
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "page");
+ if (RNA_property_is_set(op->ptr, prop) && RNA_property_boolean_get(op->ptr, prop)) {
ARegion *ar = CTX_wm_region(C);
RNA_int_set(op->ptr, "deltay", BLI_rcti_size_y(&ar->v2d.mask));
}
@@ -1296,7 +1300,7 @@ static void VIEW2D_OT_zoom_border(wmOperatorType *ot)
WM_operator_properties_gesture_border(ot, false);
}
-
+#ifdef WITH_INPUT_NDOF
static int view2d_ndof_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (event->type != NDOF_MOTION) {
@@ -1369,6 +1373,7 @@ static void VIEW2D_OT_ndof(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_LOCK_BYPASS;
}
+#endif /* WITH_INPUT_NDOF */
/* ********************************************************* */
/* SMOOTH VIEW */
@@ -2067,7 +2072,9 @@ void ED_operatortypes_view2d(void)
WM_operatortype_append(VIEW2D_OT_zoom);
WM_operatortype_append(VIEW2D_OT_zoom_border);
+#ifdef WITH_INPUT_NDOF
WM_operatortype_append(VIEW2D_OT_ndof);
+#endif
WM_operatortype_append(VIEW2D_OT_smoothview);
@@ -2097,7 +2104,9 @@ void ED_keymap_view2d(wmKeyConfig *keyconf)
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);
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index 7a7c42e501b..ca4ab30a08d 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -31,9 +31,13 @@
# include "BLI_winstuff.h"
#endif
+#include <string.h>
+#include <errno.h>
+
#include "MEM_guardedalloc.h"
#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_space_types.h"
@@ -67,9 +71,19 @@
static int wm_alembic_export_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ RNA_boolean_set(op->ptr, "init_scene_frame_range", true);
+
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ Main *bmain = CTX_data_main(C);
char filepath[FILE_MAX];
- BLI_strncpy(filepath, G.main->name, sizeof(filepath));
+
+ if (bmain->name[0] == '\0') {
+ BLI_strncpy(filepath, "untitled", sizeof(filepath));
+ }
+ else {
+ BLI_strncpy(filepath, bmain->name, sizeof(filepath));
+ }
+
BLI_replace_extension(filepath, sizeof(filepath), ".abc");
RNA_string_set(op->ptr, "filepath", filepath);
}
@@ -91,12 +105,12 @@ static int wm_alembic_export_exec(bContext *C, wmOperator *op)
char filename[FILE_MAX];
RNA_string_get(op->ptr, "filepath", filename);
- const struct AlembicExportParams params = {
+ struct AlembicExportParams params = {
.frame_start = RNA_int_get(op->ptr, "start"),
.frame_end = RNA_int_get(op->ptr, "end"),
- .frame_step_xform = 1.0 / (double)RNA_int_get(op->ptr, "xsamples"),
- .frame_step_shape = 1.0 / (double)RNA_int_get(op->ptr, "gsamples"),
+ .frame_samples_xform = RNA_int_get(op->ptr, "xsamples"),
+ .frame_samples_shape = RNA_int_get(op->ptr, "gsamples"),
.shutter_open = RNA_float_get(op->ptr, "sh_open"),
.shutter_close = RNA_float_get(op->ptr, "sh_close"),
@@ -111,23 +125,40 @@ static int wm_alembic_export_exec(bContext *C, wmOperator *op)
.renderable_only = RNA_boolean_get(op->ptr, "renderable_only"),
.face_sets = RNA_boolean_get(op->ptr, "face_sets"),
.use_subdiv_schema = RNA_boolean_get(op->ptr, "subdiv_schema"),
+ .export_hair = RNA_boolean_get(op->ptr, "export_hair"),
+ .export_particles = RNA_boolean_get(op->ptr, "export_particles"),
.compression_type = RNA_enum_get(op->ptr, "compression_type"),
.packuv = RNA_boolean_get(op->ptr, "packuv"),
+ .triangulate = RNA_boolean_get(op->ptr, "triangulate"),
+ .quad_method = RNA_enum_get(op->ptr, "quad_method"),
+ .ngon_method = RNA_enum_get(op->ptr, "ngon_method"),
.global_scale = RNA_float_get(op->ptr, "global_scale"),
};
- ABC_export(CTX_data_scene(C), C, filename, &params);
+ /* Take some defaults from the scene, if not specified explicitly. */
+ Scene *scene = CTX_data_scene(C);
+ if (params.frame_start == INT_MIN) {
+ params.frame_start = SFRA;
+ }
+ if (params.frame_end == INT_MIN) {
+ params.frame_end = EFRA;
+ }
+
+ const bool as_background_job = RNA_boolean_get(op->ptr, "as_background_job");
+ bool ok = ABC_export(scene, C, filename, &params, as_background_job);
- return OPERATOR_FINISHED;
+ return as_background_job || ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
static void ui_alembic_export_settings(uiLayout *layout, PointerRNA *imfptr)
{
- uiLayout *box = uiLayoutBox(layout);
+ uiLayout *box;
uiLayout *row;
+ uiLayout *col;
#ifdef WITH_ALEMBIC_HDF5
+ box = uiLayoutBox(layout);
row = uiLayoutRow(box, false);
uiItemL(row, IFACE_("Archive Options:"), ICON_NONE);
@@ -203,41 +234,96 @@ static void ui_alembic_export_settings(uiLayout *layout, PointerRNA *imfptr)
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "apply_subdiv", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "triangulate", 0, NULL, ICON_NONE);
+
+ const bool triangulate = RNA_boolean_get(imfptr, "triangulate");
+
+ row = uiLayoutRow(box, false);
+ uiLayoutSetEnabled(row, triangulate);
+ uiItemR(row, imfptr, "quad_method", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiLayoutSetEnabled(row, triangulate);
+ uiItemR(row, imfptr, "ngon_method", 0, NULL, ICON_NONE);
+
+ /* Object Data */
+ box = uiLayoutBox(layout);
+ row = uiLayoutRow(box, false);
+ uiItemL(row, IFACE_("Particle Systems:"), ICON_PARTICLE_DATA);
+
+ col = uiLayoutColumn(box, true);
+ uiItemR(col, imfptr, "export_hair", 0, NULL, ICON_NONE);
+ uiItemR(col, imfptr, "export_particles", 0, NULL, ICON_NONE);
}
-static void wm_alembic_export_draw(bContext *UNUSED(C), wmOperator *op)
+static void wm_alembic_export_draw(bContext *C, wmOperator *op)
{
PointerRNA ptr;
RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+
+ /* Conveniently set start and end frame to match the scene's frame range. */
+ Scene *scene = CTX_data_scene(C);
+
+ if (scene != NULL && RNA_boolean_get(&ptr, "init_scene_frame_range")) {
+ RNA_int_set(&ptr, "start", SFRA);
+ RNA_int_set(&ptr, "end", EFRA);
+
+ RNA_boolean_set(&ptr, "init_scene_frame_range", false);
+ }
+
ui_alembic_export_settings(op->layout, &ptr);
}
+static bool wm_alembic_export_check(bContext *UNUSED(C), wmOperator *op)
+{
+ char filepath[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filepath);
+
+ if (!BLI_testextensie(filepath, ".abc")) {
+ BLI_ensure_extension(filepath, FILE_MAX, ".abc");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ return true;
+ }
+
+ return false;
+}
+
void WM_OT_alembic_export(wmOperatorType *ot)
{
- ot->name = "Export Alembic Archive";
+ ot->name = "Export Alembic";
+ ot->description = "Export current scene in an Alembic archive";
ot->idname = "WM_OT_alembic_export";
ot->invoke = wm_alembic_export_invoke;
ot->exec = wm_alembic_export_exec;
ot->poll = WM_operator_winactive;
ot->ui = wm_alembic_export_draw;
+ ot->check = wm_alembic_export_check;
WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH,
FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
- RNA_def_int(ot->srna, "start", 1, INT_MIN, INT_MAX,
- "Start Frame", "Start Frame", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "start", INT_MIN, INT_MIN, INT_MAX,
+ "Start Frame",
+ "Start frame of the export, use the default value to "
+ "take the start frame of the current scene",
+ INT_MIN, INT_MAX);
- RNA_def_int(ot->srna, "end", 1, INT_MIN, INT_MAX,
- "End Frame", "End Frame", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "end", INT_MIN, INT_MIN, INT_MAX,
+ "End Frame",
+ "End frame of the export, use the default value to "
+ "take the end frame of the current scene",
+ INT_MIN, INT_MAX);
RNA_def_int(ot->srna, "xsamples", 1, 1, 128,
"Transform Samples", "Number of times per frame transformations are sampled", 1, 128);
RNA_def_int(ot->srna, "gsamples", 1, 1, 128,
- "Geometry Samples", "Number of times per frame object datas are sampled", 1, 128);
+ "Geometry Samples", "Number of times per frame object data are sampled", 1, 128);
RNA_def_float(ot->srna, "sh_open", 0.0f, -1.0f, 1.0f,
"Shutter Open", "Time at which the shutter is open", -1.0f, 1.0f);
@@ -266,7 +352,7 @@ void WM_OT_alembic_export(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "normals", 1, "Normals", "Export normals");
- RNA_def_boolean(ot->srna, "vcolors", 0, "Vertex colors", "Export vertex colors");
+ RNA_def_boolean(ot->srna, "vcolors", 0, "Vertex Colors", "Export vertex colors");
RNA_def_boolean(ot->srna, "face_sets", 0, "Face Sets", "Export per face shading group assignments");
@@ -283,6 +369,26 @@ void WM_OT_alembic_export(wmOperatorType *ot)
RNA_def_float(ot->srna, "global_scale", 1.0f, 0.0001f, 1000.0f, "Scale",
"Value by which to enlarge or shrink the objects with respect to the world's origin",
0.0001f, 1000.0f);
+
+ RNA_def_boolean(ot->srna, "triangulate", false, "Triangulate",
+ "Export Polygons (Quads & NGons) as Triangles");
+
+ RNA_def_enum(ot->srna, "quad_method", rna_enum_modifier_triangulate_quad_method_items,
+ MOD_TRIANGULATE_QUAD_SHORTEDGE, "Quad Method", "Method for splitting the quads into triangles");
+
+ RNA_def_enum(ot->srna, "ngon_method", rna_enum_modifier_triangulate_quad_method_items,
+ MOD_TRIANGULATE_NGON_BEAUTY, "Polygon Method", "Method for splitting the polygons into triangles");
+
+ RNA_def_boolean(ot->srna, "export_hair", 1, "Export Hair", "Exports hair particle systems as animated curves");
+ RNA_def_boolean(ot->srna, "export_particles", 1, "Export Particles", "Exports non-hair particle systems");
+
+ RNA_def_boolean(ot->srna, "as_background_job", true, "Run as Background Job",
+ "Enable this to run the import in the background, disable to block Blender while importing");
+
+ /* This dummy prop is used to check whether we need to init the start and
+ * end frame values to that of the scene's, otherwise they are reset at
+ * every change, draw update. */
+ RNA_def_boolean(ot->srna, "init_scene_frame_range", false, "", "");
}
/* ************************************************************************** */
@@ -314,9 +420,20 @@ static int get_sequence_len(char *filename, int *ofs)
}
char path[FILE_MAX];
+ BLI_path_abs(filename, G.main->name);
BLI_split_dir_part(filename, path, FILE_MAX);
+ if (path[0] == '\0') {
+ /* The filename had no path, so just use the blend file path. */
+ BLI_split_dir_part(G.main->name, path, FILE_MAX);
+ }
+
DIR *dir = opendir(path);
+ if (dir == NULL) {
+ fprintf(stderr, "Error opening directory '%s': %s\n",
+ path, errno ? strerror(errno) : "unknown error");
+ return -1;
+ }
const char *ext = ".abc";
const char *basename = BLI_path_basename(filename);
@@ -413,22 +530,30 @@ static int wm_alembic_import_exec(bContext *C, wmOperator *op)
const bool is_sequence = RNA_boolean_get(op->ptr, "is_sequence");
const bool set_frame_range = RNA_boolean_get(op->ptr, "set_frame_range");
const bool validate_meshes = RNA_boolean_get(op->ptr, "validate_meshes");
+ const bool as_background_job = RNA_boolean_get(op->ptr, "as_background_job");
int offset = 0;
int sequence_len = 1;
if (is_sequence) {
sequence_len = get_sequence_len(filename, &offset);
+ if (sequence_len < 0) {
+ BKE_report(op->reports, RPT_ERROR, "Unable to determine ABC sequence length");
+ return OPERATOR_CANCELLED;
+ }
}
- ABC_import(C, filename, scale, is_sequence, set_frame_range, sequence_len, offset, validate_meshes);
+ bool ok = ABC_import(C, filename, scale, is_sequence, set_frame_range,
+ sequence_len, offset, validate_meshes,
+ as_background_job);
- return OPERATOR_FINISHED;
+ return as_background_job || ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void WM_OT_alembic_import(wmOperatorType *ot)
{
- ot->name = "Import Alembic Archive";
+ ot->name = "Import Alembic";
+ ot->description = "Load an Alembic archive";
ot->idname = "WM_OT_alembic_import";
ot->invoke = WM_operator_filesel;
@@ -453,6 +578,9 @@ void WM_OT_alembic_import(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "is_sequence", false, "Is Sequence",
"Set to true if the cache is split into separate files");
+
+ RNA_def_boolean(ot->srna, "as_background_job", true, "Run as Background Job",
+ "Enable this to run the export in the background, disable to block Blender while exporting");
}
#endif
diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c
index d6e2c1ae204..a5e90ebbe7a 100644
--- a/source/blender/editors/io/io_cache.c
+++ b/source/blender/editors/io/io_cache.c
@@ -59,7 +59,9 @@ static int cachefile_open_invoke(bContext *C, wmOperator *op, const wmEvent *eve
{
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
char filepath[FILE_MAX];
- BLI_strncpy(filepath, G.main->name, sizeof(filepath));
+ Main *bmain = CTX_data_main(C);
+
+ BLI_strncpy(filepath, bmain->name, sizeof(filepath));
BLI_replace_extension(filepath, sizeof(filepath), ".abc");
RNA_string_set(op->ptr, "filepath", filepath);
}
@@ -95,28 +97,31 @@ static int cachefile_open_exec(bContext *C, wmOperator *op)
BLI_strncpy(cache_file->filepath, filename, FILE_MAX);
BKE_cachefile_reload(bmain, cache_file);
- /* hook into UI */
- PropertyPointerRNA *pprop = op->customdata;
-
- if (pprop->prop) {
- /* when creating new ID blocks, use is already 1, but RNA
- * pointer se also increases user, so this compensates it */
- id_us_min(&cache_file->id);
-
- PointerRNA idptr;
- RNA_id_pointer_create(&cache_file->id, &idptr);
- RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr);
- RNA_property_update(C, &pprop->ptr, pprop->prop);
+ /* Will be set when running invoke, not exec directly. */
+ if (op->customdata != NULL) {
+ /* hook into UI */
+ PropertyPointerRNA *pprop = op->customdata;
+ if (pprop->prop) {
+ /* when creating new ID blocks, use is already 1, but RNA
+ * pointer se also increases user, so this compensates it */
+ id_us_min(&cache_file->id);
+
+ PointerRNA idptr;
+ RNA_id_pointer_create(&cache_file->id, &idptr);
+ RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr);
+ RNA_property_update(C, &pprop->ptr, pprop->prop);
+ }
+
+ MEM_freeN(op->customdata);
}
- MEM_freeN(op->customdata);
-
return OPERATOR_FINISHED;
}
void CACHEFILE_OT_open(wmOperatorType *ot)
{
ot->name = "Open Cache File";
+ ot->description = "Load a cache file";
ot->idname = "CACHEFILE_OT_open";
ot->invoke = cachefile_open_invoke;
@@ -140,7 +145,7 @@ static int cachefile_reload_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
- BLI_listbase_clear(&cache_file->object_paths);
+ BLI_freelistN(&cache_file->object_paths);
BKE_cachefile_reload(bmain, cache_file);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index d62651cef81..ba3966d5af6 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -87,7 +87,6 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
int include_shapekeys;
int deform_bones_only;
- int include_uv_textures;
int include_material_textures;
int use_texture_copies;
int active_uv_only;
@@ -97,7 +96,10 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
int use_blender_profile;
int sort_by_name;
int export_transformation_type;
+
int open_sim;
+ int limit_precision;
+ int keep_bind_info;
int export_count;
@@ -136,7 +138,6 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
include_shapekeys = RNA_boolean_get(op->ptr, "include_shapekeys");
deform_bones_only = RNA_boolean_get(op->ptr, "deform_bones_only");
- include_uv_textures = RNA_boolean_get(op->ptr, "include_uv_textures");
include_material_textures = RNA_boolean_get(op->ptr, "include_material_textures");
use_texture_copies = RNA_boolean_get(op->ptr, "use_texture_copies");
active_uv_only = RNA_boolean_get(op->ptr, "active_uv_only");
@@ -148,11 +149,15 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
export_transformation_type = RNA_enum_get(op->ptr, "export_transformation_type_selection");
open_sim = RNA_boolean_get(op->ptr, "open_sim");
+ limit_precision = RNA_boolean_get(op->ptr, "limit_precision");
+ keep_bind_info = RNA_boolean_get(op->ptr, "keep_bind_info");
+
/* get editmode results */
ED_object_editmode_load(CTX_data_edit_object(C));
export_count = collada_export(CTX_data_scene(C),
+ CTX_data_scene_layer(C),
filepath,
apply_modifiers,
export_mesh_type,
@@ -163,7 +168,6 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
deform_bones_only,
active_uv_only,
- include_uv_textures,
include_material_textures,
use_texture_copies,
@@ -172,7 +176,11 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
use_blender_profile,
sort_by_name,
export_transformation_type,
- open_sim);
+
+ open_sim,
+ limit_precision,
+ keep_bind_info
+ );
if (export_count == 0) {
BKE_report(op->reports, RPT_WARNING, "No objects selected -- Created empty export file");
@@ -231,9 +239,6 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(row, imfptr, "active_uv_only", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "include_uv_textures", 0, NULL, ICON_NONE);
-
- row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "include_material_textures", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
@@ -256,11 +261,11 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr)
uiItemL(row, IFACE_("Collada Options:"), ICON_MODIFIER);
row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "triangulate", 0, NULL, ICON_NONE);
+ uiItemR(row, imfptr, "triangulate", 1, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "use_object_instantiation", 0, NULL, ICON_NONE);
+ uiItemR(row, imfptr, "use_object_instantiation", 1, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "use_blender_profile", 0, NULL, ICON_NONE);
+ uiItemR(row, imfptr, "use_blender_profile", 1, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
split = uiLayoutSplit(row, 0.6f, UI_LAYOUT_ALIGN_RIGHT);
@@ -270,6 +275,12 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr)
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)
@@ -280,8 +291,24 @@ static void wm_collada_export_draw(bContext *UNUSED(C), wmOperator *op)
uiCollada_exportSettings(op->layout, &ptr);
}
+static bool wm_collada_export_check(bContext *UNUSED(C), wmOperator *op)
+{
+ char filepath[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filepath);
+
+ if (!BLI_testextensie(filepath, ".dae")) {
+ BLI_ensure_extension(filepath, FILE_MAX, ".dae");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ return true;
+ }
+
+ return false;
+}
+
void WM_OT_collada_export(wmOperatorType *ot)
{
+ struct StructRNA *func = ot->srna;
+
static EnumPropertyItem prop_bc_export_mesh_type[] = {
{BC_MESH_TYPE_VIEW, "view", 0, "View", "Apply modifier's view settings"},
{BC_MESH_TYPE_RENDER, "render", 0, "Render", "Apply modifier's render settings"},
@@ -291,7 +318,6 @@ void WM_OT_collada_export(wmOperatorType *ot)
static EnumPropertyItem prop_bc_export_transformation_type[] = {
{BC_TRANSFORMATION_TYPE_MATRIX, "matrix", 0, "Matrix", "Use <matrix> to specify transformations"},
{BC_TRANSFORMATION_TYPE_TRANSROTLOC, "transrotloc", 0, "TransRotLoc", "Use <translate>, <rotate>, <scale> to specify transformations"},
- {BC_TRANSFORMATION_TYPE_BOTH, "both", 0, "Both", "Use <matrix> AND <translate>, <rotate>, <scale> to specify transformations"},
{0, NULL, 0, NULL, NULL}
};
@@ -302,6 +328,7 @@ void WM_OT_collada_export(wmOperatorType *ot)
ot->invoke = wm_collada_export_invoke;
ot->exec = wm_collada_export_exec;
ot->poll = WM_operator_winactive;
+ ot->check = wm_collada_export_check;
ot->flag |= OPTYPE_PRESET;
@@ -311,65 +338,69 @@ 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_boolean(ot->srna,
+ RNA_def_boolean(func,
"apply_modifiers", 0, "Apply Modifiers",
"Apply modifiers to exported mesh (non destructive))");
- RNA_def_int(ot->srna, "export_mesh_type", 0, INT_MIN, INT_MAX,
+ RNA_def_int(func, "export_mesh_type", 0, INT_MIN, INT_MAX,
"Resolution", "Modifier resolution for export", INT_MIN, INT_MAX);
- RNA_def_enum(ot->srna, "export_mesh_type_selection", prop_bc_export_mesh_type, 0,
+ RNA_def_enum(func, "export_mesh_type_selection", prop_bc_export_mesh_type, 0,
"Resolution", "Modifier resolution for export");
- RNA_def_boolean(ot->srna, "selected", 0, "Selection Only",
+ RNA_def_boolean(func, "selected", 0, "Selection Only",
"Export only selected elements");
- RNA_def_boolean(ot->srna, "include_children", 0, "Include Children",
+ RNA_def_boolean(func, "include_children", 0, "Include Children",
"Export all children of selected objects (even if not selected)");
- RNA_def_boolean(ot->srna, "include_armatures", 0, "Include Armatures",
+ RNA_def_boolean(func, "include_armatures", 0, "Include Armatures",
"Export related armatures (even if not selected)");
- RNA_def_boolean(ot->srna, "include_shapekeys", 1, "Include Shape Keys",
+ RNA_def_boolean(func, "include_shapekeys", 1, "Include Shape Keys",
"Export all Shape Keys from Mesh Objects");
- RNA_def_boolean(ot->srna, "deform_bones_only", 0, "Deform Bones only",
+ RNA_def_boolean(func, "deform_bones_only", 0, "Deform Bones only",
"Only export deforming bones with armatures");
- RNA_def_boolean(ot->srna, "active_uv_only", 0, "Only Selected UV Map",
+ RNA_def_boolean(func, "active_uv_only", 0, "Only Selected UV Map",
"Export only the selected UV Map");
- RNA_def_boolean(ot->srna, "include_uv_textures", 0, "Include UV Textures",
- "Export textures assigned to the object UV Maps");
-
- RNA_def_boolean(ot->srna, "include_material_textures", 0, "Include Material Textures",
+ RNA_def_boolean(func, "include_material_textures", 0, "Include Material Textures",
"Export textures assigned to the object Materials");
- RNA_def_boolean(ot->srna, "use_texture_copies", 1, "Copy",
+ RNA_def_boolean(func, "use_texture_copies", 1, "Copy",
"Copy textures to same folder where the .dae file is exported");
- RNA_def_boolean(ot->srna, "triangulate", 1, "Triangulate",
+ RNA_def_boolean(func, "triangulate", 1, "Triangulate",
"Export Polygons (Quads & NGons) as Triangles");
- RNA_def_boolean(ot->srna, "use_object_instantiation", 1, "Use Object Instances",
+ RNA_def_boolean(func, "use_object_instantiation", 1, "Use Object Instances",
"Instantiate multiple Objects from same Data");
- RNA_def_boolean(ot->srna, "use_blender_profile", 1, "Use Blender Profile",
+ RNA_def_boolean(func, "use_blender_profile", 1, "Use Blender Profile",
"Export additional Blender specific information (for material, shaders, bones, etc.)");
- RNA_def_boolean(ot->srna, "sort_by_name", 0, "Sort by Object name",
+ RNA_def_boolean(func, "sort_by_name", 0, "Sort by Object name",
"Sort exported data by Object name");
- RNA_def_int(ot->srna, "export_transformation_type", 0, INT_MIN, INT_MAX,
+ RNA_def_int(func, "export_transformation_type", 0, INT_MIN, INT_MAX,
"Transform", "Transformation type for translation, scale and rotation", INT_MIN, INT_MAX);
- RNA_def_enum(ot->srna, "export_transformation_type_selection", prop_bc_export_transformation_type, 0,
+ RNA_def_enum(func, "export_transformation_type_selection", prop_bc_export_transformation_type, 0,
"Transform", "Transformation type for translation, scale and rotation");
- RNA_def_boolean(ot->srna, "open_sim", 0, "Export to SL/OpenSim",
+ RNA_def_boolean(func, "open_sim", 0, "Export to SL/OpenSim",
"Compatibility mode for SL, OpenSim and other compatible online worlds");
+
+ RNA_def_boolean(func, "limit_precision", 0,
+ "Limit Precision", "Reduce the precision of the exported data to 6 digits");
+
+ RNA_def_boolean(func, "keep_bind_info", 0,
+ "Keep Bind Info", "Store Bindpose information in custom bone properties for later use during Collada export");
+
}
@@ -381,7 +412,9 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
int find_chains;
int auto_connect;
int fix_orientation;
- int min_chain_length;
+ int min_chain_length;
+
+ int keep_bind_info;
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
BKE_report(op->reports, RPT_ERROR, "No filename given");
@@ -393,6 +426,9 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
find_chains = RNA_boolean_get(op->ptr, "find_chains");
auto_connect = RNA_boolean_get(op->ptr, "auto_connect");
fix_orientation = RNA_boolean_get(op->ptr, "fix_orientation");
+
+ keep_bind_info = RNA_boolean_get(op->ptr, "keep_bind_info");
+
min_chain_length = RNA_int_get(op->ptr, "min_chain_length");
RNA_string_get(op->ptr, "filepath", filename);
@@ -402,7 +438,8 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
find_chains,
auto_connect,
fix_orientation,
- min_chain_length))
+ min_chain_length,
+ keep_bind_info) )
{
return OPERATOR_FINISHED;
}
@@ -439,6 +476,13 @@ static void uiCollada_importSettings(uiLayout *layout, PointerRNA *imfptr)
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "min_chain_length", 0, NULL, ICON_NONE);
+
+ box = uiLayoutBox(layout);
+ row = uiLayoutRow(box, false);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "keep_bind_info", 0, NULL, ICON_NONE);
+
}
static void wm_collada_import_draw(bContext *UNUSED(C), wmOperator *op)
@@ -494,5 +538,9 @@ void WM_OT_collada_import(wmOperatorType *ot)
0,
INT_MAX);
+ RNA_def_boolean(ot->srna,
+ "keep_bind_info", 0, "Keep Bind Info",
+ "Store Bindpose information in custom bone properties for later use during Collada export");
+
}
#endif
diff --git a/source/blender/editors/manipulator_library/CMakeLists.txt b/source/blender/editors/manipulator_library/CMakeLists.txt
new file mode 100644
index 00000000000..0604946dc24
--- /dev/null
+++ b/source/blender/editors/manipulator_library/CMakeLists.txt
@@ -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 *****
+
+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
+ manipulator_draw_utils.c
+ manipulator_geometry.h
+ manipulator_library_intern.h
+ manipulator_library_presets.c
+ manipulator_library_utils.c
+ geometry/geom_arrow_manipulator.c
+ geometry/geom_cube_manipulator.c
+ geometry/geom_dial_manipulator.c
+ manipulator_types/arrow2d_manipulator.c
+ manipulator_types/arrow3d_manipulator.c
+ manipulator_types/cage2d_manipulator.c
+ manipulator_types/dial3d_manipulator.c
+ manipulator_types/grab3d_manipulator.c
+ manipulator_types/primitive3d_manipulator.c
+)
+
+add_definitions(${GL_DEFINITIONS})
+
+blender_add_lib(bf_editor_manipulator_library "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/manipulator_library/geometry/geom_arrow_manipulator.c b/source/blender/editors/manipulator_library/geometry/geom_arrow_manipulator.c
new file mode 100644
index 00000000000..34f7d73589c
--- /dev/null
+++ b/source/blender/editors/manipulator_library/geometry/geom_arrow_manipulator.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_manipulator.c
+ * \ingroup wm
+ */
+
+#include "../manipulator_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,
+};
+
+ManipulatorGeomInfo wm_manipulator_geom_data_arrow = {
+ .nverts = 25,
+ .ntris = 46,
+ .verts = verts,
+ .normals = normals,
+ .indices = indices,
+};
diff --git a/source/blender/editors/manipulator_library/geometry/geom_cube_manipulator.c b/source/blender/editors/manipulator_library/geometry/geom_cube_manipulator.c
new file mode 100644
index 00000000000..cee8e1e22ee
--- /dev/null
+++ b/source/blender/editors/manipulator_library/geometry/geom_cube_manipulator.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_manipulator.c
+ * \ingroup wm
+ */
+
+#include "../manipulator_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,
+};
+
+ManipulatorGeomInfo wm_manipulator_geom_data_cube = {
+ .nverts = 8,
+ .ntris = 12,
+ .verts = verts,
+ .normals = normals,
+ .indices = indices,
+};
diff --git a/source/blender/editors/manipulator_library/geometry/geom_dial_manipulator.c b/source/blender/editors/manipulator_library/geometry/geom_dial_manipulator.c
new file mode 100644
index 00000000000..811fc872a81
--- /dev/null
+++ b/source/blender/editors/manipulator_library/geometry/geom_dial_manipulator.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_manipulator.c
+ * \ingroup wm
+ */
+
+#include "../manipulator_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,
+};
+
+ManipulatorGeomInfo wm_manipulator_geom_data_dial = {
+ .nverts = 192,
+ .ntris = 384,
+ .verts = verts,
+ .normals = normals,
+ .indices = indices,
+};
diff --git a/source/blender/editors/manipulator_library/manipulator_draw_utils.c b/source/blender/editors/manipulator_library/manipulator_draw_utils.c
new file mode 100644
index 00000000000..26f9ebbe54e
--- /dev/null
+++ b/source/blender/editors/manipulator_library/manipulator_draw_utils.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) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file manipulator_draw_utils.c
+ * \ingroup wm
+ */
+
+#include "BKE_context.h"
+
+#include "BLI_listbase.h"
+#include "BLI_ghash.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "GPU_batch.h"
+#include "GPU_glew.h"
+#include "GPU_immediate.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+/* only for own init/exit calls (wm_manipulatortype_init/wm_manipulatortype_free) */
+#include "wm.h"
+
+/* own includes */
+#include "manipulator_library_intern.h"
+
+/**
+ * Main draw call for ManipulatorGeomInfo data
+ */
+void wm_manipulator_geometryinfo_draw(const ManipulatorGeomInfo *info, const bool select, const float color[4])
+{
+ /* TODO store the Batches inside the ManipulatorGeomInfo and updated it when geom changes
+ * So we don't need to re-created and discard it every time */
+
+ const bool use_lighting = true || (!select && ((U.manipulator_flag & USER_MANIPULATOR_SHADED) != 0));
+ Gwn_VertBuf *vbo;
+ Gwn_IndexBuf *el;
+ Gwn_Batch *batch;
+ Gwn_IndexBufBuilder elb = {0};
+
+ Gwn_VertFormat format = {0};
+ uint pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ uint nor_id;
+
+ if (use_lighting) {
+ nor_id = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_I16, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ }
+
+ /* Elements */
+ GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, info->ntris, info->nverts);
+ for (int i = 0; i < info->ntris; ++i) {
+ const unsigned short *idx = &info->indices[i * 3];
+ GWN_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]);
+ }
+ el = GWN_indexbuf_build(&elb);
+
+ vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, info->nverts);
+
+ GWN_vertbuf_attr_fill(vbo, pos_id, info->verts);
+
+ if (use_lighting) {
+ /* Normals are expected to be smooth. */
+ GWN_vertbuf_attr_fill(vbo, nor_id, info->normals);
+ }
+
+ batch = GWN_batch_create(GWN_PRIM_TRIS, vbo, el);
+ Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR);
+
+ GWN_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);
+ glEnable(GL_DEPTH_TEST);
+#endif
+
+ GWN_batch_draw(batch);
+
+#if 0
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+#endif
+
+
+ GWN_batch_discard_all(batch);
+}
+
+void wm_manipulator_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/manipulator_library/manipulator_geometry.h b/source/blender/editors/manipulator_library/manipulator_geometry.h
new file mode 100644
index 00000000000..2083f9d4d31
--- /dev/null
+++ b/source/blender/editors/manipulator_library/manipulator_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 manipulator_geometry.h
+ * \ingroup wm
+ *
+ * \name Manipulator Geometry
+ *
+ * \brief Prototypes for arrays defining the manipulator geometry. The actual definitions can be found in files usually
+ * called geom_xxx_manipulator.c
+ */
+
+
+#ifndef __MANIPULATOR_GEOMETRY_H__
+#define __MANIPULATOR_GEOMETRY_H__
+
+typedef struct ManipulatorGeomInfo {
+ int nverts;
+ int ntris;
+ const float (*verts)[3];
+ const float (*normals)[3];
+ const unsigned short *indices;
+} ManipulatorGeomInfo;
+
+/* arrow manipulator */
+extern ManipulatorGeomInfo wm_manipulator_geom_data_arrow;
+
+/* cube manipulator */
+extern ManipulatorGeomInfo wm_manipulator_geom_data_cube;
+
+/* dial manipulator */
+extern ManipulatorGeomInfo wm_manipulator_geom_data_dial;
+
+#endif /* __MANIPULATOR_GEOMETRY_H__ */
diff --git a/source/blender/editors/manipulator_library/manipulator_library_intern.h b/source/blender/editors/manipulator_library/manipulator_library_intern.h
new file mode 100644
index 00000000000..ce71017e7bc
--- /dev/null
+++ b/source/blender/editors/manipulator_library/manipulator_library_intern.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 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file manipulator_library_intern.h
+ * \ingroup wm
+ */
+
+#ifndef __MANIPULATOR_LIBRARY_INTERN_H__
+#define __MANIPULATOR_LIBRARY_INTERN_H__
+
+/* distance around which manipulators respond to input (and get highlighted) */
+#define MANIPULATOR_HOTSPOT 14.0f
+
+/**
+ * Data for common interactions. Used in manipulator_library_utils.c functions.
+ */
+typedef struct ManipulatorCommonData {
+ int flag;
+
+ float range_fac; /* factor for arrow min/max distance */
+ float offset;
+
+ /* property range for constrained manipulators */
+ float range;
+ /* min/max value for constrained manipulators */
+ float min, max;
+} ManipulatorCommonData;
+
+typedef struct ManipulatorInteraction {
+ float init_value; /* initial property value */
+ float init_matrix[4][4];
+ float init_mval[2];
+ float init_offset;
+ float init_scale;
+
+ /* 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;
+} ManipulatorInteraction;
+
+/* ManipulatorCommonData->flag */
+enum {
+ MANIPULATOR_CUSTOM_RANGE_SET = (1 << 0),
+};
+
+
+float manipulator_offset_from_value(
+ ManipulatorCommonData *data, const float value,
+ const bool constrained, const bool inverted);
+float manipulator_value_from_offset(
+ ManipulatorCommonData *data, ManipulatorInteraction *inter, const float offset,
+ const bool constrained, const bool inverted, const bool use_precision);
+
+void manipulator_property_data_update(
+ struct wmManipulator *mpr, ManipulatorCommonData *data, wmManipulatorProperty *mpr_prop,
+ const bool constrained, const bool inverted);
+
+void manipulator_property_value_reset(
+ bContext *C, const struct wmManipulator *mpr, ManipulatorInteraction *inter, wmManipulatorProperty *mpr_prop);
+
+
+/* -------------------------------------------------------------------- */
+
+void manipulator_color_get(
+ const struct wmManipulator *mpr, const bool highlight,
+ float r_col[]);
+
+
+/* -------------------------------------------------------------------- */
+/* Manipulator drawing */
+
+#include "manipulator_geometry.h"
+
+void wm_manipulator_geometryinfo_draw(const struct ManipulatorGeomInfo *info, const bool select, const float color[4]);
+void wm_manipulator_vec_draw(
+ const float color[4], const float (*verts)[3], uint vert_count,
+ uint pos, uint primitive_type);
+
+
+#endif /* __MANIPULATOR_LIBRARY_INTERN_H__ */
+
diff --git a/source/blender/editors/manipulator_library/manipulator_library_presets.c b/source/blender/editors/manipulator_library/manipulator_library_presets.c
new file mode 100644
index 00000000000..d8e66f40be0
--- /dev/null
+++ b/source/blender/editors/manipulator_library/manipulator_library_presets.c
@@ -0,0 +1,151 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/manipulator_library/manipulator_library_presets.c
+ * \ingroup wm
+ *
+ * \name Manipulator Lib Presets
+ *
+ * \brief Preset shapes that can be drawn from any manipulator type.
+ */
+
+#include "BIF_gl.h"
+
+#include "BKE_context.h"
+
+#include "BLI_math.h"
+
+#include "DNA_view3d_types.h"
+#include "DNA_object_types.h"
+
+#include "ED_view3d.h"
+#include "ED_screen.h"
+
+#include "GPU_draw.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_select.h"
+
+#include "MEM_guardedalloc.h"
+
+
+#include "RNA_access.h"
+
+#include "WM_types.h"
+#include "WM_api.h"
+
+
+/* own includes */
+#include "ED_manipulator_library.h" /* own include */
+#include "manipulator_library_intern.h" /* own include */
+
+/* TODO, this is to be used by RNA. might move to ED_manipulator_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_manipulator_draw_preset_geometry(
+ const struct wmManipulator *mpr, float mat[4][4], int select_id,
+ const ManipulatorGeomInfo *info)
+{
+ const bool is_select = (select_id != -1);
+ const bool is_highlight = is_select && (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0;
+
+ float color[4];
+ manipulator_color_get(mpr, is_highlight, color);
+
+ if (is_select) {
+ GPU_select_load_id(select_id);
+ }
+
+ gpuPushMatrix();
+ gpuMultMatrix(mat);
+ wm_manipulator_geometryinfo_draw(info, is_select, color);
+ gpuPopMatrix();
+
+ if (is_select) {
+ GPU_select_load_id(-1);
+ }
+}
+
+void ED_manipulator_draw_preset_box(
+ const struct wmManipulator *mpr, float mat[4][4], int select_id)
+{
+ ed_manipulator_draw_preset_geometry(mpr, mat, select_id, &wm_manipulator_geom_data_cube);
+}
+
+void ED_manipulator_draw_preset_arrow(
+ const struct wmManipulator *mpr, float mat[4][4], int axis, int select_id)
+{
+ float mat_rotate[4][4];
+ single_axis_convert(OB_POSZ, mat, axis, mat_rotate);
+ ed_manipulator_draw_preset_geometry(mpr, mat_rotate, select_id, &wm_manipulator_geom_data_arrow);
+}
+
+void ED_manipulator_draw_preset_circle(
+ const struct wmManipulator *mpr, float mat[4][4], int axis, int select_id)
+{
+ float mat_rotate[4][4];
+ single_axis_convert(OB_POSZ, mat, axis, mat_rotate);
+ ed_manipulator_draw_preset_geometry(mpr, mat_rotate, select_id, &wm_manipulator_geom_data_dial);
+}
+
+void ED_manipulator_draw_preset_facemap(
+ const struct wmManipulator *mpr, struct Scene *scene, Object *ob, const int facemap, int select_id)
+{
+ const bool is_select = (select_id != -1);
+ const bool is_highlight = is_select && (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0;
+
+ float color[4];
+ manipulator_color_get(mpr, is_highlight, color);
+
+ if (is_select) {
+ GPU_select_load_id(select_id);
+ }
+
+ gpuPushMatrix();
+ gpuMultMatrix(ob->obmat);
+ ED_draw_object_facemap(scene, ob, color, facemap);
+ gpuPopMatrix();
+
+ if (is_select) {
+ GPU_select_load_id(-1);
+ }
+}
+
diff --git a/source/blender/editors/manipulator_library/manipulator_library_utils.c b/source/blender/editors/manipulator_library/manipulator_library_utils.c
new file mode 100644
index 00000000000..9c182fcf4bc
--- /dev/null
+++ b/source/blender/editors/manipulator_library/manipulator_library_utils.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) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file manipulator_library_utils.c
+ * \ingroup wm
+ *
+ * \name Manipulator Library Utilities
+ *
+ * \brief This file contains functions for common behaviors of manipulators.
+ */
+
+#include "BKE_context.h"
+
+#include "BLI_math.h"
+#include "BLI_listbase.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+/* own includes */
+#include "manipulator_library_intern.h"
+
+/* factor for precision tweaking */
+#define MANIPULATOR_PRECISION_FAC 0.05f
+
+
+BLI_INLINE float manipulator_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 manipulator_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 manipulator_offset_from_value(
+ ManipulatorCommonData *data, const float value, const bool constrained, const bool inverted)
+{
+ if (constrained)
+ return manipulator_offset_from_value_constr(data->range_fac, data->min, data->range, value, inverted);
+
+ return value;
+}
+
+float manipulator_value_from_offset(
+ ManipulatorCommonData *data, ManipulatorInteraction *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 - MANIPULATOR_PRECISION_FAC);
+ float value;
+
+ if (constrained) {
+ value = manipulator_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 & MANIPULATOR_CUSTOM_RANGE_SET) {
+ CLAMP(value, data->min, max);
+ }
+
+ return value;
+}
+
+void manipulator_property_data_update(
+ wmManipulator *mpr, ManipulatorCommonData *data, wmManipulatorProperty *mpr_prop,
+ const bool constrained, const bool inverted)
+{
+ if (mpr_prop->custom_func.value_get_fn != NULL) {
+ /* pass */
+ }
+ else if (mpr_prop->prop != NULL) {
+ /* pass */
+ }
+ else {
+ data->offset = 0.0f;
+ return;
+ }
+
+ float value = WM_manipulator_target_property_value_get(mpr, mpr_prop);
+
+ if (constrained) {
+ if ((data->flag & MANIPULATOR_CUSTOM_RANGE_SET) == 0) {
+ float range[2];
+ WM_manipulator_target_property_range_get(mpr, mpr_prop, range);
+ data->range = range[1] - range[0];
+ data->min = range[0];
+ }
+ data->offset = manipulator_offset_from_value_constr(data->range_fac, data->min, data->range, value, inverted);
+ }
+ else {
+ data->offset = value;
+ }
+}
+
+void manipulator_property_value_reset(
+ bContext *C, const wmManipulator *mpr, ManipulatorInteraction *inter,
+ wmManipulatorProperty *mpr_prop)
+{
+ WM_manipulator_target_property_value_set(C, mpr, mpr_prop, inter->init_value);
+}
+
+/* -------------------------------------------------------------------- */
+
+void manipulator_color_get(
+ const wmManipulator *mpr, const bool highlight,
+ float r_col[4])
+{
+ if (highlight && !(mpr->flag & WM_MANIPULATOR_DRAW_HOVER)) {
+ copy_v4_v4(r_col, mpr->color_hi);
+ }
+ else {
+ copy_v4_v4(r_col, mpr->color);
+ }
+}
diff --git a/source/blender/editors/manipulator_library/manipulator_types/arrow2d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/arrow2d_manipulator.c
new file mode 100644
index 00000000000..d402ab0b6f1
--- /dev/null
+++ b/source/blender/editors/manipulator_library/manipulator_types/arrow2d_manipulator.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) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file arrow2d_manipulator.c
+ * \ingroup wm
+ *
+ * \name 2D Arrow Manipulator
+ *
+ * \brief Simple arrow manipulator which is dragged into a certain direction.
+ */
+
+#include "BIF_gl.h"
+
+#include "BKE_context.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_rect.h"
+
+#include "DNA_windowmanager_types.h"
+
+#include "ED_screen.h"
+#include "ED_manipulator_library.h"
+
+#include "GPU_draw.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_types.h"
+
+/* own includes */
+#include "WM_api.h"
+
+#include "../manipulator_library_intern.h"
+
+static void arrow2d_draw_geom(wmManipulator *mpr, const float matrix[4][4], const float color[4])
+{
+ const float size = 0.11f;
+ const float size_h = size / 2.0f;
+ const float arrow_length = RNA_float_get(mpr->ptr, "length");
+ const float arrow_angle = RNA_float_get(mpr->ptr, "angle");
+ const float draw_line_ofs = (mpr->line_width * 0.5f) / mpr->scale_final;
+
+ uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ gpuPushMatrix();
+ gpuMultMatrix(matrix);
+ gpuScaleUniform(mpr->scale_final);
+ gpuRotate2D(RAD2DEGF(arrow_angle));
+ /* local offset */
+ gpuTranslate2f(
+ mpr->matrix_offset[3][0] + draw_line_ofs,
+ mpr->matrix_offset[3][1]);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor4fv(color);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2f(pos, 0.0f, 0.0f);
+ immVertex2f(pos, 0.0f, arrow_length);
+ immEnd();
+
+ immBegin(GWN_PRIM_TRIS, 3);
+ immVertex2f(pos, size_h, arrow_length);
+ immVertex2f(pos, -size_h, arrow_length);
+ immVertex2f(pos, 0.0f, arrow_length + size * 1.7f);
+ immEnd();
+
+ immUnbindProgram();
+
+ gpuPopMatrix();
+}
+
+static void manipulator_arrow2d_draw(const bContext *UNUSED(C), wmManipulator *mpr)
+{
+ float col[4];
+
+ manipulator_color_get(mpr, mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT, col);
+
+ glLineWidth(mpr->line_width);
+ glEnable(GL_BLEND);
+ arrow2d_draw_geom(mpr, mpr->matrix_basis, col);
+ glDisable(GL_BLEND);
+
+ if (mpr->interaction_data) {
+ ManipulatorInteraction *inter = mpr->interaction_data;
+
+ glEnable(GL_BLEND);
+ arrow2d_draw_geom(mpr, inter->init_matrix, (const float[4]){0.5f, 0.5f, 0.5f, 0.5f});
+ glDisable(GL_BLEND);
+ }
+}
+
+static void manipulator_arrow2d_setup(wmManipulator *mpr)
+{
+ mpr->flag |= WM_MANIPULATOR_DRAW_ACTIVE;
+}
+
+static void manipulator_arrow2d_invoke(
+ bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *UNUSED(event))
+{
+ ManipulatorInteraction *inter = MEM_callocN(sizeof(ManipulatorInteraction), __func__);
+
+ copy_m4_m4(inter->init_matrix, mpr->matrix_basis);
+ mpr->interaction_data = inter;
+}
+
+static int manipulator_arrow2d_test_select(
+ bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *event)
+{
+ const float mval[2] = {event->mval[0], event->mval[1]};
+ const float arrow_length = RNA_float_get(mpr->ptr, "length");
+ const float arrow_angle = RNA_float_get(mpr->ptr, "angle");
+ const float line_len = arrow_length * mpr->scale_final;
+ float mval_local[2];
+
+ copy_v2_v2(mval_local, mval);
+ sub_v2_v2(mval_local, mpr->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, MANIPULATOR_HOTSPOT + mpr->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] + MANIPULATOR_HOTSPOT * ((line[1][0] - line[0][0]) / line_len);
+ line_ext[1][1] = line[1][1] + MANIPULATOR_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) {
+ return IN_RANGE_INCL(lambda_1, 0.0f, 1.0f);
+ }
+ else {
+ BLI_assert(isect == 2);
+ const float lambda_2 = line_point_factor_v2(isect_2, line_ext[0], line_ext[1]);
+ return IN_RANGE_INCL(lambda_1, 0.0f, 1.0f) && IN_RANGE_INCL(lambda_2, 0.0f, 1.0f);
+ }
+ }
+
+ return 0;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name 2D Arrow Manipulator API
+ *
+ * \{ */
+
+static void MANIPULATOR_WT_arrow_2d(wmManipulatorType *wt)
+{
+ /* identifiers */
+ wt->idname = "MANIPULATOR_WT_arrow_2d";
+
+ /* api callbacks */
+ wt->draw = manipulator_arrow2d_draw;
+ wt->setup = manipulator_arrow2d_setup;
+ wt->invoke = manipulator_arrow2d_invoke;
+ wt->test_select = manipulator_arrow2d_test_select;
+
+ wt->struct_size = sizeof(wmManipulator);
+
+ /* rna */
+ RNA_def_float(wt->srna, "length", 1.0f, 0.0f, FLT_MAX, "Arrow Line Length", "", 0.0f, FLT_MAX);
+ RNA_def_float_rotation(
+ wt->srna, "angle", 0, NULL, DEG2RADF(-360.0f), DEG2RADF(360.0f),
+ "Roll", "", DEG2RADF(-360.0f), DEG2RADF(360.0f));
+}
+
+void ED_manipulatortypes_arrow_2d(void)
+{
+ WM_manipulatortype_append(MANIPULATOR_WT_arrow_2d);
+}
+
+/** \} */
diff --git a/source/blender/editors/manipulator_library/manipulator_types/arrow3d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/arrow3d_manipulator.c
new file mode 100644
index 00000000000..e95800f3db1
--- /dev/null
+++ b/source/blender/editors/manipulator_library/manipulator_types/arrow3d_manipulator.c
@@ -0,0 +1,494 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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_manipulator.c
+ * \ingroup wm
+ *
+ * \name Arrow Manipulator
+ *
+ * 3D Manipulator
+ *
+ * \brief Simple arrow manipulator 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 manipulator types that have an up.
+ * - `matrix[2]` is the arrow direction (for all arrowes).
+ */
+
+#include "BIF_gl.h"
+
+#include "BKE_context.h"
+
+#include "BLI_math.h"
+
+#include "DNA_view3d_types.h"
+
+#include "ED_view3d.h"
+#include "ED_screen.h"
+#include "ED_manipulator_library.h"
+
+#include "GPU_draw.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_select.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_types.h"
+#include "WM_api.h"
+
+/* own includes */
+#include "../manipulator_geometry.h"
+#include "../manipulator_library_intern.h"
+
+/* to use custom arrows exported to geom_arrow_manipulator.c */
+//#define USE_MANIPULATOR_CUSTOM_ARROWS
+
+typedef struct ArrowManipulator3D {
+ wmManipulator manipulator;
+ ManipulatorCommonData data;
+} ArrowManipulator3D;
+
+
+/* -------------------------------------------------------------------- */
+
+static void manipulator_arrow_matrix_world_get(wmManipulator *mpr, float r_matrix[4][4])
+{
+ ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr;
+
+ copy_m4_m4(r_matrix, arrow->manipulator.matrix_basis);
+ madd_v3_v3fl(r_matrix[3], arrow->manipulator.matrix_basis[2], arrow->data.offset);
+}
+
+static void arrow_draw_geom(const ArrowManipulator3D *arrow, const bool select, const float color[4])
+{
+ uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ bool unbind_shader = true;
+ const int draw_style = RNA_enum_get(arrow->manipulator.ptr, "draw_style");
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ if (draw_style == ED_MANIPULATOR_ARROW_STYLE_CROSS) {
+ immUniformColor4fv(color);
+
+ immBegin(GWN_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_MANIPULATOR_ARROW_STYLE_CONE) {
+ float aspect[2];
+ RNA_float_get_array(arrow->manipulator.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},
+ };
+
+ glLineWidth(arrow->manipulator.line_width);
+ wm_manipulator_vec_draw(color, vec, ARRAY_SIZE(vec), pos, GWN_PRIM_LINE_LOOP);
+ }
+ else {
+#ifdef USE_MANIPULATOR_CUSTOM_ARROWS
+ wm_manipulator_geometryinfo_draw(&wm_manipulator_geom_data_arrow, select, color);
+#else
+ const float arrow_length = RNA_float_get(arrow->manipulator.ptr, "length");
+
+ const float vec[2][3] = {
+ {0.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f, RNA_float_get(arrow->manipulator.ptr, "length")},
+ };
+
+ glLineWidth(arrow->manipulator.line_width);
+ wm_manipulator_vec_draw(color, vec, ARRAY_SIZE(vec), pos, GWN_PRIM_LINE_STRIP);
+
+
+ /* *** draw arrow head *** */
+
+ gpuPushMatrix();
+
+ if (draw_style == ED_MANIPULATOR_ARROW_STYLE_BOX) {
+ const float size = 0.05f;
+
+ /* translate to line end with some extra offset so box starts exactly where line ends */
+ gpuTranslate3f(0.0f, 0.0f, arrow_length + size);
+ /* scale down to box size */
+ gpuScale3f(size, size, size);
+
+ /* draw cube */
+ immUnbindProgram();
+ unbind_shader = false;
+ wm_manipulator_geometryinfo_draw(&wm_manipulator_geom_data_cube, select, color);
+ }
+ else {
+ BLI_assert(draw_style == ED_MANIPULATOR_ARROW_STYLE_NORMAL);
+
+ const float len = 0.25f;
+ const float width = 0.06f;
+ const bool use_lighting = (!select && ((U.manipulator_flag & USER_MANIPULATOR_SHADED) != 0));
+
+ /* translate to line end */
+ gpuTranslate3f(0.0f, 0.0f, arrow_length);
+
+ if (use_lighting) {
+ immUnbindProgram();
+ immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR);
+ }
+
+ imm_draw_circle_fill_3d(pos, 0.0, 0.0, width, 8);
+ imm_draw_cylinder_fill_3d(pos, width, 0.0, len, 8, 1);
+ }
+
+ gpuPopMatrix();
+#endif /* USE_MANIPULATOR_CUSTOM_ARROWS */
+ }
+
+ if (unbind_shader) {
+ immUnbindProgram();
+ }
+}
+
+static void arrow_draw_intern(ArrowManipulator3D *arrow, const bool select, const bool highlight)
+{
+ float col[4];
+ float final_matrix[4][4];
+
+ manipulator_color_get(&arrow->manipulator, highlight, col);
+ manipulator_arrow_matrix_world_get(&arrow->manipulator, final_matrix);
+
+ mul_mat3_m4_fl(final_matrix, arrow->manipulator.scale_final);
+ mul_m4_m4m4(final_matrix, final_matrix, arrow->manipulator.matrix_offset);
+
+ gpuPushMatrix();
+ gpuMultMatrix(final_matrix);
+ glEnable(GL_BLEND);
+ arrow_draw_geom(arrow, select, col);
+ glDisable(GL_BLEND);
+
+ gpuPopMatrix();
+
+ if (arrow->manipulator.interaction_data) {
+ ManipulatorInteraction *inter = arrow->manipulator.interaction_data;
+ float offset_matrix[4][4];
+
+ copy_m4_m4(offset_matrix, inter->init_matrix);
+ mul_mat3_m4_fl(offset_matrix, inter->init_scale);
+
+ gpuPushMatrix();
+ gpuMultMatrix(offset_matrix);
+ gpuMultMatrix(arrow->manipulator.matrix_offset);
+
+ glEnable(GL_BLEND);
+ arrow_draw_geom(arrow, select, (const float [4]){0.5f, 0.5f, 0.5f, 0.5f});
+ glDisable(GL_BLEND);
+
+ gpuPopMatrix();
+ }
+}
+
+static void manipulator_arrow_draw_select(
+ const bContext *UNUSED(C), wmManipulator *mpr,
+ int selectionbase)
+{
+ GPU_select_load_id(selectionbase);
+ arrow_draw_intern((ArrowManipulator3D *)mpr, true, false);
+}
+
+static void manipulator_arrow_draw(const bContext *UNUSED(C), wmManipulator *mpr)
+{
+ arrow_draw_intern((ArrowManipulator3D *)mpr, false, (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0);
+}
+
+/**
+ * Calculate arrow offset independent from prop min value,
+ * meaning the range will not be offset by min value first.
+ */
+static void manipulator_arrow_modal(bContext *C, wmManipulator *mpr, const wmEvent *event, const int flag)
+{
+ ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr;
+ ManipulatorInteraction *inter = mpr->interaction_data;
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+
+ float orig_origin[4];
+ float viewvec[3], tangent[3], plane[3];
+ float offset[4];
+ float m_diff[2];
+ float dir_2d[2], dir2d_final[2];
+ float facdir = 1.0f;
+ bool use_vertical = false;
+
+
+ copy_v3_v3(orig_origin, inter->init_matrix[3]);
+ orig_origin[3] = 1.0f;
+ add_v3_v3v3(offset, orig_origin, arrow->manipulator.matrix_basis[2]);
+ offset[3] = 1.0f;
+
+ /* calculate view vector */
+ if (rv3d->is_persp) {
+ sub_v3_v3v3(viewvec, orig_origin, rv3d->viewinv[3]);
+ }
+ else {
+ copy_v3_v3(viewvec, rv3d->viewinv[2]);
+ }
+ normalize_v3(viewvec);
+
+ /* first determine if view vector is really close to the direction. If it is, we use
+ * vertical movement to determine offset, just like transform system does */
+ if (RAD2DEG(acos(dot_v3v3(viewvec, arrow->manipulator.matrix_basis[2]))) > 5.0f) {
+ /* multiply to projection space */
+ mul_m4_v4(rv3d->persmat, orig_origin);
+ mul_v4_fl(orig_origin, 1.0f / orig_origin[3]);
+ mul_m4_v4(rv3d->persmat, offset);
+ mul_v4_fl(offset, 1.0f / offset[3]);
+
+ sub_v2_v2v2(dir_2d, offset, orig_origin);
+ dir_2d[0] *= ar->winx;
+ dir_2d[1] *= ar->winy;
+ normalize_v2(dir_2d);
+ }
+ else {
+ dir_2d[0] = 0.0f;
+ dir_2d[1] = 1.0f;
+ use_vertical = true;
+ }
+
+ /* find mouse difference */
+ m_diff[0] = event->mval[0] - inter->init_mval[0];
+ m_diff[1] = event->mval[1] - inter->init_mval[1];
+
+ /* project the displacement on the screen space arrow direction */
+ project_v2_v2v2(dir2d_final, m_diff, dir_2d);
+
+ float zfac = ED_view3d_calc_zfac(rv3d, orig_origin, NULL);
+ ED_view3d_win_to_delta(ar, dir2d_final, offset, zfac);
+
+ add_v3_v3v3(orig_origin, offset, inter->init_matrix[3]);
+
+ /* calculate view vector for the new position */
+ if (rv3d->is_persp) {
+ sub_v3_v3v3(viewvec, orig_origin, rv3d->viewinv[3]);
+ }
+ else {
+ copy_v3_v3(viewvec, rv3d->viewinv[2]);
+ }
+
+ normalize_v3(viewvec);
+ if (!use_vertical) {
+ /* now find a plane parallel to the view vector so we can intersect with the arrow direction */
+ cross_v3_v3v3(tangent, viewvec, offset);
+ cross_v3_v3v3(plane, tangent, viewvec);
+
+ const float plane_offset = dot_v3v3(plane, offset);
+ const float plane_dir = dot_v3v3(plane, arrow->manipulator.matrix_basis[2]);
+ const float fac = (plane_dir != 0.0f) ? (plane_offset / plane_dir) : 0.0f;
+ facdir = (fac < 0.0) ? -1.0 : 1.0;
+ if (isfinite(fac)) {
+ mul_v3_v3fl(offset, arrow->manipulator.matrix_basis[2], fac);
+ }
+ }
+ else {
+ facdir = (m_diff[1] < 0.0) ? -1.0 : 1.0;
+ }
+
+
+ ManipulatorCommonData *data = &arrow->data;
+ const float ofs_new = facdir * len_v3(offset);
+
+ wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_find(mpr, "offset");
+
+ /* set the property for the operator and call its modal function */
+ if (WM_manipulator_target_property_is_valid(mpr_prop)) {
+ const int draw_options = RNA_enum_get(arrow->manipulator.ptr, "draw_options");
+ const bool constrained = (draw_options & ED_MANIPULATOR_ARROW_STYLE_CONSTRAINED) != 0;
+ const bool inverted = (draw_options & ED_MANIPULATOR_ARROW_STYLE_INVERTED) != 0;
+ const bool use_precision = (flag & WM_MANIPULATOR_TWEAK_PRECISE) != 0;
+ float value = manipulator_value_from_offset(data, inter, ofs_new, constrained, inverted, use_precision);
+
+ WM_manipulator_target_property_value_set(C, mpr, mpr_prop, value);
+ /* get clamped value */
+ value = WM_manipulator_target_property_value_get(mpr, mpr_prop);
+
+ data->offset = manipulator_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);
+}
+
+static void manipulator_arrow_setup(wmManipulator *mpr)
+{
+ ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr;
+
+ arrow->manipulator.flag |= WM_MANIPULATOR_DRAW_ACTIVE;
+
+ arrow->data.range_fac = 1.0f;
+}
+
+static void manipulator_arrow_invoke(
+ bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *event)
+{
+ ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr;
+ ManipulatorInteraction *inter = MEM_callocN(sizeof(ManipulatorInteraction), __func__);
+ wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_find(mpr, "offset");
+
+ /* Some manipulators don't use properties. */
+ if (WM_manipulator_target_property_is_valid(mpr_prop)) {
+ inter->init_value = WM_manipulator_target_property_value_get(mpr, mpr_prop);
+ }
+
+ inter->init_offset = arrow->data.offset;
+
+ inter->init_mval[0] = event->mval[0];
+ inter->init_mval[1] = event->mval[1];
+
+ inter->init_scale = mpr->scale_final;
+
+ manipulator_arrow_matrix_world_get(mpr, inter->init_matrix);
+
+ mpr->interaction_data = inter;
+}
+
+static void manipulator_arrow_property_update(wmManipulator *mpr, wmManipulatorProperty *mpr_prop)
+{
+ ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr;
+ const int draw_options = RNA_enum_get(arrow->manipulator.ptr, "draw_options");
+ const bool constrained = (draw_options & ED_MANIPULATOR_ARROW_STYLE_CONSTRAINED) != 0;
+ const bool inverted = (draw_options & ED_MANIPULATOR_ARROW_STYLE_INVERTED) != 0;
+ manipulator_property_data_update(mpr, &arrow->data, mpr_prop, constrained, inverted);
+}
+
+static void manipulator_arrow_exit(bContext *C, wmManipulator *mpr, const bool cancel)
+{
+ if (!cancel)
+ return;
+
+ ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr;
+ ManipulatorCommonData *data = &arrow->data;
+ ManipulatorInteraction *inter = mpr->interaction_data;
+
+ wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_find(mpr, "offset");
+ manipulator_property_value_reset(C, mpr, inter, mpr_prop);
+ data->offset = inter->init_offset;
+}
+
+
+/* -------------------------------------------------------------------- */
+/** \name Arrow Manipulator API
+ *
+ * \{ */
+
+/**
+ * Define a custom property UI range
+ *
+ * \note Needs to be called before WM_manipulator_target_property_def_rna!
+ */
+void ED_manipulator_arrow3d_set_ui_range(wmManipulator *mpr, const float min, const float max)
+{
+ ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr;
+
+ BLI_assert(min < max);
+ BLI_assert(!(WM_manipulator_target_property_is_valid(WM_manipulator_target_property_find(mpr, "offset")) &&
+ "Make sure this function is called before WM_manipulator_target_property_def_rna"));
+
+ arrow->data.range = max - min;
+ arrow->data.min = min;
+ arrow->data.flag |= MANIPULATOR_CUSTOM_RANGE_SET;
+}
+
+/**
+ * Define a custom factor for arrow min/max distance
+ *
+ * \note Needs to be called before WM_manipulator_target_property_def_rna!
+ */
+void ED_manipulator_arrow3d_set_range_fac(wmManipulator *mpr, const float range_fac)
+{
+ ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr;
+ BLI_assert(!(WM_manipulator_target_property_is_valid(WM_manipulator_target_property_find(mpr, "offset")) &&
+ "Make sure this function is called before WM_manipulator_target_property_def_rna"));
+
+ arrow->data.range_fac = range_fac;
+}
+
+static void MANIPULATOR_WT_arrow_3d(wmManipulatorType *wt)
+{
+ /* identifiers */
+ wt->idname = "MANIPULATOR_WT_arrow_3d";
+
+ /* api callbacks */
+ wt->draw = manipulator_arrow_draw;
+ wt->draw_select = manipulator_arrow_draw_select;
+ wt->matrix_world_get = manipulator_arrow_matrix_world_get;
+ wt->modal = manipulator_arrow_modal;
+ wt->setup = manipulator_arrow_setup;
+ wt->invoke = manipulator_arrow_invoke;
+ wt->property_update = manipulator_arrow_property_update;
+ wt->exit = manipulator_arrow_exit;
+
+ wt->struct_size = sizeof(ArrowManipulator3D);
+
+ /* rna */
+ static EnumPropertyItem rna_enum_draw_style[] = {
+ {ED_MANIPULATOR_ARROW_STYLE_NORMAL, "NORMAL", 0, "Normal", ""},
+ {ED_MANIPULATOR_ARROW_STYLE_CROSS, "CROSS", 0, "Cross", ""},
+ {ED_MANIPULATOR_ARROW_STYLE_BOX, "BOX", 0, "Box", ""},
+ {ED_MANIPULATOR_ARROW_STYLE_CONE, "CONE", 0, "Cone", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ static EnumPropertyItem rna_enum_draw_options[] = {
+ {ED_MANIPULATOR_ARROW_STYLE_INVERTED, "INVERT", 0, "Inverted", ""},
+ {ED_MANIPULATOR_ARROW_STYLE_CONSTRAINED, "CONSTRAIN", 0, "Constrained", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ RNA_def_enum(wt->srna, "draw_style", rna_enum_draw_style, ED_MANIPULATOR_ARROW_STYLE_NORMAL, "Draw Style", "");
+ RNA_def_enum_flag(wt->srna, "draw_options", rna_enum_draw_options, 0, "Draw Options", "");
+
+ RNA_def_float(wt->srna, "length", 1.0f, 0.0f, FLT_MAX, "Arrow Line Length", "", 0.0f, FLT_MAX);
+ RNA_def_float_vector(wt->srna, "aspect", 2, NULL, 0, FLT_MAX, "Aspect", "Cone/box style only", 0.0f, FLT_MAX);
+
+ WM_manipulatortype_target_property_def(wt, "offset", PROP_FLOAT, 1);
+}
+
+void ED_manipulatortypes_arrow_3d(void)
+{
+ WM_manipulatortype_append(MANIPULATOR_WT_arrow_3d);
+}
+
+/** \} */
diff --git a/source/blender/editors/manipulator_library/manipulator_types/cage2d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/cage2d_manipulator.c
new file mode 100644
index 00000000000..973f487fd82
--- /dev/null
+++ b/source/blender/editors/manipulator_library/manipulator_types/cage2d_manipulator.c
@@ -0,0 +1,624 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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_manipulator.c
+ * \ingroup wm
+ *
+ * \name Cage Manipulator
+ *
+ * 2D Manipulator
+ *
+ * \brief Rectangular manipulator acting as a 'cage' around its content.
+ * Interacting scales or translates the manipulator.
+ */
+
+#include "BIF_gl.h"
+
+#include "BKE_context.h"
+
+#include "BLI_math.h"
+#include "BLI_rect.h"
+
+#include "ED_screen.h"
+#include "ED_manipulator_library.h"
+
+#include "GPU_matrix.h"
+#include "GPU_shader.h"
+#include "GPU_immediate.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+/* wmManipulator->highlight_part */
+enum {
+ ED_MANIPULATOR_RECT_TRANSFORM_INTERSECT_TRANSLATE = 1,
+ ED_MANIPULATOR_RECT_TRANSFORM_INTERSECT_SCALEX_LEFT = 2,
+ ED_MANIPULATOR_RECT_TRANSFORM_INTERSECT_SCALEX_RIGHT = 3,
+ ED_MANIPULATOR_RECT_TRANSFORM_INTERSECT_SCALEY_UP = 4,
+ ED_MANIPULATOR_RECT_TRANSFORM_INTERSECT_SCALEY_DOWN = 5,
+};
+
+#define MANIPULATOR_RECT_MIN_WIDTH 15.0f
+#define MANIPULATOR_RESIZER_WIDTH 20.0f
+
+
+/* -------------------------------------------------------------------- */
+
+static void rect_transform_draw_corners(
+ const rctf *r, const float offsetx, const float offsety, const float color[3])
+{
+ uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3fv(color);
+
+ immBegin(GWN_PRIM_LINES, 16);
+
+ immVertex2f(pos, r->xmin, r->ymin + offsety);
+ immVertex2f(pos, r->xmin, r->ymin);
+ immVertex2f(pos, r->xmin, r->ymin);
+ immVertex2f(pos, r->xmin + offsetx, r->ymin);
+
+ immVertex2f(pos, r->xmax, r->ymin + offsety);
+ immVertex2f(pos, r->xmax, r->ymin);
+ immVertex2f(pos, r->xmax, r->ymin);
+ immVertex2f(pos, r->xmax - offsetx, r->ymin);
+
+ immVertex2f(pos, r->xmax, r->ymax - offsety);
+ immVertex2f(pos, r->xmax, r->ymax);
+ immVertex2f(pos, r->xmax, r->ymax);
+ immVertex2f(pos, r->xmax - offsetx, r->ymax);
+
+ immVertex2f(pos, r->xmin, r->ymax - offsety);
+ immVertex2f(pos, r->xmin, r->ymax);
+ immVertex2f(pos, r->xmin, r->ymax);
+ immVertex2f(pos, r->xmin + offsetx, r->ymax);
+
+ immEnd();
+
+ immUnbindProgram();
+}
+
+static void rect_transform_draw_interaction(
+ const float col[4], const int highlighted,
+ const float half_w, const float half_h,
+ const float w, const float h, const float line_width)
+{
+ /* Why generate coordinates for 4 vertices, when we only use three? */
+ float verts[4][2];
+
+ switch (highlighted) {
+ case ED_MANIPULATOR_RECT_TRANSFORM_INTERSECT_SCALEX_LEFT:
+ verts[0][0] = -half_w + w;
+ verts[0][1] = -half_h;
+ verts[1][0] = -half_w;
+ verts[1][1] = -half_h;
+ verts[2][0] = -half_w;
+ verts[2][1] = half_h;
+ verts[3][0] = -half_w + w;
+ verts[3][1] = half_h;
+ break;
+
+ case ED_MANIPULATOR_RECT_TRANSFORM_INTERSECT_SCALEX_RIGHT:
+ verts[0][0] = half_w - w;
+ verts[0][1] = -half_h;
+ verts[1][0] = half_w;
+ verts[1][1] = -half_h;
+ verts[2][0] = half_w;
+ verts[2][1] = half_h;
+ verts[3][0] = half_w - w;
+ verts[3][1] = half_h;
+ break;
+
+ case ED_MANIPULATOR_RECT_TRANSFORM_INTERSECT_SCALEY_DOWN:
+ verts[0][0] = -half_w;
+ verts[0][1] = -half_h + h;
+ verts[1][0] = -half_w;
+ verts[1][1] = -half_h;
+ verts[2][0] = half_w;
+ verts[2][1] = -half_h;
+ verts[3][0] = half_w;
+ verts[3][1] = -half_h + h;
+ break;
+
+ case ED_MANIPULATOR_RECT_TRANSFORM_INTERSECT_SCALEY_UP:
+ verts[0][0] = -half_w;
+ verts[0][1] = half_h - h;
+ verts[1][0] = -half_w;
+ verts[1][1] = half_h;
+ verts[2][0] = half_w;
+ verts[2][1] = half_h;
+ verts[3][0] = half_w;
+ verts[3][1] = half_h - h;
+ break;
+
+ default:
+ return;
+ }
+
+ Gwn_VertFormat *format = immVertexFormat();
+ uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ uint color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+
+ glLineWidth(line_width + 3.0);
+
+ immBegin(GWN_PRIM_LINE_STRIP, 3);
+ immAttrib3f(color, 0.0f, 0.0f, 0.0f);
+ immVertex2fv(pos, verts[0]);
+ immVertex2fv(pos, verts[1]);
+ immVertex2fv(pos, verts[2]);
+ immEnd();
+
+ glLineWidth(line_width);
+
+ immBegin(GWN_PRIM_LINE_STRIP, 3);
+ immAttrib3fv(color, col);
+ immVertex2fv(pos, verts[0]);
+ immVertex2fv(pos, verts[1]);
+ immVertex2fv(pos, verts[2]);
+ immEnd();
+
+ immUnbindProgram();
+}
+
+static void manipulator_rect_transform_draw(const bContext *UNUSED(C), wmManipulator *mpr)
+{
+ float dims[2];
+ RNA_float_get_array(mpr->ptr, "dimensions", dims);
+ float w = dims[0];
+ float h = dims[1];
+
+ float scale[2];
+ RNA_float_get_array(mpr->ptr, "scale", scale);
+
+ const int transform_flag = RNA_enum_get(mpr->ptr, "transform");
+
+ float aspx = 1.0f, aspy = 1.0f;
+ const float half_w = w / 2.0f;
+ const float half_h = h / 2.0f;
+ const rctf r = {
+ .xmin = -half_w,
+ .ymin = -half_h,
+ .xmax = half_w,
+ .ymax = half_h,
+ };
+
+ gpuPushMatrix();
+ gpuMultMatrix(mpr->matrix_basis);
+ gpuMultMatrix(mpr->matrix_offset);
+ if (transform_flag & ED_MANIPULATOR_RECT_TRANSFORM_FLAG_SCALE_UNIFORM) {
+ gpuScaleUniform(scale[0]);
+ }
+ else {
+ gpuScale2fv(scale);
+ }
+
+ if (w > h) {
+ aspx = h / w;
+ }
+ else {
+ aspy = w / h;
+ }
+ w = min_ff(aspx * w / MANIPULATOR_RESIZER_WIDTH, MANIPULATOR_RESIZER_WIDTH / scale[0]);
+ h = min_ff(aspy * h / MANIPULATOR_RESIZER_WIDTH, MANIPULATOR_RESIZER_WIDTH /
+ ((transform_flag & ED_MANIPULATOR_RECT_TRANSFORM_FLAG_SCALE_UNIFORM) ? scale[0] : scale[1]));
+
+ /* corner manipulators */
+ glLineWidth(mpr->line_width + 3.0f);
+
+ rect_transform_draw_corners(&r, w, h, (const float[3]){0, 0, 0});
+
+ /* corner manipulators */
+ glLineWidth(mpr->line_width);
+ rect_transform_draw_corners(&r, w, h, mpr->color);
+
+ rect_transform_draw_interaction(
+ mpr->color, mpr->highlight_part, half_w, half_h,
+ w, h, mpr->line_width);
+
+ glLineWidth(1.0);
+ gpuPopMatrix();
+}
+
+static int manipulator_rect_transform_get_cursor(wmManipulator *mpr)
+{
+ switch (mpr->highlight_part) {
+ case ED_MANIPULATOR_RECT_TRANSFORM_INTERSECT_TRANSLATE:
+ return BC_HANDCURSOR;
+ case ED_MANIPULATOR_RECT_TRANSFORM_INTERSECT_SCALEX_LEFT:
+ case ED_MANIPULATOR_RECT_TRANSFORM_INTERSECT_SCALEX_RIGHT:
+ return CURSOR_X_MOVE;
+ case ED_MANIPULATOR_RECT_TRANSFORM_INTERSECT_SCALEY_DOWN:
+ case ED_MANIPULATOR_RECT_TRANSFORM_INTERSECT_SCALEY_UP:
+ return CURSOR_Y_MOVE;
+ default:
+ return CURSOR_STD;
+ }
+}
+
+static int manipulator_rect_transform_test_select(
+ bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *event)
+{
+ const float mouse[2] = {event->mval[0], event->mval[1]};
+ //float matrot[2][2];
+ float point_local[2];
+ float scale[2];
+ RNA_float_get_array(mpr->ptr, "scale", scale);
+ float dims[2];
+ RNA_float_get_array(mpr->ptr, "dimensions", dims);
+ float w = dims[0];
+ float h = dims[1];
+ float half_w = w / 2.0f;
+ float half_h = h / 2.0f;
+ float aspx = 1.0f, aspy = 1.0f;
+
+ const int transform_flag = RNA_enum_get(mpr->ptr, "transform");
+
+ /* rotate mouse in relation to the center and relocate it */
+ sub_v2_v2v2(point_local, mouse, mpr->matrix_basis[3]);
+ point_local[0] -= mpr->matrix_offset[3][0];
+ point_local[1] -= mpr->matrix_offset[3][1];
+ //rotate_m2(matrot, -cage->transform.rotation);
+
+ if (transform_flag & ED_MANIPULATOR_RECT_TRANSFORM_FLAG_SCALE_UNIFORM) {
+ mul_v2_fl(point_local, 1.0f / scale[0]);
+ }
+ else {
+ point_local[0] /= scale[0];
+ point_local[1] /= scale[0];
+ }
+
+ if (dims[0] > dims[1]) {
+ aspx = h / w;
+ }
+ else {
+ aspy = w / h;
+ }
+ w = min_ff(aspx * w / MANIPULATOR_RESIZER_WIDTH, MANIPULATOR_RESIZER_WIDTH / scale[0]);
+ h = min_ff(aspy * h / MANIPULATOR_RESIZER_WIDTH, MANIPULATOR_RESIZER_WIDTH /
+ ((transform_flag & ED_MANIPULATOR_RECT_TRANSFORM_FLAG_SCALE_UNIFORM) ? scale[0] : scale[1]));
+
+
+ rctf r;
+
+ r.xmin = -half_w + w;
+ r.ymin = -half_h + h;
+ r.xmax = half_w - w;
+ r.ymax = half_h - h;
+
+ bool isect = BLI_rctf_isect_pt_v(&r, point_local);
+
+ if (isect)
+ return ED_MANIPULATOR_RECT_TRANSFORM_INTERSECT_TRANSLATE;
+
+ /* if manipulator does not have a scale intersection, don't do it */
+ if (transform_flag &
+ (ED_MANIPULATOR_RECT_TRANSFORM_FLAG_SCALE | ED_MANIPULATOR_RECT_TRANSFORM_FLAG_SCALE_UNIFORM))
+ {
+ r.xmin = -half_w;
+ r.ymin = -half_h;
+ r.xmax = -half_w + w;
+ r.ymax = half_h;
+
+ isect = BLI_rctf_isect_pt_v(&r, point_local);
+
+ if (isect)
+ return ED_MANIPULATOR_RECT_TRANSFORM_INTERSECT_SCALEX_LEFT;
+
+ r.xmin = half_w - w;
+ r.ymin = -half_h;
+ r.xmax = half_w;
+ r.ymax = half_h;
+
+ isect = BLI_rctf_isect_pt_v(&r, point_local);
+
+ if (isect)
+ return ED_MANIPULATOR_RECT_TRANSFORM_INTERSECT_SCALEX_RIGHT;
+
+ r.xmin = -half_w;
+ r.ymin = -half_h;
+ r.xmax = half_w;
+ r.ymax = -half_h + h;
+
+ isect = BLI_rctf_isect_pt_v(&r, point_local);
+
+ if (isect)
+ return ED_MANIPULATOR_RECT_TRANSFORM_INTERSECT_SCALEY_DOWN;
+
+ r.xmin = -half_w;
+ r.ymin = half_h - h;
+ r.xmax = half_w;
+ r.ymax = half_h;
+
+ isect = BLI_rctf_isect_pt_v(&r, point_local);
+
+ if (isect)
+ return ED_MANIPULATOR_RECT_TRANSFORM_INTERSECT_SCALEY_UP;
+ }
+
+ return 0;
+}
+
+typedef struct RectTransformInteraction {
+ float orig_mouse[2];
+ float orig_offset[2];
+ float orig_scale[2];
+} RectTransformInteraction;
+
+static bool manipulator_rect_transform_get_prop_value(
+ wmManipulator *mpr, wmManipulatorProperty *mpr_prop, float *value)
+{
+ PropertyType type = RNA_property_type(mpr_prop->prop);
+
+ if (type != PROP_FLOAT) {
+ fprintf(stderr, "Rect Transform manipulator can only be bound to float properties");
+ return false;
+ }
+ else {
+ if (STREQ(mpr_prop->type->idname, "offset")) {
+ if (RNA_property_array_length(&mpr_prop->ptr, mpr_prop->prop) != 2) {
+ fprintf(stderr, "Rect Transform manipulator offset not only be bound to array float property");
+ return false;
+ }
+ RNA_property_float_get_array(&mpr_prop->ptr, mpr_prop->prop, value);
+ }
+ else if (STREQ(mpr_prop->type->idname, "scale")) {
+ const int transform_flag = RNA_enum_get(mpr->ptr, "transform");
+ if (transform_flag & ED_MANIPULATOR_RECT_TRANSFORM_FLAG_SCALE_UNIFORM) {
+ *value = RNA_property_float_get(&mpr_prop->ptr, mpr_prop->prop);
+ }
+ else {
+ if (RNA_property_array_length(&mpr_prop->ptr, mpr_prop->prop) != 2) {
+ fprintf(stderr, "Rect Transform manipulator scale not only be bound to array float property");
+ return false;
+ }
+ RNA_property_float_get_array(&mpr_prop->ptr, mpr_prop->prop, value);
+ }
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+
+ return true;
+}
+
+static void manipulator_rect_transform_setup(wmManipulator *mpr)
+{
+ mpr->flag |= WM_MANIPULATOR_DRAW_ACTIVE;
+}
+
+static void manipulator_rect_transform_invoke(
+ bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *event)
+{
+ RectTransformInteraction *data = MEM_callocN(sizeof(RectTransformInteraction), "cage_interaction");
+
+ float scale[2];
+ RNA_float_get_array(mpr->ptr, "scale", scale);
+
+ copy_v2_v2(data->orig_offset, mpr->matrix_offset[3]);
+ copy_v2_v2(data->orig_scale, scale);
+
+ data->orig_mouse[0] = event->mval[0];
+ data->orig_mouse[1] = event->mval[1];
+
+ mpr->interaction_data = data;
+}
+
+static void manipulator_rect_transform_modal(
+ bContext *C, wmManipulator *mpr, const wmEvent *event,
+ const int UNUSED(flag))
+{
+ RectTransformInteraction *data = mpr->interaction_data;
+ /* needed here as well in case clamping occurs */
+ const float orig_ofx = mpr->matrix_offset[3][0], orig_ofy = mpr->matrix_offset[3][1];
+
+ const float valuex = (event->mval[0] - data->orig_mouse[0]);
+ const float valuey = (event->mval[1] - data->orig_mouse[1]);
+
+ const int transform_flag = RNA_enum_get(mpr->ptr, "transform");
+
+ float dims[2];
+ RNA_float_get_array(mpr->ptr, "dimensions", dims);
+
+ float scale[2];
+ RNA_float_get_array(mpr->ptr, "scale", scale);
+
+ if (mpr->highlight_part == ED_MANIPULATOR_RECT_TRANSFORM_INTERSECT_TRANSLATE) {
+ mpr->matrix_offset[3][0] = data->orig_offset[0] + valuex;
+ mpr->matrix_offset[3][1] = data->orig_offset[1] + valuey;
+ }
+ else if (mpr->highlight_part == ED_MANIPULATOR_RECT_TRANSFORM_INTERSECT_SCALEX_LEFT) {
+ mpr->matrix_offset[3][0] = data->orig_offset[0] + valuex / 2.0;
+ scale[0] = (dims[0] * data->orig_scale[0] - valuex) / dims[0];
+ }
+ else if (mpr->highlight_part == ED_MANIPULATOR_RECT_TRANSFORM_INTERSECT_SCALEX_RIGHT) {
+ mpr->matrix_offset[3][0] = data->orig_offset[0] + valuex / 2.0;
+ scale[0] = (dims[0] * data->orig_scale[0] + valuex) / dims[0];
+ }
+ else if (mpr->highlight_part == ED_MANIPULATOR_RECT_TRANSFORM_INTERSECT_SCALEY_DOWN) {
+ mpr->matrix_offset[3][1] = data->orig_offset[1] + valuey / 2.0;
+
+ if (transform_flag & ED_MANIPULATOR_RECT_TRANSFORM_FLAG_SCALE_UNIFORM) {
+ scale[0] = (dims[1] * data->orig_scale[0] - valuey) / dims[1];
+ }
+ else {
+ scale[1] = (dims[1] * data->orig_scale[1] - valuey) / dims[1];
+ }
+ }
+ else if (mpr->highlight_part == ED_MANIPULATOR_RECT_TRANSFORM_INTERSECT_SCALEY_UP) {
+ mpr->matrix_offset[3][1] = data->orig_offset[1] + valuey / 2.0;
+
+ if (transform_flag & ED_MANIPULATOR_RECT_TRANSFORM_FLAG_SCALE_UNIFORM) {
+ scale[0] = (dims[1] * data->orig_scale[0] + valuey) / dims[1];
+ }
+ else {
+ scale[1] = (dims[1] * data->orig_scale[1] + valuey) / dims[1];
+ }
+ }
+
+ /* clamping - make sure manipulator is at least 5 pixels wide */
+ if (transform_flag & ED_MANIPULATOR_RECT_TRANSFORM_FLAG_SCALE_UNIFORM) {
+ if (scale[0] < MANIPULATOR_RECT_MIN_WIDTH / dims[1] ||
+ scale[0] < MANIPULATOR_RECT_MIN_WIDTH / dims[0])
+ {
+ scale[0] = max_ff(MANIPULATOR_RECT_MIN_WIDTH / dims[1], MANIPULATOR_RECT_MIN_WIDTH / dims[0]);
+ mpr->matrix_offset[3][0] = orig_ofx;
+ mpr->matrix_offset[3][1] = orig_ofy;
+ }
+ }
+ else {
+ if (scale[0] < MANIPULATOR_RECT_MIN_WIDTH / dims[0]) {
+ scale[0] = MANIPULATOR_RECT_MIN_WIDTH / dims[0];
+ mpr->matrix_offset[3][0] = orig_ofx;
+ }
+ if (scale[1] < MANIPULATOR_RECT_MIN_WIDTH / dims[1]) {
+ scale[1] = MANIPULATOR_RECT_MIN_WIDTH / dims[1];
+ mpr->matrix_offset[3][1] = orig_ofy;
+ }
+ }
+
+ RNA_float_set_array(mpr->ptr, "scale", scale);
+
+ wmManipulatorProperty *mpr_prop;
+
+ mpr_prop = WM_manipulator_target_property_find(mpr, "offset");
+ if (mpr_prop->prop != NULL) {
+ RNA_property_float_set_array(&mpr_prop->ptr, mpr_prop->prop, mpr->matrix_offset[3]);
+ RNA_property_update(C, &mpr_prop->ptr, mpr_prop->prop);
+ }
+
+ mpr_prop = WM_manipulator_target_property_find(mpr, "scale");
+ if (mpr_prop->prop != NULL) {
+ if (transform_flag & ED_MANIPULATOR_RECT_TRANSFORM_FLAG_SCALE_UNIFORM) {
+ RNA_property_float_set(&mpr_prop->ptr, mpr_prop->prop, scale[0]);
+ }
+ else {
+ RNA_property_float_set_array(&mpr_prop->ptr, mpr_prop->prop, scale);
+ }
+ RNA_property_update(C, &mpr_prop->ptr, mpr_prop->prop);
+ }
+
+ /* tag the region for redraw */
+ ED_region_tag_redraw(CTX_wm_region(C));
+}
+
+static void manipulator_rect_transform_property_update(wmManipulator *mpr, wmManipulatorProperty *mpr_prop)
+{
+ if (STREQ(mpr_prop->type->idname, "offset")) {
+ manipulator_rect_transform_get_prop_value(mpr, mpr_prop, mpr->matrix_offset[3]);
+ }
+ else if (STREQ(mpr_prop->type->idname, "scale")) {
+ float scale[2];
+ RNA_float_get_array(mpr->ptr, "scale", scale);
+ manipulator_rect_transform_get_prop_value(mpr, mpr_prop, scale);
+ }
+ else {
+ BLI_assert(0);
+ }
+}
+
+static void manipulator_rect_transform_exit(bContext *C, wmManipulator *mpr, const bool cancel)
+{
+ RectTransformInteraction *data = mpr->interaction_data;
+
+ if (!cancel)
+ return;
+
+ wmManipulatorProperty *mpr_prop;
+
+ /* reset properties */
+ mpr_prop = WM_manipulator_target_property_find(mpr, "offset");
+ if (mpr_prop->prop != NULL) {
+ RNA_property_float_set_array(&mpr_prop->ptr, mpr_prop->prop, data->orig_offset);
+ RNA_property_update(C, &mpr_prop->ptr, mpr_prop->prop);
+ }
+
+ mpr_prop = WM_manipulator_target_property_find(mpr, "scale");
+ if (mpr_prop->prop != NULL) {
+ const int transform_flag = RNA_enum_get(mpr->ptr, "transform");
+ if (transform_flag & ED_MANIPULATOR_RECT_TRANSFORM_FLAG_SCALE_UNIFORM) {
+ RNA_property_float_set(&mpr_prop->ptr, mpr_prop->prop, data->orig_scale[0]);
+ }
+ else {
+ RNA_property_float_set_array(&mpr_prop->ptr, mpr_prop->prop, data->orig_scale);
+ }
+ RNA_property_update(C, &mpr_prop->ptr, mpr_prop->prop);
+ }
+}
+
+
+/* -------------------------------------------------------------------- */
+/** \name Cage Manipulator API
+ *
+ * \{ */
+
+static void MANIPULATOR_WT_cage_2d(wmManipulatorType *wt)
+{
+ /* identifiers */
+ wt->idname = "MANIPULATOR_WT_cage_2d";
+
+ /* api callbacks */
+ wt->draw = manipulator_rect_transform_draw;
+ wt->setup = manipulator_rect_transform_setup;
+ wt->invoke = manipulator_rect_transform_invoke;
+ wt->property_update = manipulator_rect_transform_property_update;
+ wt->modal = manipulator_rect_transform_modal;
+ wt->test_select = manipulator_rect_transform_test_select;
+ wt->exit = manipulator_rect_transform_exit;
+ wt->cursor_get = manipulator_rect_transform_get_cursor;
+
+ wt->struct_size = sizeof(wmManipulator);
+
+ /* rna */
+ static EnumPropertyItem rna_enum_transform[] = {
+ {ED_MANIPULATOR_RECT_TRANSFORM_FLAG_TRANSLATE, "TRANSLATE", 0, "Translate", ""},
+ {ED_MANIPULATOR_RECT_TRANSFORM_FLAG_ROTATE, "ROTATE", 0, "Rotate", ""},
+ {ED_MANIPULATOR_RECT_TRANSFORM_FLAG_SCALE, "SCALE", 0, "Scale", ""},
+ {ED_MANIPULATOR_RECT_TRANSFORM_FLAG_SCALE_UNIFORM, "SCALE_UNIFORM", 0, "Scale Uniform", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ static float scale_default[2] = {1.0f, 1.0f};
+ RNA_def_float_vector(wt->srna, "scale", 2, scale_default, 0, FLT_MAX, "Scale", "", 0.0f, FLT_MAX);
+ RNA_def_float_vector(wt->srna, "dimensions", 2, NULL, 0, FLT_MAX, "Dimensions", "", 0.0f, FLT_MAX);
+ RNA_def_enum_flag(wt->srna, "transform", rna_enum_transform, 0, "Transform Options", "");
+
+ WM_manipulatortype_target_property_def(wt, "offset", PROP_FLOAT, 1);
+ WM_manipulatortype_target_property_def(wt, "scale", PROP_FLOAT, 2);
+ WM_manipulatortype_target_property_def(wt, "scale_uniform", PROP_FLOAT, 1);
+}
+
+void ED_manipulatortypes_cage_2d(void)
+{
+ WM_manipulatortype_append(MANIPULATOR_WT_cage_2d);
+}
+
+/** \} */
diff --git a/source/blender/editors/manipulator_library/manipulator_types/dial3d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/dial3d_manipulator.c
new file mode 100644
index 00000000000..0b979758688
--- /dev/null
+++ b/source/blender/editors/manipulator_library/manipulator_types/dial3d_manipulator.c
@@ -0,0 +1,467 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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_manipulator.c
+ * \ingroup wm
+ *
+ * \name Dial Manipulator
+ *
+ * 3D Manipulator
+ *
+ * \brief Circle shaped manipulator for circular interaction.
+ * Currently no own handling, use with operator only.
+ *
+ * - `matrix[0]` is derived from Y and Z.
+ * - `matrix[1]` is 'up' when DialManipulator.use_start_y_axis is set.
+ * - `matrix[2]` is the axis the dial rotates around (all dials).
+ */
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "BKE_context.h"
+
+#include "BLI_math.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "ED_manipulator_library.h"
+
+#include "GPU_select.h"
+
+#include "GPU_matrix.h"
+
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+/* own includes */
+#include "../manipulator_geometry.h"
+#include "../manipulator_library_intern.h"
+
+/* to use custom dials exported to geom_dial_manipulator.c */
+// #define USE_MANIPULATOR_CUSTOM_DIAL
+
+static void manipulator_dial_modal(bContext *C, wmManipulator *mpr, const wmEvent *event, const int flag);
+
+typedef struct DialInteraction {
+ float init_mval[2];
+
+ /* only for when using properties */
+ float init_prop_angle;
+
+ /* cache the last angle to detect rotations bigger than -/+ PI */
+ float last_angle;
+ /* number of full rotations */
+ int rotations;
+
+ /* final output values, used for drawing */
+ struct {
+ float angle_ofs;
+ float angle_delta;
+ } output;
+} DialInteraction;
+
+#define DIAL_WIDTH 1.0f
+#define DIAL_RESOLUTION 32
+
+
+static void dial_calc_matrix(const wmManipulator *mpr, float mat[4][4])
+{
+ float rot[3][3];
+ const float up[3] = {0.0f, 0.0f, 1.0f};
+
+ rotation_between_vecs_to_mat3(rot, up, mpr->matrix_basis[2]);
+ copy_m4_m3(mat, rot);
+ copy_v3_v3(mat[3], mpr->matrix_basis[3]);
+ mul_mat3_m4_fl(mat, mpr->scale_final);
+}
+
+/* -------------------------------------------------------------------- */
+
+static void dial_geom_draw(
+ const wmManipulator *mpr, const float col[4], const bool select,
+ float axis_modal_mat[4][4], float clip_plane[4])
+{
+#ifdef USE_MANIPULATOR_CUSTOM_DIAL
+ UNUSED_VARS(dial, col, axis_modal_mat, clip_plane);
+ wm_manipulator_geometryinfo_draw(&wm_manipulator_geom_data_dial, select);
+#else
+ const int draw_options = RNA_enum_get(mpr->ptr, "draw_options");
+ const bool filled = (draw_options & ED_MANIPULATOR_DIAL_DRAW_FLAG_FILL) != 0;
+
+ glLineWidth(mpr->line_width);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ if (clip_plane) {
+ immBindBuiltinProgram(GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR);
+ float clip_plane_f[4] = {clip_plane[0], clip_plane[1], clip_plane[2], clip_plane[3]};
+ immUniform4fv("ClipPlane", clip_plane_f);
+ immUniformMatrix4fv("ModelMatrix", axis_modal_mat);
+ }
+ else {
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+
+ immUniformColor4fv(col);
+
+ if (filled) {
+ imm_draw_circle_fill(pos, 0, 0, 1.0, DIAL_RESOLUTION);
+ }
+ else {
+ imm_draw_circle_wire(pos, 0, 0, 1.0, DIAL_RESOLUTION);
+ }
+
+ immUnbindProgram();
+
+ 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 col[4])
+{
+ glLineWidth(1.0f);
+
+ gpuPushMatrix();
+ gpuRotate3f(RAD2DEGF(angle), 0.0f, 0.0f, -1.0f);
+
+ uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ immUniformColor4fv(col);
+
+ immBegin(GWN_PRIM_LINE_STRIP, 2);
+ immVertex3f(pos, 0.0f, 0.0f, 0.0f);
+ immVertex3fv(pos, co_outer);
+ immEnd();
+
+ immUnbindProgram();
+
+ gpuPopMatrix();
+}
+
+static void dial_ghostarc_draw(
+ const wmManipulator *mpr, const float angle_ofs, const float angle_delta, const float color[4])
+{
+ const float width_inner = DIAL_WIDTH - mpr->line_width * 0.5f / U.manipulator_size;
+
+ Gwn_VertFormat *format = immVertexFormat();
+ uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor4fv(color);
+ imm_draw_disk_partial_fill(
+ pos, 0, 0, 0.0, width_inner, DIAL_RESOLUTION, RAD2DEGF(angle_ofs), RAD2DEGF(angle_delta));
+ immUnbindProgram();
+}
+
+static void dial_ghostarc_get_angles(
+ const wmManipulator *mpr,
+ const wmEvent *event,
+ const ARegion *ar, const View3D *v3d,
+ float mat[4][4], const float co_outer[3],
+ float *r_start, float *r_delta)
+{
+ DialInteraction *inter = mpr->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, mpr->matrix_basis[3], view_vec);
+ normalize_v3_v3(axis_vec, mpr->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, mpr->matrix_basis[3]);
+
+ float proj_mval_new_rel[3];
+ float proj_mval_init_rel[3];
+ float dial_plane[4];
+ float ray_co[3], ray_no[3];
+ float ray_lambda;
+
+ plane_from_point_normal_v3(dial_plane, mpr->matrix_basis[3], axis_vec);
+
+ if (!ED_view3d_win_to_ray(ar, v3d, inter->init_mval, ray_co, ray_no, false) ||
+ !isect_ray_plane_v3(ray_co, ray_no, dial_plane, &ray_lambda, false))
+ {
+ goto fail;
+ }
+ madd_v3_v3v3fl(proj_mval_init_rel, ray_co, ray_no, ray_lambda);
+ sub_v3_v3(proj_mval_init_rel, mpr->matrix_basis[3]);
+
+ if (!ED_view3d_win_to_ray(ar, v3d, mval, ray_co, ray_no, false) ||
+ !isect_ray_plane_v3(ray_co, ray_no, dial_plane, &ray_lambda, false))
+ {
+ goto fail;
+ }
+ madd_v3_v3v3fl(proj_mval_new_rel, ray_co, ray_no, ray_lambda);
+ sub_v3_v3(proj_mval_new_rel, mpr->matrix_basis[3]);
+
+ const int draw_options = RNA_enum_get(mpr->ptr, "draw_options");
+
+ /* Start direction from mouse or set by user */
+ const float *proj_init_rel =
+ (draw_options & ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_START_Y) ?
+ mpr->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->last_angle < 0.0f) &&
+ (fabsf(inter->last_angle) > (float)M_PI_2))
+ {
+ if (inter->last_angle < 0.0f)
+ inter->rotations--;
+ else
+ inter->rotations++;
+ }
+ inter->last_angle = delta;
+
+ *r_start = start;
+ *r_delta = fmod(delta + 2.0f * (float)M_PI * inter->rotations, 2 * (float)M_PI);
+ return;
+
+ /* If we can't project (unlikely). */
+fail:
+ *r_start = 0.0;
+ *r_delta = 0.0;
+}
+
+static void dial_draw_intern(
+ const bContext *C, wmManipulator *mpr,
+ const bool select, const bool highlight, float clip_plane[4])
+{
+ float mat[4][4];
+ float col[4];
+
+ BLI_assert(CTX_wm_area(C)->spacetype == SPACE_VIEW3D);
+
+ manipulator_color_get(mpr, highlight, col);
+
+ dial_calc_matrix(mpr, mat);
+
+ gpuPushMatrix();
+ gpuMultMatrix(mat);
+ gpuMultMatrix(mpr->matrix_offset);
+
+ /* draw rotation indicator arc first */
+ if ((mpr->flag & WM_MANIPULATOR_DRAW_VALUE) &&
+ (mpr->state & WM_MANIPULATOR_STATE_ACTIVE))
+ {
+ const float co_outer[4] = {0.0f, DIAL_WIDTH, 0.0f}; /* coordinate at which the arc drawing will be started */
+
+ DialInteraction *inter = mpr->interaction_data;
+
+ /* XXX, View3D rotation manipulator doesn't call modal. */
+ if (!WM_manipulator_target_property_is_valid_any(mpr)) {
+ wmWindow *win = CTX_wm_window(C);
+ manipulator_dial_modal((bContext *)C, mpr, win->eventstate, 0);
+ }
+
+ float angle_ofs = inter->output.angle_ofs;
+ float angle_delta = inter->output.angle_delta;
+
+ /* draw! */
+ for (int i = 0; i < 2; i++) {
+ dial_ghostarc_draw(mpr, angle_ofs, angle_delta, (const float [4]){0.8f, 0.8f, 0.8f, 0.4f});
+
+ dial_ghostarc_draw_helpline(angle_ofs, co_outer, col); /* starting position */
+ dial_ghostarc_draw_helpline(angle_ofs + angle_delta, co_outer, col); /* starting position + current value */
+
+ if (i == 0) {
+ const int draw_options = RNA_enum_get(mpr->ptr, "draw_options");
+ if ((draw_options & ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_MIRROR) == 0) {
+ break;
+ }
+ }
+
+ angle_ofs += M_PI;
+ }
+ }
+
+ /* draw actual dial manipulator */
+ dial_geom_draw(mpr, col, select, mat, clip_plane);
+
+ gpuPopMatrix();
+}
+
+static void manipulator_dial_draw_select(const bContext *C, wmManipulator *mpr, int selectionbase)
+{
+ float clip_plane_buf[4];
+ const int draw_options = RNA_enum_get(mpr->ptr, "draw_options");
+ float *clip_plane = (draw_options & ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP) ? clip_plane_buf : NULL;
+
+ /* enable clipping if needed */
+ 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], mpr->matrix_basis[3]);
+ glEnable(GL_CLIP_DISTANCE0);
+ }
+
+ GPU_select_load_id(selectionbase);
+ dial_draw_intern(C, mpr, true, false, clip_plane);
+
+ if (clip_plane) {
+ glDisable(GL_CLIP_DISTANCE0);
+ }
+}
+
+static void manipulator_dial_draw(const bContext *C, wmManipulator *mpr)
+{
+ const bool active = mpr->state & WM_MANIPULATOR_STATE_ACTIVE;
+ const bool highlight = (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0;
+ float clip_plane_buf[4];
+ const int draw_options = RNA_enum_get(mpr->ptr, "draw_options");
+ float *clip_plane = (!active && (draw_options & ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP)) ? clip_plane_buf : NULL;
+
+ /* enable clipping if needed */
+ 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], mpr->matrix_basis[3]);
+ clip_plane[3] -= 0.02 * mpr->scale_final;
+
+ glEnable(GL_CLIP_DISTANCE0);
+ }
+
+ glEnable(GL_BLEND);
+ dial_draw_intern(C, mpr, false, highlight, clip_plane);
+ glDisable(GL_BLEND);
+
+ if (clip_plane) {
+ glDisable(GL_CLIP_DISTANCE0);
+ }
+}
+
+static void manipulator_dial_modal(bContext *C, wmManipulator *mpr, const wmEvent *event, const int UNUSED(flag))
+{
+ const float co_outer[4] = {0.0f, DIAL_WIDTH, 0.0f}; /* coordinate at which the arc drawing will be started */
+ float angle_ofs, angle_delta;
+
+ float matrix[4][4];
+
+ dial_calc_matrix(mpr, matrix);
+
+ dial_ghostarc_get_angles(
+ mpr, event, CTX_wm_region(C), CTX_wm_view3d(C), matrix, co_outer, &angle_ofs, &angle_delta);
+
+ DialInteraction *inter = mpr->interaction_data;
+
+ inter->output.angle_delta = angle_delta;
+ inter->output.angle_ofs = angle_ofs;
+
+ /* set the property for the operator and call its modal function */
+ wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_find(mpr, "offset");
+ if (WM_manipulator_target_property_is_valid(mpr_prop)) {
+ WM_manipulator_target_property_value_set(C, mpr, mpr_prop, inter->init_prop_angle + angle_delta);
+ }
+}
+
+
+static void manipulator_dial_setup(wmManipulator *mpr)
+{
+ const float dir_default[3] = {0.0f, 0.0f, 1.0f};
+
+ /* defaults */
+ copy_v3_v3(mpr->matrix_basis[2], dir_default);
+}
+
+static void manipulator_dial_invoke(
+ bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *event)
+{
+ DialInteraction *inter = MEM_callocN(sizeof(DialInteraction), __func__);
+
+ inter->init_mval[0] = event->mval[0];
+ inter->init_mval[1] = event->mval[1];
+
+ wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_find(mpr, "offset");
+ if (WM_manipulator_target_property_is_valid(mpr_prop)) {
+ inter->init_prop_angle = WM_manipulator_target_property_value_get(mpr, mpr_prop);
+ }
+
+ mpr->interaction_data = inter;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Dial Manipulator API
+ *
+ * \{ */
+
+static void MANIPULATOR_WT_dial_3d(wmManipulatorType *wt)
+{
+ /* identifiers */
+ wt->idname = "MANIPULATOR_WT_dial_3d";
+
+ /* api callbacks */
+ wt->draw = manipulator_dial_draw;
+ wt->draw_select = manipulator_dial_draw_select;
+ wt->setup = manipulator_dial_setup;
+ wt->invoke = manipulator_dial_invoke;
+ wt->modal = manipulator_dial_modal;
+
+ wt->struct_size = sizeof(wmManipulator);
+
+ /* rna */
+ static EnumPropertyItem rna_enum_draw_options[] = {
+ {ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP, "CLIP", 0, "Clipped", ""},
+ {ED_MANIPULATOR_DIAL_DRAW_FLAG_FILL, "FILL", 0, "Filled", ""},
+ {ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_MIRROR, "ANGLE_MIRROR", 0, "Angle Mirror", ""},
+ {ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_START_Y, "ANGLE_START_Y", 0, "Angle Start Y", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ RNA_def_enum_flag(wt->srna, "draw_options", rna_enum_draw_options, 0, "Draw Options", "");
+
+ WM_manipulatortype_target_property_def(wt, "offset", PROP_FLOAT, 1);
+}
+
+void ED_manipulatortypes_dial_3d(void)
+{
+ WM_manipulatortype_append(MANIPULATOR_WT_dial_3d);
+}
+
+/** \} */
diff --git a/source/blender/editors/manipulator_library/manipulator_types/grab3d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/grab3d_manipulator.c
new file mode 100644
index 00000000000..6943ae2c9f0
--- /dev/null
+++ b/source/blender/editors/manipulator_library/manipulator_types/grab3d_manipulator.c
@@ -0,0 +1,259 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 grab3d_manipulator.c
+ * \ingroup wm
+ *
+ * \name Grab Manipulator
+ *
+ * 3D Manipulator
+ *
+ * \brief Simple manipulator to grab and translate.
+ *
+ * - `matrix[0]` is derived from Y and Z.
+ * - `matrix[1]` currently not used.
+ * - `matrix[2]` is the widget direction (for all manipulators).
+ *
+ */
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "BKE_context.h"
+
+#include "BLI_math.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "ED_manipulator_library.h"
+
+#include "GPU_select.h"
+
+#include "GPU_matrix.h"
+
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+/* own includes */
+#include "../manipulator_geometry.h"
+#include "../manipulator_library_intern.h"
+
+static void manipulator_grab_modal(bContext *C, wmManipulator *mpr, const wmEvent *event, const int flag);
+
+typedef struct GrabInteraction {
+ float init_mval[2];
+
+ /* only for when using properties */
+ float init_prop_co[3];
+
+ /* final output values, used for drawing */
+ struct {
+ float co_ofs[3];
+ float co_final[3];
+ } output;
+} GrabInteraction;
+
+#define DIAL_RESOLUTION 32
+
+/* -------------------------------------------------------------------- */
+
+static void grab_geom_draw(
+ const wmManipulator *mpr, const float col[4], const bool select)
+{
+#ifdef USE_MANIPULATOR_CUSTOM_DIAL
+ UNUSED_VARS(grab3d, col, axis_modal_mat);
+ wm_manipulator_geometryinfo_draw(&wm_manipulator_geom_data_grab3d, select);
+#else
+ const int draw_options = RNA_enum_get(mpr->ptr, "draw_options");
+ const bool filled = (draw_options & ED_MANIPULATOR_GRAB_DRAW_FLAG_FILL) != 0;
+
+ glLineWidth(mpr->line_width);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ immUniformColor4fv(col);
+
+ if (filled) {
+ imm_draw_circle_fill(pos, 0, 0, 1.0, DIAL_RESOLUTION);
+ }
+ else {
+ imm_draw_circle_wire(pos, 0, 0, 1.0, DIAL_RESOLUTION);
+ }
+
+ immUnbindProgram();
+
+ UNUSED_VARS(select);
+#endif
+}
+
+static void grab3d_get_translate(
+ const wmManipulator *mpr, const wmEvent *event, const ARegion *ar,
+ float co_delta[3])
+{
+ GrabInteraction *inter = mpr->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;
+ const float *co_ref = 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);
+}
+
+static void grab3d_draw_intern(
+ const bContext *C, wmManipulator *mpr,
+ const bool select, const bool highlight)
+{
+ float mat[4][4];
+ float col[4];
+
+ BLI_assert(CTX_wm_area(C)->spacetype == SPACE_VIEW3D);
+
+ manipulator_color_get(mpr, highlight, col);
+
+ copy_m4_m4(mat, mpr->matrix_basis);
+ mul_mat3_m4_fl(mat, mpr->scale_final);
+
+ gpuPushMatrix();
+ if (mpr->interaction_data) {
+ GrabInteraction *inter = mpr->interaction_data;
+ gpuTranslate3fv(inter->output.co_ofs);
+ }
+ gpuMultMatrix(mat);
+ gpuMultMatrix(mpr->matrix_offset);
+ glEnable(GL_BLEND);
+ grab_geom_draw(mpr, col, select);
+ glDisable(GL_BLEND);
+ gpuPopMatrix();
+
+ if (mpr->interaction_data) {
+ gpuPushMatrix();
+ gpuMultMatrix(mat);
+ gpuMultMatrix(mpr->matrix_offset);
+ glEnable(GL_BLEND);
+ grab_geom_draw(mpr, (const float [4]){0.5f, 0.5f, 0.5f, 0.5f}, select);
+ glDisable(GL_BLEND);
+ gpuPopMatrix();
+ }
+}
+
+static void manipulator_grab_draw_select(const bContext *C, wmManipulator *mpr, int selectionbase)
+{
+ GPU_select_load_id(selectionbase);
+ grab3d_draw_intern(C, mpr, true, false);
+}
+
+static void manipulator_grab_draw(const bContext *C, wmManipulator *mpr)
+{
+ const bool active = mpr->state & WM_MANIPULATOR_STATE_ACTIVE;
+ const bool highlight = (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0;
+
+ (void)active;
+
+ glEnable(GL_BLEND);
+ grab3d_draw_intern(C, mpr, false, highlight);
+ glDisable(GL_BLEND);
+}
+
+static void manipulator_grab_modal(bContext *C, wmManipulator *mpr, const wmEvent *event, const int UNUSED(flag))
+{
+ GrabInteraction *inter = mpr->interaction_data;
+
+ grab3d_get_translate(mpr, event, CTX_wm_region(C), inter->output.co_ofs);
+
+ add_v3_v3v3(inter->output.co_final, inter->init_prop_co, inter->output.co_ofs);
+
+ /* set the property for the operator and call its modal function */
+ wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_find(mpr, "offset");
+ if (WM_manipulator_target_property_is_valid(mpr_prop)) {
+ WM_manipulator_target_property_value_set_array(C, mpr, mpr_prop, inter->output.co_final);
+ }
+}
+
+static void manipulator_grab_invoke(
+ bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *event)
+{
+ GrabInteraction *inter = MEM_callocN(sizeof(GrabInteraction), __func__);
+
+ inter->init_mval[0] = event->mval[0];
+ inter->init_mval[1] = event->mval[1];
+
+ wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_find(mpr, "offset");
+ if (WM_manipulator_target_property_is_valid(mpr_prop)) {
+ WM_manipulator_target_property_value_get_array(mpr, mpr_prop, inter->init_prop_co);
+ }
+
+ mpr->interaction_data = inter;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Grab Manipulator API
+ *
+ * \{ */
+
+static void MANIPULATOR_WT_grab_3d(wmManipulatorType *wt)
+{
+ /* identifiers */
+ wt->idname = "MANIPULATOR_WT_grab_3d";
+
+ /* api callbacks */
+ wt->draw = manipulator_grab_draw;
+ wt->draw_select = manipulator_grab_draw_select;
+ wt->invoke = manipulator_grab_invoke;
+ wt->modal = manipulator_grab_modal;
+
+ wt->struct_size = sizeof(wmManipulator);
+
+ /* rna */
+ static EnumPropertyItem rna_enum_draw_style[] = {
+ {ED_MANIPULATOR_GRAB_STYLE_RING, "RING", 0, "Ring", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ static EnumPropertyItem rna_enum_draw_options[] = {
+ {ED_MANIPULATOR_GRAB_DRAW_FLAG_FILL, "FILL", 0, "Filled", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ RNA_def_enum(wt->srna, "draw_style", rna_enum_draw_style, ED_MANIPULATOR_GRAB_STYLE_RING, "Draw Style", "");
+ RNA_def_enum_flag(wt->srna, "draw_options", rna_enum_draw_options, 0, "Draw Options", "");
+
+ WM_manipulatortype_target_property_def(wt, "offset", PROP_FLOAT, 3);
+}
+
+void ED_manipulatortypes_grab_3d(void)
+{
+ WM_manipulatortype_append(MANIPULATOR_WT_grab_3d);
+}
+
+/** \} */ // Grab Manipulator API
diff --git a/source/blender/editors/manipulator_library/manipulator_types/primitive3d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/primitive3d_manipulator.c
new file mode 100644
index 00000000000..f6c83a4934c
--- /dev/null
+++ b/source/blender/editors/manipulator_library/manipulator_types/primitive3d_manipulator.c
@@ -0,0 +1,195 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_manipulator.c
+ * \ingroup wm
+ *
+ * \name Primitive Manipulator
+ *
+ * 3D Manipulator
+ *
+ * \brief Manipulator with primitive drawing type (plane, cube, etc.).
+ * Currently only plane primitive supported without own handling, use with operator only.
+ */
+
+#include "BIF_gl.h"
+
+#include "BKE_context.h"
+
+#include "BLI_math.h"
+
+#include "DNA_view3d_types.h"
+
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_select.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_manipulator_library.h"
+
+/* own includes */
+#include "../manipulator_library_intern.h"
+
+static float verts_plane[4][3] = {
+ {-1, -1, 0},
+ { 1, -1, 0},
+ { 1, 1, 0},
+ {-1, 1, 0},
+};
+
+
+/* -------------------------------------------------------------------- */
+
+static void manipulator_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_MANIPULATOR_PRIMITIVE_STYLE_PLANE) {
+ verts = verts_plane;
+ vert_count = ARRAY_SIZE(verts_plane);
+ }
+
+ if (vert_count > 0) {
+ uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ wm_manipulator_vec_draw(col_inner, verts, vert_count, pos, GWN_PRIM_TRI_FAN);
+ wm_manipulator_vec_draw(col_outer, verts, vert_count, pos, GWN_PRIM_LINE_LOOP);
+ immUnbindProgram();
+ }
+}
+
+static void manipulator_primitive_draw_intern(
+ wmManipulator *mpr, const bool UNUSED(select),
+ const bool highlight)
+{
+ float col_inner[4], col_outer[4];
+ float mat[4][4];
+ const int draw_style = RNA_enum_get(mpr->ptr, "draw_style");
+
+ manipulator_color_get(mpr, highlight, col_outer);
+ copy_v4_v4(col_inner, col_outer);
+ col_inner[3] *= 0.5f;
+
+ copy_m4_m4(mat, mpr->matrix_basis);
+ mul_mat3_m4_fl(mat, mpr->scale_final);
+
+ gpuPushMatrix();
+ gpuMultMatrix(mat);
+
+ glEnable(GL_BLEND);
+ gpuMultMatrix(mpr->matrix_offset);
+ manipulator_primitive_draw_geom(col_inner, col_outer, draw_style);
+ glDisable(GL_BLEND);
+
+ gpuPopMatrix();
+
+ if (mpr->interaction_data) {
+ ManipulatorInteraction *inter = mpr->interaction_data;
+
+ copy_v4_fl(col_inner, 0.5f);
+ copy_v3_fl(col_outer, 0.5f);
+ col_outer[3] = 0.8f;
+
+ copy_m4_m4(mat, inter->init_matrix);
+ mul_mat3_m4_fl(mat, inter->init_scale);
+
+ gpuPushMatrix();
+ gpuMultMatrix(mat);
+
+ glEnable(GL_BLEND);
+ gpuMultMatrix(mpr->matrix_offset);
+ manipulator_primitive_draw_geom(col_inner, col_outer, draw_style);
+ glDisable(GL_BLEND);
+
+ gpuPopMatrix();
+ }
+}
+
+static void manipulator_primitive_draw_select(
+ const bContext *UNUSED(C), wmManipulator *mpr,
+ int selectionbase)
+{
+ GPU_select_load_id(selectionbase);
+ manipulator_primitive_draw_intern(mpr, true, false);
+}
+
+static void manipulator_primitive_draw(const bContext *UNUSED(C), wmManipulator *mpr)
+{
+ manipulator_primitive_draw_intern(
+ mpr, false,
+ (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT));
+}
+
+static void manipulator_primitive_setup(wmManipulator *mpr)
+{
+ mpr->flag |= WM_MANIPULATOR_DRAW_ACTIVE;
+}
+
+static void manipulator_primitive_invoke(
+ bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *UNUSED(event))
+{
+ ManipulatorInteraction *inter = MEM_callocN(sizeof(ManipulatorInteraction), __func__);
+
+ copy_m4_m4(inter->init_matrix, mpr->matrix_basis);
+ inter->init_scale = mpr->scale_final;
+
+ mpr->interaction_data = inter;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Primitive Manipulator API
+ *
+ * \{ */
+
+static void MANIPULATOR_WT_primitive_3d(wmManipulatorType *wt)
+{
+ /* identifiers */
+ wt->idname = "MANIPULATOR_WT_primitive_3d";
+
+ /* api callbacks */
+ wt->draw = manipulator_primitive_draw;
+ wt->draw_select = manipulator_primitive_draw_select;
+ wt->setup = manipulator_primitive_setup;
+ wt->invoke = manipulator_primitive_invoke;
+
+ wt->struct_size = sizeof(wmManipulator);
+
+ static EnumPropertyItem rna_enum_draw_style[] = {
+ {ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE, "PLANE", 0, "Plane", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ RNA_def_enum(wt->srna, "draw_style", rna_enum_draw_style, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE, "Draw Style", "");
+}
+
+void ED_manipulatortypes_primitive_3d(void)
+{
+ WM_manipulatortype_append(MANIPULATOR_WT_primitive_3d);
+}
+
+/** \} */
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 e3e8f35e7d8..ad1a567f843 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"
@@ -692,7 +693,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;
}
@@ -770,15 +771,19 @@ static int create_primitive_from_points(bContext *C, wmOperator *op, const float
new_spline = BKE_mask_spline_add(mask_layer);
new_spline->flag = MASK_SPLINE_CYCLIC | SELECT;
- new_spline->tot_point = num_points;
new_spline->points = MEM_recallocN(new_spline->points,
- sizeof(MaskSplinePoint) * new_spline->tot_point);
+ sizeof(MaskSplinePoint) * num_points);
mask_layer->act_spline = new_spline;
mask_layer->act_point = NULL;
+ const int spline_index = BKE_mask_layer_shape_spline_to_index(mask_layer, new_spline);
+
for (i = 0; i < num_points; i++) {
+ new_spline->tot_point = i + 1;
+
MaskSplinePoint *new_point = &new_spline->points[i];
+ BKE_mask_parent_init(&new_point->parent);
copy_v2_v2(new_point->bezt.vec[1], points[i]);
mul_v2_fl(new_point->bezt.vec[1], scale);
@@ -787,6 +792,12 @@ static int create_primitive_from_points(bContext *C, wmOperator *op, const float
new_point->bezt.h1 = handle_type;
new_point->bezt.h2 = handle_type;
BKE_mask_point_select_set(new_point, true);
+
+ if (mask_layer->splines_shapes.first) {
+ BKE_mask_layer_shape_changed_add(mask_layer,
+ spline_index + i,
+ true, true);
+ }
}
WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index 2b4f94a37ef..72bc61139c6 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,10 +49,13 @@
#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 "UI_resources.h"
#include "UI_view2d.h"
@@ -93,40 +97,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 +104,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 +123,70 @@ static void draw_single_handle(const MaskLayer *mask_layer, const MaskSplinePoin
return;
}
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_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();
+ glLineWidth(3.0f);
+ immBegin(GWN_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();
+ glLineWidth(1.0f);
+ immBegin(GWN_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(GWN_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 +196,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 +207,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);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_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 +242,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(GWN_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);
}
/* 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 +290,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 +301,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(GWN_PRIM_POINTS, 1);
+ immVertex2fv(pos, vert);
+ immEnd();
- glBegin(GL_POINTS);
- glVertex2fv(vert);
- glEnd();
+ immUnbindProgram();
minmax_v2v2_v2(min, max, vert);
}
+ if (is_smooth) {
+ glDisable(GL_LINE_SMOOTH);
+ }
+
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(GWN_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 +370,21 @@ static void mask_color_active_tint(unsigned char r_rgb[4], const unsigned char r
}
}
+static void mask_draw_array(unsigned int pos, Gwn_PrimType prim_type, const float (*points)[2], unsigned int vertex_ct)
+{
+ immBegin(prim_type, vertex_ct);
+ for (unsigned int i = 0; i < vertex_ct; ++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 Gwn_PrimType draw_method = (spline->flag & MASK_SPLINE_CYCLIC) ? GWN_PRIM_LINE_LOOP : GWN_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 +393,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);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_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);
+
+ glLineWidth(3.0f);
mask_color_active_tint(rgb_tmp, rgb_black, is_active);
- glColor4ubv(rgb_tmp);
+ immUniformColor4ubv(rgb_tmp);
+ mask_draw_array(pos, draw_method, points, tot_point);
- glDrawArrays(draw_method, 0, tot_point);
+ glLineWidth(1.0f);
- glLineWidth(1);
mask_color_active_tint(rgb_tmp, rgb_spline, is_active);
- glColor4ubv(rgb_tmp);
- glDrawArrays(draw_method, 0, tot_point);
-
- break;
-
- case MASK_DT_DASH:
- default:
- GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
- GPU_basic_shader_line_stipple(3, 0xAAAA);
-
-#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);
+ glLineWidth(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 +444,39 @@ 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:
+ /* TODO(merwin): use dashed line shader here
+ * probably better with geometry shader (after core profile switch)
+ */
+#if 0
+ glLineWidth(1.0f);
+
+ GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ GPU_basic_shader_line_stipple(3, 0xAAAA);
+
+ mask_color_active_tint(rgb_tmp, rgb_spline, is_active);
+ immUniformColor4ubv(rgb_tmp);
+ mask_draw_array(pos, draw_method, points, tot_point);
+
+ mask_color_active_tint(rgb_tmp, rgb_black, is_active);
+ immUniformColor4ubv(rgb_tmp);
+ GPU_basic_shader_line_stipple(3, 0x5555);
+ mask_draw_array(pos, draw_method, points, tot_point);
+ GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+#endif
break;
- }
- glDisableClientState(GL_VERTEX_ARRAY);
+ default:
+ BLI_assert(false);
+ }
if (points != orig_points)
MEM_freeN(points);
@@ -548,8 +509,6 @@ static void draw_spline_curve(const bContext *C, MaskLayer *masklay, MaskSpline
if (is_smooth) {
glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
feather_points = BKE_mask_spline_feather_differentiated_points_with_resolution(spline, &tot_feather_point, resol, (is_fill != false));
@@ -557,26 +516,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 +542,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) {
+ if (is_smooth) {
glDisable(GL_LINE_SMOOTH);
- glDisable(GL_BLEND);
}
-
- (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)
{
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_enable_program_point_size();
+
MaskLayer *masklay;
int i;
@@ -616,11 +574,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 +585,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();
+ glDisable(GL_BLEND);
}
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);
}
typedef struct ThreadedMaskRasterizeState {
@@ -802,28 +754,26 @@ 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 = threaded_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;
+ glBlendFunc(GL_DST_COLOR, GL_ZERO);
}
- glPushMatrix();
- glTranslatef(x, y, 0);
- glScalef(zoomx, zoomy, 0);
+ gpuPushMatrix();
+ gpuTranslate2f(x, y);
+ gpuScale2f(zoomx, zoomy);
if (stabmat) {
- glMultMatrixf(stabmat);
+ gpuMultMatrix(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);
+
+ gpuPopMatrix();
if (overlay_mode != MASK_OVERLAY_ALPHACHANNEL) {
glDisable(GL_BLEND);
@@ -833,27 +783,26 @@ void ED_mask_draw_region(Mask *mask, ARegion *ar,
}
/* apply transformation so mask editing tools will assume drawing from the origin in normalized space */
- glPushMatrix();
-
+ gpuPushMatrix();
+ gpuTranslate2f(x + xofs, y + yofs);
+ gpuScale2f(zoomx, zoomy);
if (stabmat) {
- glMultMatrixf(stabmat);
+ gpuMultMatrix(stabmat);
}
-
- glTranslatef(x + xofs, y + yofs, 0);
- glScalef(maxdim * zoomx, maxdim * zoomy, 0);
+ gpuScale2f(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();
+ gpuPopMatrix();
}
void ED_mask_draw_frames(Mask *mask, ARegion *ar, const int cfra, const int sfra, const int efra)
@@ -862,25 +811,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;
-
- for (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;
- glVertex2i(x, 0);
- glVertex2i(x, height);
+ unsigned int num_lines = BLI_listbase_count(&masklay->splines_shapes);
+
+ if (num_lines > 0) {
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4ub(255, 175, 0, 255);
+
+ immBegin(GWN_PRIM_LINES, 2 * num_lines);
+
+ 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_ops.c b/source/blender/editors/mask/mask_ops.c
index eef03852007..7bd8d9de278 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 */
@@ -889,7 +890,7 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY))
data->is_accurate = (event->val == KM_PRESS);
- /* fall-through */ /* update CV position */
+ ATTR_FALLTHROUGH; /* update CV position */
case MOUSEMOVE:
{
ScrArea *sa = CTX_wm_area(C);
@@ -1062,7 +1063,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 +1090,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 +1106,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;
@@ -1376,7 +1377,7 @@ static int slide_spline_curvature_modal(bContext *C, wmOperator *op, const wmEve
}
- /* fall-through */ /* update CV position */
+ ATTR_FALLTHROUGH; /* update CV position */
case MOUSEMOVE:
{
float B[2], mouse_coord[2], delta[2];
@@ -1469,7 +1470,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 +1484,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 +1496,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 +1542,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 +1901,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;
}
@@ -1954,7 +1955,7 @@ static int mask_hide_view_clear_exec(bContext *C, wmOperator *UNUSED(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;
}
@@ -2016,7 +2017,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;
}
@@ -2076,7 +2077,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_shapekey.c b/source/blender/editors/mask/mask_shapekey.c
index 99ffc9cd7d2..3fb1cc87dbd 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;
}
@@ -124,7 +125,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;
}
@@ -216,7 +217,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;
}
@@ -386,7 +387,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 8783367ef7e..4607ed79c3b 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
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index c4e87614732..cd7940126ec 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -106,6 +106,8 @@ void paintface_flush_flags(Object *ob, short flag)
/* draw-object caches hidden faces, force re-generation T46867 */
GPU_drawobject_free(dm);
}
+
+ BKE_mesh_batch_cache_dirty(me, BKE_MESH_BATCH_DIRTY_NOCHECK);
}
void paintface_hide(Object *ob, const bool unselected)
@@ -306,31 +308,30 @@ void paintface_deselect_all_visible(Object *ob, int action, bool flush_flags)
bool paintface_minmax(Object *ob, float r_min[3], float r_max[3])
{
- Mesh *me;
- MPoly *mp;
- MTexPoly *tf;
- MLoop *ml;
- MVert *mvert;
+ const Mesh *me;
+ const MPoly *mp;
+ const MLoop *ml;
+ const MVert *mvert;
int a, b;
bool ok = false;
float vec[3], bmat[3][3];
me = BKE_mesh_from_object(ob);
- if (!me || !me->mtpoly) return ok;
+ if (!me || !me->mloopuv) {
+ return ok;
+ }
copy_m3_m4(bmat, ob->obmat);
mvert = me->mvert;
mp = me->mpoly;
- tf = me->mtpoly;
- for (a = me->totpoly; a > 0; a--, mp++, tf++) {
+ for (a = me->totpoly; a > 0; a--, mp++) {
if (mp->flag & ME_HIDE || !(mp->flag & ME_FACE_SEL))
continue;
ml = me->mloop + mp->totloop;
for (b = 0; b < mp->totloop; b++, ml++) {
- copy_v3_v3(vec, (mvert[ml->v].co));
- mul_m3_v3(bmat, vec);
+ mul_v3_m3v3(vec, bmat, mvert[ml->v].co);
add_v3_v3v3(vec, vec, ob->obmat[3]);
minmax_v3v3_v3(r_min, r_max, vec);
}
@@ -388,7 +389,7 @@ 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);
ED_region_tag_redraw(CTX_wm_region(C)); // XXX - should redraw all 3D views
@@ -516,6 +517,8 @@ void paintvert_flush_flags(Object *ob)
dm_mv->flag = me->mvert[i].flag;
}
}
+
+ BKE_mesh_batch_cache_dirty(me, BKE_MESH_BATCH_DIRTY_NOCHECK);
}
/* 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 2a9f9c830f4..07fedffaf80 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -384,7 +384,7 @@ void MESH_OT_primitive_cone_add(wmOperatorType *ot)
/* props */
RNA_def_int(ot->srna, "vertices", 32, 3, MESH_ADD_VERTS_MAXI, "Vertices", "", 3, 500);
RNA_def_float_distance(ot->srna, "radius1", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius 1", "", 0.001, 100.00);
- RNA_def_float_distance(ot->srna, "radius2", 0.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius 2", "", 0.001, 100.00);
+ RNA_def_float_distance(ot->srna, "radius2", 0.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius 2", "", 0.0, 100.00);
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, "Base Fill Type", "");
@@ -461,6 +461,7 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op)
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);
@@ -471,9 +472,13 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op)
em = BKE_editmesh_from_object(obedit);
+ if (calc_uvs) {
+ ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ }
+
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
- "create_monkey matrix=%m4", mat))
+ "create_monkey matrix=%m4 calc_uvs=%b", mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
@@ -498,6 +503,8 @@ void MESH_OT_primitive_monkey_add(wmOperatorType *ot)
ED_object_add_unit_props(ot);
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* props */
+ ED_object_add_mesh_props(ot);
ED_object_add_generic_props(ot, true);
}
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 302ca407add..a81add7a86e 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -145,6 +145,7 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
opdata->em = em;
opdata->is_modal = is_modal;
opdata->value_mode = OFFSET_VALUE;
+ opdata->segments = (float) RNA_int_get(op->ptr, "segments");
pixels_per_inch = U.dpi * U.pixelsize;
for (i = 0; i < NUM_VALUE_KINDS; i++) {
diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c
index 0e1ba2b1c25..9b6df11d470 100644
--- a/source/blender/editors/mesh/editmesh_bisect.c
+++ b/source/blender/editors/mesh/editmesh_bisect.c
@@ -50,9 +50,15 @@
#include "ED_screen.h"
#include "ED_view3d.h"
-
#include "mesh_intern.h" /* own include */
+#define USE_MANIPULATOR
+
+#ifdef USE_MANIPULATOR
+#include "ED_manipulator_library.h"
+#include "ED_util.h"
+#endif
+
static int mesh_bisect_exec(bContext *C, wmOperator *op);
/* -------------------------------------------------------------------- */
@@ -73,6 +79,7 @@ static bool mesh_bisect_interactive_calc(
wmGesture *gesture = op->customdata;
BisectData *opdata;
+ View3D *v3d = CTX_wm_view3d(C);
ARegion *ar = CTX_wm_region(C);
RegionView3D *rv3d = ar->regiondata;
@@ -101,7 +108,7 @@ static bool mesh_bisect_interactive_calc(
normalize_v3(plane_no); /* not needed but nicer for user */
/* point on plane, can use either start or endpoint */
- ED_view3d_win_to_3d(ar, co_ref, co_a_ss, plane_co);
+ 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);
@@ -185,6 +192,16 @@ static int mesh_bisect_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (ret & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) {
edbm_bisect_exit(C, &opdata_back);
+
+#ifdef USE_MANIPULATOR
+ /* Setup manipulators */
+ {
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d && (v3d->twtype & V3D_MANIPULATOR_DRAW)) {
+ WM_manipulator_group_add("MESH_WGT_bisect");
+ }
+ }
+#endif
}
return ret;
@@ -314,6 +331,9 @@ static int mesh_bisect_exec(bContext *C, wmOperator *op)
}
}
+#ifdef USE_MANIPULATOR
+static void MESH_WGT_bisect(struct wmManipulatorGroupType *wgt);
+#endif
void MESH_OT_bisect(struct wmOperatorType *ot)
{
@@ -349,4 +369,324 @@ void MESH_OT_bisect(struct wmOperatorType *ot)
RNA_def_float(ot->srna, "threshold", 0.0001, 0.0, 10.0, "Axis Threshold", "", 0.00001, 0.1);
WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
+
+#ifdef USE_MANIPULATOR
+ WM_manipulatorgrouptype_append(MESH_WGT_bisect);
+#endif
+}
+
+
+#ifdef USE_MANIPULATOR
+
+/* -------------------------------------------------------------------- */
+
+/** \name Bisect Manipulator
+ * \{ */
+
+typedef struct ManipulatorGroup {
+ /* Arrow to change plane depth. */
+ struct wmManipulator *translate_z;
+ /* Translate XYZ */
+ struct wmManipulator *translate_c;
+ /* For grabbing the manipulator and moving freely. */
+ struct wmManipulator *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;
+} ManipulatorGroup;
+
+/**
+ * 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 manipulator_bisect_exec(ManipulatorGroup *man)
+{
+ wmOperator *op = man->data.op;
+ if (op == WM_operator_last_redo((bContext *)man->data.context)) {
+ ED_undo_operator_repeat((bContext *)man->data.context, op);
+ }
+}
+
+static void manipulator_mesh_bisect_update_from_op(ManipulatorGroup *man)
+{
+ wmOperator *op = man->data.op;
+
+ float plane_co[3], plane_no[3];
+
+ RNA_property_float_get_array(op->ptr, man->data.prop_plane_co, plane_co);
+ RNA_property_float_get_array(op->ptr, man->data.prop_plane_no, plane_no);
+
+ WM_manipulator_set_matrix_location(man->translate_z, plane_co);
+ WM_manipulator_set_matrix_location(man->translate_c, plane_co);
+ WM_manipulator_set_matrix_location(man->rotate_c, plane_co);
+
+ WM_manipulator_set_matrix_rotation_from_z_axis(man->translate_z, plane_no);
+
+ WM_manipulator_set_scale(man->translate_c, 0.2);
+
+ RegionView3D *rv3d = ED_view3d_context_rv3d(man->data.context);
+ if (rv3d) {
+ normalize_v3_v3(man->data.rotate_axis, rv3d->viewinv[2]);
+ normalize_v3_v3(man->data.rotate_up, rv3d->viewinv[1]);
+
+ /* ensure its orthogonal */
+ project_plane_normalized_v3_v3v3(man->data.rotate_up, man->data.rotate_up, man->data.rotate_axis);
+ normalize_v3(man->data.rotate_up);
+
+ WM_manipulator_set_matrix_rotation_from_z_axis(man->translate_c, plane_no);
+
+ float plane_no_cross[3];
+ cross_v3_v3v3(plane_no_cross, plane_no, man->data.rotate_axis);
+
+ WM_manipulator_set_matrix_offset_rotation_from_yz_axis(man->rotate_c, plane_no_cross, man->data.rotate_axis);
+ RNA_enum_set(man->rotate_c->ptr, "draw_options",
+ ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_MIRROR |
+ ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_START_Y);
+ }
+}
+
+/* depth callbacks */
+static void manipulator_bisect_prop_depth_get(
+ const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
+ void *value_p)
+{
+ ManipulatorGroup *man = mpr->parent_mgroup->customdata;
+ wmOperator *op = man->data.op;
+ float *value = value_p;
+
+ BLI_assert(mpr_prop->type->array_length == 1);
+ UNUSED_VARS_NDEBUG(mpr_prop);
+
+ float plane_co[3], plane_no[3];
+ RNA_property_float_get_array(op->ptr, man->data.prop_plane_co, plane_co);
+ RNA_property_float_get_array(op->ptr, man->data.prop_plane_no, plane_no);
+
+ value[0] = dot_v3v3(plane_no, plane_co) - dot_v3v3(plane_no, mpr->matrix_basis[3]);
+}
+
+static void manipulator_bisect_prop_depth_set(
+ const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
+ const void *value_p)
+{
+ ManipulatorGroup *man = mpr->parent_mgroup->customdata;
+ wmOperator *op = man->data.op;
+ const float *value = value_p;
+
+ BLI_assert(mpr_prop->type->array_length == 1);
+ UNUSED_VARS_NDEBUG(mpr_prop);
+
+ float plane_co[3], plane[4];
+ RNA_property_float_get_array(op->ptr, man->data.prop_plane_co, plane_co);
+ RNA_property_float_get_array(op->ptr, man->data.prop_plane_no, plane);
+ normalize_v3(plane);
+
+ plane[3] = -value[0] - dot_v3v3(plane, mpr->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, man->data.prop_plane_co, plane_co);
+
+ manipulator_bisect_exec(man);
+}
+
+/* translate callbacks */
+static void manipulator_bisect_prop_translate_get(
+ const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
+ void *value_p)
+{
+ ManipulatorGroup *man = mpr->parent_mgroup->customdata;
+ wmOperator *op = man->data.op;
+
+ BLI_assert(mpr_prop->type->array_length == 3);
+ UNUSED_VARS_NDEBUG(mpr_prop);
+
+ RNA_property_float_get_array(op->ptr, man->data.prop_plane_co, value_p);
+}
+
+static void manipulator_bisect_prop_translate_set(
+ const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
+ const void *value_p)
+{
+ ManipulatorGroup *man = mpr->parent_mgroup->customdata;
+ wmOperator *op = man->data.op;
+
+ BLI_assert(mpr_prop->type->array_length == 3);
+ UNUSED_VARS_NDEBUG(mpr_prop);
+
+ RNA_property_float_set_array(op->ptr, man->data.prop_plane_co, value_p);
+
+ manipulator_bisect_exec(man);
+}
+
+/* angle callbacks */
+static void manipulator_bisect_prop_angle_get(
+ const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
+ void *value_p)
+{
+ ManipulatorGroup *man = mpr->parent_mgroup->customdata;
+ wmOperator *op = man->data.op;
+ float *value = value_p;
+
+ BLI_assert(mpr_prop->type->array_length == 1);
+ UNUSED_VARS_NDEBUG(mpr_prop);
+
+ float plane_no[4];
+ RNA_property_float_get_array(op->ptr, man->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, man->data.rotate_axis);
+
+ if (!is_zero_v3(plane_no_proj)) {
+ const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, man->data.rotate_up, man->data.rotate_axis);
+ value[0] = angle;
+ }
+ else {
+ value[0] = 0.0f;
+ }
+}
+
+static void manipulator_bisect_prop_angle_set(
+ const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
+ const void *value_p)
+{
+ ManipulatorGroup *man = mpr->parent_mgroup->customdata;
+ wmOperator *op = man->data.op;
+ const float *value = value_p;
+
+ BLI_assert(mpr_prop->type->array_length == 1);
+ UNUSED_VARS_NDEBUG(mpr_prop);
+
+ float plane_no[4];
+ RNA_property_float_get_array(op->ptr, man->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, man->data.rotate_axis);
+
+ if (!is_zero_v3(plane_no_proj)) {
+ const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, man->data.rotate_up, man->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, man->data.rotate_axis, angle_delta);
+ mul_m3_v3(mat, plane_no);
+
+ /* re-normalize - seems acceptable */
+ RNA_property_float_set_array(op->ptr, man->data.prop_plane_no, plane_no);
+
+ manipulator_bisect_exec(man);
+ }
+ }
}
+
+static bool manipulator_mesh_bisect_poll(const bContext *C, wmManipulatorGroupType *wgt)
+{
+ wmOperator *op = WM_operator_last_redo(C);
+ if (op == NULL || !STREQ(op->type->idname, "MESH_OT_bisect")) {
+ WM_manipulator_group_remove_ptr_delayed(wgt);
+ return false;
+ }
+ return true;
+}
+
+static void manipulator_mesh_bisect_setup(const bContext *C, wmManipulatorGroup *mgroup)
+{
+ wmOperator *op = WM_operator_last_redo(C);
+
+ if (op == NULL || !STREQ(op->type->idname, "MESH_OT_bisect")) {
+ return;
+ }
+
+ struct ManipulatorGroup *man = MEM_callocN(sizeof(ManipulatorGroup), __func__);
+ mgroup->customdata = man;
+
+ const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_3d", true);
+ const wmManipulatorType *wt_grab = WM_manipulatortype_find("MANIPULATOR_WT_grab_3d", true);
+ const wmManipulatorType *wt_dial = WM_manipulatortype_find("MANIPULATOR_WT_dial_3d", true);
+
+ man->translate_z = WM_manipulator_new_ptr(wt_arrow, mgroup, "translate_z", NULL);
+ man->translate_c = WM_manipulator_new_ptr(wt_grab, mgroup, "translate_c", NULL);
+ man->rotate_c = WM_manipulator_new_ptr(wt_dial, mgroup, "rotate_c", NULL);
+
+ RNA_enum_set(man->translate_z->ptr, "draw_style", ED_MANIPULATOR_ARROW_STYLE_NORMAL);
+ RNA_enum_set(man->translate_c->ptr, "draw_style", ED_MANIPULATOR_GRAB_STYLE_RING);
+
+ WM_manipulator_set_flag(man->translate_c, WM_MANIPULATOR_DRAW_VALUE, true);
+ WM_manipulator_set_flag(man->rotate_c, WM_MANIPULATOR_DRAW_VALUE, true);
+
+ {
+ man->data.context = (bContext *)C;
+ man->data.op = op;
+ man->data.prop_plane_co = RNA_struct_find_property(op->ptr, "plane_co");
+ man->data.prop_plane_no = RNA_struct_find_property(op->ptr, "plane_no");
+ }
+
+ manipulator_mesh_bisect_update_from_op(man);
+
+ /* Setup property callbacks */
+ {
+ WM_manipulator_target_property_def_func(
+ man->translate_z, "offset",
+ &(const struct wmManipulatorPropertyFnParams) {
+ .value_get_fn = manipulator_bisect_prop_depth_get,
+ .value_set_fn = manipulator_bisect_prop_depth_set,
+ .range_get_fn = NULL,
+ .user_data = NULL,
+ });
+
+ WM_manipulator_target_property_def_func(
+ man->translate_c, "offset",
+ &(const struct wmManipulatorPropertyFnParams) {
+ .value_get_fn = manipulator_bisect_prop_translate_get,
+ .value_set_fn = manipulator_bisect_prop_translate_set,
+ .range_get_fn = NULL,
+ .user_data = NULL,
+ });
+
+ WM_manipulator_target_property_def_func(
+ man->rotate_c, "offset",
+ &(const struct wmManipulatorPropertyFnParams) {
+ .value_get_fn = manipulator_bisect_prop_angle_get,
+ .value_set_fn = manipulator_bisect_prop_angle_set,
+ .range_get_fn = NULL,
+ .user_data = NULL,
+ });
+ }
+}
+
+static void manipulator_mesh_bisect_draw_prepare(
+ const bContext *UNUSED(C), wmManipulatorGroup *mgroup)
+{
+ ManipulatorGroup *man = mgroup->customdata;
+ manipulator_mesh_bisect_update_from_op(man);
+}
+
+static void MESH_WGT_bisect(struct wmManipulatorGroupType *wgt)
+{
+ wgt->name = "Mesh Bisect";
+ wgt->idname = "MESH_WGT_bisect";
+
+ wgt->flag = WM_MANIPULATORGROUPTYPE_3D;
+
+ wgt->mmap_params.spaceid = SPACE_VIEW3D;
+ wgt->mmap_params.regionid = RGN_TYPE_WINDOW;
+
+ wgt->poll = manipulator_mesh_bisect_poll;
+ wgt->setup = manipulator_mesh_bisect_setup;
+ wgt->draw_prepare = manipulator_mesh_bisect_draw_prepare;
+}
+
+/** \} */
+
+#endif /* USE_MANIPULATOR */
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index d4c49833c2c..d5b2a3d3b82 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -45,6 +45,7 @@
#include "RNA_define.h"
#include "RNA_access.h"
+#include "WM_api.h"
#include "WM_types.h"
#include "ED_mesh.h"
@@ -52,8 +53,17 @@
#include "ED_transform.h"
#include "ED_view3d.h"
+#include "MEM_guardedalloc.h"
+
#include "mesh_intern.h" /* own include */
+#define USE_MANIPULATOR
+
+#ifdef USE_MANIPULATOR
+#include "ED_manipulator_library.h"
+#include "ED_util.h"
+#endif
+
static void edbm_extrude_edge_exclude_mirror(
Object *obedit, BMEditMesh *em,
const char hflag,
@@ -584,7 +594,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
copy_v3_v3(min, cent);
mul_m4_v3(vc.obedit->obmat, min); /* view space */
- ED_view3d_win_to_3d_int(vc.ar, min, event->mval, min);
+ ED_view3d_win_to_3d_int(vc.v3d, vc.ar, min, event->mval, min);
mul_m4_v3(vc.obedit->imat, min); // back in object space
sub_v3_v3(min, cent);
@@ -633,7 +643,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
BMOIter oiter;
copy_v3_v3(min, curs);
- ED_view3d_win_to_3d_int(vc.ar, min, event->mval, min);
+ ED_view3d_win_to_3d_int(vc.v3d, vc.ar, min, event->mval, min);
invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
mul_m4_v3(vc.obedit->imat, min); // back in object space
@@ -743,9 +753,25 @@ static int edbm_spin_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e
}
}
- return edbm_spin_exec(C, op);
+ int ret = edbm_spin_exec(C, op);
+
+#ifdef USE_MANIPULATOR
+ if (ret & OPERATOR_FINISHED) {
+ /* Setup manipulators */
+ if (v3d && (v3d->twtype & V3D_MANIPULATOR_DRAW)) {
+ WM_manipulator_group_add("MESH_WGT_spin");
+ }
+ }
+#endif
+
+ return ret;
+
}
+#ifdef USE_MANIPULATOR
+static void MESH_WGT_spin(struct wmManipulatorGroupType *wgt);
+#endif
+
void MESH_OT_spin(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -774,8 +800,376 @@ 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);
+#ifdef USE_MANIPULATOR
+ WM_manipulatorgrouptype_append(MESH_WGT_spin);
+#endif
+}
+
+
+#ifdef USE_MANIPULATOR
+
+/* -------------------------------------------------------------------- */
+
+/** \name Spin Manipulator
+ * \{ */
+
+typedef struct ManipulatorSpinGroup {
+ /* Arrow to change plane depth. */
+ struct wmManipulator *translate_z;
+ /* Translate XYZ */
+ struct wmManipulator *translate_c;
+ /* For grabbing the manipulator and moving freely. */
+ struct wmManipulator *rotate_c;
+ /* Spin angle */
+ struct wmManipulator *angle_z;
+
+ /* We could store more vars here! */
+ struct {
+ bContext *context;
+ wmOperator *op;
+ PropertyRNA *prop_axis_co;
+ PropertyRNA *prop_axis_no;
+ PropertyRNA *prop_angle;
+
+ float rotate_axis[3];
+ float rotate_up[3];
+ } data;
+} ManipulatorSpinGroup;
+
+/**
+ * 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 manipulator_spin_exec(ManipulatorSpinGroup *man)
+{
+ wmOperator *op = man->data.op;
+ if (op == WM_operator_last_redo((bContext *)man->data.context)) {
+ ED_undo_operator_repeat((bContext *)man->data.context, op);
+ }
}
+static void manipulator_mesh_spin_update_from_op(ManipulatorSpinGroup *man)
+{
+ wmOperator *op = man->data.op;
+
+ float plane_co[3], plane_no[3];
+
+ RNA_property_float_get_array(op->ptr, man->data.prop_axis_co, plane_co);
+ RNA_property_float_get_array(op->ptr, man->data.prop_axis_no, plane_no);
+
+ WM_manipulator_set_matrix_location(man->translate_z, plane_co);
+ WM_manipulator_set_matrix_location(man->translate_c, plane_co);
+ WM_manipulator_set_matrix_location(man->rotate_c, plane_co);
+ WM_manipulator_set_matrix_location(man->angle_z, plane_co);
+
+ WM_manipulator_set_matrix_rotation_from_z_axis(man->translate_z, plane_no);
+ WM_manipulator_set_matrix_rotation_from_z_axis(man->angle_z, plane_no);
+
+ WM_manipulator_set_scale(man->translate_c, 0.2);
+
+ RegionView3D *rv3d = ED_view3d_context_rv3d(man->data.context);
+ if (rv3d) {
+ normalize_v3_v3(man->data.rotate_axis, rv3d->viewinv[2]);
+ normalize_v3_v3(man->data.rotate_up, rv3d->viewinv[1]);
+
+ /* ensure its orthogonal */
+ project_plane_normalized_v3_v3v3(man->data.rotate_up, man->data.rotate_up, man->data.rotate_axis);
+ normalize_v3(man->data.rotate_up);
+
+ WM_manipulator_set_matrix_rotation_from_z_axis(man->translate_c, plane_no);
+ WM_manipulator_set_matrix_rotation_from_yz_axis(man->rotate_c, man->data.rotate_axis, plane_no);
+
+ /* show the axis instead of mouse cursor */
+ RNA_enum_set(man->rotate_c->ptr, "draw_options",
+ ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_MIRROR |
+ ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_START_Y);
+
+ }
+}
+
+/* depth callbacks */
+static void manipulator_spin_prop_depth_get(
+ const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
+ void *value_p)
+{
+ ManipulatorSpinGroup *man = mpr->parent_mgroup->customdata;
+ wmOperator *op = man->data.op;
+ float *value = value_p;
+
+ BLI_assert(mpr_prop->type->array_length == 1);
+ UNUSED_VARS_NDEBUG(mpr_prop);
+
+ float plane_co[3], plane_no[3];
+ RNA_property_float_get_array(op->ptr, man->data.prop_axis_co, plane_co);
+ RNA_property_float_get_array(op->ptr, man->data.prop_axis_no, plane_no);
+
+ value[0] = dot_v3v3(plane_no, plane_co) - dot_v3v3(plane_no, mpr->matrix_basis[3]);
+}
+
+static void manipulator_spin_prop_depth_set(
+ const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
+ const void *value_p)
+{
+ ManipulatorSpinGroup *man = mpr->parent_mgroup->customdata;
+ wmOperator *op = man->data.op;
+ const float *value = value_p;
+
+ BLI_assert(mpr_prop->type->array_length == 1);
+ UNUSED_VARS_NDEBUG(mpr_prop);
+
+ float plane_co[3], plane[4];
+ RNA_property_float_get_array(op->ptr, man->data.prop_axis_co, plane_co);
+ RNA_property_float_get_array(op->ptr, man->data.prop_axis_no, plane);
+ normalize_v3(plane);
+
+ plane[3] = -value[0] - dot_v3v3(plane, mpr->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, man->data.prop_axis_co, plane_co);
+
+ manipulator_spin_exec(man);
+}
+
+/* translate callbacks */
+static void manipulator_spin_prop_translate_get(
+ const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
+ void *value_p)
+{
+ ManipulatorSpinGroup *man = mpr->parent_mgroup->customdata;
+ wmOperator *op = man->data.op;
+ float *value = value_p;
+
+ BLI_assert(mpr_prop->type->array_length == 3);
+ UNUSED_VARS_NDEBUG(mpr_prop);
+
+ RNA_property_float_get_array(op->ptr, man->data.prop_axis_co, value);
+}
+
+static void manipulator_spin_prop_translate_set(
+ const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
+ const void *value)
+{
+ ManipulatorSpinGroup *man = mpr->parent_mgroup->customdata;
+ wmOperator *op = man->data.op;
+
+ BLI_assert(mpr_prop->type->array_length == 3);
+ UNUSED_VARS_NDEBUG(mpr_prop);
+
+ RNA_property_float_set_array(op->ptr, man->data.prop_axis_co, value);
+
+ manipulator_spin_exec(man);
+}
+
+/* angle callbacks */
+static void manipulator_spin_prop_axis_angle_get(
+ const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
+ void *value_p)
+{
+ ManipulatorSpinGroup *man = mpr->parent_mgroup->customdata;
+ wmOperator *op = man->data.op;
+ float *value = value_p;
+
+ BLI_assert(mpr_prop->type->array_length == 1);
+ UNUSED_VARS_NDEBUG(mpr_prop);
+
+ float plane_no[4];
+ RNA_property_float_get_array(op->ptr, man->data.prop_axis_no, plane_no);
+ normalize_v3(plane_no);
+
+ float plane_no_proj[3];
+ project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, man->data.rotate_axis);
+
+ if (!is_zero_v3(plane_no_proj)) {
+ const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, man->data.rotate_up, man->data.rotate_axis);
+ value[0] = angle;
+ }
+ else {
+ value[0] = 0.0f;
+ }
+}
+
+static void manipulator_spin_prop_axis_angle_set(
+ const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
+ const void *value_p)
+{
+ ManipulatorSpinGroup *man = mpr->parent_mgroup->customdata;
+ wmOperator *op = man->data.op;
+ const float *value = value_p;
+
+ BLI_assert(mpr_prop->type->array_length == 1);
+ UNUSED_VARS_NDEBUG(mpr_prop);
+
+ float plane_no[4];
+ RNA_property_float_get_array(op->ptr, man->data.prop_axis_no, plane_no);
+ normalize_v3(plane_no);
+
+ float plane_no_proj[3];
+ project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, man->data.rotate_axis);
+
+ if (!is_zero_v3(plane_no_proj)) {
+ const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, man->data.rotate_up, man->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, man->data.rotate_axis, angle_delta);
+ mul_m3_v3(mat, plane_no);
+
+ /* re-normalize - seems acceptable */
+ RNA_property_float_set_array(op->ptr, man->data.prop_axis_no, plane_no);
+
+ manipulator_spin_exec(man);
+ }
+ }
+}
+
+/* angle callbacks */
+static void manipulator_spin_prop_angle_get(
+ const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
+ void *value_p)
+{
+ ManipulatorSpinGroup *man = mpr->parent_mgroup->customdata;
+ wmOperator *op = man->data.op;
+ float *value = value_p;
+
+ BLI_assert(mpr_prop->type->array_length == 1);
+ UNUSED_VARS_NDEBUG(mpr_prop);
+ value[0] = RNA_property_float_get(op->ptr, man->data.prop_angle);
+}
+
+static void manipulator_spin_prop_angle_set(
+ const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
+ const void *value_p)
+{
+ ManipulatorSpinGroup *man = mpr->parent_mgroup->customdata;
+ wmOperator *op = man->data.op;
+ BLI_assert(mpr_prop->type->array_length == 1);
+ UNUSED_VARS_NDEBUG(mpr_prop);
+ const float *value = value_p;
+ RNA_property_float_set(op->ptr, man->data.prop_angle, value[0]);
+
+ manipulator_spin_exec(man);
+}
+
+static bool manipulator_mesh_spin_poll(const bContext *C, wmManipulatorGroupType *wgt)
+{
+ wmOperator *op = WM_operator_last_redo(C);
+ if (op == NULL || !STREQ(op->type->idname, "MESH_OT_spin")) {
+ WM_manipulator_group_remove_ptr_delayed(wgt);
+ return false;
+ }
+ return true;
+}
+
+static void manipulator_mesh_spin_setup(const bContext *C, wmManipulatorGroup *mgroup)
+{
+ wmOperator *op = WM_operator_last_redo(C);
+
+ if (op == NULL || !STREQ(op->type->idname, "MESH_OT_spin")) {
+ return;
+ }
+
+ struct ManipulatorSpinGroup *man = MEM_callocN(sizeof(ManipulatorSpinGroup), __func__);
+ mgroup->customdata = man;
+
+ const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_3d", true);
+ const wmManipulatorType *wt_grab = WM_manipulatortype_find("MANIPULATOR_WT_grab_3d", true);
+ const wmManipulatorType *wt_dial = WM_manipulatortype_find("MANIPULATOR_WT_dial_3d", true);
+
+ man->translate_z = WM_manipulator_new_ptr(wt_arrow, mgroup, "translate_z", NULL);
+ man->translate_c = WM_manipulator_new_ptr(wt_grab, mgroup, "translate_c", NULL);
+ man->rotate_c = WM_manipulator_new_ptr(wt_dial, mgroup, "rotate_c", NULL);
+ man->angle_z = WM_manipulator_new_ptr(wt_dial, mgroup, "angle_z", NULL);
+
+ RNA_enum_set(man->translate_z->ptr, "draw_style", ED_MANIPULATOR_ARROW_STYLE_NORMAL);
+ RNA_enum_set(man->translate_c->ptr, "draw_style", ED_MANIPULATOR_GRAB_STYLE_RING);
+
+ WM_manipulator_set_flag(man->translate_c, WM_MANIPULATOR_DRAW_VALUE, true);
+ WM_manipulator_set_flag(man->rotate_c, WM_MANIPULATOR_DRAW_VALUE, true);
+ WM_manipulator_set_flag(man->angle_z, WM_MANIPULATOR_DRAW_VALUE, true);
+
+ WM_manipulator_set_scale(man->angle_z, 0.5f);
+
+ {
+ man->data.context = (bContext *)C;
+ man->data.op = op;
+ man->data.prop_axis_co = RNA_struct_find_property(op->ptr, "center");
+ man->data.prop_axis_no = RNA_struct_find_property(op->ptr, "axis");
+ man->data.prop_angle = RNA_struct_find_property(op->ptr, "angle");
+ }
+
+ manipulator_mesh_spin_update_from_op(man);
+
+ /* Setup property callbacks */
+ {
+ WM_manipulator_target_property_def_func(
+ man->translate_z, "offset",
+ &(const struct wmManipulatorPropertyFnParams) {
+ .value_get_fn = manipulator_spin_prop_depth_get,
+ .value_set_fn = manipulator_spin_prop_depth_set,
+ .range_get_fn = NULL,
+ .user_data = NULL,
+ });
+
+ WM_manipulator_target_property_def_func(
+ man->translate_c, "offset",
+ &(const struct wmManipulatorPropertyFnParams) {
+ .value_get_fn = manipulator_spin_prop_translate_get,
+ .value_set_fn = manipulator_spin_prop_translate_set,
+ .range_get_fn = NULL,
+ .user_data = NULL,
+ });
+
+ WM_manipulator_target_property_def_func(
+ man->rotate_c, "offset",
+ &(const struct wmManipulatorPropertyFnParams) {
+ .value_get_fn = manipulator_spin_prop_axis_angle_get,
+ .value_set_fn = manipulator_spin_prop_axis_angle_set,
+ .range_get_fn = NULL,
+ .user_data = NULL,
+ });
+
+ WM_manipulator_target_property_def_func(
+ man->angle_z, "offset",
+ &(const struct wmManipulatorPropertyFnParams) {
+ .value_get_fn = manipulator_spin_prop_angle_get,
+ .value_set_fn = manipulator_spin_prop_angle_set,
+ .range_get_fn = NULL,
+ .user_data = NULL,
+ });
+
+ }
+}
+
+static void manipulator_mesh_spin_draw_prepare(
+ const bContext *UNUSED(C), wmManipulatorGroup *mgroup)
+{
+ ManipulatorSpinGroup *man = mgroup->customdata;
+ manipulator_mesh_spin_update_from_op(man);
+}
+
+static void MESH_WGT_spin(struct wmManipulatorGroupType *wgt)
+{
+ wgt->name = "Mesh Spin";
+ wgt->idname = "MESH_WGT_spin";
+
+ wgt->flag = WM_MANIPULATORGROUPTYPE_3D;
+
+ wgt->mmap_params.spaceid = SPACE_VIEW3D;
+ wgt->mmap_params.regionid = RGN_TYPE_WINDOW;
+
+ wgt->poll = manipulator_mesh_spin_poll;
+ wgt->setup = manipulator_mesh_spin_setup;
+ wgt->draw_prepare = manipulator_mesh_spin_draw_prepare;
+}
+
+/** \} */
+
+#endif /* USE_MANIPULATOR */
+
+
static int edbm_screw_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index 281a8b2a02d..49bfde77032 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -51,6 +51,7 @@
#include "mesh_intern.h" /* own include */
#include "tools/bmesh_intersect.h"
+#include "tools/bmesh_separate.h"
/* detect isolated holes and fill them */
@@ -137,6 +138,12 @@ enum {
ISECT_SEL_UNSEL = 1,
};
+enum {
+ ISECT_SEPARATE_ALL = 0,
+ ISECT_SEPARATE_CUT = 1,
+ ISECT_SEPARATE_NONE = 2,
+};
+
static int edbm_intersect_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -144,7 +151,9 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op)
BMesh *bm = em->bm;
const int mode = RNA_enum_get(op->ptr, "mode");
int (*test_fn)(BMFace *, void *);
- bool use_separate = RNA_boolean_get(op->ptr, "use_separate");
+ bool use_separate_all = false;
+ bool use_separate_cut = false;
+ const int separate_mode = RNA_enum_get(op->ptr, "separate_mode");
const float eps = RNA_float_get(op->ptr, "threshold");
bool use_self;
bool has_isect;
@@ -160,15 +169,38 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op)
break;
}
+ switch (separate_mode) {
+ case ISECT_SEPARATE_ALL:
+ use_separate_all = true;
+ break;
+ case ISECT_SEPARATE_CUT:
+ if (use_self == false) {
+ use_separate_cut = true;
+ }
+ else {
+ /* we could support this but would require more advanced logic inside 'BM_mesh_intersect'
+ * for now just separate all */
+ use_separate_all = true;
+ }
+ break;
+ default: /* ISECT_SEPARATE_NONE */
+ break;
+ }
has_isect = BM_mesh_intersect(
bm,
em->looptris, em->tottri,
test_fn, NULL,
- use_self, use_separate, true, true,
+ use_self, use_separate_all, 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 (has_isect) {
edbm_intersect_select(em);
@@ -190,6 +222,16 @@ void MESH_OT_intersect(struct wmOperatorType *ot)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem isect_separate_items[] = {
+ {ISECT_SEPARATE_ALL, "ALL", 0, "All",
+ "Separate all geometry from intersections"},
+ {ISECT_SEPARATE_CUT, "CUT", 0, "Cut",
+ "Cut into geometry keeping each side separate (Selected/Unselected only)"},
+ {ISECT_SEPARATE_NONE, "NONE", 0, "Merge",
+ "Merge all geometry from the intersection"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
/* identifiers */
ot->name = "Intersect (Knife)";
ot->description = "Cut an intersection into faces";
@@ -201,7 +243,7 @@ void MESH_OT_intersect(struct wmOperatorType *ot)
/* props */
RNA_def_enum(ot->srna, "mode", isect_mode_items, ISECT_SEL_UNSEL, "Source", "");
- RNA_def_boolean(ot->srna, "use_separate", true, "Separate", "");
+ RNA_def_enum(ot->srna, "separate_mode", isect_separate_items, ISECT_SEPARATE_CUT, "Separate Mode", "");
RNA_def_float_distance(ot->srna, "threshold", 0.000001f, 0.0, 0.01, "Merge threshold", "", 0.0, 0.001);
/* flags */
@@ -239,7 +281,7 @@ static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op)
bm,
em->looptris, em->tottri,
test_fn, NULL,
- false, false, true, true,
+ false, false, true, true, true,
boolean_operation,
eps);
@@ -439,7 +481,7 @@ static void bm_face_split_by_edges_island_connect(
LinkNode *e_link, const int e_link_len,
MemArena *mem_arena_edgenet)
{
- BMEdge **edge_arr = BLI_memarena_alloc(mem_arena_edgenet, sizeof(BMEdge **) * e_link_len);
+ BMEdge **edge_arr = BLI_memarena_alloc(mem_arena_edgenet, sizeof(*edge_arr) * e_link_len);
int edge_arr_len = 0;
while (e_link) {
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index a84b8d9dcc8..3c974e4b3b9 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -54,8 +54,8 @@
#include "BKE_editmesh_bvh.h"
#include "BKE_report.h"
-#include "BIF_gl.h"
-#include "BIF_glutil.h" /* for paint cursor */
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
#include "ED_screen.h"
#include "ED_space_api.h"
@@ -971,7 +971,7 @@ static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd)
copy_v3_v3(co_depth, kcd->prev.cage);
mul_m4_v3(kcd->ob->obmat, co_depth);
- ED_view3d_win_to_3d(kcd->ar, co_depth, kcd->curr.mval, curr_cage_adjust);
+ ED_view3d_win_to_3d(kcd->vc.v3d, kcd->ar, co_depth, kcd->curr.mval, curr_cage_adjust);
mul_m4_v3(kcd->ob->imat, curr_cage_adjust);
sub_v3_v3v3(ray_dir, curr_cage_adjust, kcd->prev.cage);
@@ -1002,12 +1002,18 @@ static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd)
copy_v3_v3(v2, ray_hit_best[1]);
}
- UI_ThemeColor(TH_TRANSFORM);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformThemeColor(TH_TRANSFORM);
glLineWidth(2.0);
- glBegin(GL_LINES);
- glVertex3fv(v1);
- glVertex3fv(v2);
- glEnd();
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex3fv(pos, v1);
+ immVertex3fv(pos, v2);
+ immEnd();
+
+ immUnbindProgram();
}
static void knife_init_colors(KnifeColors *colors)
@@ -1035,66 +1041,69 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
glPolygonOffset(1.0f, 1.0f);
- glPushMatrix();
- glMultMatrixf(kcd->ob->obmat);
+ gpuPushMatrix();
+ gpuMultMatrix(kcd->ob->obmat);
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
if (kcd->mode == MODE_DRAGGING) {
if (kcd->is_angle_snapping)
knifetool_draw_angle_snapping(kcd);
- glColor3ubv(kcd->colors.line);
-
+ immUniformColor3ubv(kcd->colors.line);
glLineWidth(2.0);
- glBegin(GL_LINES);
- glVertex3fv(kcd->prev.cage);
- glVertex3fv(kcd->curr.cage);
- glEnd();
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex3fv(pos, kcd->prev.cage);
+ immVertex3fv(pos, kcd->curr.cage);
+ immEnd();
}
if (kcd->prev.vert) {
- glColor3ubv(kcd->colors.point);
+ immUniformColor3ubv(kcd->colors.point);
glPointSize(11);
- glBegin(GL_POINTS);
- glVertex3fv(kcd->prev.cage);
- glEnd();
+ immBegin(GWN_PRIM_POINTS, 1);
+ immVertex3fv(pos, kcd->prev.cage);
+ immEnd();
}
if (kcd->prev.bmface) {
- glColor3ubv(kcd->colors.curpoint);
+ immUniformColor3ubv(kcd->colors.curpoint);
glPointSize(9);
- glBegin(GL_POINTS);
- glVertex3fv(kcd->prev.cage);
- glEnd();
+ immBegin(GWN_PRIM_POINTS, 1);
+ immVertex3fv(pos, kcd->prev.cage);
+ immEnd();
}
if (kcd->curr.edge) {
- glColor3ubv(kcd->colors.edge);
+ immUniformColor3ubv(kcd->colors.edge);
glLineWidth(2.0);
- glBegin(GL_LINES);
- glVertex3fv(kcd->curr.edge->v1->cageco);
- glVertex3fv(kcd->curr.edge->v2->cageco);
- glEnd();
+ immBegin(GWN_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);
+ immUniformColor3ubv(kcd->colors.point);
glPointSize(11);
- glBegin(GL_POINTS);
- glVertex3fv(kcd->curr.cage);
- glEnd();
+ immBegin(GWN_PRIM_POINTS, 1);
+ immVertex3fv(pos, kcd->curr.cage);
+ immEnd();
}
if (kcd->curr.bmface) {
- glColor3ubv(kcd->colors.curpoint);
+ immUniformColor3ubv(kcd->colors.curpoint);
glPointSize(9);
- glBegin(GL_POINTS);
- glVertex3fv(kcd->curr.cage);
- glEnd();
+ immBegin(GWN_PRIM_POINTS, 1);
+ immVertex3fv(pos, kcd->curr.cage);
+ immEnd();
}
if (kcd->totlinehit > 0) {
@@ -1105,26 +1114,35 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
/* draw any snapped verts first */
- glColor4ubv(kcd->colors.point_a);
+ immUniformColor4ubv(kcd->colors.point_a);
glPointSize(11);
- glBegin(GL_POINTS);
+
+ immBeginAtMost(GWN_PRIM_POINTS, kcd->totlinehit);
+
lh = kcd->linehits;
for (i = 0; i < kcd->totlinehit; i++, lh++) {
- if (lh->v)
- glVertex3fv(lh->cagehit);
+ if (lh->v) {
+ immVertex3fv(pos, lh->cagehit);
+ }
}
- glEnd();
+
+ immEnd();
/* now draw the rest */
- glColor4ubv(kcd->colors.curpoint_a);
+ immUniformColor4ubv(kcd->colors.curpoint_a);
glPointSize(7);
- glBegin(GL_POINTS);
+
+ immBeginAtMost(GWN_PRIM_POINTS, kcd->totlinehit);
+
lh = kcd->linehits;
for (i = 0; i < kcd->totlinehit; i++, lh++) {
- if (!lh->v)
- glVertex3fv(lh->cagehit);
+ if (!lh->v) {
+ immVertex3fv(pos, lh->cagehit);
+ }
}
- glEnd();
+
+ immEnd();
+
glDisable(GL_BLEND);
}
@@ -1132,44 +1150,46 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
BLI_mempool_iter iter;
KnifeEdge *kfe;
+ immUniformColor3ubv(kcd->colors.line);
glLineWidth(1.0);
- glBegin(GL_LINES);
+
+ immBeginAtMost(GWN_PRIM_LINES, BLI_mempool_count(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();
}
if (kcd->totkvert > 0) {
BLI_mempool_iter iter;
KnifeVert *kfv;
+ immUniformColor3ubv(kcd->colors.point);
glPointSize(5.0);
- glBegin(GL_POINTS);
+ immBeginAtMost(GWN_PRIM_POINTS, BLI_mempool_count(kcd->kverts));
+
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();
}
- glPopMatrix();
+ immUnbindProgram();
+
+ gpuPopMatrix();
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
}
@@ -1396,7 +1416,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;
@@ -1414,7 +1434,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);
@@ -1472,7 +1492,7 @@ static void clip_to_ortho_planes(float v1[3], float v2[3], const float center[3]
/* could be v1 or v2 */
sub_v3_v3(v1, center);
- project_plane_v3_v3v3(closest, v1, dir);
+ project_plane_normalized_v3_v3v3(closest, v1, dir);
add_v3_v3(closest, center);
madd_v3_v3v3fl(v1, closest, dir, d);
@@ -1487,7 +1507,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;
@@ -1517,8 +1536,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;
@@ -1647,7 +1664,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;
@@ -1710,7 +1727,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 */
@@ -1739,7 +1756,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);
@@ -1751,7 +1768,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);
@@ -1784,13 +1801,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);
@@ -2140,7 +2153,7 @@ static float snap_v2_angle(float r[2], const float v[2], const float v_ref[2], f
normalize_v2_v2(v_unit, v);
angle = angle_signed_v2v2(v_unit, v_ref);
angle_delta = (roundf(angle / angle_snap) * angle_snap) - angle;
- rotate_m2(m2, angle_delta);
+ angle_to_mat2(m2, angle_delta);
mul_v2_m2v2(r, m2, v);
return angle + angle_delta;
@@ -2992,7 +3005,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);
@@ -3011,10 +3023,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 */
@@ -3123,7 +3131,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_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c
index f1c1e4105d0..6a656ace09c 100644
--- a/source/blender/editors/mesh/editmesh_loopcut.c
+++ b/source/blender/editors/mesh/editmesh_loopcut.c
@@ -45,7 +45,8 @@
#include "BKE_DerivedMesh.h"
#include "BKE_unit.h"
-#include "BIF_gl.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
#include "UI_interface.h"
@@ -104,27 +105,41 @@ static void ringsel_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
if (v3d && v3d->zbuf)
glDisable(GL_DEPTH_TEST);
- glPushMatrix();
- glMultMatrixf(lcd->ob->obmat);
+ gpuPushMatrix();
+ gpuMultMatrix(lcd->ob->obmat);
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor3ub(255, 0, 255);
- 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);
+ immBegin(GWN_PRIM_LINES, lcd->totedge * 2);
+
+ for (int i = 0; i < lcd->totedge; i++) {
+ immVertex3fv(pos, lcd->edges[i][0]);
+ immVertex3fv(pos, lcd->edges[i][1]);
+ }
+
+ immEnd();
}
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);
+ immBegin(GWN_PRIM_POINTS, lcd->totpoint);
+
+ for (int i = 0; i < lcd->totpoint; i++) {
+ immVertex3fv(pos, lcd->points[i]);
+ }
+
+ immEnd();
}
- glPopMatrix();
+ immUnbindProgram();
+
+ gpuPopMatrix();
+
if (v3d && v3d->zbuf)
glEnable(GL_DEPTH_TEST);
}
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index e31e4096ded..1a2f9fdb62b 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -496,7 +496,7 @@ static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *u
}
/* face should never exist */
- BLI_assert(BM_face_exists(f_verts, f_verts[3] ? 4 : 3, &f) == false);
+ BLI_assert(!BM_face_exists(f_verts, f_verts[3] ? 4 : 3));
f = BM_face_create_verts(bm, f_verts, f_verts[3] ? 4 : 3, f_example, BM_CREATE_NOP, true);
@@ -596,7 +596,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
BMVert *v_new;
BLI_assert(l_sep->v == v);
- v_new = bmesh_urmv_loop_region(bm, l_sep);
+ v_new = BM_face_loop_separate_multi_isolated(bm, l_sep);
BLI_assert(BM_vert_find_first_loop(v));
BM_vert_select_set(bm, v, false);
@@ -665,7 +665,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
BM_vert_select_set(bm, v, false);
- bmesh_vert_separate(bm, v, &vout, &vout_len, true);
+ bmesh_kernel_vert_separate(bm, v, &vout, &vout_len, true);
if (vout_len < 2) {
MEM_freeN(vout);
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 5d5731a7e16..c8d8ac68334 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -32,6 +32,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_bitmap.h"
+#include "BLI_bitmap_draw_2d.h"
#include "BLI_listbase.h"
#include "BLI_linklist.h"
#include "BLI_linklist_stack.h"
@@ -294,7 +295,7 @@ bool EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short
lasso_mask_data.px = dr_mask;
lasso_mask_data.width = (xmax - xmin) + 1;
- fill_poly_v2i_n(
+ BLI_bitmap_draw_2d_poly_v2i_n(
xmin, ymin, xmax + 1, ymax + 1,
mcords, tot,
edbm_mask_lasso_px_cb, &lasso_mask_data);
@@ -445,6 +446,9 @@ BMVert *EDBM_vert_find_nearest_ex(
unsigned int index;
BMVert *eve;
+ /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */
+ ED_view3d_backbuf_validate(vc);
+
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;
@@ -629,7 +633,8 @@ BMEdge *EDBM_edge_find_nearest_ex(
float dist_test = 0.0f;
unsigned int index;
BMEdge *eed;
-
+
+ /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */
ED_view3d_backbuf_validate(vc);
index = ED_view3d_backbuf_sample_rect(vc, vc->mval, dist_px, bm_solidoffs, bm_wireoffs, &dist_test);
@@ -984,13 +989,13 @@ static EnumPropertyItem prop_similar_types[] = {
#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", ""},
+ {SIMFACE_FACEMAP, "FACE_MAP", 0, "Face-Map", ""},
#ifdef WITH_FREESTYLE
{SIMFACE_FREESTYLE, "FREESTYLE_FACE", 0, "Freestyle Face Marks", ""},
#endif
@@ -1168,7 +1173,7 @@ static EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *UNUS
#ifdef WITH_FREESTYLE
const int a_end = SIMFACE_FREESTYLE;
#else
- const int a_end = SIMFACE_SMOOTH;
+ 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);
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 1a14fad8650..cbed6a37c1f 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -47,15 +47,18 @@
#include "BLI_rand.h"
#include "BLI_sort_utils.h"
+#include "BKE_layer.h"
#include "BKE_material.h"
#include "BKE_context.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.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"
#include "RNA_define.h"
@@ -306,7 +309,7 @@ void EMBM_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), SNAP_OBJECT_USE_CACHE,
+ CTX_data_main(C), CTX_data_scene(C), CTX_data_scene_layer(C), 0,
ar, CTX_wm_view3d(C));
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
@@ -684,27 +687,38 @@ static void edbm_add_edge_face_exec__tricky_finalize_sel(BMesh *bm, BMElem *ele_
/* now we need to find the edge that isnt connected to this element */
BM_select_history_clear(bm);
+ /* Notes on hidden geometry:
+ * - un-hide the face since its possible hidden was copied when copying surrounding face attributes.
+ * - un-hide before adding to select history
+ * since we may extend into an existing, hidden vert/edge.
+ */
+
+ BM_elem_flag_disable(f, BM_ELEM_HIDDEN);
+ BM_face_select_set(bm, f, false);
+
if (ele_desel->head.htype == BM_VERT) {
BMLoop *l = BM_face_vert_share_loop(f, (BMVert *)ele_desel);
BLI_assert(f->len == 3);
- BM_face_select_set(bm, f, false);
BM_vert_select_set(bm, (BMVert *)ele_desel, false);
-
BM_edge_select_set(bm, l->next->e, true);
BM_select_history_store(bm, l->next->e);
}
else {
BMLoop *l = BM_face_edge_share_loop(f, (BMEdge *)ele_desel);
BLI_assert(f->len == 4 || f->len == 3);
- BM_face_select_set(bm, f, false);
+
BM_edge_select_set(bm, (BMEdge *)ele_desel, false);
if (f->len == 4) {
- BM_edge_select_set(bm, l->next->next->e, true);
- BM_select_history_store(bm, l->next->next->e);
+ BMEdge *e_active = l->next->next->e;
+ BM_elem_flag_disable(e_active, BM_ELEM_HIDDEN);
+ BM_edge_select_set(bm, e_active, true);
+ BM_select_history_store(bm, e_active);
}
else {
- BM_vert_select_set(bm, l->next->next->v, true);
- BM_select_history_store(bm, l->next->next->v);
+ BMVert *v_active = l->next->next->v;
+ BM_elem_flag_disable(v_active, BM_ELEM_HIDDEN);
+ BM_vert_select_set(bm, v_active, true);
+ BM_select_history_store(bm, v_active);
}
}
}
@@ -758,6 +772,14 @@ static int edbm_add_edge_face_exec(bContext *C, wmOperator *op)
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);
+
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);
}
@@ -1561,6 +1583,18 @@ static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op)
/* 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);
+
+ 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);
+
+ BKE_reportf(op->reports, RPT_WARNING, "Unable to rotate %d edge(s)", tot_failed);
+ }
+
EDBM_selectmode_flush(em);
if (!EDBM_op_finish(em, &bmop, op, true)) {
@@ -2417,7 +2451,7 @@ static void shape_propagate(BMEditMesh *em, wmOperator *op)
//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);
+ DEG_id_tag_update(&base->object->id, OB_RECALC_DATA);
}
}
#endif
@@ -2979,7 +3013,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, SceneLayer *sl, Base *base_old, BMesh *bm_old)
{
Base *base_new;
Object *obedit = base_old->object;
@@ -3000,11 +3034,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, sl, base_old, USER_DUP_MESH);
/* DAG_relations_tag_update(bmain); */ /* normally would call directly after but in this case delay recalc */
assign_matarar(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);
@@ -3026,7 +3060,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, SceneLayer *sl, 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);
@@ -3034,7 +3068,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, sl, base_old, bm_old) != NULL);
}
/* flush a hflag to from verts to edges/faces */
@@ -3080,7 +3114,7 @@ static void bm_mesh_hflag_flush_vert(BMesh *bm, const char hflag)
* \note This could be used for split-by-material for non mesh types.
* \note This could take material data from another object or args.
*/
-static void mesh_separate_material_assign_mat_nr(Object *ob, const short mat_nr)
+static void mesh_separate_material_assign_mat_nr(Main *bmain, Object *ob, const short mat_nr)
{
ID *obdata = ob->data;
@@ -3116,22 +3150,24 @@ static void mesh_separate_material_assign_mat_nr(Object *ob, const short mat_nr)
ma_obdata = NULL;
}
- BKE_material_clear_id(obdata, true);
- BKE_material_resize_object(ob, 1, true);
- BKE_material_resize_id(obdata, 1, true);
+ BKE_material_clear_id(bmain, obdata, true);
+ BKE_material_resize_object(bmain, ob, 1, true);
+ BKE_material_resize_id(bmain, obdata, 1, true);
ob->mat[0] = ma_ob;
+ id_us_plus((ID *)ma_ob);
ob->matbits[0] = matbit;
(*matarar)[0] = ma_obdata;
+ id_us_plus((ID *)ma_obdata);
}
else {
- BKE_material_clear_id(obdata, true);
- BKE_material_resize_object(ob, 0, true);
- BKE_material_resize_id(obdata, 0, true);
+ BKE_material_clear_id(bmain, obdata, true);
+ BKE_material_resize_object(bmain, ob, 0, true);
+ BKE_material_resize_id(bmain, obdata, 0, true);
}
}
-static bool mesh_separate_material(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old)
+static bool mesh_separate_material(Main *bmain, Scene *scene, SceneLayer *sl, Base *base_old, BMesh *bm_old)
{
BMFace *f_cmp, *f;
BMIter iter;
@@ -3162,7 +3198,7 @@ static bool mesh_separate_material(Main *bmain, Scene *scene, Base *base_old, BM
/* leave the current object with some materials */
if (tot == bm_old->totface) {
- mesh_separate_material_assign_mat_nr(base_old->object, mat_nr);
+ mesh_separate_material_assign_mat_nr(bmain, base_old->object, mat_nr);
/* since we're in editmode, must set faces here */
BM_ITER_MESH (f, &iter, bm_old, BM_FACES_OF_MESH) {
@@ -3172,9 +3208,9 @@ 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, sl, base_old, bm_old);
if (base_new) {
- mesh_separate_material_assign_mat_nr(base_new->object, mat_nr);
+ mesh_separate_material_assign_mat_nr(bmain, base_new->object, mat_nr);
}
result |= (base_new != NULL);
@@ -3183,7 +3219,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, SceneLayer *sl, Base *base_old, BMesh *bm_old)
{
int i;
BMEdge *e;
@@ -3236,7 +3272,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, sl, base_old, bm_old) != NULL);
}
return result;
@@ -3246,6 +3282,7 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
const int type = RNA_enum_get(op->ptr, "type");
int retval = 0;
@@ -3266,13 +3303,13 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
/* editmode separate */
switch (type) {
case MESH_SEPARATE_SELECTED:
- retval = mesh_separate_selected(bmain, scene, base, em->bm);
+ retval = mesh_separate_selected(bmain, scene, sl, base, em->bm);
break;
case MESH_SEPARATE_MATERIAL:
- retval = mesh_separate_material(bmain, scene, base, em->bm);
+ retval = mesh_separate_material(bmain, scene, sl, base, em->bm);
break;
case MESH_SEPARATE_LOOSE:
- retval = mesh_separate_loose(bmain, scene, base, em->bm);
+ retval = mesh_separate_loose(bmain, scene, sl, base, em->bm);
break;
default:
BLI_assert(0);
@@ -3307,10 +3344,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, sl, 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, sl, base_iter, bm_old);
break;
default:
BLI_assert(0);
@@ -3320,7 +3357,7 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
if (retval_iter) {
BM_mesh_bm_to_me(bm_old, me, (&(struct BMeshToMeshParams){0}));
- 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);
}
@@ -3335,7 +3372,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;
@@ -5202,8 +5239,10 @@ static int edbm_noise_exec(bContext *C, wmOperator *op)
else {
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- float tin, dum;
- externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum, 0, NULL, false, false);
+ 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;
}
}
@@ -5851,7 +5890,7 @@ static int edbm_mark_freestyle_edge_exec(bContext *C, wmOperator *op)
}
}
- DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ DEG_id_tag_update(obedit->data, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
return OPERATOR_FINISHED;
@@ -5915,7 +5954,7 @@ static int edbm_mark_freestyle_face_exec(bContext *C, wmOperator *op)
}
}
- DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ DEG_id_tag_update(obedit->data, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index faa975406ce..a35f70caef3 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -369,7 +369,9 @@ struct UMArrayData {
UndoMesh *um;
const UndoMesh *um_ref; /* can be NULL */
};
-static void um_arraystore_compact_cb(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
+static void um_arraystore_compact_cb(TaskPool *__restrict UNUSED(pool),
+ void *taskdata,
+ int UNUSED(threadid))
{
struct UMArrayData *um_data = taskdata;
um_arraystore_compact_with_info(um_data->um, um_data->um_ref);
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 4fc61e0912e..555fe6c917d 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -44,7 +44,6 @@
#include "BKE_DerivedMesh.h"
#include "BKE_context.h"
#include "BKE_global.h"
-#include "BKE_depsgraph.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
@@ -52,6 +51,8 @@
#include "BKE_editmesh.h"
#include "BKE_editmesh_bvh.h"
+#include "DEG_depsgraph.h"
+
#include "BKE_object.h" /* XXX. only for EDBM_mesh_ensure_valid_dm_hack() which will be removed */
#include "WM_api.h"
@@ -116,7 +117,7 @@ void EDBM_mesh_ensure_valid_dm_hack(Scene *scene, BMEditMesh *em)
{
/* since we may not have done selection flushing */
if ((em->ob->recalc & OB_RECALC_DATA) == 0) {
- DAG_id_tag_update(&em->ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&em->ob->id, OB_RECALC_DATA);
}
BKE_object_handle_update(G.main->eval_ctx, scene, em->ob);
}
@@ -520,7 +521,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;
@@ -602,7 +602,6 @@ UvVertMap *BM_uv_vert_map_create(
newvlist = v;
efa = BM_face_at_index(bm, v->f);
- /* tf = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, v->tfindex);
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
@@ -614,7 +613,6 @@ UvVertMap *BM_uv_vert_map_create(
while (iterv) {
next = iterv->next;
efa = BM_face_at_index(bm, iterv->f);
- /* tf = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex);
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
@@ -929,29 +927,27 @@ 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 */
-MTexPoly *EDBM_mtexpoly_active_get(BMEditMesh *em, BMFace **r_act_efa, const bool sloppy, const bool selected)
+BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool selected)
{
BMFace *efa = NULL;
- if (!EDBM_mtexpoly_check(em))
+ if (!EDBM_uv_check(em))
return NULL;
efa = BM_mesh_active_face_get(em->bm, sloppy, selected);
if (efa) {
- if (r_act_efa) *r_act_efa = efa;
- return CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ return efa;
}
- if (r_act_efa) *r_act_efa = NULL;
return NULL;
}
/* can we edit UV's for this mesh?*/
-bool EDBM_mtexpoly_check(BMEditMesh *em)
+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) &&
+ return em && em->bm->totface &&
CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV);
}
@@ -1139,7 +1135,6 @@ BMEdge *EDBM_verts_mirror_get_edge(BMEditMesh *em, BMEdge *e)
BMFace *EDBM_verts_mirror_get_face(BMEditMesh *em, BMFace *f)
{
- BMFace *f_mirr = NULL;
BMVert **v_mirr_arr = BLI_array_alloca(v_mirr_arr, f->len);
BMLoop *l_iter, *l_first;
@@ -1152,8 +1147,7 @@ BMFace *EDBM_verts_mirror_get_face(BMEditMesh *em, BMFace *f)
}
} while ((l_iter = l_iter->next) != l_first);
- BM_face_exists(v_mirr_arr, f->len, &f_mirr);
- return f_mirr;
+ return BM_face_exists(v_mirr_arr, f->len);
}
void EDBM_verts_mirror_cache_clear(BMEditMesh *em, BMVert *v)
@@ -1283,7 +1277,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) {
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index 772bb1bd308..49755c75480 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -42,7 +42,6 @@
#include "BLI_math.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
@@ -50,6 +49,8 @@
#include "BKE_report.h"
#include "BKE_editmesh.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_define.h"
#include "WM_api.h"
@@ -245,14 +246,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_index(pdata, CD_MTEXPOLY);
+ CustomData *ldata = GET_CD_DATA(me, ldata);
+ const int layernum = CustomData_get_active_layer_index(ldata, CD_MLOOPUV);
ED_mesh_uv_loop_reset_ex(me, layernum);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
@@ -269,21 +270,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 +288,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 +315,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 +329,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 +343,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 +363,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 +376,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 +434,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;
@@ -477,7 +453,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;
@@ -551,7 +527,7 @@ static int drop_named_image_invoke(bContext *C, wmOperator *op, const wmEvent *e
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
- Base *base;
+ BaseLegacy *base;
Image *ima = NULL;
Mesh *me;
Object *obedit;
@@ -598,7 +574,7 @@ static int drop_named_image_invoke(bContext *C, wmOperator *op, const wmEvent *e
/* 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);
+ DEG_id_tag_update(&me->id, 0);
}
/* dummie drop support; ensure view shows a result :) */
@@ -737,7 +713,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;
@@ -833,7 +809,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;
@@ -895,7 +871,7 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator
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;
@@ -972,7 +948,7 @@ void ED_mesh_update(Mesh *mesh, bContext *C, int calc_edges, int 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);
}
@@ -1292,7 +1268,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_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c
index b95921964eb..66c77593c75 100644
--- a/source/blender/editors/mesh/mesh_navmesh.c
+++ b/source/blender/editors/mesh/mesh_navmesh.c
@@ -41,7 +41,6 @@
#include "BLI_linklist.h"
#include "BKE_library.h"
-#include "BKE_depsgraph.h"
#include "BKE_context.h"
#include "BKE_mesh.h"
#include "BKE_scene.h"
@@ -58,6 +57,8 @@
#include "recast-capi.h"
+#include "DEG_depsgraph.h"
+
#include "mesh_intern.h" /* own include */
@@ -326,7 +327,7 @@ static bool buildNavMesh(const RecastData *recastParams, int nverts, float *vert
}
static Object *createRepresentation(bContext *C, struct recast_polyMesh *pmesh, struct recast_polyMeshDetail *dmesh,
- Base *base, unsigned int lay)
+ BaseLegacy *base, unsigned int lay)
{
float co[3], rot[3];
BMEditMesh *em;
@@ -440,7 +441,7 @@ static Object *createRepresentation(bContext *C, struct recast_polyMesh *pmesh,
recast_destroyPolyMesh(pmesh);
recast_destroyPolyMeshDetail(dmesh);
- DAG_id_tag_update((ID *)obedit->data, OB_RECALC_DATA);
+ DEG_id_tag_update((ID *)obedit->data, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
@@ -461,14 +462,15 @@ static Object *createRepresentation(bContext *C, struct recast_polyMesh *pmesh,
static int navmesh_create_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
LinkNode *obs = NULL;
- Base *navmeshBase = NULL;
+ BaseLegacy *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) {
+ if (!navmeshBase || base == sl->basact) {
navmeshBase = base;
}
}
@@ -551,7 +553,7 @@ static int navmesh_face_copy_exec(bContext *C, wmOperator *op)
}
}
- DAG_id_tag_update((ID *)obedit->data, OB_RECALC_DATA);
+ DEG_id_tag_update((ID *)obedit->data, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
return OPERATOR_FINISHED;
@@ -632,7 +634,7 @@ static int navmesh_face_add_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- DAG_id_tag_update((ID *)obedit->data, OB_RECALC_DATA);
+ DEG_id_tag_update((ID *)obedit->data, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
return OPERATOR_FINISHED;
@@ -681,7 +683,7 @@ static int navmesh_reset_exec(bContext *C, wmOperator *UNUSED(op))
BKE_mesh_ensure_navmesh(me);
- 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->id);
return OPERATOR_FINISHED;
@@ -709,7 +711,7 @@ static int navmesh_clear_exec(bContext *C, wmOperator *UNUSED(op))
CustomData_free_layers(&me->pdata, CD_RECAST, me->totpoly);
- 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->id);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index b26989113d4..e7b1f925d5e 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -49,7 +49,6 @@
#include "BLI_kdtree.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_deform.h"
#include "BKE_DerivedMesh.h"
#include "BKE_key.h"
@@ -57,10 +56,14 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_material.h"
+#include "BKE_object.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"
#include "ED_view3d.h"
@@ -75,26 +78,217 @@
/* join selected meshes into the active mesh, context sensitive
* return 0 if no join is made (error) and 1 if the join is done */
+static void join_mesh_single(
+ Main *bmain, Scene *scene,
+ Object *ob_dst, Base *base_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,
+ int totvert, int totedge, int totloop, int totpoly,
+ Key *key, Key *nkey,
+ Material **matar, int *matmap, int totcol,
+ int *vertofs, int *edgeofs, int *loopofs, int *polyofs)
+{
+ int a, b;
+
+ Mesh *me = base_src->object->data;
+ MVert *mvert = *mvert_pp;
+ MEdge *medge = *medge_pp;
+ MLoop *mloop = *mloop_pp;
+ MPoly *mpoly = *mpoly_pp;
+
+ if (me->totvert) {
+ /* merge customdata flag */
+ ((Mesh *)ob_dst->data)->cd_flag |= me->cd_flag;
+
+ /* standard data */
+ CustomData_merge(&me->vdata, vdata, CD_MASK_MESH, CD_DEFAULT, totvert);
+ CustomData_copy_data_named(&me->vdata, vdata, 0, *vertofs, me->totvert);
+
+ /* vertex groups */
+ MDeformVert *dvert = CustomData_get(vdata, *vertofs, CD_MDEFORMVERT);
+ MDeformVert *dvert_src = CustomData_get(&me->vdata, 0, CD_MDEFORMVERT);
+
+ /* Remap to correct new vgroup indices, if needed. */
+ if (dvert_src) {
+ BLI_assert(dvert != NULL);
+
+ /* Build src to merged mapping of vgroup indices. */
+ bDeformGroup *dg_src;
+ int *vgroup_index_map = alloca(sizeof(*vgroup_index_map) * BLI_listbase_count(&base_src->object->defbase));
+ bool is_vgroup_remap_needed = false;
+
+ for (dg_src = base_src->object->defbase.first, b = 0; dg_src; dg_src = dg_src->next, b++) {
+ vgroup_index_map[b] = defgroup_name_index(ob_dst, dg_src->name);
+ is_vgroup_remap_needed = is_vgroup_remap_needed || (vgroup_index_map[b] != b);
+ }
+
+ if (is_vgroup_remap_needed) {
+ for (a = 0; a < me->totvert; a++) {
+ for (b = 0; b < dvert[a].totweight; b++) {
+ dvert[a].dw[b].def_nr = vgroup_index_map[dvert_src[a].dw[b].def_nr];
+ }
+ }
+ }
+ }
+
+ /* if this is the object we're merging into, no need to do anything */
+ if (base_src->object != ob_dst) {
+ float cmat[4][4];
+
+ /* watch this: switch matmul order really goes wrong */
+ mul_m4_m4m4(cmat, imat, base_src->object->obmat);
+
+ /* transform vertex coordinates into new space */
+ for (a = 0, mvert = *mvert_pp; a < me->totvert; a++, mvert++) {
+ mul_m4_v3(cmat, mvert->co);
+ }
+
+ /* for each shapekey in destination mesh:
+ * - if there's a matching one, copy it across (will need to transform vertices into new space...)
+ * - otherwise, just copy own coordinates of mesh (no need to transform vertex coordinates into new space)
+ */
+ if (key) {
+ /* if this mesh has any shapekeys, check first, otherwise just copy coordinates */
+ for (KeyBlock *kb = key->block.first; kb; kb = kb->next) {
+ /* get pointer to where to write data for this mesh in shapekey's data array */
+ float (*cos)[3] = ((float (*)[3])kb->data) + *vertofs;
+
+ /* check if this mesh has such a shapekey */
+ KeyBlock *okb = me->key ? BKE_keyblock_find_name(me->key, kb->name) : NULL;
+ if (okb) {
+ /* copy this mesh's shapekey to the destination shapekey (need to transform first) */
+ float (*ocos)[3] = okb->data;
+ for (a = 0; a < me->totvert; a++, cos++, ocos++) {
+ copy_v3_v3(*cos, *ocos);
+ mul_m4_v3(cmat, *cos);
+ }
+ }
+ else {
+ /* copy this mesh's vertex coordinates to the destination shapekey */
+ for (a = 0, mvert = *mvert_pp; a < me->totvert; a++, cos++, mvert++) {
+ copy_v3_v3(*cos, mvert->co);
+ }
+ }
+ }
+ }
+ }
+ else {
+ /* for each shapekey in destination mesh:
+ * - if it was an 'original', copy the appropriate data from nkey
+ * - otherwise, copy across plain coordinates (no need to transform coordinates)
+ */
+ if (key) {
+ for (KeyBlock *kb = key->block.first; kb; kb = kb->next) {
+ /* get pointer to where to write data for this mesh in shapekey's data array */
+ float (*cos)[3] = ((float (*)[3])kb->data) + *vertofs;
+
+ /* check if this was one of the original shapekeys */
+ KeyBlock *okb = nkey ? BKE_keyblock_find_name(nkey, kb->name) : NULL;
+ if (okb) {
+ /* copy this mesh's shapekey to the destination shapekey */
+ float (*ocos)[3] = okb->data;
+ for (a = 0; a < me->totvert; a++, cos++, ocos++) {
+ copy_v3_v3(*cos, *ocos);
+ }
+ }
+ else {
+ /* copy base-coordinates to the destination shapekey */
+ for (a = 0, mvert = *mvert_pp; a < me->totvert; a++, cos++, mvert++) {
+ copy_v3_v3(*cos, mvert->co);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (me->totedge) {
+ CustomData_merge(&me->edata, edata, CD_MASK_MESH, CD_DEFAULT, totedge);
+ CustomData_copy_data_named(&me->edata, edata, 0, *edgeofs, me->totedge);
+
+ for (a = 0; a < me->totedge; a++, medge++) {
+ medge->v1 += *vertofs;
+ medge->v2 += *vertofs;
+ }
+ }
+
+ if (me->totloop) {
+ if (base_src->object != ob_dst) {
+ MultiresModifierData *mmd;
+
+ multiresModifier_prepare_join(scene, base_src->object, ob_dst);
+
+ if ((mmd = get_multires_modifier(scene, base_src->object, true))) {
+ ED_object_iter_other(bmain, base_src->object, true,
+ ED_object_multires_update_totlevels_cb,
+ &mmd->totlvl);
+ }
+ }
+
+ CustomData_merge(&me->ldata, ldata, CD_MASK_MESH, CD_DEFAULT, totloop);
+ CustomData_copy_data_named(&me->ldata, ldata, 0, *loopofs, me->totloop);
+
+ for (a = 0; a < me->totloop; a++, mloop++) {
+ mloop->v += *vertofs;
+ mloop->e += *edgeofs;
+ }
+ }
+
+ if (me->totpoly) {
+ if (matmap) {
+ /* make mapping for materials */
+ for (a = 1; a <= base_src->object->totcol; a++) {
+ Material *ma = give_current_material(base_src->object, a);
+
+ for (b = 0; b < totcol; b++) {
+ if (ma == matar[b]) {
+ matmap[a - 1] = b;
+ break;
+ }
+ }
+ }
+ }
+
+ CustomData_merge(&me->pdata, pdata, CD_MASK_MESH, CD_DEFAULT, totpoly);
+ CustomData_copy_data_named(&me->pdata, pdata, 0, *polyofs, me->totpoly);
+
+ for (a = 0; a < me->totpoly; a++, mpoly++) {
+ mpoly->loopstart += *loopofs;
+ mpoly->mat_nr = matmap ? matmap[mpoly->mat_nr] : 0;
+ }
+ }
+
+ /* these are used for relinking (cannot be set earlier, or else reattaching goes wrong) */
+ *vertofs += me->totvert;
+ *mvert_pp += me->totvert;
+ *edgeofs += me->totedge;
+ *medge_pp += me->totedge;
+ *loopofs += me->totloop;
+ *mloop_pp += me->totloop;
+ *polyofs += me->totpoly;
+ *mpoly_pp += me->totpoly;
+}
+
int join_mesh_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- Material **matar, *ma;
+ Base *ob_base = CTX_data_active_base(C);
+ Object *ob = ob_base->object;
+ Material **matar = NULL, *ma;
Mesh *me;
- MVert *mvert, *mv;
+ MVert *mvert = NULL;
MEdge *medge = NULL;
MPoly *mpoly = NULL;
MLoop *mloop = NULL;
Key *key, *nkey = NULL;
- KeyBlock *kb, *okb, *kbn;
- float imat[4][4], cmat[4][4], *fp1, *fp2;
+ KeyBlock *kb, *kbn;
+ float imat[4][4];
int a, b, totcol, totmat = 0, totedge = 0, totvert = 0;
int totloop = 0, totpoly = 0, vertofs, *matmap = NULL;
- int i, j, index, haskey = 0, edgeofs, loopofs, polyofs;
+ int i, haskey = 0, edgeofs, loopofs, polyofs;
bool ok = false;
bDeformGroup *dg, *odg;
- MDeformVert *dvert;
CustomData vdata, edata, fdata, ldata, pdata;
if (scene->obedit) {
@@ -154,8 +348,10 @@ int join_mesh_exec(bContext *C, wmOperator *op)
BKE_mesh_tessface_clear(me);
/* new material indices and material array */
- matar = MEM_callocN(sizeof(void *) * totmat, "join_mesh matar");
- if (totmat) matmap = MEM_callocN(sizeof(int) * totmat, "join_mesh matmap");
+ if (totmat) {
+ matar = MEM_callocN(sizeof(*matar) * totmat, "join_mesh matar");
+ matmap = MEM_callocN(sizeof(*matmap) * totmat, "join_mesh matmap");
+ }
totcol = ob->totcol;
/* obact materials in new main array, is nicer start! */
@@ -214,7 +410,9 @@ int join_mesh_exec(bContext *C, wmOperator *op)
ma = give_current_material(base->object, a);
for (b = 0; b < totcol; b++) {
- if (ma == matar[b]) break;
+ if (ma == matar[b]) {
+ break;
+ }
}
if (b == totcol) {
matar[b] = ma;
@@ -223,8 +421,9 @@ int join_mesh_exec(bContext *C, wmOperator *op)
}
totcol++;
}
- if (totcol >= MAXMAT)
+ if (totcol >= MAXMAT) {
break;
+ }
}
}
@@ -301,187 +500,41 @@ int join_mesh_exec(bContext *C, wmOperator *op)
/* inverse transform for all selected meshes in this object */
invert_m4_m4(imat, ob->obmat);
-
+
+ /* Add back active mesh first. This allows to keep things similar as they were, as much as possible (i.e. data from
+ * 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,
+ ob, ob_base, imat,
+ &mvert, &medge, &mloop, &mpoly,
+ &vdata, &edata, &ldata, &pdata,
+ totvert, totedge, totloop, totpoly,
+ key, nkey,
+ matar, matmap, totcol,
+ &vertofs, &edgeofs, &loopofs, &polyofs);
+
CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
{
+ if (base->object == ob) {
+ continue;
+ }
/* only join if this is a mesh */
if (base->object->type == OB_MESH) {
- me = base->object->data;
-
- if (me->totvert) {
-
- /* merge customdata flag */
- ((Mesh *)ob->data)->cd_flag |= me->cd_flag;
-
- /* standard data */
- CustomData_merge(&me->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert);
- CustomData_copy_data_named(&me->vdata, &vdata, 0, vertofs, me->totvert);
-
- /* vertex groups */
- dvert = CustomData_get(&vdata, vertofs, CD_MDEFORMVERT);
-
- /* NB: vertex groups here are new version */
- if (dvert) {
- for (i = 0; i < me->totvert; i++) {
- for (j = 0; j < dvert[i].totweight; j++) {
- /* Find the old vertex group */
- odg = BLI_findlink(&base->object->defbase, dvert[i].dw[j].def_nr);
- if (odg) {
- /* Search for a match in the new object, and set new index */
- for (dg = ob->defbase.first, index = 0; dg; dg = dg->next, index++) {
- if (STREQ(dg->name, odg->name)) {
- dvert[i].dw[j].def_nr = index;
- break;
- }
- }
- }
- }
- }
- }
-
- /* if this is the object we're merging into, no need to do anything */
- if (base->object != ob) {
- /* watch this: switch matmul order really goes wrong */
- mul_m4_m4m4(cmat, imat, base->object->obmat);
-
- /* transform vertex coordinates into new space */
- for (a = 0, mv = mvert; a < me->totvert; a++, mv++) {
- mul_m4_v3(cmat, mv->co);
- }
-
- /* for each shapekey in destination mesh:
- * - if there's a matching one, copy it across (will need to transform vertices into new space...)
- * - otherwise, just copy own coordinates of mesh (no need to transform vertex coordinates into new space)
- */
- if (key) {
- /* if this mesh has any shapekeys, check first, otherwise just copy coordinates */
- for (kb = key->block.first; kb; kb = kb->next) {
- /* get pointer to where to write data for this mesh in shapekey's data array */
- fp1 = ((float *)kb->data) + (vertofs * 3);
-
- /* check if this mesh has such a shapekey */
- okb = me->key ? BKE_keyblock_find_name(me->key, kb->name) : NULL;
-
- if (okb) {
- /* copy this mesh's shapekey to the destination shapekey (need to transform first) */
- fp2 = ((float *)(okb->data));
- for (a = 0; a < me->totvert; a++, fp1 += 3, fp2 += 3) {
- copy_v3_v3(fp1, fp2);
- mul_m4_v3(cmat, fp1);
- }
- }
- else {
- /* copy this mesh's vertex coordinates to the destination shapekey */
- mv = mvert;
- for (a = 0; a < me->totvert; a++, fp1 += 3, mv++) {
- copy_v3_v3(fp1, mv->co);
- }
- }
- }
- }
- }
- else {
- /* for each shapekey in destination mesh:
- * - if it was an 'original', copy the appropriate data from nkey
- * - otherwise, copy across plain coordinates (no need to transform coordinates)
- */
- if (key) {
- for (kb = key->block.first; kb; kb = kb->next) {
- /* get pointer to where to write data for this mesh in shapekey's data array */
- fp1 = ((float *)kb->data) + (vertofs * 3);
-
- /* check if this was one of the original shapekeys */
- okb = nkey ? BKE_keyblock_find_name(nkey, kb->name) : NULL;
- if (okb) {
- /* copy this mesh's shapekey to the destination shapekey */
- fp2 = ((float *)(okb->data));
- for (a = 0; a < me->totvert; a++, fp1 += 3, fp2 += 3) {
- copy_v3_v3(fp1, fp2);
- }
- }
- else {
- /* copy base-coordinates to the destination shapekey */
- mv = mvert;
- for (a = 0; a < me->totvert; a++, fp1 += 3, mv++) {
- copy_v3_v3(fp1, mv->co);
- }
- }
- }
- }
- }
-
- /* advance mvert pointer to end of base mesh's data */
- mvert += me->totvert;
- }
-
- if (me->totedge) {
- CustomData_merge(&me->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge);
- CustomData_copy_data_named(&me->edata, &edata, 0, edgeofs, me->totedge);
-
- for (a = 0; a < me->totedge; a++, medge++) {
- medge->v1 += vertofs;
- medge->v2 += vertofs;
- }
- }
-
- if (me->totloop) {
- if (base->object != ob) {
- MultiresModifierData *mmd;
+ join_mesh_single(
+ bmain, scene,
+ ob, base, imat,
+ &mvert, &medge, &mloop, &mpoly,
+ &vdata, &edata, &ldata, &pdata,
+ totvert, totedge, totloop, totpoly,
+ key, nkey,
+ matar, matmap, totcol,
+ &vertofs, &edgeofs, &loopofs, &polyofs);
- multiresModifier_prepare_join(scene, base->object, ob);
-
- if ((mmd = get_multires_modifier(scene, base->object, true))) {
- ED_object_iter_other(bmain, base->object, true,
- ED_object_multires_update_totlevels_cb,
- &mmd->totlvl);
- }
- }
-
- CustomData_merge(&me->ldata, &ldata, CD_MASK_MESH, CD_DEFAULT, totloop);
- CustomData_copy_data_named(&me->ldata, &ldata, 0, loopofs, me->totloop);
-
- for (a = 0; a < me->totloop; a++, mloop++) {
- mloop->v += vertofs;
- mloop->e += edgeofs;
- }
- }
-
- if (me->totpoly) {
- if (totmat) {
- /* make mapping for materials */
- for (a = 1; a <= base->object->totcol; a++) {
- ma = give_current_material(base->object, a);
-
- for (b = 0; b < totcol; b++) {
- if (ma == matar[b]) {
- matmap[a - 1] = b;
- break;
- }
- }
- }
- }
-
- CustomData_merge(&me->pdata, &pdata, CD_MASK_MESH, CD_DEFAULT, totpoly);
- CustomData_copy_data_named(&me->pdata, &pdata, 0, polyofs, me->totpoly);
-
- for (a = 0; a < me->totpoly; a++, mpoly++) {
- mpoly->loopstart += loopofs;
- mpoly->mat_nr = matmap ? matmap[(int)mpoly->mat_nr] : 0;
- }
-
- polyofs += me->totpoly;
- }
-
- /* these are used for relinking (cannot be set earlier,
- * or else reattaching goes wrong)
- */
- vertofs += me->totvert;
- edgeofs += me->totedge;
- loopofs += me->totloop;
-
/* free base, now that data is merged */
- if (base->object != ob)
- ED_base_object_free_and_unlink(bmain, scene, base);
+ if (base->object != ob) {
+ ED_base_object_free_and_unlink(bmain, scene, base->object);
+ }
}
}
CTX_DATA_END;
@@ -529,34 +582,20 @@ int join_mesh_exec(bContext *C, wmOperator *op)
if (totcol) {
me->mat = matar;
- ob->mat = MEM_callocN(sizeof(void *) * totcol, "join obmatar");
- ob->matbits = MEM_callocN(sizeof(char) * totcol, "join obmatbits");
+ ob->mat = MEM_callocN(sizeof(*ob->mat) * totcol, "join obmatar");
+ ob->matbits = MEM_callocN(sizeof(*ob->matbits) * totcol, "join obmatbits");
+ MEM_freeN(matmap);
}
- else
- MEM_freeN(matar);
-
+
ob->totcol = me->totcol = totcol;
- if (matmap) MEM_freeN(matmap);
-
/* other mesh users */
test_all_objects_materials(bmain, (ID *)me);
/* free temp copy of destination shapekeys (if applicable) */
if (nkey) {
- /* XXX 2.5 Animato */
-#if 0
- /* free it's ipo too - both are not actually freed from memory yet as ID-blocks */
- if (nkey->ipo) {
- BKE_ipo_free(nkey->ipo);
- BLI_remlink(&bmain->ipo, nkey->ipo);
- MEM_freeN(nkey->ipo);
- }
-#endif
-
- BKE_key_free(nkey);
- BLI_remlink(&bmain->key, nkey);
- MEM_freeN(nkey);
+ /* We can assume nobody is using that ID currently. */
+ BKE_libblock_free_ex(bmain, nkey, false, false);
}
/* ensure newly inserted keys are time sorted */
@@ -564,9 +603,12 @@ int join_mesh_exec(bContext *C, wmOperator *op)
BKE_key_sort(key);
}
- DAG_relations_tag_update(bmain); // removed objects, need to rebuild dag
+ /* Due to dependnecy cycle some other object might access old derived data. */
+ BKE_object_free_derived_caches(ob);
+
+ 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);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
diff --git a/source/blender/editors/metaball/CMakeLists.txt b/source/blender/editors/metaball/CMakeLists.txt
index 0f9de8dbf87..89ba942ac36 100644
--- a/source/blender/editors/metaball/CMakeLists.txt
+++ b/source/blender/editors/metaball/CMakeLists.txt
@@ -22,6 +22,7 @@ set(INC
../include
../../blenkernel
../../blenlib
+ ../../depsgraph
../../makesdna
../../makesrna
../../render/extern/include
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index d9279181e32..174057d1fb9 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -48,10 +48,11 @@
#include "RNA_define.h"
#include "RNA_access.h"
-#include "BKE_depsgraph.h"
#include "BKE_context.h"
#include "BKE_mball.h"
+#include "DEG_depsgraph.h"
+
#include "ED_mball.h"
#include "ED_screen.h"
#include "ED_view3d.h"
@@ -433,7 +434,7 @@ static int duplicate_metaelems_exec(bContext *C, wmOperator *UNUSED(op))
ml = ml->prev;
}
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;
@@ -475,7 +476,7 @@ static int delete_metaelems_exec(bContext *C, wmOperator *UNUSED(op))
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;
@@ -515,7 +516,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 +557,7 @@ static int reveal_metaelems_exec(bContext *C, wmOperator *UNUSED(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;
@@ -592,12 +593,9 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese
view3d_set_viewcontext(C, &vc);
- rect.xmin = mval[0] - 12;
- rect.xmax = mval[0] + 12;
- rect.ymin = mval[1] - 12;
- rect.ymax = mval[1] + 12;
+ BLI_rcti_init_pt_radius(&rect, mval, 12);
- hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true);
+ hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST);
/* does startelem exist? */
ml = mb->editelems->first;
diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt
index b3d02d45e13..8050508983b 100644
--- a/source/blender/editors/object/CMakeLists.txt
+++ b/source/blender/editors/object/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../blenlib
../../blentranslation
../../bmesh
+ ../../depsgraph
../../gpu
../../ikplugin
../../imbuf
@@ -46,6 +47,7 @@ set(SRC
object_bake_api.c
object_constraint.c
object_edit.c
+ object_facemap_ops.c
object_group.c
object_hook.c
object_lattice.c
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index a8b0c28599d..491dddb066a 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -45,6 +45,7 @@
#include "DNA_object_fluidsim.h"
#include "DNA_object_force.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"
@@ -63,9 +64,10 @@
#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"
@@ -73,8 +75,10 @@
#include "BKE_group.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_main.h"
#include "BKE_material.h"
@@ -90,6 +94,9 @@
#include "BKE_speaker.h"
#include "BKE_texture.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -111,7 +118,7 @@
#include "UI_resources.h"
-#include "GPU_material.h"
+#include "GPU_lamp.h"
#include "object_intern.h"
@@ -145,6 +152,16 @@ static EnumPropertyItem field_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
+static EnumPropertyItem lightprobe_type_items[] = {
+ {LIGHTPROBE_TYPE_CUBE, "SPHERE", ICON_MESH_UVSPHERE, "Reflection Cubemap",
+ "Reflection probe with spherical or cubic attenuation"},
+ {LIGHTPROBE_TYPE_PLANAR, "PLANAR", ICON_MESH_PLANE, "Reflection Plane",
+ "Planar reflection probe"},
+ {LIGHTPROBE_TYPE_GRID, "GRID", ICON_MESH_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])
@@ -404,10 +421,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, unsigned int UNUSED(layer))
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *ob;
/* for as long scene has editmode... */
@@ -415,13 +433,12 @@ Object *ED_object_add_type(
ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); /* freedata, and undo */
/* deselects all, sets scene->basact */
- ob = BKE_object_add(bmain, scene, type, name);
- BASACT->lay = ob->lay = layer;
+ ob = BKE_object_add(bmain, scene, sl, type, name);
/* editor level activate, notifiers */
- ED_base_object_activate(C, BASACT);
+ ED_object_base_activate(C, sl->basact);
/* more editor stuff */
- ED_object_base_init_transform(C, BASACT, loc, rot);
+ ED_object_base_init_transform(C, sl->basact, loc, rot);
/* Ignore collisions by default for non-mesh objects */
if (type != OB_MESH) {
@@ -429,8 +446,8 @@ Object *ED_object_add_type(
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 */
}
- DAG_id_type_tag(bmain, ID_OB);
- DAG_relations_tag_update(bmain);
+ DEG_id_type_tag(bmain, ID_OB);
+ DEG_relations_tag_update(bmain);
if (ob->data) {
ED_render_id_flush_update(bmain, ob->data);
}
@@ -440,6 +457,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;
}
@@ -491,6 +511,79 @@ void OBJECT_OT_add(wmOperatorType *ot)
ED_object_add_generic_props(ot, true);
}
+/********************** Add Probe Operator **********************/
+
+/* for object add operator */
+static int lightprobe_add_exec(bContext *C, wmOperator *op)
+{
+ Object *ob;
+ LightProbe *probe;
+ int type;
+ bool enter_editmode;
+ unsigned int layer;
+ 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, &layer, NULL))
+ return OPERATOR_CANCELLED;
+
+ type = RNA_enum_get(op->ptr, "type");
+ radius = RNA_float_get(op->ptr, "radius");
+
+ const char *name = CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "Light Probe");
+ ob = ED_object_add_type(C, OB_LIGHTPROBE, name, loc, rot, false, layer);
+ 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(ot);
+ ED_object_add_generic_props(ot, true);
+}
+
/********************* Add Effector Operator ********************/
/* for object add operator */
@@ -534,7 +627,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;
}
@@ -639,7 +732,7 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op)
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);
@@ -743,7 +836,7 @@ static int object_armature_add_exec(bContext *C, wmOperator *op)
newob = true;
}
else {
- DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
}
if (obedit == NULL) {
@@ -829,7 +922,7 @@ static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEv
{
Scene *scene = CTX_data_scene(C);
- Base *base = NULL;
+ BaseLegacy *base = NULL;
Image *ima = NULL;
Object *ob = NULL;
@@ -998,10 +1091,10 @@ static int group_instance_add_exec(bContext *C, wmOperator *op)
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_lib_extern(&group->id);
+ id_us_plus(&group->id);
/* works without this except if you try render right after, see: 22027 */
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
@@ -1108,20 +1201,20 @@ static void object_delete_check_glsl_update(Object *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_base_object_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) {
+ 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);
+ object_delete_check_glsl_update(ob);
+ BKE_collections_object_remove(bmain, scene, ob, true);
+ DEG_id_type_tag(bmain, ID_OB);
}
static int object_delete_exec(bContext *C, wmOperator *op)
@@ -1136,56 +1229,60 @@ static int object_delete_exec(bContext *C, wmOperator *op)
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) {
+ 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;
+ }
+
+ /* 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 && 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, &ob->id);
+ changed = true;
continue;
}
+
/* remove from Grease Pencil parent */
+ /* XXX This is likely not correct? Will also remove parent from grease pencil from other scenes,
+ * even when use_global is false... */
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);
+ ED_base_object_free_and_unlink(bmain, scene, ob);
changed = true;
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_DATABLOCK(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) {
- 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_base_object_free_and_unlink(bmain, scene_iter, ob);
}
}
}
@@ -1199,12 +1296,12 @@ static int object_delete_exec(bContext *C, wmOperator *op)
/* 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);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
@@ -1241,7 +1338,7 @@ static void copy_object_set_idnew(bContext *C)
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
{
- BKE_libblock_relink(&ob->id);
+ BKE_libblock_relink_to_newid(&ob->id);
}
CTX_DATA_END;
@@ -1253,10 +1350,10 @@ static void copy_object_set_idnew(bContext *C)
/********************* Make Duplicates Real ************************/
/**
- * \note regarding hashing dupli-objects, skip the first member of #DupliObject.persistent_id
+ * \note regarding hashing dupli-objects when using OB_DUPLIGROUP, 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_hash(const void *ptr)
+static unsigned int dupliobject_group_hash(const void *ptr)
{
const DupliObject *dob = ptr;
unsigned int hash = BLI_ghashutil_ptrhash(dob->ob);
@@ -1267,7 +1364,20 @@ static unsigned int dupliobject_hash(const void *ptr)
return hash;
}
-static bool dupliobject_cmp(const void *a_, const void *b_)
+/**
+ * \note regarding hashing dupli-objects when NOT using OB_DUPLIGROUP, 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)
+{
+ const DupliObject *dob = ptr;
+ unsigned int hash = BLI_ghashutil_ptrhash(dob->ob);
+ hash ^= (dob->persistent_id[0] ^ 0);
+ return hash;
+}
+
+/* Compare function that matches dupliobject_group_hash */
+static bool dupliobject_group_cmp(const void *a_, const void *b_)
{
const DupliObject *a = a_;
const DupliObject *b = b_;
@@ -1290,11 +1400,30 @@ static bool dupliobject_cmp(const void *a_, const void *b_)
return false;
}
+/* Compare function that matches dupliobject_hash */
+static bool dupliobject_cmp(const void *a_, const void *b_)
+{
+ const DupliObject *a = a_;
+ const DupliObject *b = b_;
+
+ if (a->ob != b->ob) {
+ return true;
+ }
+
+ if (a->persistent_id[0] != b->persistent_id[0]) {
+ return true;
+ }
+
+ /* matching */
+ return false;
+}
+
static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
const bool use_base_parent,
const bool use_hierarchy)
{
Main *bmain = CTX_data_main(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
ListBase *lb;
DupliObject *dob;
GHash *dupli_gh = NULL, *parent_gh = NULL;
@@ -1307,24 +1436,29 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
if (use_hierarchy || use_base_parent) {
dupli_gh = BLI_ghash_ptr_new(__func__);
- parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__);
+ if (use_hierarchy) {
+ if (base->object->transflag & OB_DUPLIGROUP) {
+ parent_gh = BLI_ghash_new(dupliobject_group_hash, dupliobject_group_cmp, __func__);
+ }
+ else {
+ parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__);
+ }
+ }
}
for (dob = lb->first; dob; dob = dob->next) {
Base *basen;
- Object *ob = BKE_object_copy(bmain, dob->ob);
+ Object *ob = ID_NEW_SET(dob->ob, BKE_object_copy(bmain, dob->ob));
/* font duplis can have a totcol without material, we get them from parent
* should be implemented better...
*/
if (ob->mat == NULL) ob->totcol = 0;
- basen = MEM_dupallocN(base);
- basen->flag &= ~(OB_FROMDUPLI | OB_FROMGROUP);
- ob->flag = basen->flag;
- basen->lay = base->lay;
- BLI_addhead(&scene->base, basen); /* addhead: othwise eternal loop */
- basen->object = ob;
+ BKE_collection_object_add_from(scene, dob->ob, ob);
+ basen = BKE_scene_layer_base_find(sl, ob);
+
+ BKE_scene_object_base_flag_sync_from_base(basen);
/* make sure apply works */
BKE_animdata_free(&ob->id, true);
@@ -1336,20 +1470,31 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
ob->proxy = NULL;
ob->parent = NULL;
- BLI_listbase_clear(&ob->constraints);
+ BKE_constraints_free(&ob->constraints);
ob->curve_cache = NULL;
ob->transflag &= ~OB_DUPLI;
- ob->lay = base->lay;
copy_m4_m4(ob->obmat, dob->mat);
BKE_object_apply_mat4(ob, ob->obmat, false, false);
- if (dupli_gh)
+ if (dupli_gh) {
BLI_ghash_insert(dupli_gh, dob, ob);
- if (parent_gh)
- BLI_ghash_insert(parent_gh, dob, ob);
+ }
+ if (parent_gh) {
+ void **val;
+ /* Due to nature of hash/comparison of this ghash, a lot of duplis may be considered as 'the same',
+ * this avoids trying to insert same key several time and raise asserts in debug builds... */
+ if (!BLI_ghash_ensure_p(parent_gh, dob, &val)) {
+ *val = ob;
+ }
+ }
+
+ /* Remap new object to itself, and clear again newid pointer of orig object. */
+ BKE_libblock_relink_to_newid(&ob->id);
+ set_sca_new_poins_ob(ob);
+ BKE_id_clear_newpoin(&dob->ob->id);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
if (use_hierarchy) {
@@ -1367,9 +1512,14 @@ 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;
- memcpy(&dob_key.persistent_id[1],
- &dob->persistent_id[1],
- sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1));
+ if (base->object->transflag & OB_DUPLIGROUP) {
+ memcpy(&dob_key.persistent_id[1],
+ &dob->persistent_id[1],
+ sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1));
+ }
+ else {
+ dob_key.persistent_id[0] = dob->persistent_id[0];
+ }
ob_dst_par = BLI_ghash_lookup(parent_gh, &dob_key);
}
@@ -1391,14 +1541,12 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
}
if (ob_dst->parent) {
- invert_m4_m4(ob_dst->parentinv, dob->mat);
-
/* note, this may be the parent of other objects, but it should
* 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);
+ DEG_id_tag_update(&ob_dst->id, OB_RECALC_OB);
}
}
}
@@ -1413,9 +1561,8 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
ob_dst->partype = PAROBJECT;
/* similer to the code above, see comments */
- invert_m4_m4(ob_dst->parentinv, dob->mat);
BKE_object_apply_mat4(ob_dst, dob->mat, false, true);
- DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob_dst->id, OB_RECALC_OB);
}
}
@@ -1424,7 +1571,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
if (object->proxy_group == base->object) {
object->proxy = NULL;
object->proxy_from = NULL;
- DAG_id_tag_update(&object->id, OB_RECALC_OB);
+ DEG_id_tag_update(&object->id, OB_RECALC_OB);
}
}
}
@@ -1434,8 +1581,6 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
if (parent_gh)
BLI_ghash_free(parent_gh, NULL, NULL);
- copy_object_set_idnew(C);
-
free_object_duplilist(lb);
base->object->transflag &= ~OB_DUPLI;
@@ -1460,7 +1605,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);
@@ -1533,7 +1678,7 @@ static int convert_poll(bContext *C)
}
/* 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, SceneLayer *sl, Base *base, Object *ob)
{
Object *obn;
Base *basen;
@@ -1543,17 +1688,12 @@ 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(scene, ob, obn);
+ basen = BKE_scene_layer_base_find(sl, obn);
+ ED_object_base_select(basen, BA_SELECT);
+ ED_object_base_select(basen, BA_DESELECT);
return basen;
}
@@ -1561,6 +1701,7 @@ static int convert_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Base *basen = NULL, *basact = NULL;
Object *ob, *ob1, *newob, *obact = CTX_data_active_object(C);
DerivedMesh *dm;
@@ -1569,13 +1710,13 @@ static int convert_exec(bContext *C, wmOperator *op)
MetaBall *mb;
Mesh *me;
const short target = RNA_enum_get(op->ptr, "target");
- const bool keep_original = RNA_boolean_get(op->ptr, "keep_original");
+ bool keep_original = RNA_boolean_get(op->ptr, "keep_original");
int a, mballConverted = 0;
/* don't forget multiple users! */
{
- Base *base;
+ BaseLegacy *base;
for (base = scene->base.first; base; base = base->next) {
ob = base->object;
@@ -1599,8 +1740,38 @@ static int convert_exec(bContext *C, wmOperator *op)
}
}
- CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
+ ListBase selected_editable_bases = CTX_data_collection_get(C, "selected_editable_bases");
+
+ /* Ensure we get all meshes calculated with a sufficient data-mask,
+ * needed since re-evaluating single modifiers causes bugs if they depend
+ * on other objects data masks too, see: T50950. */
{
+ for (CollectionPointerLink *link = selected_editable_bases.first; link; link = link->next) {
+ BaseLegacy *base = link->ptr.data;
+ ob = base->object;
+
+ /* The way object type conversion works currently (enforcing conversion of *all* objetcs 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.
+ * But at the very least, do not do that with linked IDs! */
+ if ((ID_IS_LINKED_DATABLOCK(ob) || ID_IS_LINKED_DATABLOCK(ob->data)) && !keep_original) {
+ keep_original = true;
+ BKE_reportf(op->reports, RPT_INFO,
+ "Converting some linked object/object data, enforcing 'Keep Original' option to True");
+ }
+
+ 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);
+ scene->customdata_mask = customdata_mask_prev;
+ }
+
+ for (CollectionPointerLink *link = selected_editable_bases.first; link; link = link->next) {
+ BaseLegacy *base = link->ptr.data;
ob = base->object;
if (ob->flag & OB_DONE || !IS_TAGGED(ob->data)) {
@@ -1622,7 +1793,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, sl, base, NULL);
newob = basen->object;
/* decrement original mesh's usage count */
@@ -1643,11 +1814,11 @@ static int convert_exec(bContext *C, wmOperator *op)
ED_rigidbody_object_remove(bmain, scene, newob);
}
}
- else if (ob->type == OB_MESH && ob->modifiers.first) { /* converting a mesh with no modifiers causes a segfault */
+ else if (ob->type == OB_MESH) {
ob->flag |= OB_DONE;
if (keep_original) {
- basen = duplibase_for_convert(bmain, scene, base, NULL);
+ basen = duplibase_for_convert(bmain, scene, sl, base, NULL);
newob = basen->object;
/* decrement original mesh's usage count */
@@ -1659,7 +1830,7 @@ 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 */
@@ -1667,7 +1838,6 @@ static int convert_exec(bContext *C, wmOperator *op)
* cases this doesnt give correct results (when MDEF is used for eg)
*/
dm = mesh_get_derived_final(scene, newob, CD_MASK_MESH);
- // dm = mesh_create_derived_no_deform(ob1, NULL); /* this was called original (instead of get_derived). man o man why! (ton) */
DM_to_mesh(dm, newob->data, newob, CD_MASK_MESH, true);
@@ -1679,7 +1849,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, sl, base, NULL);
newob = basen->object;
/* decrement original curve's usage count */
@@ -1726,7 +1896,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);
}
}
}
@@ -1750,7 +1920,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, sl, base, NULL);
newob = basen->object;
/* decrement original curve's usage count */
@@ -1785,7 +1955,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, sl, base, baseob);
newob = basen->object;
mb = newob->data;
@@ -1828,35 +1998,32 @@ 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 */
}
}
- CTX_DATA_END;
+ BLI_freelistN(&selected_editable_bases);
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;
+ FOREACH_SCENE_OBJECT(scene, ob_mball)
+ {
if (ob->type == OB_MBALL) {
if (ob->flag & OB_DONE) {
Object *ob_basis = NULL;
- if (BKE_mball_is_basis(ob) ||
- ((ob_basis = BKE_mball_basis_find(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_base_object_free_and_unlink(bmain, scene, ob_mball);
}
}
}
}
+ FOREACH_SCENE_OBJECT_END
}
/* delete object should renew depsgraph */
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
}
// XXX ED_object_editmode_enter(C, 0);
@@ -1864,15 +2031,15 @@ 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_NEW = 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_NEW->object->flag & OB_DONE) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, BASACT_NEW->object);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DATA, BASACT_NEW->object);
}
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, scene);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
@@ -1910,55 +2077,57 @@ void OBJECT_OT_convert(wmOperatorType *ot)
/* used below, assumes id.new is correct */
/* leaves selection of base/object unaltered */
-static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base, int dupflag)
+/* Does set ID->newid pointers. */
+static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, SceneLayer *sl, 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;
Material ***matarar;
- Object *ob, *obn;
+ Object *obn;
ID *id;
int a, didit;
- ob = base->object;
if (ob->mode & OB_MODE_POSE) {
; /* nothing? */
}
else {
- obn = BKE_object_copy(bmain, ob);
- DAG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob));
+ DEG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- basen = MEM_mallocN(sizeof(Base), "duplibase");
- *basen = *base;
- BLI_addhead(&scene->base, basen); /* addhead: prevent eternal loop */
- basen->object = obn;
+ BKE_collection_object_add_from(scene, ob, obn);
+ basen = BKE_scene_layer_base_find(sl, obn);
/* 1) duplis should end up in same group as the original
* 2) Rigid Body sim participants MUST always be part of a group...
*/
// XXX: is 2) really a good measure here?
- if ((basen->flag & OB_FROMGROUP) || ob->rigidbody_object || ob->rigidbody_constraint) {
+ if ((ob->flag & OB_FROMGROUP) != 0 || 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);
+ BKE_group_object_add(group, obn);
}
}
/* duplicates using userflags */
if (dupflag & USER_DUP_ACT) {
- BKE_animdata_copy_id_action(&obn->id);
+ BKE_animdata_copy_id_action(&obn->id, true);
}
if (dupflag & USER_DUP_MAT) {
for (a = 0; a < obn->totcol; a++) {
id = (ID *)obn->mat[a];
if (id) {
- ID_NEW_US(obn->mat[a])
- else
- obn->mat[a] = BKE_material_copy(bmain, obn->mat[a]);
+ ID_NEW_REMAP_US(obn->mat[a])
+ else {
+ obn->mat[a] = ID_NEW_SET(obn->mat[a], BKE_material_copy(bmain, obn->mat[a]));
+ }
id_us_min(id);
if (dupflag & USER_DUP_ACT) {
- BKE_animdata_copy_id_action(&obn->mat[a]->id);
+ BKE_animdata_copy_id_action(&obn->mat[a]->id, true);
}
}
}
@@ -1968,12 +2137,13 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
for (psys = obn->particlesystem.first; psys; psys = psys->next) {
id = (ID *) psys->part;
if (id) {
- ID_NEW_US(psys->part)
- else
- psys->part = BKE_particlesettings_copy(bmain, psys->part);
+ ID_NEW_REMAP_US(psys->part)
+ else {
+ psys->part = ID_NEW_SET(psys->part, BKE_particlesettings_copy(bmain, psys->part));
+ }
if (dupflag & USER_DUP_ACT) {
- BKE_animdata_copy_id_action(&psys->part->id);
+ BKE_animdata_copy_id_action(&psys->part->id, true);
}
id_us_min(id);
@@ -1987,9 +2157,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
switch (obn->type) {
case OB_MESH:
if (dupflag & USER_DUP_MESH) {
- ID_NEW_US2(obn->data)
+ ID_NEW_REMAP_US2(obn->data)
else {
- obn->data = BKE_mesh_copy(bmain, obn->data);
+ obn->data = ID_NEW_SET(obn->data, BKE_mesh_copy(bmain, obn->data));
didit = 1;
}
id_us_min(id);
@@ -1997,9 +2167,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
break;
case OB_CURVE:
if (dupflag & USER_DUP_CURVE) {
- ID_NEW_US2(obn->data)
+ ID_NEW_REMAP_US2(obn->data)
else {
- obn->data = BKE_curve_copy(bmain, obn->data);
+ obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data));
didit = 1;
}
id_us_min(id);
@@ -2007,9 +2177,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
break;
case OB_SURF:
if (dupflag & USER_DUP_SURF) {
- ID_NEW_US2(obn->data)
+ ID_NEW_REMAP_US2(obn->data)
else {
- obn->data = BKE_curve_copy(bmain, obn->data);
+ obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data));
didit = 1;
}
id_us_min(id);
@@ -2017,9 +2187,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
break;
case OB_FONT:
if (dupflag & USER_DUP_FONT) {
- ID_NEW_US2(obn->data)
+ ID_NEW_REMAP_US2(obn->data)
else {
- obn->data = BKE_curve_copy(bmain, obn->data);
+ obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data));
didit = 1;
}
id_us_min(id);
@@ -2027,9 +2197,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
break;
case OB_MBALL:
if (dupflag & USER_DUP_MBALL) {
- ID_NEW_US2(obn->data)
+ ID_NEW_REMAP_US2(obn->data)
else {
- obn->data = BKE_mball_copy(bmain, obn->data);
+ obn->data = ID_NEW_SET(obn->data, BKE_mball_copy(bmain, obn->data));
didit = 1;
}
id_us_min(id);
@@ -2037,22 +2207,22 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
break;
case OB_LAMP:
if (dupflag & USER_DUP_LAMP) {
- ID_NEW_US2(obn->data)
+ ID_NEW_REMAP_US2(obn->data)
else {
- obn->data = BKE_lamp_copy(bmain, obn->data);
+ obn->data = ID_NEW_SET(obn->data, BKE_lamp_copy(bmain, obn->data));
didit = 1;
}
id_us_min(id);
}
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_US2(obn->data)
+ ID_NEW_REMAP_US2(obn->data)
else {
- obn->data = BKE_armature_copy(bmain, obn->data);
+ obn->data = ID_NEW_SET(obn->data, BKE_armature_copy(bmain, obn->data));
BKE_pose_rebuild(obn, obn->data);
didit = 1;
}
@@ -2061,9 +2231,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
break;
case OB_LATTICE:
if (dupflag != 0) {
- ID_NEW_US2(obn->data)
+ ID_NEW_REMAP_US2(obn->data)
else {
- obn->data = BKE_lattice_copy(bmain, obn->data);
+ obn->data = ID_NEW_SET(obn->data, BKE_lattice_copy(bmain, obn->data));
didit = 1;
}
id_us_min(id);
@@ -2071,9 +2241,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
break;
case OB_CAMERA:
if (dupflag != 0) {
- ID_NEW_US2(obn->data)
+ ID_NEW_REMAP_US2(obn->data)
else {
- obn->data = BKE_camera_copy(bmain, obn->data);
+ obn->data = ID_NEW_SET(obn->data, BKE_camera_copy(bmain, obn->data));
didit = 1;
}
id_us_min(id);
@@ -2081,9 +2251,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
break;
case OB_SPEAKER:
if (dupflag != 0) {
- ID_NEW_US2(obn->data)
+ ID_NEW_REMAP_US2(obn->data)
else {
- obn->data = BKE_speaker_copy(bmain, obn->data);
+ obn->data = ID_NEW_SET(obn->data, BKE_speaker_copy(bmain, obn->data));
didit = 1;
}
id_us_min(id);
@@ -2098,12 +2268,15 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (dupflag & USER_DUP_ACT) {
bActuator *act;
- BKE_animdata_copy_id_action((ID *)obn->data);
+ BKE_animdata_copy_id_action((ID *)obn->data, true);
if (key) {
- BKE_animdata_copy_id_action((ID *)key);
+ BKE_animdata_copy_id_action((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;
@@ -2120,9 +2293,10 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
for (a = 0; a < obn->totcol; a++) {
id = (ID *)(*matarar)[a];
if (id) {
- ID_NEW_US((*matarar)[a])
- else
- (*matarar)[a] = BKE_material_copy(bmain, (*matarar)[a]);
+ ID_NEW_REMAP_US((*matarar)[a])
+ else {
+ (*matarar)[a] = ID_NEW_SET((*matarar)[a], BKE_material_copy(bmain, (*matarar)[a]));
+ }
id_us_min(id);
}
}
@@ -2131,6 +2305,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
}
}
return basen;
+
+#undef ID_NEW_REMAP_US
+#undef ID_NEW_REMAP_US2
}
/* single object duplicate, if dupflag==0, fully linked, else it uses the flags given */
@@ -2138,15 +2315,14 @@ 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, SceneLayer *sl, Base *base, int dupflag)
{
Base *basen;
Object *ob;
- BKE_main_id_clear_newpoins(bmain);
- clear_sca_new_poins(); /* sensor/contr/act */
+ clear_sca_new_poins(); /* BGE logic */
- basen = object_add_duplicate_internal(bmain, scene, base, dupflag);
+ basen = object_add_duplicate_internal(bmain, scene, sl, base->object, dupflag);
if (basen == NULL) {
return NULL;
}
@@ -2154,7 +2330,7 @@ Base *ED_object_add_duplicate(Main *bmain, Scene *scene, Base *base, int dupflag
ob = basen->object;
/* link own references to the newly duplicated data [#26816] */
- BKE_libblock_relink(&ob->id);
+ BKE_libblock_relink_to_newid(&ob->id);
set_sca_new_poins_ob(ob);
/* DAG_relations_tag_update(bmain); */ /* caller must do */
@@ -2163,6 +2339,8 @@ Base *ED_object_add_duplicate(Main *bmain, Scene *scene, Base *base, int dupflag
ED_render_id_flush_update(bmain, ob->data);
}
+ BKE_main_id_clear_newpoins(bmain);
+
return basen;
}
@@ -2171,37 +2349,42 @@ static int duplicate_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
const bool linked = RNA_boolean_get(op->ptr, "linked");
int dupflag = (linked) ? 0 : U.dupflag;
- BKE_main_id_clear_newpoins(bmain);
- clear_sca_new_poins(); /* sensor/contr/act */
+ 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, sl, 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_NEW == 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;
copy_object_set_idnew(C);
- DAG_relations_tag_update(bmain);
+ BKE_main_id_clear_newpoins(bmain);
+
+ DEG_relations_tag_update(bmain);
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update(&CTX_data_scene(C)->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
@@ -2237,9 +2420,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;
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Base *basen;
Object *ob;
const bool linked = RNA_boolean_get(op->ptr, "linked");
int dupflag = (linked) ? 0 : U.dupflag;
@@ -2254,23 +2437,17 @@ 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 */
- BKE_main_id_clear_newpoins(bmain);
- clear_sca_new_poins(); /* sensor/contr/act */
+ clear_sca_new_poins(); /* BGE logic */
- basen = object_add_duplicate_internal(bmain, scene, base, dupflag);
+ basen = object_add_duplicate_internal(bmain, scene, sl, ob, dupflag);
+ BKE_scene_object_base_flag_sync_from_object(basen);
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);
basen->object->restrictflag &= ~OB_RESTRICT_VIEW;
if (event) {
@@ -2281,14 +2458,14 @@ static int add_named_exec(bContext *C, wmOperator *op)
ED_view3d_cursor3d_position(C, basen->object->loc, mval);
}
- 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);
- DAG_relations_tag_update(bmain);
+ BKE_main_id_clear_newpoins(bmain);
- MEM_freeN(base);
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT | ND_OB_ACTIVE, scene);
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index 11d96da5786..e3dd47295fe 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"
@@ -86,6 +88,11 @@
* 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;
@@ -152,7 +159,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 +167,7 @@ static bool multiresbake_check(bContext *C, wmOperator *op)
else {
a = me->totpoly;
while (ok && a--) {
- Image *ima = me->mtpoly[a].tpage;
+ Image *ima = BKE_object_material_edit_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");
@@ -283,20 +290,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,11 +326,10 @@ 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;
@@ -325,7 +338,11 @@ static int multiresbake_image_exec_locked(bContext *C, wmOperator *op)
clear_flag = CLEAR_DISPLACEMENT;
}
- clear_images_poly(me->mtpoly, me->totpoly, clear_flag);
+ {
+ Image **ob_image_array = BKE_object_material_edit_image_get_array(ob);
+ clear_images_poly(ob_image_array, ob->totcol, clear_flag);
+ MEM_freeN(ob_image_array);
+ }
}
CTX_DATA_END;
}
@@ -351,11 +368,16 @@ static int multiresbake_image_exec_locked(bContext *C, wmOperator *op)
//bkr.reports= op->reports;
/* create low-resolution DM (to bake to) and hi-resolution DM (to bake from) */
+ bkr.ob_image.array = BKE_object_material_edit_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);
@@ -401,6 +423,9 @@ static void init_multiresbake_job(bContext *C, MultiresBakeJob *bkj)
data = MEM_callocN(sizeof(MultiresBakerJobData), "multiresBaker derivedMesh_data");
+ data->ob_image.array = BKE_object_material_edit_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,8 +446,6 @@ 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) {
@@ -432,7 +455,7 @@ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, floa
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);
}
}
@@ -445,6 +468,8 @@ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, floa
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;
@@ -493,6 +518,8 @@ static void multiresbake_freejob(void *bkv)
GPU_free_image(ima);
}
+ MEM_freeN(data->ob_image.array);
+
BLI_freelistN(&data->images);
MEM_freeN(data);
@@ -589,6 +616,7 @@ static int test_bake_internal(bContext *C, ReportList *reports)
static void init_bake_internal(BakeRender *bkr, bContext *C)
{
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
bScreen *sc = CTX_wm_screen(C);
/* get editmode results */
@@ -597,7 +625,7 @@ static void init_bake_internal(BakeRender *bkr, bContext *C)
bkr->sa = sc ? BKE_screen_find_big_area(sc, SPACE_IMAGE, 10) : NULL; /* can be NULL */
bkr->main = CTX_data_main(C);
bkr->scene = scene;
- bkr->actob = (scene->r.bake_flag & R_BAKE_TO_ACTIVE) ? OBACT : NULL;
+ bkr->actob = (scene->r.bake_flag & R_BAKE_TO_ACTIVE) ? OBACT_NEW : NULL;
bkr->re = RE_NewRender("_Bake View_");
if (scene->r.bake_mode == RE_BAKE_AO) {
@@ -661,7 +689,7 @@ static void finish_bake_internal(BakeRender *bkr)
}
BKE_image_release_ibuf(ima, ibuf, NULL);
- DAG_id_tag_update(&ima->id, 0);
+ DEG_id_tag_update(&ima->id, 0);
}
}
@@ -671,7 +699,7 @@ static void finish_bake_internal(BakeRender *bkr)
BLI_assert(BLI_thread_is_main());
for (me = G.main->mesh.first; me; me = me->id.next) {
if (me->id.tag & LIB_TAG_DOIT) {
- DAG_id_tag_update(&me->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&me->id, OB_RECALC_DATA);
BKE_mesh_tessface_clear(me);
}
}
@@ -810,6 +838,7 @@ static int bake_image_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
int result = OPERATOR_CANCELLED;
if (is_multires_bake(scene)) {
@@ -829,7 +858,7 @@ static int bake_image_exec(bContext *C, wmOperator *op)
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);
+ RE_Database_Baking(bkr.re, bmain, scene, scene->lay, scene->r.bake_mode, (scene->r.bake_flag & R_BAKE_TO_ACTIVE) ? OBACT_NEW : NULL);
/* baking itself is threaded, cannot use test_break in threads */
BLI_init_threads(&threads, do_bake_render, 1);
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index fd95d6129ad..990761e233a 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -51,12 +51,14 @@
#include "BKE_image.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_material.h"
#include "BKE_node.h"
#include "BKE_report.h"
#include "BKE_modifier.h"
#include "BKE_mesh.h"
#include "BKE_screen.h"
-#include "BKE_depsgraph.h"
+
+#include "DEG_depsgraph.h"
#include "RE_engine.h"
#include "RE_pipeline.h"
@@ -82,6 +84,7 @@ static void bake_set_props(wmOperator *op, Scene *scene);
typedef struct BakeAPIRender {
Object *ob;
Main *main;
+ Depsgraph *depsgraph;
Scene *scene;
ReportList *reports;
ListBase selected_objects;
@@ -271,7 +274,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);
}
}
}
@@ -352,12 +355,17 @@ static bool is_noncolor_pass(ScenePassType pass_type)
}
/* if all is good tag image and return true */
-static bool bake_object_check(Object *ob, ReportList *reports)
+static bool bake_object_check(Scene *scene, Object *ob, ReportList *reports)
{
Image *image;
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);
+ return false;
+ }
+
if (ob->type != OB_MESH) {
BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not a mesh", ob->id.name + 2);
return false;
@@ -406,22 +414,18 @@ static bool bake_object_check(Object *ob, ReportList *reports)
}
}
else {
- if (ob->mat[i]) {
- BKE_reportf(reports, RPT_ERROR,
- "No active image found in material \"%s\" (%d) for object \"%s\"",
- ob->mat[i]->id.name + 2, i, ob->id.name + 2);
- }
- else if (((Mesh *) ob->data)->mat[i]) {
- BKE_reportf(reports, RPT_ERROR,
+ Material *mat = give_current_material(ob, i);
+ if (mat != NULL) {
+ BKE_reportf(reports, RPT_INFO,
"No active image found in material \"%s\" (%d) for object \"%s\"",
- ((Mesh *) ob->data)->mat[i]->id.name + 2, i, ob->id.name + 2);
+ mat->id.name + 2, i, ob->id.name + 2);
}
else {
- BKE_reportf(reports, RPT_ERROR,
- "No active image found in material (%d) for object \"%s\"",
+ BKE_reportf(reports, RPT_INFO,
+ "No active image found in material slot (%d) for object \"%s\"",
i, ob->id.name + 2);
}
- return false;
+ continue;
}
image->id.tag |= LIB_TAG_DOIT;
@@ -491,7 +495,7 @@ static bool bake_pass_filter_check(ScenePassType pass_type, const int pass_filte
}
/* before even getting in the bake function we check for some basic errors */
-static bool bake_objects_check(Main *bmain, Object *ob, ListBase *selected_objects,
+static bool bake_objects_check(Main *bmain, Scene *scene, Object *ob, ListBase *selected_objects,
ReportList *reports, const bool is_selected_to_active)
{
CollectionPointerLink *link;
@@ -502,7 +506,7 @@ static bool bake_objects_check(Main *bmain, Object *ob, ListBase *selected_objec
if (is_selected_to_active) {
int tot_objects = 0;
- if (!bake_object_check(ob, reports))
+ if (!bake_object_check(scene, ob, reports))
return false;
for (link = selected_objects->first; link; link = link->next) {
@@ -530,7 +534,7 @@ static bool bake_objects_check(Main *bmain, Object *ob, ListBase *selected_objec
}
for (link = selected_objects->first; link; link = link->next) {
- if (!bake_object_check(link->ptr.data, reports))
+ if (!bake_object_check(scene, link->ptr.data, reports))
return false;
}
}
@@ -561,7 +565,11 @@ static void build_image_lookup(Main *bmain, Object *ob, BakeImages *bake_images)
Image *image;
ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL);
- if ((image->id.tag & LIB_TAG_DOIT)) {
+ /* Some materials have no image, we just ignore those cases. */
+ if (image == NULL) {
+ bake_images->lookup[i] = -1;
+ }
+ else if (image->id.tag & LIB_TAG_DOIT) {
for (j = 0; j < i; j++) {
if (bake_images->data[j].image == image) {
bake_images->lookup[i] = j;
@@ -619,13 +627,13 @@ static Mesh *bake_mesh_new_from_object(Main *bmain, Scene *scene, Object *ob)
ED_object_editmode_load(ob);
Mesh *me = BKE_mesh_new_from_object(bmain, scene, ob, 1, 2, 0, 0);
- BKE_mesh_split_faces(me);
+ BKE_mesh_split_faces(me, true);
return me;
}
static int bake(
- Render *re, Main *bmain, Scene *scene, Object *ob_low, ListBase *selected_objects, ReportList *reports,
+ Render *re, Main *bmain, Depsgraph *graph, Scene *scene, Object *ob_low, ListBase *selected_objects, ReportList *reports,
const ScenePassType pass_type, const int pass_filter, const int margin,
const BakeSaveMode 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,
@@ -664,7 +672,7 @@ static int bake(
size_t num_pixels;
int tot_materials;
- RE_bake_engine_set_engine_parameters(re, bmain, scene);
+ RE_bake_engine_set_engine_parameters(re, bmain, graph, scene);
if (!RE_bake_has_engine(re)) {
BKE_report(reports, RPT_ERROR, "Current render engine does not support baking");
@@ -1112,6 +1120,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->depsgraph = CTX_data_depsgraph(C);
bkr->scene = CTX_data_scene(C);
bkr->sa = sc ? BKE_screen_find_big_area(sc, SPACE_IMAGE, 10) : NULL;
@@ -1167,6 +1176,9 @@ static int bake_exec(bContext *C, wmOperator *op)
BakeAPIRender bkr = {NULL};
Scene *scene = CTX_data_scene(C);
+ G.is_break = false;
+ G.is_rendering = true;
+
bake_set_props(op, scene);
bake_init_api_data(op, C, &bkr);
@@ -1179,7 +1191,7 @@ static int bake_exec(bContext *C, wmOperator *op)
goto finally;
}
- if (!bake_objects_check(bkr.main, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.is_selected_to_active)) {
+ if (!bake_objects_check(bkr.main, bkr.scene, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.is_selected_to_active)) {
goto finally;
}
@@ -1192,7 +1204,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.depsgraph, bkr.scene, 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,
@@ -1205,7 +1217,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.depsgraph, bkr.scene, 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,
@@ -1218,6 +1230,7 @@ static int bake_exec(bContext *C, wmOperator *op)
finally:
+ G.is_rendering = false;
BLI_freelistN(&bkr.selected_objects);
return result;
}
@@ -1237,7 +1250,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa
return;
}
- if (!bake_objects_check(bkr->main, bkr->ob, &bkr->selected_objects, bkr->reports, bkr->is_selected_to_active)) {
+ if (!bake_objects_check(bkr->main, bkr->scene, bkr->ob, &bkr->selected_objects, bkr->reports, bkr->is_selected_to_active)) {
bkr->result = OPERATOR_CANCELLED;
return;
}
@@ -1249,7 +1262,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->depsgraph, bkr->scene, 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,
@@ -1262,7 +1275,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->depsgraph, bkr->scene, 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_constraint.c b/source/blender/editors/object/object_constraint.c
index 59d78f13ccb..d110400de80 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
@@ -1196,9 +1198,9 @@ void ED_object_constraint_update(Object *ob)
object_test_constraints(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)
@@ -1221,7 +1223,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(Object *ob, bConstraint *con)
@@ -1233,9 +1235,9 @@ void ED_object_constraint_tag_update(Object *ob, bConstraint *con)
object_test_constraint(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);
}
void ED_object_constraint_dependency_tag_update(Main *bmain, Object *ob, bConstraint *con)
@@ -1245,7 +1247,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 int constraint_poll(bContext *C)
@@ -1269,7 +1271,7 @@ static int constraint_delete_exec(bContext *C, wmOperator *UNUSED(op))
ED_object_constraint_update(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);
@@ -1411,12 +1413,12 @@ static int pose_constraints_clear_exec(bContext *C, wmOperator *UNUSED(op))
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);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob);
return OPERATOR_FINISHED;
@@ -1443,12 +1445,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);
@@ -1496,13 +1498,13 @@ static int pose_constraint_copy_exec(bContext *C, wmOperator *op)
chan->constflag |= pchan->constflag;
BKE_pose_tag_recalc(bmain, ob->pose);
- DAG_id_tag_update((ID *)ob, OB_RECALC_DATA);
+ DEG_id_tag_update((ID *)ob, OB_RECALC_DATA);
}
}
BLI_freelistN(&lb);
/* 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);
@@ -1535,13 +1537,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);
@@ -1682,14 +1684,15 @@ 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;
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Base *base = BASACT_NEW, *newbase = NULL;
Object *obt;
/* add new target object */
- obt = BKE_object_add(bmain, scene, OB_EMPTY, NULL);
+ obt = BKE_object_add(bmain, scene, sl, OB_EMPTY, NULL);
/* set layers OK */
- newbase = BASACT;
+ newbase = BASACT_NEW;
newbase->lay = base->lay;
obt->lay = newbase->lay;
@@ -1708,8 +1711,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_NEW = base;
+ base->flag |= BASE_SELECTED;
/* make our new target the new object */
*tar_ob = obt;
@@ -1817,7 +1820,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 */
@@ -1827,10 +1830,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);
@@ -2070,7 +2073,7 @@ static int pose_ik_clear_exec(bContext *C, wmOperator *UNUSED(op))
CTX_DATA_END;
/* refresh depsgraph */
- 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_CONSTRAINT | NA_REMOVED, ob);
diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c
index acee69daab7..9a89ec453fd 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_object.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -135,19 +136,19 @@ static EnumPropertyItem *dt_layers_select_src_itemf(
if (ob_src) {
DerivedMesh *dm_src;
- CustomData *pdata;
+ CustomData *ldata;
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);
+ dm_src = mesh_get_derived_final(scene, ob_src, CD_MASK_BAREMESH | CD_MLOOPUV);
+ ldata = dm_src->getLoopDataLayout(dm_src);
+ 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);
}
}
@@ -423,7 +424,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);
@@ -641,7 +642,7 @@ static int datalayout_transfer_exec(bContext *C, wmOperator *op)
BKE_object_data_transfer_layout(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;
@@ -672,7 +673,7 @@ static int datalayout_transfer_exec(bContext *C, wmOperator *op)
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);
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index ee75e0bd2bf..15bf540fb2f 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -41,6 +41,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -57,6 +58,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_vfont_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_workspace_types.h"
#include "IMB_imbuf_types.h"
@@ -65,7 +67,6 @@
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_effect.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_lattice.h"
@@ -82,6 +83,10 @@
#include "BKE_modifier.h"
#include "BKE_editmesh.h"
#include "BKE_report.h"
+#include "BKE_workspace.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "ED_armature.h"
#include "ED_curve.h"
@@ -131,189 +136,6 @@ Object *ED_object_active_context(bContext *C)
}
-/* ********* clear/set restrict view *********/
-static int object_hide_view_clear_exec(bContext *C, wmOperator *UNUSED(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;
-
- /* 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)) {
- base->flag |= SELECT;
- }
- base->object->flag = base->flag;
- base->object->restrictflag &= ~OB_RESTRICT_VIEW;
- changed = true;
- }
- }
- 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);
- }
-
- 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->idname = "OBJECT_OT_hide_view_clear";
-
- /* api callbacks */
- ot->exec = object_hide_view_clear_exec;
- ot->poll = ED_operator_view3d_active;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-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;
- const bool unselected = RNA_boolean_get(op->ptr, "unselected");
-
- CTX_DATA_BEGIN(C, Base *, base, visible_bases)
- {
- 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);
- }
- }
- }
- else {
- if (!(base->flag & SELECT)) {
- base->object->restrictflag |= OB_RESTRICT_VIEW;
- changed = true;
- if (base == BASACT) {
- ED_base_object_activate(C, NULL);
- }
- }
- }
- }
- 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);
-
- }
-
- return OPERATOR_FINISHED;
-}
-
-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->idname = "OBJECT_OT_hide_view_set";
-
- /* api callbacks */
- ot->exec = object_hide_view_set_exec;
- 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");
-
-}
-
-/* 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))
-{
- bool changed = false;
-
- /* 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;
- }
- }
- CTX_DATA_END;
-
- if (changed)
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void OBJECT_OT_hide_render_clear(wmOperatorType *ot)
-{
-
- /* 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";
-
- /* api callbacks */
- ot->exec = object_hide_render_clear_exec;
- ot->poll = ED_operator_view3d_active;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int object_hide_render_set_exec(bContext *C, wmOperator *op)
-{
- const bool unselected = RNA_boolean_get(op->ptr, "unselected");
-
- CTX_DATA_BEGIN(C, Base *, base, visible_bases)
- {
- if (!unselected) {
- if (base->flag & SELECT) {
- base->object->restrictflag |= OB_RESTRICT_RENDER;
- }
- }
- else {
- if (!(base->flag & SELECT)) {
- base->object->restrictflag |= OB_RESTRICT_RENDER;
- }
- }
- }
- 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)
-{
- /* 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";
-
- /* api callbacks */
- ot->exec = object_hide_render_set_exec;
- 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");
-}
-
/* ******************* toggle editmode operator ***************** */
static bool mesh_needs_keyindex(const Mesh *me)
@@ -375,7 +197,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)) {
ED_curve_editnurb_load(obedit);
@@ -397,7 +219,7 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f
/* Tag update so no access to freed data referenced from
* derived cache will happen.
*/
- DAG_id_tag_update((ID *)obedit->data, 0);
+ DEG_id_tag_update((ID *)obedit->data, 0);
return true;
}
@@ -413,6 +235,7 @@ void ED_object_editmode_exit(bContext *C, int flag)
/* Note! only in exceptional cases should 'EM_DO_UNDO' NOT be in the flag */
/* Note! if 'EM_FREEDATA' isn't in the flag, use ED_object_editmode_load directly */
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *obedit = CTX_data_edit_object(C);
const bool freedata = (flag & EM_FREEDATA) != 0;
@@ -421,8 +244,8 @@ void ED_object_editmode_exit(bContext *C, int flag)
if (ED_object_editmode_load_ex(CTX_data_main(C), 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(sl->basact && (sl->basact->object->mode & OB_MODE_EDIT))) {
+ sl->basact->object->mode &= ~OB_MODE_EDIT;
}
if (flag & EM_WAITCURSOR) waitcursor(0);
return;
@@ -447,7 +270,7 @@ void ED_object_editmode_exit(bContext *C, int flag)
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);
if (flag & EM_DO_UNDO)
ED_undo_push(C, "Editmode");
@@ -458,37 +281,31 @@ void ED_object_editmode_exit(bContext *C, int flag)
}
if (flag & EM_WAITCURSOR) waitcursor(0);
+
+ /* This way we ensure scene's obedit is copied into all CoW scenes. */
+ DEG_id_tag_update(&scene->id, 0);
}
void ED_object_editmode_enter(bContext *C, int flag)
{
Scene *scene = CTX_data_scene(C);
- Base *base = NULL;
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *ob;
- ScrArea *sa = CTX_wm_area(C);
- View3D *v3d = NULL;
bool ok = false;
if (ID_IS_LINKED_DATABLOCK(scene)) return;
- 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 */
+ ob = CTX_data_active_object(C); /* active layer checked here for view3d */
- if (base == NULL) return;
- else if (v3d && (base->lay & v3d->lay) == 0) return;
- else if (!v3d && (base->lay & scene->lay) == 0) return;
+ if (ob == NULL) return;
}
else {
- base = scene->basact;
+ ob = sl->basact->object;
}
- if (ELEM(NULL, base, base->object, base->object->data)) return;
-
- ob = base->object;
+ if (ELEM(NULL, ob, ob->data)) return;
/* this checks actual object->data, for cases when other scenes have it in editmode context */
if (BKE_object_is_in_editmode(ob))
@@ -547,7 +364,7 @@ void ED_object_editmode_enter(bContext *C, int flag)
scene->obedit = ob;
ED_armature_to_edit(arm);
/* 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);
}
@@ -581,7 +398,9 @@ void ED_object_editmode_enter(bContext *C, int flag)
}
if (ok) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ /* This way we ensure scene's obedit is copied into all CoW scenes. */
+ DEG_id_tag_update(&scene->id, 0);
}
else {
scene->obedit = NULL; /* XXX for context */
@@ -693,7 +512,7 @@ void OBJECT_OT_posemode_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static void copymenu_properties(Scene *scene, View3D *v3d, Object *ob)
+static void copymenu_properties(SceneLayer *sl, Object *ob)
{
//XXX no longer used - to be removed - replaced by game_properties_copy_exec
bProperty *prop;
@@ -726,8 +545,8 @@ static void copymenu_properties(Scene *scene, View3D *v3d, Object *ob)
nr = pupmenu(str);
if (nr == 1 || nr == 2) {
- for (base = FIRSTBASE; base; base = base->next) {
- if ((base != BASACT) && (TESTBASELIB(v3d, base))) {
+ for (base = FIRSTBASE_NEW; base; base = base->next) {
+ if ((base != BASACT_NEW) && (TESTBASELIB_NEW(base))) {
if (nr == 1) { /* replace */
BKE_bproperty_copy_list(&base->object->prop, &ob->prop);
}
@@ -743,8 +562,8 @@ static void copymenu_properties(Scene *scene, View3D *v3d, Object *ob)
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))) {
+ for (base = FIRSTBASE_NEW; base; base = base->next) {
+ if ((base != BASACT_NEW) && (TESTBASELIB_NEW(base))) {
BKE_bproperty_object_set(base->object, prop);
}
}
@@ -754,14 +573,14 @@ static void copymenu_properties(Scene *scene, View3D *v3d, Object *ob)
}
-static void copymenu_logicbricks(Scene *scene, View3D *v3d, Object *ob)
+static void copymenu_logicbricks(SceneLayer *sl, Object *ob)
{
//XXX no longer used - to be removed - replaced by logicbricks_copy_exec
Base *base;
- for (base = FIRSTBASE; base; base = base->next) {
+ for (base = FIRSTBASE_NEW; base; base = base->next) {
if (base->object != ob) {
- if (TESTBASELIB(v3d, base)) {
+ if (TESTBASELIB_NEW(base)) {
/* first: free all logic */
free_sensors(&base->object->sensors);
@@ -840,7 +659,7 @@ 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, SceneLayer *sl, short event)
{
Object *ob;
Base *base;
@@ -850,18 +669,18 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
if (ID_IS_LINKED_DATABLOCK(scene)) return;
- if (!(ob = OBACT)) return;
+ if (!(ob = OBACT_NEW)) return;
if (scene->obedit) { // XXX get from context
/* obedit_copymenu(); */
return;
}
if (event == 9) {
- copymenu_properties(scene, v3d, ob);
+ copymenu_properties(sl, ob);
return;
}
else if (event == 10) {
- copymenu_logicbricks(scene, v3d, ob);
+ copymenu_logicbricks(sl, ob);
return;
}
else if (event == 24) {
@@ -870,10 +689,10 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
return;
}
- for (base = FIRSTBASE; base; base = base->next) {
- if (base != BASACT) {
- if (TESTBASELIB(v3d, base)) {
- DAG_id_tag_update(&base->object->id, OB_RECALC_DATA);
+ for (base = FIRSTBASE_NEW; base; base = base->next) {
+ if (base != BASACT_NEW) {
+ if (TESTBASELIB_NEW(base)) {
+ DEG_id_tag_update(&base->object->id, OB_RECALC_DATA);
if (event == 1) { /* loc */
copy_v3_v3(base->object->loc, ob->loc);
@@ -910,7 +729,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
base->object->dup_group = ob->dup_group;
if (ob->dup_group)
- id_lib_extern(&ob->dup_group->id);
+ id_us_plus(&ob->dup_group->id);
}
else if (event == 7) { /* mass */
base->object->mass = ob->mass;
@@ -976,7 +795,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 */
@@ -992,7 +811,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 */
@@ -1011,7 +830,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) {
@@ -1027,7 +846,7 @@ 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);
}
}
}
@@ -1088,16 +907,16 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
}
if (do_depgraph_update)
- DAG_relations_tag_update(bmain);
+ DEG_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, SceneLayer *sl)
{
Object *ob;
short event;
char str[512];
- if (!(ob = OBACT)) return;
+ if (!(ob = OBACT_NEW)) return;
if (scene->obedit) { /* XXX get from context */
/* if (ob->type == OB_MESH) */
@@ -1145,7 +964,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, sl, event);
}
/* ******************* force field toggle operator ***************** */
@@ -1444,7 +1263,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(ob->data, BKE_MESH_BATCH_DIRTY_NOCHECK);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
done = true;
@@ -1457,7 +1277,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;
@@ -1508,7 +1328,7 @@ void OBJECT_OT_shade_smooth(wmOperatorType *ot)
/* ********************** */
-static void UNUSED_FUNCTION(image_aspect) (Scene *scene, View3D *v3d)
+static void UNUSED_FUNCTION(image_aspect) (Scene *scene, SceneLayer *sl)
{
/* all selected objects with an image map: scale in image aspect */
Base *base;
@@ -1521,8 +1341,8 @@ static void UNUSED_FUNCTION(image_aspect) (Scene *scene, View3D *v3d)
if (scene->obedit) return; // XXX get from context
if (ID_IS_LINKED_DATABLOCK(scene)) return;
- for (base = FIRSTBASE; base; base = base->next) {
- if (TESTBASELIB(v3d, base)) {
+ for (base = FIRSTBASE_NEW; base; base = base->next) {
+ if (TESTBASELIB_NEW(base)) {
ob = base->object;
done = false;
@@ -1555,7 +1375,7 @@ static void UNUSED_FUNCTION(image_aspect) (Scene *scene, View3D *v3d)
else ob->size[1] = ob->size[0] * y / x;
done = true;
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
BKE_image_release_ibuf(tex->ima, ibuf, NULL);
}
@@ -1691,8 +1511,15 @@ bool ED_object_mode_compat_set(bContext *C, Object *ob, int mode, ReportList *re
{
bool ok;
if (!ELEM(ob->mode, mode, OB_MODE_OBJECT)) {
+ WorkSpace *workspace = CTX_wm_workspace(C);
const char *opstring = object_mode_op_string(ob->mode);
+
WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL);
+#ifdef USE_WORKSPACE_MODE
+ BKE_workspace_object_mode_set(workspace, ob->mode);
+#else
+ UNUSED_VARS(workspace);
+#endif
ok = ELEM(ob->mode, mode, OB_MODE_OBJECT);
if (!ok) {
wmOperatorType *ot = WM_operatortype_find(opstring, false);
@@ -1802,13 +1629,23 @@ void OBJECT_OT_mode_set(wmOperatorType *ot)
}
-
void ED_object_toggle_modes(bContext *C, int mode)
{
if (mode != OB_MODE_OBJECT) {
const char *opstring = object_mode_op_string(mode);
+
if (opstring) {
+#ifdef USE_WORKSPACE_MODE
+ WorkSpace *workspace = CTX_wm_workspace(C);
+#endif
WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL);
+
+#ifdef USE_WORKSPACE_MODE
+ Object *ob = CTX_data_active_object(C);
+ if (ob) {
+ BKE_workspace_object_mode_set(workspace, ob->mode);
+ }
+#endif
}
}
}
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..87b59da6c62
--- /dev/null
+++ b/source/blender/editors/object/object_facemap_ops.c
@@ -0,0 +1,493 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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 "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+
+#include "WM_types.h"
+#include "WM_api.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 "BLI_utildefines.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_listbase.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "ED_mesh.h"
+#include "ED_object.h"
+
+#include "RNA_define.h"
+#include "RNA_access.h"
+
+#include <string.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 there's is no facemap layer then create one */
+ 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 int 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 int face_map_supported_edit_mode_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 && ob->mode == OB_MODE_EDIT);
+}
+
+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_group.c b/source/blender/editors/object/object_group.c
index 0fe43c44d7d..3064bf8af1a 100644
--- a/source/blender/editors/object/object_group.c
+++ b/source/blender/editors/object/object_group.c
@@ -40,7 +40,6 @@
#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"
@@ -48,6 +47,8 @@
#include "BKE_report.h"
#include "BKE_object.h"
+#include "DEG_depsgraph_build.h"
+
#include "ED_screen.h"
#include "ED_object.h"
@@ -128,7 +129,6 @@ 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(ob, single_group_index);
Group *group;
@@ -151,7 +151,7 @@ static int objects_add_active_exec(bContext *C, wmOperator *op)
continue;
if (!BKE_group_object_cyclic_check(bmain, base->object, group)) {
- BKE_group_object_add(group, base->object, scene, base);
+ BKE_group_object_add(group, base->object);
updated = true;
}
else {
@@ -167,7 +167,7 @@ static int objects_add_active_exec(bContext *C, wmOperator *op)
if (!updated)
return OPERATOR_CANCELLED;
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -200,8 +200,8 @@ void GROUP_OT_objects_add_active(wmOperatorType *ot)
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;
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *ob = OBACT_NEW;
int single_group_index = RNA_enum_get(op->ptr, "group");
Group *single_group = group_object_active_find_index(ob, single_group_index);
Group *group;
@@ -221,7 +221,7 @@ static int objects_remove_active_exec(bContext *C, wmOperator *op)
/* Remove groups from selected objects */
CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
{
- BKE_group_object_unlink(group, base->object, scene, base);
+ BKE_group_object_unlink(group, base->object);
ok = 1;
}
CTX_DATA_END;
@@ -231,7 +231,7 @@ static int objects_remove_active_exec(bContext *C, wmOperator *op)
if (!ok)
BKE_report(op->reports, RPT_ERROR, "Active object contains no groups");
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -264,15 +264,14 @@ void GROUP_OT_objects_remove_active(wmOperatorType *ot)
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(scene, base, base->object);
+ BKE_object_groups_clear(base->object);
}
CTX_DATA_END;
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -297,7 +296,6 @@ 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(ob, single_group_index);
Group *group;
@@ -315,7 +313,7 @@ static int group_objects_remove_exec(bContext *C, wmOperator *op)
/* now remove all selected objects from the group */
CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
{
- BKE_group_object_unlink(group, base->object, scene, base);
+ BKE_group_object_unlink(group, base->object);
updated = true;
}
CTX_DATA_END;
@@ -324,7 +322,7 @@ static int group_objects_remove_exec(bContext *C, wmOperator *op)
if (!updated)
return OPERATOR_CANCELLED;
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -357,7 +355,6 @@ void GROUP_OT_objects_remove(wmOperatorType *ot)
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 */
@@ -367,11 +364,11 @@ static int group_create_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN (C, Base *, base, selected_bases)
{
- BKE_group_object_add(group, base->object, scene, base);
+ BKE_group_object_add(group, base->object);
}
CTX_DATA_END;
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -398,7 +395,6 @@ void GROUP_OT_create(wmOperatorType *ot)
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;
@@ -407,7 +403,7 @@ static int group_add_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
group = BKE_group_add(bmain, "Group");
- BKE_group_object_add(group, ob, scene, NULL);
+ BKE_group_object_add(group, ob);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
@@ -432,7 +428,6 @@ void OBJECT_OT_group_add(wmOperatorType *ot)
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"));
@@ -457,7 +452,7 @@ static int group_link_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BKE_group_object_add(group, ob, scene, NULL);
+ BKE_group_object_add(group, ob);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
@@ -490,14 +485,13 @@ void OBJECT_OT_group_link(wmOperatorType *ot)
static int group_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
- 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(group, ob, scene, NULL); /* base will be used if found */
+ BKE_group_object_unlink(group, ob);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
@@ -528,8 +522,7 @@ static int group_unlink_exec(bContext *C, wmOperator *UNUSED(op))
if (!group)
return OPERATOR_CANCELLED;
- BKE_libblock_unlink(bmain, group, false, false);
- BKE_libblock_free(bmain, group);
+ BKE_libblock_delete(bmain, group);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
@@ -560,8 +553,10 @@ static int select_grouped_exec(bContext *C, wmOperator *UNUSED(op)) /* Select o
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_SELECTABLED) != 0)) {
+ if (BKE_group_object_exists(group, base->object)) {
+ ED_object_base_select(base, BA_SELECT);
+ }
}
}
CTX_DATA_END;
diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c
index 438c10c51fa..fce55689e9a 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(Scene *scene, Object *obedit,
EDBM_mesh_load(obedit);
EDBM_mesh_make(scene->toolsettings, obedit, true);
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
em = me->edit_btmesh;
@@ -445,26 +448,26 @@ static int 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, SceneLayer *sl, Object *obedit)
{
Base *base, *basedit;
Object *ob;
- ob = BKE_object_add(bmain, scene, OB_EMPTY, NULL);
+ ob = BKE_object_add(bmain, scene, sl, OB_EMPTY, NULL);
- basedit = BKE_scene_base_find(scene, obedit);
- base = scene->basact;
+ basedit = BKE_scene_layer_base_find(sl, obedit);
+ base = sl->basact;
base->lay = ob->lay = obedit->lay;
- BLI_assert(scene->basact->object == ob);
+ BLI_assert(sl->basact->object == ob);
/* icky, BKE_object_add sets new base as active.
* so set it back to the original edit object */
- scene->basact = basedit;
+ sl->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(Main *bmain, Scene *scene, SceneLayer *sl, Object *obedit, Object *ob, int mode, ReportList *reports)
{
ModifierData *md = NULL;
HookModifierData *hmd = NULL;
@@ -482,7 +485,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, sl, obedit);
/* transform cent to global coords for loc */
mul_v3_m4v3(ob->loc, obedit->obmat, cent);
@@ -547,7 +550,7 @@ static int add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob
/* 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 +559,7 @@ static int object_add_hook_selob_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_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 +584,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(bmain, scene, sl, obedit, obsel, mode, op->reports)) {
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obedit);
return OPERATOR_FINISHED;
}
@@ -611,9 +615,10 @@ static int object_add_hook_newob_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_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(bmain, scene, sl, obedit, NULL, OBJECT_ADDHOOK_NEWOB, op->reports)) {
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 +660,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 +734,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;
@@ -779,7 +784,7 @@ static int object_hook_recenter_exec(bContext *C, wmOperator *op)
sub_v3_v3v3(hmd->cent, scene->cursor, 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;
@@ -837,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;
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 9710e4f843d..f6fb3cc75b8 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -70,7 +70,6 @@ void OBJECT_OT_make_local(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);
@@ -78,10 +77,6 @@ void OBJECT_OT_unlink_data(struct wmOperatorType *ot);
void OBJECT_OT_mode_set(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);
@@ -117,6 +112,7 @@ 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_effector_add(struct wmOperatorType *ot);
@@ -186,6 +182,7 @@ void OBJECT_OT_skin_loose_mark_clear(struct wmOperatorType *ot);
void OBJECT_OT_skin_radii_equalize(struct wmOperatorType *ot);
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);
/* object_constraint.c */
void OBJECT_OT_constraint_add(struct wmOperatorType *ot);
@@ -246,6 +243,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);
diff --git a/source/blender/editors/object/object_lattice.c b/source/blender/editors/object/object_lattice.c
index b72c5c148bc..edfc5b431b1 100644
--- a/source/blender/editors/object/object_lattice.c
+++ b/source/blender/editors/object/object_lattice.c
@@ -52,13 +52,14 @@
#include "RNA_enum_types.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_deform.h"
#include "BKE_report.h"
#include "BKE_utildefines.h"
+#include "DEG_depsgraph.h"
+
#include "ED_lattice.h"
#include "ED_object.h"
#include "ED_screen.h"
@@ -591,7 +592,7 @@ static int make_regular_exec(bContext *C, wmOperator *UNUSED(op))
BKE_lattice_resize(lt, lt->pntsu, lt->pntsv, lt->pntsw, 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_GEOM | ND_DATA, ob->data);
return OPERATOR_FINISHED;
@@ -811,7 +812,7 @@ static int lattice_flip_exec(bContext *C, wmOperator *op)
}
/* updates */
- 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, obedit->data);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index b44ddf925a8..85751fd64de 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -54,7 +54,6 @@
#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_effect.h"
@@ -75,6 +74,9 @@
#include "BKE_softbody.h"
#include "BKE_editmesh.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -98,12 +100,12 @@ ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *sc
ModifierData *md = NULL, *new_md = NULL;
const ModifierTypeInfo *mti = modifierType_getInfo(type);
- /* only geometry objects should be able to get modifiers [#25291] */
- if (!ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
+ /* Check compatibility of modifier [T25291, T50373]. */
+ if (!BKE_object_support_modifier_type_check(ob, type)) {
BKE_reportf(reports, RPT_WARNING, "Modifiers cannot be added to object '%s'", ob->id.name + 2);
return NULL;
}
-
+
if (mti->flags & eModifierTypeFlag_Single) {
if (modifiers_findByType(ob, type)) {
BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed");
@@ -171,8 +173,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;
}
@@ -253,7 +255,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;
@@ -320,7 +322,7 @@ static bool object_modifier_remove(Main *bmain, Object *ob, ModifierData *md,
ob->mode &= ~OB_MODE_PARTICLE_EDIT;
}
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
BLI_remlink(&ob->modifiers, md);
modifier_free(md);
@@ -341,8 +343,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 +367,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 +413,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, SceneLayer *sl, Object *ob, ModifierData *md)
{
Object *obn;
ParticleSystem *psys;
@@ -463,7 +465,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, sl, OB_MESH, NULL);
me = obn->data;
me->totvert = totvert;
@@ -515,7 +517,7 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene *
}
}
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
return 1;
}
@@ -643,7 +645,7 @@ static int modifier_apply_obdata(ReportList *reports, Scene *scene, Object *ob,
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");
@@ -793,7 +795,7 @@ void OBJECT_OT_modifier_add(wmOperatorType *ot)
/* identifiers */
ot->name = "Add Modifier";
- ot->description = "Add a modifier to the active object";
+ ot->description = "Add a procedural operation/effect to the active object";
ot->idname = "OBJECT_OT_modifier_add";
/* api callbacks */
@@ -872,7 +874,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);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *ob = ED_object_active_context(C);
ModifierData *md = edit_modifier_property_get(op, ob, 0);
int mode_orig = ob->mode;
@@ -885,7 +887,7 @@ static int modifier_remove_exec(bContext *C, wmOperator *op)
/* 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 (sl->basact && sl->basact->object == ob)
WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
return OPERATOR_FINISHED;
@@ -924,7 +926,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;
@@ -963,7 +965,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;
@@ -1005,7 +1007,7 @@ static int modifier_apply_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_MODIFIER, ob);
return OPERATOR_FINISHED;
@@ -1048,13 +1050,14 @@ static int modifier_convert_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_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, sl, 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;
@@ -1093,7 +1096,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;
@@ -1187,7 +1190,7 @@ static int multires_subdivide_exec(bContext *C, wmOperator *op)
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) {
@@ -1256,7 +1259,7 @@ static int multires_reshape_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_MODIFIER, ob);
return OPERATOR_FINISHED;
@@ -1404,7 +1407,7 @@ static int multires_base_apply_exec(bContext *C, wmOperator *op)
multiresModifier_base_apply(mmd, 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;
@@ -1484,7 +1487,6 @@ static int skin_root_mark_exec(bContext *C, wmOperator *UNUSED(op))
Object *ob = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(ob);
BMesh *bm = em->bm;
- const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
BMVert *bm_vert;
BMIter bm_iter;
GSet *visited;
@@ -1493,6 +1495,8 @@ static int skin_root_mark_exec(bContext *C, wmOperator *UNUSED(op))
BKE_mesh_ensure_skin_customdata(ob->data);
+ const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
+
BM_ITER_MESH (bm_vert, &bm_iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(bm_vert, BM_ELEM_SELECT) &&
BLI_gset_add(visited, bm_vert))
@@ -1509,7 +1513,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;
@@ -1564,7 +1568,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;
@@ -1614,7 +1618,7 @@ static int skin_radii_equalize_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_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
@@ -1683,7 +1687,7 @@ static void skin_armature_bone_create(Object *skin_ob,
}
}
-static Object *modifier_skin_armature_create(Main *bmain, Scene *scene, Object *skin_ob)
+static Object *modifier_skin_armature_create(Main *bmain, Scene *scene, SceneLayer *sl, Object *skin_ob)
{
BLI_bitmap *edges_visited;
DerivedMesh *deform_dm;
@@ -1706,7 +1710,7 @@ static Object *modifier_skin_armature_create(Main *bmain, Scene *scene, Object *
NULL,
me->totvert);
- arm_ob = BKE_object_add(bmain, scene, OB_ARMATURE, NULL);
+ arm_ob = BKE_object_add(bmain, scene, sl, OB_ARMATURE, NULL);
BKE_object_transform_copy(arm_ob, skin_ob);
arm = arm_ob->data;
arm->layer = 1;
@@ -1765,6 +1769,7 @@ static int skin_armature_create_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *ob = CTX_data_active_object(C), *arm_ob;
Mesh *me = ob->data;
ModifierData *skin_md;
@@ -1776,7 +1781,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(bmain, scene, sl, ob);
/* add a modifier to connect the new armature to the mesh */
arm_md = (ArmatureModifierData *)modifier_new(eModifierType_Armature);
@@ -1786,8 +1791,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);
@@ -1854,7 +1859,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;
@@ -1923,7 +1928,7 @@ static int meshdeform_bind_exec(bContext *C, wmOperator *op)
mmd->totcagevert = 0;
mmd->totinfluence = 0;
- 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 {
@@ -1997,7 +2002,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;
@@ -2142,7 +2147,7 @@ static int ocean_bake_exec(bContext *C, wmOperator *op)
if (free) {
omd->refresh |= MOD_OCEAN_REFRESH_CLEAR_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_MODIFIER, ob);
return OPERATOR_FINISHED;
}
@@ -2192,7 +2197,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
@@ -2265,7 +2270,7 @@ static int laplaciandeform_bind_exec(bContext *C, wmOperator *op)
else {
lmd->flag |= MOD_LAPLACIANDEFORM_BIND;
}
- 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;
}
@@ -2294,3 +2299,56 @@ void OBJECT_OT_laplaciandeform_bind(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
edit_modifier_properties(ot);
}
+
+/************************ sdef bind operator *********************/
+
+static int surfacedeform_bind_poll(bContext *C)
+{
+ return edit_modifier_poll_generic(C, &RNA_SurfaceDeformModifier, 0);
+}
+
+static int surfacedeform_bind_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_active_context(C);
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)edit_modifier_property_get(op, ob, eModifierType_SurfaceDeform);
+
+ if (!smd)
+ return OPERATOR_CANCELLED;
+
+ if (smd->flags & MOD_SDEF_BIND) {
+ smd->flags &= ~MOD_SDEF_BIND;
+ }
+ else if (smd->target) {
+ smd->flags |= MOD_SDEF_BIND;
+ }
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int surfacedeform_bind_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (edit_modifier_invoke_properties(C, op))
+ return surfacedeform_bind_exec(C, op);
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void OBJECT_OT_surfacedeform_bind(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Surface Deform Bind";
+ ot->description = "Bind mesh to target in surface deform modifier";
+ ot->idname = "OBJECT_OT_surfacedeform_bind";
+
+ /* api callbacks */
+ ot->poll = surfacedeform_bind_poll;
+ ot->invoke = surfacedeform_bind_invoke;
+ ot->exec = surfacedeform_bind_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ edit_modifier_properties(ot);
+}
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 7e7e1ef182c..ca02457ba39 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -67,10 +67,6 @@ void ED_operatortypes_object(void)
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);
@@ -90,13 +86,11 @@ void ED_operatortypes_object(void)
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_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);
@@ -113,6 +107,7 @@ void ED_operatortypes_object(void)
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_camera_add);
@@ -202,6 +197,14 @@ 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);
@@ -255,6 +258,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_data_transfer);
WM_operatortype_append(OBJECT_OT_datalayout_transfer);
+ WM_operatortype_append(OBJECT_OT_surfacedeform_bind);
}
void ED_operatormacros_object(void)
@@ -382,25 +386,6 @@ void ED_keymap_object(wmKeyConfig *keyconf)
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);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index d5c7632765f..333bcf00a8c 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -63,24 +63,28 @@
#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_global.h"
#include "BKE_group.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_query.h"
+#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mball.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
+#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_sca.h"
@@ -89,6 +93,9 @@
#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"
@@ -120,6 +127,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *obedit = CTX_data_edit_object(C);
BMVert *eve;
BMIter iter;
@@ -139,7 +147,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
EDBM_mesh_load(obedit);
EDBM_mesh_make(scene->toolsettings, obedit, true);
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
em = me->edit_btmesh;
@@ -227,7 +235,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)) {
@@ -236,7 +244,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
else {
Object workob;
- ob->parent = BASACT->object;
+ ob->parent = BASACT_NEW->object;
if (v3) {
ob->partype = PARVERT3;
ob->par1 = v1 - 1;
@@ -260,7 +268,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);
@@ -330,6 +338,7 @@ static int make_proxy_exec(bContext *C, wmOperator *op)
Object *ob, *gob = ED_object_active_context(C);
GroupObject *go;
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
if (gob->dup_group != NULL) {
go = BLI_findlink(&gob->dup_group->gobject, RNA_enum_get(op->ptr, "object"));
@@ -342,16 +351,16 @@ static int make_proxy_exec(bContext *C, wmOperator *op)
if (ob) {
Object *newob;
- Base *newbase, *oldbase = BASACT;
+ BaseLegacy *newbase, *oldbase = BASACT_NEW;
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(bmain, scene, sl, OB_EMPTY, name);
/* set layers OK */
- newbase = BASACT; /* BKE_object_add sets active... */
+ newbase = BASACT_NEW; /* BKE_object_add sets active... */
newbase->lay = oldbase->lay;
newob->lay = newbase->lay;
@@ -364,8 +373,8 @@ static int make_proxy_exec(bContext *C, wmOperator *op)
BKE_object_make_proxy(newob, ob, gob);
/* 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 {
@@ -520,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 */
@@ -535,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;
@@ -609,7 +618,7 @@ bool ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
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) {
@@ -706,7 +715,7 @@ bool ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
((CurveModifierData *)md)->object = par;
}
if (par->curve_cache && par->curve_cache->path == NULL) {
- DAG_id_tag_update(&par->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&par->id, OB_RECALC_DATA);
}
}
break;
@@ -789,7 +798,7 @@ bool ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
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);
}
}
@@ -875,7 +884,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);
@@ -991,7 +1000,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)
@@ -1006,7 +1015,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;
@@ -1016,7 +1025,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;
@@ -1051,7 +1060,7 @@ static int object_slow_parent_clear_exec(bContext *C, wmOperator *UNUSED(op))
ob->partype -= PARSLOW;
BKE_object_where_is_calc(scene, ob);
ob->partype |= PARSLOW;
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
}
}
}
@@ -1089,7 +1098,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;
@@ -1143,7 +1152,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) {
@@ -1157,7 +1166,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;
@@ -1217,7 +1226,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)) {
@@ -1240,7 +1249,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)) {
@@ -1264,7 +1273,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)) {
@@ -1278,7 +1287,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;
@@ -1304,119 +1313,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 values[20], a;
- 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
@@ -1439,20 +1335,6 @@ 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"));
@@ -1472,9 +1354,10 @@ static int make_links_scene_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ SceneCollection *sc_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(scene_to, sc_to, base->object);
}
CTX_DATA_END;
@@ -1530,7 +1413,6 @@ 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);
const int type = RNA_enum_get(op->ptr, "type");
Object *ob_src;
ID *obdata_id;
@@ -1567,7 +1449,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
/* if amount of material indices changed: */
test_object_materials(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 */
@@ -1575,7 +1457,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
Material *ma = give_current_material(ob_src, a + 1);
assign_material(ob_dst, ma, a + 1, BKE_MAT_ASSIGN_USERPREF); /* also works with ma==NULL */
}
- DAG_id_tag_update(&ob_dst->id, 0);
+ DEG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
break;
case MAKE_LINKS_ANIMDATA:
BKE_animdata_copy_id((ID *)ob_dst, (ID *)ob_src, false);
@@ -1586,19 +1468,19 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
}
BKE_animdata_copy_id((ID *)ob_dst->data, (ID *)ob_src->data, false);
}
- 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;
/* first clear groups */
- BKE_object_groups_clear(scene, base_dst, ob_dst);
+ BKE_object_groups_clear(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);
+ BKE_group_object_add(group_node->link, ob_dst);
}
else {
is_cycle = true;
@@ -1609,13 +1491,13 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
case MAKE_LINKS_DUPLIGROUP:
ob_dst->dup_group = ob_src->dup_group;
if (ob_dst->dup_group) {
- id_lib_extern(&ob_dst->dup_group->id);
+ id_us_plus(&ob_dst->dup_group->id);
ob_dst->transflag |= OB_DUPLIGROUP;
}
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);
+ DEG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
break;
case MAKE_LINKS_FONTS:
{
@@ -1644,7 +1526,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;
}
}
@@ -1667,7 +1549,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);
@@ -1731,60 +1613,87 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot)
/**************************** Make Single User ********************************/
-static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const int flag, const bool copy_groups)
+static Object *single_object_users_object(Main *bmain, Scene *scene, Object *ob, const bool copy_groups)
{
- Base *base;
- Object *ob, *obn;
- Group *group, *groupn;
- GroupObject *go;
+ if (!ID_IS_LINKED_DATABLOCK(ob) && ob->id.us > 1) {
+ /* base gets copy of object */
+ Object *obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob));
- clear_sca_new_poins(); /* sensor/contr/act */
+ if (copy_groups) {
+ if (ob->flag & OB_FROMGROUP) {
+ obn->flag |= OB_FROMGROUP;
+ }
+ }
+ else {
+ /* copy already clears */
+ }
+ /* remap gpencil parenting */
- /* newid may still have some trash from Outliner tree building,
- * so clear that first to avoid errors [#26002] */
- for (ob = bmain->object.first; ob; ob = ob->id.next)
- ob->id.newid = NULL;
+ if (scene->gpd) {
+ bGPdata *gpd = scene->gpd;
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl->parent == ob) {
+ gpl->parent = obn;
+ }
+ }
+ }
- /* duplicate (must set newid) */
- for (base = FIRSTBASE; base; base = base->next) {
- ob = base->object;
+ id_us_min(&ob->id);
+ return obn;
+ }
+ return NULL;
+}
- if ((base->flag & flag) == flag) {
- if (!ID_IS_LINKED_DATABLOCK(ob) && ob->id.us > 1) {
- /* base gets copy of object */
- obn = BKE_object_copy(bmain, ob);
- base->object = obn;
+static void libblock_relink_scene_collection(SceneCollection *sc)
+{
+ for (LinkData *link = sc->objects.first; link; link = link->next) {
+ BKE_libblock_relink_to_newid(link->data);
+ }
- if (copy_groups) {
- if (ob->flag & OB_FROMGROUP) {
- obn->flag |= OB_FROMGROUP;
- }
- }
- else {
- /* copy already clears */
- }
- /* remap gpencil parenting */
+ for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
+ libblock_relink_scene_collection(nsc);
+ }
+}
- if (scene->gpd) {
- bGPdata *gpd = scene->gpd;
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if (gpl->parent == ob) {
- gpl->parent = obn;
- }
- }
- }
+static void single_object_users_scene_collection(Main *bmain, Scene *scene, SceneCollection *sc, const int flag, const bool copy_groups)
+{
+ for (LinkData *link = sc->objects.first; link; link = link->next) {
+ Object *ob = link->data;
+ /* an object may be in more than one collection */
+ if ((ob->id.newid == NULL) && ((ob->flag & flag) == flag)) {
+ link->data = single_object_users_object(bmain, scene, link->data, copy_groups);
+ }
+ }
- base->flag = obn->flag;
+ /* we reset filter objects because they should be regenerated after this */
+ BLI_freelistN(&sc->filter_objects);
- id_us_min(&ob->id);
- }
+ for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
+ single_object_users_scene_collection(bmain, scene, nsc, flag, copy_groups);
+ }
+}
+
+/* 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)
+{
+ Group *group, *groupn;
+ GroupObject *go;
+
+ clear_sca_new_poins(); /* BGE logic */
+
+ /* duplicate all the objects of the scene */
+ SceneCollection *msc = BKE_collection_master(scene);
+ single_object_users_scene_collection(bmain, scene, msc, flag, copy_groups);
+
+ /* loop over SceneLayers and assign the pointers accordingly */
+ for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
+ for (Base *base = sl->object_bases.first; base; base = base->next) {
+ ID_NEW_REMAP(base->object);
}
}
/* duplicate groups that consist entirely of duplicated objects */
for (group = bmain->group.first; group; group = group->id.next) {
- group->id.newid = NULL;
-
if (copy_groups && group->gobject.first) {
bool all_duplicated = true;
@@ -1796,10 +1705,11 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
}
if (all_duplicated) {
- groupn = BKE_group_copy(bmain, group);
+ groupn = ID_NEW_SET(group, BKE_group_copy(bmain, group));
- for (go = groupn->gobject.first; go; go = go->next)
+ for (go = groupn->gobject.first; go; go = go->next) {
go->ob = (Object *)go->ob->id.newid;
+ }
}
}
}
@@ -1807,30 +1717,33 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
/* group pointers in scene */
BKE_scene_groups_relink(scene);
- ID_NEW(scene->camera);
- if (v3d) ID_NEW(v3d->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(&base->object->id);
- }
+ libblock_relink_scene_collection(msc);
set_sca_new_poins();
+
+ /* TODO redo filter */
+ TODO_LAYER_SYNC_FILTER
}
/* 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(scene, ob_iter)
+ {
+ ob_iter->flag &= ~OB_DONE;
}
+ FOREACH_SCENE_OBJECT_END
+
+ /* tag only the one object */
+ ob->flag |= OB_DONE;
- single_object_users(bmain, scene, NULL, OB_DONE, copy_groups);
+ single_object_users(bmain, scene, NULL, OB_DONE, false);
+ BKE_main_id_clear_newpoins(bmain);
}
static void new_id_matar(Main *bmain, Material **matar, const int totcol)
@@ -1847,75 +1760,73 @@ static void new_id_matar(Main *bmain, Material **matar, const int totcol)
id_us_min(id);
}
else if (id->us > 1) {
- matar[a] = BKE_material_copy(bmain, matar[a]);
+ matar[a] = ID_NEW_SET(id, BKE_material_copy(bmain, matar[a]));
id_us_min(id);
- id->newid = (ID *)matar[a];
}
}
}
}
-static void single_obdata_users(Main *bmain, Scene *scene, const int flag)
+static void single_obdata_users(Main *bmain, Scene *scene, SceneLayer *sl, 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_DATABLOCK(ob) && (base->flag & flag) == flag) {
+ FOREACH_OBJECT_FLAG(scene, sl, flag, ob)
+ {
+ if (!ID_IS_LINKED_DATABLOCK(ob)) {
id = ob->data;
if (id && id->us > 1 && !ID_IS_LINKED_DATABLOCK(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 = BKE_lamp_copy(bmain, ob->data);
+ 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(la->mtex[a]->object);
+ ID_NEW_REMAP(la->mtex[a]->object);
}
}
break;
case OB_CAMERA:
- ob->data = BKE_camera_copy(bmain, ob->data);
+ ob->data = ID_NEW_SET(ob->data, BKE_camera_copy(bmain, ob->data));
break;
case OB_MESH:
- ob->data = me = BKE_mesh_copy(bmain, ob->data);
- if (me->key)
- BKE_animdata_copy_id_action((ID *)me->key);
+ /* Needed to remap texcomesh below. */
+ me = ob->data = ID_NEW_SET(ob->data, BKE_mesh_copy(bmain, ob->data));
+ if (me->key) /* We do not need to set me->key->id.newid here... */
+ BKE_animdata_copy_id_action((ID *)me->key, false);
break;
case OB_MBALL:
- ob->data = BKE_mball_copy(bmain, ob->data);
+ ob->data = ID_NEW_SET(ob->data, BKE_mball_copy(bmain, ob->data));
break;
case OB_CURVE:
case OB_SURF:
case OB_FONT:
- ob->data = cu = BKE_curve_copy(bmain, ob->data);
- ID_NEW(cu->bevobj);
- ID_NEW(cu->taperobj);
- if (cu->key)
- BKE_animdata_copy_id_action((ID *)cu->key);
+ ob->data = cu = ID_NEW_SET(ob->data, BKE_curve_copy(bmain, ob->data));
+ ID_NEW_REMAP(cu->bevobj);
+ ID_NEW_REMAP(cu->taperobj);
+ if (cu->key) /* We do not need to set cu->key->id.newid here... */
+ BKE_animdata_copy_id_action((ID *)cu->key, false);
break;
case OB_LATTICE:
- ob->data = lat = BKE_lattice_copy(bmain, ob->data);
- if (lat->key)
- BKE_animdata_copy_id_action((ID *)lat->key);
+ ob->data = lat = ID_NEW_SET(ob->data, BKE_lattice_copy(bmain, ob->data));
+ if (lat->key) /* We do not need to set lat->key->id.newid here... */
+ BKE_animdata_copy_id_action((ID *)lat->key, false);
break;
case OB_ARMATURE:
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- ob->data = BKE_armature_copy(bmain, ob->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);
break;
case OB_SPEAKER:
- ob->data = BKE_speaker_copy(bmain, ob->data);
+ ob->data = ID_NEW_SET(ob->data, BKE_speaker_copy(bmain, ob->data));
break;
default:
if (G.debug & G_DEBUG)
@@ -1928,54 +1839,47 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag)
* AnimData structure, which is not what we want.
* (sergey)
*/
- BKE_animdata_copy_id_action((ID *)ob->data);
+ BKE_animdata_copy_id_action((ID *)ob->data, false);
id_us_min(id);
- id->newid = ob->data;
}
}
}
+ FOREACH_OBJECT_FLAG_END
me = bmain->mesh.first;
while (me) {
- ID_NEW(me->texcomesh);
+ ID_NEW_REMAP(me->texcomesh);
me = me->id.next;
}
}
-static void single_object_action_users(Scene *scene, const int flag)
+static void single_object_action_users(Scene *scene, SceneLayer *sl, const int flag)
{
- Object *ob;
- Base *base;
-
- for (base = FIRSTBASE; base; base = base->next) {
- ob = base->object;
- if (!ID_IS_LINKED_DATABLOCK(ob) && (flag == 0 || (base->flag & SELECT)) ) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- BKE_animdata_copy_id_action(&ob->id);
+ FOREACH_OBJECT_FLAG(scene, sl, flag, ob)
+ if (!ID_IS_LINKED_DATABLOCK(ob)) {
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ BKE_animdata_copy_id_action(&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, SceneLayer *sl, const int flag, const bool do_textures)
{
- Object *ob;
- Base *base;
Material *ma, *man;
Tex *tex;
int a, b;
- for (base = FIRSTBASE; base; base = base->next) {
- ob = base->object;
- if (!ID_IS_LINKED_DATABLOCK(ob) && (flag == 0 || (base->flag & SELECT)) ) {
+ FOREACH_OBJECT_FLAG(scene, sl, flag, ob)
+ if (!ID_IS_LINKED_DATABLOCK(ob)) {
for (a = 1; a <= ob->totcol; a++) {
ma = give_current_material(ob, a);
if (ma) {
- /* do not test for LIB_TAG_NEW: this functions guaranteed delivers single_users! */
+ /* do not test for LIB_TAG_NEW or use newid: this functions guaranteed delivers single_users! */
if (ma->id.us > 1) {
man = BKE_material_copy(bmain, ma);
- BKE_animdata_copy_id_action(&man->id);
+ BKE_animdata_copy_id_action(&man->id, false);
man->id.us = 0;
assign_material(ob, man, a, BKE_MAT_ASSIGN_USERPREF);
@@ -1986,7 +1890,7 @@ static void single_mat_users(Main *bmain, Scene *scene, const int flag, const bo
if (tex->id.us > 1) {
id_us_min(&tex->id);
tex = BKE_texture_copy(bmain, tex);
- BKE_animdata_copy_id_action(&tex->id);
+ BKE_animdata_copy_id_action(&tex->id, false);
man->mtex[b]->tex = tex;
}
}
@@ -1996,7 +1900,7 @@ static void single_mat_users(Main *bmain, Scene *scene, const int flag, const bo
}
}
}
- }
+ FOREACH_OBJECT_FLAG_END
}
static void do_single_tex_user(Main *bmain, Tex **from)
@@ -2012,8 +1916,8 @@ static void do_single_tex_user(Main *bmain, Tex **from)
id_us_min(&tex->id);
}
else if (tex->id.us > 1) {
- texn = BKE_texture_copy(bmain, tex);
- BKE_animdata_copy_id_action(&texn->id);
+ texn = ID_NEW_SET(tex, BKE_texture_copy(bmain, tex));
+ BKE_animdata_copy_id_action(&texn->id, false);
tex->id.newid = (ID *)texn;
id_us_min(&tex->id);
*from = texn;
@@ -2090,7 +1994,7 @@ static void single_mat_users_expand(Main *bmain)
if (ma->id.tag & LIB_TAG_NEW)
for (a = 0; a < MAX_MTEX; a++)
if (ma->mtex[a])
- ID_NEW(ma->mtex[a]->object);
+ ID_NEW_REMAP(ma->mtex[a]->object);
}
/* used for copying scenes */
@@ -2099,35 +2003,58 @@ void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bo
single_object_users(bmain, scene, NULL, 0, copy_groups);
if (full) {
- single_obdata_users(bmain, scene, 0);
- single_object_action_users(scene, 0);
+ single_obdata_users(bmain, scene, NULL, 0);
+ single_object_action_users(scene, NULL, 0);
single_mat_users_expand(bmain);
single_tex_users_expand(bmain);
}
- BKE_main_id_clear_newpoins(bmain);
-}
+ /* Relink nodetrees' pointers that have been duplicated. */
+ FOREACH_NODETREE(bmain, ntree, id)
+ {
+ /* This is a bit convoluted, we want to root ntree of copied IDs and only those,
+ * so we first check that old ID has been copied and that ntree is root tree of old ID,
+ * then get root tree of new ID and remap its pointers to new ID... */
+ if (id->newid && (&ntree->id != id)) {
+ ntree = ntreeFromID(id->newid);
+ BKE_libblock_relink_to_newid(&ntree->id);
+ }
+ } FOREACH_NODETREE_END
-/******************************* Make Local ***********************************/
+ /* Relink datablock pointer properties */
+ {
+ IDP_RelinkProperty(scene->id.properties);
-/* helper for below, ma was checked to be not NULL */
-static void make_local_makelocalmaterial(Material *ma)
-{
- AnimData *adt;
- int b;
+ for (Base *base = scene->base.first; base; base = base->next) {
+ Object *ob = base->object;
+ if (!ID_IS_LINKED_DATABLOCK(ob)) {
+ IDP_RelinkProperty(ob->id.properties);
+ }
+ }
- id_make_local(G.main, &ma->id, false, false);
+ if (scene->nodetree) {
+ IDP_RelinkProperty(scene->nodetree->id.properties);
+ for (bNode *node = scene->nodetree->nodes.first; node; node = node->next) {
+ IDP_RelinkProperty(node->prop);
+ }
+ }
- for (b = 0; b < MAX_MTEX; b++)
- if (ma->mtex[b] && ma->mtex[b]->tex)
- id_make_local(G.main, &ma->mtex[b]->tex->id, false, false);
+ if (scene->gpd) {
+ IDP_RelinkProperty(scene->gpd->id.properties);
+ }
- adt = BKE_animdata_from_id(&ma->id);
- if (adt) BKE_animdata_make_local(adt);
+ IDP_RelinkProperty(scene->world->id.properties);
- /* nodetree? XXX */
+ if (scene->clip) {
+ IDP_RelinkProperty(scene->clip->id.properties);
+ }
+ }
+ BKE_main_id_clear_newpoins(bmain);
+ DEG_relations_tag_update(bmain);
}
+/******************************* Make Local ***********************************/
+
enum {
MAKE_LOCAL_SELECT_OB = 1,
MAKE_LOCAL_SELECT_OBDATA = 2,
@@ -2136,7 +2063,7 @@ enum {
};
static int tag_localizable_looper(
- void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int UNUSED(cd_flag))
+ void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int UNUSED(cb_flag))
{
if (*id_pointer) {
(*id_pointer)->tag &= ~LIB_TAG_DOIT;
@@ -2173,12 +2100,12 @@ static void tag_localizable_objects(bContext *C, const int mode)
*/
for (Object *object = bmain->object.first; object; object = object->id.next) {
if ((object->id.tag & LIB_TAG_DOIT) == 0) {
- BKE_library_foreach_ID_link(&object->id, tag_localizable_looper, NULL, IDWALK_READONLY);
+ BKE_library_foreach_ID_link(NULL, &object->id, tag_localizable_looper, NULL, IDWALK_READONLY);
}
if (object->data) {
ID *data_id = (ID *) object->data;
if ((data_id->tag & LIB_TAG_DOIT) == 0) {
- BKE_library_foreach_ID_link(data_id, tag_localizable_looper, NULL, IDWALK_READONLY);
+ BKE_library_foreach_ID_link(NULL, data_id, tag_localizable_looper, NULL, IDWALK_READONLY);
}
}
}
@@ -2190,7 +2117,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, Scene *scene, SceneLayer *sl, SceneCollection *sc)
{
Object *ob;
bool changed = false;
@@ -2201,10 +2128,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(scene, sc, ob);
+ base = BKE_scene_layer_base_find(sl, 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;
}
@@ -2213,123 +2141,145 @@ static bool make_local_all__instance_indirect_unused(Main *bmain, Scene *scene)
return changed;
}
-static int make_local_exec(bContext *C, wmOperator *op)
+static void make_local_animdata_tag_strips(ListBase *strips)
{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- AnimData *adt;
- ParticleSystem *psys;
- Material *ma, ***matarar;
- Lamp *la;
- ID *id;
- const int mode = RNA_enum_get(op->ptr, "type");
- int a, b;
+ NlaStrip *strip;
- if (mode == MAKE_LOCAL_ALL) {
- /* de-select so the user can differentiate newly instanced from existing objects */
- BKE_scene_base_deselect_all(scene);
-
- if (make_local_all__instance_indirect_unused(bmain, scene)) {
- BKE_report(op->reports, RPT_INFO,
- "Orphan library objects added to the current scene to avoid loss");
+ for (strip = strips->first; strip; strip = strip->next) {
+ 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;
}
- BKE_library_make_local(bmain, NULL, false, false); /* NULL is all libs */
- WM_event_add_notifier(C, NC_WINDOW, NULL);
- return OPERATOR_FINISHED;
+ make_local_animdata_tag_strips(&strip->strips);
}
+}
- tag_localizable_objects(C, mode);
- BKE_main_id_clear_newpoins(bmain);
-
- CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
- {
- if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
- continue;
+/* Tag all actions used by given animdata to be made local. */
+static void make_local_animdata_tag(AnimData *adt)
+{
+ if (adt) {
+ /* Actions - Active and Temp */
+ if (adt->action) {
+ adt->action->id.tag &= ~LIB_TAG_PRE_EXISTING;
+ }
+ 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;
}
- if (ob->id.lib)
- id_make_local(bmain, &ob->id, false, false);
- }
- CTX_DATA_END;
+ /* Drivers */
+ /* TODO: need to handle the ID-targets too? */
- /* maybe object pointers */
- CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
- {
- if (ob->id.lib == NULL) {
- ID_NEW(ob->parent);
+ /* NLA Data */
+ for (NlaTrack *nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ make_local_animdata_tag_strips(&nlt->strips);
}
}
- CTX_DATA_END;
-
- CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
- {
- if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
- continue;
- }
+}
- id = ob->data;
+static void make_local_material_tag(Material *ma)
+{
+ if (ma) {
+ ma->id.tag &= ~LIB_TAG_PRE_EXISTING;
+ make_local_animdata_tag(BKE_animdata_from_id(&ma->id));
- if (id && (ELEM(mode, MAKE_LOCAL_SELECT_OBDATA, MAKE_LOCAL_SELECT_OBDATA_MATERIAL))) {
- id_make_local(bmain, id, false, false);
- adt = BKE_animdata_from_id(id);
- if (adt) BKE_animdata_make_local(adt);
+ /* About nodetrees: root one is made local together with material, others we keep linked for now... */
- /* tag indirect data direct */
- matarar = give_matarar(ob);
- if (matarar) {
- for (a = 0; a < ob->totcol; a++) {
- ma = (*matarar)[a];
- if (ma)
- id_lib_extern(&ma->id);
- }
+ 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;
}
}
+ }
+}
- for (psys = ob->particlesystem.first; psys; psys = psys->next)
- id_make_local(bmain, &psys->part->id, false, false);
+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) {
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ SceneCollection *sc = CTX_data_scene_collection(C);
- adt = BKE_animdata_from_id(&ob->id);
- if (adt) BKE_animdata_make_local(adt);
+ 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);
+
+ if (make_local_all__instance_indirect_unused(bmain, scene, sl, sc)) {
+ BKE_report(op->reports, RPT_INFO, "Orphan library objects added to the current scene to avoid loss");
+ }
}
- CTX_DATA_END;
+ else {
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
+ tag_localizable_objects(C, mode);
- if (mode == MAKE_LOCAL_SELECT_OBDATA_MATERIAL) {
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
continue;
}
- if (ob->type == OB_LAMP) {
- la = ob->data;
-
- for (b = 0; b < MAX_MTEX; b++)
- if (la->mtex[b] && la->mtex[b]->tex)
- id_make_local(bmain, &la->mtex[b]->tex->id, false, false);
+ ob->id.tag &= ~LIB_TAG_PRE_EXISTING;
+ make_local_animdata_tag(BKE_animdata_from_id(&ob->id));
+ for (psys = ob->particlesystem.first; psys; psys = psys->next) {
+ psys->part->id.tag &= ~LIB_TAG_PRE_EXISTING;
}
- else {
+
+ if (mode == MAKE_LOCAL_SELECT_OBDATA_MATERIAL) {
for (a = 0; a < ob->totcol; a++) {
ma = ob->mat[a];
- if (ma)
- make_local_makelocalmaterial(ma);
+ if (ma) {
+ make_local_material_tag(ma);
+ }
}
matarar = (Material ***)give_matarar(ob);
if (matarar) {
for (a = 0; a < ob->totcol; a++) {
ma = (*matarar)[a];
- if (ma)
- make_local_makelocalmaterial(ma);
+ if (ma) {
+ make_local_material_tag(ma);
+ }
+ }
+ }
+
+ 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) {
+ ID *ob_data = ob->data;
+ ob_data->tag &= ~LIB_TAG_PRE_EXISTING;
+ make_local_animdata_tag(BKE_animdata_from_id(ob_data));
+ }
}
CTX_DATA_END;
}
- WM_event_add_notifier(C, NC_WINDOW, NULL);
+ BKE_library_make_local(bmain, NULL, NULL, true, false); /* NULL is all libs */
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
return OPERATOR_FINISHED;
}
@@ -2345,7 +2295,7 @@ void OBJECT_OT_make_local(wmOperatorType *ot)
/* identifiers */
ot->name = "Make Local";
- ot->description = "Make library linked datablocks local to this file";
+ ot->description = "Make library linked data-blocks local to this file";
ot->idname = "OBJECT_OT_make_local";
/* api callbacks */
@@ -2369,26 +2319,31 @@ static int make_single_user_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_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;
bool update_deps = false;
- BKE_main_id_clear_newpoins(bmain);
-
if (RNA_boolean_get(op->ptr, "object")) {
- single_object_users(bmain, scene, v3d, flag, copy_groups);
+ if (flag == SELECT) {
+ BKE_scene_layer_selected_objects_tag(sl, OB_DONE);
+ single_object_users(bmain, scene, v3d, OB_DONE, copy_groups);
+ }
+ else {
+ single_object_users(bmain, scene, v3d, 0, copy_groups);
+ }
/* 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, sl, 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, sl, flag, RNA_boolean_get(op->ptr, "texture"));
}
#if 0 /* can't do this separate from materials */
@@ -2396,20 +2351,15 @@ static int make_single_user_exec(bContext *C, wmOperator *op)
single_mat_users(scene, flag, true);
#endif
if (RNA_boolean_get(op->ptr, "animation")) {
- single_object_action_users(scene, flag);
+ single_object_action_users(scene, sl, flag);
}
- /* TODO(sergey): This should not be needed, however some tool still could rely
- * on the fact, that id->newid is kept NULL by default.
- * Need to make sure all the guys are learing newid before they're
- * using it, not after.
- */
BKE_main_id_clear_newpoins(bmain);
WM_event_add_notifier(C, NC_WINDOW, NULL);
if (update_deps) {
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
}
return OPERATOR_FINISHED;
@@ -2440,7 +2390,7 @@ 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 datablock");
+ 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");
@@ -2448,7 +2398,7 @@ void OBJECT_OT_make_single_user(wmOperatorType *ot)
static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Base *base = ED_view3d_give_base_under_cursor(C, event->mval);
+ BaseLegacy *base = ED_view3d_give_base_under_cursor(C, event->mval);
Material *ma;
char name[MAX_ID_NAME - 2];
@@ -2459,7 +2409,7 @@ static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent
assign_material(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 f1b7186f8a1..0a9b8b749f1 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -41,22 +41,26 @@
#include "DNA_scene_types.h"
#include "DNA_armature_types.h"
#include "DNA_lamp_types.h"
+#include "DNA_workspace_types.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
#include "BLI_rand.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_group.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_particle.h"
#include "BKE_property.h"
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "BKE_workspace.h"
#include "BKE_library.h"
#include "BKE_deform.h"
@@ -85,22 +89,22 @@
/* 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_base_object_select(BaseLegacy *base, short mode)
{
if (base) {
if (mode == BA_SELECT) {
if (!(base->object->restrictflag & OB_RESTRICT_SELECT))
- base->flag |= SELECT;
+ base->flag_legacy |= SELECT;
}
else if (mode == BA_DESELECT) {
- base->flag &= ~SELECT;
+ base->flag_legacy &= ~SELECT;
}
- base->object->flag = base->flag;
+ BKE_scene_base_flag_sync_from_base(base);
}
}
/* also to set active NULL */
-void ED_base_object_activate(bContext *C, Base *base)
+void ED_base_object_activate(bContext *C, BaseLegacy *base)
{
Scene *scene = CTX_data_scene(C);
@@ -108,7 +112,12 @@ void ED_base_object_activate(bContext *C, Base *base)
BASACT = base;
if (base) {
-
+#ifdef USE_WORKSPACE_MODE
+ WorkSpace *workspace = CTX_wm_workspace(C);
+
+ BKE_workspace_object_mode_set(workspace, base->object->mode);
+#endif
+
/* XXX old signals, remember to handle notifiers now! */
// select_actionchannel_by_name(base->object->action, "Object", 1);
@@ -118,6 +127,33 @@ void ED_base_object_activate(bContext *C, Base *base)
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, NULL);
}
+void ED_object_base_select(Base *base, short mode)
+{
+ if (base) {
+ if (mode == BA_SELECT) {
+ if ((base->flag & BASE_SELECTABLED) != 0) {
+ base->flag |= BASE_SELECTED;
+ }
+ }
+ else if (mode == BA_DESELECT) {
+ base->flag &= ~BASE_SELECTED;
+ }
+ }
+}
+
+void ED_object_base_activate(bContext *C, Base *base)
+{
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ sl->basact = base;
+
+ if (base) {
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, sl);
+ }
+ else {
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, NULL);
+ }
+}
+
/********************** Selection Operators **********************/
static int objects_selectable_poll(bContext *C)
@@ -146,7 +182,7 @@ static int object_select_by_type_exec(bContext *C, wmOperator *op)
if (extend == 0) {
CTX_DATA_BEGIN (C, Base *, base, visible_bases)
{
- ED_base_object_select(base, BA_DESELECT);
+ ED_object_base_select(base, BA_DESELECT);
}
CTX_DATA_END;
}
@@ -154,7 +190,7 @@ static int object_select_by_type_exec(bContext *C, wmOperator *op)
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;
@@ -209,38 +245,15 @@ static 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_SELECTABLED) != 0)) {
if (base->object->data == obdata) {
- base->flag |= SELECT;
- base->object->flag = base->flag;
-
+ ED_object_base_select(base, BA_SELECT);
changed = true;
}
}
@@ -256,7 +269,7 @@ static bool object_select_all_by_material_texture(bContext *C, int use_texture,
CTX_DATA_BEGIN (C, Base *, base, visible_bases)
{
- if ((base->flag & SELECT) == 0) {
+ if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLED) != 0)) {
Object *ob = base->object;
Material *mat1;
int a, b;
@@ -266,7 +279,7 @@ static bool object_select_all_by_material_texture(bContext *C, int use_texture,
if (!use_texture) {
if (mat1 == mat) {
- base->flag |= SELECT;
+ ED_object_base_select(base, BA_SELECT);
changed = true;
}
}
@@ -274,7 +287,7 @@ static bool object_select_all_by_material_texture(bContext *C, int use_texture,
for (b = 0; b < MAX_MTEX; b++) {
if (mat1->mtex[b]) {
if (tex == mat1->mtex[b]->tex) {
- base->flag |= SELECT;
+ ED_object_base_select(base, BA_SELECT);
changed = true;
break;
}
@@ -282,8 +295,6 @@ static bool object_select_all_by_material_texture(bContext *C, int use_texture,
}
}
}
-
- base->object->flag = base->flag;
}
}
CTX_DATA_END;
@@ -298,12 +309,10 @@ static bool object_select_all_by_dup_group(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_SELECTABLED) != 0)) {
Group *dup_group_other = (base->object->transflag & OB_DUPLIGROUP) ? 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;
}
}
@@ -320,23 +329,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_SELECTABLED) != 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;
@@ -350,11 +357,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_SELECTABLED) != 0)) {
if (lib == base->object->id.lib) {
- base->flag |= SELECT;
- base->object->flag = base->flag;
-
+ ED_object_base_select(base, BA_SELECT);
changed = true;
}
}
@@ -370,11 +375,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_SELECTABLED) != 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;
}
}
@@ -407,6 +410,7 @@ void ED_object_select_linked_by_id(bContext *C, ID *id)
static int object_select_linked_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *ob;
int nr = RNA_enum_get(op->ptr, "type");
bool changed = false, extend;
@@ -416,12 +420,12 @@ static int object_select_linked_exec(bContext *C, wmOperator *op)
if (extend == 0) {
CTX_DATA_BEGIN (C, Base *, base, visible_bases)
{
- ED_base_object_select(base, BA_DESELECT);
+ ED_object_base_select(base, BA_DESELECT);
}
CTX_DATA_END;
}
- ob = OBACT;
+ ob = OBACT_NEW;
if (ob == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active object");
return OPERATOR_CANCELLED;
@@ -516,7 +520,7 @@ enum {
OBJECT_GRPSEL_PARENT = 2,
OBJECT_GRPSEL_SIBLINGS = 3,
OBJECT_GRPSEL_TYPE = 4,
- OBJECT_GRPSEL_LAYER = 5,
+ /*OBJECT_GRPSEL_LAYER = 5,*/
OBJECT_GRPSEL_GROUP = 6,
OBJECT_GRPSEL_HOOK = 7,
OBJECT_GRPSEL_PASS = 8,
@@ -532,7 +536,6 @@ static 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_HOOK, "HOOK", 0, "Hook", ""},
{OBJECT_GRPSEL_PASS, "PASS", 0, "Pass", "Render pass Index"},
@@ -550,13 +553,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;
@@ -565,20 +569,20 @@ 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);
- View3D *v3d = CTX_wm_view3d(C);
-
- bool changed = false;
+ SceneLayer *sl = CTX_data_scene_layer(C);
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_scene_layer_base_find(sl, 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);
+ if (baspar && BASE_SELECTABLE_NEW(baspar)) {
+ ED_object_base_select(baspar, BA_SELECT);
+ ED_object_base_activate(C, baspar);
changed = true;
}
return changed;
@@ -607,9 +611,11 @@ static bool select_grouped_group(bContext *C, Object *ob) /* Select objects in
group = ob_groups[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_SELECTABLED) != 0)) {
+ if (BKE_group_object_exists(group, base->object)) {
+ ED_object_base_select(base, BA_SELECT);
+ changed = true;
+ }
}
}
CTX_DATA_END;
@@ -631,8 +637,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);
- View3D *v3d = CTX_wm_view3d(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
bool changed = false;
Base *base;
@@ -643,8 +648,8 @@ static bool select_grouped_object_hooks(bContext *C, Object *ob)
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))) {
+ base = BKE_scene_layer_base_find(sl, hmd->object);
+ if (base && (BASE_SELECTABLE_NEW(base))) {
ED_base_object_select(base, BA_SELECT);
changed = true;
}
@@ -662,8 +667,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;
}
}
@@ -680,8 +685,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;
}
}
@@ -695,23 +700,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;
}
}
@@ -725,8 +715,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;
}
}
@@ -740,8 +730,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);
+ if (((base->flag & BASE_SELECTED) == 0) && (compare_v3v3(base->object->col, ob->col, 0.005f))) {
+ ED_object_base_select(base, BA_SELECT);
changed = true;
}
}
@@ -767,8 +757,8 @@ static bool select_grouped_gameprops(bContext *C, Object *ob)
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) && (objects_share_gameprop(base->object, ob))) {
+ ED_object_base_select(base, BA_SELECT);
changed = true;
}
}
@@ -806,7 +796,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,
@@ -815,7 +805,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;
}
@@ -830,6 +820,7 @@ 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);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *ob;
const int type = RNA_enum_get(op->ptr, "type");
bool changed = false, extend;
@@ -839,13 +830,13 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op)
if (extend == 0) {
CTX_DATA_BEGIN (C, Base *, base, visible_bases)
{
- ED_base_object_select(base, BA_DESELECT);
+ ED_object_base_select(base, BA_DESELECT);
changed = true;
}
CTX_DATA_END;
}
- ob = OBACT;
+ ob = OBACT_NEW;
if (ob == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active object");
return OPERATOR_CANCELLED;
@@ -867,9 +858,6 @@ 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);
break;
@@ -927,85 +915,6 @@ 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 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)
@@ -1019,7 +928,7 @@ static int object_select_all_exec(bContext *C, wmOperator *op)
action = SEL_SELECT;
CTX_DATA_BEGIN (C, Base *, base, visible_bases)
{
- if (base->flag & SELECT) {
+ if ((base->flag & BASE_SELECTED) != 0) {
action = SEL_DESELECT;
break;
}
@@ -1031,17 +940,17 @@ static int object_select_all_exec(bContext *C, wmOperator *op)
{
switch (action) {
case SEL_SELECT:
- ED_base_object_select(base, BA_SELECT);
+ ED_object_base_select(base, BA_SELECT);
break;
case SEL_DESELECT:
- ED_base_object_select(base, BA_DESELECT);
+ ED_object_base_select(base, BA_DESELECT);
break;
case SEL_INVERT:
- if (base->flag & SELECT) {
- ED_base_object_select(base, BA_DESELECT);
+ if ((base->flag & BASE_SELECTED) != 0) {
+ ED_object_base_select(base, BA_DESELECT);
}
else {
- ED_base_object_select(base, BA_SELECT);
+ ED_object_base_select(base, BA_SELECT);
}
break;
}
@@ -1091,8 +1000,11 @@ static int object_select_same_group_exec(bContext *C, wmOperator *op)
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_SELECTABLED) != 0)) {
+ if (BKE_group_object_exists(group, base->object)) {
+ ED_object_base_select(base, BA_SELECT);
+ }
+ }
}
CTX_DATA_END;
@@ -1123,6 +1035,7 @@ void OBJECT_OT_select_same_group(wmOperatorType *ot)
static int object_select_mirror_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
bool extend;
extend = RNA_boolean_get(op->ptr, "extend");
@@ -1131,20 +1044,20 @@ static int object_select_mirror_exec(bContext *C, wmOperator *op)
{
char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, primbase->object->id.name + 2, true);
+ BLI_string_flip_side_name(name_flip, primbase->object->id.name + 2, true, sizeof(name_flip));
if (!STREQ(name_flip, primbase->object->id.name + 2)) {
Object *ob = (Object *)BKE_libblock_find_name(ID_OB, name_flip);
if (ob) {
- Base *secbase = BKE_scene_base_find(scene, ob);
+ Base *secbase = BKE_scene_layer_base_find(sl, 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;
@@ -1179,9 +1092,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);
+ SceneLayer *sl = CTX_data_scene_layer(C);
- for (Base *base = scene->base.first; base; base = base->next) {
+ for (BaseLegacy *base = sl->object_bases.first; base; base = base->next) {
Object *ob = base->object;
ob->flag &= ~OB_DONE;
ob->id.tag &= ~LIB_TAG_DOIT;
@@ -1222,7 +1135,7 @@ static bool object_select_more_less(bContext *C, const bool select)
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);
+ ED_object_base_select(base, select_mode);
changed = true;
}
}
@@ -1304,7 +1217,7 @@ 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;
diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c
index e04114761e4..b7c0a2679bc 100644
--- a/source/blender/editors/object/object_shapekey.c
+++ b/source/blender/editors/object/object_shapekey.c
@@ -51,7 +51,6 @@
#include "DNA_object_types.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_key.h"
#include "BKE_library.h"
#include "BKE_main.h"
@@ -59,6 +58,9 @@
#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
#include "ED_object.h"
@@ -213,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;
@@ -264,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;
}
@@ -302,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;
@@ -343,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;
@@ -378,7 +380,7 @@ static int shape_key_retime_exec(bContext *C, wmOperator *UNUSED(op))
for (kb = key->block.first; kb; kb = kb->next)
kb->pos = (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;
@@ -469,7 +471,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 4d7d7df0d2f..542b98d771f 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -46,7 +46,6 @@
#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 +58,8 @@
#include "BKE_lattice.h"
#include "BKE_tracking.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_define.h"
#include "RNA_access.h"
@@ -265,7 +266,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;
@@ -371,7 +372,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;
@@ -617,7 +618,7 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l
ignore_parent_tx(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;
}
@@ -644,7 +645,7 @@ static int visual_transform_apply_exec(bContext *C, wmOperator *UNUSED(op))
BKE_object_where_is_calc(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;
}
@@ -784,7 +785,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);
}
}
@@ -898,7 +899,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;
}
@@ -976,7 +977,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;
}
@@ -1034,7 +1035,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
(ob->transflag | ob_other->transflag) & OB_DUPLIGROUP)))
{
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);
@@ -1052,9 +1053,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_mesh_batch_cache_dirty(tob->data, BKE_MESH_BATCH_DIRTY_NOCHECK);
+ 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);
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index ad41fb23a69..51723ac14d3 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -56,9 +56,9 @@
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
#include "BKE_mesh_mapping.h"
#include "BKE_editmesh.h"
+#include "BKE_layer.h"
#include "BKE_modifier.h"
#include "BKE_report.h"
#include "BKE_DerivedMesh.h"
@@ -66,6 +66,8 @@
#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"
@@ -363,8 +365,8 @@ void ED_vgroup_parray_remove_zero(MDeformVert **dvert_array, const int dvert_tot
/* matching index only */
bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
{
- MDeformVert **dvert_array_from, **dvf;
- MDeformVert **dvert_array, **dv;
+ MDeformVert **dvert_array_from = NULL, **dvf;
+ MDeformVert **dvert_array = NULL, **dv;
int dvert_tot_from;
int dvert_tot;
int i;
@@ -375,26 +377,30 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
if (ob == ob_from)
return true;
- ED_vgroup_parray_alloc(ob_from->data, &dvert_array_from, &dvert_tot_from, false);
- ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false);
-
- if ((dvert_array == NULL) && (dvert_array_from != NULL) && BKE_object_defgroup_data_create(ob->data)) {
+ /* in case we copy vgroup between two objects using same data, we only have to care about object side of things. */
+ if (ob->data != ob_from->data) {
+ ED_vgroup_parray_alloc(ob_from->data, &dvert_array_from, &dvert_tot_from, false);
ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false);
- new_vgroup = true;
- }
- if (dvert_tot == 0 || (dvert_tot != dvert_tot_from) || dvert_array_from == NULL || dvert_array == NULL) {
+ if ((dvert_array == NULL) && (dvert_array_from != NULL) && BKE_object_defgroup_data_create(ob->data)) {
+ ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false);
+ new_vgroup = true;
+ }
- if (dvert_array) MEM_freeN(dvert_array);
- if (dvert_array_from) MEM_freeN(dvert_array_from);
+ if (dvert_tot == 0 || (dvert_tot != dvert_tot_from) || dvert_array_from == NULL || dvert_array == NULL) {
+ if (dvert_array)
+ MEM_freeN(dvert_array);
+ if (dvert_array_from)
+ MEM_freeN(dvert_array_from);
- if (new_vgroup == true) {
- /* free the newly added vgroup since it wasn't compatible */
- BKE_object_defgroup_remove_all(ob);
- }
+ if (new_vgroup == true) {
+ /* free the newly added vgroup since it wasn't compatible */
+ BKE_object_defgroup_remove_all(ob);
+ }
- /* if true: both are 0 and nothing needs changing, consider this a success */
- return (dvert_tot == dvert_tot_from);
+ /* if true: both are 0 and nothing needs changing, consider this a success */
+ return (dvert_tot == dvert_tot_from);
+ }
}
/* do the copy */
@@ -412,22 +418,23 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
MEM_freeN(remap);
}
- dvf = dvert_array_from;
- dv = dvert_array;
+ if (dvert_array_from != NULL && dvert_array != NULL) {
+ dvf = dvert_array_from;
+ dv = dvert_array;
- for (i = 0; i < dvert_tot; i++, dvf++, dv++) {
- if ((*dv)->dw)
- MEM_freeN((*dv)->dw);
+ for (i = 0; i < dvert_tot; i++, dvf++, dv++) {
+ MEM_SAFE_FREE((*dv)->dw);
+ *(*dv) = *(*dvf);
- *(*dv) = *(*dvf);
+ if ((*dv)->dw) {
+ (*dv)->dw = MEM_dupallocN((*dv)->dw);
+ }
+ }
- if ((*dv)->dw)
- (*dv)->dw = MEM_dupallocN((*dv)->dw);
+ MEM_freeN(dvert_array);
+ MEM_freeN(dvert_array_from);
}
- MEM_freeN(dvert_array);
- MEM_freeN(dvert_array_from);
-
return true;
}
@@ -886,7 +893,7 @@ static float get_vert_def_nr(Object *ob, const int def_nr, const int vertnum)
const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
/* warning, this lookup is _not_ fast */
- if (cd_dvert_offset != -1) {
+ if (cd_dvert_offset != -1 && vertnum < em->bm->totvert) {
BMVert *eve;
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
eve = BM_vert_at_index(em->bm, vertnum);
@@ -2576,7 +2583,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);
@@ -2604,10 +2611,12 @@ static int vertex_group_remove_exec(bContext *C, wmOperator *op)
if (RNA_boolean_get(op->ptr, "all"))
BKE_object_defgroup_remove_all(ob);
+ else if (RNA_boolean_get(op->ptr, "all_unlocked"))
+ BKE_object_defgroup_remove_all_ex(ob, true);
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);
@@ -2633,6 +2642,7 @@ void OBJECT_OT_vertex_group_remove(wmOperatorType *ot)
/* properties */
RNA_def_boolean(ot->srna, "all", 0, "All", "Remove all vertex groups");
+ RNA_def_boolean(ot->srna, "all_unlocked", 0, "All Unlocked", "Remove all unlocked vertex groups");
}
static int vertex_group_assign_exec(bContext *C, wmOperator *UNUSED(op))
@@ -2641,7 +2651,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;
@@ -2714,7 +2724,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;
@@ -2803,7 +2813,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);
@@ -2839,7 +2849,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);
@@ -2873,7 +2883,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);
@@ -2912,7 +2922,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);
@@ -2967,7 +2977,7 @@ static int vertex_group_fix_exec(bContext *C, wmOperator *op)
}
vgroup_fix(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);
@@ -3039,7 +3049,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);
@@ -3082,7 +3092,7 @@ static int vertex_group_smooth_exec(bContext *C, wmOperator *op)
vgroup_smooth_subset(ob, vgroup_validmap, vgroup_tot, subset_count, fac, repeat, fac_expand, source);
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);
@@ -3132,7 +3142,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);
@@ -3173,7 +3183,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);
@@ -3214,7 +3224,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);
@@ -3259,7 +3269,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);
@@ -3292,25 +3302,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(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;
}
@@ -3340,7 +3351,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++;
}
@@ -3383,7 +3394,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;
@@ -3597,7 +3608,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);
}
@@ -3633,7 +3644,8 @@ static int vgroup_move_exec(bContext *C, wmOperator *op)
Object *ob = ED_object_context(C);
bDeformGroup *def;
char *name_array;
- int dir = RNA_enum_get(op->ptr, "direction"), ret;
+ int dir = RNA_enum_get(op->ptr, "direction");
+ int ret = OPERATOR_FINISHED;
def = BLI_findlink(&ob->defbase, ob->actdef - 1);
if (!def) {
@@ -3642,36 +3654,25 @@ static int vgroup_move_exec(bContext *C, wmOperator *op)
name_array = vgroup_init_remap(ob);
- if (dir == 1) { /*up*/
- void *prev = def->prev;
+ if (BLI_listbase_link_move(&ob->defbase, def, dir)) {
+ ret = vgroup_do_remap(ob, name_array, op);
- BLI_remlink(&ob->defbase, def);
- BLI_insertlinkbefore(&ob->defbase, prev, def);
- }
- else { /*down*/
- void *next = def->next;
-
- BLI_remlink(&ob->defbase, def);
- BLI_insertlinkafter(&ob->defbase, next, def);
+ if (ret != OPERATOR_CANCELLED) {
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob);
+ }
}
- ret = vgroup_do_remap(ob, name_array, op);
-
if (name_array) MEM_freeN(name_array);
- if (ret != OPERATOR_CANCELLED) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob);
- }
-
return ret;
}
void OBJECT_OT_vertex_group_move(wmOperatorType *ot)
{
static EnumPropertyItem vgroup_slot_move[] = {
- {1, "UP", 0, "Up", ""},
- {-1, "DOWN", 0, "Down", ""},
+ {-1, "UP", 0, "Up", ""},
+ {1, "DOWN", 0, "Down", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -3687,7 +3688,8 @@ void OBJECT_OT_vertex_group_move(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_enum(ot->srna, "direction", vgroup_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
+ RNA_def_enum(ot->srna, "direction", vgroup_slot_move, 0, "Direction",
+ "Direction to move the active vertex group towards");
}
static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr)
@@ -3785,7 +3787,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;
@@ -3822,7 +3824,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;
@@ -3855,7 +3857,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);
}
@@ -3892,7 +3894,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;
@@ -3925,7 +3927,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 9f4da87903d..92b82e2a31b 100644
--- a/source/blender/editors/object/object_warp.c
+++ b/source/blender/editors/object/object_warp.c
@@ -53,8 +53,7 @@ static void object_warp_calc_view_matrix(float r_mat_view[4][4], float r_center_
float viewmat_roll[4][4];
/* apply the rotation offset by rolling the view */
- unit_m4(mat_offset);
- rotate_m4(mat_offset, 'Z', offset_angle);
+ axis_angle_to_mat4_single(mat_offset, 'Z', offset_angle);
mul_m4_m4m4(viewmat_roll, mat_offset, viewmat);
/* apply the view and the object matrix */
diff --git a/source/blender/editors/physics/CMakeLists.txt b/source/blender/editors/physics/CMakeLists.txt
index 898422dac51..3cecdccd758 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 3d7a45843cc..cd07b57577b 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"
@@ -135,7 +137,7 @@ static int surface_slot_remove_exec(bContext *C, wmOperator *UNUSED(op))
}
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;
@@ -279,13 +281,14 @@ void DPAINT_OT_output_toggle(wmOperatorType *ot)
/***************************** Image Sequence Baking ******************************/
typedef struct DynamicPaintBakeJob {
- /* from wmJob */
- void *owner;
- short *stop, *do_update;
- float *progress;
+ /* from wmJob */
+ void *owner;
+ short *stop, *do_update;
+ float *progress;
struct Main *bmain;
Scene *scene;
+ SceneLayer *scene_layer;
Object *ob;
DynamicPaintSurface *surface;
@@ -297,13 +300,13 @@ typedef struct DynamicPaintBakeJob {
static void dpaint_bake_free(void *customdata)
{
- DynamicPaintBakeJob *job = customdata;
- MEM_freeN(job);
+ DynamicPaintBakeJob *job = customdata;
+ MEM_freeN(job);
}
static void dpaint_bake_endjob(void *customdata)
{
- DynamicPaintBakeJob *job = customdata;
+ DynamicPaintBakeJob *job = customdata;
DynamicPaintCanvasSettings *canvas = job->canvas;
canvas->flags &= ~MOD_DPAINT_BAKING;
@@ -311,7 +314,7 @@ static void dpaint_bake_endjob(void *customdata)
dynamicPaint_freeSurfaceData(job->surface);
G.is_rendering = false;
- BKE_spacedata_draw_locks(false);
+ BKE_spacedata_draw_locks(false);
WM_set_locked_interface(G.main->wm.first, false);
@@ -384,7 +387,7 @@ 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(surface, scene, cObject, frame)) {
+ if (!dynamicPaint_calculateFrame(surface, scene, job->scene_layer, cObject, frame)) {
job->success = 0;
return;
}
@@ -421,26 +424,26 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job)
static void dpaint_bake_startjob(void *customdata, short *stop, short *do_update, float *progress)
{
- DynamicPaintBakeJob *job = customdata;
+ DynamicPaintBakeJob *job = customdata;
- job->stop = stop;
- job->do_update = do_update;
- job->progress = progress;
+ job->stop = stop;
+ job->do_update = do_update;
+ job->progress = progress;
job->start = PIL_check_seconds_timer();
job->success = 1;
- G.is_break = false; /* reset BKE_blender_test_break*/
+ G.is_break = false; /* reset BKE_blender_test_break*/
/* XXX annoying hack: needed to prevent data corruption when changing
* scene frame in separate threads
- */
- G.is_rendering = true;
- BKE_spacedata_draw_locks(true);
+ */
+ G.is_rendering = true;
+ BKE_spacedata_draw_locks(true);
dynamicPaint_bakeImageSequence(job);
- *do_update = true;
- *stop = 0;
+ *do_update = true;
+ *stop = 0;
}
/*
@@ -452,6 +455,7 @@ static int dynamicpaint_bake_exec(struct bContext *C, struct wmOperator *op)
DynamicPaintCanvasSettings *canvas;
Object *ob = ED_object_context(C);
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
DynamicPaintSurface *surface;
@@ -479,6 +483,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->scene_layer = sl;
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 14b12497c4a..681ac75e847 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 e22a145b3a6..fb3cfdc86b2 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -53,7 +53,6 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
#include "BKE_object.h"
@@ -64,8 +63,9 @@
#include "BKE_bvhutils.h"
#include "BKE_pointcache.h"
+#include "DEG_depsgraph.h"
+
#include "BIF_gl.h"
-#include "BIF_glutil.h"
#include "ED_object.h"
#include "ED_physics.h"
@@ -73,6 +73,9 @@
#include "ED_particle.h"
#include "ED_view3d.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+
#include "UI_resources.h"
#include "WM_api.h"
@@ -83,7 +86,7 @@
#include "physics_intern.h"
-void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys);
+void PE_create_particle_edit(Scene *scene, SceneLayer *sl, Object *ob, PointCache *cache, ParticleSystem *psys);
void PTCacheUndo_clear(PTCacheEdit *edit);
void recalc_lengths(PTCacheEdit *edit);
void recalc_emitter_field(Object *ob, ParticleSystem *psys);
@@ -109,24 +112,26 @@ void update_world_cos(Object *ob, PTCacheEdit *edit);
int PE_poll(bContext *C)
{
Scene *scene= CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *ob= CTX_data_active_object(C);
- if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT))
+ if (!scene || !sl || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT))
return 0;
- return (PE_get_current(scene, ob) != NULL);
+ return (PE_get_current(scene, sl, ob) != NULL);
}
int PE_hair_poll(bContext *C)
{
Scene *scene= CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *ob= CTX_data_active_object(C);
PTCacheEdit *edit;
if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT))
return 0;
- edit= PE_get_current(scene, ob);
+ edit= PE_get_current(scene, sl, ob);
return (edit && edit->psys);
}
@@ -211,7 +216,7 @@ static float pe_brush_size_get(const Scene *UNUSED(scene), ParticleBrushData *br
*
* note: this function runs on poll, therefor it can runs many times a second
* keep it fast! */
-static PTCacheEdit *pe_get_current(Scene *scene, Object *ob, int create)
+static PTCacheEdit *pe_get_current(Scene *scene, SceneLayer *sl, Object *ob, int create)
{
ParticleEditSettings *pset= PE_settings(scene);
PTCacheEdit *edit = NULL;
@@ -222,6 +227,7 @@ static PTCacheEdit *pe_get_current(Scene *scene, Object *ob, int create)
return NULL;
pset->scene = scene;
+ pset->scene_layer = sl;
pset->object = ob;
BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
@@ -250,18 +256,18 @@ static PTCacheEdit *pe_get_current(Scene *scene, Object *ob, int create)
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(scene, ob, pid->cache, NULL);
+ PE_create_particle_edit(scene, sl, ob, pid->cache, NULL);
edit = pid->cache->edit;
}
else {
if (create && !psys->edit && psys->flag & PSYS_HAIR_DONE)
- PE_create_particle_edit(scene, ob, NULL, psys);
+ PE_create_particle_edit(scene, sl, ob, NULL, psys);
edit = psys->edit;
}
}
else {
if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit)
- PE_create_particle_edit(scene, ob, pid->cache, psys);
+ PE_create_particle_edit(scene, sl, ob, pid->cache, psys);
edit = pid->cache->edit;
}
@@ -272,7 +278,7 @@ static PTCacheEdit *pe_get_current(Scene *scene, Object *ob, int create)
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(scene, ob, pid->cache, NULL);
+ PE_create_particle_edit(scene, sl, ob, pid->cache, NULL);
}
edit = pid->cache->edit;
break;
@@ -281,7 +287,7 @@ static PTCacheEdit *pe_get_current(Scene *scene, Object *ob, int create)
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(scene, ob, pid->cache, NULL);
+ PE_create_particle_edit(scene, sl, ob, pid->cache, NULL);
}
edit = pid->cache->edit;
break;
@@ -296,14 +302,14 @@ static PTCacheEdit *pe_get_current(Scene *scene, Object *ob, int create)
return edit;
}
-PTCacheEdit *PE_get_current(Scene *scene, Object *ob)
+PTCacheEdit *PE_get_current(Scene *scene, SceneLayer *sl, Object *ob)
{
- return pe_get_current(scene, ob, 0);
+ return pe_get_current(scene, sl, ob, 0);
}
PTCacheEdit *PE_create_current(Scene *scene, Object *ob)
{
- return pe_get_current(scene, ob, 1);
+ return pe_get_current(scene, NULL, ob, 1);
}
void PE_current_changed(Scene *scene, Object *ob)
@@ -351,9 +357,9 @@ static int pe_x_mirror(Object *ob)
typedef struct PEData {
ViewContext vc;
- bglMats mats;
Scene *scene;
+ SceneLayer *scene_layer;
Object *ob;
DerivedMesh *dm;
PTCacheEdit *edit;
@@ -388,8 +394,9 @@ static void PE_set_data(bContext *C, PEData *data)
memset(data, 0, sizeof(*data));
data->scene= CTX_data_scene(C);
+ data->scene_layer = CTX_data_scene_layer(C);
data->ob= CTX_data_active_object(C);
- data->edit= PE_get_current(data->scene, data->ob);
+ data->edit= PE_get_current(data->scene, data->scene_layer, data->ob);
}
static void PE_set_view3d_data(bContext *C, PEData *data)
@@ -397,8 +404,6 @@ static void PE_set_view3d_data(bContext *C, PEData *data)
PE_set_data(C, data);
view3d_set_viewcontext(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) {
@@ -439,7 +444,6 @@ static bool key_test_depth(PEData *data, const float co[3], const int screen_co[
{
View3D *v3d= data->vc.v3d;
ViewDepths *vd = data->vc.rv3d->depths;
- double ux, uy, uz;
float depth;
/* nothing to do */
@@ -455,9 +459,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);
@@ -467,7 +468,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;
@@ -1152,9 +1156,9 @@ void recalc_emitter_field(Object *ob, ParticleSystem *psys)
BLI_kdtree_balance(edit->emitter_field);
}
-static void PE_update_selection(Scene *scene, Object *ob, int useflag)
+static void PE_update_selection(Scene *scene, SceneLayer *sl, Object *ob, int useflag)
{
- PTCacheEdit *edit= PE_get_current(scene, ob);
+ PTCacheEdit *edit= PE_get_current(scene, sl, ob);
HairKey *hkey;
POINT_P; KEY_K;
@@ -1259,12 +1263,12 @@ static void update_velocities(PTCacheEdit *edit)
}
}
-void PE_update_object(Scene *scene, Object *ob, int useflag)
+void PE_update_object(Scene *scene, SceneLayer *sl, 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(scene, ob);
+ PTCacheEdit *edit = PE_get_current(scene, sl, ob);
POINT_P;
if (!edit)
@@ -1399,8 +1403,9 @@ static void select_action_apply(PTCacheEditPoint *point, PTCacheEditKey *key, in
static int pe_select_all_exec(bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *ob= CTX_data_active_object(C);
- PTCacheEdit *edit= PE_get_current(scene, ob);
+ PTCacheEdit *edit= PE_get_current(scene, sl, ob);
POINT_P; KEY_K;
int action = RNA_enum_get(op->ptr, "action");
@@ -1423,7 +1428,7 @@ static int pe_select_all_exec(bContext *C, wmOperator *op)
}
}
- PE_update_selection(scene, ob, 1);
+ PE_update_selection(scene, sl, ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
return OPERATOR_FINISHED;
@@ -1452,8 +1457,9 @@ int PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool deselec
{
PEData data;
Scene *scene= CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *ob= CTX_data_active_object(C);
- PTCacheEdit *edit= PE_get_current(scene, ob);
+ PTCacheEdit *edit= PE_get_current(scene, sl, ob);
POINT_P; KEY_K;
if (!PE_start_edit(edit))
@@ -1480,7 +1486,7 @@ int PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool deselec
else
for_mouse_hit_keys(&data, toggle_key_select, 1);
- PE_update_selection(scene, ob, 1);
+ PE_update_selection(scene, sl, ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
return OPERATOR_FINISHED;
@@ -1521,7 +1527,7 @@ static int select_roots_exec(bContext *C, wmOperator *op)
data.select_action = action;
foreach_point(&data, select_root);
- PE_update_selection(data.scene, data.ob, 1);
+ PE_update_selection(data.scene, data.scene_layer, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
return OPERATOR_FINISHED;
@@ -1586,7 +1592,7 @@ static int select_tips_exec(bContext *C, wmOperator *op)
data.select_action = action;
foreach_point(&data, select_tip);
- PE_update_selection(data.scene, data.ob, 1);
+ PE_update_selection(data.scene, data.scene_layer, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
return OPERATOR_FINISHED;
@@ -1625,6 +1631,7 @@ static int select_random_exec(bContext *C, wmOperator *op)
PEData data;
int type;
Scene *scene;
+ SceneLayer *sl;
Object *ob;
/* used by LOOP_VISIBLE_POINTS, LOOP_VISIBLE_KEYS and LOOP_KEYS */
@@ -1644,8 +1651,9 @@ static int select_random_exec(bContext *C, wmOperator *op)
PE_set_data(C, &data);
data.select_action = SEL_SELECT;
scene = CTX_data_scene(C);
+ sl = CTX_data_scene_layer(C);
ob = CTX_data_active_object(C);
- edit = PE_get_current(scene, ob);
+ edit = PE_get_current(scene, sl, ob);
rng = BLI_rng_new_srandom(seed);
@@ -1670,7 +1678,7 @@ static int select_random_exec(bContext *C, wmOperator *op)
BLI_rng_free(rng);
- PE_update_selection(data.scene, data.ob, 1);
+ PE_update_selection(data.scene, data.scene_layer, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
return OPERATOR_FINISHED;
@@ -1714,7 +1722,7 @@ static int select_linked_exec(bContext *C, wmOperator *op)
data.select= !RNA_boolean_get(op->ptr, "deselect");
for_mouse_hit_keys(&data, select_keys, 1); /* nearest only */
- PE_update_selection(data.scene, data.ob, 1);
+ PE_update_selection(data.scene, data.scene_layer, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
return OPERATOR_FINISHED;
@@ -1762,8 +1770,9 @@ void PE_deselect_all_visible(PTCacheEdit *edit)
int PE_border_select(bContext *C, rcti *rect, bool select, bool extend)
{
Scene *scene= CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *ob= CTX_data_active_object(C);
- PTCacheEdit *edit= PE_get_current(scene, ob);
+ PTCacheEdit *edit= PE_get_current(scene, sl, ob);
PEData data;
if (!PE_start_edit(edit))
@@ -1778,7 +1787,7 @@ int PE_border_select(bContext *C, rcti *rect, bool select, bool extend)
for_mouse_hit_keys(&data, select_key, 0);
- PE_update_selection(scene, ob, 1);
+ PE_update_selection(scene, sl, ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
return OPERATOR_FINISHED;
@@ -1789,8 +1798,9 @@ int PE_border_select(bContext *C, rcti *rect, bool select, bool extend)
int PE_circle_select(bContext *C, int selecting, const int mval[2], float rad)
{
Scene *scene= CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *ob= CTX_data_active_object(C);
- PTCacheEdit *edit= PE_get_current(scene, ob);
+ PTCacheEdit *edit= PE_get_current(scene, sl, ob);
PEData data;
if (!PE_start_edit(edit))
@@ -1803,7 +1813,7 @@ int PE_circle_select(bContext *C, int selecting, const int mval[2], float rad)
for_mouse_hit_keys(&data, select_key, 0);
- PE_update_selection(scene, ob, 1);
+ PE_update_selection(scene, sl, ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
return OPERATOR_FINISHED;
@@ -1814,10 +1824,11 @@ int PE_circle_select(bContext *C, int selecting, const int mval[2], float rad)
int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, bool extend, bool select)
{
Scene *scene= CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *ob= CTX_data_active_object(C);
ARegion *ar= CTX_wm_region(C);
ParticleEditSettings *pset= PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(scene, sl, ob);
ParticleSystem *psys = edit->psys;
ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
POINT_P; KEY_K;
@@ -1891,7 +1902,7 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, bool
}
}
- PE_update_selection(scene, ob, 1);
+ PE_update_selection(scene, sl, ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
return OPERATOR_FINISHED;
@@ -1903,7 +1914,8 @@ static int hide_exec(bContext *C, wmOperator *op)
{
Object *ob= CTX_data_active_object(C);
Scene *scene= CTX_data_scene(C);
- PTCacheEdit *edit= PE_get_current(scene, ob);
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ PTCacheEdit *edit= PE_get_current(scene, sl, ob);
POINT_P; KEY_K;
if (RNA_enum_get(op->ptr, "unselected")) {
@@ -1925,7 +1937,7 @@ static int hide_exec(bContext *C, wmOperator *op)
}
}
- PE_update_selection(scene, ob, 1);
+ PE_update_selection(scene, sl, ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
return OPERATOR_FINISHED;
@@ -1955,7 +1967,8 @@ static int reveal_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob= CTX_data_active_object(C);
Scene *scene= CTX_data_scene(C);
- PTCacheEdit *edit= PE_get_current(scene, ob);
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ PTCacheEdit *edit= PE_get_current(scene, sl, ob);
POINT_P; KEY_K;
LOOP_POINTS {
@@ -1968,7 +1981,7 @@ static int reveal_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- PE_update_selection(scene, ob, 1);
+ PE_update_selection(scene, sl, ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
return OPERATOR_FINISHED;
@@ -2027,7 +2040,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.scene, data.ob, 1);
+ PE_update_selection(data.scene, data.scene_layer, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
return OPERATOR_FINISHED;
@@ -2089,7 +2102,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.scene, data.ob, 1);
+ PE_update_selection(data.scene, data.scene_layer, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
return OPERATOR_FINISHED;
@@ -2186,7 +2199,7 @@ static int rekey_exec(bContext *C, wmOperator *op)
foreach_selected_point(&data, rekey_particle);
recalc_lengths(data.edit);
- PE_update_object(data.scene, data.ob, 1);
+ PE_update_object(data.scene, data.scene_layer, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob);
return OPERATOR_FINISHED;
@@ -2211,9 +2224,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(Scene *scene, Object *ob, int pa_index, float path_time)
+static void rekey_particle_to_time(Scene *scene, SceneLayer *sl, Object *ob, int pa_index, float path_time)
{
- PTCacheEdit *edit= PE_get_current(scene, ob);
+ PTCacheEdit *edit= PE_get_current(scene, sl, ob);
ParticleSystem *psys;
ParticleSimulationData sim= {0};
ParticleData *pa;
@@ -2517,7 +2530,7 @@ static int subdivide_exec(bContext *C, wmOperator *UNUSED(op))
foreach_point(&data, subdivide_particle);
recalc_lengths(data.edit);
- PE_update_object(data.scene, data.ob, 1);
+ PE_update_object(data.scene, data.scene_layer, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob);
return OPERATOR_FINISHED;
@@ -2543,8 +2556,9 @@ void PARTICLE_OT_subdivide(wmOperatorType *ot)
static int remove_doubles_exec(bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *ob= CTX_data_active_object(C);
- PTCacheEdit *edit= PE_get_current(scene, ob);
+ PTCacheEdit *edit= PE_get_current(scene, sl, ob);
ParticleSystem *psys = edit->psys;
ParticleSystemModifierData *psmd;
KDTree *tree;
@@ -2606,7 +2620,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;
@@ -2635,9 +2649,10 @@ void PARTICLE_OT_remove_doubles(wmOperatorType *ot)
static int weight_set_exec(bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
ParticleEditSettings *pset= PE_settings(scene);
Object *ob= CTX_data_active_object(C);
- PTCacheEdit *edit= PE_get_current(scene, ob);
+ PTCacheEdit *edit= PE_get_current(scene, sl, ob);
ParticleSystem *psys = edit->psys;
POINT_P;
KEY_K;
@@ -2658,7 +2673,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;
@@ -2690,24 +2705,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];
+ brush = &pset->brush[pset->brushtype];
if (brush) {
- glPushMatrix();
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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);
+
+ imm_draw_circle_wire(pos, (float)x, (float)y, pe_brush_size_get(scene, brush), 40);
+
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
-
- glPopMatrix();
+
+ immUnbindProgram();
}
}
@@ -2764,7 +2782,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;
@@ -2791,11 +2809,11 @@ void PARTICLE_OT_delete(wmOperatorType *ot)
/*************************** mirror operator **************************/
-static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
+static void PE_mirror_x(Scene *scene, SceneLayer *sl, Object *ob, int tagged)
{
Mesh *me= (Mesh *)(ob->data);
ParticleSystemModifierData *psmd;
- PTCacheEdit *edit= PE_get_current(scene, ob);
+ PTCacheEdit *edit= PE_get_current(scene, sl, ob);
ParticleSystem *psys = edit->psys;
ParticleData *pa, *newpa, *new_pars;
PTCacheEditPoint *newpoint, *new_points;
@@ -2942,14 +2960,15 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
static int mirror_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene= CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *ob= CTX_data_active_object(C);
- PTCacheEdit *edit= PE_get_current(scene, ob);
+ PTCacheEdit *edit= PE_get_current(scene, sl, ob);
- PE_mirror_x(scene, ob, 0);
+ PE_mirror_x(scene, sl, ob, 0);
update_world_cos(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;
}
@@ -3082,7 +3101,7 @@ static void brush_cut(PEData *data, int pa_index)
edit->points[pa_index].flag |= PEP_TAG;
}
else {
- rekey_particle_to_time(data->scene, ob, pa_index, cut_time);
+ rekey_particle_to_time(data->scene, data->scene_layer, ob, pa_index, cut_time);
edit->points[pa_index].flag |= PEP_EDIT_RECALC;
}
}
@@ -3711,6 +3730,7 @@ static int brush_add(PEData *data, short number)
typedef struct BrushEdit {
Scene *scene;
+ SceneLayer *sl;
Object *ob;
PTCacheEdit *edit;
@@ -3725,9 +3745,10 @@ typedef struct BrushEdit {
static int brush_edit_init(bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *ob= CTX_data_active_object(C);
ParticleEditSettings *pset= PE_settings(scene);
- PTCacheEdit *edit= PE_get_current(scene, ob);
+ PTCacheEdit *edit= PE_get_current(scene, sl, ob);
ARegion *ar= CTX_wm_region(C);
BrushEdit *bedit;
float min[3], max[3];
@@ -3737,7 +3758,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(scene, min, max);
+ PE_minmax(scene, sl, min, max);
mid_v3_v3v3(min, min, max);
bedit= MEM_callocN(sizeof(BrushEdit), "BrushEdit");
@@ -3745,6 +3766,7 @@ static int brush_edit_init(bContext *C, wmOperator *op)
op->customdata= bedit;
bedit->scene= scene;
+ bedit->sl = sl;
bedit->ob= ob;
bedit->edit= edit;
@@ -3760,6 +3782,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
{
BrushEdit *bedit= op->customdata;
Scene *scene= bedit->scene;
+ SceneLayer *sl = bedit->sl;
Object *ob= bedit->ob;
PTCacheEdit *edit= bedit->edit;
ParticleEditSettings *pset= PE_settings(scene);
@@ -3950,21 +3973,21 @@ 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(scene, ob, 1);
+ PE_mirror_x(scene, sl, ob, 1);
update_world_cos(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(scene, ob, 1);
+ PE_update_object(scene, sl, 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);
}
@@ -4170,7 +4193,7 @@ static void shape_cut(PEData *data, int pa_index)
edit->points[pa_index].flag |= PEP_TAG;
}
else {
- rekey_particle_to_time(data->scene, ob, pa_index, cut_time);
+ rekey_particle_to_time(data->scene, data->scene_layer, ob, pa_index, cut_time);
edit->points[pa_index].flag |= PEP_EDIT_RECALC;
}
}
@@ -4179,9 +4202,10 @@ static void shape_cut(PEData *data, int pa_index)
static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *ob = CTX_data_active_object(C);
ParticleEditSettings *pset = PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(scene, sl, ob);
Object *shapeob = pset->shape_object;
int selected = count_selected_keys(scene, edit);
int lock_root = pset->flag & PE_LOCK_FIRST;
@@ -4214,16 +4238,16 @@ static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op))
if (removed) {
update_world_cos(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(scene, ob, 1);
+ PE_update_object(scene, sl, 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);
}
@@ -4389,9 +4413,9 @@ static void get_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
}
}
-void PE_undo_push(Scene *scene, const char *str)
+void PE_undo_push(Scene *scene, SceneLayer *sl, const char *str)
{
- PTCacheEdit *edit= PE_get_current(scene, OBACT);
+ PTCacheEdit *edit= PE_get_current(scene, sl, OBACT_NEW);
PTCacheUndo *undo;
int nr;
@@ -4419,7 +4443,7 @@ void PE_undo_push(Scene *scene, const char *str)
undo= undo->prev;
}
if (undo) {
- while (edit->undo.first!=undo) {
+ while (edit->undo.first != undo) {
PTCacheUndo *first= edit->undo.first;
BLI_remlink(&edit->undo, first);
free_PTCacheUndo(first);
@@ -4431,9 +4455,9 @@ void PE_undo_push(Scene *scene, const char *str)
make_PTCacheUndo(edit, edit->curundo);
}
-void PE_undo_step(Scene *scene, int step)
+void PE_undo_step(Scene *scene, SceneLayer *sl, int step)
{
- PTCacheEdit *edit= PE_get_current(scene, OBACT);
+ PTCacheEdit *edit= PE_get_current(scene, sl, OBACT_NEW);
if (!edit) return;
@@ -4464,12 +4488,12 @@ void PE_undo_step(Scene *scene, int step)
}
}
- DAG_id_tag_update(&OBACT->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&OBACT_NEW->id, OB_RECALC_DATA);
}
-bool PE_undo_is_valid(Scene *scene)
+bool PE_undo_is_valid(Scene *scene, SceneLayer *sl)
{
- PTCacheEdit *edit= PE_get_current(scene, OBACT);
+ PTCacheEdit *edit= PE_get_current(scene, sl, OBACT_NEW);
if (edit) {
return (edit->undo.last != edit->undo.first);
@@ -4492,19 +4516,19 @@ void PTCacheUndo_clear(PTCacheEdit *edit)
edit->curundo= NULL;
}
-void PE_undo(Scene *scene)
+void PE_undo(Scene *scene, SceneLayer *sl)
{
- PE_undo_step(scene, 1);
+ PE_undo_step(scene, sl, 1);
}
-void PE_redo(Scene *scene)
+void PE_redo(Scene *scene, SceneLayer *sl)
{
- PE_undo_step(scene, -1);
+ PE_undo_step(scene, sl, -1);
}
-void PE_undo_number(Scene *scene, int nr)
+void PE_undo_number(Scene *scene, SceneLayer *sl, int nr)
{
- PTCacheEdit *edit= PE_get_current(scene, OBACT);
+ PTCacheEdit *edit= PE_get_current(scene, sl, OBACT_NEW);
PTCacheUndo *undo;
int a=0;
@@ -4512,15 +4536,15 @@ void PE_undo_number(Scene *scene, int nr)
if (a==nr) break;
}
edit->curundo= undo;
- PE_undo_step(scene, 0);
+ PE_undo_step(scene, sl, 0);
}
/* get name of undo item, return null if no item with this index */
/* if active pointer, set it to 1 if true */
-const char *PE_undo_get_name(Scene *scene, int nr, bool *r_active)
+const char *PE_undo_get_name(Scene *scene, SceneLayer *sl, int nr, bool *r_active)
{
- PTCacheEdit *edit= PE_get_current(scene, OBACT);
+ PTCacheEdit *edit= PE_get_current(scene, sl, OBACT_NEW);
PTCacheUndo *undo;
if (r_active) *r_active = false;
@@ -4539,10 +4563,10 @@ const char *PE_undo_get_name(Scene *scene, int nr, bool *r_active)
/************************ utilities ******************************/
-int PE_minmax(Scene *scene, float min[3], float max[3])
+int PE_minmax(Scene *scene, SceneLayer *sl, float min[3], float max[3])
{
- Object *ob= OBACT;
- PTCacheEdit *edit= PE_get_current(scene, ob);
+ Object *ob= OBACT_NEW;
+ PTCacheEdit *edit= PE_get_current(scene, sl, ob);
ParticleSystem *psys;
ParticleSystemModifierData *psmd = NULL;
POINT_P; KEY_K;
@@ -4579,7 +4603,7 @@ int PE_minmax(Scene *scene, float min[3], float max[3])
/************************ particle edit toggle operator ************************/
/* initialize needed data for bake edit */
-void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys)
+void PE_create_particle_edit(Scene *scene, SceneLayer *sl, Object *ob, PointCache *cache, ParticleSystem *psys)
{
PTCacheEdit *edit;
ParticleSystemModifierData *psmd = (psys) ? psys_get_modifier(ob, psys) : NULL;
@@ -4680,10 +4704,10 @@ void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, Partic
recalc_lengths(edit);
if (psys && !cache)
recalc_emitter_field(ob, psys);
- PE_update_object(scene, ob, 1);
+ PE_update_object(scene, sl, ob, 1);
PTCacheUndo_clear(edit);
- PE_undo_push(scene, "Original");
+ PE_undo_push(scene, sl, "Original");
}
}
@@ -4710,6 +4734,9 @@ static int particle_edit_toggle_exec(bContext *C, wmOperator *op)
const int mode_flag = OB_MODE_PARTICLE_EDIT;
const bool is_mode_set = (ob->mode & mode_flag) != 0;
+ BKE_report(op->reports, RPT_INFO, "Particles are changing, editing is not possible");
+ return OPERATOR_CANCELLED;
+
if (!is_mode_set) {
if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
return OPERATOR_CANCELLED;
@@ -4735,7 +4762,7 @@ 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);
return OPERATOR_FINISHED;
}
@@ -4776,7 +4803,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 */
@@ -4784,7 +4811,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;
@@ -4887,19 +4914,20 @@ static int unify_length_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = CTX_data_active_object(C);
Scene *scene = CTX_data_scene(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ PTCacheEdit *edit = PE_get_current(scene, sl, 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(scene, ob, 1);
+ PE_update_object(scene, sl, 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_object.c b/source/blender/editors/physics/particle_object.c
index 0dd00df6182..cd7bb8640b5 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -43,7 +43,6 @@
#include "BLI_string.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_global.h"
@@ -55,6 +54,9 @@
#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"
@@ -69,7 +71,7 @@
#include "physics_intern.h"
-extern void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys);
+extern void PE_create_particle_edit(Scene *scene, SceneLayer *sl, Object *ob, PointCache *cache, ParticleSystem *psys);
extern void PTCacheUndo_clear(PTCacheEdit *edit);
extern void recalc_lengths(PTCacheEdit *edit);
extern void recalc_emitter_field(Object *ob, ParticleSystem *psys);
@@ -133,6 +135,7 @@ static int particle_system_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = ED_object_context(C);
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
int mode_orig;
if (!scene || !ob)
@@ -146,7 +149,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 (sl->basact && sl->basact->object == ob) {
WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, NULL);
}
}
@@ -208,8 +211,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);
@@ -256,8 +259,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);
@@ -304,8 +307,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);
@@ -344,7 +347,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;
}
@@ -382,7 +385,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;
}
@@ -565,7 +568,7 @@ void PARTICLE_OT_dupliob_move_down(wmOperatorType *ot)
/************************ connect/disconnect hair operators *********************/
-static void disconnect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
+static void disconnect_hair(Scene *scene, SceneLayer *sl, Object *ob, ParticleSystem *psys)
{
ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
ParticleEditSettings *pset= PE_settings(scene);
@@ -611,12 +614,13 @@ static void disconnect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
if (ELEM(pset->brushtype, PE_BRUSH_ADD, PE_BRUSH_PUFF))
pset->brushtype = PE_BRUSH_NONE;
- PE_update_object(scene, ob, 0);
+ PE_update_object(scene, sl, ob, 0);
}
static int disconnect_hair_exec(bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *ob= ED_object_context(C);
ParticleSystem *psys= NULL;
const bool all = RNA_boolean_get(op->ptr, "all");
@@ -626,15 +630,15 @@ static int disconnect_hair_exec(bContext *C, wmOperator *op)
if (all) {
for (psys=ob->particlesystem.first; psys; psys=psys->next) {
- disconnect_hair(scene, ob, psys);
+ disconnect_hair(scene, sl, ob, psys);
}
}
else {
psys = psys_get_current(ob);
- disconnect_hair(scene, ob, psys);
+ disconnect_hair(scene, sl, 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;
@@ -657,7 +661,7 @@ 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(Scene *scene, Object *ob, ParticleSystem *psys,
+static bool remap_hair_emitter(Scene *scene, SceneLayer *sl, 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)
{
@@ -697,6 +701,9 @@ static bool remap_hair_emitter(Scene *scene, Object *ob, ParticleSystem *psys,
dm = target_psmd->dm_deformed;
}
target_dm = target_psmd->dm_final;
+ if (dm == NULL) {
+ return false;
+ }
/* don't modify the original vertices */
dm = CDDM_copy(dm);
@@ -840,19 +847,19 @@ static bool remap_hair_emitter(Scene *scene, Object *ob, ParticleSystem *psys,
psys_free_path_cache(target_psys, target_edit);
- PE_update_object(scene, target_ob, 0);
+ PE_update_object(scene, sl, target_ob, 0);
return true;
}
-static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
+static bool connect_hair(Scene *scene, SceneLayer *sl, Object *ob, ParticleSystem *psys)
{
bool ok;
if (!psys)
return false;
- ok = remap_hair_emitter(scene, ob, psys, ob, psys, psys->edit, ob->obmat, ob->obmat, psys->flag & PSYS_GLOBAL_HAIR, false);
+ ok = remap_hair_emitter(scene, sl, ob, psys, ob, psys, psys->edit, ob->obmat, ob->obmat, psys->flag & PSYS_GLOBAL_HAIR, false);
psys->flag &= ~PSYS_GLOBAL_HAIR;
return ok;
@@ -861,6 +868,7 @@ static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
static int connect_hair_exec(bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *ob= ED_object_context(C);
ParticleSystem *psys= NULL;
const bool all = RNA_boolean_get(op->ptr, "all");
@@ -871,12 +879,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(scene, ob, psys);
+ any_connected |= connect_hair(scene, sl, ob, psys);
}
}
else {
psys = psys_get_current(ob);
- any_connected |= connect_hair(scene, ob, psys);
+ any_connected |= connect_hair(scene, sl, ob, psys);
}
if (!any_connected) {
@@ -885,7 +893,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;
@@ -912,7 +920,7 @@ typedef enum eCopyParticlesSpace {
PAR_COPY_SPACE_WORLD = 1,
} eCopyParticlesSpace;
-static void copy_particle_edit(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystem *psys_from)
+static void copy_particle_edit(Scene *scene, SceneLayer *sl, Object *ob, ParticleSystem *psys, ParticleSystem *psys_from)
{
PTCacheEdit *edit_from = psys_from->edit, *edit;
ParticleData *pa;
@@ -962,10 +970,10 @@ static void copy_particle_edit(Scene *scene, Object *ob, ParticleSystem *psys, P
recalc_lengths(edit);
recalc_emitter_field(ob, psys);
- PE_update_object(scene, ob, true);
+ PE_update_object(scene, sl, ob, true);
PTCacheUndo_clear(edit);
- PE_undo_push(scene, "Original");
+ PE_undo_push(scene, sl, "Original");
}
static void remove_particle_systems_from_object(Object *ob_to)
@@ -993,7 +1001,14 @@ 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(Scene *scene, Object *ob_from, ParticleSystem *single_psys_from, Object *ob_to, int space)
+static bool copy_particle_systems_to_object(Main *bmain,
+ Scene *scene,
+ SceneLayer *sl,
+ Object *ob_from,
+ ParticleSystem *single_psys_from,
+ Object *ob_to,
+ int space,
+ bool duplicate_settings)
{
ModifierData *md;
ParticleSystem *psys_start = NULL, *psys, *psys_from;
@@ -1069,7 +1084,12 @@ static bool copy_particle_systems_to_object(Scene *scene, Object *ob_from, Parti
DM_ensure_tessface(psmd->dm_final);
if (psys_from->edit)
- copy_particle_edit(scene, ob_to, psys, psys_from);
+ copy_particle_edit(scene, sl, ob_to, psys, psys_from);
+
+ if (duplicate_settings) {
+ id_us_min(&psys->part->id);
+ psys->part = BKE_particlesettings_copy(bmain, psys->part);
+ }
}
MEM_freeN(tmp_psys);
@@ -1097,8 +1117,9 @@ static bool copy_particle_systems_to_object(Scene *scene, Object *ob_from, Parti
BLI_assert(false);
break;
}
-
- remap_hair_emitter(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);
+ if (ob_from != ob_to) {
+ remap_hair_emitter(scene, sl, ob_from, psys_from, ob_to, psys, psys->edit, from_mat, to_mat, psys_from->flag & PSYS_GLOBAL_HAIR, psys->flag & PSYS_GLOBAL_HAIR);
+ }
/* tag for recalc */
// psys->recalc |= PSYS_RECALC_RESET;
@@ -1107,7 +1128,7 @@ static bool copy_particle_systems_to_object(Scene *scene, Object *ob_from, Parti
#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;
}
@@ -1130,7 +1151,9 @@ 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);
+ SceneLayer *sl = CTX_data_scene_layer(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;
@@ -1145,7 +1168,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(scene, ob_from, psys_from, ob_to, space))
+ if (copy_particle_systems_to_object(bmain, scene, sl, ob_from, psys_from, ob_to, space, false))
changed = true;
else
fail++;
@@ -1187,3 +1210,42 @@ void PARTICLE_OT_copy_particle_systems(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "remove_target_particles", true, "Remove Target Particles", "Remove particle systems on the target objects");
RNA_def_boolean(ot->srna, "use_active", false, "Use Active", "Use the active particle system from the context");
}
+
+static int duplicate_particle_systems_poll(bContext *C)
+{
+ if (!ED_operator_object_active_editable(C)) {
+ return false;
+ }
+ Object *ob = ED_object_active_context(C);
+ if (BLI_listbase_is_empty(&ob->particlesystem)) {
+ return false;
+ }
+ return true;
+}
+
+static int duplicate_particle_systems_exec(bContext *C, wmOperator *op)
+{
+ const bool duplicate_settings = RNA_boolean_get(op->ptr, "use_duplicate_settings");
+ 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, CTX_data_scene_layer(C), 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->description = "Duplicate particle system within the active object";
+ ot->idname = "PARTICLE_OT_duplicate_particle_system";
+
+ ot->poll = duplicate_particle_systems_poll;
+ ot->exec = duplicate_particle_systems_exec;
+
+ /* flags */
+ 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");
+}
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c
index b5adf38527b..6e62dbabbca 100644
--- a/source/blender/editors/physics/physics_fluid.c
+++ b/source/blender/editors/physics/physics_fluid.c
@@ -329,6 +329,7 @@ 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);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Base *base;
int i;
int length = channels->length;
@@ -343,7 +344,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_NEW; base; base = base->next) {
Object *ob = base->object;
FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim);
@@ -570,14 +571,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, SceneLayer *sl, 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_NEW; base; base = base->next) {
Object *ob = base->object;
FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim);
@@ -631,71 +632,63 @@ static int fluid_validate_scene(ReportList *reports, Scene *scene, Object *fsDom
#define FLUID_SUFFIX_CONFIG_TMP (FLUID_SUFFIX_CONFIG ".tmp")
#define FLUID_SUFFIX_SURFACE "fluidsurface"
-static int fluid_init_filepaths(Object *fsDomain, char *targetDir, char *targetFile, char *debugStrBuffer)
+static bool fluid_init_filepaths(
+ ReportList *reports, FluidsimSettings *domainSettings, Object *fsDomain,
+ char *targetDir, char *targetFile)
{
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim);
- FluidsimSettings *domainSettings= fluidmd->fss;
- FILE *fileCfg;
- int dirExist = 0;
- char newSurfdataPath[FILE_MAX]; /* modified output settings */
const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP;
- int outStringsChanged = 0;
/* prepare names... */
- const char *relbase= modifier_path_relbase(fsDomain);
+ const char *relbase = modifier_path_relbase(fsDomain);
+
+ /* We do not accept empty paths, they can end in random places silently, see T51176. */
+ if (domainSettings->surfdataPath[0] == '\0') {
+ modifier_path_init(domainSettings->surfdataPath, sizeof(domainSettings->surfdataPath),
+ OB_FLUIDSIM_SURF_DIR_DEFAULT);
+ BKE_reportf(reports, RPT_WARNING, "Fluidsim: empty cache path, reset to default '%s'",
+ domainSettings->surfdataPath);
+ }
BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR);
- BLI_strncpy(newSurfdataPath, domainSettings->surfdataPath, FILE_MAXDIR); /* if 0'd out below, this value is never used! */
- BLI_path_abs(targetDir, relbase); /* fixed #frame-no */
+ BLI_path_abs(targetDir, relbase);
/* .tmp: don't overwrite/delete original file */
BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp);
- // make sure all directories exist
- // as the bobjs use the same dir, this only needs to be checked
- // for the cfg output
- BLI_make_existing_file(targetFile);
-
- // check selected directory
- // simply try to open cfg file for writing to test validity of settings
- fileCfg = BLI_fopen(targetFile, "w");
- if (fileCfg) {
- dirExist = 1; fclose(fileCfg);
- // remove cfg dummy from directory test
- BLI_delete(targetFile, false, false);
- }
-
- if (targetDir[0] == '\0' || (!dirExist)) {
- char blendFile[FILE_MAX];
-
- // invalid dir, reset to current/previous
- BLI_split_file_part(G.main->name, blendFile, sizeof(blendFile));
- BLI_replace_extension(blendFile, FILE_MAX, ""); /* strip .blend */
- BLI_snprintf(newSurfdataPath, FILE_MAX, "//fluidsimdata/%s_%s_", blendFile, fsDomain->id.name);
-
- BLI_snprintf(debugStrBuffer, 256, "fluidsimBake::error - warning resetting output dir to '%s'\n", newSurfdataPath);
- elbeemDebugOut(debugStrBuffer);
- outStringsChanged=1;
- }
-
- /* check if modified output dir is ok */
-#if 0
- if (outStringsChanged) {
- char dispmsg[FILE_MAX+256];
- int selection=0;
- BLI_strncpy(dispmsg, "Output settings set to: '", sizeof(dispmsg));
- strcat(dispmsg, newSurfdataPath);
- strcat(dispmsg, "'%t|Continue with changed settings %x1|Discard and abort %x0");
-
- /* ask user if thats what he/she wants... */
- selection = pupmenu(dispmsg);
- if (selection < 1) return 0; /* 0 from menu, or -1 aborted */
- BLI_strncpy(targetDir, newSurfdataPath, sizeof(targetDir));
- strncpy(domainSettings->surfdataPath, newSurfdataPath, FILE_MAXDIR);
- BLI_path_abs(targetDir, G.main->name); /* fixed #frame-no */
+ /* Ensure whole path exists and is wirtable. */
+ const bool dir_exists = BLI_dir_create_recursive(targetDir);
+ const bool is_writable = BLI_file_is_writable(targetFile);
+
+ /* We change path to some presumably valid default value, but do not allow bake process to continue,
+ * this gives user chance to set manually another path. */
+ if (!dir_exists || !is_writable) {
+ modifier_path_init(domainSettings->surfdataPath, sizeof(domainSettings->surfdataPath),
+ OB_FLUIDSIM_SURF_DIR_DEFAULT);
+
+ if (!dir_exists) {
+ BKE_reportf(reports, RPT_ERROR, "Fluidsim: could not create cache directory '%s', reset to default '%s'",
+ targetDir, domainSettings->surfdataPath);
+ }
+ else {
+ BKE_reportf(reports, RPT_ERROR, "Fluidsim: cache directory '%s' is not writable, reset to default '%s'",
+ targetDir, domainSettings->surfdataPath);
+ }
+
+ BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR);
+ BLI_path_abs(targetDir, relbase);
+
+ /* .tmp: don't overwrite/delete original file */
+ BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp);
+
+ /* Ensure whole path exists and is wirtable. */
+ if (!BLI_dir_create_recursive(targetDir) || !BLI_file_is_writable(targetFile)) {
+ BKE_reportf(reports, RPT_ERROR, "Fluidsim: could not use default cache directory '%s', "
+ "please define a valid cache path manually", targetDir);
+ }
+ return false;
}
-#endif
- return outStringsChanged;
+
+ return true;
}
/* ******************************************************************************** */
@@ -843,7 +836,8 @@ static void fluidsim_delete_until_lastframe(FluidsimSettings *fss, const char *r
static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, short do_job)
{
- Scene *scene= CTX_data_scene(C);
+ Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
int i;
FluidsimSettings *domainSettings;
@@ -857,7 +851,6 @@ static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, shor
char targetDir[FILE_MAX]; // store & modify output settings
char targetFile[FILE_MAX]; // temp. store filename from targetDir for access
- int outStringsChanged = 0; // modified? copy back before baking
float domainMat[4][4];
float invDomMat[4][4];
@@ -891,7 +884,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, sl, fsDomain)) {
fluidbake_free_data(channels, fobjects, fsset, fb);
return 0;
}
@@ -943,7 +936,11 @@ static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, shor
/* ******** prepare output file paths ******** */
- outStringsChanged = fluid_init_filepaths(fsDomain, targetDir, targetFile, debugStrBuffer);
+ if (!fluid_init_filepaths(reports, domainSettings, fsDomain, targetDir, targetFile)) {
+ fluidbake_free_data(channels, fobjects, fsset, fb);
+ return false;
+ }
+
channels->length = scene->r.efra; // DG TODO: why using endframe and not "noFrames" here? .. because "noFrames" is buggy too? (not using sfra)
channels->aniFrameTime = (double)((double)domainSettings->animEnd - (double)domainSettings->animStart) / (double)noFrames;
@@ -968,11 +965,6 @@ static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, shor
/* ******** start writing / exporting ******** */
// use .tmp, don't overwrite/delete original file
BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixConfigTmp);
-
- // make sure these directories exist as well
- if (outStringsChanged) {
- BLI_make_existing_file(targetFile);
- }
/* ******** export domain to elbeem ******** */
elbeemResetSettings(fsset);
diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h
index 361c058647a..6b6df15e987 100644
--- a/source/blender/editors/physics/physics_intern.h
+++ b/source/blender/editors/physics/physics_intern.h
@@ -75,6 +75,7 @@ void PARTICLE_OT_target_move_down(struct wmOperatorType *ot);
void PARTICLE_OT_connect_hair(struct wmOperatorType *ot);
void PARTICLE_OT_disconnect_hair(struct wmOperatorType *ot);
void PARTICLE_OT_copy_particle_systems(struct wmOperatorType *ot);
+void PARTICLE_OT_duplicate_particle_system(struct wmOperatorType *ot);
void PARTICLE_OT_dupliob_copy(struct wmOperatorType *ot);
void PARTICLE_OT_dupliob_remove(struct wmOperatorType *ot);
diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c
index 5074a41ad20..758ef43590e 100644
--- a/source/blender/editors/physics/physics_ops.c
+++ b/source/blender/editors/physics/physics_ops.c
@@ -83,6 +83,7 @@ static void operatortypes_particle(void)
WM_operatortype_append(PARTICLE_OT_connect_hair);
WM_operatortype_append(PARTICLE_OT_disconnect_hair);
WM_operatortype_append(PARTICLE_OT_copy_particle_systems);
+ WM_operatortype_append(PARTICLE_OT_duplicate_particle_system);
WM_operatortype_append(PARTICLE_OT_dupliob_copy);
WM_operatortype_append(PARTICLE_OT_dupliob_remove);
@@ -136,9 +137,6 @@ static void keymap_particle(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "PARTICLE_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "unselected", true);
- kmi = WM_keymap_verify_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_ANY, 0);
- RNA_boolean_set(kmi->ptr, "release_confirm", true);
-
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);
diff --git a/source/blender/editors/physics/physics_pointcache.c b/source/blender/editors/physics/physics_pointcache.c
index e81aa584586..d4f949880ee 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"
@@ -99,45 +100,45 @@ static int ptcache_job_break(void *customdata)
static void ptcache_job_update(void *customdata, float progress, int *cancel)
{
- PointCacheJob *job = customdata;
+ PointCacheJob *job = customdata;
- if (ptcache_job_break(job)) {
- *cancel = 1;
- }
+ if (ptcache_job_break(job)) {
+ *cancel = 1;
+ }
- *(job->do_update) = true;
- *(job->progress) = progress;
+ *(job->do_update) = true;
+ *(job->progress) = progress;
}
static void ptcache_job_startjob(void *customdata, short *stop, short *do_update, float *progress)
{
- PointCacheJob *job = customdata;
+ PointCacheJob *job = customdata;
- job->stop = stop;
- job->do_update = do_update;
- job->progress = progress;
+ job->stop = stop;
+ job->do_update = do_update;
+ job->progress = progress;
- G.is_break = false;
+ G.is_break = false;
- /* XXX annoying hack: needed to prevent data corruption when changing
- * scene frame in separate threads
- */
- G.is_rendering = true;
- BKE_spacedata_draw_locks(true);
+ /* XXX annoying hack: needed to prevent data corruption when changing
+ * scene frame in separate threads
+ */
+ G.is_rendering = true;
+ BKE_spacedata_draw_locks(true);
BKE_ptcache_bake(job->baker);
- *do_update = true;
- *stop = 0;
+ *do_update = true;
+ *stop = 0;
}
static void ptcache_job_endjob(void *customdata)
{
- PointCacheJob *job = customdata;
+ PointCacheJob *job = customdata;
Scene *scene = job->baker->scene;
- G.is_rendering = false;
- BKE_spacedata_draw_locks(false);
+ G.is_rendering = false;
+ BKE_spacedata_draw_locks(false);
WM_set_locked_interface(G.main->wm.first, false);
@@ -253,22 +254,23 @@ static void ptcache_bake_cancel(bContext *C, wmOperator *op)
static int ptcache_free_bake_all_exec(bContext *C, wmOperator *UNUSED(op))
{
- Scene *scene= CTX_data_scene(C);
- Base *base;
+ Scene *scene = CTX_data_scene(C);
PTCacheID *pid;
ListBase pidlist;
- for (base=scene->base.first; base; base= base->next) {
- BKE_ptcache_ids_from_object(&pidlist, base->object, scene, MAX_DUPLI_RECUR);
+ FOREACH_SCENE_OBJECT(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);
diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c
index 1bfc162a331..d93eb95243e 100644
--- a/source/blender/editors/physics/rigidbody_constraint.c
+++ b/source/blender/editors/physics/rigidbody_constraint.c
@@ -38,13 +38,15 @@
#include "DNA_scene_types.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_group.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"
@@ -89,10 +91,10 @@ bool ED_rigidbody_constraint_add(Main *bmain, Scene *scene, Object *ob, int 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_group_object_add(rbw->constraints, 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);
return true;
}
@@ -102,10 +104,10 @@ void ED_rigidbody_constraint_remove(Main *bmain, Scene *scene, Object *ob)
BKE_rigidbody_remove_constraint(scene, ob);
if (rbw)
- BKE_group_object_unlink(rbw->constraints, ob, scene, NULL);
+ BKE_group_object_unlink(rbw->constraints, 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);
}
/* ********************************************** */
@@ -117,8 +119,9 @@ static int rigidbody_con_add_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
- Object *ob = (scene) ? OBACT : NULL;
+ Object *ob = OBACT_NEW;
int type = RNA_enum_get(op->ptr, "type");
bool changed;
@@ -166,11 +169,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;
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *ob = OBACT_NEW;
/* 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 30597d95497..cf9dc8ff2a3 100644
--- a/source/blender/editors/physics/rigidbody_object.c
+++ b/source/blender/editors/physics/rigidbody_object.c
@@ -43,13 +43,15 @@
#include "BLT_translation.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_group.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"
@@ -119,10 +121,10 @@ 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_group_object_add(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);
return true;
}
@@ -133,10 +135,10 @@ void ED_rigidbody_object_remove(Main *bmain, Scene *scene, Object *ob)
BKE_rigidbody_remove_object(scene, ob);
if (rbw)
- BKE_group_object_unlink(rbw->group, ob, scene, NULL);
+ BKE_group_object_unlink(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);
}
/* ********************************************** */
@@ -345,7 +347,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;
}
@@ -527,7 +529,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/render/CMakeLists.txt b/source/blender/editors/render/CMakeLists.txt
index 971ab9f3458..ec00a258ebb 100644
--- a/source/blender/editors/render/CMakeLists.txt
+++ b/source/blender/editors/render/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../blenlib
../../blenloader
../../blentranslation
+ ../../depsgraph
../../gpu
../../imbuf
../../bmesh
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 8c5d25ad44d..193fac63050 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -54,7 +54,6 @@
#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_library.h"
@@ -66,6 +65,8 @@
#include "BKE_screen.h"
#include "BKE_scene.h"
+#include "DEG_depsgraph.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -81,6 +82,7 @@
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
+#include "GPU_shader.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -116,6 +118,7 @@ typedef struct RenderJob {
ScrArea *sa;
ColorManagedViewSettings view_settings;
ColorManagedDisplaySettings display_settings;
+ bool supports_glsl_draw;
bool interface_locked;
} RenderJob;
@@ -210,7 +213,7 @@ static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibu
}
else {
if (rr->renlay == NULL) return;
- rectf = RE_RenderLayerGetPass(rr->renlay, SCE_PASS_COMBINED, viewname);
+ rectf = RE_RenderLayerGetPass(rr->renlay, RE_PASSNAME_COMBINED, viewname);
}
}
if (rectf == NULL) return;
@@ -305,6 +308,7 @@ static int screen_render_exec(bContext *C, wmOperator *op)
}
re = RE_NewRender(scene->id.name);
+ RE_SetDepsgraph(re, CTX_data_depsgraph(C));
lay_override = (v3d && v3d->lay != scene->lay) ? v3d->lay : 0;
G.is_break = false;
@@ -488,8 +492,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.
@@ -569,6 +574,7 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec
* operate with.
*/
if (rr->do_exr_tile ||
+ !rj->supports_glsl_draw ||
ibuf->channels == 1 ||
U.image_draw_method != IMAGE_DRAW_METHOD_GLSL)
{
@@ -614,8 +620,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;
@@ -716,7 +723,7 @@ static void render_endjob(void *rjv)
scene->lay_updated = 0;
}
- DAG_on_visible_update(G.main, false);
+ DEG_on_visible_update(G.main, false);
}
}
@@ -780,7 +787,7 @@ 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(Main *bmain, Scene *scene)
{
Object *object;
Scene *sce_iter;
@@ -791,7 +798,7 @@ static void clean_viewport_memory(Main *bmain, Scene *scene, int renderlay)
}
for (SETLOOPER(scene, sce_iter, base)) {
- if ((base->lay & renderlay) == 0) {
+ if ((base->flag & BASE_VISIBLED) == 0) {
continue;
}
if (RE_allow_render_generic_object(base->object)) {
@@ -904,6 +911,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
rj->orig_layer = 0;
rj->last_layer = 0;
rj->sa = sa;
+ rj->supports_glsl_draw = IMB_colormanagement_support_glsl_draw(&scene->view_settings);
BKE_color_managed_display_settings_copy(&rj->display_settings, &scene->display_settings);
BKE_color_managed_view_settings_copy(&rj->view_settings, &scene->view_settings);
@@ -927,8 +935,6 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
/* 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.
@@ -942,7 +948,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 */
@@ -968,6 +974,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_SetDepsgraph(re, CTX_data_depsgraph(C));
rj->re = re;
G.is_break = false;
@@ -1539,11 +1546,10 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C)
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);
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
+ immDrawPixelsTex(&state, xof, yof, rres.rectx, rres.recty,
+ GL_RGBA, GL_FLOAT, GL_NEAREST, rres.rectf,
+ scale_x, scale_y, NULL);;
glDisable(GL_BLEND);
IMB_colormanagement_finish_glsl_draw();
@@ -1560,12 +1566,11 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C)
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);
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
+ immDrawPixelsTex(&state, xof, yof, rres.rectx, rres.recty,
+ GL_RGBA, GL_UNSIGNED_BYTE,
+ GL_NEAREST, display_buffer,
+ scale_x, scale_y, NULL);
glDisable(GL_BLEND);
MEM_freeN(display_buffer);
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index 85c05ab0e5c..65b0eb2b005 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -38,8 +38,8 @@
#include "BLI_math_color_blend.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BLI_jitter.h"
#include "BLI_threads.h"
+#include "BLI_task.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -70,17 +70,28 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "GPU_glew.h"
#include "GPU_compositing.h"
#include "GPU_framebuffer.h"
-
+#include "GPU_matrix.h"
#include "render_intern.h"
+/* Define this to get timing information. */
+// #undef DEBUG_TIME
+
+#ifdef DEBUG_TIME
+# include "PIL_time.h"
+#endif
+
+// TODO(sergey): Find better approximation of the scheduled frames.
+// For really highres renders it might fail still.
+#define MAX_SCHEDULED_FRAMES 8
+
typedef struct OGLRender {
Main *bmain;
Render *re;
Scene *scene;
+ SceneLayer *scene_layer;
View3D *v3d;
RegionView3D *rv3d;
@@ -123,18 +134,20 @@ typedef struct OGLRender {
wmTimer *timer; /* use to check if running modal or not (invoke'd or exec'd)*/
void **movie_ctx_arr;
-} 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;
- }
-}
+ TaskScheduler *task_scheduler;
+ TaskPool *task_pool;
+ bool pool_ok;
+ bool is_animation;
+ SpinLock reports_lock;
+ unsigned int num_scheduled_frames;
+ ThreadMutex task_mutex;
+ ThreadCondition task_condition;
+
+#ifdef DEBUG_TIME
+ double time_start;
+#endif
+} OGLRender;
static bool screen_opengl_is_multiview(OGLRender *oglrender)
{
@@ -182,6 +195,9 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
if (rv_del->rectz)
MEM_freeN(rv_del->rectz);
+ if (rv_del->rect32)
+ MEM_freeN(rv_del->rect32);
+
MEM_freeN(rv_del);
}
}
@@ -194,8 +210,6 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
while (rv) {
srv = BLI_findstring(&rd->views, rv->name, offsetof(SceneRenderView, name));
if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
- if (rv->rectf == NULL)
- rv->rectf = MEM_callocN(sizeof(float) * 4 * oglrender->sizex * oglrender->sizey, "screen_opengl_render_init rect");
rv = rv->prev;
}
else {
@@ -210,6 +224,9 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
if (rv_del->rectz)
MEM_freeN(rv_del->rectz);
+ if (rv_del->rect32)
+ MEM_freeN(rv_del->rect32);
+
MEM_freeN(rv_del);
}
}
@@ -229,16 +246,8 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
}
}
- for (rv = rr->views.first; rv; rv = rv->next) {
- if (rv->rectf == NULL) {
- rv->rectf = MEM_callocN(sizeof(float) * 4 * oglrender->sizex * oglrender->sizey, "screen_opengl_render_init rect");
- }
- }
-
- BLI_lock_thread(LOCK_DRAW_IMAGE);
if (!(is_multiview && BKE_scene_multiview_is_stereo3d(rd)))
oglrender->iuser.flag &= ~IMA_SHOW_STEREO;
- BLI_unlock_thread(LOCK_DRAW_IMAGE);
/* will only work for non multiview correctly */
if (v3d) {
@@ -255,6 +264,7 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
{
Scene *scene = oglrender->scene;
+ SceneLayer *sl = oglrender->scene_layer;
ARegion *ar = oglrender->ar;
View3D *v3d = oglrender->v3d;
RegionView3D *rv3d = oglrender->rv3d;
@@ -266,6 +276,7 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
bool draw_sky = (scene->r.alphamode == R_ADDSKY);
unsigned char *rect = NULL;
const char *viewname = RE_GetActiveRenderView(oglrender->re);
+ ImBuf *ibuf_result = NULL;
if (oglrender->is_sequencer) {
SpaceSeq *sseq = oglrender->sseq;
@@ -292,6 +303,12 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
RE_render_result_rect_from_ibuf(rr, &scene->r, out, oglrender->view_id);
IMB_freeImBuf(out);
}
+ else if (gpd) {
+ /* If there are no strips, Grease Pencil still needs a buffer to draw on */
+ ImBuf *out = IMB_allocImBuf(oglrender->sizex, oglrender->sizey, 32, IB_rect);
+ RE_render_result_rect_from_ibuf(rr, &scene->r, out, oglrender->view_id);
+ IMB_freeImBuf(out);
+ }
if (gpd) {
int i;
@@ -304,7 +321,7 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
wmOrtho2(0, sizex, 0, sizey);
- glTranslatef(sizex / 2, sizey / 2, 0.0f);
+ gpuTranslate2f(sizex / 2, sizey / 2);
G.f |= G_RENDER_OGL;
ED_gpencil_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ);
@@ -329,7 +346,7 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
if (view_context) {
ibuf_view = ED_view3d_draw_offscreen_imbuf(
- scene, v3d, ar, sizex, sizey,
+ scene, sl, v3d, ar, sizex, sizey,
IB_rect, draw_bgpic,
alpha_mode, oglrender->ofs_samples, oglrender->ofs_full_samples, viewname,
oglrender->fx, oglrender->ofs, err_out);
@@ -341,7 +358,7 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
}
else {
ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(
- scene, scene->camera, oglrender->sizex, oglrender->sizey,
+ scene, sl, scene->camera, oglrender->sizex, oglrender->sizey,
IB_rect, OB_SOLID, false, true, true,
alpha_mode, oglrender->ofs_samples, oglrender->ofs_full_samples, viewname,
oglrender->fx, oglrender->ofs, err_out);
@@ -349,46 +366,20 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
}
if (ibuf_view) {
- /* steal rect reference from ibuf */
+ ibuf_result = ibuf_view;
rect = (unsigned char *)ibuf_view->rect;
- ibuf_view->mall &= ~IB_rect;
-
- IMB_freeImBuf(ibuf_view);
}
else {
fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out);
}
}
- /* note on color management:
- *
- * OpenGL renders into sRGB colors, but render buffers are expected to be
- * linear So we convert to linear here, so the conversion back to bytes can make it
- * sRGB (or other display space) again, and so that e.g. openexr saving also saves the
- * correct linear float buffer.
- */
-
- if (rect) {
- int profile_to;
- float *rectf = RE_RenderViewGetById(rr, oglrender->view_id)->rectf;
-
- if (BKE_scene_check_color_management_enabled(scene))
- profile_to = IB_PROFILE_LINEAR_RGB;
- else
- profile_to = IB_PROFILE_SRGB;
-
- /* sequencer has got trickier conversion happened above
- * also assume opengl's space matches byte buffer color space */
- IMB_buffer_float_from_byte(rectf, rect,
- profile_to, IB_PROFILE_SRGB, true,
- oglrender->sizex, oglrender->sizey, oglrender->sizex, oglrender->sizex);
-
- /* rr->rectf is now filled with image data */
-
- if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW))
- BKE_image_stamp_buf(scene, camera, NULL, rect, rectf, rr->rectx, rr->recty, 4);
-
- MEM_freeN(rect);
+ 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);
+ }
+ RE_render_result_rect_from_ibuf(rr, &scene->r, ibuf_result, oglrender->view_id);
+ IMB_freeImBuf(ibuf_result);
}
}
@@ -445,6 +436,9 @@ static void add_gpencil_renderpass(OGLRender *oglrender, RenderResult *rr, Rende
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;
@@ -477,23 +471,26 @@ static void add_gpencil_renderpass(OGLRender *oglrender, RenderResult *rr, Rende
RenderPass *rp = RE_create_gp_pass(rr, gpl->info, rv->name);
/* copy image data from rectf */
- float *src = RE_RenderViewGetById(rr, oglrender->view_id)->rectf;
- float *dest = rp->rect;
-
- float *pixSrc, *pixDest;
- int x, y, rectx, recty;
- rectx = rr->rectx;
- recty = rr->recty;
- for (y = 0; y < recty; y++) {
- for (x = 0; x < rectx; x++) {
- pixSrc = src + 4 * (rectx * y + x);
- if (pixSrc[3] > 0.0) {
- pixDest = dest + 4 * (rectx * y + x);
- addAlphaOverFloat(pixDest, pixSrc);
+ // 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) {
@@ -543,8 +540,11 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
BLI_assert(view_id < oglrender->views_len);
RE_SetActiveRenderView(oglrender->re, rv->name);
oglrender->view_id = view_id;
- /* add grease pencil passes */
- add_gpencil_renderpass(oglrender, rr, rv);
+ /* 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);
}
@@ -562,6 +562,24 @@ 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 */
@@ -575,7 +593,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");
@@ -638,9 +656,11 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
oglrender->sizey = sizey;
oglrender->bmain = CTX_data_main(C);
oglrender->scene = scene;
+ oglrender->scene_layer = CTX_data_scene_layer(C);
oglrender->cfrao = scene->r.cfra;
oglrender->write_still = is_write_still && !is_animation;
+ oglrender->is_animation = is_animation;
oglrender->views_len = BKE_scene_multiview_num_views_get(&scene->r);
@@ -695,6 +715,34 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
oglrender->mh = NULL;
oglrender->movie_ctx_arr = NULL;
+ if (is_animation) {
+ TaskScheduler *task_scheduler = BLI_task_scheduler_get();
+ if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
+ task_scheduler = BLI_task_scheduler_create(1);
+ oglrender->task_scheduler = task_scheduler;
+ oglrender->task_pool = BLI_task_pool_create_background(task_scheduler,
+ oglrender);
+ }
+ else {
+ oglrender->task_scheduler = NULL;
+ oglrender->task_pool = BLI_task_pool_create(task_scheduler,
+ oglrender);
+ }
+ oglrender->pool_ok = true;
+ BLI_spin_init(&oglrender->reports_lock);
+ }
+ else {
+ oglrender->task_scheduler = NULL;
+ oglrender->task_pool = NULL;
+ }
+ oglrender->num_scheduled_frames = 0;
+ BLI_mutex_init(&oglrender->task_mutex);
+ BLI_condition_init(&oglrender->task_condition);
+
+#ifdef DEBUG_TIME
+ oglrender->time_start = PIL_check_seconds_timer();
+#endif
+
return true;
}
@@ -704,6 +752,39 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
Scene *scene = oglrender->scene;
int i;
+ if (oglrender->is_animation) {
+ /* Trickery part for movie output:
+ *
+ * We MUST write frames in an exact order, so we only let background
+ * thread to work on that, and main thread is simply waits for that
+ * thread to do all the dirty work.
+ *
+ * After this loop is done work_and_wait() will have nothing to do,
+ * so we don't run into wrong order of frames written to the stream.
+ */
+ if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
+ BLI_mutex_lock(&oglrender->task_mutex);
+ while (oglrender->num_scheduled_frames > 0) {
+ BLI_condition_wait(&oglrender->task_condition,
+ &oglrender->task_mutex);
+ }
+ BLI_mutex_unlock(&oglrender->task_mutex);
+ }
+ BLI_task_pool_work_and_wait(oglrender->task_pool);
+ BLI_task_pool_free(oglrender->task_pool);
+ /* Depending on various things we might or might not use global scheduler. */
+ if (oglrender->task_scheduler != NULL) {
+ BLI_task_scheduler_free(oglrender->task_scheduler);
+ }
+ BLI_spin_end(&oglrender->reports_lock);
+ }
+ BLI_mutex_end(&oglrender->task_mutex);
+ BLI_condition_end(&oglrender->task_condition);
+
+#ifdef DEBUG_TIME
+ printf("Total render time: %f\n", PIL_check_seconds_timer() - oglrender->time_start);
+#endif
+
if (oglrender->mh) {
if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
for (i = 0; i < oglrender->totvideos; i++) {
@@ -719,7 +800,7 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
if (oglrender->timer) { /* exec will not have a timer */
scene->r.cfra = oglrender->cfrao;
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, screen_opengl_layers(oglrender));
+ BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene);
WM_event_remove_timer(oglrender->wm, oglrender->win, oglrender->timer);
}
@@ -798,6 +879,122 @@ static bool screen_opengl_render_anim_initialize(bContext *C, wmOperator *op)
return true;
}
+typedef struct WriteTaskData {
+ RenderResult *rr;
+ Scene tmp_scene;
+} WriteTaskData;
+
+static void write_result_func(TaskPool * __restrict pool,
+ void *task_data_v,
+ int UNUSED(thread_id))
+{
+ OGLRender *oglrender = (OGLRender *) BLI_task_pool_userdata(pool);
+ WriteTaskData *task_data = (WriteTaskData *) task_data_v;
+ Scene *scene = &task_data->tmp_scene;
+ RenderResult *rr = task_data->rr;
+ const bool is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);
+ const int cfra = scene->r.cfra;
+ bool ok;
+ /* Don't attempt to write if we've got an error. */
+ if (!oglrender->pool_ok) {
+ RE_FreeRenderResult(rr);
+ BLI_mutex_lock(&oglrender->task_mutex);
+ oglrender->num_scheduled_frames--;
+ BLI_condition_notify_all(&oglrender->task_condition);
+ BLI_mutex_unlock(&oglrender->task_mutex);
+ return;
+ }
+ /* Construct local thread0safe copy of reports structure which we can
+ * safely pass to the underlying functions.
+ */
+ ReportList reports;
+ BKE_reports_init(&reports, oglrender->reports->flag & ~RPT_PRINT);
+ /* Do actual save logic here, depending on the file format.
+ *
+ * NOTE: We have to construct temporary scene with proper scene->r.cfra.
+ * This is because underlying calls do not use r.cfra but use scene
+ * for that.
+ */
+ if (is_movie) {
+ ok = RE_WriteRenderViewsMovie(&reports,
+ rr,
+ scene,
+ &scene->r,
+ oglrender->mh,
+ oglrender->movie_ctx_arr,
+ oglrender->totvideos,
+ PRVRANGEON != 0);
+ }
+ else {
+ /* TODO(sergey): We can in theory save some CPU ticks here because we
+ * calculate file name again here.
+ */
+ char name[FILE_MAX];
+ BKE_image_path_from_imformat(name,
+ scene->r.pic,
+ oglrender->bmain->name,
+ cfra,
+ &scene->r.im_format,
+ (scene->r.scemode & R_EXTENSION) != 0,
+ true,
+ NULL);
+
+ BKE_render_result_stamp_info(scene, scene->camera, rr, false);
+ ok = RE_WriteRenderViewsImage(NULL, rr, scene, true, name);
+ if (!ok) {
+ BKE_reportf(&reports,
+ RPT_ERROR,
+ "Write error: cannot save %s",
+ name);
+ }
+ }
+ if (reports.list.first != NULL) {
+ BLI_spin_lock(&oglrender->reports_lock);
+ for (Report *report = reports.list.first;
+ report != NULL;
+ report = report->next)
+ {
+ BKE_report(oglrender->reports,
+ report->type,
+ report->message);
+ }
+ BLI_spin_unlock(&oglrender->reports_lock);
+ }
+ if (!ok) {
+ oglrender->pool_ok = false;
+ }
+ RE_FreeRenderResult(rr);
+ BLI_mutex_lock(&oglrender->task_mutex);
+ oglrender->num_scheduled_frames--;
+ BLI_condition_notify_all(&oglrender->task_condition);
+ BLI_mutex_unlock(&oglrender->task_mutex);
+}
+
+static bool schedule_write_result(OGLRender *oglrender, RenderResult *rr)
+{
+ if (!oglrender->pool_ok) {
+ RE_FreeRenderResult(rr);
+ return false;
+ }
+ Scene *scene = oglrender->scene;
+ WriteTaskData *task_data = MEM_mallocN(sizeof(WriteTaskData), "write task data");
+ task_data->rr = rr;
+ task_data->tmp_scene = *scene;
+ BLI_mutex_lock(&oglrender->task_mutex);
+ oglrender->num_scheduled_frames++;
+ if (oglrender->num_scheduled_frames > MAX_SCHEDULED_FRAMES) {
+ BLI_condition_wait(&oglrender->task_condition,
+ &oglrender->task_mutex);
+ }
+ BLI_mutex_unlock(&oglrender->task_mutex);
+ BLI_task_pool_push(oglrender->task_pool,
+ write_result_func,
+ task_data,
+ true,
+ TASK_PRIORITY_LOW);
+ return true;
+}
+
static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -813,12 +1010,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_update_for_newframe(bmain->eval_ctx, bmain, scene);
CFRA++;
}
@@ -830,7 +1022,9 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
&scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL);
if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) {
+ BLI_spin_lock(&oglrender->reports_lock);
BKE_reportf(op->reports, RPT_INFO, "Skipping existing frame \"%s\"", name);
+ BLI_spin_unlock(&oglrender->reports_lock);
ok = true;
goto finally;
}
@@ -838,7 +1032,7 @@ 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_update_for_newframe(bmain->eval_ctx, bmain, scene);
if (view_context) {
if (oglrender->rv3d->persp == RV3D_CAMOB && oglrender->v3d->camera && oglrender->v3d->scenelock) {
@@ -858,34 +1052,10 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
/* save to disk */
rr = RE_AcquireResultRead(oglrender->re);
-
- if (is_movie) {
- ok = RE_WriteRenderViewsMovie(oglrender->reports, rr, scene, &scene->r, oglrender->mh,
- oglrender->movie_ctx_arr, oglrender->totvideos, PRVRANGEON != 0);
- if (ok) {
- printf("Append frame %d", scene->r.cfra);
- BKE_reportf(op->reports, RPT_INFO, "Appended frame: %d", scene->r.cfra);
- }
- }
- else {
- BKE_render_result_stamp_info(scene, scene->camera, rr, false);
- ok = RE_WriteRenderViewsImage(op->reports, rr, scene, true, name);
- if (ok) {
- printf("Saved: %s", name);
- BKE_reportf(op->reports, RPT_INFO, "Saved file: %s", name);
- }
- else {
- printf("Write error: cannot save %s\n", name);
- BKE_reportf(op->reports, RPT_ERROR, "Write error: cannot save %s", name);
- }
- }
-
+ RenderResult *new_rr = RE_DuplicateRenderResult(rr);
RE_ReleaseResult(oglrender->re);
-
- /* movie stats prints have no line break */
- printf("\n");
-
+ ok = schedule_write_result(oglrender, new_rr);
finally: /* Step the frame and bail early if needed */
@@ -911,13 +1081,14 @@ static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent
switch (event->type) {
case ESCKEY:
/* cancel */
+ oglrender->pool_ok = false; /* Flag pool for cancel. */
screen_opengl_render_end(C, op->customdata);
return OPERATOR_FINISHED;
case TIMER:
/* render frame? */
if (oglrender->timer == event->customdata)
break;
- /* fall-through */
+ ATTR_FALLTHROUGH;
default:
/* nothing to do */
return OPERATOR_RUNNING_MODAL;
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index b4f3426677a..1a3d1ce083e 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -69,6 +69,7 @@
#include "BKE_image.h"
#include "BKE_icons.h"
#include "BKE_lamp.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_library_remap.h"
#include "BKE_main.h"
@@ -78,6 +79,9 @@
#include "BKE_texture.h"
#include "BKE_world.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_thumbs.h"
@@ -85,6 +89,7 @@
#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_shader.h"
#include "RE_pipeline.h"
#include "RE_engine.h"
@@ -94,6 +99,7 @@
#include "ED_datafiles.h"
#include "ED_render.h"
+#include "ED_screen.h"
#ifndef NDEBUG
/* Used for database init assert(). */
@@ -196,7 +202,7 @@ static Main *load_main_from_memory(const void *blend, int blend_size)
BlendFileData *bfd;
G.fileflags |= G_FILE_NO_UI;
- bfd = BLO_read_from_memory(blend, blend_size, NULL);
+ bfd = BLO_read_from_memory(blend, blend_size, NULL, BLO_READ_SKIP_NONE);
if (bfd) {
bmain = bfd->main;
@@ -269,20 +275,62 @@ static Scene *preview_get_scene(Main *pr_main)
return pr_main->scene.first;
}
+static const char *preview_layer_name(const char pr_type)
+{
+ 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 "";
+ }
+}
+
+static void set_preview_layer(SceneLayer *scene_layer, char pr_type)
+{
+ LayerCollection *lc;
+ const char *collection_name = preview_layer_name(pr_type);
+ for (lc = scene_layer->layer_collections.first; lc; lc = lc->next) {
+ if (STREQ(lc->scene_collection->name, collection_name)) {
+ lc->flag = COLLECTION_VISIBLE;
+ }
+ else {
+ lc->flag = 0;
+ }
+ }
+}
/* 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, bmain->name, sizeof(pr_main->name));
sce = preview_get_scene(pr_main);
if (sce) {
-
+ SceneLayer *scene_layer = BKE_scene_layer_from_scene_get(sce);
+
/* this flag tells render to not execute depsgraph or ipos etc */
sce->r.scemode |= R_BUTS_PREVIEW;
/* set world always back, is used now */
@@ -357,26 +405,34 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty
/* 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);
+ for (Base *base = scene_layer->object_bases.first; base; base = base->next) {
+ Object *ob = base->object;
+ if (ob->id.name[2] == 'c') {
+ Material *shadmat = give_current_material(ob, ob->actcol);
if (shadmat) {
- if (mat->mode2 & MA_CASTSHADOW) shadmat->septex = 0;
- else shadmat->septex |= 1;
+ 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) {
+ for (Base *base = scene_layer->object_bases.first; base; base = base->next) {
+ Object *ob = base->object;
+ if (ob->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;
+ if (!STREQ(ob->id.name + 2, "Lamp.002")) {
+ if (mat->material_type == MA_TYPE_VOLUME) {
+ base->flag &= ~BASE_VISIBLED;
+ }
+ else {
+ base->flag |= BASE_VISIBLED;
+ }
}
}
}
@@ -389,10 +445,10 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty
if (sp->pr_method == PR_ICON_RENDER) {
if (mat->material_type == MA_TYPE_HALO) {
- sce->lay = 1 << MA_FLAT;
+ set_preview_layer(scene_layer, MA_FLAT);
}
else {
- sce->lay = 1 << MA_SPHERE_A;
+ set_preview_layer(scene_layer, MA_SPHERE_A);
/* same as above, use current scene world to light sphere */
if (BKE_scene_use_new_shading_nodes(scene))
@@ -400,7 +456,8 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty
}
}
else {
- sce->lay = 1 << mat->pr_type;
+ set_preview_layer(scene_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);
@@ -413,7 +470,7 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty
}
- for (base = sce->base.first; base; base = base->next) {
+ for (Base *base = scene_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);
@@ -427,7 +484,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_VISIBLED;
}
}
}
@@ -440,9 +497,9 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty
sp->texcopy = tex;
BLI_addtail(&pr_main->tex, tex);
}
- sce->lay = 1 << MA_TEXTURE;
+ set_preview_layer(scene_layer, MA_TEXTURE);
- for (base = sce->base.first; base; base = base->next) {
+ for (Base *base = scene_layer->object_bases.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]) {
@@ -481,21 +538,23 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty
BLI_addtail(&pr_main->lamp, la);
}
- sce->lay = 1 << 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;
+ set_preview_layer(scene_layer, 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);
+ set_preview_layer(scene_layer, MA_LAMP);
}
}
+ else {
+ set_preview_layer(scene_layer, MA_LAMP);
+ }
- for (base = sce->base.first; base; base = base->next) {
+ for (Base *base = scene_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;
@@ -517,7 +576,7 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty
BLI_addtail(&pr_main->world, wrld);
}
- sce->lay = 1 << MA_SKY;
+ set_preview_layer(scene_layer, MA_SKY);
sce->world = wrld;
if (wrld && wrld->nodetree && sp->pr_method == PR_NODE_RENDER) {
@@ -526,7 +585,12 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty
BKE_node_preview_init_tree(origwrld->nodetree, sp->sizex, sp->sizey, true);
}
}
-
+
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update(&sce->id, 0);
+ DEG_relations_tag_update(pr_main);
+ BKE_scene_update_tagged(pr_main->eval_ctx, pr_main, sce);
+
return sce;
}
@@ -593,7 +657,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);
@@ -863,8 +929,6 @@ static void shader_preview_free(void *customdata)
/* get rid of copied world */
BLI_remlink(&pr_main->world, sp->worldcopy);
- /* T32865 - we need to unlink the texture copies, unlike for materials */
- BKE_libblock_relink_ex(pr_main, sp->worldcopy, NULL, NULL, true);
BKE_world_free(sp->worldcopy);
properties = IDP_GetProperties((ID *)sp->worldcopy, false);
@@ -881,7 +945,6 @@ static void shader_preview_free(void *customdata)
/* get rid of copied lamp */
BLI_remlink(&pr_main->lamp, sp->lampcopy);
- BKE_libblock_relink_ex(pr_main, sp->lampcopy, NULL, NULL, true);
BKE_lamp_free(sp->lampcopy);
properties = IDP_GetProperties((ID *)sp->lampcopy, false);
@@ -1025,6 +1088,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);
@@ -1083,13 +1152,19 @@ static void icon_preview_add_size(IconPreview *ip, unsigned int *rect, int sizex
static void icon_preview_startjob_all_sizes(void *customdata, short *stop, short *do_update, float *progress)
{
IconPreview *ip = (IconPreview *)customdata;
- IconPreviewSize *cur_size = ip->sizes.first;
+ IconPreviewSize *cur_size;
const bool use_new_shading = BKE_scene_use_new_shading_nodes(ip->scene);
- while (cur_size) {
+ for (cur_size = ip->sizes.first; cur_size; cur_size = cur_size->next) {
PreviewImage *prv = ip->owner;
+
+ if (prv->tag & PRV_TAG_DEFFERED_DELETE) {
+ /* Non-thread-protected reading is not an issue here. */
+ continue;
+ }
+
ShaderPreview *sp = MEM_callocN(sizeof(ShaderPreview), "Icon ShaderPreview");
- const bool is_render = !prv->use_deferred;
+ const bool is_render = !(prv->tag & PRV_TAG_DEFFERED);
/* construct shader preview from image size and previewcustomdata */
sp->scene = ip->scene;
@@ -1120,8 +1195,6 @@ static void icon_preview_startjob_all_sizes(void *customdata, short *stop, short
common_preview_startjob(sp, stop, do_update, progress);
shader_preview_free(sp);
-
- cur_size = cur_size->next;
}
}
@@ -1150,6 +1223,15 @@ static void icon_preview_endjob(void *customdata)
}
#endif
}
+
+ if (ip->owner) {
+ PreviewImage *prv_img = ip->owner;
+ prv_img->tag &= ~PRV_TAG_DEFFERED_RENDERING;
+ if (prv_img->tag & PRV_TAG_DEFFERED_DELETE) {
+ BLI_assert(prv_img->tag & PRV_TAG_DEFFERED);
+ BKE_previewimg_cached_release_pointer(prv_img);
+ }
+ }
}
static void icon_preview_free(void *customdata)
@@ -1170,7 +1252,7 @@ void ED_preview_icon_render(Main *bmain, Scene *scene, ID *id, unsigned int *rec
ip.bmain = bmain;
ip.scene = scene;
- ip.owner = id;
+ ip.owner = BKE_previewimg_id_ensure(id);
ip.id = id;
icon_preview_add_size(&ip, rect, sizex, sizey);
@@ -1208,6 +1290,14 @@ void ED_preview_icon_job(const bContext *C, void *owner, ID *id, unsigned int *r
icon_preview_add_size(ip, rect, sizex, sizey);
+ /* Special threading hack: warn main code that this preview is being rendered and cannot be freed... */
+ {
+ PreviewImage *prv_img = owner;
+ if (prv_img->tag & PRV_TAG_DEFFERED) {
+ prv_img->tag |= PRV_TAG_DEFFERED_RENDERING;
+ }
+ }
+
/* setup job */
WM_jobs_customdata_set(wm_job, ip, icon_preview_free);
WM_jobs_timer(wm_job, 0.1, NC_WINDOW, NC_WINDOW);
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index 5a0c250c777..2cdd49b3113 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -50,10 +50,10 @@
#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.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"
@@ -65,7 +65,8 @@
#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 +84,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"
@@ -153,7 +155,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);
@@ -219,7 +221,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;
@@ -359,7 +361,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);
}
}
@@ -424,7 +426,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 | ND_DATA, ob);
return OPERATOR_FINISHED;
@@ -449,7 +451,8 @@ void OBJECT_OT_material_slot_move(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_enum(ot->srna, "direction", material_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
+ RNA_def_enum(ot->srna, "direction", material_slot_move, 0, "Direction",
+ "Direction to move the active material towards");
}
/********************** new material operator *********************/
@@ -610,7 +613,7 @@ void WORLD_OT_new(wmOperatorType *ot)
/* identifiers */
ot->name = "New World";
ot->idname = "WORLD_OT_new";
- ot->description = "Add a new world";
+ ot->description = "Create a new world Data-Block";
/* api callbacks */
ot->exec = new_world_exec;
@@ -625,11 +628,12 @@ static int render_layer_add_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- BKE_scene_add_render_layer(scene, NULL);
- scene->r.actlay = BLI_listbase_count(&scene->r.layers) - 1;
+ BKE_scene_layer_add(scene, NULL);
+ scene->active_layer = BLI_listbase_count(&scene->render_layers) - 1;
- 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;
}
@@ -650,15 +654,16 @@ void SCENE_OT_render_layer_add(wmOperatorType *ot)
static int render_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);
+ SceneLayer *sl = BKE_scene_layer_context_active_PLACEHOLDER(scene);
- if (!BKE_scene_remove_render_layer(CTX_data_main(C), scene, rl))
+ if (!ED_scene_render_layer_delete(bmain, scene, sl, 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;
}
@@ -799,7 +804,7 @@ static int freestyle_module_remove_exec(bContext *C, wmOperator *UNUSED(op))
BKE_freestyle_module_delete(&srl->freestyleConfig, 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;
@@ -828,14 +833,10 @@ static int freestyle_module_move_exec(bContext *C, wmOperator *op)
FreestyleModuleConfig *module = ptr.data;
int dir = RNA_enum_get(op->ptr, "direction");
- if (dir == 1) {
- BKE_freestyle_module_move_up(&srl->freestyleConfig, module);
- }
- else {
- BKE_freestyle_module_move_down(&srl->freestyleConfig, module);
+ if (BKE_freestyle_module_move(&srl->freestyleConfig, module, dir)) {
+ DEG_id_tag_update(&scene->id, 0);
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
}
- DAG_id_tag_update(&scene->id, 0);
- WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
return OPERATOR_FINISHED;
}
@@ -843,8 +844,8 @@ static int freestyle_module_move_exec(bContext *C, wmOperator *op)
void SCENE_OT_freestyle_module_move(wmOperatorType *ot)
{
static EnumPropertyItem direction_items[] = {
- {1, "UP", 0, "Up", ""},
- {-1, "DOWN", 0, "Down", ""},
+ {-1, "UP", 0, "Up", ""},
+ {1, "DOWN", 0, "Down", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -861,7 +862,8 @@ void SCENE_OT_freestyle_module_move(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
/* props */
- RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction", "Direction to move, UP or DOWN");
+ RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction",
+ "Direction to move the chosen style module towards");
}
static int freestyle_lineset_add_exec(bContext *C, wmOperator *UNUSED(op))
@@ -872,7 +874,7 @@ static int freestyle_lineset_add_exec(bContext *C, wmOperator *UNUSED(op))
BKE_freestyle_lineset_add(bmain, &srl->freestyleConfig, 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;
@@ -936,7 +938,7 @@ static int freestyle_lineset_paste_exec(bContext *C, wmOperator *UNUSED(op))
FRS_paste_active_lineset(&srl->freestyleConfig);
- 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;
@@ -964,7 +966,7 @@ static int freestyle_lineset_remove_exec(bContext *C, wmOperator *UNUSED(op))
FRS_delete_active_lineset(&srl->freestyleConfig);
- 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;
@@ -991,14 +993,10 @@ static int freestyle_lineset_move_exec(bContext *C, wmOperator *op)
SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
int dir = RNA_enum_get(op->ptr, "direction");
- if (dir == 1) {
- FRS_move_active_lineset_up(&srl->freestyleConfig);
+ if (FRS_move_active_lineset(&srl->freestyleConfig, dir)) {
+ DEG_id_tag_update(&scene->id, 0);
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
}
- else {
- FRS_move_active_lineset_down(&srl->freestyleConfig);
- }
- DAG_id_tag_update(&scene->id, 0);
- WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
return OPERATOR_FINISHED;
}
@@ -1006,8 +1004,8 @@ static int freestyle_lineset_move_exec(bContext *C, wmOperator *op)
void SCENE_OT_freestyle_lineset_move(wmOperatorType *ot)
{
static EnumPropertyItem direction_items[] = {
- {1, "UP", 0, "Up", ""},
- {-1, "DOWN", 0, "Down", ""},
+ {-1, "UP", 0, "Up", ""},
+ {1, "DOWN", 0, "Down", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -1024,7 +1022,8 @@ void SCENE_OT_freestyle_lineset_move(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
/* props */
- RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction", "Direction to move, UP or DOWN");
+ RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction",
+ "Direction to move the active line set towards");
}
static int freestyle_linestyle_new_exec(bContext *C, wmOperator *op)
@@ -1045,7 +1044,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;
@@ -1081,7 +1080,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;
@@ -1121,7 +1120,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;
@@ -1161,7 +1160,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;
@@ -1201,7 +1200,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;
@@ -1268,7 +1267,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;
@@ -1318,7 +1317,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;
@@ -1347,6 +1346,7 @@ static int freestyle_modifier_move_exec(bContext *C, wmOperator *op)
PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier);
LineStyleModifier *modifier = ptr.data;
int dir = RNA_enum_get(op->ptr, "direction");
+ bool changed = false;
if (!freestyle_linestyle_check_report(lineset, op->reports)) {
return OPERATOR_CANCELLED;
@@ -1354,23 +1354,26 @@ static int freestyle_modifier_move_exec(bContext *C, wmOperator *op)
switch (freestyle_get_modifier_type(&ptr)) {
case LS_MODIFIER_TYPE_COLOR:
- BKE_linestyle_color_modifier_move(lineset->linestyle, modifier, dir);
+ changed = BKE_linestyle_color_modifier_move(lineset->linestyle, modifier, dir);
break;
case LS_MODIFIER_TYPE_ALPHA:
- BKE_linestyle_alpha_modifier_move(lineset->linestyle, modifier, dir);
+ changed = BKE_linestyle_alpha_modifier_move(lineset->linestyle, modifier, dir);
break;
case LS_MODIFIER_TYPE_THICKNESS:
- BKE_linestyle_thickness_modifier_move(lineset->linestyle, modifier, dir);
+ changed = BKE_linestyle_thickness_modifier_move(lineset->linestyle, modifier, dir);
break;
case LS_MODIFIER_TYPE_GEOMETRY:
- BKE_linestyle_geometry_modifier_move(lineset->linestyle, modifier, dir);
+ changed = BKE_linestyle_geometry_modifier_move(lineset->linestyle, modifier, dir);
break;
default:
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);
- WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
+
+ if (changed) {
+ DEG_id_tag_update(&lineset->linestyle->id, 0);
+ WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
+ }
return OPERATOR_FINISHED;
}
@@ -1378,8 +1381,8 @@ static int freestyle_modifier_move_exec(bContext *C, wmOperator *op)
void SCENE_OT_freestyle_modifier_move(wmOperatorType *ot)
{
static EnumPropertyItem direction_items[] = {
- {1, "UP", 0, "Up", ""},
- {-1, "DOWN", 0, "Down", ""},
+ {-1, "UP", 0, "Up", ""},
+ {1, "DOWN", 0, "Down", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -1396,7 +1399,8 @@ void SCENE_OT_freestyle_modifier_move(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
/* props */
- RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction", "Direction to move, UP or DOWN");
+ RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction",
+ "Direction to move the chosen modifier towards");
}
static int freestyle_stroke_material_create_exec(bContext *C, wmOperator *op)
@@ -1488,7 +1492,7 @@ static int texture_slot_move_exec(bContext *C, wmOperator *op)
}
}
- DAG_id_tag_update(id, 0);
+ DEG_id_tag_update(id, 0);
WM_event_add_notifier(C, NC_TEXTURE, CTX_data_scene(C));
}
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c
index f11a8177bf8..42d914b1a71 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.c
@@ -48,12 +48,14 @@
#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_lamp.h"
#include "GPU_material.h"
#include "GPU_buffers.h"
@@ -64,6 +66,8 @@
#include "ED_render.h"
#include "ED_view3d.h"
+#include "WM_api.h"
+
#include "render_intern.h" // own include
extern Material defmaterial;
@@ -102,7 +106,7 @@ 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;
@@ -189,8 +193,12 @@ void ED_render_engine_changed(Main *bmain)
RE_FreePersistentData();
- for (scene = bmain->scene.first; scene; scene = scene->id.next)
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
ED_render_id_flush_update(bmain, &scene->id);
+ if (scene->nodetree) {
+ ntreeCompositUpdateRLayers(scene->nodetree);
+ }
+ }
}
/***************************** Updates ***********************************
@@ -340,7 +348,6 @@ static void material_changed(Main *bmain, Material *ma)
static void lamp_changed(Main *bmain, Lamp *la)
{
Object *ob;
- Material *ma;
/* icons */
BKE_icon_changed(BKE_icon_id_ensure(&la->id));
@@ -350,10 +357,6 @@ static void lamp_changed(Main *bmain, Lamp *la)
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);
}
@@ -374,6 +377,7 @@ static void texture_changed(Main *bmain, Tex *tex)
Lamp *la;
World *wo;
Scene *scene;
+ SceneLayer *sl;
Object *ob;
bNode *node;
bool texture_draw = false;
@@ -382,8 +386,11 @@ static void texture_changed(Main *bmain, Tex *tex)
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);
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
+ for (sl = scene->render_layers.first; sl; sl = sl->next) {
+ BKE_paint_invalidate_overlay_tex(scene, sl, tex);
+ }
+ }
/* find materials */
for (ma = bmain->mat.first; ma; ma = ma->id.next) {
@@ -464,18 +471,15 @@ static void texture_changed(Main *bmain, Tex *tex)
}
}
-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));
+
+ /* XXX temporary flag waiting for depsgraph proper tagging */
+ wo->update_flag = 1;
/* 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);
@@ -499,31 +503,15 @@ 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)
@@ -568,6 +556,6 @@ 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;
+ ret->render_to_view = render_view3d_draw;
}
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c
index 65f0fec50bc..e4bae9d78ea 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.c
@@ -44,6 +44,7 @@
#include "WM_types.h"
#include "ED_screen.h"
+#include "UI_interface.h"
#include "wm_window.h"
@@ -89,8 +90,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)
@@ -128,8 +131,8 @@ static ScrArea *find_area_image_empty(bContext *C)
/* new window uses x,y to set position */
ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
{
- wmWindow *win = CTX_wm_window(C);
Scene *scene = CTX_data_scene(C);
+ wmWindow *win = NULL;
ScrArea *sa = NULL;
SpaceImage *sima;
bool area_was_image = false;
@@ -138,25 +141,15 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
return NULL;
if (scene->r.displaymode == R_OUTPUT_WINDOW) {
- rcti rect;
- int sizex, sizey;
-
- sizex = 10 + (scene->r.xsch * scene->r.size) / 100;
- sizey = 40 + (scene->r.ysch * scene->r.size) / 100;
+ int sizex = 30 * UI_DPI_FAC + (scene->r.xsch * scene->r.size) / 100;
+ int sizey = 60 * UI_DPI_FAC + (scene->r.ysch * scene->r.size) / 100;
/* arbitrary... miniature image window views don't make much sense */
if (sizex < 320) sizex = 320;
if (sizey < 256) sizey = 256;
- /* some magic to calculate postition */
- /* pixelsize: mouse coords are in U.pixelsize units :/ */
- rect.xmin = (mx / U.pixelsize) + win->posx - sizex / 2;
- rect.ymin = (my / U.pixelsize) + win->posy - sizey / 2;
- rect.xmax = rect.xmin + sizex;
- rect.ymax = rect.ymin + sizey;
-
/* changes context! */
- if (WM_window_open_temp(C, &rect, WM_WINDOW_RENDER) == NULL) {
+ if (WM_window_open_temp(C, mx, my, sizex, sizey, WM_WINDOW_RENDER) == NULL) {
BKE_report(reports, RPT_ERROR, "Failed to open window!");
return NULL;
}
@@ -255,7 +248,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;
}
@@ -301,7 +294,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 {
@@ -310,8 +303,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..00a56f3dbc7
--- /dev/null
+++ b/source/blender/editors/scene/scene_edit.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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/scene/scene_edit.c
+ * \ingroup edscene
+ */
+
+#include <stdio.h>
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_layer.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 "BLI_compiler_attrs.h"
+#include "BLI_listbase.h"
+
+#include "BLT_translation.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_change_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;
+
+ if (scene->id.prev)
+ scene_new = scene->id.prev;
+ else if (scene->id.next)
+ scene_new = scene->id.next;
+ else
+ return false;
+
+ WM_window_change_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);
+ BKE_libblock_free(bmain, scene);
+
+ return true;
+}
+
+void ED_scene_exit(bContext *C)
+{
+ ED_object_editmode_exit(C, EM_FREEDATA | EM_DO_UNDO);
+}
+
+void ED_scene_changed_update(Main *bmain, bContext *C, Scene *scene_new, const bScreen *active_screen)
+{
+ /* XXX Just using active scene render-layer for workspace when switching,
+ * but workspace should remember the last one set. Could store render-layer
+ * per window-workspace combination (using WorkSpaceDataRelation) */
+ SceneLayer *layer_new = BLI_findlink(&scene_new->render_layers, scene_new->active_layer);
+
+ CTX_data_scene_set(C, scene_new);
+ BKE_workspace_render_layer_set(CTX_wm_workspace(C), layer_new);
+ BKE_scene_set_background(bmain, scene_new);
+ DEG_on_visible_update(bmain, false);
+
+ ED_screen_update_after_scene_change(active_screen, scene_new);
+ ED_render_engine_changed(bmain);
+ ED_update_for_newframe(bmain, scene_new, 1);
+
+ /* complete redraw */
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+}
+
+static bool scene_render_layer_remove_poll(
+ const Scene *scene, const SceneLayer *layer)
+{
+ const int act = BLI_findindex(&scene->render_layers, layer);
+
+ if (act == -1) {
+ return false;
+ }
+ else if ((scene->render_layers.first == scene->render_layers.last) &&
+ (scene->render_layers.first == layer))
+ {
+ /* ensure 1 layer is kept */
+ return false;
+ }
+
+ return true;
+}
+
+static void scene_render_layer_remove_unset_nodetrees(const Main *bmain, Scene *scene, SceneLayer *layer)
+{
+ int act_layer_index = BLI_findindex(&scene->render_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_render_layer_delete(
+ Main *bmain, Scene *scene, SceneLayer *layer,
+ ReportList *reports)
+{
+ if (scene_render_layer_remove_poll(scene, layer) == false) {
+ if (reports) {
+ BKE_reportf(reports, RPT_ERROR, "Render layer '%s' could not be removed from scene '%s'",
+ layer->name, scene->id.name + 2);
+ }
+
+ return false;
+ }
+
+ BLI_remlink(&scene->render_layers, layer);
+ BLI_assert(BLI_listbase_is_empty(&scene->render_layers) == false);
+ scene->active_layer = 0;
+
+ ED_workspace_render_layer_unset(bmain, layer, scene->render_layers.first);
+ scene_render_layer_remove_unset_nodetrees(bmain, scene, layer);
+
+ BKE_scene_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 ed86ffa5e16..02584a4611b 100644
--- a/source/blender/editors/screen/CMakeLists.txt
+++ b/source/blender/editors/screen/CMakeLists.txt
@@ -23,6 +23,7 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
+ ../../blenloader
../../blentranslation
../../bmesh
../../gpu
@@ -42,9 +43,12 @@ set(SRC
area.c
glutil.c
screen_context.c
+ screen_draw.c
screen_edit.c
screen_ops.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 8d058ed2081..5eb51667988 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -57,8 +57,11 @@
#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 "BLF_api.h"
#include "IMB_imbuf.h"
@@ -71,7 +74,7 @@
#include "screen_intern.h"
-extern void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3); /* xxx temp */
+extern void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3, const float color[4]); /* xxx temp */
/* general area and region code */
@@ -89,21 +92,30 @@ static void region_draw_emboss(const ARegion *ar, const rcti *scirct)
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBegin(GWN_PRIM_LINE_STRIP, 5);
+
/* right */
- glColor4ub(0, 0, 0, 30);
- sdrawline(rect.xmax, rect.ymin, rect.xmax, rect.ymax);
+ immAttrib4ub(color, 0, 0, 0, 30);
+ immVertex2f(pos, rect.xmax, rect.ymax);
+ immVertex2f(pos, rect.xmax, rect.ymin);
/* bottom */
- glColor4ub(0, 0, 0, 30);
- sdrawline(rect.xmin, rect.ymin, 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 */
- glColor4ub(255, 255, 255, 30);
- sdrawline(rect.xmin, rect.ymin, rect.xmin, rect.ymax);
+ immAttrib4ub(color, 255, 255, 255, 30);
+ immVertex2f(pos, rect.xmin, rect.ymax);
+
+ /* top */
+ immVertex2f(pos, rect.xmax, rect.ymax);
+
+ immEnd();
+ immUnbindProgram();
glDisable(GL_BLEND);
}
@@ -111,11 +123,11 @@ static void region_draw_emboss(const ARegion *ar, const rcti *scirct)
void ED_region_pixelspace(ARegion *ar)
{
wmOrtho2_region_pixelspace(ar);
- glLoadIdentity();
+ gpuLoadIdentity();
}
/* only exported for WM */
-void ED_region_do_listen(bScreen *sc, ScrArea *sa, ARegion *ar, wmNotifier *note)
+void ED_region_do_listen(bScreen *sc, ScrArea *sa, ARegion *ar, wmNotifier *note, const Scene *scene)
{
/* generic notes first */
switch (note->category) {
@@ -129,15 +141,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(sc, sa, ar, note, scene);
}
/* only exported for WM */
-void ED_area_do_listen(bScreen *sc, ScrArea *sa, wmNotifier *note)
+void ED_area_do_listen(bScreen *sc, ScrArea *sa, wmNotifier *note, const Scene *scene)
{
/* no generic notes? */
if (sa->type && sa->type->listener) {
- sa->type->listener(sc, sa, note);
+ sa->type->listener(sc, sa, note, scene);
}
}
@@ -206,15 +218,27 @@ 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;
+ unsigned 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);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
+ immAttrib4ub(color, 255, 0, 0, alpha_debug);
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ imm_draw_line_box(pos, click_rect.xmin, click_rect.ymin, click_rect.xmax, click_rect.ymax);
+
+ immAttrib4ub(color, 0, 255, 255, alpha_debug);
+ immBegin(GWN_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();
+
+ immUnbindProgram();
}
}
@@ -229,69 +253,96 @@ static void area_draw_azone(short x1, short y1, short x2, short y2)
dx = copysign(ceilf(0.3f * abs(dx)), dx);
dy = copysign(ceilf(0.3f * abs(dy)), dy);
- glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBegin(GWN_PRIM_LINES, 12);
+
+ immAttrib4ub(col, 255, 255, 255, 180);
+ immVertex2f(pos, x1, y2);
+ immVertex2f(pos, x2, y1);
+
+ immAttrib4ub(col, 255, 255, 255, 130);
+ immVertex2f(pos, x1, y2 - dy);
+ immVertex2f(pos, x2 - dx, y1);
+
+ immAttrib4ub(col, 255, 255, 255, 80);
+ immVertex2f(pos, x1, y2 - 2 * dy);
+ immVertex2f(pos, x2 - 2 * dx, y1);
- 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);
-
- 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);
+ immAttrib4ub(col, 0, 0, 0, 210);
+ immVertex2f(pos, x1, y2 + 1);
+ immVertex2f(pos, x2 + 1, y1);
+
+ immAttrib4ub(col, 0, 0, 0, 180);
+ immVertex2f(pos, x1, y2 - dy + 1);
+ immVertex2f(pos, x2 - dx + 1, y1);
+
+ immAttrib4ub(col, 0, 0, 0, 150);
+ immVertex2f(pos, x1, y2 - 2 * dy + 1);
+ immVertex2f(pos, x2 - 2 * dx + 1, y1);
+
+ immEnd();
+ immUnbindProgram();
glDisable(GL_LINE_SMOOTH);
- glDisable(GL_BLEND);
}
static void region_draw_azone_icon(AZone *az)
{
- 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);
+ float midx = az->x1 + (az->x2 - az->x1) * 0.5f;
+ float midy = az->y1 + (az->y2 - az->y1) * 0.5f;
- glColor4f(1.f, 1.f, 1.f, 0.8f);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
- gluQuadricDrawStyle(qobj, GLU_FILL);
- gluDisk(qobj, 0.0, 4.25f, 16, 1);
+ /* outlined circle */
+ GPU_enable_program_point_size(); /* TODO: make a fixed-size shader to avoid this */
+ immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
+ immUniform4f("outlineColor", 0.2f, 0.2f, 0.2f, 0.9f);
+ immUniform1f("outlineWidth", 1.0f);
+ immUniform1f("size", 9.5f);
+ immBegin(GWN_PRIM_POINTS, 1);
+ immVertex2f(pos, midx, midy);
+ immEnd();
+ immUnbindProgram();
+ GPU_disable_program_point_size();
- 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);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4f(0.2f, 0.2f, 0.2f, 0.9f);
+ immBegin(GWN_PRIM_LINES, 4);
+ immVertex2f(pos, midx, midy - 2);
+ immVertex2f(pos, midx, midy + 3);
+ immVertex2f(pos, midx - 2, midy);
+ immVertex2f(pos, midx + 3, midy);
+ immEnd();
+ immUnbindProgram();
}
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);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ glEnable(GL_BLEND);
+ 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();
+ glDisable(GL_BLEND);
}
static void region_draw_azone_tab_plus(AZone *az)
@@ -314,54 +365,41 @@ 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);
+ 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);
- glEnable(GL_BLEND);
-
- 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];
+ float col[4], black[4] = {0.0f, 0.0f, 0.0f, 0.5f};
glEnable(GL_BLEND);
UI_GetThemeColor3fv(TH_HEADER, col);
- glColor4f(col[0], col[1], col[2], 0.5f);
-
+ col[3] = 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);
+ UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
+ UI_draw_roundbox_shade_x(true, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f, col);
+ UI_draw_roundbox_aa(false, (float)az->x1, 0.3f + (float)az->y1, (float)az->x2, 0.3f + (float)az->y2, 4.0f, black);
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);
+ UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
+ UI_draw_roundbox_shade_x(true, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f, col);
+ UI_draw_roundbox_aa(false, (float)az->x1, 0.3f + (float)az->y1, (float)az->x2, 0.3f + (float)az->y2, 4.0f, black);
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);
+ UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT);
+ UI_draw_roundbox_shade_x(true, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f, col);
+ UI_draw_roundbox_aa(false, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, black);
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);
+ UI_draw_roundbox_corner_set(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
+ UI_draw_roundbox_shade_x(true, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f, col);
+ UI_draw_roundbox_aa(false, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, black);
break;
}
@@ -372,24 +410,24 @@ 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);
+ float color[4] = {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);
+ 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, color);
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);
+ 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, color);
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);
+ 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, color);
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);
+ 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, color);
break;
}
@@ -413,8 +451,8 @@ static void region_draw_azones(ScrArea *sa, ARegion *ar)
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glPushMatrix();
- glTranslatef(-ar->winrct.xmin, -ar->winrct.ymin, 0.0f);
+ gpuPushMatrix();
+ gpuTranslate2f(-ar->winrct.xmin, -ar->winrct.ymin);
for (az = sa->actionzones.first; az; az = az->next) {
/* test if action zone is over this region */
@@ -451,7 +489,7 @@ static void region_draw_azones(ScrArea *sa, ARegion *ar)
}
}
- glPopMatrix();
+ gpuPopMatrix();
glDisable(GL_BLEND);
}
@@ -511,7 +549,7 @@ void ED_region_do_draw(bContext *C, ARegion *ar)
UI_ThemeClearColor(TH_HEADER);
glClear(GL_COLOR_BUFFER_BIT);
- UI_ThemeColor(TH_TEXT);
+ UI_FontThemeColor(BLF_default(), TH_TEXT);
BLF_draw_default(UI_UNIT_X, 0.4f * UI_UNIT_Y, 0.0f, ar->headerstr, BLF_DRAW_STR_DUMMY_MAX);
}
else if (at->draw) {
@@ -528,9 +566,13 @@ 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,
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_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);
+ immUnbindProgram();
glDisable(GL_BLEND);
#endif
@@ -539,9 +581,11 @@ void ED_region_do_draw(bContext *C, ARegion *ar)
UI_blocklist_free_inactive(C, &ar->uiblocks);
if (sa) {
+ const bScreen *screen = WM_window_get_active_screen(win);
+
/* 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) {
+ if (((screen->state == SCREENFULL) && (ar->alignment == RGN_ALIGN_NONE)) == 0) {
region_draw_emboss(ar, &ar->winrct);
}
}
@@ -655,7 +699,7 @@ void ED_area_headerprint(ScrArea *sa, const char *str)
/* ************************************************************ */
-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;
@@ -1311,7 +1355,9 @@ static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti
* must be minimum '4' */
}
else {
- if (ELEM(win->screen->state, SCREENNORMAL, SCREENMAXIMIZED)) {
+ const bScreen *screen = WM_window_get_active_screen(win);
+
+ if (ELEM(screen->state, SCREENNORMAL, SCREENMAXIMIZED)) {
region_azone_add(sa, ar, alignment, false);
}
else {
@@ -1367,9 +1413,12 @@ static void region_subwindow(wmWindow *win, ARegion *ar, bool activate)
static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ListBase *handlers, int flag)
{
/* note, add-handler checks if it already exists */
-
+
/* XXX it would be good to have boundbox checks for some of these... */
if (flag & ED_KEYMAP_UI) {
+ wmKeyMap *keymap = WM_keymap_find(wm->defaultconf, "User Interface", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap);
+
/* user interface widgets */
UI_region_handlers_add(handlers);
}
@@ -1432,6 +1481,7 @@ static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ListBase *hand
/* called in screen_refresh, or screens_init, also area size changes */
void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa)
{
+ const bScreen *screen = WM_window_get_active_screen(win);
ARegion *ar;
rcti rect;
@@ -1450,7 +1500,7 @@ void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa)
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_azone_initialize(win, screen, sa);
/* region rect sizes */
rect = sa->totrct;
@@ -1470,8 +1520,9 @@ void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa)
/* default region handlers */
ed_default_handlers(wm, sa, &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 */
@@ -1746,7 +1797,7 @@ 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.5 * U.widget_unit, U.widget_unit,
+ 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, "");
return xco + 1.7 * U.widget_unit;
@@ -1965,8 +2016,12 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int c
/* 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);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColor((ar->type->regionid == RGN_TYPE_PREVIEW) ? TH_PREVIEW_BACK : TH_BACK);
+ immRecti(pos, 0, 0, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct) + 1);
+ immUnbindProgram();
glDisable(GL_BLEND);
}
else {
@@ -2070,22 +2125,37 @@ 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)
+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];
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.ymin = BLI_rcti_size_y(&ar->winrct) - header_height * num_lines;
rect.ymax = BLI_rcti_size_y(&ar->winrct);
/* setup scissor */
@@ -2095,17 +2165,28 @@ void ED_region_info_draw(ARegion *ar, const char *text, float fill_color[4], con
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);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_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();
glDisable(GL_BLEND);
/* 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);
@@ -2113,6 +2194,11 @@ void ED_region_info_draw(ARegion *ar, const char *text, float fill_color[4], con
glScissor(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
static const char *meta_data_list[] =
@@ -2281,11 +2367,11 @@ void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, const rctf *frame,
return;
/* find window pixel coordinates of origin */
- glPushMatrix();
+ gpuPushMatrix();
/* offset and zoom using ogl */
- glTranslatef(x, y, 0.0f);
- glScalef(zoomx, zoomy, 1.0f);
+ gpuTranslate2f(x, y);
+ gpuScale2f(zoomx, zoomy);
BLF_size(blf_mono_font, style->widgetlabel.points * 1.5f * U.pixelsize, U.dpi);
@@ -2295,17 +2381,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);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_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);
@@ -2317,23 +2406,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);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_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();
+ gpuPopMatrix();
}
void ED_region_grid_draw(ARegion *ar, float zoomx, float zoomy)
@@ -2343,11 +2435,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);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_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);
@@ -2367,33 +2464,52 @@ 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);
- /* the large resolution level */
- UI_ThemeColor(TH_BACK);
+ if (count_fine > 0) {
+ GWN_vertformat_clear(format);
+ pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBegin(GWN_PRIM_LINES, 4 * count_fine + 4 * count_large);
+
+ float theme_color[3];
+ UI_GetThemeColorShade3fv(TH_BACK, (int)(20.0f * (1.0f - blendfac)), theme_color);
+ immAttrib3fv(color, theme_color);
+ fac = 0.0f;
+
+ /* the fine resolution level */
+ for (int i = 0; i < count_fine; i++) {
+ immVertex2f(pos, x1, y1 * (1.0f - fac) + y2 * fac);
+ immVertex2f(pos, x2, y1 * (1.0f - fac) + y2 * fac);
+ immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y1);
+ immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y2);
+ fac += 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;
+ if (count_large > 0) {
+ UI_GetThemeColor3fv(TH_BACK, theme_color);
+ immAttrib3fv(color, theme_color);
+ fac = 0.0f;
+
+ /* the large resolution level */
+ for (int i = 0; i < count_large; i++) {
+ immVertex2f(pos, x1, y1 * (1.0f - fac) + y2 * fac);
+ immVertex2f(pos, x2, y1 * (1.0f - fac) + y2 * fac);
+ immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y1);
+ immVertex2f(pos, 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 */
@@ -2430,8 +2546,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);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_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)
@@ -2447,9 +2566,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);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_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));
}
@@ -2457,17 +2580,18 @@ 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;
-
- glColor4ub(128, 128, 255, 128);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4ub(128, 128, 255, 128);
- for (a = 0; a < num_segments; a++) {
- float x1, x2;
+ 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;
- x1 = (float)(points[a * 2] - sfra) / (efra - sfra + 1) * ar->winx;
- x2 = (float)(points[a * 2 + 1] - sfra + 1) / (efra - sfra + 1) * ar->winx;
-
- glRecti(x1, 0, x2, 8 * UI_DPI_FAC);
+ immRecti(pos, x1, 0, x2, 8 * UI_DPI_FAC);
+ /* TODO(merwin): use primitive restart to draw multiple rects more efficiently */
}
+
+ immUnbindProgram();
}
}
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index 93bac3f6660..7ce16efdb97 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -49,133 +49,11 @@
#include "IMB_imbuf_types.h"
#include "GPU_basic_shader.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.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)
@@ -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,24 +137,66 @@ 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)
+{
+ Gwn_VertFormat *vert_format = immVertexFormat();
+ state->pos = GWN_vertformat_attr_add(vert_format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ state->texco = GWN_vertformat_attr_add(vert_format, "texCoord", GWN_COMP_F32, 2, GWN_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);
glBindTexture(GL_TEXTURE_2D, texid);
@@ -401,18 +205,12 @@ 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;
-
+
offset_x = tex_w - seamless;
offset_y = tex_h - seamless;
-
+
nsubparts_x = (img_w + (offset_x - 1)) / (offset_x);
nsubparts_y = (img_h + (offset_y - 1)) / (offset_y);
@@ -420,7 +218,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");
@@ -436,6 +234,7 @@ void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h,
* it's possible to use GL_RGBA16F_ARB
*/
+ /* TODO viewport : remove extension */
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, tex_w, tex_h, 0, format, GL_FLOAT, NULL);
}
else {
@@ -443,6 +242,16 @@ void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h,
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;
@@ -474,7 +283,7 @@ void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h,
if (type == GL_FLOAT) {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_FLOAT, &f_rect[((size_t)subpart_y) * offset_y * img_w * components + subpart_x * offset_x * components]);
-
+
/* add an extra border of pixels so linear looks ok at edges of full image */
if (subpart_w < tex_w)
glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, format, GL_FLOAT, &f_rect[((size_t)subpart_y) * offset_y * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
@@ -485,7 +294,7 @@ void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h,
}
else {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_UNSIGNED_BYTE, &uc_rect[((size_t)subpart_y) * offset_y * img_w * components + subpart_x * offset_x * components]);
-
+
if (subpart_w < tex_w)
glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, format, GL_UNSIGNED_BYTE, &uc_rect[((size_t)subpart_y) * offset_y * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
if (subpart_h < tex_h)
@@ -494,158 +303,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(GWN_PRIM_TRI_FAN, 4);
+ immAttrib2f(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);
+ immAttrib2f(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);
+ immAttrib2f(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);
+ immAttrib2f(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();
}
}
+ if (state->do_shader_unbind) {
+ immUnbindProgram();
+ }
+
glBindTexture(GL_TEXTURE_2D, 0);
- glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
-
-#if defined(__APPLE__) && 0
- /* workaround for os x 10.5/10.6 driver bug (above) */
- glPixelZoom(xzoom, yzoom);
-#endif
+ 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 scissor[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_SCISSOR_BOX, scissor);
- draw_w = min_ii(img_w - off_x, ceil((scissor[2] - rast_x) / xzoom));
- draw_h = min_ii(img_h - off_y, ceil((scissor[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)
+ float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y,
+ float xzoom, float yzoom, float color[4])
{
- 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);
+ 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);
}
/* 2D Drawing Assistance */
@@ -664,15 +370,12 @@ void glaDefine2DArea(rcti *screen_rect)
* 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();
+ gpuOrtho2D(GLA_PIXEL_OFS, sc_w + GLA_PIXEL_OFS, GLA_PIXEL_OFS, sc_h + GLA_PIXEL_OFS);
+ gpuLoadIdentity();
}
+/* TODO(merwin): put the following 2D code to use, or build new 2D code inspired & informd by it */
+
#if 0 /* UNUSED */
struct gla2DDrawInfo {
@@ -726,8 +429,8 @@ gla2DDrawInfo *glaBegin2DDraw(rcti *screen_rect, rctf *world_rect)
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);
+ gpuGetProjectionMatrix(di->orig_projmat);
+ gpuGetModelViewMatrix(di->orig_viewmat);
di->screen_rect = *screen_rect;
if (world_rect) {
@@ -778,42 +481,14 @@ 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);
+ gpuLoadProjectionMatrix(di->orig_projmat);
+ gpuLoadMatrix(di->orig_viewmat);
MEM_freeN(di);
}
-#endif
+#endif /* UNUSED */
-/* 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;
-}
/* *************** glPolygonOffset hack ************* */
@@ -831,8 +506,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);
+ gpuGetProjectionMatrix(winmat);
/* dist is from camera to center point */
@@ -863,17 +537,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);
}
+
+ gpuLoadProjectionMatrix(winmat);
}
/* **** Color management helper functions for GLSL display/transform ***** */
@@ -883,7 +553,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 +573,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 +596,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 +607,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 +637,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 +651,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 +663,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 +672,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 +693,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(GWN_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(GWN_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(GWN_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(GWN_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 dc95886945c..d631401ab4d 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -38,6 +38,7 @@
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "BLI_utildefines.h"
@@ -47,8 +48,10 @@
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_gpencil.h"
+#include "BKE_layer.h"
#include "BKE_screen.h"
#include "BKE_sequencer.h"
+#include "BKE_workspace.h"
#include "RNA_access.h"
@@ -60,20 +63,8 @@
#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", "render_layer", "visible_objects", "visible_bases", "selectable_objects", "selectable_bases",
"selected_objects", "selected_bases",
"editable_objects", "editable_bases",
"selected_editable_objects", "selected_editable_bases",
@@ -92,20 +83,14 @@ const char *screen_context_dir[] = {
int ed_screen_context(const bContext *C, const char *member, bContextDataResult *result)
{
+ wmWindow *win = CTX_wm_window(C);
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
+ Scene *scene = WM_window_get_active_scene(win);
+ WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
+ SceneLayer *sl = BKE_scene_layer_from_workspace_get(workspace);
Object *obedit = scene->obedit;
- Object *obact = OBACT;
- base = BASACT;
-#endif
+ Object *obact = sl->basact ? sl->basact->object : NULL;
if (CTX_data_dir(member)) {
CTX_data_dir_set(result, screen_context_dir);
@@ -115,84 +100,100 @@ 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(sl, 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 = sl->object_bases.first; base; base = base->next) {
+ if (((base->flag & BASE_VISIBLED) != 0) && ((base->flag & BASE_SELECTABLED) != 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(sl, 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(sl, 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(sl, 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(sl, 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 = sl->object_bases.first; base; base = base->next) {
+ if ((base->flag & BASE_SELECTABLED) != 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 = sl->object_bases.first; base; base = base->next) {
+ 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 = sl->object_bases.first; base; base = base->next) {
+ 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 = sl->object_bases.first; base; base = base->next) {
+ if ((base->flag & BASE_VISIBLED) != 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);
}
}
}
@@ -344,8 +345,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 (sl->basact)
+ CTX_data_pointer_set(result, &scene->id, &RNA_ObjectBase, sl->basact);
return 1;
}
@@ -515,7 +516,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
bGPDbrush *brush = BKE_gpencil_brush_getactive(scene->toolsettings);
if (brush) {
- CTX_data_pointer_set(result, NULL, &RNA_GPencilBrush, brush);
+ CTX_data_pointer_set(result, &scene->id, &RNA_GPencilBrush, brush);
return 1;
}
}
diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c
new file mode 100644
index 00000000000..5690076fedb
--- /dev/null
+++ b/source/blender/editors/screen/screen_draw.c
@@ -0,0 +1,496 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_draw.c
+ * \ingroup edscr
+ */
+
+#include "ED_screen.h"
+
+#include "GPU_framebuffer.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+
+#include "WM_api.h"
+#include "WM_types.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, unsigned int pos)
+{
+ 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;
+ w = height / 4;
+ }
+ else {
+ h = width / 8;
+ w = width / 4;
+ }
+
+ points[0].x = sa->v1->vec.x;
+ points[0].y = sa->v1->vec.y + height / 2;
+
+ points[1].x = sa->v1->vec.x;
+ points[1].y = sa->v1->vec.y;
+
+ points[2].x = sa->v4->vec.x - w;
+ points[2].y = sa->v4->vec.y;
+
+ points[3].x = sa->v4->vec.x - w;
+ points[3].y = sa->v4->vec.y + height / 2 - 2 * h;
+
+ points[4].x = sa->v4->vec.x - 2 * w;
+ points[4].y = sa->v4->vec.y + height / 2;
+
+ points[5].x = sa->v4->vec.x - w;
+ points[5].y = sa->v4->vec.y + height / 2 + 2 * h;
+
+ points[6].x = sa->v3->vec.x - w;
+ points[6].y = sa->v3->vec.y;
+
+ points[7].x = sa->v2->vec.x;
+ points[7].y = sa->v2->vec.y;
+
+ points[8].x = sa->v4->vec.x;
+ points[8].y = sa->v4->vec.y + height / 2 - h;
+
+ points[9].x = sa->v4->vec.x;
+ points[9].y = sa->v4->vec.y + height / 2 + h;
+
+ if (dir == 'l') {
+ /* when direction is left, then we flip direction of arrow */
+ float cx = sa->v1->vec.x + width;
+ for (i = 0; i < 10; i++) {
+ points[i].x -= cx;
+ points[i].x = -points[i].x;
+ points[i].x += sa->v1->vec.x;
+ }
+ }
+
+ immBegin(GWN_PRIM_TRI_FAN, 5);
+
+ for (i = 0; i < 5; i++) {
+ immVertex2f(pos, points[i].x, points[i].y);
+ }
+
+ immEnd();
+
+ immBegin(GWN_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, unsigned int pos)
+{
+ 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;
+ w = height / 8;
+ }
+ else {
+ h = width / 4;
+ w = width / 8;
+ }
+
+ points[0].x = sa->v1->vec.x + width / 2;
+ points[0].y = sa->v3->vec.y;
+
+ points[1].x = sa->v2->vec.x;
+ points[1].y = sa->v2->vec.y;
+
+ points[2].x = sa->v1->vec.x;
+ points[2].y = sa->v1->vec.y + h;
+
+ points[3].x = sa->v1->vec.x + width / 2 - 2 * w;
+ points[3].y = sa->v1->vec.y + h;
+
+ points[4].x = sa->v1->vec.x + width / 2;
+ points[4].y = sa->v1->vec.y + 2 * h;
+
+ points[5].x = sa->v1->vec.x + width / 2 + 2 * w;
+ points[5].y = sa->v1->vec.y + h;
+
+ points[6].x = sa->v4->vec.x;
+ points[6].y = sa->v4->vec.y + h;
+
+ points[7].x = sa->v3->vec.x;
+ points[7].y = sa->v3->vec.y;
+
+ points[8].x = sa->v1->vec.x + width / 2 - w;
+ points[8].y = sa->v1->vec.y;
+
+ points[9].x = sa->v1->vec.x + width / 2 + w;
+ points[9].y = sa->v1->vec.y;
+
+ if (dir == 'u') {
+ /* when direction is up, then we flip direction of arrow */
+ float cy = sa->v1->vec.y + height;
+ for (i = 0; i < 10; i++) {
+ points[i].y -= cy;
+ points[i].y = -points[i].y;
+ points[i].y += sa->v1->vec.y;
+ }
+ }
+
+ immBegin(GWN_PRIM_TRI_FAN, 5);
+
+ for (i = 0; i < 5; i++) {
+ immVertex2f(pos, points[i].x, points[i].y);
+ }
+
+ immEnd();
+
+ immBegin(GWN_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, unsigned int pos)
+{
+ if (dir == 'u' || dir == 'd') {
+ draw_vertical_join_shape(sa, dir, pos);
+ }
+ else {
+ draw_horizontal_join_shape(sa, dir, pos);
+ }
+}
+
+/**
+ * Draw screen area darker with arrow (visualization of future joining).
+ */
+static void scrarea_draw_shape_dark(ScrArea *sa, char dir, unsigned int pos)
+{
+ glBlendFunc(GL_SRC_ALPHA, GL_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), unsigned int pos)
+{
+ glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA);
+ /* value 181 was hardly computed: 181~105 */
+ immUniformColor4ub(255, 255, 255, 50);
+ /* draw_join_shape(sa, dir); */
+
+ 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, unsigned int pos)
+{
+ int count = 0;
+
+ if (x2 < sizex - 1) count += 2;
+ if (x1 > 0) count += 2;
+ if (y2 < sizey - 1) count += 2;
+ if (y1 > 0) count += 2;
+
+ if (count == 0) {
+ return;
+ }
+
+ immBegin(GWN_PRIM_LINES, count);
+
+ /* right border area */
+ if (x2 < sizex - 1) {
+ immVertex2f(pos, x2, y1);
+ immVertex2f(pos, x2, y2);
+ }
+
+ /* left border area */
+ if (x1 > 0) { /* otherwise it draws the emboss of window over */
+ immVertex2f(pos, x1, y1);
+ immVertex2f(pos, x1, y2);
+ }
+
+ /* top border area */
+ if (y2 < sizey - 1) {
+ immVertex2f(pos, x1, y2);
+ immVertex2f(pos, x2, y2);
+ }
+
+ /* bottom border area */
+ if (y1 > 0) {
+ immVertex2f(pos, x1, y1);
+ immVertex2f(pos, x2, y1);
+ }
+
+ immEnd();
+}
+
+/**
+ * \brief Screen edges drawing.
+ */
+static void drawscredge_area(ScrArea *sa, int sizex, int sizey, unsigned int pos)
+{
+ 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, pos);
+}
+
+/**
+ * Only for edge lines between areas, and the blended join arrows.
+ */
+void ED_screen_draw(wmWindow *win)
+{
+ bScreen *screen = WM_window_get_active_screen(win);
+ const int winsize_x = WM_window_pixels_x(win);
+ const int winsize_y = WM_window_pixels_y(win);
+
+ ScrArea *sa;
+ ScrArea *sa1 = NULL;
+ ScrArea *sa2 = NULL;
+ ScrArea *sa3 = NULL;
+
+ wmSubWindowSet(win, screen->mainwin);
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ /* 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);
+ immUniformColor3ub(0x50, 0x50, 0x50);
+
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ drawscredge_area(sa, winsize_x, winsize_y, pos);
+ }
+ }
+
+ glLineWidth(1);
+ immUniformColor3ub(0, 0, 0);
+
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ drawscredge_area(sa, winsize_x, winsize_y, pos);
+
+ /* gather area split/join info */
+ if (sa->flag & AREA_FLAG_DRAWJOINFROM) sa1 = sa;
+ if (sa->flag & AREA_FLAG_DRAWJOINTO) sa2 = sa;
+ if (sa->flag & (AREA_FLAG_DRAWSPLIT_H | AREA_FLAG_DRAWSPLIT_V)) sa3 = sa;
+ }
+
+ /* blended join arrow */
+ if (sa1 && sa2) {
+ int dir = area_getorientation(sa1, sa2);
+ int dira = -1;
+ if (dir != -1) {
+ switch (dir) {
+ case 0: /* W */
+ dir = 'r';
+ dira = 'l';
+ break;
+ case 1: /* N */
+ dir = 'd';
+ dira = 'u';
+ break;
+ case 2: /* E */
+ dir = 'l';
+ dira = 'r';
+ break;
+ case 3: /* S */
+ dir = 'u';
+ dira = 'd';
+ break;
+ }
+ }
+
+ glEnable(GL_BLEND);
+
+ scrarea_draw_shape_dark(sa2, dir, pos);
+ scrarea_draw_shape_light(sa1, dira, pos);
+
+ glDisable(GL_BLEND);
+ }
+
+ /* splitpoint */
+ if (sa3) {
+ glEnable(GL_BLEND);
+ immUniformColor4ub(255, 255, 255, 100);
+
+ immBegin(GWN_PRIM_LINES, 2);
+
+ if (sa3->flag & AREA_FLAG_DRAWSPLIT_H) {
+ immVertex2f(pos, sa3->totrct.xmin, win->eventstate->y);
+ immVertex2f(pos, sa3->totrct.xmax, win->eventstate->y);
+
+ immEnd();
+
+ immUniformColor4ub(0, 0, 0, 100);
+
+ immBegin(GWN_PRIM_LINES, 2);
+
+ immVertex2f(pos, sa3->totrct.xmin, win->eventstate->y + 1);
+ immVertex2f(pos, sa3->totrct.xmax, win->eventstate->y + 1);
+ }
+ else {
+ immVertex2f(pos, win->eventstate->x, sa3->totrct.ymin);
+ immVertex2f(pos, win->eventstate->x, sa3->totrct.ymax);
+
+ immEnd();
+
+ immUniformColor4ub(0, 0, 0, 100);
+
+ immBegin(GWN_PRIM_LINES, 2);
+
+ immVertex2f(pos, win->eventstate->x + 1, sa3->totrct.ymin);
+ immVertex2f(pos, win->eventstate->x + 1, sa3->totrct.ymax);
+ }
+
+ immEnd();
+
+ glDisable(GL_BLEND);
+ }
+
+ immUnbindProgram();
+
+ screen->do_draw = false;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* 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;
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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(GWN_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 */
+ gpuPushMatrix();
+ gpuTranslate2f(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);
+
+ gpuPopMatrix();
+}
+
+/**
+ * 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, err_out);
+
+ GPU_offscreen_bind(offscreen, true);
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_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 677a6472c72..3e4b4b501ce 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -34,6 +34,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_scene_types.h"
+#include "DNA_workspace_types.h"
#include "DNA_userdef_types.h"
#include "BLI_math.h"
@@ -41,7 +42,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
+#include "BKE_icons.h"
#include "BKE_image.h"
#include "BKE_global.h"
#include "BKE_library.h"
@@ -50,9 +51,7 @@
#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"
@@ -266,7 +265,7 @@ bool scredge_is_horizontal(ScrEdge *se)
}
/* need win size to make sure not to include edges along screen edge */
-ScrEdge *screen_find_active_scredge(bScreen *sc,
+ScrEdge *screen_find_active_scredge(const bScreen *sc,
const int winsize_x, const int winsize_y,
const int mx, const int my)
{
@@ -457,39 +456,35 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge)
return newa;
}
-/* empty screen, with 1 dummy area without spacedata */
-/* uses window size */
-bScreen *ED_screen_add(wmWindow *win, Scene *scene, const char *name)
+/**
+ * Empty screen, with 1 dummy area without spacedata. Uses window size.
+ */
+bScreen *screen_add(const char *name, const int winsize_x, const int winsize_y)
{
- 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(G.main, ID_SCR, name);
- 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);
-
+
screen_addedge(sc, sv1, sv2);
screen_addedge(sc, sv2, sv3);
screen_addedge(sc, sv3, sv4);
screen_addedge(sc, sv4, sv1);
-
+
/* dummy type, no spacedata */
screen_addarea(sc, sv1, sv2, sv3, sv4, HEADERDOWN, 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;
@@ -532,7 +527,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;
}
@@ -615,7 +619,9 @@ int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2)
screen_delarea(C, scr, sa2);
removedouble_scrverts(scr);
sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
-
+ /* Update preview thumbnail */
+ BKE_icon_changed(scr->id.icon_id);
+
return 1;
}
@@ -766,7 +772,9 @@ static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y)
/* lower edge */
const int yval = sa->v2->vec.y - headery_init;
se = screen_findedge(sc, sa->v4, sa->v1);
- select_connected_scredge(sc, se);
+ 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) {
@@ -779,7 +787,9 @@ static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y)
/* upper edge */
const int yval = sa->v1->vec.y + headery_init;
se = screen_findedge(sc, sa->v2, sa->v3);
- select_connected_scredge(sc, se);
+ 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) {
@@ -834,241 +844,21 @@ static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y)
}
-/* *********************** DRAWING **************************************** */
-
-/* draw vertical shape visualizing future joining (left as well
- * right direction of future joining) */
-static void draw_horizontal_join_shape(ScrArea *sa, char dir)
-{
- 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;
- w = height / 4;
- }
- else {
- h = width / 8;
- w = width / 4;
- }
-
- points[0].x = sa->v1->vec.x;
- points[0].y = sa->v1->vec.y + height / 2;
-
- points[1].x = sa->v1->vec.x;
- points[1].y = sa->v1->vec.y;
-
- points[2].x = sa->v4->vec.x - w;
- points[2].y = sa->v4->vec.y;
-
- points[3].x = sa->v4->vec.x - w;
- points[3].y = sa->v4->vec.y + height / 2 - 2 * h;
-
- points[4].x = sa->v4->vec.x - 2 * w;
- points[4].y = sa->v4->vec.y + height / 2;
-
- points[5].x = sa->v4->vec.x - w;
- points[5].y = sa->v4->vec.y + height / 2 + 2 * h;
-
- points[6].x = sa->v3->vec.x - w;
- points[6].y = sa->v3->vec.y;
-
- points[7].x = sa->v2->vec.x;
- points[7].y = sa->v2->vec.y;
-
- points[8].x = sa->v4->vec.x;
- points[8].y = sa->v4->vec.y + height / 2 - h;
-
- points[9].x = sa->v4->vec.x;
- points[9].y = sa->v4->vec.y + height / 2 + h;
-
- if (dir == 'l') {
- /* when direction is left, then we flip direction of arrow */
- float cx = sa->v1->vec.x + width;
- for (i = 0; i < 10; i++) {
- points[i].x -= cx;
- points[i].x = -points[i].x;
- points[i].x += sa->v1->vec.x;
- }
- }
-
- 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);
-}
-
-/* draw vertical shape visualizing future joining (up/down direction) */
-static void draw_vertical_join_shape(ScrArea *sa, char dir)
-{
- 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;
- w = height / 8;
- }
- else {
- h = width / 4;
- w = width / 8;
- }
-
- points[0].x = sa->v1->vec.x + width / 2;
- points[0].y = sa->v3->vec.y;
-
- points[1].x = sa->v2->vec.x;
- points[1].y = sa->v2->vec.y;
-
- points[2].x = sa->v1->vec.x;
- points[2].y = sa->v1->vec.y + h;
-
- points[3].x = sa->v1->vec.x + width / 2 - 2 * w;
- points[3].y = sa->v1->vec.y + h;
-
- points[4].x = sa->v1->vec.x + width / 2;
- points[4].y = sa->v1->vec.y + 2 * h;
-
- points[5].x = sa->v1->vec.x + width / 2 + 2 * w;
- points[5].y = sa->v1->vec.y + h;
-
- points[6].x = sa->v4->vec.x;
- points[6].y = sa->v4->vec.y + h;
-
- points[7].x = sa->v3->vec.x;
- points[7].y = sa->v3->vec.y;
-
- points[8].x = sa->v1->vec.x + width / 2 - w;
- points[8].y = sa->v1->vec.y;
-
- points[9].x = sa->v1->vec.x + width / 2 + w;
- points[9].y = sa->v1->vec.y;
-
- if (dir == 'u') {
- /* when direction is up, then we flip direction of arrow */
- float cy = sa->v1->vec.y + height;
- for (i = 0; i < 10; i++) {
- points[i].y -= cy;
- points[i].y = -points[i].y;
- points[i].y += sa->v1->vec.y;
- }
- }
-
- 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);
-}
-
-/* draw join shape due to direction of joining */
-static void draw_join_shape(ScrArea *sa, char dir)
-{
- if (dir == 'u' || dir == 'd')
- draw_vertical_join_shape(sa, dir);
- else
- draw_horizontal_join_shape(sa, dir);
-}
-
-/* draw screen area darker with arrow (visualization of future joining) */
-static void scrarea_draw_shape_dark(ScrArea *sa, char dir)
-{
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glColor4ub(0, 0, 0, 50);
- draw_join_shape(sa, dir);
-}
-
-/* draw screen area ligher with arrow shape ("eraser" of previous dark shape) */
-static void scrarea_draw_shape_light(ScrArea *sa, char UNUSED(dir))
-{
- glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA);
- /* value 181 was hardly computed: 181~105 */
- glColor4ub(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);
-}
-
-static void drawscredge_area_draw(int sizex, int sizey, short x1, short y1, short x2, short y2)
-{
- /* right border area */
- if (x2 < sizex - 1) {
- glVertex2s(x2, y1);
- glVertex2s(x2, y2);
- }
-
- /* left border area */
- if (x1 > 0) { /* otherwise it draws the emboss of window over */
- glVertex2s(x1, y1);
- glVertex2s(x1, y2);
- }
-
- /* top border area */
- if (y2 < sizey - 1) {
- glVertex2s(x1, y2);
- glVertex2s(x2, y2);
- }
-
- /* bottom border area */
- if (y1 > 0) {
- glVertex2s(x1, y1);
- glVertex2s(x2, y1);
- }
-}
-
-/** screen edges drawing **/
-static void drawscredge_area(ScrArea *sa, int sizex, int sizey)
-{
- 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);
-}
/* ****************** EXPORTED API TO OTHER MODULES *************************** */
-bScreen *ED_screen_duplicate(wmWindow *win, bScreen *sc)
-{
- bScreen *newsc;
-
- if (sc->state != SCREENNORMAL) return NULL; /* XXX handle this case! */
-
- /* make new empty screen: */
- newsc = ED_screen_add(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) {
+ bScreen *screen = WM_window_get_active_screen(win);
+
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
if (ar->swinid == swinid) {
if (swin_changed || (ar->type && ar->type->event_cursor)) {
+ if (WM_manipulatormap_cursor_set(ar->manipulator_map, win)) {
+ return;
+ }
ED_region_cursor_set(win, sa, ar);
}
return;
@@ -1080,19 +870,20 @@ 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)
@@ -1101,100 +892,6 @@ void ED_screen_do_listen(bContext *C, wmNotifier *note)
}
}
-/* only for edge lines between areas, and the blended join arrows */
-void ED_screen_draw(wmWindow *win)
-{
- const int winsize_x = WM_window_pixels_x(win);
- const int winsize_y = WM_window_pixels_y(win);
-
- ScrArea *sa;
- ScrArea *sa1 = NULL;
- ScrArea *sa2 = NULL;
- ScrArea *sa3 = NULL;
-
- 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();
- }
-
- 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);
-
- /* gather area split/join info */
- if (sa->flag & AREA_FLAG_DRAWJOINFROM) sa1 = sa;
- if (sa->flag & AREA_FLAG_DRAWJOINTO) sa2 = sa;
- if (sa->flag & (AREA_FLAG_DRAWSPLIT_H | AREA_FLAG_DRAWSPLIT_V)) sa3 = sa;
- }
- glEnd();
-
- /* blended join arrow */
- if (sa1 && sa2) {
- int dir = area_getorientation(sa1, sa2);
- int dira = -1;
- if (dir != -1) {
- switch (dir) {
- case 0: /* W */
- dir = 'r';
- dira = 'l';
- break;
- case 1: /* N */
- dir = 'd';
- dira = 'u';
- break;
- case 2: /* E */
- dir = 'l';
- dira = 'r';
- break;
- case 3: /* S */
- dir = 'u';
- dira = 'd';
- break;
- }
- }
- glEnable(GL_BLEND);
- scrarea_draw_shape_dark(sa2, dir);
- scrarea_draw_shape_light(sa1, dira);
- glDisable(GL_BLEND);
- }
-
- /* splitpoint */
- if (sa3) {
- glEnable(GL_BLEND);
- glBegin(GL_LINES);
- glColor4ub(255, 255, 255, 100);
-
- if (sa3->flag & AREA_FLAG_DRAWSPLIT_H) {
- glVertex2s(sa3->totrct.xmin, win->eventstate->y);
- glVertex2s(sa3->totrct.xmax, win->eventstate->y);
- glColor4ub(0, 0, 0, 100);
- glVertex2s(sa3->totrct.xmin, win->eventstate->y + 1);
- glVertex2s(sa3->totrct.xmax, win->eventstate->y + 1);
- }
- else {
- glVertex2s(win->eventstate->x, sa3->totrct.ymin);
- glVertex2s(win->eventstate->x, sa3->totrct.ymax);
- glColor4ub(0, 0, 0, 100);
- glVertex2s(win->eventstate->x + 1, sa3->totrct.ymin);
- glVertex2s(win->eventstate->x + 1, sa3->totrct.ymax);
- }
- glEnd();
- glDisable(GL_BLEND);
- }
-
- win->screen->do_draw = false;
-}
-
/* helper call for below, dpi changes headers */
static void screen_refresh_headersizes(void)
{
@@ -1210,7 +907,9 @@ static void screen_refresh_headersizes(void)
/* make this screen usable */
/* 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);
@@ -1224,34 +923,37 @@ void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
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);
+ screen_test_scale(screen, winsize_x, winsize_y);
- if (win->screen->mainwin == 0) {
- win->screen->mainwin = wm_subwindow_open(win, &winrct, false);
+ if (screen->mainwin == 0) {
+ screen->mainwin = wm_subwindow_open(win, &winrct, false);
}
else {
- wm_subwindow_position(win, win->screen->mainwin, &winrct, false);
+ wm_subwindow_position(win, screen->mainwin, &winrct, false);
}
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
/* set spacetype and region callbacks, calls init() */
/* sets subwindows for regions, adds handlers */
ED_area_initialize(wm, win, sa);
}
/* 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, ... */
@@ -1260,10 +962,10 @@ void ED_screens_initialize(wmWindowManager *wm)
wmWindow *win;
for (win = wm->windows.first; win; win = win->next) {
-
- if (win->screen == NULL)
- win->screen = G.main->screen.first;
-
+ if (WM_window_get_active_workspace(win) == NULL) {
+ WM_window_set_active_workspace(win, G.main->workspaces.first);
+ }
+
ED_screen_refresh(wm, win);
}
}
@@ -1274,25 +976,28 @@ void ED_screens_initialize(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);
+ WM_event_modal_handler_region_replace(win, ar, NULL);
if (ar->swinid) {
- wm_subwindow_close(CTX_wm_window(C), ar->swinid);
+ wm_subwindow_close(win, ar->swinid);
ar->swinid = 0;
}
-
+
if (ar->headerstr) {
MEM_freeN(ar->headerstr);
ar->headerstr = NULL;
}
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;
}
@@ -1302,6 +1007,7 @@ void ED_region_exit(bContext *C, ARegion *ar)
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;
@@ -1309,10 +1015,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);
}
@@ -1344,7 +1053,7 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
/* 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);
}
@@ -1360,13 +1069,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, wmEvent *event)
{
+ const bScreen *screen = WM_window_get_active_screen(win);
const int winsize_x = WM_window_pixels_x(win);
const int winsize_y = WM_window_pixels_y(win);
AZone *az = NULL;
ScrArea *sa;
- for (sa = win->screen->areabase.first; sa; sa = sa->next)
+ for (sa = screen->areabase.first; sa; sa = sa->next)
if ((az = is_in_area_actionzone(sa, &event->x)))
break;
@@ -1381,7 +1091,7 @@ static void screen_cursor_set(wmWindow *win, wmEvent *event)
}
}
else {
- ScrEdge *actedge = screen_find_active_scredge(win->screen, winsize_x, winsize_y, event->x, event->y);
+ ScrEdge *actedge = screen_find_active_scredge(screen, winsize_x, winsize_y, event->x, event->y);
if (actedge) {
if (scredge_is_horizontal(actedge))
@@ -1400,9 +1110,9 @@ static void screen_cursor_set(wmWindow *win, wmEvent *event)
void ED_screen_set_subwinactive(bContext *C, wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
-
- if (win->screen) {
- bScreen *scr = win->screen;
+ bScreen *scr = WM_window_get_active_screen(win);
+
+ if (scr) {
ScrArea *sa;
ARegion *ar;
int oldswin = scr->subwinactive;
@@ -1455,7 +1165,7 @@ void ED_screen_set_subwinactive(bContext *C, wmEvent *event)
/* 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);
+ UI_screen_free_active_but(C, scr);
}
else
region_cursor_set(win, scr->subwinactive, false);
@@ -1483,177 +1193,120 @@ int ED_screen_area_active(const bContext *C)
return 0;
}
+
+/* -------------------------------------------------------------------- */
+/* 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->full == screen) {
+ return screen_iter;
+ }
+ }
+
+ return screen;
+}
+
/**
- * operator call, WM + Window + screen already existed before
- *
- * \warning Do NOT call in area/region queues!
- * \returns success.
+ * \return the screen to activate.
+ * \warning The returned screen may not always equal \a screen_new!
*/
-bool ED_screen_set(bContext *C, bScreen *sc)
+bScreen *screen_change_prepare(bScreen *screen_old, bScreen *screen_new, Main *bmain, bContext *C, wmWindow *win)
{
- Main *bmain = CTX_data_main(C);
- wmWindowManager *wm = CTX_wm_manager(C);
- wmWindow *win = CTX_wm_window(C);
- bScreen *oldscreen = CTX_wm_screen(C);
-
/* validate screen, it's called with notifier reference */
- if (BLI_findindex(&bmain->screen, sc) == -1) {
- return true;
+ if (BLI_findindex(&bmain->screen, screen_new) == -1) {
+ return NULL;
}
- 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;
- }
- }
+ if (ELEM(screen_new->state, SCREENMAXIMIZED, SCREENFULL)) {
+ screen_new = screen_fullscreen_find_associated_normal_screen(bmain, screen_new);
}
/* check for valid winid */
- if (sc->winid != 0 && sc->winid != win->winid) {
- return false;
+ if (!(screen_new->winid == 0 || screen_new->winid == win->winid)) {
+ return NULL;
}
-
- if (oldscreen != sc) {
- wmTimer *wt = oldscreen->animtimer;
- ScrArea *sa;
- Scene *oldscene = oldscreen->scene;
+
+ if (screen_old != screen_new) {
+ wmTimer *wt = screen_old->animtimer;
/* remove handlers referencing areas in old screen */
- for (sa = oldscreen->areabase.first; sa; sa = sa->next) {
+ for (ScrArea *sa = screen_old->areabase.first; sa; sa = sa->next) {
WM_event_remove_area_handler(&win->modalhandlers, sa);
}
/* we put timer to sleep, so screen_exit has to think there's no timer */
- oldscreen->animtimer = NULL;
+ screen_old->animtimer = NULL;
if (wt) {
- WM_event_timer_sleep(wm, win, wt, true);
+ WM_event_timer_sleep(CTX_wm_manager(C), win, wt, true);
}
-
- ED_screen_exit(C, win, oldscreen);
+ ED_screen_exit(C, win, screen_old);
/* Same scene, "transfer" playback to new screen. */
if (wt) {
- if (oldscene == sc->scene) {
- sc->animtimer = wt;
- }
- /* Else, stop playback. */
- else {
- oldscreen->animtimer = wt;
- ED_screen_animation_play(C, 0, 0);
- }
- }
-
- 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);
+ screen_new->animtimer = wt;
}
- /* 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);
+ return screen_new;
}
- return true;
+ return NULL;
}
-static bool ed_screen_used(wmWindowManager *wm, bScreen *sc)
+void screen_changed_update(bContext *C, wmWindow *win, bScreen *sc)
{
- wmWindow *win;
+ 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);
- for (win = wm->windows.first; win; win = win->next) {
- if (win->screen == sc) {
- return true;
- }
+ CTX_wm_window_set(C, win); /* stores C->wm.screen... hrmf */
- if (ELEM(win->screen->state, SCREENMAXIMIZED, SCREENFULL)) {
- ScrArea *sa = win->screen->areabase.first;
- if (sa->full == sc) {
- return true;
- }
- }
- }
+ ED_screen_refresh(CTX_wm_manager(C), win);
- return false;
+ 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);
+
+ /* makes button hilites work */
+ WM_event_add_mousemove(C);
}
-/* only call outside of area/region loops */
-bool ED_screen_delete(bContext *C, bScreen *sc)
+
+/**
+ * \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);
- wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
- bScreen *newsc;
-
- /* don't allow deleting temp fullscreens for now */
- if (ELEM(sc->state, SCREENMAXIMIZED, SCREENFULL)) {
- return false;
- }
-
- /* 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 */
-
- for (newsc = sc->id.prev; newsc; newsc = newsc->id.prev)
- if (!ed_screen_used(wm, newsc) && !newsc->temp)
- break;
-
- if (!newsc) {
- for (newsc = sc->id.next; newsc; newsc = newsc->id.next)
- if (!ed_screen_used(wm, newsc) && !newsc->temp)
- break;
- }
+ bScreen *screen_old = CTX_wm_screen(C);
+ bScreen *screen_new = screen_change_prepare(screen_old, sc, bmain, C, win);
- if (!newsc) {
- return false;
- }
-
- ED_screen_set(C, newsc);
+ if (screen_new) {
+ WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
+ WM_window_set_active_screen(win, workspace, sc);
+ screen_changed_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, 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);
+ v3d->camera = BKE_scene_camera_find(scene);
// XXX if (sc == curscreen) handle_view3d_lock();
if (!v3d->camera) {
ARegion *ar;
@@ -1677,90 +1330,16 @@ 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_update_after_scene_change(const bScreen *screen, Scene *scene_new)
{
- Main *bmain = CTX_data_main(C);
- bScreen *sc;
-
- if (screen == NULL)
- return;
-
- if (ed_screen_used(CTX_wm_manager(C), screen))
- ED_object_editmode_exit(C, EM_FREEDATA | EM_DO_UNDO);
-
- 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;
+ 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_new, sa, v3d);
}
-
}
}
-
- // 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;
- }
- }
- }
-
- 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;
-
- 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);
-
- BKE_libblock_free(bmain, scene);
-
- return true;
}
ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
@@ -1867,6 +1446,7 @@ void ED_screen_full_restore(bContext *C, ScrArea *sa)
ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const short state)
{
wmWindowManager *wm = CTX_wm_manager(C);
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
bScreen *sc, *oldscreen;
ARegion *ar;
@@ -1888,11 +1468,12 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
}
if (sa && sa->full) {
+ WorkSpaceLayout *layout_old = WM_window_get_active_layout(win);
/* restoring back to SCREENNORMAL */
ScrArea *old;
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;
@@ -1920,10 +1501,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_screen_free(oldscreen);
- 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.
@@ -1933,14 +1513,18 @@ 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;
+ 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(win, oldscreen->scene, newname);
+
+ layout_new = ED_workspace_layout_add(workspace, win, newname);
+
+ sc = BKE_workspace_layout_screen_get(layout_new);
sc->state = state;
sc->redraws_flag = oldscreen->redraws_flag;
sc->temp = oldscreen->temp;
@@ -1995,7 +1579,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
BLI_assert(false);
}
- ED_screen_set(C, sc);
+ ED_screen_change(C, sc);
}
/* XXX bad code: setscreen() ends with first area active. fullscreen render assumes this too */
@@ -2076,7 +1660,13 @@ void ED_screen_animation_timer(bContext *C, int redraws, int refresh, int sync,
sad->flag |= (sync == 0) ? ANIMPLAY_FLAG_NO_SYNC : (sync == 1) ? ANIMPLAY_FLAG_SYNC : 0;
ScrArea *sa = CTX_wm_area(C);
- sad->from_anim_edit = (ELEM(sa->spacetype, SPACE_IPO, SPACE_ACTION, SPACE_NLA, SPACE_TIME));
+
+ char spacetype = -1;
+
+ if (sa)
+ spacetype = sa->spacetype;
+
+ sad->from_anim_edit = (ELEM(spacetype, SPACE_IPO, SPACE_ACTION, SPACE_NLA, SPACE_TIME));
screen->animtimer->customdata = sad;
@@ -2128,10 +1718,6 @@ void ED_screen_animation_timer_update(bScreen *screen, int redraws, int refresh)
* screen can be NULL */
void ED_update_for_newframe(Main *bmain, Scene *scene, int UNUSED(mute))
{
- wmWindowManager *wm = bmain->wm.first;
- wmWindow *window;
- int layers = 0;
-
#ifdef DURIAN_CAMERA_SWITCH
void *camera = BKE_scene_camera_switch_find(scene);
if (camera && scene->camera != camera) {
@@ -2139,19 +1725,15 @@ 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);
}
}
#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_update_for_newframe(bmain->eval_ctx, bmain, scene);
/* composite */
if (scene->use_nodes && scene->nodetree)
@@ -2160,10 +1742,11 @@ void ED_update_for_newframe(Main *bmain, Scene *scene, int UNUSED(mute))
/* update animated texture nodes */
{
Tex *tex;
- for (tex = bmain->tex.first; tex; tex = tex->id.next)
+ for (tex = bmain->tex.first; tex; tex = tex->id.next) {
if (tex->use_nodes && tex->nodetree) {
ntreeTexTagAnimated(tex->nodetree);
}
+ }
}
}
@@ -2171,11 +1754,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) {
@@ -2250,3 +1832,19 @@ 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(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 WM_window_get_active_scene(win);
+ }
+ }
+
+ BLI_assert(0);
+ return NULL;
+}
diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h
index ccb6d5a6dca..4eb68d01df7 100644
--- a/source/blender/editors/screen/screen_intern.h
+++ b/source/blender/editors/screen/screen_intern.h
@@ -31,6 +31,9 @@
#ifndef __SCREEN_INTERN_H__
#define __SCREEN_INTERN_H__
+struct bContextDataResult;
+struct Main;
+
/* internal exports only */
#define AZONESPOT (0.6f * U.widget_unit)
@@ -40,12 +43,17 @@
/* 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(bContext *C, ARegion *ar, const bool do_fade);
+void region_toggle_hidden(struct bContext *C, ARegion *ar, const bool do_fade);
/* screen_edit.c */
+bScreen *screen_add(const char *name, const int winsize_x, const int winsize_y);
+void screen_data_copy(bScreen *to, bScreen *from);
+void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new);
+void screen_changed_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);
ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2);
ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge);
-int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2);
+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);
@@ -54,14 +62,14 @@ 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,
+ScrEdge *screen_find_active_scredge(const bScreen *sc,
const int winsize_x, const int winsize_y,
const int mx, const int my);
struct AZone *is_in_area_actionzone(ScrArea *sa, const int xy[2]);
/* screen_context.c */
-int ed_screen_context(const bContext *C, const char *member, bContextDataResult *result);
+int ed_screen_context(const struct bContext *C, const char *member, struct bContextDataResult *result);
extern const char *screen_context_dir[]; /* doc access */
@@ -72,5 +80,8 @@ void SCREEN_OT_screencast(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 6dbb5db53d0..b8fa16117a9 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -48,11 +48,13 @@
#include "DNA_meta_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_global.h"
+#include "BKE_icons.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_report.h"
@@ -61,6 +63,7 @@
#include "BKE_editmesh.h"
#include "BKE_sound.h"
#include "BKE_mask.h"
+#include "BKE_workspace.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -442,6 +445,17 @@ int ED_operator_posemode(bContext *C)
return 0;
}
+int ED_operator_posemode_local(bContext *C)
+{
+ if (ED_operator_posemode(C)) {
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm = ob->data;
+ return !(ID_IS_LINKED_DATABLOCK(&ob->id) ||
+ ID_IS_LINKED_DATABLOCK(&arm->id));
+ }
+ return false;
+}
+
/* wrapper for ED_space_image_show_uvedit */
int ED_operator_uvedit(bContext *C)
{
@@ -560,8 +574,8 @@ int 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);
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ return ED_space_image_check_show_maskedit(sl, sima);
}
}
}
@@ -966,13 +980,17 @@ static void SCREEN_OT_area_swap(wmOperatorType *ot)
/* operator callback */
static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- 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! */
@@ -998,11 +1016,15 @@ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
*newwin->stereo3d_format = *win->stereo3d_format;
-
+
+ newwin->scene = scene;
+
+ WM_window_set_active_workspace(newwin, workspace);
/* allocs new screen and adds to newly created window, using window size */
- newsc = ED_screen_add(newwin, CTX_data_scene(C), sc->id.name + 2);
- newwin->screen = newsc;
-
+ layout_new = ED_workspace_layout_add(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);
@@ -1209,6 +1231,8 @@ static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int
}
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); /* redraw everything */
+ /* Update preview thumbnail */
+ BKE_icon_changed(sc->id.icon_id);
}
}
@@ -1497,7 +1521,9 @@ 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;
}
@@ -1698,7 +1724,7 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
- CTX_wm_window(C)->screen->do_draw = true;
+ CTX_wm_screen(C)->do_draw = true;
}
@@ -2068,12 +2094,11 @@ 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 &&
@@ -2136,7 +2161,8 @@ static void SCREEN_OT_frame_offset(wmOperatorType *ot)
ot->exec = frame_offset_exec;
ot->poll = ED_operator_screenactive_norender;
- ot->flag = 0;
+ ot->flag = OPTYPE_UNDO_GROUPED;
+ ot->undo_group = "FRAME_CHANGE";
/* rna */
RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
@@ -2189,7 +2215,8 @@ static void SCREEN_OT_frame_jump(wmOperatorType *ot)
ot->exec = frame_jump_exec;
ot->poll = ED_operator_screenactive_norender;
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO_GROUPED;
+ ot->undo_group = "FRAME_CHANGE";
/* rna */
RNA_def_boolean(ot->srna, "end", 0, "Last Frame", "Jump to the last frame of the frame range");
@@ -2295,7 +2322,8 @@ static void SCREEN_OT_keyframe_jump(wmOperatorType *ot)
ot->exec = keyframe_jump_exec;
ot->poll = ED_operator_screenactive_norender;
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO_GROUPED;
+ ot->undo_group = "FRAME_CHANGE";
/* properties */
RNA_def_boolean(ot->srna, "next", true, "Next Keyframe", "");
@@ -2357,7 +2385,8 @@ static void SCREEN_OT_marker_jump(wmOperatorType *ot)
ot->exec = marker_jump_exec;
ot->poll = ED_operator_screenactive_norender;
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO_GROUPED;
+ ot->undo_group = "FRAME_CHANGE";
/* properties */
RNA_def_boolean(ot->srna, "next", true, "Next Marker", "");
@@ -2365,64 +2394,16 @@ static void SCREEN_OT_marker_jump(wmOperatorType *ot)
/* ************** switch 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;
}
@@ -2793,7 +2774,7 @@ static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent
bScreen *sc = CTX_wm_screen(C);
uiPopupMenu *pup;
uiLayout *layout;
- PointerRNA ptr1, ptr2;
+ PointerRNA ptr;
ScrEdge *actedge;
const int winsize_x = WM_window_pixels_x(win);
const int winsize_y = WM_window_pixels_y(win);
@@ -2805,22 +2786,17 @@ static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent
pup = UI_popup_menu_begin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE);
layout = UI_popup_menu_layout(pup);
- WM_operator_properties_create(&ptr1, "SCREEN_OT_area_join");
-
- /* mouse cursor on edge, '4' can fail on wide edges... */
- RNA_int_set(&ptr1, "min_x", event->x + 4);
- RNA_int_set(&ptr1, "min_y", event->y + 4);
- RNA_int_set(&ptr1, "max_x", event->x - 4);
- RNA_int_set(&ptr1, "max_y", event->y - 4);
-
- WM_operator_properties_create(&ptr2, "SCREEN_OT_area_split");
-
+ ptr = uiItemFullO(layout, "SCREEN_OT_area_split", NULL, ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
/* store initial mouse cursor position */
- RNA_int_set(&ptr2, "mouse_x", event->x);
- RNA_int_set(&ptr2, "mouse_y", event->y);
-
- uiItemFullO(layout, "SCREEN_OT_area_split", NULL, ICON_NONE, ptr2.data, WM_OP_INVOKE_DEFAULT, 0);
- uiItemFullO(layout, "SCREEN_OT_area_join", NULL, ICON_NONE, ptr1.data, WM_OP_INVOKE_DEFAULT, 0);
+ RNA_int_set(&ptr, "mouse_x", event->x);
+ RNA_int_set(&ptr, "mouse_y", event->y);
+
+ ptr = uiItemFullO(layout, "SCREEN_OT_area_join", NULL, ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ /* mouse cursor on edge, '4' can fail on wide edges... */
+ RNA_int_set(&ptr, "min_x", event->x + 4);
+ RNA_int_set(&ptr, "min_y", event->y + 4);
+ RNA_int_set(&ptr, "max_x", event->x - 4);
+ RNA_int_set(&ptr, "max_y", event->y - 4);
UI_popup_menu_end(C, pup);
@@ -2888,10 +2864,23 @@ static void SCREEN_OT_spacedata_cleanup(wmOperatorType *ot)
static int repeat_last_exec(bContext *C, wmOperator *UNUSED(op))
{
- wmOperator *lastop = CTX_wm_manager(C)->operators.last;
-
- if (lastop)
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmOperator *lastop = wm->operators.last;
+
+ /* Seek last registered operator */
+ while (lastop) {
+ if (lastop->type->flag & OPTYPE_REGISTER) {
+ break;
+ }
+ else {
+ lastop = lastop->prev;
+ }
+ }
+
+ if (lastop) {
+ WM_operator_free_all_after(wm, lastop);
WM_operator_repeat(C, lastop);
+ }
return OPERATOR_CANCELLED;
}
@@ -2926,8 +2915,9 @@ static int repeat_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNU
layout = UI_popup_menu_layout(pup);
for (i = items - 1, lastop = wm->operators.last; lastop; lastop = lastop->prev, i--)
- if (WM_operator_repeat_check(C, lastop))
+ if ((lastop->type->flag & OPTYPE_REGISTER) && WM_operator_repeat_check(C, lastop)) {
uiItemIntO(layout, RNA_struct_ui_name(lastop->type->srna), ICON_NONE, op->type->idname, "index", i);
+ }
UI_popup_menu_end(C, pup);
@@ -3268,7 +3258,7 @@ static int header_toggle_menus_exec(bContext *C, wmOperator *UNUSED(op))
sa->flag = sa->flag ^ HEADER_NO_PULLDOWN;
ED_area_tag_redraw(sa);
- WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
@@ -3565,7 +3555,9 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
ED_update_for_newframe(bmain, scene, 1);
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;
@@ -3639,11 +3631,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;
}
}
@@ -3652,11 +3644,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;
}
}
@@ -3732,7 +3724,7 @@ static int screen_animation_cancel_exec(bContext *C, wmOperator *op)
bScreen *screen = ED_screen_animation_playing(CTX_wm_manager(C));
if (screen) {
- if (RNA_boolean_get(op->ptr, "restore_frame")) {
+ if (RNA_boolean_get(op->ptr, "restore_frame") && screen->animtimer) {
ScreenAnimData *sad = screen->animtimer->customdata;
Scene *scene = CTX_data_scene(C);
@@ -3859,22 +3851,11 @@ static void SCREEN_OT_back_to_previous(struct wmOperatorType *ot)
static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- wmWindow *win = CTX_wm_window(C);
- rcti rect;
- int sizex, sizey;
-
- sizex = 800 * UI_DPI_WINDOW_FAC;
- sizey = 480 * UI_DPI_WINDOW_FAC;
-
- /* some magic to calculate postition */
- /* pixelsize: mouse coords are in U.pixelsize units :/ */
- rect.xmin = (event->x / U.pixelsize) + win->posx - sizex / 2;
- rect.ymin = (event->y / U.pixelsize) + win->posy - sizey / 2;
- rect.xmax = rect.xmin + sizex;
- rect.ymax = rect.ymin + sizey;
+ int sizex = 800 * UI_DPI_FAC;
+ int sizey = 480 * UI_DPI_FAC;
/* changes context! */
- if (WM_window_open_temp(C, &rect, WM_WINDOW_USERPREFS) != NULL) {
+ if (WM_window_open_temp(C, event->x, event->y, sizex, sizey, WM_WINDOW_USERPREFS) != NULL) {
return OPERATOR_FINISHED;
}
else {
@@ -3901,11 +3882,13 @@ static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
static int screen_new_exec(bContext *C, wmOperator *UNUSED(op))
{
wmWindow *win = CTX_wm_window(C);
- bScreen *sc = CTX_wm_screen(C);
-
- sc = ED_screen_duplicate(win, sc);
- WM_event_add_notifier(C, NC_SCREEN | ND_SCREENBROWSE, sc);
-
+ WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
+ WorkSpaceLayout *layout_old = BKE_workspace_active_layout_get(win->workspace_hook);
+ WorkSpaceLayout *layout_new;
+
+ layout_new = ED_workspace_layout_duplicate(workspace, layout_old, win);
+ WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTBROWSE, layout_new);
+
return OPERATOR_FINISHED;
}
@@ -3926,9 +3909,11 @@ static void SCREEN_OT_new(wmOperatorType *ot)
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);
-
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, sc);
+
+ WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTDELETE, layout);
+
return OPERATOR_FINISHED;
}
@@ -3943,95 +3928,6 @@ static void SCREEN_OT_delete(wmOperatorType *ot)
ot->exec = screen_delete_exec;
}
-/********************* new scene operator *********************/
-
-static int scene_new_exec(bContext *C, wmOperator *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);
-
- WM_event_add_notifier(C, NC_SCENE | ND_SCENEBROWSE, newscene);
-
- 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", "");
-}
-
-/********************* delete scene operator *********************/
-
-static int scene_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);
-
- 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;
-}
-
/* ***************** region alpha blending ***************** */
/* implementation note: a disappearing region needs at least 1 last draw with 100% backbuffer
@@ -4174,6 +4070,89 @@ static void SCREEN_OT_region_blend(wmOperatorType *ot)
/* properties */
}
+/* ******************** space context cycling operator ******************** */
+
+/* SCREEN_OT_space_context_cycle direction */
+enum {
+ SPACE_CONTEXT_CYCLE_PREV,
+ SPACE_CONTEXT_CYCLE_NEXT,
+};
+
+static EnumPropertyItem space_context_cycle_direction[] = {
+ {SPACE_CONTEXT_CYCLE_PREV, "PREV", 0, "Previous", ""},
+ {SPACE_CONTEXT_CYCLE_NEXT, "NEXT", 0, "Next", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int space_context_cycle_poll(bContext *C)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ /* sa might be NULL if called out of window bounds */
+ return (sa && ELEM(sa->spacetype, SPACE_BUTS, SPACE_USERPREF));
+}
+
+/**
+ * Helper to get the correct RNA pointer/property pair for changing
+ * the display context of active space type in \a sa.
+ */
+static void context_cycle_prop_get(
+ bScreen *screen, const ScrArea *sa,
+ PointerRNA *r_ptr, PropertyRNA **r_prop)
+{
+ const char *propname;
+
+ switch (sa->spacetype) {
+ case SPACE_BUTS:
+ RNA_pointer_create(&screen->id, &RNA_SpaceProperties, sa->spacedata.first, r_ptr);
+ propname = "context";
+ break;
+ case SPACE_USERPREF:
+ RNA_pointer_create(NULL, &RNA_UserPreferences, &U, r_ptr);
+ propname = "active_section";
+ break;
+ default:
+ BLI_assert(0);
+ propname = "";
+ }
+
+ *r_prop = RNA_struct_find_property(r_ptr, propname);
+}
+
+static int space_context_cycle_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ const int direction = RNA_enum_get(op->ptr, "direction");
+
+ 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);
+ RNA_property_enum_set(&ptr, prop, new_context);
+ RNA_property_update(C, &ptr, prop);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCREEN_OT_space_context_cycle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Cycle Space Context";
+ ot->description = "Cycle through the editor context by activating the next/previous one";
+ ot->idname = "SCREEN_OT_space_context_cycle";
+
+ /* api callbacks */
+ ot->invoke = space_context_cycle_invoke;
+ ot->poll = space_context_cycle_poll;
+
+ ot->flag = 0;
+
+ RNA_def_enum(ot->srna, "direction", space_context_cycle_direction, SPACE_CONTEXT_CYCLE_NEXT, "Direction",
+ "Direction to cycle through");
+}
+
/* **************** Assigning operatortypes to global list, adding handlers **************** */
@@ -4209,6 +4188,7 @@ void ED_operatortypes_screen(void)
WM_operatortype_append(SCREEN_OT_screencast);
WM_operatortype_append(SCREEN_OT_userpref_show);
WM_operatortype_append(SCREEN_OT_region_blend);
+ WM_operatortype_append(SCREEN_OT_space_context_cycle);
/*frame changes*/
WM_operatortype_append(SCREEN_OT_frame_offset);
@@ -4219,17 +4199,16 @@ void ED_operatortypes_screen(void)
WM_operatortype_append(SCREEN_OT_animation_step);
WM_operatortype_append(SCREEN_OT_animation_play);
WM_operatortype_append(SCREEN_OT_animation_cancel);
-
+
/* 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);
WM_operatortype_append(ED_OT_undo_push);
WM_operatortype_append(ED_OT_redo);
+ WM_operatortype_append(ED_OT_undo_redo);
WM_operatortype_append(ED_OT_undo_history);
WM_operatortype_append(ED_OT_flush_edits);
@@ -4331,7 +4310,12 @@ void ED_keymap_screen(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "SCREEN_OT_screenshot", F3KEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "SCREEN_OT_screencast", F3KEY, KM_PRESS, KM_ALT, 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);
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index 2dd7400bc37..6fa8905293c 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -54,7 +54,9 @@
#include "BKE_writeavi.h"
#include "BIF_gl.h"
-#include "BIF_glutil.h"
+
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -451,25 +453,24 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float
/* Helper callback for drawing the cursor itself */
static void screencast_draw_cursor(bContext *UNUSED(C), int x, int y, void *UNUSED(p_ptr))
{
-
- glPushMatrix();
-
- glTranslatef((float)x, (float)y, 0.0f);
-
-
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
-
- glColor4ub(0, 0, 0, 32);
- glutil_draw_filled_arc(0.0, M_PI * 2.0, 20, 40);
-
- glColor4ub(255, 255, 255, 128);
- glutil_draw_lined_arc(0.0, M_PI * 2.0, 20, 40);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor4ub(0, 0, 0, 32);
+ imm_draw_circle_fill(pos, (float)x, (float)y, 20, 40);
+
+ immUniformColor4ub(255, 255, 255, 128);
+ imm_draw_circle_wire(pos, (float)x, (float)y, 20, 40);
+
+ immUnbindProgram();
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
-
- glPopMatrix();
}
/* Turn brush cursor in 3D view on/off */
diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c
new file mode 100644
index 00000000000..34def82f16e
--- /dev/null
+++ b/source/blender/editors/screen/workspace_edit.c
@@ -0,0 +1,439 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_main.h"
+#include "BKE_library.h"
+#include "BKE_report.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_object.h"
+#include "ED_screen.h"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "WM_api.h"
+#include "WM_types.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, SceneLayer *act_render_layer)
+{
+ WorkSpace *workspace = BKE_workspace_add(bmain, name);
+
+#ifdef USE_WORKSPACE_MODE
+ BKE_workspace_object_mode_set(workspace, OB_MODE_OBJECT);
+#endif
+
+ BKE_workspace_render_layer_set(workspace, act_render_layer);
+
+ return workspace;
+}
+
+#ifdef USE_WORKSPACE_MODE
+/**
+ * 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_mode(
+ const WorkSpace *workspace_old, const WorkSpace *workspace_new,
+ bContext *C, Object *ob_act, ReportList *reports)
+{
+ ObjectMode mode_old = BKE_workspace_object_mode_get(workspace_old);
+ ObjectMode mode_new = BKE_workspace_object_mode_get(workspace_new);
+
+ if (mode_old != mode_new) {
+ ED_object_mode_compat_set(C, ob_act, mode_new, reports);
+ ED_object_toggle_modes(C, mode_new);
+ }
+}
+#endif
+
+static void workspace_change_update_render_layer(
+ WorkSpace *workspace_new, const WorkSpace *workspace_old)
+{
+ if (!BKE_workspace_render_layer_get(workspace_new)) {
+ BKE_workspace_render_layer_set(workspace_new, BKE_workspace_render_layer_get(workspace_old));
+ }
+}
+
+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) */
+ workspace_change_update_render_layer(workspace_new, workspace_old);
+#ifdef USE_WORKSPACE_MODE
+ workspace_change_update_mode(workspace_old, workspace_new, C, CTX_data_active_object(C), &wm->reports);
+#else
+ UNUSED_VARS(C, wm);
+#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(
+ WorkSpace *workspace_new, wmWindow *win)
+{
+ /* ED_workspace_duplicate may have stored a layout to activate once the workspace gets activated. */
+ 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 */
+ layout_temp = ED_workspace_layout_duplicate(workspace_new, layout_new, 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(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) {
+ WM_window_set_active_layout(win, workspace_new, layout_new);
+ WM_window_set_active_workspace(win, workspace_new);
+
+ /* update screen *after* changing workspace - which also causes the actual screen change */
+ screen_changed_update(C, win, screen_new);
+ workspace_change_update(workspace_new, workspace_old, C, wm);
+
+ BLI_assert(BKE_workspace_render_layer_get(workspace_new) != NULL);
+ BLI_assert(CTX_wm_workspace(C) == workspace_new);
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * 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,
+ BKE_workspace_render_layer_get(workspace_old));
+ ListBase *transform_orientations_old = BKE_workspace_transform_orientations_get(workspace_old);
+ ListBase *transform_orientations_new = BKE_workspace_transform_orientations_get(workspace_new);
+
+#ifdef USE_WORKSPACE_MODE
+ BKE_workspace_object_mode_set(workspace_new, BKE_workspace_object_mode_get(workspace_old));
+#endif
+ BLI_duplicatelist(transform_orientations_new, transform_orientations_old);
+
+ for (WorkSpaceLayout *layout_old = layouts_old->first; layout_old; layout_old = layout_old->next) {
+ WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(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, wmWindow *win)
+{
+ ID *workspace_id = (ID *)workspace;
+
+ if (BLI_listbase_is_single(&bmain->workspaces)) {
+ return false;
+ }
+
+ if (WM_window_get_active_workspace(win) == workspace) {
+ 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);
+}
+
+void ED_workspace_render_layer_unset(
+ const Main *bmain, const SceneLayer *layer_unset, SceneLayer *layer_new)
+{
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ if (BKE_workspace_render_layer_get(workspace) == layer_unset) {
+ BKE_workspace_render_layer_set(workspace, layer_new);
+ }
+ }
+}
+
+/** \} Workspace API */
+
+
+/** \name Workspace Operators
+ *
+ * \{ */
+
+static int workspace_new_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ wmWindow *win = CTX_wm_window(C);
+ WorkSpace *workspace = ED_workspace_duplicate(WM_window_get_active_workspace(win), bmain, win);
+
+ WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, workspace);
+
+ return OPERATOR_FINISHED;
+}
+
+static void WORKSPACE_OT_workspace_duplicate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "New Workspace";
+ ot->description = "Add a new workspace";
+ ot->idname = "WORKSPACE_OT_workspace_duplicate";
+
+ /* api callbacks */
+ ot->exec = workspace_new_exec;
+ ot->poll = WM_operator_winactive;
+}
+
+static int workspace_delete_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
+
+ ED_workspace_delete(WM_window_get_active_workspace(win), bmain, C, wm, win);
+
+ return OPERATOR_FINISHED;
+}
+
+static void WORKSPACE_OT_workspace_delete(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete Workspace";
+ ot->description = "Delete the active workspace";
+ ot->idname = "WORKSPACE_OT_workspace_delete";
+
+ /* api callbacks */
+ ot->exec = workspace_delete_exec;
+}
+
+static void workspace_config_file_path_from_folder_id(
+ const Main *bmain, int folder_id, char *r_path)
+{
+ const char *app_template = U.app_template[0] ? U.app_template : NULL;
+ const char * const cfgdir = BKE_appdir_folder_id(folder_id, app_template);
+
+ if (cfgdir) {
+ BLI_make_file_string(bmain->name, r_path, cfgdir, BLENDER_WORKSPACES_FILE);
+ }
+ else {
+ r_path[0] = '\0';
+ }
+}
+
+ATTR_NONNULL(1)
+static WorkspaceConfigFileData *workspace_config_file_read(
+ const Main *bmain, ReportList *reports)
+{
+ char workspace_config_path[FILE_MAX];
+ bool has_path = false;
+
+ workspace_config_file_path_from_folder_id(bmain, BLENDER_USER_CONFIG, workspace_config_path);
+ if (BLI_exists(workspace_config_path)) {
+ has_path = true;
+ }
+ else {
+ workspace_config_file_path_from_folder_id(bmain, BLENDER_DATAFILES, workspace_config_path);
+ if (BLI_exists(workspace_config_path)) {
+ has_path = true;
+ }
+ }
+
+ return has_path ? BKE_blendfile_workspace_config_read(workspace_config_path, reports) : 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];
+
+ BLI_path_join(
+ lib_path, sizeof(lib_path), from_main->name, BKE_idcode_to_name(GS(id->name)), NULL);
+
+ BLI_assert(STREQ(ot_append->idname, "WM_OT_append"));
+ opptr = uiItemFullO_ptr(
+ layout, ot_append, workspace->id.name + 2, ICON_NONE, NULL,
+ WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ RNA_string_set(&opptr, "directory", lib_path);
+ RNA_string_set(&opptr, "filename", id->name + 2);
+}
+
+ATTR_NONNULL(1, 2)
+static void workspace_config_file_append_buttons(
+ uiLayout *layout, const Main *bmain, ReportList *reports)
+{
+ WorkspaceConfigFileData *workspace_config = workspace_config_file_read(bmain, reports);
+
+ if (workspace_config) {
+ wmOperatorType *ot_append = WM_operatortype_find("WM_OT_append", true);
+
+ for (WorkSpace *workspace = workspace_config->workspaces.first; workspace; workspace = workspace->id.next) {
+ workspace_append_button(layout, ot_append, workspace, workspace_config->main);
+ }
+
+ BKE_blendfile_workspace_config_data_free(workspace_config);
+ }
+}
+
+static int workspace_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ const Main *bmain = CTX_data_main(C);
+
+ uiPopupMenu *pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
+ uiLayout *layout = UI_popup_menu_layout(pup);
+
+ uiItemO(layout, "Duplicate Current", ICON_NONE, "WORKSPACE_OT_workspace_duplicate");
+ uiItemS(layout);
+ workspace_config_file_append_buttons(layout, bmain, op->reports);
+
+ UI_popup_menu_end(C, pup);
+
+ return OPERATOR_INTERFACE;
+}
+
+static void WORKSPACE_OT_workspace_add_menu(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_workspace_add_menu";
+
+ /* api callbacks */
+ ot->invoke = workspace_add_invoke;
+}
+
+void ED_operatortypes_workspace(void)
+{
+ WM_operatortype_append(WORKSPACE_OT_workspace_duplicate);
+ WM_operatortype_append(WORKSPACE_OT_workspace_delete);
+ WM_operatortype_append(WORKSPACE_OT_workspace_add_menu);
+}
+
+/** \} 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..e4dd841f833
--- /dev/null
+++ b/source/blender/editors/screen/workspace_layout_edit.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 blender/editors/screen/workspace_layout_edit.c
+ * \ingroup edscr
+ */
+
+#include <stdlib.h>
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_screen.h"
+#include "BKE_workspace.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+
+#include "DNA_screen_types.h"
+#include "DNA_workspace_types.h"
+
+#include "ED_screen.h"
+
+#include "WM_api.h"
+
+#include "screen_intern.h"
+
+
+/**
+ * Empty screen, with 1 dummy area without spacedata. Uses window size.
+ */
+WorkSpaceLayout *ED_workspace_layout_add(
+ WorkSpace *workspace,
+ wmWindow *win,
+ const char *name)
+{
+ const int winsize_x = WM_window_pixels_x(win);
+ const int winsize_y = WM_window_pixels_y(win);
+
+ bScreen *screen = screen_add(name, winsize_x, winsize_y);
+ WorkSpaceLayout *layout = BKE_workspace_layout_add(workspace, screen, name);
+
+ return layout;
+}
+
+WorkSpaceLayout *ED_workspace_layout_duplicate(
+ 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(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 46753df4e13..ead420b1faa 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 53c11e2a6a9..a9b4df81277 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -53,14 +53,14 @@
#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 "UI_resources.h"
@@ -335,8 +335,8 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima
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);
@@ -351,8 +351,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);
@@ -459,18 +457,16 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
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);
@@ -604,22 +600,20 @@ static void paint_draw_tex_overlay(UnifiedPaintSettings *ups, Brush *brush,
glDepthMask(GL_FALSE);
glDepthFunc(GL_ALWAYS);
- glMatrixMode(GL_TEXTURE);
- glPushMatrix();
- glLoadIdentity();
-
if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
+ gpuPushMatrix();
+
/* 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);
+ gpuTranslate2f(x, y);
+ gpuRotate2D(-RAD2DEGF(primary ? ups->brush_rotation : ups->brush_rotation_sec));
+ gpuTranslate2f(-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;
+ gpuTranslate2f(x, y);
+ gpuScale2f(scale, scale);
+ gpuTranslate2f(-x, -y);
}
if (ups->draw_anchored) {
@@ -657,41 +651,46 @@ static void paint_draw_tex_overlay(UnifiedPaintSettings *ups, Brush *brush,
quad.xmax = brush->mask_stencil_dimension[0];
quad.ymax = brush->mask_stencil_dimension[1];
}
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
+ gpuPushMatrix();
if (primary)
- glTranslate2fv(brush->stencil_pos);
+ gpuTranslate2fv(brush->stencil_pos);
else
- glTranslate2fv(brush->mask_stencil_pos);
- glRotatef(RAD2DEGF(mtex->rot), 0, 0, 1);
- glMatrixMode(GL_TEXTURE);
+ gpuTranslate2fv(brush->mask_stencil_pos);
+ gpuRotate2D(RAD2DEGF(mtex->rot));
}
/* set quad color. Colored overlay does not get blending */
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int texCoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_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);
+ 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(GWN_PRIM_TRI_FAN, 4);
+ immAttrib2f(texCoord, 0.0f, 0.0f);
+ immVertex2f(pos, quad.xmin, quad.ymin);
+ immAttrib2f(texCoord, 1.0f, 0.0f);
+ immVertex2f(pos, quad.xmax, quad.ymin);
+ immAttrib2f(texCoord, 1.0f, 1.0f);
+ immVertex2f(pos, quad.xmax, quad.ymax);
+ immAttrib2f(texCoord, 0.0f, 1.0f);
+ immVertex2f(pos, quad.xmin, quad.ymax);
+ immEnd();
+
+ immUnbindProgram();
+
+ if (ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_VIEW)) {
+ gpuPopMatrix();
}
}
}
@@ -739,32 +738,41 @@ static void paint_draw_cursor_overlay(UnifiedPaintSettings *ups, Brush *brush,
/* 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);
+ gpuPushMatrix();
+ gpuLoadIdentity();
+ gpuTranslate2fv(center);
+ gpuScaleUniform(ups->size_pressure_value);
+ gpuTranslate2f(-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);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int texCoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_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", GL_TEXTURE0);
+
+ immBegin(GWN_PRIM_TRI_FAN, 4);
+ immAttrib2f(texCoord, 0.0f, 0.0f);
+ immVertex2f(pos, quad.xmin, quad.ymin);
+ immAttrib2f(texCoord, 1.0f, 0.0f);
+ immVertex2f(pos, quad.xmax, quad.ymin);
+ immAttrib2f(texCoord, 1.0f, 1.0f);
+ immVertex2f(pos, quad.xmax, quad.ymax);
+ immAttrib2f(texCoord, 0.0f, 1.0f);
+ immVertex2f(pos, quad.xmin, quad.ymax);
+ immEnd();
+
+ immUnbindProgram();
if (do_pop)
- glPopMatrix();
+ gpuPopMatrix();
}
}
@@ -774,19 +782,7 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush,
/* color means that primary brush texture is colured and secondary is used for alpha/mask control */
bool col = ELEM(mode, ePaintTextureProjective, ePaintTexture2D, ePaintVertex) ? true : false;
OverlayControlFlags 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);
/* coloured overlay should be drawn separately */
if (col) {
@@ -804,86 +800,98 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush,
paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom);
}
- glPopAttrib();
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ 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);
+
+ glLineWidth(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(GWN_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);
+ glLineWidth(1.0f);
+
+ immBegin(GWN_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);
+
+ glLineWidth(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_line_box(pos, minx, miny, maxx, maxy);
+
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
+ glLineWidth(1.0f);
+
+ imm_draw_line_box(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);
+ glLineWidth(3.0f);
+
+ immBegin(GWN_PRIM_LINE_STRIP, 3);
+ immVertex2fv(pos, bez->vec[0]);
+ immVertex2fv(pos, bez->vec[1]);
+ immVertex2fv(pos, bez->vec[2]);
+ immEnd();
+
+ glLineWidth(1.0f);
+
+ if (bez->f1 || bez->f2) {
+ immUniformColor4fv(sel_col);
+ }
+ else {
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
+ }
+ immBegin(GWN_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(GWN_PRIM_LINES, 2);
+ immVertex2fv(pos, bez->vec[1]);
+ immVertex2fv(pos, bez->vec[2]);
+ immEnd();
}
static void paint_draw_curve_cursor(Brush *brush)
@@ -895,18 +903,26 @@ static void paint_draw_curve_cursor(Brush *brush)
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
- glEnableClientState(GL_VERTEX_ARRAY);
/* draw the bezier handles and the curve segment between the current and next point */
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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(
@@ -916,25 +932,35 @@ 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);
+ glLineWidth(3.0f);
+ immBegin(GWN_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);
+ glLineWidth(1.0f);
+ immBegin(GWN_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);
+ 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);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
- glDisableClientState(GL_VERTEX_ARRAY);
+
+ immUnbindProgram();
}
}
@@ -988,11 +1014,6 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
Paint *paint = BKE_paint_get_active_from_context(C);
Brush *brush = BKE_paint_brush(paint);
PaintMode 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))
@@ -1000,8 +1021,10 @@ 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;
view3d_set_viewcontext(C, &vc);
+ float zoomx, zoomy;
get_imapaint_zoom(C, &zoomx, &zoomy);
zoomx = max_ff(zoomx, zoomy);
@@ -1012,11 +1035,10 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
}
/* 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 */
@@ -1032,10 +1054,9 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
if ((mode == ePaintSculpt) && 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);
@@ -1065,24 +1086,25 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* make lines pretty */
glLineWidth(1.0f);
- glEnable(GL_BLEND);
+ glEnable(GL_BLEND); /* TODO: also set blend mode? */
glEnable(GL_LINE_SMOOTH);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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(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(pos, translation[0], translation[1], final_radius, 40);
+
+ immUnbindProgram();
/* restore GL state */
glDisable(GL_BLEND);
diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c
index 5af6792f10f..d7c3b7377da 100644
--- a/source/blender/editors/sculpt_paint/paint_hide.c
+++ b/source/blender/editors/sculpt_paint/paint_hide.c
@@ -52,8 +52,6 @@
#include "BKE_paint.h"
#include "BKE_subsurf.h"
-#include "BIF_glutil.h"
-
#include "WM_api.h"
#include "WM_types.h"
@@ -323,12 +321,10 @@ static void clip_planes_from_rect(bContext *C,
{
ViewContext vc;
BoundBox bb;
- bglMats mats = {{0}};
view3d_operator_needs_opengl(C);
view3d_set_viewcontext(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);
}
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index bf344e1f721..8c6b3b0106c 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -51,7 +51,6 @@
#include "DNA_object_types.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_brush.h"
#include "BKE_image.h"
@@ -61,6 +60,8 @@
#include "BKE_paint.h"
#include "BKE_texture.h"
+#include "DEG_depsgraph.h"
+
#include "UI_interface.h"
#include "UI_view2d.h"
@@ -78,9 +79,9 @@
#include "GPU_draw.h"
#include "GPU_buffers.h"
+#include "GPU_immediate.h"
#include "BIF_gl.h"
-#include "BIF_glutil.h"
#include "IMB_colormanagement.h"
@@ -372,7 +373,7 @@ void ED_image_undo_restore(bContext *C, ListBase *lb)
ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */
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);
}
@@ -721,12 +722,28 @@ static void gradient_draw_line(bContext *UNUSED(C), int x, int y, void *customda
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
glLineWidth(4.0);
- glColor4ub(0, 0, 0, 255);
- sdrawline(x, y, pop->startmouse[0], pop->startmouse[1]);
+ immUniformColor4ub(0, 0, 0, 255);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2i(pos, x, y);
+ immVertex2i(pos, pop->startmouse[0], pop->startmouse[1]);
+ immEnd();
+
glLineWidth(2.0);
- glColor4ub(255, 255, 255, 255);
- sdrawline(x, y, pop->startmouse[0], pop->startmouse[1]);
+ immUniformColor4ub(255, 255, 255, 255);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2i(pos, x, y);
+ immVertex2i(pos, pop->startmouse[0], pop->startmouse[1]);
+ immEnd();
+
+ immUnbindProgram();
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
@@ -748,7 +765,8 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const flo
/* initialize from context */
if (CTX_wm_region_view3d(C)) {
- Object *ob = OBACT;
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *ob = OBACT_NEW;
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);
@@ -1039,16 +1057,20 @@ static void toggle_paint_cursor(bContext *C, int enable)
void ED_space_image_paint_update(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(scene, ePaintTexture2D, PAINT_CURSOR_TEXTURE_PAINT);
@@ -1499,7 +1521,7 @@ void ED_imapaint_bucket_fill(struct bContext *C, float color[3], wmOperator *op)
ED_undo_paint_push_end(UNDO_PAINT_IMAGE);
- 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 9474a46d716..eb6eebf3c54 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -45,13 +45,14 @@
#include "BLI_task.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 "BKE_texture.h"
+#include "DEG_depsgraph.h"
+
#include "ED_paint.h"
#include "ED_screen.h"
@@ -1355,7 +1356,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)
@@ -1489,7 +1490,8 @@ void paint_2d_bucket_fill(
float image_init[2];
int minx = ibuf->x, miny = ibuf->y, maxx = 0, maxy = 0;
float pixel_color[4];
- float threshold_sq = br->fill_threshold * br->fill_threshold;
+ /* We are comparing to sum of three squared values (assumed in range [0,1]), so need to multiply... */
+ float threshold_sq = br->fill_threshold * br->fill_threshold * 3;
UI_view2d_region_to_view(s->v2d, mouse_init[0], mouse_init[1], &image_init[0], &image_init[1]);
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index d60c8e8dbd9..eeb357d43e7 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -64,7 +64,6 @@
#include "BKE_camera.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"
@@ -80,6 +79,8 @@
#include "BKE_scene.h"
#include "BKE_texture.h"
+#include "DEG_depsgraph.h"
+
#include "UI_interface.h"
#include "ED_mesh.h"
@@ -371,6 +372,8 @@ typedef struct ProjPaintState {
*/
const MLoopUV **dm_mloopuv;
const MLoopUV **dm_mloopuv_clone; /* other UV map, use for cloning between layers */
+
+ bool use_colormanagement;
} ProjPaintState;
typedef union pixelPointer {
@@ -1623,7 +1626,12 @@ static ProjPixel *project_paint_uvpixel_init(
unsigned char rgba_ub[4];
float rgba[4];
project_face_pixel(lt_other_tri_uv, ibuf_other, w, rgba_ub, NULL);
- srgb_to_linearrgb_uchar4(rgba, rgba_ub);
+ if (ps->use_colormanagement) {
+ srgb_to_linearrgb_uchar4(rgba, rgba_ub);
+ }
+ else {
+ rgba_uchar_to_float(rgba, rgba_ub);
+ }
straight_to_premul_v4_v4(((ProjPixelClone *)projPixel)->clonepx.f, rgba);
}
}
@@ -1632,7 +1640,12 @@ static ProjPixel *project_paint_uvpixel_init(
float rgba[4];
project_face_pixel(lt_other_tri_uv, ibuf_other, w, NULL, rgba);
premul_to_straight_v4(rgba);
- linearrgb_to_srgb_uchar3(((ProjPixelClone *)projPixel)->clonepx.ch, rgba);
+ if (ps->use_colormanagement) {
+ linearrgb_to_srgb_uchar3(((ProjPixelClone *)projPixel)->clonepx.ch, rgba);
+ }
+ else {
+ rgb_float_to_uchar(((ProjPixelClone *)projPixel)->clonepx.ch, rgba);
+ }
((ProjPixelClone *)projPixel)->clonepx.ch[3] = rgba[3] * 255;
}
else { /* char to char */
@@ -3475,7 +3488,7 @@ 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");
@@ -3700,8 +3713,12 @@ static void project_paint_prepare_all_faces(
}
/* don't allow using the same inage for painting and stencilling */
- if (slot->ima == ps->stencil_ima)
+ 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;
continue;
+ }
tpage = slot->ima;
}
@@ -3834,7 +3851,7 @@ static void project_paint_begin(
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(&((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);
@@ -3922,7 +3939,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);
}
}
@@ -4359,7 +4376,12 @@ static void do_projectpaint_draw(
if (ps->is_texbrush) {
mul_v3_v3v3(rgb, texrgb, ps->paint_color_linear);
/* TODO(sergey): Support texture paint color space. */
- linearrgb_to_srgb_v3_v3(rgb, rgb);
+ if (ps->use_colormanagement) {
+ linearrgb_to_srgb_v3_v3(rgb, rgb);
+ }
+ else {
+ copy_v3_v3(rgb, rgb);
+ }
}
else {
copy_v3_v3(rgb, ps->paint_color);
@@ -4957,11 +4979,21 @@ static void paint_proj_stroke_ps(
/* handle gradient and inverted stroke color here */
if (ps->tool == PAINT_TOOL_DRAW) {
paint_brush_color_get(scene, brush, false, ps->mode == BRUSH_STROKE_INVERT, distance, pressure, ps->paint_color, NULL);
- srgb_to_linearrgb_v3_v3(ps->paint_color_linear, ps->paint_color);
+ if (ps->use_colormanagement) {
+ srgb_to_linearrgb_v3_v3(ps->paint_color_linear, ps->paint_color);
+ }
+ else {
+ copy_v3_v3(ps->paint_color_linear, ps->paint_color);
+ }
}
else if (ps->tool == PAINT_TOOL_FILL) {
copy_v3_v3(ps->paint_color, BKE_brush_color_get(scene, brush));
- srgb_to_linearrgb_v3_v3(ps->paint_color_linear, ps->paint_color);
+ if (ps->use_colormanagement) {
+ srgb_to_linearrgb_v3_v3(ps->paint_color_linear, ps->paint_color);
+ }
+ else {
+ copy_v3_v3(ps->paint_color_linear, ps->paint_color);
+ }
}
else if (ps->tool == PAINT_TOOL_MASK) {
ps->stencil_value = brush->weight;
@@ -4990,6 +5022,7 @@ void paint_proj_stroke(
/* clone gets special treatment here to avoid going through image initialization */
if (ps_handle->is_clone_cursor_pick) {
Scene *scene = ps_handle->scene;
+ struct Depsgraph *graph = CTX_data_depsgraph(C);
View3D *v3d = CTX_wm_view3d(C);
ARegion *ar = CTX_wm_region(C);
float *cursor = ED_view3d_cursor3d_get(scene, v3d);
@@ -4997,8 +5030,9 @@ void paint_proj_stroke(
view3d_operator_needs_opengl(C);
- if (!ED_view3d_autodist(scene, ar, v3d, mval_i, cursor, false, NULL))
+ if (!ED_view3d_autodist(graph, ar, v3d, mval_i, cursor, false, NULL)) {
return;
+ }
ED_region_tag_redraw(ar);
@@ -5112,7 +5146,9 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
ps->normal_angle_inner__cos = cosf(ps->normal_angle_inner);
ps->dither = settings->imapaint.dither;
-
+
+ ps->use_colormanagement = BKE_scene_check_color_management_enabled(CTX_data_scene(C));
+
return;
}
@@ -5174,7 +5210,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;
}
@@ -5276,11 +5312,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);
+ SceneLayer *sl = CTX_data_scene_layer(C);
ProjPaintState ps = {NULL};
int orig_brush_size;
IDProperty *idgroup;
IDProperty *view_data = NULL;
- Object *ob = OBACT;
+ Object *ob = OBACT_NEW;
bool uvs, mat, tex;
if (ob == NULL || ob->type != OB_MESH) {
@@ -5409,6 +5446,7 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
char filename[FILE_MAX];
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
ToolSettings *settings = scene->toolsettings;
int w = settings->imapaint.screen_grab_size[0];
int h = settings->imapaint.screen_grab_size[1];
@@ -5423,7 +5461,7 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
if (h > maxsize) h = maxsize;
ibuf = ED_view3d_draw_offscreen_imbuf(
- scene, CTX_wm_view3d(C), CTX_wm_region(C),
+ scene, sl, CTX_wm_view3d(C), CTX_wm_region(C),
w, h, IB_rect, false, R_ALPHAPREMUL, 0, false, NULL,
NULL, NULL, err_out);
if (!ibuf) {
@@ -5557,7 +5595,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;
@@ -5682,21 +5720,16 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
/* successful creation of mtex layer, now create set */
if (mtex) {
int type = MAP_COL;
- int type_id = 0;
+ char imagename_buff[MAX_ID_NAME - 2];
+ const char *imagename = DATA_("Diffuse Color");
if (op) {
- int i;
type = RNA_enum_get(op->ptr, "type");
-
- for (i = 0; i < ARRAY_SIZE(layer_type_items); i++) {
- if (layer_type_items[i].value == type) {
- type_id = i;
- break;
- }
- }
+ RNA_string_get(op->ptr, "name", imagename_buff);
+ imagename = imagename_buff;
}
- mtex->tex = BKE_texture_add(bmain, DATA_(layer_type_items[type_id].name));
+ mtex->tex = BKE_texture_add(bmain, imagename);
mtex->mapto = type;
if (mtex->tex) {
@@ -5711,7 +5744,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
BKE_texpaint_slot_refresh_cache(scene, ma);
BKE_image_signal(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);
@@ -5783,7 +5816,7 @@ void PAINT_OT_add_texture_paint_slot(wmOperatorType *ot)
/* properties */
prop = RNA_def_enum(ot->srna, "type", layer_type_items, 0, "Type", "Merge method to use");
RNA_def_property_flag(prop, PROP_HIDDEN);
- RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image datablock name");
+ RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image data-block name");
prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
RNA_def_property_subtype(prop, PROP_PIXEL);
prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
@@ -5827,7 +5860,7 @@ static int texture_paint_delete_texture_paint_slot_exec(bContext *C, wmOperator
ma->mtex[slot->index] = NULL;
BKE_texpaint_slot_refresh_cache(scene, ma);
- DAG_id_tag_update(&ma->id, 0);
+ DEG_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);
@@ -5885,7 +5918,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;
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 7e05ab929ae..69c4621945b 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -209,7 +209,6 @@ bool paint_convert_bb_to_rect(struct rcti *rect,
* 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);
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index a47b9a0b936..1ac40b0354e 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -35,8 +35,7 @@
#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"
#include "BLI_utildefines.h"
@@ -250,7 +249,6 @@ int ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *r
{
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;
@@ -268,8 +266,7 @@ 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);
@@ -410,7 +407,6 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
if (mcords) {
float clip_planes[4][4], clip_planes_final[4][4];
BoundBox bb;
- bglMats mats = {{0}};
Object *ob;
ViewContext vc;
LassoMaskData data;
@@ -428,7 +424,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 */
view3d_set_viewcontext(C, &vc);
- view3d_get_transformation(vc.ar, vc.rv3d, vc.obact, &mats);
/* lasso data calculations */
data.vc = &vc;
@@ -439,12 +434,12 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
data.width = data.rect.xmax - data.rect.xmin;
data.px = BLI_BITMAP_NEW(data.width * (data.rect.ymax - data.rect.ymin), __func__);
- fill_poly_v2i_n(
+ BLI_bitmap_draw_2d_poly_v2i_n(
data.rect.xmin, data.rect.ymin, data.rect.xmax, data.rect.ymax,
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);
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 1431958501d..b1007f01c8d 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -51,6 +51,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 +59,7 @@
#include "BIF_gl.h"
#include "BIF_glutil.h"
-#include "GPU_basic_shader.h"
+#include "GPU_immediate.h"
#include "ED_screen.h"
#include "ED_view3d.h"
@@ -88,7 +89,6 @@ typedef struct PaintStroke {
/* Cached values */
ViewContext vc;
- bglMats mats;
Brush *brush;
UnifiedPaintSettings *ups;
@@ -146,9 +146,18 @@ static void paint_draw_smooth_cursor(bContext *C, int x, int y, void *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]);
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4ubv(paint->paint_cursor_col);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2f(pos, x, y);
+ immVertex2f(pos, stroke->last_mouse_position[0], stroke->last_mouse_position[1]);
+ immEnd();
+
+ immUnbindProgram();
+
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
}
@@ -160,36 +169,35 @@ static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata)
PaintStroke *stroke = customdata;
glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
- 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 = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("num_colors", 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(GWN_PRIM_LINES, 2);
- 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], stroke->last_mouse_position[1]);
+ immVertex2f(shdr_pos, stroke->constrained_pos[0], stroke->constrained_pos[1]);
}
else {
- sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
- x, y);
+ immVertex2f(shdr_pos, stroke->last_mouse_position[0], stroke->last_mouse_position[1]);
+ 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);
}
@@ -675,8 +683,6 @@ PaintStroke *paint_stroke_new(bContext *C,
float zoomx, zoomy;
view3d_set_viewcontext(C, &stroke->vc);
- if (stroke->vc.v3d)
- view3d_get_transformation(stroke->vc.ar, stroke->vc.rv3d, stroke->vc.obact, &stroke->mats);
stroke->get_location = get_location;
stroke->test_start = test_start;
@@ -1102,12 +1108,14 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
paint_stroke_add_sample(p, stroke, event->mval[0], event->mval[1], pressure);
paint_stroke_sample_average(stroke, &sample_average);
+#ifdef WITH_INPUT_NDOF
/* let NDOF motion pass through to the 3D view so we can paint and rotate simultaneously!
* this isn't perfect... even when an extra MOUSEMOVE is spoofed, the stroke discards it
* since the 2D deltas are zero -- code in this file needs to be updated to use the
* post-NDOF_MOTION MOUSEMOVE */
if (event->type == NDOF_MOTION)
return OPERATOR_PASS_THROUGH;
+#endif
/* one time initialization */
if (!stroke->stroke_init) {
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 31c471c3517..e36cc275ba9 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -59,8 +59,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
+#include "GPU_matrix.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
@@ -130,17 +129,12 @@ bool paint_convert_bb_to_rect(rcti *rect,
* 2D screens-space bounding box into four 3D planes) */
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;
@@ -148,7 +142,7 @@ void paint_calc_redraw_planes(float planes[4][4],
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);
}
@@ -290,8 +284,8 @@ static void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, c
/* get the needed opengl matrices */
glGetIntegerv(GL_VIEWPORT, view);
- glGetFloatv(GL_MODELVIEW_MATRIX, (float *)matrix);
- glGetFloatv(GL_PROJECTION_MATRIX, (float *)proj);
+ gpuGetModelViewMatrix(matrix);
+ gpuGetProjectionMatrix(proj);
view[0] = view[1] = 0;
mul_m4_m4m4(matrix, matrix, ob->obmat);
mul_m4_m4m4(matrix, proj, matrix);
@@ -447,7 +441,8 @@ 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;
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *ob = OBACT_NEW;
bool sample_success = false;
ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
bool use_material = (imapaint->mode == IMAGEPAINT_MODE_MATERIAL);
@@ -561,8 +556,9 @@ static int brush_curve_preset_exec(bContext *C, wmOperator *op)
if (br) {
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_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, sl, br->curve);
}
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 991025a4d5d..46d71ad0c45 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -36,6 +36,7 @@
#include "BLI_array_utils.h"
#include "BLI_bitmap.h"
#include "BLI_stack.h"
+#include "BLI_string_utils.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -56,7 +57,6 @@
#include "BKE_action.h"
#include "BKE_brush.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_deform.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
@@ -66,6 +66,8 @@
#include "BKE_report.h"
#include "BKE_colortools.h"
+#include "DEG_depsgraph.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -261,7 +263,7 @@ static bool make_vertexcol(Object *ob) /* single ob */
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);
}
@@ -275,7 +277,7 @@ static int wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active)
int mirrdef;
char name_flip[MAXBONENAME];
- BKE_deform_flip_side_name(name_flip, defgroup->name, false);
+ BLI_string_flip_side_name(name_flip, defgroup->name, false, sizeof(name_flip));
mirrdef = defgroup_name_index(ob, name_flip);
if (mirrdef == -1) {
if (BKE_defgroup_new(ob, name_flip)) {
@@ -364,7 +366,7 @@ bool ED_vpaint_fill(Object *ob, unsigned int 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;
}
@@ -449,7 +451,7 @@ bool ED_wpaint_fill(VPaint *wp, Object *ob, float paintweight)
copy_wpaint_prev(wp, NULL, 0);
- DAG_id_tag_update(&me->id, 0);
+ DEG_id_tag_update(&me->id, 0);
return true;
}
@@ -495,7 +497,7 @@ bool ED_vpaint_smooth(Object *ob)
MEM_freeN(mlooptag);
- DAG_id_tag_update(&me->id, 0);
+ DEG_id_tag_update(&me->id, 0);
return true;
}
@@ -540,7 +542,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;
}
@@ -1211,7 +1213,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;
}
@@ -1821,12 +1823,14 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op)
ED_vgroup_sync_from_pose(ob);
}
+ BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_NOCHECK);
+
/* Weightpaint works by overriding colors in mesh,
* so need to make sure we recalc on enter and
* 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);
@@ -2381,7 +2385,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(ob->data, BKE_MESH_BATCH_DIRTY_NOCHECK);
+
+ DEG_id_tag_update(ob->data, 0);
ED_region_tag_redraw(vc->ar);
}
@@ -2438,7 +2444,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);
}
@@ -2586,8 +2592,10 @@ static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op)
BKE_paint_init(scene, ePaintVertex, PAINT_CURSOR_VERTEX_PAINT);
}
+ BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_NOCHECK);
+
/* 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);
@@ -2858,12 +2866,14 @@ static void vpaint_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);
+ BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_NOCHECK);
+
ED_region_tag_redraw(vc->ar);
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! */
@@ -2889,7 +2899,7 @@ static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
MEM_freeN(vpd->mlooptag);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
- DAG_id_tag_update(&me->id, 0);
+ DEG_id_tag_update(&me->id, 0);
MEM_freeN(vpd);
}
@@ -2972,7 +2982,7 @@ static int weight_from_bones_exec(bContext *C, wmOperator *op)
create_vgroups_from_armature(op->reports, 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;
@@ -3161,7 +3171,7 @@ static int paint_weight_gradient_modal(bContext *C, wmOperator *op, const wmEven
free_wpaint_prev(wp);
}
- 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) {
@@ -3255,7 +3265,7 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
dm->foreachMappedVert(dm, gradientVertUpdate__mapFunc, &data, DM_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) {
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index fe0fb3f5035..9be196d1561 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -57,7 +57,6 @@
#include "BKE_brush.h"
#include "BKE_ccg.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_key.h"
@@ -73,6 +72,8 @@
#include "BKE_subsurf.h"
#include "BKE_colortools.h"
+#include "DEG_depsgraph.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -626,8 +627,7 @@ static 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 */
@@ -635,7 +635,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
@@ -821,10 +821,9 @@ static float calc_overlap(StrokeCache *cache, const char symm, const char axis,
flip_v3_v3(mirror, cache->true_location, symm);
if (axis != 0) {
- float mat[4][4];
- unit_m4(mat);
- rotate_m4(mat, axis, angle);
- mul_m4_v3(mat, mirror);
+ float mat[3][3];
+ axis_angle_to_mat3_single(mat, axis, angle);
+ mul_m3_v3(mat, mirror);
}
/* distsq = len_squared_v3v3(mirror, cache->traced_location); */
@@ -2045,6 +2044,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,
@@ -4188,7 +4191,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
/* compute 3d coordinate at same z from original location + mouse */
mul_v3_m4v3(loc, ob->obmat, cache->orig_grab_location);
- ED_view3d_win_to_3d(cache->vc->ar, loc, mouse, grab_location);
+ ED_view3d_win_to_3d(cache->vc->v3d, cache->vc->ar, loc, mouse, grab_location);
/* compute delta to move verts by */
if (!cache->first_time) {
@@ -4609,7 +4612,7 @@ static void sculpt_flush_update(bContext *C)
GPU_drawobject_free(ob->derivedFinal);
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 {
@@ -4639,6 +4642,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(ob->data, BKE_MESH_BATCH_DIRTY_SCULPT_COORDS);
}
/* Returns whether the mouse/stylus is over the mesh (1)
@@ -4688,7 +4694,7 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *UNUSED(st
sculpt_restore_mesh(sd, ob);
if (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT) {
- BKE_pbvh_bmesh_detail_size_set(ss->pbvh, sd->constant_detail / 100.0f);
+ BKE_pbvh_bmesh_detail_size_set(ss->pbvh, 1.0f / sd->constant_detail);
}
else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
BKE_pbvh_bmesh_detail_size_set(ss->pbvh, ss->cache->radius * sd->detail_percent / 100.0f);
@@ -4793,7 +4799,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);
}
@@ -5362,8 +5368,12 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
if (mmd)
multires_force_update(ob);
- if (flush_recalc || (ob->sculpt && ob->sculpt->bm))
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ /* Always for now, so leaving sculpt mode always ensures scene is in
+ * a consistent state.
+ */
+ if (true || flush_recalc || (ob->sculpt && ob->sculpt->bm)) {
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
/* Dynamic topology must be disabled before exiting sculpt
@@ -5387,7 +5397,7 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
ob->mode |= mode_flag;
if (flush_recalc)
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
/* Create persistent sculpt mode data */
if (!ts->sculpt) {
@@ -5406,7 +5416,7 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
if (!ts->sculpt->detail_percent)
ts->sculpt->detail_percent = 25;
if (ts->sculpt->constant_detail == 0.0f)
- ts->sculpt->constant_detail = 30.0f;
+ ts->sculpt->constant_detail = 3.0f;
/* Set sane default tiling offsets */
if (!ts->sculpt->paint.tile_offset[0]) ts->sculpt->paint.tile_offset[0] = 1.0f;
@@ -5543,7 +5553,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
size = max_fff(bb_max[0], bb_max[1], bb_max[2]);
/* update topology size */
- BKE_pbvh_bmesh_detail_size_set(ss->pbvh, sd->constant_detail / 100.0f);
+ BKE_pbvh_bmesh_detail_size_set(ss->pbvh, 1.0f / sd->constant_detail);
sculpt_undo_push_begin("Dynamic topology flood fill");
sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_COORDS);
@@ -5608,7 +5618,8 @@ static void sample_detail(bContext *C, int ss_co[2])
ray_start, ray_normal, false);
if (srd.hit) {
- sd->constant_detail = srd.detail * 100.0f;
+ /* convert edge length to detail resolution */
+ sd->constant_detail = 1.0f / srd.detail;
}
}
@@ -5693,11 +5704,11 @@ 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", NULL, 0);
- RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.constant_detail");
+ set_brush_rc_props(&props_ptr, "sculpt", "constant_detail_resolution", NULL, 0);
+ 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", NULL, 0);
+ set_brush_rc_props(&props_ptr, "sculpt", "constant_detail_resolution", NULL, 0);
RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_percent");
}
else {
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 44bd872d107..9d55cc1369e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -51,12 +51,12 @@
#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_subsurf.h"
+#include "DEG_depsgraph.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -555,7 +555,7 @@ static void sculpt_undo_restore(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);
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index fd2a0b15cb9..ee6f25ee44e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -46,15 +46,19 @@
#include "BKE_paint.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_mesh_mapping.h"
#include "BKE_customdata.h"
#include "BKE_editmesh.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 "WM_api.h"
#include "WM_types.h"
@@ -64,9 +68,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
@@ -173,7 +174,7 @@ static int uv_sculpt_brush_poll_do(bContext *C, const bool check_region)
}
em = BKE_editmesh_from_object(obedit);
- ret = EDBM_mtexpoly_check(em);
+ ret = EDBM_uv_check(em);
if (ret) {
ARegion *ar = CTX_wm_region(C);
@@ -212,18 +213,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();
-
- glTranslatef((float)x, (float)y, 0.0f);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3fvAlpha(brush->add_col, alpha);
- 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);
+ imm_draw_circle_wire(pos, (float)x, (float)y, size, 40);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
- glPopMatrix();
+ immUnbindProgram();
}
#undef PX_SIZE_FADE_MAX
#undef PX_SIZE_FADE_MIN
@@ -899,7 +899,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/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index 03f2e146b7d..d103530fa81 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -217,32 +217,56 @@ static void SOUND_OT_open_mono(wmOperatorType *ot)
/* ******************************************************* */
-static int sound_update_animation_flags_exec(bContext *C, wmOperator *UNUSED(op))
+static void sound_update_animation_flags(Scene *scene);
+
+static int sound_update_animation_flags_cb(Sequence *seq, void *user_data)
{
- Sequence *seq;
- Scene *scene = CTX_data_scene(C);
struct FCurve *fcu;
+ Scene *scene = (Scene *)user_data;
bool driven;
- SEQ_BEGIN(scene->ed, seq)
- {
- fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "volume", 0, &driven);
- if (fcu || driven)
- seq->flag |= SEQ_AUDIO_VOLUME_ANIMATED;
- else
- seq->flag &= ~SEQ_AUDIO_VOLUME_ANIMATED;
+ fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "volume", 0, &driven);
+ if (fcu || driven)
+ seq->flag |= SEQ_AUDIO_VOLUME_ANIMATED;
+ else
+ seq->flag &= ~SEQ_AUDIO_VOLUME_ANIMATED;
- fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "pitch", 0, &driven);
- if (fcu || driven)
- seq->flag |= SEQ_AUDIO_PITCH_ANIMATED;
- else
- seq->flag &= ~SEQ_AUDIO_PITCH_ANIMATED;
+ fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "pitch", 0, &driven);
+ if (fcu || driven)
+ seq->flag |= SEQ_AUDIO_PITCH_ANIMATED;
+ else
+ seq->flag &= ~SEQ_AUDIO_PITCH_ANIMATED;
- fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "pan", 0, &driven);
- if (fcu || driven)
- seq->flag |= SEQ_AUDIO_PAN_ANIMATED;
- else
- seq->flag &= ~SEQ_AUDIO_PAN_ANIMATED;
+ fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "pan", 0, &driven);
+ if (fcu || driven)
+ seq->flag |= SEQ_AUDIO_PAN_ANIMATED;
+ else
+ seq->flag &= ~SEQ_AUDIO_PAN_ANIMATED;
+
+ if (seq->type == SEQ_TYPE_SCENE) {
+ /* TODO(sergey): For now we do manual recursion into the scene strips,
+ * but perhaps it should be covered by recursive_apply?
+ */
+ sound_update_animation_flags(seq->scene);
+ }
+
+ return 0;
+}
+
+static void sound_update_animation_flags(Scene *scene)
+{
+ struct FCurve *fcu;
+ bool driven;
+ Sequence *seq;
+
+ if (scene->id.tag & LIB_TAG_DOIT) {
+ return;
+ }
+ scene->id.tag |= LIB_TAG_DOIT;
+
+ SEQ_BEGIN(scene->ed, seq)
+ {
+ BKE_sequencer_recursive_apply(seq, sound_update_animation_flags_cb, scene);
}
SEQ_END
@@ -251,7 +275,12 @@ static int sound_update_animation_flags_exec(bContext *C, wmOperator *UNUSED(op)
scene->audio.flag |= AUDIO_VOLUME_ANIMATED;
else
scene->audio.flag &= ~AUDIO_VOLUME_ANIMATED;
+}
+static int sound_update_animation_flags_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ BKE_main_id_tag_idcode(CTX_data_main(C), ID_SCE, LIB_TAG_DOIT, false);
+ sound_update_animation_flags(CTX_data_scene(C));
return OPERATOR_FINISHED;
}
@@ -289,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_update_for_newframe(bmain->eval_ctx, bmain, scene);
}
scene->r.cfra = oldfra;
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay);
+ BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene);
return OPERATOR_FINISHED;
}
@@ -348,12 +377,14 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op)
BLI_path_abs(filename, bmain->name);
if (split)
- result = AUD_mixdown_per_channel(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA) * specs.rate / FPS,
+ result = AUD_mixdown_per_channel(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA + 1) * specs.rate / FPS,
accuracy, filename, specs, container, codec, bitrate);
else
- result = AUD_mixdown(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA) * specs.rate / FPS,
+ result = AUD_mixdown(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA + 1) * specs.rate / FPS,
accuracy, filename, specs, container, codec, bitrate);
+ BKE_sound_reset_scene_specs(scene);
+
if (result) {
BKE_report(op->reports, RPT_ERROR, result);
return OPERATOR_CANCELLED;
@@ -639,7 +670,7 @@ static void SOUND_OT_mixdown(wmOperatorType *ot)
/* identifiers */
ot->name = "Mixdown";
- ot->description = "Mixes the scene's audio to a sound file";
+ ot->description = "Mix the scene's audio to a sound file";
ot->idname = "SOUND_OT_mixdown";
/* api callbacks */
@@ -784,7 +815,7 @@ static void SOUND_OT_unpack(wmOperatorType *ot)
/* properties */
RNA_def_enum(ot->srna, "method", rna_enum_unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack");
- RNA_def_string(ot->srna, "id", NULL, MAX_ID_NAME - 2, "Sound Name", "Sound datablock name to unpack"); /* XXX, weark!, will fail with library, name collisions */
+ RNA_def_string(ot->srna, "id", NULL, MAX_ID_NAME - 2, "Sound Name", "Sound data-block name to unpack"); /* XXX, weark!, will fail with library, name collisions */
}
/* ******************************************************* */
diff --git a/source/blender/editors/space_action/action_buttons.c b/source/blender/editors/space_action/action_buttons.c
index bfc808f6d83..80ec9107984 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_main.h"
#include "BKE_global.h"
diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c
index 6755a6316cc..fdf2dfe8371 100644
--- a/source/blender/editors/space_action/action_data.c
+++ b/source/blender/editors/space_action/action_data.c
@@ -669,8 +669,8 @@ void ACTION_OT_unlink(wmOperatorType *ot)
ot->poll = action_unlink_poll;
/* properties */
- prop = RNA_def_boolean(ot->srna, "force_delete", false, "Force Delete",
- "Clear Fake User and remove copy stashed in this datablock's NLA stack");
+ prop = RNA_def_boolean(ot->srna, "force_delete", false, "Force Delete", "Clear Fake User and remove "
+ "copy stashed in this data-block's NLA stack");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c
index 9fc96e06299..11ac1d60f39 100644
--- a/source/blender/editors/space_action/action_draw.c
+++ b/source/blender/editors/space_action/action_draw.c
@@ -61,6 +61,7 @@
#include "ED_keyframes_draw.h"
#include "action_intern.h"
+#include "GPU_immediate.h"
/* ************************************************************************* */
/* Channel List */
@@ -156,20 +157,19 @@ 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];
+ const bool show_group_colors = !(saction->flag & SACTION_NODRAWGCOLORS);
+
/* get theme colors */
UI_GetThemeColor3ubv(TH_BACK, col2);
@@ -192,10 +192,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)
*/
@@ -203,6 +203,12 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
/* first backdrop strips */
y = (float)(-ACHANNEL_HEIGHT(ac));
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
glEnable(GL_BLEND);
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -221,72 +227,85 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
/* determine if channel is selected */
if (acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT))
sel = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT);
-
+
if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY)) {
switch (ale->type) {
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 ? 0x45 : 0x22);
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 ? 0x45 : 0x22);
break;
}
case ANIMTYPE_GROUP:
{
- if (sel) glColor4ub(col1a[0], col1a[1], col1a[2], 0x22);
- else glColor4ub(col2a[0], col2a[1], col2a[2], 0x22);
+ bActionGroup *agrp = ale->data;
+ if (show_group_colors && agrp->customCol) {
+ if (sel) {
+ immUniformColor3ubvAlpha((unsigned char *)agrp->cs.select, 0x45);
+ }
+ else {
+ immUniformColor3ubvAlpha((unsigned char *)agrp->cs.solid, 0x1D);
+ }
+ }
+ else {
+ immUniformColor3ubvAlpha(sel ? col1a : col2a, 0x22);
+ }
break;
}
- default:
+ case ANIMTYPE_FCURVE:
{
- if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
- else glColor4ub(col2[0], col2[1], col2[2], 0x22);
+ FCurve *fcu = ale->data;
+ if (show_group_colors && fcu->grp && fcu->grp->customCol) {
+ immUniformColor3ubvAlpha((unsigned char *)fcu->grp->cs.active, sel ? 0x65 : 0x0B);
+ }
+ else {
+ immUniformColor3ubvAlpha(sel ? col1 : col2, 0x22);
+ }
break;
}
+ default:
+ {
+ immUniformColor3ubvAlpha(sel ? col1 : col2, 0x22);
+ }
}
/* 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));
+ immUniformColor3ubvAlpha(sel ? col1 : col2, 0x22);
+ 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(sel ? col1 : col2, 0x44);
+ 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));
+ immUniformColor3ubvAlpha(sel ? col1 : col2, 0x22);
+ 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(sel ? col1 : col2, 0x44);
+ immRectf(pos, v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac));
}
}
}
@@ -295,18 +314,29 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
y -= ACHANNEL_STEP(ac);
}
glDisable(GL_BLEND);
-
- /* Draw keyframes
+
+ /* black line marking 'current frame' for Time-Slide transform mode */
+ if (saction->flag & SACTION_MOVING) {
+ immUniformColor3f(0.0f, 0.0f, 0.0f);
+
+ immBegin(GWN_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.
* This is to try to optimize this for heavier data sets
* 2) Keyframes which are out of view horizontally are disregarded
*/
y = (float)(-ACHANNEL_HEIGHT(ac));
-
+
for (ale = anim_data.first; ale; ale = ale->next) {
const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac));
-
+
/* check if visible */
if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
@@ -314,7 +344,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
/* check if anything to show for this channel */
if (ale->datatype != ALE_NONE) {
adt = ANIM_nla_mapping_get(ac, ale);
-
+
/* draw 'keyframes' for each specific datatype */
switch (ale->datatype) {
case ALE_ALL:
@@ -344,20 +374,10 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
}
}
}
-
+
y -= ACHANNEL_STEP(ac);
}
-
- /* free tempolary 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);
-
- glBegin(GL_LINES);
- glVertex2f(saction->timeslide, v2d->cur.ymin - EXTRA_SCROLL_PAD);
- glVertex2f(saction->timeslide, v2d->cur.ymax);
- glEnd();
- }
+ /* free temporary channels used for drawing */
+ ANIM_animdata_freelist(&anim_data);
}
diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c
index a261202b690..718a4fd3c38 100644
--- a/source/blender/editors/space_action/action_ops.c
+++ b/source/blender/editors/space_action/action_ops.c
@@ -240,7 +240,9 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
/* 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);
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index 671d6bb083e..fca54b282f8 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -308,7 +308,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(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -337,7 +339,7 @@ static void action_channel_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(
}
break;
case NC_GPENCIL:
- if (wmn->action == NA_RENAME)
+ if (ELEM(wmn->action, NA_RENAME, NA_SELECTED))
ED_region_tag_redraw(ar);
break;
case NC_ID:
@@ -351,7 +353,9 @@ 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 action_main_region_listener(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -391,7 +395,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);
@@ -400,17 +408,23 @@ static void action_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa)
}
/* editor level listener */
-static void action_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
+static void action_listener(
+ bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, const Scene *UNUSED(scene))
{
SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
/* context changes */
switch (wmn->category) {
case NC_GPENCIL:
- if (wmn->action == NA_EDITED) {
- /* only handle this event in GPencil mode for performance considerations */
- if (saction->mode == SACTCONT_GPENCIL)
+ /* only handle these events in GPencil mode for performance considerations */
+ if (saction->mode == SACTCONT_GPENCIL) {
+ if (wmn->action == NA_EDITED) {
ED_area_tag_redraw(sa);
+ }
+ else if (wmn->action == NA_SELECTED) {
+ saction->flag |= SACTION_TEMP_NEEDCHANSYNC;
+ ED_area_tag_refresh(sa);
+ }
}
break;
case NC_ANIMATION:
@@ -502,7 +516,9 @@ static void action_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
}
}
-static void action_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void action_header_region_listener(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
// SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
@@ -554,7 +570,9 @@ static void action_buttons_area_draw(const bContext *C, ARegion *ar)
ED_region_panels(C, ar, NULL, -1, true);
}
-static void action_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void action_region_listener(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index 7fb79940ffe..43543428a21 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"
@@ -65,6 +66,7 @@
#include "ED_clip.h"
#include "ED_mask.h"
#include "ED_sequencer.h"
+#include "ED_manipulator_library.h"
#include "io_ops.h"
@@ -99,6 +101,8 @@ void ED_spacetypes_init(void)
// ...
/* register operator types for screen and all spaces */
+ ED_operatortypes_workspace();
+ ED_operatortypes_scene();
ED_operatortypes_screen();
ED_operatortypes_anim();
ED_operatortypes_animchannels();
@@ -122,12 +126,25 @@ void ED_spacetypes_init(void)
ED_operatortypes_view2d();
ED_operatortypes_ui();
-
- /* register operators */
+
+ /* manipulator types */
+ ED_manipulatortypes_dial_3d();
+ ED_manipulatortypes_grab_3d();
+ ED_manipulatortypes_arrow_2d();
+ ED_manipulatortypes_arrow_3d();
+ ED_manipulatortypes_primitive_3d();
+ ED_manipulatortypes_cage_2d();
+
+ /* register types for operators and manipulators */
spacetypes = BKE_spacetypes_list();
for (type = spacetypes->first; type; type = type->next) {
- if (type->operatortypes)
+ /* init manipulator types first, operator-types need them */
+ if (type->manipulators) {
+ type->manipulators();
+ }
+ if (type->operatortypes) {
type->operatortypes();
+ }
}
/* register internal render callbacks */
@@ -253,7 +270,6 @@ void ED_region_draw_cb_draw(const bContext *C, ARegion *ar, int type)
for (rdc = ar->type->drawcalls.first; rdc; rdc = rdc->next) {
if (rdc->type == type) {
- UI_reinit_gl_state();
rdc->draw(C, ar, rdc->customdata);
}
}
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index 5b03bdd7761..f6c15f4d030 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -49,6 +49,7 @@
#include "BKE_context.h"
#include "BKE_action.h"
+#include "BKE_layer.h"
#include "BKE_material.h"
#include "BKE_modifier.h"
#include "BKE_paint.h"
@@ -180,7 +181,9 @@ static int buttons_context_path_object(ButsContextPath *path)
/* 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;
+
+ SceneLayer *sl = BKE_scene_layer_context_active_PLACEHOLDER(scene);
+ ob = (sl->basact) ? sl->basact->object : NULL;
if (ob) {
RNA_id_pointer_create(&ob->id, &path->ptr[path->len]);
@@ -208,6 +211,7 @@ static int buttons_context_path_data(ButsContextPath *path, int type)
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_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;
/* 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;
@@ -367,7 +371,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 +385,10 @@ 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) {
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ br = BKE_paint_brush(BKE_paint_get_active(scene, sl));
+ }
if (br) {
RNA_id_pointer_create((ID *)br, &path->ptr[path->len]);
@@ -396,7 +402,7 @@ 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 */
@@ -414,7 +420,7 @@ static int buttons_context_path_texture(ButsContextPath *path, ButsContextTextur
if (id) {
if (GS(id->name) == ID_BR)
- buttons_context_path_brush(path);
+ buttons_context_path_brush(C, path);
else if (GS(id->name) == ID_MA)
buttons_context_path_material(path, false, true);
else if (GS(id->name) == ID_WO)
@@ -553,6 +559,36 @@ static bool buttons_context_linestyle_pinnable(const bContext *C)
}
#endif
+static int buttons_context_path_collection(const bContext *C, ButsContextPath *path)
+{
+ PointerRNA *ptr = &path->ptr[path->len - 1];
+
+ /* if we already have a (pinned) Collection, we're done */
+ if (RNA_struct_is_a(ptr->type, &RNA_LayerCollection)) {
+ return 1;
+ }
+
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ LayerCollection *sc = BKE_layer_collection_get_active(sl);
+
+ if (sc) {
+ RNA_pointer_create(NULL, &RNA_LayerCollection, sc, &path->ptr[path->len]);
+ path->len++;
+
+ /* temporary object in context path to get edit mode */
+ Object *ob = CTX_data_active_object(C);
+ if (ob) {
+ RNA_id_pointer_create(&ob->id, &path->ptr[path->len]);
+ path->len++;
+ }
+
+ return 1;
+ }
+
+ /* no path to a collection possible */
+ return 0;
+}
+
static int buttons_context_path(const bContext *C, ButsContextPath *path, int mainb, int flag)
{
SpaceButs *sbuts = CTX_wm_space_buts(C);
@@ -617,7 +653,7 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma
found = buttons_context_path_material(path, false, (sbuts->texuser != NULL));
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);
@@ -627,6 +663,9 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma
case BCONTEXT_BONE_CONSTRAINT:
found = buttons_context_path_pose_bone(path);
break;
+ case BCONTEXT_COLLECTION:
+ found = buttons_context_path_collection(C, path);
+ break;
default:
found = 0;
break;
@@ -740,11 +779,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", "lamp", "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)
@@ -809,6 +848,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;
@@ -1064,6 +1107,10 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
set_pointer_type(path, result, &RNA_FreestyleLineStyle);
return 1;
}
+ else if (CTX_data_equals(member, "collection")) {
+ set_pointer_type(path, result, &RNA_LayerCollection);
+ return 1;
+ }
else {
return 0; /* not found */
}
@@ -1106,7 +1153,7 @@ void buttons_context_draw(const bContext *C, uiLayout *layout)
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 datablock displayed"));
+ 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);
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index 58c538c4ee5..1d67ac620b0 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -470,7 +470,7 @@ void buttons_texture_context_compute(const bContext *C, SpaceButs *sbuts)
}
else {
/* set one user as active based on active index */
- if (ct->index == BLI_listbase_count_ex(&ct->users, ct->index + 1))
+ if (ct->index >= BLI_listbase_count_ex(&ct->users, ct->index + 1))
ct->index = 0;
ct->user = BLI_findlink(&ct->users, ct->index);
@@ -587,6 +587,8 @@ static void template_texture_user_menu(bContext *C, uiLayout *layout, void *UNUS
last_category = user->category;
}
+
+ UI_block_flag_enable(block, UI_BLOCK_NO_FLIP);
}
void uiTemplateTextureUser(uiLayout *layout, bContext *C)
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index e4c23ad74f8..299ab7171d6 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -171,11 +171,27 @@ static void buttons_main_region_draw(const bContext *C, ARegion *ar)
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);
+ else if (sbuts->mainb == BCONTEXT_COLLECTION)
+ ED_region_panels(C, ar, "collection", sbuts->mainb, vertical);
sbuts->re_align = 0;
sbuts->mainbo = sbuts->mainb;
}
+static void buttons_main_region_listener(
+ bScreen *UNUSED(sc), 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);
@@ -218,7 +234,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(
+ bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, const Scene *UNUSED(scene))
{
SpaceButs *sbuts = sa->spacedata.first;
@@ -468,6 +485,7 @@ void ED_spacetype_buttons(void)
art->regionid = RGN_TYPE_WINDOW;
art->init = buttons_main_region_init;
art->draw = buttons_main_region_draw;
+ art->listener = buttons_main_region_listener;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
BLI_addhead(&st->regiontypes, art);
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 0378c68d12c..eb9aadd2e72 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"
@@ -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;
diff --git a/source/blender/editors/space_clip/clip_dopesheet_draw.c b/source/blender/editors/space_clip/clip_dopesheet_draw.c
index 4bf4c1e7baa..0f06d66d033 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,9 @@
#include "RNA_access.h"
+#include "GPU_draw.h"
+#include "GPU_immediate.h"
+
#include "clip_intern.h" /* own include */
static void track_channel_color(MovieTrackingTrack *track, float default_color[3], float color[3])
@@ -72,78 +73,25 @@ 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();
+ immAttrib4fv(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;
MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
MovieTrackingDopesheetCoverageSegment *coverage_segment;
-
+
for (coverage_segment = dopesheet->coverage_segments.first;
coverage_segment;
coverage_segment = coverage_segment->next)
@@ -153,12 +101,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 +124,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);
+ unsigned int keyframe_ct = 0;
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos_id = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_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);
@@ -197,7 +149,7 @@ void clip_draw_dopesheet_main(SpaceClip *sc, ARegion *ar, Scene *scene)
glEnable(GL_BLEND);
- 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 +160,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 +169,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_ct += 2;
}
else {
- draw_keyframe_shape(start_frame, y, xscale, yscale, sel, alpha);
+ keyframe_ct++;
}
}
@@ -253,9 +198,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_ct++;
}
i++;
@@ -266,6 +209,76 @@ void clip_draw_dopesheet_main(SpaceClip *sc, ARegion *ar, Scene *scene)
y -= CHANNEL_STEP;
}
+ immUnbindProgram();
+
+ if (keyframe_ct > 0) {
+ /* draw keyframe markers */
+ format = immVertexFormat();
+ pos_id = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int size_id = GWN_vertformat_attr_add(format, "size", GWN_COMP_F32, 1, GWN_FETCH_FLOAT);
+ unsigned int color_id = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 4, GWN_FETCH_FLOAT);
+ unsigned int outline_color_id = GWN_vertformat_attr_add(format, "outlineColor", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND);
+ GPU_enable_program_point_size();
+ immBegin(GWN_PRIM_POINTS, keyframe_ct);
+
+ /* all same size with black outline */
+ immAttrib1f(size_id, 2.0f * STRIP_HEIGHT_HALF);
+ immAttrib4ub(outline_color_id, 0, 0, 0, 255);
+
+ 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();
+ }
+
glDisable(GL_BLEND);
}
@@ -279,22 +292,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 +315,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;
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_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 +359,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,12 +373,12 @@ 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);
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index 695d04d3850..95ff76e48cc 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -55,10 +55,11 @@
#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 "WM_types.h"
@@ -66,26 +67,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(GWN_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);
}
}
@@ -166,6 +166,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);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_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 +192,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 +212,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,8 +229,9 @@ 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);
+ }
}
}
@@ -233,15 +240,22 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc
/* 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 = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_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 +289,16 @@ static void draw_movieclip_muted(ARegion *ar, int width, int height, float zoomx
{
int x, y;
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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,
@@ -297,7 +316,7 @@ static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar,
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- fdrawcheckerboard(x, y, x + zoomx * ibuf->x, y + zoomy * ibuf->y);
+ imm_draw_checker_box(x, y, x + zoomx * ibuf->x, y + zoomy * ibuf->y);
}
/* non-scaled proxy shouldn't use filtering */
@@ -307,13 +326,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;
@@ -335,31 +348,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 = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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);
+
+ gpuPushMatrix();
+ gpuTranslate2f(x, y);
+
+ gpuScale2f(zoomx, zoomy);
+ gpuMultMatrix(sc->stabmat);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
- glPushMatrix();
- glTranslatef(x, y, 0.0f);
+ immUniform1i("num_colors", 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_line_box(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();
+ gpuPopMatrix();
glDisable(GL_COLOR_LOGIC_OP);
- GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
}
}
@@ -423,69 +442,113 @@ static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackin
i++;
}
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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);
- for (i = a; i < b; i++) {
- if (i != curindex)
- glVertex2f(path[i][0], path[i][1]);
+ if ((b - a - 1) >= 1) {
+ glPointSize(5.0f);
+
+ immBegin(GWN_PRIM_POINTS, b - a - 1);
+
+ for (i = a; i < b; i++) {
+ if (i != curindex) {
+ immVertex2f(pos, path[i][0], path[i][1]);
+ }
+ }
+
+ immEnd();
}
- glEnd();
}
- glLineWidth(3.0f);
- glBegin(GL_LINE_STRIP);
- for (i = a; i < b; i++)
- glVertex2f(path[i][0], path[i][1]);
- glEnd();
- }
+ if ((b - a) >= 2) {
+ glLineWidth(3.0f);
+
+ immBegin(GWN_PRIM_LINE_STRIP, b - a);
+
+ for (i = a; i < b; i++) {
+ immVertex2f(pos, path[i][0], path[i][1]);
+ }
- UI_ThemeColor(TH_PATH_BEFORE);
+ immEnd();
+ }
+ }
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) {
+ immUniformThemeColor(TH_PATH_BEFORE);
+
+ immBegin(GWN_PRIM_POINTS, curindex - a);
+
+ for (i = a; i < curindex; i++) {
+ immVertex2f(pos, path[i][0], path[i][1]);
+ }
+
+ immEnd();
}
- glEnd();
- }
- UI_ThemeColor(TH_PATH_BEFORE);
+ if ((b - curindex - 1) >= 1) {
+ immUniformThemeColor(TH_PATH_AFTER);
+
+ immBegin(GWN_PRIM_POINTS, b - curindex - 1);
+
+ for (i = curindex + 1; i < b; i++) {
+ immVertex2f(pos, path[i][0], path[i][1]);
+ }
+
+ immEnd();
+ }
+ }
glLineWidth(1);
- glBegin(GL_LINE_STRIP);
- for (i = a; i < b; i++) {
- if (i == count + 1)
- UI_ThemeColor(TH_PATH_AFTER);
+ if ((curindex - a + 1) >= 2) {
+ immUniformThemeColor(TH_PATH_BEFORE);
+
+ immBegin(GWN_PRIM_LINE_STRIP, curindex - a + 1);
+
+ for (i = a; i <= curindex; i++) {
+ immVertex2f(pos, path[i][0], path[i][1]);
+ }
+
+ immEnd();
+ }
+
+ if ((b - curindex) >= 2) {
+ immUniformThemeColor(TH_PATH_AFTER);
+
+ immBegin(GWN_PRIM_LINE_STRIP, b - curindex);
+
+ for (i = curindex; i < b; i++) {
+ immVertex2f(pos, path[i][0], path[i][1]);
+ }
- glVertex2f(path[i][0], path[i][1]);
+ immEnd();
}
- glEnd();
+
+ immUnbindProgram();
}
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);
+ immUniformThemeColor(TH_MARKER_OUTLINE);
+
if ((marker->flag & MARKER_DISABLED) == 0) {
float pos[2];
float p[2];
@@ -500,51 +563,54 @@ static void draw_marker_outline(SpaceClip *sc, MovieTrackingTrack *track, MovieT
marker->pattern_corners[2], marker->pattern_corners[3]))
{
glPointSize(tiny ? 3.0f : 4.0f);
- glBegin(GL_POINTS);
- glVertex2f(pos[0], pos[1]);
- glEnd();
+
+ immBegin(GWN_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(GWN_PRIM_LINES, 8);
+
+ immVertex2f(position, pos[0] + px[0] * 2, pos[1]);
+ immVertex2f(position, 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] - px[0] * 2, pos[1]);
- glVertex2f(pos[0] - px[0] * 8, pos[1]);
+ 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);
+ 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();
+ immEnd();
}
}
/* pattern and search outline */
- glPushMatrix();
- glTranslate2fv(marker_pos);
+ gpuPushMatrix();
+ gpuTranslate2fv(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(GWN_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_line_box(position, marker->search_min[0],
+ marker->search_min[1],
+ marker->search_max[0],
+ marker->search_max[1]);
+ }
+
+ gpuPopMatrix();
}
static void track_colors(MovieTrackingTrack *track, int act, float col[3], float scol[3])
@@ -568,11 +634,12 @@ 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);
@@ -581,23 +648,34 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra
glLineWidth(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];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniform1i("num_colors", 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);
@@ -609,123 +687,114 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra
marker->pattern_corners[2], marker->pattern_corners[3]))
{
glPointSize(tiny ? 1.0f : 2.0f);
- glBegin(GL_POINTS);
- glVertex2f(pos[0], pos[1]);
- glEnd();
+
+ immUniform1f("dash_factor", 2.0f); /* Solid "line" */
+
+ immBegin(GWN_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(GWN_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]);
- 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);
+ 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);
- glEnd();
+ immEnd();
+
+ 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(GWN_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);
-
- 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);
- }
+ gpuPushMatrix();
+ gpuTranslate2fv(marker_pos);
- 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(GWN_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_line_box(shdr_pos, marker->search_min[0], marker->search_min[1],
+ marker->search_max[0], marker->search_max[1]);
}
- glPopMatrix();
+ gpuPopMatrix();
+
+ /* Restore default shader */
+ immUnbindProgram();
+
+ const uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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)
@@ -746,7 +815,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;
@@ -758,15 +827,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;
@@ -778,15 +842,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(GWN_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;
@@ -801,11 +866,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);
+ gpuPushMatrix();
+ gpuTranslate2fv(marker_pos);
dx = 6.0f / width / sc->zoom;
dy = 6.0f / height / sc->zoom;
@@ -822,17 +887,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)) {
@@ -842,16 +904,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 ** */
@@ -861,18 +920,16 @@ static void draw_marker_slide_zones(SpaceClip *sc, MovieTrackingTrack *track, Mo
glLineWidth(outline ? 3.0f : 1.0f);
- glBegin(GL_LINES);
- glVertex2f(0.0f, 0.0f);
- glVertex2fv(tilt_ctrl);
- glEnd();
-
- GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ immBegin(GWN_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();
+ gpuPopMatrix();
}
static void draw_marker_texts(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
@@ -890,16 +947,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) &&
@@ -960,10 +1018,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,
@@ -1060,9 +1115,6 @@ static void draw_plane_marker_image(Scene *scene,
glBlendFunc(GL_SRC_ALPHA, GL_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);
glBindTexture(GL_TEXTURE_2D, texid);
@@ -1073,20 +1125,38 @@ 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);
+ gpuPushMatrix();
+ gpuMultMatrix(gl_matrix);
+
+ Gwn_VertFormat *imm_format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(imm_format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int texCoord = GWN_vertformat_attr_add(imm_format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR);
+ immUniformColor4f(1.0f, 1.0f, 1.0f, plane_track->image_opacity);
+ immUniform1i("image", GL_TEXTURE0);
+
+ immBegin(GWN_PRIM_TRI_FAN, 4);
+
+ immAttrib2f(texCoord, 0.0f, 0.0f);
+ immVertex2f(pos, 0.0f, 0.0f);
+
+ immAttrib2f(texCoord, 1.0f, 0.0f);
+ immVertex2f(pos, 1.0f, 0.0f);
+
+ immAttrib2f(texCoord, 1.0f, 1.0f);
+ immVertex2f(pos, 1.0f, 1.0f);
+
+ immAttrib2f(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();
+ gpuPopMatrix();
glBindTexture(GL_TEXTURE_2D, 0);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
if (transparent) {
glDisable(GL_BLEND);
@@ -1109,20 +1179,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;
@@ -1132,66 +1189,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 = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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];
+ glGetFloatv(GL_VIEWPORT, 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("num_colors", 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);
+ glLineWidth(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(GWN_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(GWN_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(GWN_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();
}
}
@@ -1243,13 +1326,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);
+ gpuPushMatrix();
+ gpuTranslate2f(x, y);
- glPushMatrix();
- glScalef(zoomx, zoomy, 0);
- glMultMatrixf(sc->stabmat);
- glScalef(width, height, 0);
+ gpuPushMatrix();
+ gpuScale2f(zoomx, zoomy);
+ gpuMultMatrix(sc->stabmat);
+ gpuScale2f(width, height);
act_track = BKE_tracking_track_get_active(tracking);
@@ -1315,6 +1398,10 @@ static void draw_tracking_tracks(SpaceClip *sc, Scene *scene, ARegion *ar, Movie
}
}
+ unsigned int position = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
/* markers outline and non-selected areas */
track = tracksbase->first;
fp = marker_pos;
@@ -1325,10 +1412,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;
@@ -1351,8 +1438,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)
@@ -1371,8 +1458,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);
}
}
}
@@ -1381,7 +1468,6 @@ 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);
aspy = 1.0f / clip->tracking.camera.pixel_aspect;
@@ -1410,28 +1496,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(GWN_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();
+
+ gpuPopMatrix();
if (sc->flag & SC_SHOW_NAMES) {
/* scaling should be cleared before drawing texts, otherwise font would also be scaled */
@@ -1457,7 +1549,7 @@ static void draw_tracking_tracks(SpaceClip *sc, Scene *scene, ARegion *ar, Movie
}
}
- glPopMatrix();
+ gpuPopMatrix();
if (marker_pos)
MEM_freeN(marker_pos);
@@ -1484,11 +1576,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);
+ gpuPushMatrix();
+ gpuTranslate2f(x, y);
+ gpuScale2f(zoomx, zoomy);
+ gpuMultMatrix(sc->stabmat);
+ gpuScale2f(width, height);
+
+ unsigned int position = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* grid */
if (sc->flag & SC_SHOW_GRID) {
@@ -1560,22 +1656,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(GWN_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(GWN_PRIM_LINE_STRIP, n + 1);
+
for (i = 0; i <= n; i++) {
- glVertex2fv(grid[i][j]);
+ immVertex2fv(position, grid[i][j]);
}
- glEnd();
+
+ immEnd();
}
}
@@ -1594,7 +1694,8 @@ static void draw_distortion(SpaceClip *sc, ARegion *ar, MovieClip *clip,
continue;
}
- glColor4fv(layer->color);
+ immUniformColor4fv(layer->color);
+
glLineWidth(layer->thickness);
glPointSize((float)(layer->thickness + 2));
@@ -1604,7 +1705,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;
@@ -1627,19 +1727,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(GWN_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(GWN_PRIM_POINTS, 1);
+ immVertex2f(position, stroke->points[0].x + offsx, stroke->points[0].y + offsy);
+ immEnd();
}
}
@@ -1653,7 +1756,9 @@ static void draw_distortion(SpaceClip *sc, ARegion *ar, MovieClip *clip,
}
}
- glPopMatrix();
+ immUnbindProgram();
+
+ gpuPopMatrix();
}
void clip_draw_main(const bContext *C, SpaceClip *sc, ARegion *ar)
@@ -1750,8 +1855,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);
+ gpuPushMatrix();
+ gpuMultMatrix(sc->unistabmat);
if (is_track_source) {
MovieTrackingTrack *track = BKE_tracking_track_get_active(&sc->clip->tracking);
@@ -1760,13 +1865,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);
+ gpuTranslate2fv(marker->pos);
}
}
ED_gpencil_draw_2dimage(C);
- glPopMatrix();
+ gpuPopMatrix();
}
}
else {
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index 14d0f909d23..942bc2661c3 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -259,11 +259,9 @@ ImBuf *ED_space_clip_get_stable_buffer(SpaceClip *sc, float loc[2], float *scale
return NULL;
}
-/* Returns color in the display space, matching ED_space_image_color_sample(). */
-bool ED_space_clip_color_sample(Scene *scene, SpaceClip *sc, ARegion *ar, int mval[2], float r_col[3])
+/* Returns color in linear space, matching ED_space_image_color_sample(). */
+bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *ar, int mval[2], float r_col[3])
{
- const char *display_device = scene->display_settings.display_device;
- struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
ImBuf *ibuf;
float fx, fy, co[2];
bool ret = false;
@@ -299,11 +297,7 @@ bool ED_space_clip_color_sample(Scene *scene, SpaceClip *sc, ARegion *ar, int mv
ret = true;
}
}
-
- if (ret) {
- IMB_colormanagement_scene_linear_to_display_v3(r_col, display);
- }
-
+
IMB_freeImBuf(ibuf);
return ret;
@@ -311,15 +305,12 @@ bool ED_space_clip_color_sample(Scene *scene, SpaceClip *sc, ARegion *ar, int mv
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..5c2782dc26d 100644
--- a/source/blender/editors/space_clip/clip_graph_draw.c
+++ b/source/blender/editors/space_clip/clip_graph_draw.c
@@ -42,7 +42,9 @@
#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 "WM_types.h"
@@ -53,52 +55,30 @@
#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);
}
@@ -107,22 +87,22 @@ static void tracking_segment_start_cb(void *userdata, MovieTrackingTrack *track,
glLineWidth(1.0f);
}
- glColor4fv(col);
+ immUniformColor4fv(col);
- glBegin(GL_LINE_STRIP);
+ if (is_point) {
+ immBeginAtMost(GWN_PRIM_POINTS, 1);
+ }
+ else {
+ /* Graph can be composed of smaller segments, if any marker is disabled */
+ immBeginAtMost(GWN_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 +116,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);
+
+ gpuPushMatrix();
+ gpuTranslate2f(scene_framenr, val);
+ gpuScale2f(1.0f / data->xscale * data->hsize, 1.0f / data->yscale * data->hsize);
- draw_curve_knot(scene_framenr, val, data->xscale, data->yscale, data->hsize);
+ imm_draw_circle_wire(data->pos, 0, 0, 0.7, 8);
+
+ gpuPopMatrix();
}
}
-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,18 +145,18 @@ 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);
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);
@@ -195,6 +178,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 +214,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;
@@ -249,20 +233,26 @@ static void tracking_error_segment_start_cb(void *userdata, MovieTrackingTrack *
glLineWidth(1.0f);
}
- glColor4fv(col);
+ immUniformColor4fv(col);
- glBegin(GL_LINE_STRIP);
+ if (is_point) { /* This probably never happens here, but just in case... */
+ immBeginAtMost(GWN_PRIM_POINTS, 1);
+ }
+ else {
+ /* Graph can be composed of smaller segments, if any marker is disabled */
+ immBeginAtMost(GWN_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 +263,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 +280,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(GWN_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,14 +327,24 @@ 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);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ glPointSize(3.0f);
- if (sc->flag & SC_SHOW_GRAPH_TRACKS_ERROR)
- draw_tracks_error_curves(sc);
+ 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, pos);
+ }
+
+ if (sc->flag & SC_SHOW_GRAPH_FRAMES) {
+ draw_frame_curves(sc, pos);
+ }
- if (sc->flag & SC_SHOW_GRAPH_FRAMES)
- draw_frame_curves(sc);
+ immUnbindProgram();
}
/* frame range */
diff --git a/source/blender/editors/space_clip/clip_graph_ops.c b/source/blender/editors/space_clip/clip_graph_ops.c
index e781d199d35..edac128d18b 100644
--- a/source/blender/editors/space_clip/clip_graph_ops.c
+++ b/source/blender/editors/space_clip/clip_graph_ops.c
@@ -37,7 +37,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"
@@ -691,7 +692,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 2a5d959bb84..ffc7a41f0aa 100644
--- a/source/blender/editors/space_clip/clip_intern.h
+++ b/source/blender/editors/space_clip/clip_intern.h
@@ -106,7 +106,9 @@ void CLIP_OT_change_frame(wmOperatorType *ot);
void CLIP_OT_rebuild_proxy(struct wmOperatorType *ot);
void CLIP_OT_mode_set(struct wmOperatorType *ot);
+#ifdef WITH_INPUT_NDOF
void CLIP_OT_view_ndof(struct wmOperatorType *ot);
+#endif
void CLIP_OT_prefetch(struct wmOperatorType *ot);
@@ -123,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,
@@ -185,7 +187,10 @@ void CLIP_OT_detect_features(struct wmOperatorType *ot);
void CLIP_OT_stabilize_2d_add(struct wmOperatorType *ot);
void CLIP_OT_stabilize_2d_remove(struct wmOperatorType *ot);
void CLIP_OT_stabilize_2d_select(struct wmOperatorType *ot);
-void CLIP_OT_stabilize_2d_set_rotation(struct wmOperatorType *ot);
+
+void CLIP_OT_stabilize_2d_rotation_add(struct wmOperatorType *ot);
+void CLIP_OT_stabilize_2d_rotation_remove(struct wmOperatorType *ot);
+void CLIP_OT_stabilize_2d_rotation_select(struct wmOperatorType *ot);
void CLIP_OT_clean_tracks(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index 83876ae2669..9430ee626ba 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -103,7 +103,7 @@ static void sclip_zoom_set(const bContext *C, float zoom, float location[2])
width *= sc->zoom;
height *= sc->zoom;
- if ((width < 4) && (height < 4))
+ if ((width < 4) && (height < 4) && sc->zoom < oldzoom)
sc->zoom = oldzoom;
else if (BLI_rcti_size_x(&ar->winrct) <= sc->zoom)
sc->zoom = oldzoom;
@@ -476,7 +476,7 @@ void CLIP_OT_view_pan(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
/* properties */
RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
@@ -1405,6 +1405,7 @@ void CLIP_OT_mode_set(wmOperatorType *ot)
RNA_def_enum(ot->srna, "mode", rna_enum_clip_editor_mode_items, SC_MODE_TRACKING, "Mode", "");
}
+#ifdef WITH_INPUT_NDOF
/********************** NDOF operator *********************/
/* Combined pan/zoom from a 3D mouse device.
@@ -1451,6 +1452,7 @@ void CLIP_OT_view_ndof(wmOperatorType *ot)
ot->invoke = clip_view_ndof_invoke;
ot->poll = ED_space_clip_view_clip_poll;
}
+#endif /* WITH_INPUT_NDOF */
/********************** Prefetch operator *********************/
diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c
index 5964e9a898b..40661937bae 100644
--- a/source/blender/editors/space_clip/clip_utils.c
+++ b/source/blender/editors/space_clip/clip_utils.c
@@ -41,10 +41,11 @@
#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 "GPU_immediate.h"
+#include "GPU_matrix.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -52,7 +53,6 @@
#include "ED_screen.h"
#include "ED_clip.h"
-
#include "UI_interface.h"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -63,7 +63,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);
@@ -72,7 +72,7 @@ void clip_graph_tracking_values_iterate_track(
BKE_movieclip_get_size(clip, &sc->user, &width, &height);
for (coord = 0; coord < 2; coord++) {
- int i, prevfra = 0;
+ int i, prevfra = track->markers[0].framenr;
bool open = false;
float prevval = 0.0f;
@@ -92,8 +92,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 +130,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);
@@ -175,21 +181,15 @@ void clip_graph_tracking_iterate(SpaceClip *sc, bool selected_only, bool include
void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track)
{
MovieTracking *tracking = &clip->tracking;
- MovieTrackingStabilization *stab = &tracking->stabilization;
MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- bool has_bundle = false, update_stab = false;
+ bool has_bundle = false;
char track_name_escaped[MAX_NAME], prefix[MAX_NAME * 2];
+ const bool used_for_stabilization = (track->flag & (TRACK_USE_2D_STAB | TRACK_USE_2D_STAB_ROT));
if (track == act_track)
tracking->act_track = NULL;
- if (track == stab->rot_track) {
- stab->rot_track = NULL;
-
- update_stab = true;
- }
-
/* handle reconstruction display in 3d viewport */
if (track->flag & TRACK_HAS_BUNDLE)
has_bundle = true;
@@ -207,12 +207,11 @@ void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track)
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
- if (update_stab) {
- tracking->stabilization.ok = false;
+ if (used_for_stabilization) {
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
}
- DAG_id_tag_update(&clip->id, 0);
+ DEG_id_tag_update(&clip->id, 0);
if (has_bundle)
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
@@ -245,31 +244,35 @@ void clip_view_center_to_point(SpaceClip *sc, float x, float y)
void clip_draw_cfra(SpaceClip *sc, ARegion *ar, Scene *scene)
{
+ /* Draw a light green line to indicate current frame */
View2D *v2d = &ar->v2d;
- float xscale, yscale;
+ float x = (float)(sc->user.framenr * scene->r.framelen);
- /* Draw a light green line to indicate current frame */
- UI_ThemeColor(TH_CFRAME);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
- float x = (float)(sc->user.framenr * scene->r.framelen);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColor(TH_CFRAME);
+ glLineWidth(2.0f);
- glLineWidth(2.0);
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2f(pos, x, v2d->cur.ymin);
+ immVertex2f(pos, x, v2d->cur.ymax);
+ immEnd();
- glBegin(GL_LINES);
- glVertex2f(x, v2d->cur.ymin);
- glVertex2f(x, v2d->cur.ymax);
- glEnd();
+ immUnbindProgram();
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);
+ float xscale;
+ UI_view2d_scale_get(v2d, &xscale, NULL);
+ gpuPushMatrix();
+ gpuScale2f(1.0f / xscale, 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);
+ gpuPopMatrix();
}
void clip_draw_sfra_efra(View2D *v2d, Scene *scene)
@@ -279,15 +282,27 @@ void clip_draw_sfra_efra(View2D *v2d, Scene *scene)
/* 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);
- glRectf(v2d->cur.xmin, v2d->cur.ymin, (float)SFRA, v2d->cur.ymax);
- glRectf((float)EFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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);
+
glDisable(GL_BLEND);
- 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);
+ glLineWidth(1.0f);
+
+ immBegin(GWN_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 396d71f0a20..eed2acbfc68 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -60,7 +60,7 @@
#include "IMB_imbuf.h"
-#include "BIF_gl.h"
+#include "GPU_matrix.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -225,18 +225,6 @@ static void clip_scopes_check_gpencil_change(ScrArea *sa)
}
}
-static void clip_stabilization_tag_refresh(ScrArea *sa)
-{
- SpaceClip *sc = (SpaceClip *) sa->spacedata.first;
- MovieClip *clip = ED_space_clip_get_clip(sc);
-
- if (clip) {
- MovieTrackingStabilization *stab = &clip->tracking.stabilization;
-
- stab->ok = false;
- }
-}
-
/* ******************** default callbacks for clip space ***************** */
static SpaceLink *clip_new(const bContext *C)
@@ -341,7 +329,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(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -349,7 +337,7 @@ static void clip_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
switch (wmn->data) {
case ND_FRAME:
clip_scopes_tag_refresh(sa);
- /* fall-through */
+ ATTR_FALLTHROUGH;
case ND_FRAME_RANGE:
ED_area_tag_redraw(sa);
@@ -368,7 +356,6 @@ static void clip_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
case NA_REMOVED:
case NA_EDITED:
case NA_EVALUATED:
- clip_stabilization_tag_refresh(sa);
/* fall-through */
case NA_SELECTED:
@@ -412,7 +399,6 @@ static void clip_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
case NC_SPACE:
if (wmn->data == ND_SPACE_CLIP) {
clip_scopes_tag_refresh(sa);
- clip_stabilization_tag_refresh(sa);
ED_area_tag_redraw(sa);
}
break;
@@ -443,7 +429,9 @@ static void clip_operatortypes(void)
WM_operatortype_append(CLIP_OT_change_frame);
WM_operatortype_append(CLIP_OT_rebuild_proxy);
WM_operatortype_append(CLIP_OT_mode_set);
+#ifdef WITH_INPUT_NDOF
WM_operatortype_append(CLIP_OT_view_ndof);
+#endif
WM_operatortype_append(CLIP_OT_prefetch);
WM_operatortype_append(CLIP_OT_set_scene_frames);
WM_operatortype_append(CLIP_OT_cursor_set);
@@ -457,7 +445,7 @@ static void clip_operatortypes(void)
/* navigation */
WM_operatortype_append(CLIP_OT_frame_jump);
- /* foorage */
+ /* set optical center to frame center */
WM_operatortype_append(CLIP_OT_set_center_principal);
/* selection */
@@ -505,7 +493,9 @@ static void clip_operatortypes(void)
WM_operatortype_append(CLIP_OT_stabilize_2d_add);
WM_operatortype_append(CLIP_OT_stabilize_2d_remove);
WM_operatortype_append(CLIP_OT_stabilize_2d_select);
- WM_operatortype_append(CLIP_OT_stabilize_2d_set_rotation);
+ WM_operatortype_append(CLIP_OT_stabilize_2d_rotation_add);
+ WM_operatortype_append(CLIP_OT_stabilize_2d_rotation_remove);
+ WM_operatortype_append(CLIP_OT_stabilize_2d_rotation_select);
/* clean-up */
WM_operatortype_append(CLIP_OT_clear_track_path);
@@ -634,8 +624,10 @@ static void clip_keymap(struct wmKeyConfig *keyconf)
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);
@@ -791,7 +783,9 @@ static void clip_keymap(struct wmKeyConfig *keyconf)
/* 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);
@@ -822,7 +816,9 @@ static void clip_keymap(struct wmKeyConfig *keyconf)
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
}
const char *clip_context_dir[] = {"edit_movieclip", "edit_mask", NULL};
@@ -1217,13 +1213,13 @@ 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);
+ gpuPushMatrix();
+ gpuTranslate2f(x, y);
+ gpuScale2f(zoomx, zoomy);
+ gpuMultMatrix(sc->stabmat);
+ gpuScale2f(width, height);
ED_image_draw_cursor(ar, sc->cursor);
- glPopMatrix();
+ gpuPopMatrix();
}
clip_draw_cache_and_notes(C, sc, ar);
@@ -1242,7 +1238,9 @@ static void clip_main_region_draw(const bContext *C, ARegion *ar)
}
}
-static void clip_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void clip_main_region_listener(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -1353,7 +1351,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(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar),
+ wmNotifier *UNUSED(wmn), const Scene *UNUSED(scene))
{
}
@@ -1394,7 +1394,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(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar),
+ wmNotifier *UNUSED(wmn), const Scene *UNUSED(scene))
{
}
@@ -1411,7 +1413,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(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -1451,7 +1455,9 @@ static void clip_tools_region_draw(const bContext *C, ARegion *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(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -1496,7 +1502,9 @@ static void clip_properties_region_draw(const bContext *C, ARegion *ar)
ED_region_panels(C, ar, NULL, -1, true);
}
-static void clip_properties_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void clip_properties_region_listener(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index 61bfa5b315b..ea7ede46887 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"
@@ -875,8 +876,7 @@ static int slide_marker_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY)) {
data->accurate = event->val == KM_PRESS;
}
-
- /* fall-through */
+ ATTR_FALLTHROUGH;
case MOUSEMOVE:
mdelta[0] = event->mval[0] - data->mval[0];
mdelta[1] = event->mval[1] - data->mval[1];
@@ -906,7 +906,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) {
@@ -1201,7 +1201,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);
@@ -1509,8 +1509,10 @@ static int join_tracks_exec(bContext *C, wmOperator *op)
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
+ MovieTrackingStabilization *stab = &tracking->stabilization;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
+ bool update_stabilization = false;
MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
if (act_track == NULL) {
@@ -1528,8 +1530,25 @@ static int join_tracks_exec(bContext *C, wmOperator *op)
if (TRACK_VIEW_SELECTED(sc, track) && track != act_track) {
BKE_tracking_tracks_join(tracking, act_track, track);
- if (tracking->stabilization.rot_track == track) {
- tracking->stabilization.rot_track = act_track;
+ if (track->flag & TRACK_USE_2D_STAB) {
+ update_stabilization = true;
+ if ((act_track->flag & TRACK_USE_2D_STAB) == 0) {
+ act_track->flag |= TRACK_USE_2D_STAB;
+ }
+ else {
+ stab->tot_track--;
+ }
+ BLI_assert(0 <= stab->tot_track);
+ }
+ if (track->flag & TRACK_USE_2D_STAB_ROT) {
+ update_stabilization = true;
+ if ((act_track->flag & TRACK_USE_2D_STAB_ROT) == 0) {
+ act_track->flag |= TRACK_USE_2D_STAB_ROT;
+ }
+ else {
+ stab->tot_rot_track--;
+ }
+ BLI_assert(0 <= stab->tot_rot_track);
}
for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first;
@@ -1551,6 +1570,10 @@ static int join_tracks_exec(bContext *C, wmOperator *op)
}
}
+ if (update_stabilization) {
+ WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
+ }
+
GSetIterator gs_iter;
int framenr = ED_space_clip_get_clip_frame_number(sc);
GSET_ITER (gs_iter, point_tracks) {
diff --git a/source/blender/editors/space_clip/tracking_ops_orient.c b/source/blender/editors/space_clip/tracking_ops_orient.c
index f81180d65a9..671825ef7c3 100644
--- a/source/blender/editors/space_clip/tracking_ops_orient.c
+++ b/source/blender/editors/space_clip/tracking_ops_orient.c
@@ -43,10 +43,12 @@
#include "BKE_constraint.h"
#include "BKE_tracking.h"
#include "BKE_global.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"
@@ -69,17 +71,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(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;
}
@@ -87,6 +88,7 @@ static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip)
static Object *get_orientation_object(bContext *C)
{
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
@@ -97,7 +99,7 @@ static Object *get_orientation_object(bContext *C)
object = get_camera_with_movieclip(scene, clip);
}
else {
- object = OBACT;
+ object = OBACT_NEW;
}
if (object != NULL && object->parent != NULL) {
@@ -111,7 +113,7 @@ static int set_orientation_poll(bContext *C)
{
SpaceClip *sc = CTX_wm_space_clip(C);
if (sc != NULL) {
- Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
if (clip != NULL) {
MovieTracking *tracking = &clip->tracking;
@@ -120,7 +122,7 @@ static int set_orientation_poll(bContext *C)
return true;
}
else {
- return OBACT != NULL;
+ return OBACT_NEW != NULL;
}
}
}
@@ -247,8 +249,8 @@ static int set_origin_exec(bContext *C, wmOperator *op)
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);
@@ -493,8 +495,8 @@ static int set_plane_exec(bContext *C, wmOperator *op)
BKE_object_where_is_calc(scene, object);
set_axis(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);
@@ -567,8 +569,8 @@ static int set_axis_exec(bContext *C, wmOperator *op)
set_axis(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);
@@ -694,10 +696,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 4332f3ea765..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"
@@ -301,8 +302,7 @@ static int slide_plane_marker_modal(bContext *C,
if (ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY)) {
data->accurate = event->val == KM_PRESS;
}
-
- /* fall-through */
+ ATTR_FALLTHROUGH;
case MOUSEMOVE:
mdelta[0] = event->mval[0] - data->previous_mval[0];
mdelta[1] = event->mval[1] - data->previous_mval[1];
@@ -373,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);
@@ -391,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..89dfadc8974 100644
--- a/source/blender/editors/space_clip/tracking_ops_solve.c
+++ b/source/blender/editors/space_clip/tracking_ops_solve.c
@@ -43,10 +43,11 @@
#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 "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 8d6173e1cea..4eb6a4fbb24 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,8 +85,7 @@ static int stabilize_2d_add_exec(bContext *C, wmOperator *UNUSED(op))
}
if (update) {
- stab->ok = 0;
- DAG_id_tag_update(&clip->id, 0);
+ DEG_id_tag_update(&clip->id, 0);
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
}
@@ -96,7 +96,7 @@ void CLIP_OT_stabilize_2d_add(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Add Stabilization Tracks";
- ot->description = "Add selected tracks to 2D stabilization tool";
+ ot->description = "Add selected tracks to 2D translation stabilization";
ot->idname = "CLIP_OT_stabilize_2d_add";
/* api callbacks */
@@ -139,8 +139,7 @@ static int stabilize_2d_remove_exec(bContext *C, wmOperator *UNUSED(op))
}
if (update) {
- stab->ok = 0;
- DAG_id_tag_update(&clip->id, 0);
+ DEG_id_tag_update(&clip->id, 0);
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
}
@@ -151,7 +150,7 @@ void CLIP_OT_stabilize_2d_remove(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Remove Stabilization Track";
- ot->description = "Remove selected track from stabilization";
+ ot->description = "Remove selected track from translation stabilization";
ot->idname = "CLIP_OT_stabilize_2d_remove";
/* api callbacks */
@@ -193,7 +192,7 @@ void CLIP_OT_stabilize_2d_select(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Select Stabilization Tracks";
- ot->description = "Select tracks which are used for stabilization";
+ ot->description = "Select tracks which are used for translation stabilization";
ot->idname = "CLIP_OT_stabilize_2d_select";
/* api callbacks */
@@ -204,39 +203,146 @@ void CLIP_OT_stabilize_2d_select(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/***************** set 2d stabilization rotation track operator ****************/
+/********************** add 2d stabilization tracks for rotation operator ****************/
+
+static int stabilize_2d_rotation_add_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ MovieTrackingStabilization *stab = &tracking->stabilization;
+
+ bool update = false;
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ if (TRACK_VIEW_SELECTED(sc, track) &&
+ (track->flag & TRACK_USE_2D_STAB_ROT) == 0)
+ {
+ track->flag |= TRACK_USE_2D_STAB_ROT;
+ stab->tot_rot_track++;
+ update = true;
+ }
+ }
+
+ if (update) {
+ DEG_id_tag_update(&clip->id, 0);
+ WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_stabilize_2d_rotation_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Stabilization Rotation Tracks";
+ ot->description = "Add selected tracks to 2D rotation stabilization";
+ ot->idname = "CLIP_OT_stabilize_2d_rotation_add";
+
+ /* api callbacks */
+ ot->exec = stabilize_2d_rotation_add_exec;
+ ot->poll = stabilize_2d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/********************** remove 2d stabilization tracks for rotation operator *************/
-static int stabilize_2d_set_rotation_exec(bContext *C, wmOperator *UNUSED(op))
+static int stabilize_2d_rotation_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
- MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
+ MovieTrackingStabilization *stab = &tracking->stabilization;
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ int a = 0;
+ bool update = false;
- if (act_track != NULL) {
- MovieTrackingStabilization *stab = &tracking->stabilization;
- stab->rot_track = act_track;
- stab->ok = 0;
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ if (track->flag & TRACK_USE_2D_STAB_ROT) {
+ if (a == stab->act_rot_track) {
+ track->flag &= ~TRACK_USE_2D_STAB_ROT;
+ stab->act_rot_track--;
+ stab->tot_rot_track--;
+ if (stab->act_rot_track < 0) {
+ stab->act_rot_track = 0;
+ }
+ update = true;
+ break;
+ }
+ a++;
+ }
+ }
- DAG_id_tag_update(&clip->id, 0);
+ if (update) {
+ DEG_id_tag_update(&clip->id, 0);
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
}
return OPERATOR_FINISHED;
}
-void CLIP_OT_stabilize_2d_set_rotation(wmOperatorType *ot)
+void CLIP_OT_stabilize_2d_rotation_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Stabilization Rotation Track";
+ ot->description = "Remove selected track from rotation stabilization";
+ ot->idname = "CLIP_OT_stabilize_2d_rotation_remove";
+
+ /* api callbacks */
+ ot->exec = stabilize_2d_rotation_remove_exec;
+ ot->poll = stabilize_2d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/********************** select 2d stabilization rotation tracks operator *****************/
+
+static int stabilize_2d_rotation_select_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ bool update = false;
+
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ if (track->flag & TRACK_USE_2D_STAB_ROT) {
+ BKE_tracking_track_flag_set(track, TRACK_AREA_ALL, SELECT);
+ update = true;
+ }
+ }
+
+ if (update) {
+ WM_event_add_notifier(C, NC_MOVIECLIP | ND_SELECT, clip);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_stabilize_2d_rotation_select(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Set Rotation Track";
- ot->description = "Use active track to compensate rotation when "
- "doing 2D stabilization";
- ot->idname = "CLIP_OT_stabilize_2d_set_rotation";
+ ot->name = "Select Stabilization Rotation Tracks";
+ ot->description = "Select tracks which are used for rotation stabilization";
+ ot->idname = "CLIP_OT_stabilize_2d_rotation_select";
/* api callbacks */
- ot->exec = stabilize_2d_set_rotation_exec;
+ ot->exec = stabilize_2d_rotation_select_exec;
ot->poll = stabilize_2d_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c
index 6396b390ca0..c8a06545e0f 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];
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_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 97a85bce006..9a2f4b5d431 100644
--- a/source/blender/editors/space_console/space_console.c
+++ b/source/blender/editors/space_console/space_console.c
@@ -368,7 +368,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(
+ bScreen *UNUSED(sc), 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 52d01063175..be873358931 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"
@@ -71,6 +70,9 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+
#include "filelist.h"
#include "file_intern.h" // own include
@@ -258,9 +260,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 +288,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 +314,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 +339,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);
@@ -381,12 +386,12 @@ static void file_draw_preview(
/* 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);
@@ -394,8 +399,13 @@ static void file_draw_preview(
/* border */
if (use_dropshadow) {
- glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
- fdrawbox((float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey));
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2,GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f);
+ imm_draw_line_box(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);
@@ -451,49 +461,70 @@ static void draw_background(FileLayout *layout, View2D *v2d)
int i;
int sy;
- UI_ThemeColorShade(TH_BACK, -7);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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_ct = 0;
+ int sx = (int)v2d->tot.xmin;
+ while (sx < v2d->cur.xmax) {
+ sx += step;
+ vertex_ct += 4; /* vertex_count = 2 points per line * 2 lines per divider */
+ }
- v1[1] = v2d->cur.ymax - layout->tile_border_y;
- v2[1] = v2d->cur.ymin;
+ if (vertex_ct > 0) {
+ int v1[2], v2[2];
+ unsigned char col_hi[3], col_lo[3];
- glBegin(GL_LINES);
+ UI_GetThemeColorShade3ubv(TH_BACK, 30, col_hi);
+ UI_GetThemeColorShade3ubv(TH_BACK, -30, col_lo);
- /* vertical column dividers */
- sx = (int)v2d->tot.xmin;
- while (sx < v2d->cur.xmax) {
- sx += step;
+ v1[1] = v2d->cur.ymax - layout->tile_border_y;
+ v2[1] = v2d->cur.ymin;
- glColor3ubv(col_lo);
- v1[0] = v2[0] = sx;
- glVertex2iv(v1);
- glVertex2iv(v2);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
- glColor3ubv(col_hi);
- v1[0] = v2[0] = sx + 1;
- glVertex2iv(v1);
- glVertex2iv(v2);
- }
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBegin(GWN_PRIM_LINES, vertex_ct);
+
+ sx = (int)v2d->tot.xmin;
+ while (sx < v2d->cur.xmax) {
+ sx += step;
+
+ v1[0] = v2[0] = sx;
+ immSkipAttrib(color);
+ immVertex2iv(pos, v1);
+ immAttrib3ubv(color, col_lo);
+ immVertex2iv(pos, v2);
- glEnd();
+ v1[0] = v2[0] = sx + 1;
+ immSkipAttrib(color);
+ immVertex2iv(pos, v1);
+ immAttrib3ubv(color, col_hi);
+ immVertex2iv(pos, v2);
+ }
+
+ immEnd();
+ immUnbindProgram();
+ }
}
void file_draw_list(const bContext *C, ARegion *ar)
@@ -517,6 +548,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));
@@ -587,9 +619,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))
@@ -625,7 +654,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;
@@ -656,7 +685,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;
@@ -668,7 +697,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;
}
@@ -679,10 +709,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 {
@@ -697,7 +729,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;
}
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index a55b18a2212..71e38f72a7a 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -128,7 +128,6 @@ void file_panels_register(struct ARegionType *art);
/* file_utils.c */
void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, rcti *r_bounds);
-bool file_is_dir(struct SpaceFile *sfile, const char *path);
#endif /* __FILE_INTERN_H__ */
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index c42ff120102..b7228f634bf 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -1061,7 +1061,8 @@ void FILE_OT_bookmark_move(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER; /* No undo! */
- RNA_def_enum(ot->srna, "direction", slot_move, 0, "Direction", "Direction to move, UP or DOWN");
+ RNA_def_enum(ot->srna, "direction", slot_move, 0, "Direction",
+ "Direction to move the active bookmark towards");
}
static int reset_recent_exec(bContext *C, wmOperator *UNUSED(op))
@@ -1894,7 +1895,7 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
file_expand_directory(C);
/* special case, user may have pasted a filepath into the directory */
- if (!file_is_dir(sfile, sfile->params->dir)) {
+ if (!filelist_is_dir(sfile->files, sfile->params->dir)) {
char tdir[FILE_MAX_LIBEXTRA];
char *group, *name;
@@ -1920,7 +1921,7 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
BLI_cleanup_dir(G.main->name, sfile->params->dir);
- if (file_is_dir(sfile, sfile->params->dir)) {
+ if (filelist_is_dir(sfile->files, sfile->params->dir)) {
/* if directory exists, enter it immediately */
ED_file_change_dir(C);
@@ -1993,7 +1994,7 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
BLI_join_dirfile(filepath, sizeof(sfile->params->dir), sfile->params->dir, sfile->params->file);
/* if directory, open it and empty filename field */
- if (file_is_dir(sfile, filepath)) {
+ if (filelist_is_dir(sfile->files, filepath)) {
BLI_cleanup_dir(G.main->name, filepath);
BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
sfile->params->file[0] = '\0';
diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c
index f19e301064d..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"
@@ -48,17 +49,3 @@ void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, r
BLI_rcti_init(r_bounds, xmin, xmin + layout->tile_w + layout->tile_border_x,
ymax - layout->tile_h - layout->tile_border_y, ymax);
}
-
-/* Cannot directly use BLI_is_dir in libloading context... */
-bool file_is_dir(struct SpaceFile *sfile, const char *path)
-{
- if (sfile->params->type == FILE_LOADLIB) {
- char tdir[FILE_MAX_LIBEXTRA];
- char *name;
- if (BLO_library_path_explode(sfile->params->dir, tdir, NULL, &name) && BLI_is_file(tdir)) {
- /* .blend file itself and group are considered as directories, not final datablock names. */
- return name ? false : true;
- }
- }
- return BLI_is_dir(path);
-}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index b6e4991bf52..6c33091ff01 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -309,8 +309,9 @@ typedef struct FileList {
struct BlendHandle *libfiledata;
- /* Set given path as root directory, may change given string in place to a valid value. */
- void (*checkdirf)(struct FileList *, char *);
+ /* Set given path as root directory, if last bool is true may change given string in place to a valid value.
+ * Returns True if valid dir. */
+ bool (*checkdirf)(struct FileList *, char *, const bool);
/* Fill filelist (to be called by read job). */
void (*read_jobf)(struct FileList *, const char *, short *, short *, float *, ThreadMutex *);
@@ -942,24 +943,37 @@ int filelist_geticon(struct FileList *filelist, const int index, const bool is_m
/* ********** Main ********** */
-static void filelist_checkdir_dir(struct FileList *UNUSED(filelist), char *r_dir)
+static bool filelist_checkdir_dir(struct FileList *UNUSED(filelist), char *r_dir, const bool do_change)
{
- BLI_make_exist(r_dir);
+ if (do_change) {
+ BLI_make_exist(r_dir);
+ return true;
+ }
+ else {
+ return BLI_is_dir(r_dir);
+ }
}
-static void filelist_checkdir_lib(struct FileList *UNUSED(filelist), char *r_dir)
+static bool filelist_checkdir_lib(struct FileList *UNUSED(filelist), char *r_dir, const bool do_change)
{
- char dir[FILE_MAX_LIBEXTRA];
- if (!BLO_library_path_explode(r_dir, dir, NULL, NULL)) {
+ char tdir[FILE_MAX_LIBEXTRA];
+ char *name;
+
+ const bool is_valid = (BLI_is_dir(r_dir) ||
+ (BLO_library_path_explode(r_dir, tdir, NULL, &name) && BLI_is_file(tdir) && !name));
+
+ if (do_change && !is_valid) {
/* if not a valid library, we need it to be a valid directory! */
BLI_make_exist(r_dir);
+ return true;
}
+ return is_valid;
}
-static void filelist_checkdir_main(struct FileList *filelist, char *r_dir)
+static bool filelist_checkdir_main(struct FileList *filelist, char *r_dir, const bool do_change)
{
/* TODO */
- filelist_checkdir_lib(filelist, r_dir);
+ return filelist_checkdir_lib(filelist, r_dir, do_change);
}
static void filelist_entry_clear(FileDirEntry *entry)
@@ -1378,6 +1392,11 @@ const char *filelist_dir(struct FileList *filelist)
return filelist->filelist.root;
}
+bool filelist_is_dir(struct FileList *filelist, const char *path)
+{
+ return filelist->checkdirf(filelist, (char *)path, false);
+}
+
/**
* May modify in place given r_dir, which is expected to be FILE_MAX_LIBEXTRA length.
*/
@@ -1386,7 +1405,9 @@ void filelist_setdir(struct FileList *filelist, char *r_dir)
BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA);
BLI_cleanup_dir(G.main->name, r_dir);
- filelist->checkdirf(filelist, r_dir);
+ const bool is_valid_path = filelist->checkdirf(filelist, r_dir, true);
+ BLI_assert(is_valid_path);
+ UNUSED_VARS_NDEBUG(is_valid_path);
if (!STREQ(filelist->filelist.root, r_dir)) {
BLI_strncpy(filelist->filelist.root, r_dir, sizeof(filelist->filelist.root));
@@ -1632,6 +1653,7 @@ bool filelist_file_cache_block(struct FileList *filelist, const int index)
int start_index = max_ii(0, index - (cache_size / 2));
int end_index = min_ii(nbr_entries, index + (cache_size / 2));
int i;
+ const bool full_refresh = (filelist->flags & FL_IS_READY) == 0;
if ((index < 0) || (index >= nbr_entries)) {
// printf("Wrong index %d ([%d:%d])", index, 0, nbr_entries);
@@ -1654,8 +1676,8 @@ bool filelist_file_cache_block(struct FileList *filelist, const int index)
// start_index, end_index, index, cache->block_start_index, cache->block_end_index);
/* If we have something to (re)cache... */
- if ((start_index != cache->block_start_index) || (end_index != cache->block_end_index)) {
- if ((start_index >= cache->block_end_index) || (end_index <= cache->block_start_index)) {
+ if (full_refresh || (start_index != cache->block_start_index) || (end_index != cache->block_end_index)) {
+ if (full_refresh || (start_index >= cache->block_end_index) || (end_index <= cache->block_start_index)) {
int size1 = cache->block_end_index - cache->block_start_index;
int size2 = 0;
int idx1 = cache->block_cursor, idx2 = 0;
@@ -1942,7 +1964,7 @@ int ED_path_extension_type(const char *path)
else if (BLI_testextensie(path, ".py")) {
return FILE_TYPE_PYSCRIPT;
}
- else if (BLI_testextensie_n(path, ".txt", ".glsl", ".osl", ".data", NULL)) {
+ else if (BLI_testextensie_n(path, ".txt", ".glsl", ".osl", ".data", ".pov", ".ini", ".mcr", ".inc", NULL)) {
return FILE_TYPE_TEXT;
}
else if (BLI_testextensie_n(path, ".ttf", ".ttc", ".pfb", ".otf", ".otc", NULL)) {
@@ -2488,7 +2510,7 @@ static void filelist_readjob_do(
* Using an atomic operation to avoid having to lock thread...
* Note that we do not really need this here currently, since there is a single listing thread, but better
* remain consistent about threading! */
- *((uint32_t *)entry->uuid) = atomic_add_uint32((uint32_t *)filelist->filelist_intern.curr_uuid, 1);
+ *((uint32_t *)entry->uuid) = atomic_add_and_fetch_uint32((uint32_t *)filelist->filelist_intern.curr_uuid, 1);
/* Only thing we change in direntry here, so we need to free it first. */
MEM_freeN(entry->relpath);
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index d70faab1d6a..f4304681780 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -86,6 +86,7 @@ void filelist_clear_ex(struct FileList *filelist, const bool do_c
void filelist_free(struct FileList *filelist);
const char * filelist_dir(struct FileList *filelist);
+bool filelist_is_dir(struct FileList *filelist, const char *path);
void filelist_setdir(struct FileList *filelist, char *r_dir);
int filelist_files_ensure(struct FileList *filelist);
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 1a558d40560..3dfeb5eb5b3 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -215,7 +215,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;
@@ -228,7 +229,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"))) {
@@ -592,7 +593,7 @@ void ED_file_change_dir(bContext *C)
sfile->params->filter_search[0] = '\0';
sfile->params->active_file = -1;
- if (!file_is_dir(sfile, sfile->params->dir)) {
+ if (!filelist_is_dir(sfile->files, sfile->params->dir)) {
BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), sizeof(sfile->params->dir));
/* could return but just refresh the current dir */
}
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index e71c05d19c5..ee0ec3fda39 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -48,9 +48,6 @@
#ifdef WIN32
# include <windows.h> /* need to include windows.h so _WIN32_IE is defined */
-# ifndef _WIN32_IE
-# define _WIN32_IE 0x0400 /* minimal requirements for SHGetSpecialFolderPath on MINGW MSVC has this defined already */
-# endif
# include <shlobj.h> /* for SHGetSpecialFolderPath, has to be done before BLI_winstuff
* because 'near' is disabled through BLI_windstuff */
# include "BLI_winstuff.h"
@@ -169,12 +166,15 @@ void ED_fsmenu_entry_set_path(struct FSMenuEntry *fsentry, const char *path)
static void fsmenu_entry_generate_name(struct FSMenuEntry *fsentry, char *name, size_t name_size)
{
- char temp[FILE_MAX];
+ int offset = 0;
+ int len = name_size;
- BLI_strncpy(temp, fsentry->path, FILE_MAX);
- BLI_add_slash(temp);
- BLI_getlastdir(temp, name, name_size);
- BLI_del_slash(name);
+ if (BLI_path_name_at_index(fsentry->path, -1, &offset, &len)) {
+ /* use as size */
+ len += 1;
+ }
+
+ BLI_strncpy(name, &fsentry->path[offset], MIN2(len, name_size));
if (!name[0]) {
name[0] = '/';
name[1] = '\0';
@@ -518,14 +518,18 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
CFURLEnumeratorRef volEnum = CFURLEnumeratorCreateForMountedVolumes(NULL, kCFURLEnumeratorSkipInvisibles, NULL);
while (result != kCFURLEnumeratorEnd) {
- unsigned char defPath[FILE_MAX];
+ char defPath[FILE_MAX];
result = CFURLEnumeratorGetNextURL(volEnum, &cfURL, NULL);
if (result != kCFURLEnumeratorSuccess)
continue;
CFURLGetFileSystemRepresentation(cfURL, false, (UInt8 *)defPath, FILE_MAX);
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, (char *)defPath, NULL, FS_INSERT_SORTED);
+
+ /* Add end slash for consistency with other platforms */
+ BLI_add_slash(defPath);
+
+ fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, defPath, NULL, FS_INSERT_SORTED);
}
CFRelease(volEnum);
@@ -533,32 +537,29 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
/* Finally get user favorite places */
if (read_bookmarks) {
UInt32 seed;
- OSErr err = noErr;
- CFArrayRef pathesArray;
- LSSharedFileListRef list;
- LSSharedFileListItemRef itemRef;
- CFIndex i, pathesCount;
- CFURLRef cfURL = NULL;
- CFStringRef pathString = NULL;
- list = LSSharedFileListCreate(NULL, kLSSharedFileListFavoriteItems, NULL);
- pathesArray = LSSharedFileListCopySnapshot(list, &seed);
- pathesCount = CFArrayGetCount(pathesArray);
+ LSSharedFileListRef list = LSSharedFileListCreate(NULL, kLSSharedFileListFavoriteItems, NULL);
+ CFArrayRef pathesArray = LSSharedFileListCopySnapshot(list, &seed);
+ CFIndex pathesCount = CFArrayGetCount(pathesArray);
- for (i = 0; i < pathesCount; i++) {
- itemRef = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(pathesArray, i);
+ for (CFIndex i = 0; i < pathesCount; i++) {
+ LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(pathesArray, i);
- err = LSSharedFileListItemResolve(itemRef,
- kLSSharedFileListNoUserInteraction |
- kLSSharedFileListDoNotMountVolumes,
- &cfURL, NULL);
- if (err != noErr)
+ CFURLRef cfURL = NULL;
+ OSErr err = LSSharedFileListItemResolve(itemRef,
+ kLSSharedFileListNoUserInteraction |
+ kLSSharedFileListDoNotMountVolumes,
+ &cfURL, NULL);
+ if (err != noErr || !cfURL)
continue;
- pathString = CFURLCopyFileSystemPath(cfURL, kCFURLPOSIXPathStyle);
+ CFStringRef pathString = CFURLCopyFileSystemPath(cfURL, kCFURLPOSIXPathStyle);
if (pathString == NULL || !CFStringGetCString(pathString, line, sizeof(line), kCFStringEncodingUTF8))
continue;
+ /* Add end slash for consistency with other platforms */
+ BLI_add_slash(line);
+
/* Exclude "all my files" as it makes no sense in blender fileselector */
/* Exclude "airdrop" if wlan not active as it would show "" ) */
if (!strstr(line, "myDocuments.cannedSearch") && (*line != '\0')) {
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 7fb294529c9..269b1146ba0 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -291,7 +291,7 @@ static void file_refresh(const bContext *C, ScrArea *sa)
}
}
-static void file_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
+static void file_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, const Scene *UNUSED(scene))
{
SpaceFile *sfile = (SpaceFile *)sa->spacedata.first;
@@ -333,7 +333,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(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -435,6 +437,7 @@ static void file_operatortypes(void)
WM_operatortype_append(FILE_OT_bookmark_cleanup);
WM_operatortype_append(FILE_OT_bookmark_move);
WM_operatortype_append(FILE_OT_reset_recent);
+ WM_operatortype_append(FILE_OT_hidedot);
WM_operatortype_append(FILE_OT_filenum);
WM_operatortype_append(FILE_OT_directory_new);
WM_operatortype_append(FILE_OT_delete);
@@ -596,7 +599,9 @@ static void file_tools_region_draw(const bContext *C, ARegion *ar)
ED_region_panels(C, ar, NULL, -1, true);
}
-static void file_tools_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn))
+static void file_tools_region_listener(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar),
+ wmNotifier *UNUSED(wmn), const Scene *UNUSED(scene))
{
#if 0
/* context changes */
@@ -658,7 +663,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(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
diff --git a/source/blender/editors/space_graph/CMakeLists.txt b/source/blender/editors/space_graph/CMakeLists.txt
index 40a196fa95b..64ce1704b07 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
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index 516814b63b4..d6843cc959d 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -48,13 +48,13 @@
#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_build.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -475,7 +475,7 @@ static void do_graph_region_driver_buttons(bContext *C, void *UNUSED(arg), int e
case B_IPO_DEPCHANGE:
{
/* rebuild depsgraph for the new deps */
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
break;
}
}
@@ -616,30 +616,31 @@ static void graph_panel_driverVar__rotDiff(uiLayout *layout, ID *id, DriverVar *
Object *ob2 = (Object *)dtar2->id;
PointerRNA dtar_ptr, dtar2_ptr;
uiLayout *col;
-
+
/* initialize RNA pointer to the target */
- RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr);
- RNA_pointer_create(id, &RNA_DriverTarget, dtar2, &dtar2_ptr);
-
- /* Bone 1 */
+ RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr);
+ RNA_pointer_create(id, &RNA_DriverTarget, dtar2, &dtar2_ptr);
+
+ /* Object 1 */
col = uiLayoutColumn(layout, true);
uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
- uiItemR(col, &dtar_ptr, "id", 0, IFACE_("Bone 1"), ICON_NONE);
-
+ uiItemR(col, &dtar_ptr, "id", 0, IFACE_("Object 1"), ICON_NONE);
+
if (dtar->id && GS(dtar->id->name) == ID_OB && ob1->pose) {
PointerRNA tar_ptr;
-
+
RNA_pointer_create(dtar->id, &RNA_Pose, ob1->pose, &tar_ptr);
uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
}
-
+
+ /* Object 2 */
col = uiLayoutColumn(layout, true);
uiLayoutSetRedAlert(col, (dtar2->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
- uiItemR(col, &dtar2_ptr, "id", 0, IFACE_("Bone 2"), ICON_NONE);
-
+ uiItemR(col, &dtar2_ptr, "id", 0, IFACE_("Object 2"), ICON_NONE);
+
if (dtar2->id && GS(dtar2->id->name) == ID_OB && ob2->pose) {
PointerRNA tar_ptr;
-
+
RNA_pointer_create(dtar2->id, &RNA_Pose, ob2->pose, &tar_ptr);
uiItemPointerR(col, &dtar2_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
}
@@ -658,8 +659,8 @@ static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar *
/* initialize RNA pointer to the target */
RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr);
RNA_pointer_create(id, &RNA_DriverTarget, dtar2, &dtar2_ptr);
-
- /* Bone 1 */
+
+ /* Object 1 */
col = uiLayoutColumn(layout, true);
uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
uiItemR(col, &dtar_ptr, "id", 0, IFACE_("Object 1"), ICON_NONE);
@@ -673,7 +674,8 @@ static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar *
uiLayoutSetRedAlert(col, false); /* we can clear it again now - it's only needed when creating the ID/Bone fields */
uiItemR(col, &dtar_ptr, "transform_space", 0, NULL, ICON_NONE);
-
+
+ /* Object 2 */
col = uiLayoutColumn(layout, true);
uiLayoutSetRedAlert(col, (dtar2->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
uiItemR(col, &dtar2_ptr, "id", 0, IFACE_("Object 2"), ICON_NONE);
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index ae91a466495..1739569767e 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -46,10 +46,12 @@
#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 "ED_anim_api.h"
#include "graph_intern.h"
@@ -82,38 +84,59 @@ static void draw_fcurve_modifier_controls_envelope(FModifier *fcm, View2D *v2d)
FCM_EnvelopeData *fed;
const float fac = 0.05f * BLI_rctf_size_x(&v2d->cur);
int i;
-
+
+ const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ glLineWidth(1.0f);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniform1i("num_colors", 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);
-
- glVertex2f(v2d->cur.xmin, env->midval + env->max);
- glVertex2f(v2d->cur.xmax, env->midval + env->max);
- glEnd();
- setlinestyle(0);
-
- /* set size of vertices (non-adjustable for now) */
- glPointSize(2.0f);
-
- /* for now, point color is fixed, and is white */
- glColor3f(1.0f, 1.0f, 1.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);
+
+ immBegin(GWN_PRIM_LINES, 4);
+ immVertex2f(shdr_pos, v2d->cur.xmin, env->midval + env->min);
+ immVertex2f(shdr_pos, v2d->cur.xmax, env->midval + env->min);
+
+ immVertex2f(shdr_pos, v2d->cur.xmin, env->midval + env->max);
+ immVertex2f(shdr_pos, v2d->cur.xmax, env->midval + env->max);
+ immEnd();
+
+ immUnbindProgram();
+
+ if (env->totvert > 0) {
+ /* set size of vertices (non-adjustable for now) */
+ glPointSize(2.0f);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ /* for now, point color is fixed, and is white */
+ immUniformColor3f(1.0f, 1.0f, 1.0f);
+
+ immBeginAtMost(GWN_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 +144,37 @@ 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)
+{
+ /* Fade the 'intensity' of the vertices based on the selection of the curves too */
+ int alphaOffset = (int)((fcurve_display_alpha(fcu) - 1.0f) * 255);
+
+ float color[4];
+
+ /* 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_GetThemeColorShadeAlpha4fv(sel ? TH_VERTEX_SELECT : TH_VERTEX, 0, alphaOffset, color);
+ }
+ else {
+ /* Curve's points CANNOT BE edited */
+ UI_GetThemeColorShadeAlpha4fv(sel ? TH_TEXT_HI : TH_TEXT, 0, alphaOffset, color);
+ }
+
+ 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);
-
- for (i = 0; i < fcu->totvert; i++, bezt++) {
+
+ set_fcurve_vertex_color(fcu, sel);
+
+ immBeginAtMost(GWN_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,80 +185,50 @@ 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();
- }
-
- /* adjust view transform before starting */
- glTranslatef(x, y, 0.0f);
- glScalef(1.0f / xscale * hsize, 1.0f / yscale * hsize, 1.0f);
-
- /* draw! */
- glCallList(displist);
-
- /* restore view transform */
- glScalef(xscale / hsize, yscale / hsize, 1.0);
- glTranslatef(-x, -y, 0.0f);
+ immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
+
+ immUniform1f("size", UI_GetThemeValuef(TH_VERTEX_SIZE) * U.pixelsize);
+
+ draw_fcurve_selected_keyframe_vertices(fcu, v2d, edit, false, pos);
+ draw_fcurve_selected_keyframe_vertices(fcu, v2d, edit, true, pos);
+
+ 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);
+ (void) v2d; /* TODO: use this to draw only points in view */
- /* Compensate OGL scale sued for unit mapping, so circle will be circle, not ellipse */
- yscale *= units_scale;
-
/* set handle color */
- if (sel) UI_ThemeColor(TH_HANDLE_VERTEX_SELECT);
- else UI_ThemeColor(TH_HANDLE_VERTEX);
-
- /* anti-aliased lines for more consistent appearance */
- if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
-
- for (i = 0; i < fcu->totvert; i++, prevbezt = bezt, bezt++) {
- /* Draw the editmode handles for a bezier curve (others don't have handles)
+ 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.4f);
+
+ immBeginAtMost(GWN_PRIM_POINTS, fcu->totvert * 2);
+
+ 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
* - second handle only if current beztriple is bezier-mode
@@ -225,68 +239,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);
-
- /* 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);
- }
+ /* smooth outlines for more consistent appearance */
+ immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
+
+ /* set handle size */
+ immUniform1f("size", (UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE) + 1.0f) * U.pixelsize);
+ immUniform1f("outlineWidth", 1.0f * 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));
-
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ glEnable(GL_BLEND);
+ 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);
-
- set_fcurve_vertex_color(fcu, 1);
- draw_fcurve_vertices_keyframes(fcu, sipo, v2d, !(fcu->flag & FCURVE_PROTECTED), 1);
+ draw_fcurve_keyframe_vertices(fcu, v2d, !(fcu->flag & FCURVE_PROTECTED), pos);
+
+ GPU_disable_program_point_size();
+ glDisable(GL_BLEND);
}
/* Handles ---------------- */
@@ -303,10 +310,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;
}
}
@@ -315,13 +322,10 @@ static bool draw_fcurve_handles_check(SpaceIpo *sipo, FCurve *fcu)
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);
-
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
/* slightly hacky, but we want to draw unselected points before selected ones
* so that selected points are clearly visible
*/
@@ -348,18 +352,24 @@ 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);
+ immUniformColor4ubv(col);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2fv(pos, fp);
+ immVertex2fv(pos, fp + 3);
+ immEnd();
}
/* 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);
+ immUniformColor4ubv(col);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2fv(pos, fp + 3);
+ immVertex2fv(pos, fp + 6);
+ immEnd();
}
}
else {
@@ -370,9 +380,12 @@ 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);
+ immUniformColor4ubv(col);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2fv(pos, fp);
+ immVertex2fv(pos, fp + 3);
+ immEnd();
}
/* only draw second handle if this segment is bezier, and selection is ok */
@@ -382,15 +395,18 @@ 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);
+ immUniformColor4ubv(col);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2fv(pos, fp);
+ immVertex2fv(pos, fp + 3);
+ immEnd();
}
}
}
}
-
- glEnd(); /* GL_LINES */
+
+ immUnbindProgram();
}
/* Samples ---------------- */
@@ -399,36 +415,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);
-
- /* draw! */
- glCallList(displist);
-
+ gpuPushMatrix();
+ gpuTranslate2f(x, y);
+ gpuScale2f(1.0f / xscale * hsize, 1.0f / yscale * hsize);
+
+ /* draw X shape */
+ immBegin(GWN_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);
+ gpuPopMatrix();
}
/* helper func - draw keyframe vertices only for an F-Curve */
@@ -441,10 +445,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);
@@ -454,10 +454,17 @@ static void draw_fcurve_samples(SpaceIpo *sipo, ARegion *ar, FCurve *fcu)
/* anti-aliased lines for more consistent appearance */
if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
-
- 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);
-
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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);
+
+ immUnbindProgram();
+
glDisable(GL_BLEND);
if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) glDisable(GL_LINE_SMOOTH);
}
@@ -466,7 +473,7 @@ static void draw_fcurve_samples(SpaceIpo *sipo, ARegion *ar, FCurve *fcu)
/* 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 +543,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);
+
+ if (n > 0) {
+ immBegin(GWN_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();
}
-
- glEnd();
-
+
/* 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();
+ gpuPushMatrix();
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);
+ gpuScale2f(1.0f, unit_scale);
+ gpuTranslate2f(0.0f, offset);
- glBegin(GL_LINE_STRIP);
+ immBegin(GWN_PRIM_LINE_STRIP, count);
/* extrapolate to left? - left-side of view comes before first keyframe? */
if (prevfpt->vec[0] > v2d->cur.xmin) {
@@ -584,26 +604,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 +636,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();
+
+ gpuPopMatrix();
}
/* helper func - check if the F-Curve only contains easily drawable segments
@@ -648,7 +662,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 +675,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();
+ gpuPushMatrix();
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);
+ gpuScale2f(1.0f, unit_scale);
+ gpuTranslate2f(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(GWN_PRIM_LINE_STRIP, (b * 32 + 3));
/* extrapolate to left? */
if (prevbezt->vec[1][0] > v2d->cur.xmin) {
@@ -691,14 +708,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 +725,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 +755,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 +777,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 +791,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 +818,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();
+
+ gpuPopMatrix();
}
/* Debugging -------------------------------- */
@@ -825,7 +844,16 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
/* for now, only show when debugging driver... */
//if ((driver->flag & DRIVER_FLAG_SHOWDEBUG) == 0)
// return;
-
+
+ const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniform1i("num_colors", 0); /* Simple dashes. */
+
/* No curve to modify/visualize the result?
* => We still want to show the 1-1 default...
*/
@@ -833,26 +861,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);
+ immUniform1f("dash_width", 40.0f);
+ immUniform1f("dash_factor", 0.5f);
glLineWidth(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);
-
- t = v2d->cur.xmax;
- glVertex2f(t, (t + offset) * unitfac);
- }
- glEnd();
-
- /* cleanup line drawing */
- setlinestyle(0);
+ immBegin(GWN_PRIM_LINES, 2);
+
+ t = v2d->cur.xmin;
+ immVertex2f(shdr_pos, t, (t + offset) * unitfac);
+
+ t = v2d->cur.xmax;
+ immVertex2f(shdr_pos, t, (t + offset) * unitfac);
+
+ immEnd();
}
/* draw driver only if actually functional */
@@ -866,53 +892,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);
-
- glBegin(GL_LINES);
- {
- /* x-axis lookup */
- co[0] = x;
-
- if (y >= v2d->cur.ymin) {
- co[1] = v2d->cur.ymin - 1.0f;
- glVertex2fv(co);
-
- co[1] = y;
- glVertex2fv(co);
- }
-
- /* y-axis lookup */
+ immUniformColor3f(0.9f, 0.9f, 0.9f);
+ immUniform1f("dash_width", 10.0f);
+ immUniform1f("dash_factor", 0.5f);
+
+ immBegin(GWN_PRIM_LINES, (y >= v2d->cur.ymin) ? 4 : 2);
+
+ /* x-axis lookup */
+ co[0] = x;
+
+ if (y >= v2d->cur.ymin) {
+ co[1] = v2d->cur.ymin - 1.0f;
+ immVertex2fv(shdr_pos, co);
+
co[1] = y;
-
- co[0] = v2d->cur.xmin - 1.0f;
- glVertex2fv(co);
-
- co[0] = x;
- glVertex2fv(co);
+ immVertex2fv(shdr_pos, co);
}
- glEnd();
-
- setlinestyle(0);
+
+ /* y-axis lookup */
+ co[1] = y;
+
+ co[0] = v2d->cur.xmin - 1.0f;
+ immVertex2fv(shdr_pos, co);
+
+ co[0] = x;
+ immVertex2fv(shdr_pos, co);
+
+ immEnd();
+ immUnbindProgram();
+
+ /* GWN_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);
+ immUniformColor3f(0.9f, 0.9f, 0.9f);
glPointSize(7.0);
- glBegin(GL_POINTS);
- glVertex2f(x, y);
- glEnd();
+ immBegin(GWN_PRIM_POINTS, 1);
+ immVertex2f(shdr_pos, x, y);
+ immEnd();
/* inner frame */
- glColor3f(0.9f, 0.0f, 0.0f);
+ immUniformColor3f(0.9f, 0.0f, 0.0f);
glPointSize(3.0);
- glBegin(GL_POINTS);
- glVertex2f(x, y);
- glEnd();
+ immBegin(GWN_PRIM_POINTS, 1);
+ immVertex2f(shdr_pos, x, y);
+ immEnd();
}
}
+
+ immUnbindProgram();
}
/* Public Curve-Drawing API ---------------- */
@@ -925,29 +957,43 @@ void graph_draw_ghost_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar)
FCurve *fcu;
/* draw with thick dotted lines */
- setlinestyle(10);
glLineWidth(3.0f);
/* anti-aliased lines for less jagged appearance */
- if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) glEnable(GL_LINE_SMOOTH);
+ if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) {
+ glEnable(GL_LINE_SMOOTH);
+ }
glEnable(GL_BLEND);
-
+
+ const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniform1i("num_colors", 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) {
/* set whatever color the curve has set
* - 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);
+ }
+
+ immUnbindProgram();
+
+ if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) {
+ glDisable(GL_LINE_SMOOTH);
}
-
- /* restore settings */
- setlinestyle(0);
-
- if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) glDisable(GL_LINE_SMOOTH);
glDisable(GL_BLEND);
}
@@ -975,9 +1021,10 @@ 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)
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
-
+ 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,
* so we need to check which method should be used
@@ -986,60 +1033,82 @@ 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) {
+ 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);
+
+ const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniform1i("num_colors", 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
+ /* 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);
-
- if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) glDisable(GL_LINE_SMOOTH);
+
+ immUnbindProgram();
+
+ if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) {
+ glDisable(GL_LINE_SMOOTH);
+ }
glDisable(GL_BLEND);
}
@@ -1047,7 +1116,7 @@ void graph_draw_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGrid
* - 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,9 +1132,9 @@ 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);
+ gpuPushMatrix();
+ gpuScale2f(1.0f, unit_scale);
+ gpuTranslate2f(0.0f, offset);
/* set this once and for all - all handles and handle-verts should use the same thickness */
glLineWidth(1.0);
@@ -1080,14 +1149,14 @@ void graph_draw_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGrid
glDisable(GL_BLEND);
}
- 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();
+ gpuPopMatrix();
}
}
@@ -1131,7 +1200,7 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
* start of list offset, and the second is as a correction for the scrollers.
*/
height = (float)((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac) * 2));
- UI_view2d_totRect_set(v2d, ar->winx, height);
+ UI_view2d_totRect_set(v2d, BLI_rcti_size_x(&ar->v2d.mask), height);
/* loop through channels, and set up drawing depending on their type */
{ /* first pass: just the standard GL-drawing for backdrop + text */
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index f38d36853d7..09e38579c21 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -54,13 +54,14 @@
#include "BLT_translation.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_nla.h"
#include "BKE_context.h"
#include "BKE_report.h"
+#include "DEG_depsgraph_build.h"
+
#include "UI_view2d.h"
#include "ED_anim_api.h"
@@ -2714,7 +2715,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));
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index 478dbd3d9c0..75f0da83e77 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -632,7 +632,9 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
/* 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);
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index 2582ba4be8d..d2358a494d5 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -53,7 +53,7 @@
#include "ED_anim_api.h"
#include "ED_markers.h"
-#include "BIF_gl.h"
+#include "GPU_immediate.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -265,43 +265,52 @@ 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) {
- float y = sipo->cursorVal;
-
- /* Draw a green line to indicate the cursor value */
- UI_ThemeColorShadeAlpha(TH_CFRAME, -10, -50);
- glEnable(GL_BLEND);
- glLineWidth(2.0);
+ if (((sipo->flag & SIPO_NODRAWCURSOR) == 0) || (sipo->mode == SIPO_MODE_DRIVERS)) {
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
- glBegin(GL_LINES);
- glVertex2f(v2d->cur.xmin, y);
- glVertex2f(v2d->cur.xmax, y);
- glEnd();
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- glDisable(GL_BLEND);
- }
-
- /* 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);
-
- glBegin(GL_LINES);
- glVertex2f(x, v2d->cur.ymin);
- glVertex2f(x, v2d->cur.ymax);
- glEnd();
+ /* horizontal component of value-cursor (value line before the current frame line) */
+ if ((sipo->flag & SIPO_NODRAWCURSOR) == 0) {
+
+ float y = sipo->cursorVal;
+
+ /* Draw a green line to indicate the cursor value */
+ immUniformThemeColorShadeAlpha(TH_CFRAME, -10, -50);
+ glEnable(GL_BLEND);
+ glLineWidth(2.0);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2f(pos, v2d->cur.xmin, y);
+ immVertex2f(pos, v2d->cur.xmax, y);
+ immEnd();
+
+ glDisable(GL_BLEND);
+ }
+
+ /* 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 */
+ immUniformThemeColorShadeAlpha(TH_CFRAME, -40, -50);
+ glEnable(GL_BLEND);
+ glLineWidth(2.0);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2f(pos, x, v2d->cur.ymin);
+ immVertex2f(pos, x, v2d->cur.ymax);
+ immEnd();
+
+ glDisable(GL_BLEND);
+ }
- glDisable(GL_BLEND);
+ 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;
@@ -335,8 +344,8 @@ static void graph_channel_region_init(wmWindowManager *wm, ARegion *ar)
wmKeyMap *keymap;
/* make sure we keep the hide flags */
- ar->v2d.scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM);
- ar->v2d.scroll &= ~(V2D_SCROLL_LEFT | V2D_SCROLL_TOP); /* prevent any noise of past */
+ ar->v2d.scroll |= V2D_SCROLL_RIGHT;
+ ar->v2d.scroll &= ~(V2D_SCROLL_LEFT | V2D_SCROLL_TOP | V2D_SCROLL_BOTTOM); /* prevent any noise of past */
ar->v2d.scroll |= V2D_SCROLL_HORIZONTAL_HIDE;
ar->v2d.scroll |= V2D_SCROLL_VERTICAL_HIDE;
@@ -404,7 +413,9 @@ static void graph_buttons_region_draw(const bContext *C, ARegion *ar)
ED_region_panels(C, ar, NULL, -1, true);
}
-static void graph_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void graph_region_listener(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -450,6 +461,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);
@@ -459,7 +475,7 @@ static void graph_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), AReg
}
/* editor level listener */
-static void graph_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
+static void graph_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, const Scene *UNUSED(scene))
{
SpaceIpo *sipo = (SpaceIpo *)sa->spacedata.first;
@@ -687,7 +703,7 @@ static void graph_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID
return;
}
- if ((ID *)sgraph->ads->filter_grp == old_id) {
+ if (sgraph->ads && (ID *)sgraph->ads->filter_grp == old_id) {
sgraph->ads->filter_grp = (Group *)new_id;
}
}
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 b9d98dfe794..8037c2deb5b 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -428,7 +428,6 @@ static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void *
RenderPass *rpass;
const char *fake_name;
int nr;
- int passflag = 0;
/* may have been freed since drawing */
rr = BKE_image_acquire_renderresult(scene, image);
@@ -450,30 +449,31 @@ static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void *
fake_name = ui_imageuser_pass_fake_name(rl);
if (fake_name) {
- BLI_strncpy(rpass_fake.internal_name, fake_name, sizeof(rpass_fake.internal_name));
+ BLI_strncpy(rpass_fake.name, fake_name, sizeof(rpass_fake.name));
nr += 1;
}
+ ListBase added_passes;
+ BLI_listbase_clear(&added_passes);
+
/* rendered results don't have a Combined pass */
/* multiview: the ordering must be ascending, so the left-most pass is always the one picked */
for (rpass = rl ? rl->passes.first : NULL; rpass; rpass = rpass->next, nr++) {
-
/* just show one pass of each kind */
- if (passflag & rpass->passtype)
+ if (BLI_findstring_ptr(&added_passes, rpass->name, offsetof(LinkData, data))) {
continue;
+ }
+ BLI_addtail(&added_passes, BLI_genericNodeN(rpass->name));
- passflag |= rpass->passtype;
-
-final:
- uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, IFACE_(rpass->internal_name), 0, 0,
+ uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, IFACE_(rpass->name), 0, 0,
UI_UNIT_X * 5, UI_UNIT_X, &iuser->pass, (float) nr, 0.0, 0, -1, "");
}
+ BLI_freelistN(&added_passes);
+
if (fake_name) {
- fake_name = NULL;
- rpass = &rpass_fake;
- nr = 0;
- goto final;
+ uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, IFACE_(rpass_fake.name), 0, 0,
+ UI_UNIT_X * 5, UI_UNIT_X, &iuser->pass, 0.0f, 0.0, 0, -1, "");
}
BKE_image_release_renderresult(scene, image);
@@ -633,7 +633,7 @@ static bool ui_imageuser_pass_menu_step(bContext *C, int direction, void *rnd_pt
int rp_index = iuser->pass + 1;
for (rp = rpass->next; rp; rp = rp->next, rp_index++) {
- if (rp->passtype != rpass->passtype) {
+ if (!STREQ(rp->name, rpass->name)) {
iuser->pass = rp_index;
changed = true;
break;
@@ -650,7 +650,7 @@ static bool ui_imageuser_pass_menu_step(bContext *C, int direction, void *rnd_pt
}
for (rp = rl->passes.first; rp; rp = rp->next, rp_index++) {
- if (rp->passtype == rpass->passtype) {
+ if (STREQ(rp->name, rpass->name)) {
iuser->pass = rp_index - 1;
changed = true;
break;
@@ -712,6 +712,10 @@ static void uiblock_layer_pass_buttons(
const char *display_name = "";
const bool show_stereo = (iuser->flag & IMA_SHOW_STEREO) != 0;
+ if (iuser->scene == NULL) {
+ return;
+ }
+
uiLayoutRow(layout, true);
/* layer menu is 1/3 larger than pass */
@@ -769,7 +773,7 @@ static void uiblock_layer_pass_buttons(
fake_name = ui_imageuser_pass_fake_name(rl);
rpass = (rl ? BLI_findlink(&rl->passes, iuser->pass - (fake_name ? 1 : 0)) : NULL);
- display_name = rpass ? rpass->internal_name : (fake_name ? fake_name : "");
+ display_name = rpass ? rpass->name : (fake_name ? fake_name : "");
rnd_pt = ui_imageuser_data_copy(&rnd_pt_local);
but = uiDefMenuBut(
block, ui_imageuser_pass_menu, rnd_pt, IFACE_(display_name),
@@ -1204,7 +1208,7 @@ void uiTemplateImageStereo3d(uiLayout *layout, PointerRNA *stereo3d_format_ptr)
case S3D_DISPLAY_SIDEBYSIDE:
{
uiItemR(col, stereo3d_format_ptr, "use_sidebyside_crosseyed", 0, NULL, ICON_NONE);
- /* fall-through */
+ ATTR_FALLTHROUGH;
}
case S3D_DISPLAY_TOPBOTTOM:
{
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index e810f4db7dd..1af717fd7f8 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -60,9 +60,12 @@
#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 "BLF_api.h"
#include "ED_gpencil.h"
@@ -87,7 +90,6 @@ static void draw_render_info(const bContext *C,
float zoomx,
float zoomy)
{
- RenderResult *rr;
Render *re = RE_GetRender(scene->id.name);
RenderData *rd = RE_engine_get_render_data(re);
Scene *stats_scene = ED_render_job_get_scene(C);
@@ -95,7 +97,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 +109,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);
+ gpuPushMatrix();
+ gpuTranslate2f(x, y);
+ gpuScale2f(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 */
+ gpuTranslate2f((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);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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);
+
+ 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();
+ gpuPopMatrix();
}
}
}
@@ -169,28 +173,34 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, bool color_manage, bool use_d
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_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);
+ immUniformColor4ub(0, 0, 0, 190);
+ immRecti(pos, 0, 0, BLI_rcti_size_x(&ar->winrct) + 1, UI_UNIT_Y);
+
+ immUnbindProgram();
+
glDisable(GL_BLEND);
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 +214,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 +232,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 +243,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 +255,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 +277,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,9 +315,9 @@ 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);
@@ -318,13 +328,18 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, bool color_manage, bool use_d
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 = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_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 +347,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);
+ immUniformColor3fvAlpha(finalcol, fp ? fp[3] : (cp[3] / 255.0f));
+ immRecti(pos, color_rect.xmin, color_rect.ymin, color_rect.xmax, color_rect.ymax);
glDisable(GL_BLEND);
}
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 = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3ub(128, 128, 128);
+ imm_draw_line_box(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 +393,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,70 +416,37 @@ 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)
{
-
- /* 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);
+ float red[4] = {1.0f, 0.0f, 0.0f, 0.0f};
- glaDrawPixelsSafe(x1, y1, rectx, recty, rectx, GL_LUMINANCE, GL_UNSIGNED_INT, recti);
- glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
-}
+ /* 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;
+ }
-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);
-}
+ 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_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);
+ immDrawPixelsTex(&state, x1, y1, rectx, recty, GL_RED, GL_INT, GL_NEAREST, recti, zoomx, zoomy, NULL);
+
+ 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;
clipend = ((Camera *)scene->camera->data)->clipend;
@@ -473,8 +457,8 @@ static void sima_draw_zbuffloat_pixels(Scene *scene, float x1, float y1, int rec
scale = 0.01f;
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,92 +469,85 @@ 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);
-}
-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
+ 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, 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) {
+ imm_draw_checker_box(x, y, x + ibuf->x * zoomx, y + ibuf->y * zoomy);
+
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- fdrawcheckerboard(x, y, x + ibuf->x * zoomx, y + ibuf->y * zoomy);
}
- 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);
}
+
+ IMB_display_buffer_release(cache_handle);
}
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)
@@ -601,7 +578,7 @@ static void draw_image_buffer_tiled(SpaceImage *sima, ARegion *ar, Scene *scene,
unsigned int *rect;
int dx, dy, sx, sy, x, y;
void *cache_handle;
- int channel_offset = -1;
+ float shuffle[4] = {0.0f, 0.0f, 0.0f, 0.0f};
/* verify valid values, just leave this a while */
if (ima->xrep < 1) return;
@@ -615,8 +592,6 @@ static void draw_image_buffer_tiled(SpaceImage *sima, ARegion *ar, Scene *scene,
if (!display_buffer)
return;
- glPixelZoom(zoomx, zoomy);
-
if (sima->curtile >= ima->xrep * ima->yrep)
sima->curtile = ima->xrep * ima->yrep - 1;
@@ -628,24 +603,34 @@ static void draw_image_buffer_tiled(SpaceImage *sima, ARegion *ar, Scene *scene,
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);
+ if ((sima->flag & (SI_SHOW_R | SI_SHOW_G | SI_SHOW_B | SI_SHOW_ALPHA)) != 0) {
+ 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;
}
+
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);
+
+ if ((sima->flag & (SI_SHOW_R | SI_SHOW_G | SI_SHOW_B | SI_SHOW_ALPHA)) == 0) {
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
+ immDrawPixelsTex(&state, x, y, dx, dy, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, rect, zoomx, zoomy, NULL);
}
else {
- glaDrawPixelsSafe(x, y, dx, dy, dx, GL_LUMINANCE, GL_UNSIGNED_INT,
- (unsigned char *)rect - (4 - channel_offset));
+ 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);
+
+ immDrawPixelsTex(&state, x, y, dx, dy, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, rect, zoomx, zoomy, NULL);
}
}
}
- glPixelZoom(1.0f, 1.0f);
-
IMB_display_buffer_release(cache_handle);
MEM_freeN(rect);
@@ -701,134 +686,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);
-
- }
-}
-
-/* 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;
-
- if (draw) {
- getmouseco_areawin(mval);
-
- radius = BKE_brush_size_get(brush) * G.sima->zoom;
- fdrawXORcirc(mval[0], mval[1], radius);
-
- if (brush->innerradius != 1.0) {
- radius *= brush->innerradius;
- fdrawXORcirc(mval[0], mval[1], radius);
- }
- }
- }
-}
-#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);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int shdr_dashed_pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
- if (!display_buffer) {
- BKE_image_release_ibuf(brush->clone.image, ibuf, NULL);
- IMB_display_buffer_release(cache_handle);
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
- return NULL;
- }
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
- rect = MEM_dupallocN(display_buffer);
+ immUniform1i("num_colors", 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);
- IMB_display_buffer_release(cache_handle);
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2fv(shdr_dashed_pos, hist->co[0]);
+ immVertex2fv(shdr_dashed_pos, hist->co[1]);
+ immEnd();
- if (!rect) {
- BKE_image_release_ibuf(brush->clone.image, ibuf, NULL);
- return NULL;
+ immUnbindProgram();
}
-
- *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);
+
+ if (!display_buffer) {
+ BKE_image_release_ibuf(brush->clone.image, ibuf, NULL);
+ IMB_display_buffer_release(cache_handle);
+ return;
+ }
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);
- glPixelZoom(1.0, 1.0);
+ 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);
- MEM_freeN(clonerect);
+ glDisable(GL_BLEND);
+
+ BKE_image_release_ibuf(brush->clone.image, ibuf, NULL);
+ IMB_display_buffer_release(cache_handle);
}
}
}
@@ -924,23 +837,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_unlock_thread(LOCK_DRAW_IMAGE);
}
@@ -1002,8 +898,12 @@ void draw_image_cache(const bContext *C, ARegion *ar)
/* 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);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_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 8f2f6595408..a3a115b3e6a 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -365,7 +365,7 @@ bool ED_space_image_show_uvedit(SpaceImage *sima, Object *obedit)
struct BMEditMesh *em = BKE_editmesh_from_object(obedit);
bool ret;
- ret = EDBM_mtexpoly_check(em);
+ ret = EDBM_uv_check(em);
return ret;
}
@@ -374,10 +374,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(SceneLayer *sl, SpaceImage *sima)
{
/* check editmode - this is reserved for UV editing */
- Object *ob = OBACT;
+ Object *ob = OBACT_NEW;
if (ob && ob->mode & OB_MODE_EDIT && ED_space_image_show_uvedit(sima, ob)) {
return false;
}
@@ -390,8 +390,8 @@ int 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);
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ return ED_space_image_check_show_maskedit(sl, sima);
}
return false;
diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h
index 69993c3be65..52d04ad4956 100644
--- a/source/blender/editors/space_image/image_intern.h
+++ b/source/blender/editors/space_image/image_intern.h
@@ -64,7 +64,9 @@ void IMAGE_OT_view_zoom_in(struct wmOperatorType *ot);
void IMAGE_OT_view_zoom_out(struct wmOperatorType *ot);
void IMAGE_OT_view_zoom_ratio(struct wmOperatorType *ot);
void IMAGE_OT_view_zoom_border(struct wmOperatorType *ot);
+#ifdef WITH_INPUT_NDOF
void IMAGE_OT_view_ndof(struct wmOperatorType *ot);
+#endif
void IMAGE_OT_new(struct wmOperatorType *ot);
void IMAGE_OT_open(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 1158e692182..659dfbfd57d 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -52,10 +52,10 @@
#include "DNA_node_types.h"
#include "DNA_packedFile_types.h"
#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_icons.h"
#include "BKE_image.h"
@@ -69,6 +69,8 @@
#include "BKE_sound.h"
#include "BKE_scene.h"
+#include "DEG_depsgraph.h"
+
#include "GPU_draw.h"
#include "GPU_buffers.h"
@@ -122,7 +124,7 @@ static void sima_zoom_set(SpaceImage *sima, ARegion *ar, float zoom, const float
width *= sima->zoom;
height *= sima->zoom;
- if ((width < 4) && (height < 4))
+ if ((width < 4) && (height < 4) && sima->zoom < oldzoom)
sima->zoom = oldzoom;
else if (BLI_rcti_size_x(&ar->winrct) <= sima->zoom)
sima->zoom = oldzoom;
@@ -656,6 +658,7 @@ void IMAGE_OT_view_zoom(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN);
}
+#ifdef WITH_INPUT_NDOF
/********************** NDOF operator *********************/
/* Combined pan/zoom from a 3D mouse device.
@@ -705,6 +708,7 @@ void IMAGE_OT_view_ndof(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_LOCK_BYPASS;
}
+#endif /* WITH_INPUT_NDOF */
/********************** view all operator *********************/
@@ -789,6 +793,7 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
SpaceImage *sima;
ARegion *ar;
Scene *scene;
+ SceneLayer *sl;
Object *obedit;
Image *ima;
@@ -796,6 +801,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);
+ sl = CTX_data_scene_layer(C);
obedit = CTX_data_edit_object(C);
ima = ED_space_image(sima);
@@ -807,7 +813,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(sl, sima)) {
if (!ED_mask_selected_minmax(C, min, max)) {
return OPERATOR_CANCELLED;
}
@@ -1064,6 +1070,7 @@ typedef struct ImageOpenData {
typedef struct ImageFrameRange {
struct ImageFrameRange *next, *prev;
ListBase frames;
+ /** The full path of the first file in the list of image files */
char filepath[FILE_MAX];
} ImageFrameRange;
@@ -1089,12 +1096,12 @@ static void image_open_cancel(bContext *UNUSED(C), wmOperator *op)
/**
* \brief Get a list of frames from the list of image files matching the first file name sequence pattern
* \param ptr [in] the RNA pointer containing the "directory" entry and "files" collection
- * \param frames [out] the list of frame numbers found in the files matching the first one by name
- * \param path [out] the full path of the first file in the list of image files
+ * \param frames_all [out] the list of frame numbers found in the files matching the first one by name
*/
static void image_sequence_get_frame_ranges(PointerRNA *ptr, ListBase *frames_all)
{
char dir[FILE_MAXDIR];
+ const bool do_frame_range = RNA_boolean_get(ptr, "use_sequence_detection");
ImageFrameRange *frame_range = NULL;
RNA_string_get(ptr, "directory", dir);
@@ -1110,7 +1117,8 @@ static void image_sequence_get_frame_ranges(PointerRNA *ptr, ListBase *frames_al
frame->framenr = BLI_stringdec(filename, head, tail, &digits);
/* still in the same sequence */
- if ((frame_range != NULL) &&
+ if (do_frame_range &&
+ (frame_range != NULL) &&
(STREQLEN(base_head, head, FILE_MAX)) &&
(STREQLEN(base_tail, tail, FILE_MAX)))
{
@@ -1216,7 +1224,7 @@ static Image *image_open_single(
static int image_open_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- SpaceImage *sima = CTX_wm_space_image(C); /* XXX other space types can call */
+ ScrArea *sa = CTX_wm_area(C);
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
ImageUser *iuser = NULL;
@@ -1295,10 +1303,21 @@ static int image_open_exec(bContext *C, wmOperator *op)
if (iod->iuser) {
iuser = iod->iuser;
}
- else if (sima) {
+ else if (sa->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = sa->spacedata.first;
ED_space_image_set(sima, scene, obedit, ima);
iuser = &sima->iuser;
}
+ else if (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) {
@@ -1311,7 +1330,11 @@ static int image_open_exec(bContext *C, wmOperator *op)
iuser->frames = frame_seq_len;
iuser->sfra = 1;
iuser->framenr = 1;
- iuser->offset = frame_ofs - 1;
+ if (ima->source == IMA_SRC_MOVIE) {
+ iuser->offset = 0;
+ } else {
+ iuser->offset = frame_ofs - 1;
+ }
iuser->fie_ima = 2;
iuser->scene = scene;
BKE_image_init_imageuser(ima, iuser);
@@ -1434,6 +1457,9 @@ void IMAGE_OT_open(wmOperatorType *ot)
ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILES | WM_FILESEL_RELPATH,
FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+
+ RNA_def_boolean(ot->srna, "use_sequence_detection", true, "Detect Sequences",
+ "Automatically detect animated sequences in selected images (based on file names)");
}
/******************** Match movie length operator ********************/
@@ -1461,7 +1487,10 @@ static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op))
if (!ima || !iuser || !BKE_image_has_anim(ima))
return OPERATOR_CANCELLED;
- iuser->frames = IMB_anim_get_duration(((ImageAnim *) ima->anims.first)->anim, IMB_TC_RECORD_RUN);
+ struct anim *anim = ((ImageAnim *)ima->anims.first)->anim;
+ 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);
return OPERATOR_FINISHED;
@@ -1606,18 +1635,26 @@ static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima,
/* imtype */
simopts->im_format = scene->r.im_format;
is_depth_set = true;
+ if (!BKE_image_is_multiview(ima)) {
+ /* In case multiview is disabled, render settings would be invalid for render result in this area. */
+ simopts->im_format.stereo3d_format = *ima->stereo3d_format;
+ simopts->im_format.views_format = ima->views_format;
+ }
}
else {
if (ima->source == IMA_SRC_GENERATED) {
simopts->im_format.imtype = R_IMF_IMTYPE_PNG;
simopts->im_format.compress = ibuf->foptions.quality;
+ simopts->im_format.planes = ibuf->planes;
}
else {
BKE_imbuf_to_image_format(&simopts->im_format, ibuf);
}
- }
- simopts->im_format.planes = ibuf->planes;
+ /* use the multiview image settings as the default */
+ simopts->im_format.stereo3d_format = *ima->stereo3d_format;
+ simopts->im_format.views_format = ima->views_format;
+ }
//simopts->subimtype = scene->r.subimtype; /* XXX - this is lame, we need to make these available too! */
@@ -1658,10 +1695,6 @@ static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima,
}
}
- /* use the multiview image settings as the default */
- simopts->im_format.stereo3d_format = *ima->stereo3d_format;
- simopts->im_format.views_format = ima->views_format;
-
/* color management */
BKE_color_managed_display_settings_copy(&simopts->im_format.display_settings, &scene->display_settings);
BKE_color_managed_view_settings_copy(&simopts->im_format.view_settings, &scene->view_settings);
@@ -1869,7 +1902,6 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI
}
else {
colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
- IMB_metadata_copy(colormanaged_ibuf, ibuf);
ok = BKE_imbuf_write_as(colormanaged_ibuf, simopts->filepath, imf, save_copy);
save_imbuf_post(ibuf, colormanaged_ibuf);
}
@@ -2316,7 +2348,7 @@ static int image_reload_exec(bContext *C, wmOperator *UNUSED(op))
// XXX other users?
BKE_image_signal(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);
@@ -2540,7 +2572,7 @@ void IMAGE_OT_new(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO;
/* properties */
- RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image datablock name");
+ RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image data-block name");
prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
RNA_def_property_subtype(prop, PROP_PIXEL);
prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
@@ -2841,7 +2873,7 @@ void IMAGE_OT_unpack(wmOperatorType *ot)
/* properties */
RNA_def_enum(ot->srna, "method", rna_enum_unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack");
- RNA_def_string(ot->srna, "id", NULL, MAX_ID_NAME - 2, "Image Name", "Image datablock name to unpack"); /* XXX, weark!, will fail with library, name collisions */
+ RNA_def_string(ot->srna, "id", NULL, MAX_ID_NAME - 2, "Image Name", "Image data-block name to unpack"); /* XXX, weark!, will fail with library, name collisions */
}
/******************** sample image operator ********************/
@@ -2879,11 +2911,9 @@ static void image_sample_draw(const bContext *C, ARegion *ar, void *arg_info)
}
}
-/* Returns color in the display space, matching ED_space_node_color_sample(). */
-bool ED_space_image_color_sample(Scene *scene, SpaceImage *sima, ARegion *ar, int mval[2], float r_col[3])
+/* Returns color in linear space, matching ED_space_node_color_sample(). */
+bool ED_space_image_color_sample(SpaceImage *sima, ARegion *ar, int mval[2], float r_col[3])
{
- const char *display_device = scene->display_settings.display_device;
- struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
void *lock;
ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
float fx, fy;
@@ -2917,10 +2947,6 @@ bool ED_space_image_color_sample(Scene *scene, SpaceImage *sima, ARegion *ar, in
}
}
- if (ret) {
- IMB_colormanagement_scene_linear_to_display_v3(r_col, display);
- }
-
ED_space_image_release_buffer(sima, ibuf, lock);
return ret;
}
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 35a658eac23..58fb75edd84 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -44,10 +44,15 @@
#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_scene.h"
#include "BKE_screen.h"
+#include "BKE_material.h"
+
+#include "DEG_depsgraph.h"
#include "IMB_imbuf_types.h"
@@ -59,6 +64,7 @@
#include "ED_space_api.h"
#include "ED_screen.h"
#include "ED_uvedit.h"
+#include "ED_transform.h"
#include "BIF_gl.h"
@@ -235,7 +241,9 @@ static void image_operatortypes(void)
WM_operatortype_append(IMAGE_OT_view_zoom_out);
WM_operatortype_append(IMAGE_OT_view_zoom_ratio);
WM_operatortype_append(IMAGE_OT_view_zoom_border);
+#ifdef WITH_INPUT_NDOF
WM_operatortype_append(IMAGE_OT_view_ndof);
+#endif
WM_operatortype_append(IMAGE_OT_new);
WM_operatortype_append(IMAGE_OT_open);
@@ -296,8 +304,10 @@ static void image_keymap(struct wmKeyConfig *keyconf)
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);
@@ -418,27 +428,22 @@ static void image_refresh(const bContext *C, ScrArea *sa)
}
else {
/* old shading system, we set texface */
- MTexPoly *tf;
-
- if (em && EDBM_mtexpoly_check(em)) {
- tf = EDBM_mtexpoly_active_get(em, NULL, sloppy, selected);
+ if (em && EDBM_uv_check(em)) {
+ BMFace *efa = BM_mesh_active_face_get(em->bm, sloppy, selected);
- if (tf) {
+ if (efa) {
/* don't need to check for pin here, see above */
- sima->image = tf->tpage;
-
- if ((sima->flag & SI_EDITTILE) == 0) {
- sima->curtile = tf->tile;
- }
+ Image *image = BKE_object_material_edit_image_get(obedit, efa->mat_nr);
+
+ sima->image = image;
}
}
}
}
}
-static void image_listener(bScreen *sc, ScrArea *sa, wmNotifier *wmn)
+static void image_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, const Scene *scene)
{
- Scene *scene = sc->scene;
SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
/* context changes */
@@ -531,7 +536,8 @@ static void image_listener(bScreen *sc, ScrArea *sa, wmNotifier *wmn)
case ND_TRANSFORM:
case ND_MODIFIER:
{
- Object *ob = OBACT;
+ SceneLayer *sl = BKE_scene_layer_context_active_PLACEHOLDER(scene);
+ Object *ob = OBACT_NEW;
if (ob && (ob == wmn->reference) && (ob->mode & OB_MODE_EDIT)) {
if (sima->lock && (sima->flag & SI_DRAWSHADOW)) {
ED_area_tag_refresh(sa);
@@ -583,6 +589,27 @@ static int image_context(const bContext *C, const char *member, bContextDataResu
return 0;
}
+static void IMAGE_WGT_manipulator2d(wmManipulatorGroupType *wgt)
+{
+ wgt->name = "UV Transform Manipulator";
+ wgt->idname = "IMAGE_WGT_manipulator2d";
+
+ wgt->flag |= WM_MANIPULATORGROUPTYPE_PERSISTENT;
+
+ wgt->poll = ED_widgetgroup_manipulator2d_poll;
+ wgt->setup = ED_widgetgroup_manipulator2d_setup;
+ wgt->refresh = ED_widgetgroup_manipulator2d_refresh;
+ wgt->draw_prepare = ED_widgetgroup_manipulator2d_draw_prepare;
+}
+
+static void image_widgets(void)
+{
+ wmManipulatorMapType *mmap_type = WM_manipulatormaptype_ensure(
+ &(const struct wmManipulatorMapType_Params){SPACE_IMAGE, RGN_TYPE_WINDOW});
+
+ WM_manipulatorgrouptype_append_and_link(mmap_type, IMAGE_WGT_manipulator2d);
+}
+
/************************** main region ***************************/
/* sets up the fields of the View2D from zoom and offset */
@@ -646,6 +673,16 @@ static void image_main_region_init(wmWindowManager *wm, ARegion *ar)
// image space manages own v2d
// UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_STANDARD, ar->winx, ar->winy);
+ /* manipulators */
+ if (ar->manipulator_map == NULL) {
+ const struct wmManipulatorMapType_Params wmap_params = {
+ .spaceid = SPACE_IMAGE,
+ .regionid = RGN_TYPE_WINDOW,
+ };
+ ar->manipulator_map = WM_manipulatormap_new_from_type(&wmap_params);
+ }
+ WM_manipulatormap_add_handlers(ar, ar->manipulator_map);
+
/* mask polls mode */
keymap = WM_keymap_find(wm->defaultconf, "Mask Editing", 0, 0);
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
@@ -671,7 +708,6 @@ static void image_main_region_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler(&ar->handlers, keymap);
keymap = WM_keymap_find(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)
@@ -680,9 +716,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);
+ SceneLayer *sl = CTX_data_scene_layer(C);
View2D *v2d = &ar->v2d;
//View2DScrollers *scrollers;
float col[3];
@@ -718,7 +756,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, sl, obedit, obact, depsgraph);
/* check for mask (delay draw) */
if (ED_space_image_show_uvedit(sima, obedit)) {
@@ -787,6 +825,8 @@ static void image_main_region_draw(const bContext *C, ARegion *ar)
UI_view2d_view_restore(C);
}
+ WM_manipulatormap_draw(ar->manipulator_map, C, WM_MANIPULATORMAP_DRAWSTEP_2D);
+
draw_image_cache(C, ar);
/* scrollers? */
@@ -797,10 +837,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(
+ bScreen *UNUSED(sc), 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_manipulatormap_tag_refresh(ar->manipulator_map);
+ break;
case NC_GPENCIL:
if (ELEM(wmn->action, NA_EDITED, NA_SELECTED))
ED_region_tag_redraw(ar);
@@ -810,6 +856,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_manipulatormap_tag_refresh(ar->manipulator_map);
break;
case NC_MATERIAL:
if (wmn->data == ND_SHADING_LINKS) {
@@ -819,6 +866,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,7 +893,9 @@ static void image_buttons_region_draw(const bContext *C, ARegion *ar)
ED_region_panels(C, ar, NULL, -1, true);
}
-static void image_buttons_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void image_buttons_region_listener(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -914,7 +968,9 @@ static void image_tools_region_draw(const bContext *C, ARegion *ar)
ED_region_panels(C, ar, NULL, -1, true);
}
-static void image_tools_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void image_tools_region_listener(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -960,7 +1016,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(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -1029,6 +1087,7 @@ void ED_spacetype_image(void)
st->refresh = image_refresh;
st->listener = image_listener;
st->context = image_context;
+ st->manipulators = image_widgets;
st->id_remap = image_id_remap;
/* regions: main window */
diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c
index 0e427623840..b87a0de23b9 100644
--- a/source/blender/editors/space_info/info_ops.c
+++ b/source/blender/editors/space_info/info_ops.c
@@ -162,7 +162,6 @@ static int pack_all_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
packAll(bmain, op->reports, true);
- G.fileflags |= G_AUTOPACK;
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index 8dc6c4229b2..bd1bdb952d6 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -49,6 +49,7 @@
#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"
@@ -271,7 +272,7 @@ static void stats_object_sculpt_dynamic_topology(Object *ob, SceneStats *stats)
static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats)
{
- if (base->flag & SELECT) stats->totobjsel++;
+ if (base->flag & BASE_SELECTED) stats->totobjsel++;
if (ob->transflag & OB_DUPLIPARTS) {
/* Dupli Particles */
@@ -300,7 +301,7 @@ static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats)
}
}
- stats_object(ob, base->flag & SELECT, 1, stats);
+ stats_object(ob, base->flag_legacy & SELECT, 1, stats);
stats->totobj++;
}
else if (ob->parent && (ob->parent->transflag & (OB_DUPLIVERTS | OB_DUPLIFACES))) {
@@ -316,23 +317,23 @@ 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, base->flag_legacy & SELECT, 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, base->flag_legacy & SELECT, tot, stats);
}
else if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) {
/* Dupli Group */
int tot = count_duplilist(ob);
stats->totobj += tot;
- stats_object(ob, base->flag & SELECT, tot, stats);
+ stats_object(ob, base->flag_legacy & SELECT, tot, stats);
}
else {
/* No Dupli */
- stats_object(ob, base->flag & SELECT, 1, stats);
+ stats_object(ob, base->flag_legacy & SELECT, 1, stats);
stats->totobj++;
}
}
@@ -344,10 +345,10 @@ static bool stats_is_object_dynamic_topology_sculpt(Object *ob)
}
/* Statistics displayed in info header. Called regularly on scene changes. */
-static void stats_update(Scene *scene)
+static void stats_update(Scene *scene, SceneLayer *sl)
{
SceneStats stats = {0};
- Object *ob = (scene->basact) ? scene->basact->object : NULL;
+ Object *ob = (sl->basact) ? sl->basact->object : NULL;
Base *base;
if (scene->obedit) {
@@ -364,23 +365,25 @@ static void stats_update(Scene *scene)
}
else {
/* Objects */
- for (base = scene->base.first; base; base = base->next)
- if (scene->lay & base->lay)
+ for (base = sl->object_bases.first; base; base = base->next)
+ if (base->flag & BASE_VISIBLED) {
stats_dupli_object(base, base->object, &stats);
+ }
}
- if (!scene->stats)
- scene->stats = MEM_callocN(sizeof(SceneStats), "SceneStats");
+ if (!sl->stats) {
+ sl->stats = MEM_callocN(sizeof(SceneStats), "SceneStats");
+ }
- *(scene->stats) = stats;
+ *(sl->stats) = stats;
}
-static void stats_string(Scene *scene)
+static void stats_string(Scene *scene, SceneLayer *sl)
{
#define MAX_INFO_MEM_LEN 64
- SceneStats *stats = scene->stats;
+ SceneStats *stats = sl->stats;
SceneStatsFmt stats_fmt;
- Object *ob = (scene->basact) ? scene->basact->object : NULL;
+ Object *ob = (sl->basact) ? sl->basact->object : NULL;
uintptr_t mem_in_use, mmap_in_use;
char memstr[MAX_INFO_MEM_LEN];
char gpumemstr[MAX_INFO_MEM_LEN] = "";
@@ -487,19 +490,20 @@ static void stats_string(Scene *scene)
#undef MAX_INFO_LEN
-void ED_info_stats_clear(Scene *scene)
+void ED_info_stats_clear(SceneLayer *sl)
{
- if (scene->stats) {
- MEM_freeN(scene->stats);
- scene->stats = NULL;
+ if (sl->stats) {
+ MEM_freeN(sl->stats);
+ sl->stats = NULL;
}
}
-const char *ED_info_stats_string(Scene *scene)
+const char *ED_info_stats_string(Scene *scene, SceneLayer *sl)
{
- if (!scene->stats)
- stats_update(scene);
- stats_string(scene);
+ if (!sl->stats) {
+ stats_update(scene, sl);
+ }
+ stats_string(scene, sl);
- return scene->stats->infostr;
+ return sl->stats->infostr;
}
diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c
index 21777fd8afa..4f042364c63 100644
--- a/source/blender/editors/space_info/space_info.c
+++ b/source/blender/editors/space_info/space_info.c
@@ -236,7 +236,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(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
// SpaceInfo *sinfo = sa->spacedata.first;
@@ -251,13 +253,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(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
case NC_SCREEN:
- if (ELEM(wmn->data, ND_SCREENCAST, ND_ANIMPLAY))
+ if (ELEM(wmn->data, ND_LAYER, ND_SCREENCAST, ND_ANIMPLAY)) {
ED_region_tag_redraw(ar);
+ }
break;
case NC_WM:
if (wmn->data == ND_JOB)
diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c
index c801a736e31..3eb0158e7b5 100644
--- a/source/blender/editors/space_info/textview.c
+++ b/source/blender/editors/space_info/textview.c
@@ -39,6 +39,8 @@
#include "BLI_utildefines.h"
#include "BLI_string_utf8.h"
+#include "GPU_immediate.h"
+
#include "BIF_gl.h"
#include "BKE_text.h"
@@ -81,9 +83,15 @@ static void console_draw_sel(const char *str, const int sel[2], const int xy[2],
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glColor4ubv(bg_sel);
- glRecti(xy[0] + (cwidth * sta), xy[1] - 2 + lheight, xy[0] + (cwidth * end), xy[1] - 2);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_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);
+
+ immUnbindProgram();
glDisable(GL_BLEND);
}
@@ -182,21 +190,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)));
- }
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_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 +222,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 +241,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);
- }
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_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 +261,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_ops.c b/source/blender/editors/space_logic/logic_ops.c
index 074368a82c5..1559515221e 100644
--- a/source/blender/editors/space_logic/logic_ops.c
+++ b/source/blender/editors/space_logic/logic_ops.c
@@ -37,6 +37,7 @@
#include "DNA_scene_types.h"
#include "BLI_blenlib.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c
index 874e54ba5e7..04790f54057 100644
--- a/source/blender/editors/space_logic/logic_window.c
+++ b/source/blender/editors/space_logic/logic_window.c
@@ -47,8 +47,8 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
-#include "BLI_path_util.h"
#include "BKE_action.h"
#include "BKE_context.h"
@@ -461,13 +461,13 @@ static void set_sca_ob(Object *ob)
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);
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(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 */
@@ -485,19 +485,12 @@ static ID **get_selected_and_linked_obs(bContext *C, short *count, short scavisf
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;
- }
+ for (base = FIRSTBASE_NEW; base; base = base->next) {
+ if ((base->flag & BASE_VISIBLED) && (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) {
diff --git a/source/blender/editors/space_logic/space_logic.c b/source/blender/editors/space_logic/space_logic.c
index 69966e9bf34..af90ef487e0 100644
--- a/source/blender/editors/space_logic/space_logic.c
+++ b/source/blender/editors/space_logic/space_logic.c
@@ -186,7 +186,9 @@ static void logic_keymap(struct wmKeyConfig *keyconf)
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))
@@ -196,7 +198,9 @@ static void logic_refresh(const bContext *UNUSED(C), ScrArea *UNUSED(sa))
}
-static void logic_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void logic_listener(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index 3243579f7d0..c774b99629c 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -502,51 +502,57 @@ static void nla_panel_modifiers(const bContext *C, Panel *pa)
void nla_buttons_register(ARegionType *art)
{
PanelType *pt;
-
+
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel animdata");
strcpy(pt->idname, "NLA_PT_animdata");
strcpy(pt->label, N_("Animation Data"));
+ strcpy(pt->category, "Animations");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_animdata;
pt->poll = nla_animdata_panel_poll;
pt->flag = PNL_DEFAULT_CLOSED;
BLI_addtail(&art->paneltypes, pt);
-
+
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel track");
strcpy(pt->idname, "NLA_PT_track");
strcpy(pt->label, N_("Active Track"));
+ strcpy(pt->category, "Animations");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_track;
pt->poll = nla_track_panel_poll;
BLI_addtail(&art->paneltypes, pt);
-
+
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties");
strcpy(pt->idname, "NLA_PT_properties");
strcpy(pt->label, N_("Active Strip"));
+ strcpy(pt->category, "Animations");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_properties;
pt->poll = nla_strip_panel_poll;
BLI_addtail(&art->paneltypes, pt);
-
+
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties");
strcpy(pt->idname, "NLA_PT_actionclip");
strcpy(pt->label, N_("Action Clip"));
+ strcpy(pt->category, "Animations");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_actclip;
pt->poll = nla_strip_actclip_panel_poll;
BLI_addtail(&art->paneltypes, pt);
-
+
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel evaluation");
strcpy(pt->idname, "NLA_PT_evaluation");
strcpy(pt->label, N_("Evaluation"));
+ strcpy(pt->category, "Animations");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_evaluation;
pt->poll = nla_strip_eval_panel_poll;
BLI_addtail(&art->paneltypes, pt);
-
+
pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel modifiers");
strcpy(pt->idname, "NLA_PT_modifiers");
strcpy(pt->label, N_("Modifiers"));
+ strcpy(pt->category, "Modifiers");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_modifiers;
pt->poll = nla_strip_eval_panel_poll;
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index 4f30c049d9d..48e822ef876 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"
@@ -125,7 +126,7 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe
{
bDopeSheet *ads = (bDopeSheet *)ac->data;
Scene *sce = (Scene *)ads->source;
- Base *base = (Base *)ale->data;
+ BaseLegacy *base = (BaseLegacy *)ale->data;
Object *ob = base->object;
AnimData *adt = ob->adt;
@@ -133,24 +134,24 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe
/* set selection status */
if (selectmode == SELECT_INVERT) {
/* swap select */
- base->flag ^= SELECT;
- ob->flag = base->flag;
+ base->flag_legacy ^= SELECT;
+ BKE_scene_base_flag_sync_from_base(base);
if (adt) adt->flag ^= ADT_UI_SELECTED;
}
else {
- Base *b;
+ BaseLegacy *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;
+ b->flag_legacy &= ~SELECT;
+ BKE_scene_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;
+ base->flag_legacy |= SELECT;
ob->flag |= SELECT;
if (adt) adt->flag |= ADT_UI_SELECTED;
}
@@ -425,7 +426,7 @@ static int nlachannels_pushdown_exec(bContext *C, wmOperator *op)
/* active animdata block */
if (nla_panel_context(C, &adt_ptr, NULL, NULL) == 0 || (adt_ptr.data == NULL)) {
BKE_report(op->reports, RPT_ERROR, "No active AnimData block to use "
- "(select a datablock expander first or set the appropriate flags on an AnimData block)");
+ "(select a data-block expander first or set the appropriate flags on an AnimData block)");
return OPERATOR_CANCELLED;
}
else {
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index 5b3c062e16d..966f24269c7 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -53,9 +53,11 @@
#include "ED_anim_api.h"
#include "ED_keyframes_draw.h"
-#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_immediate.h"
+#include "GPU_draw.h"
+
#include "WM_types.h"
#include "UI_interface.h"
@@ -97,50 +99,70 @@ 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(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);
-
- if (ELEM(NULL, act, keys.first))
+
+ if (!(act && keys.first))
return;
-
+
/* draw a darkened region behind the strips
* - 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);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos_id = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor4fv(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);
-
-
- /* get View2D scaling factor */
- UI_view2d_scale_get(v2d, &xscale, NULL);
-
- /* for now, color is hardcoded to be black */
- glColor3f(0.0f, 0.0f, 0.0f);
-
- /* 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
- */
- 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 */
+ unsigned int key_ct = 0;
+ for (ActKeyColumn *ak = keys.first; ak; ak = ak->next) {
+ key_ct++;
+ }
+
+ if (key_ct > 0) {
+ format = immVertexFormat();
+ pos_id = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int size_id = GWN_vertformat_attr_add(format, "size", GWN_COMP_F32, 1, GWN_FETCH_FLOAT);
+ unsigned int color_id = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ unsigned int outline_color_id = GWN_vertformat_attr_add(format, "outlineColor", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND);
+ GPU_enable_program_point_size();
+ immBegin(GWN_PRIM_POINTS, key_ct);
+
+ /* - 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);
+ }
+
+ immEnd();
+ GPU_disable_program_point_size();
+ immUnbindProgram();
+ }
+
/* free icons */
BLI_dlrbTree_free(&keys);
}
@@ -148,57 +170,68 @@ 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;
-
- if (ELEM(NULL, strip->act, strip->act->markers.first))
+ const bAction *act = strip->act;
+
+ if (!(act && act->markers.first))
return;
-
- for (marker = act->markers.first; marker; marker = marker->next) {
+
+ const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ if (dashed) {
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniform1i("num_colors", 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(GWN_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);
+ glLineWidth(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);
}
/* Strips (Proper) ---------------------- */
@@ -266,15 +299,12 @@ 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)
{
+ immUniformColor3f(0.7f, 0.7f, 0.7f);
+
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);
-
+
/* draw with AA'd line */
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
@@ -285,42 +315,44 @@ static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc)
float cfra;
/* plot the curve (over the strip's main region) */
- glBegin(GL_LINE_STRIP);
+ immBegin(GWN_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); // assume this to be in 0-1 range
- glVertex2f(cfra, ((y * yheight) + yminc));
+ float y = evaluate_fcurve(fcu, cfra); /* assume this to be in 0-1 range */
+ CLAMP(y, 0.0f, 1.0f);
+ 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(GWN_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);
@@ -330,11 +362,14 @@ static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc)
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];
-
+ float color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+
/* get color of strip */
nla_strip_get_color_inside(adt, strip, color);
-
+
+ uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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
*/
@@ -342,7 +377,7 @@ static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStri
/* enable transparency... */
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
-
+
switch (strip->extendmode) {
/* since this does both sides, only do the 'before' side, and leave the rest to the next case */
case NLASTRIP_EXTEND_HOLD:
@@ -351,135 +386,153 @@ 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);
}
- /* fall-through */
+ ATTR_FALLTHROUGH;
/* this only draws after the strip */
case NLASTRIP_EXTEND_HOLD_FORWARD:
/* 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);
}
-
-
+
+
/* 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(GL_POLYGON, strip->start, yminc, strip->end, ymaxc, 0.0, 0.5, 0.1);
+ UI_draw_roundbox_shade_x(true, strip->start, yminc, strip->end, ymaxc, 0.0, 0.5, 0.1, color);
+
+ /* restore current vertex format & program (roundbox trashes it) */
+ shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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);
+ immRectf(shdr_pos, strip->start, yminc, strip->end, ymaxc);
glDisable(GL_BLEND);
}
-
-
+
+
/* draw strip's control 'curves'
* - 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)
nla_strip_draw_markers(strip, yminc, ymaxc);
-
- /* draw strip outline
+
+ /* draw strip outline
* - color used here is to indicate active vs non-active
*/
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 */
- UI_draw_roundbox_shade_x(GL_LINE_LOOP, strip->start, yminc, strip->end, ymaxc, 0.0, 0.0, 0.1);
-
+ /* XXX TODO Was dashed like code below, not implemented for now so kept solid... */
+ UI_draw_roundbox_shade_x(false, strip->start, yminc, strip->end, ymaxc, 0.0, 0.0, 0.1, color);
+
+ /* restore current vertex format & program (roundbox trashes it) */
+ /* Note that we use dahsed shader here, and make it draw solid lines if not muted... */
+ shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniform1i("num_colors", 0); /* Simple dashes. */
+ immUniformColor3fv(color);
+
+ /* - line style: dotted for muted */
+ if ((nlt->flag & NLATRACK_MUTED) || (strip->flag & NLASTRIP_FLAG_MUTED)) {
+ immUniform1f("dash_width", 4.0f);
+ immUniform1f("dash_factor", 0.5f);
+ }
+ else {
+ immUniform1f("dash_factor", 2.0f); /* solid line */
+ }
+
/* 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) {
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(GWN_PRIM_LINES, 2 * (strip->repeat - 1));
+ 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;
-
+ float y = (ymaxc - yminc) * 0.5f + yminc;
+
+ immBeginAtMost(GWN_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 */
static void nla_draw_strip_text(
@@ -490,7 +543,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) {
@@ -517,12 +569,14 @@ 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);
}
@@ -535,9 +589,7 @@ static void nla_draw_strip_frames_text(NlaTrack *UNUSED(nlt), NlaStrip *strip, V
const float ytol = 1.0f; /* small offset to vertical positioning of text, for legibility */
const char col[4] = {220, 220, 220, 255}; /* light gray */
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.
@@ -545,9 +597,9 @@ static void nla_draw_strip_frames_text(NlaTrack *UNUSED(nlt), NlaStrip *strip, V
* while also preserving some accuracy, since we do use floats
*/
/* start frame */
- numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.1f", strip->start);
+ size_t numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.1f", strip->start);
UI_view2d_text_cache_add(v2d, strip->start - 1.0f, ymaxc + ytol, numstr, numstr_len, col);
-
+
/* end frame */
numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.1f", strip->end);
UI_view2d_text_cache_add(v2d, strip->end, ymaxc + ytol, numstr, numstr_len, col);
@@ -557,20 +609,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
@@ -578,16 +624,16 @@ 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));
@@ -601,11 +647,10 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar)
{
AnimData *adt = ale->adt;
NlaTrack *nlt = (NlaTrack *)ale->data;
- NlaStrip *strip;
- int index;
/* draw each strip in the track (if visible) */
- for (strip = nlt->strips.first, index = 1; strip; strip = strip->next, index++) {
+ int index = 1;
+ for (NlaStrip *strip = nlt->strips.first; strip; strip = strip->next, index++) {
if (BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) {
const float xminc = strip->start + text_margin_x;
const float xmaxc = strip->end + text_margin_x;
@@ -630,45 +675,60 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar)
case ANIMTYPE_NLAACTION:
{
AnimData *adt = ale->adt;
- float color[4];
-
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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);
-
+
/* 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);
-
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.3f);
+ immBegin(GWN_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);
-
+ immUniformColor3f(0.0f, 0.0f, 0.0f);
+ immBegin(GWN_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(adt, ale->data, y, yminc + NLACHANNEL_SKIP, ymaxc - NLACHANNEL_SKIP);
+
glDisable(GL_BLEND);
break;
}
}
}
-
+
/* adjust y-position for next one */
y -= NLACHANNEL_STEP(snla);
}
@@ -684,17 +744,14 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
- int filter;
SpaceNla *snla = (SpaceNla *)ac->sl;
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);
- 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);
/* 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
@@ -702,7 +759,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)
*/
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index 3e7e8ccc3f4..1f298373a80 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -605,8 +605,8 @@ static int nlaedit_add_actionclip_exec(bContext *C, wmOperator *op)
else if (act->idroot == 0) {
/* hopefully in this case (i.e. library of userless actions), the user knows what they're doing... */
BKE_reportf(op->reports, RPT_WARNING,
- "Action '%s' does not specify what datablocks it can be used on "
- "(try setting the 'ID Root Type' setting from the Datablocks Editor "
+ "Action '%s' does not specify what data-blocks it can be used on "
+ "(try setting the 'ID Root Type' setting from the data-blocks editor "
"for this action to avoid future problems)",
act->id.name + 2);
}
diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c
index 386950ead3a..48037a10b2d 100644
--- a/source/blender/editors/space_nla/nla_ops.c
+++ b/source/blender/editors/space_nla/nla_ops.c
@@ -242,7 +242,9 @@ static void nla_keymap_main(wmKeyConfig *keyconf, wmKeyMap *keymap)
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);
diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c
index 3b5604087b9..ab7a913ce62 100644
--- a/source/blender/editors/space_nla/space_nla.c
+++ b/source/blender/editors/space_nla/space_nla.c
@@ -353,7 +353,9 @@ static void nla_buttons_region_draw(const bContext *C, ARegion *ar)
ED_region_panels(C, ar, NULL, -1, true);
}
-static void nla_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void nla_region_listener(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -386,7 +388,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(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -424,6 +428,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 +440,9 @@ 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_channel_region_listener(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -466,7 +477,7 @@ static void nla_channel_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa)
}
/* editor level listener */
-static void nla_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
+static void nla_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt
index cde818333e4..77b1351435b 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_manipulators.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 7b08b8368ba..bee2379cd81 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -50,9 +50,12 @@
#include "BLF_api.h"
#include "BLT_translation.h"
-#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_draw.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
@@ -62,6 +65,7 @@
#include "WM_types.h"
#include "UI_resources.h"
+#include "UI_view2d.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
@@ -80,49 +84,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)
@@ -392,6 +353,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 +362,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 +428,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,40 +438,32 @@ 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);
-
- glDisable(GL_LINE_SMOOTH);
- glDisable(GL_BLEND);
+ UI_GetThemeColorShadeAlpha4fv(TH_SELECT, 0, -40, color);
+
+ UI_draw_roundbox_aa(false, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD, color);
}
-
+
/* label */
node_draw_frame_label(ntree, node, snode->aspect);
@@ -580,15 +535,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,23 +551,26 @@ 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);
/* 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);
@@ -637,9 +589,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_circle_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);
@@ -798,7 +748,7 @@ static void node_shader_buts_geometry(uiLayout *layout, bContext *C, PointerRNA
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, "uv_layer", &dataptr, "uv_layers", "", ICON_NONE);
uiItemPointerR(col, ptr, "color_layer", &dataptr, "vertex_colors", "", ICON_NONE);
}
else {
@@ -1016,7 +966,7 @@ static void node_shader_buts_uvmap(uiLayout *layout, bContext *C, PointerRNA *pt
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);
}
}
}
@@ -1035,7 +985,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);
@@ -1057,7 +1007,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);
@@ -1234,6 +1184,7 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_BSDF_GLOSSY:
case SH_NODE_BSDF_GLASS:
case SH_NODE_BSDF_REFRACTION:
+ case SH_NODE_BSDF_PRINCIPLED:
ntype->draw_buttons = node_shader_buts_glossy;
break;
case SH_NODE_BSDF_ANISOTROPIC:
@@ -1320,9 +1271,6 @@ static void node_composit_buts_renderlayers(uiLayout *layout, bContext *C, Point
PropertyRNA *prop;
const char *layer_name;
char scene_name[MAX_ID_NAME - 2];
- wmOperatorType *ot = WM_operatortype_find("RENDER_OT_render", 1);
-
- BLI_assert(ot != 0);
uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL);
@@ -1339,11 +1287,9 @@ static void node_composit_buts_renderlayers(uiLayout *layout, bContext *C, Point
scn_ptr = RNA_pointer_get(ptr, "scene");
RNA_string_get(&scn_ptr, "name", scene_name);
- WM_operator_properties_create_ptr(&op_ptr, ot);
+ op_ptr = uiItemFullO(row, "RENDER_OT_render", "", ICON_RENDER_STILL, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&op_ptr, "layer", layer_name);
RNA_string_set(&op_ptr, "scene", scene_name);
- uiItemFullO_ptr(row, ot, "", ICON_RENDER_STILL, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
-
}
@@ -1629,17 +1575,6 @@ static void node_composit_buts_zcombine(uiLayout *layout, bContext *UNUSED(C), P
uiItemR(col, ptr, "use_antialias_z", 0, NULL, ICON_NONE);
}
-
-static void node_composit_buts_hue_sat(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "color_hue", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "color_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "color_value", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
-}
-
static void node_composit_buts_dilateerode(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
@@ -1803,6 +1738,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
Scene *scene = CTX_data_scene(C);
PointerRNA imfptr = RNA_pointer_get(ptr, "format");
PointerRNA active_input_ptr, op_ptr;
+ wmOperatorType *ot;
uiLayout *row, *col;
int active_index;
const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
@@ -1841,11 +1777,10 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
active_input_ptr.id.data = ptr->id.data;
col = uiLayoutColumn(row, true);
- op_ptr = uiItemFullO(col, "NODE_OT_output_file_move_active_socket", "",
- ICON_TRIA_UP, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ ot = WM_operatortype_find("NODE_OT_output_file_move_active_socket", false);
+ op_ptr = uiItemFullO_ptr(col, ot, "", ICON_TRIA_UP, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&op_ptr, "direction", 1);
- op_ptr = uiItemFullO(col, "NODE_OT_output_file_move_active_socket", "",
- ICON_TRIA_DOWN, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ op_ptr = uiItemFullO_ptr(col, ot, "", ICON_TRIA_DOWN, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&op_ptr, "direction", 2);
if (active_input_ptr.data) {
@@ -2177,14 +2112,7 @@ static void node_composit_buts_switch(uiLayout *layout, bContext *UNUSED(C), Poi
static void node_composit_buts_switch_view_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *UNUSED(ptr))
{
- PointerRNA op_ptr;
- wmOperatorType *ot = WM_operatortype_find("NODE_OT_switch_view_update", 1);
-
- BLI_assert(ot != 0);
-
- WM_operator_properties_create_ptr(&op_ptr, ot);
-
- uiItemFullO_ptr(layout, ot, "Update Views", ICON_FILE_REFRESH, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
+ uiItemFullO(layout, "NODE_OT_switch_view_update", "Update Views", ICON_FILE_REFRESH, NULL, WM_OP_INVOKE_DEFAULT, 0);
}
static void node_composit_buts_boxmask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -2229,14 +2157,21 @@ static void node_composit_backdrop_viewer(SpaceNode *snode, ImBuf *backdrop, bNo
const float cx = x + snode->zoom * backdropWidth * node->custom3;
const float cy = y + snode->zoom * backdropHeight * node->custom4;
- glColor3f(1.0, 1.0, 1.0);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
- glBegin(GL_LINES);
- glVertex2f(cx - 25, cy - 25);
- glVertex2f(cx + 25, cy + 25);
- glVertex2f(cx + 25, cy - 25);
- glVertex2f(cx - 25, cy + 25);
- glEnd();
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor3f(1.0f, 1.0f, 1.0f);
+
+ immBegin(GWN_PRIM_LINES, 4);
+ immVertex2f(pos, cx - 25, cy - 25);
+ immVertex2f(pos, cx + 25, cy + 25);
+ immVertex2f(pos, cx + 25, cy - 25);
+ immVertex2f(pos, cx - 25, cy + 25);
+ immEnd();
+
+ immUnbindProgram();
}
}
@@ -2255,9 +2190,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;
@@ -2270,12 +2202,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();
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor3f(1.0f, 1.0f, 1.0f);
+
+ immBegin(GWN_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)
@@ -2293,9 +2234,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;
@@ -2308,13 +2246,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);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
- glVertex2f(x1, y1);
- glVertex2f(x2, y2);
- glVertex2f(x3, y3);
- glVertex2f(x4, y4);
- glEnd();
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor3f(1.0f, 1.0f, 1.0f);
+
+ immBegin(GWN_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_buts_ellipsemask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -2500,6 +2446,11 @@ static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), P
uiItemR(layout, ptr, "ray_length", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
+static void node_composit_buts_brightcontrast(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "use_premultiply", 0, NULL, ICON_NONE);
+}
+
/* only once called */
static void node_composit_set_butfunc(bNodeType *ntype)
{
@@ -2580,9 +2531,6 @@ static void node_composit_set_butfunc(bNodeType *ntype)
case CMP_NODE_ALPHAOVER:
ntype->draw_buttons = node_composit_buts_alphaover;
break;
- case CMP_NODE_HUE_SAT:
- ntype->draw_buttons = node_composit_buts_hue_sat;
- break;
case CMP_NODE_TEXTURE:
ntype->draw_buttons = node_buts_texture;
break;
@@ -2730,6 +2678,8 @@ static void node_composit_set_butfunc(bNodeType *ntype)
case CMP_NODE_SUNBEAMS:
ntype->draw_buttons = node_composit_buts_sunbeams;
break;
+ case CMP_NODE_BRIGHTCONTRAST:
+ ntype->draw_buttons = node_composit_buts_brightcontrast;
}
}
@@ -3101,7 +3051,7 @@ static void std_node_socket_draw(bContext *C, uiLayout *layout, PointerRNA *ptr,
node_file_output_socket_draw(C, layout, ptr, node_ptr);
return;
}
-
+
if ((sock->in_out == SOCK_OUT) || (sock->flag & SOCK_IN_USE) || (sock->flag & SOCK_HIDE_VALUE)) {
node_socket_button_label(C, layout, ptr, node_ptr, text);
return;
@@ -3216,6 +3166,7 @@ void ED_init_node_socket_type_virtual(bNodeSocketType *stype)
void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeInstanceKey parent_key)
{
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;
@@ -3230,12 +3181,10 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, b
ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
if (ibuf) {
float x, y;
-
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
-
+
+ gpuPushProjectionMatrix();
+ gpuPushMatrix();
+
/* somehow the offset has to be calculated inverse */
glaDefine2DArea(&ar->winrct);
@@ -3248,60 +3197,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));
-
- glPixelZoom(1.0f, 1.0f);
- }
- else if (snode->flag & SNODE_SHOW_ALPHA) {
- display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, &cache_handle);
-
- 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);
-
-#ifdef __BIG_ENDIAN__
- glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
-#endif
- glPixelZoom(1.0f, 1.0f);
+
+ 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;
+
+ 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);
+
+ immDrawPixelsTex(&state, x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST,
+ display_buffer, snode->zoom, snode->zoom, NULL);
+
+ 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);
-
- 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);
+
glDisable(GL_BLEND);
}
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)
@@ -3326,20 +3252,24 @@ 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);
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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();
+
+ gpuPopProjectionMatrix();
+ gpuPopMatrix();
}
BKE_image_release_ibuf(ima, ibuf, lock);
@@ -3450,8 +3380,8 @@ void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link,
/* store current linewidth */
float linew;
float arrow[2], arrow1[2], arrow2[2];
- const float px_fac = UI_DPI_WINDOW_FAC;
glGetFloatv(GL_LINE_WIDTH, &linew);
+ unsigned int pos;
/* we can reuse the dist variable here to increment the GL curve eval amount*/
dist = 1.0f / (float)LINK_RESOL;
@@ -3475,141 +3405,89 @@ void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link,
arrow[0] = coord_array[LINK_ARROW][0];
arrow[1] = coord_array[LINK_ARROW][1];
}
+
+ if (do_triple || drawarrow || (!do_shaded)) {
+ pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ }
+
if (do_triple) {
- UI_ThemeColorShadeAlpha(th_col3, -80, -120);
- glLineWidth(4.0f * px_fac);
-
- glBegin(GL_LINE_STRIP);
+ immUniformThemeColorShadeAlpha(th_col3, -80, -120);
+ glLineWidth(4.0f);
+
+ immBegin(GWN_PRIM_LINE_STRIP, (LINK_RESOL + 1));
+
for (i = 0; i <= LINK_RESOL; i++) {
- glVertex2fv(coord_array[i]);
+ immVertex2fv(pos, coord_array[i]);
}
- glEnd();
+
+ immEnd();
+
if (drawarrow) {
- glBegin(GL_LINE_STRIP);
- glVertex2fv(arrow1);
- glVertex2fv(arrow);
- glVertex2fv(arrow2);
- glEnd();
+ immBegin(GWN_PRIM_LINE_STRIP, 3);
+ immVertex2fv(pos, arrow1);
+ immVertex2fv(pos, arrow);
+ immVertex2fv(pos, arrow2);
+ immEnd();
}
}
-
- /* 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 * px_fac);
- 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();
+
+ glLineWidth(1.5f);
+
+ if (drawarrow) {
+ immUniformThemeColorBlend(th_col1, th_col2, 0.5f);
+
+ immBegin(GWN_PRIM_LINE_STRIP, 3);
+ immVertex2fv(pos, arrow1);
+ immVertex2fv(pos, arrow);
+ immVertex2fv(pos, arrow2);
+ immEnd();
}
- else {
- UI_ThemeColor(th_col1);
- glBegin(GL_LINE_STRIP);
+
+ if (!do_shaded) {
+ immUniformThemeColor(th_col1);
+
+ immBegin(GWN_PRIM_LINE_STRIP, (LINK_RESOL + 1));
+
for (i = 0; i <= LINK_RESOL; i++) {
- glVertex2fv(coord_array[i]);
+ immVertex2fv(pos, coord_array[i]);
}
- glEnd();
+
+ immEnd();
}
-
- if (drawarrow) {
- glBegin(GL_LINE_STRIP);
- glVertex2fv(arrow1);
- glVertex2fv(arrow);
- glVertex2fv(arrow2);
- glEnd();
+
+ if (do_triple || drawarrow || (!do_shaded)) {
+ immUnbindProgram();
}
-
- glDisable(GL_LINE_SMOOTH);
- }
-}
-#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])
-{
- 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;
- }
-}
+ if (do_shaded) {
+ unsigned char col[3];
-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)
-{
- float coord_array[2][2];
- int i;
-
- node_link_straight_points(v2d, snode, link, coord_array);
-
- glEnable(GL_LINE_SMOOTH);
-
- if (do_triple) {
- UI_ThemeColorShadeAlpha(th_col3, -80, -120);
- glLineWidth(4.0f);
-
- glBegin(GL_LINES);
- glVertex2fv(coord_array[0]);
- glVertex2fv(coord_array[1]);
- glEnd();
- }
-
- UI_ThemeColor(th_col1);
- glLineWidth(1.5f);
-
- /* 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]);
- }
- 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]);
+ Gwn_VertFormat *format = immVertexFormat();
+ pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+
+ immBegin(GWN_PRIM_LINE_STRIP, (LINK_RESOL + 1));
+
+ for (i = 0; i <= LINK_RESOL; i++) {
+ UI_GetThemeColorBlend3ubv(th_col1, th_col2, spline_step, col);
+ immAttrib3ubv(color, col);
+
+ immVertex2fv(pos, coord_array[i]);
+
+ spline_step += dist;
+ }
+
+ immEnd();
+
+ immUnbindProgram();
}
- glEnd();
+
+ glDisable(GL_LINE_SMOOTH);
}
-
- 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)
@@ -3632,7 +3510,7 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link)
return;
if (link->fromsock->flag & SOCK_UNAVAIL)
return;
-
+
if (link->flag & NODE_LINK_VALID) {
/* special indicated link, on drop-node */
if (link->flag & NODE_LINKFLAG_HILITE) {
@@ -3652,32 +3530,32 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link)
th_col1 = TH_REDALERT;
}
}
-
+
node_draw_link_bezier(v2d, snode, link, th_col1, do_shaded, th_col2, do_triple, 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(GWN_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 b50df02beae..dc6b06790e0 100644
--- a/source/blender/editors/space_node/node_add.c
+++ b/source/blender/editors/space_node/node_add.c
@@ -44,6 +44,8 @@
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_texture.h"
#include "ED_node.h" /* own include */
#include "ED_screen.h"
@@ -105,13 +107,15 @@ static bool add_reroute_intersect_check(bNodeLink *link, float mcoords[][2], int
if (node_link_bezier_points(NULL, NULL, link, coord_array, NODE_LINK_RESOL)) {
- for (i = 0; i < tot - 1; i++)
- for (b = 0; b < NODE_LINK_RESOL; b++)
+ for (i = 0; i < tot - 1; i++) {
+ for (b = 0; b < NODE_LINK_RESOL; b++) {
if (isect_seg_seg_v2(mcoords[i], mcoords[i + 1], coord_array[b], coord_array[b + 1]) > 0) {
result[0] = (mcoords[i][0] + mcoords[i + 1][0]) / 2.0f;
result[1] = (mcoords[i][1] + mcoords[i + 1][1]) / 2.0f;
return 1;
}
+ }
+ }
}
return 0;
}
@@ -312,7 +316,10 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
switch (snode->nodetree->type) {
case NTREE_SHADER:
- type = SH_NODE_TEX_IMAGE;
+ if (BKE_scene_use_new_shading_nodes(CTX_data_scene(C)))
+ type = SH_NODE_TEX_IMAGE;
+ else
+ type = SH_NODE_TEXTURE;
break;
case NTREE_TEXTURE:
type = TEX_NODE_IMAGE;
@@ -333,7 +340,14 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- node->id = (ID *)ima;
+ 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;
/* When adding new image file via drag-drop we need to load imbuf in order
* to get proper image source.
@@ -382,7 +396,7 @@ void NODE_OT_add_file(wmOperatorType *ot)
WM_operator_properties_filesel(
ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
- RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Datablock name to assign");
+ RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
}
/* ****************** Add Mask Node Operator ******************* */
@@ -441,7 +455,7 @@ void NODE_OT_add_mask(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
- RNA_def_string(ot->srna, "name", "Mask", MAX_ID_NAME - 2, "Name", "Datablock name to assign");
+ RNA_def_string(ot->srna, "name", "Mask", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
}
/********************** New node tree operator *********************/
diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c
index f0567924edd..925298451ce 100644
--- a/source/blender/editors/space_node/node_buttons.c
+++ b/source/blender/editors/space_node/node_buttons.c
@@ -133,6 +133,7 @@ static void node_tree_interface_panel(const bContext *C, Panel *pa)
int in_out;
uiLayout *layout = pa->layout, *row, *split, *col;
PointerRNA ptr, sockptr, opptr;
+ wmOperatorType *ot;
if (!ntree)
return;
@@ -146,23 +147,25 @@ static void node_tree_interface_panel(const bContext *C, Panel *pa)
split = uiLayoutRow(row, true);
col = uiLayoutColumn(split, true);
+ 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);
- opptr = uiItemFullO(col, "NODE_OT_tree_socket_add", "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ opptr = uiItemFullO_ptr(col, ot, "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
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);
- opptr = uiItemFullO(col, "NODE_OT_tree_socket_add", "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ opptr = uiItemFullO_ptr(col, ot, "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&opptr, "in_out", SOCK_OUT);
+ ot = WM_operatortype_find("NODE_OT_tree_socket_move", false);
col = uiLayoutColumn(row, true);
- opptr = uiItemFullO(col, "NODE_OT_tree_socket_move", "", ICON_TRIA_UP, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ opptr = uiItemFullO_ptr(col, ot, "", ICON_TRIA_UP, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&opptr, "direction", 1);
- opptr = uiItemFullO(col, "NODE_OT_tree_socket_move", "", ICON_TRIA_DOWN, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ opptr = uiItemFullO_ptr(col, ot, "", ICON_TRIA_DOWN, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&opptr, "direction", 2);
if (sock) {
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index d9c51e427c8..d99d1c97653 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -44,16 +44,21 @@
#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 "WM_api.h"
#include "WM_types.h"
@@ -128,10 +133,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 +149,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);
}
}
@@ -617,60 +622,16 @@ static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node)
glDisable(GL_LINE_SMOOTH);
}
-/* this might have some more generic use */
-static void node_circle_draw(float x, float y, float size, const float col[4], int highlight)
+static void node_socket_circle_draw(const bContext *C, bNodeTree *ntree, PointerRNA node_ptr, bNodeSocket *sock, unsigned pos, unsigned col)
{
- /* 16 values of sin function */
- static const 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 const 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;
-
- glColor4fv(col);
-
- glEnable(GL_BLEND);
- glBegin(GL_POLYGON);
- for (a = 0; a < 16; a++)
- glVertex2f(x + size * si[a], y + size * co[a]);
- 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 < 16; a++)
- glVertex2f(x + size * si[a], y + size * co[a]);
- glEnd();
- glDisable(GL_LINE_SMOOTH);
- glDisable(GL_BLEND);
-}
-
-void node_socket_circle_draw(const bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *sock, float size, int 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);
- node_circle_draw(sock->locx, sock->locy, size, color, highlight);
+
+ immAttrib4fv(col, color);
+ immVertex2f(pos, sock->locx, sock->locy);
}
/* ************** Socket callbacks *********** */
@@ -679,10 +640,15 @@ static void node_draw_preview_background(float tile, rctf *rect)
{
float x, y;
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_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) {
@@ -693,7 +659,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) {
@@ -705,9 +671,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 */
@@ -740,15 +707,17 @@ static void node_draw_preview(bNodePreview *preview, rctf *prv)
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_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);
- UI_ThemeColorShadeAlpha(TH_BACK, -15, +100);
- fdrawbox(draw_rect.xmin, draw_rect.ymin, draw_rect.xmax, draw_rect.ymax);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShadeAlpha(TH_BACK, -15, +100);
+ imm_draw_line_box(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 */
@@ -773,23 +742,134 @@ 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 unsigned int total_input_ct = BLI_listbase_count(&node->inputs);
+ const unsigned int total_output_ct = BLI_listbase_count(&node->outputs);
+
+ if (total_input_ct + total_output_ct == 0) {
+ return;
+ }
+
+ PointerRNA node_ptr;
+ RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
+
+ float scale;
+ UI_view2d_scale_get(v2d, &scale, NULL);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int col = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 4, GWN_FETCH_FLOAT);
+
+ glEnable(GL_BLEND);
+ 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(GWN_PRIM_POINTS, total_input_ct + total_output_ct);
+ }
+
+ /* socket inputs */
+ short selected_input_ct = 0;
+ bNodeSocket *sock;
+ for (sock = node->inputs.first; sock; sock = sock->next) {
+ if (nodeSocketIsHidden(sock))
+ continue;
+ if (select_all || (sock->flag & SELECT)) {
+ ++selected_input_ct;
+ continue;
+ }
+
+ node_socket_circle_draw(C, ntree, node_ptr, sock, pos, col);
+ }
+
+ /* socket outputs */
+ short selected_output_ct = 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_ct;
+ 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_ct + selected_output_ct > 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(GWN_PRIM_POINTS, selected_input_ct + selected_output_ct);
+
+ if (selected_input_ct) {
+ /* 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_ct == 0)
+ break; /* stop as soon as last one is drawn */
+ }
+ }
+ }
+
+ if (selected_output_ct) {
+ /* 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_ct == 0)
+ break; /* stop as soon as last one is drawn */
+ }
+ }
+ }
+
+ immEnd();
+ }
+
+ immUnbindProgram();
+
+ GPU_disable_program_point_size();
+ glDisable(GL_BLEND);
+}
+
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;
@@ -798,7 +878,7 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN
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;
@@ -807,31 +887,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
- UI_ThemeColor(color_id);
-
- if (node->flag & NODE_MUTED)
- UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f);
-
-
-#ifdef WITH_COMPOSITOR
- if (ntree->type == NTREE_COMPOSIT && (snode->flag & SNODE_SHOW_HIGHLIGHT)) {
- if (COM_isHighlightedbNode(node)) {
- UI_ThemeColorBlend(color_id, TH_ACTIVE, 0.5f);
+ 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);
}
}
-#endif
glLineWidth(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;
@@ -864,10 +937,12 @@ 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? */
{
@@ -882,17 +957,9 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN
UI_block_emboss_set(node->block, UI_EMBOSS);
/* 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.5f * U.widget_unit, rct->ymax - NODE_DY / 2.0f, '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)
@@ -905,55 +972,30 @@ 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_circle_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_circle_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) {
bNodePreview *preview = BKE_node_instance_hash_lookup(previews, key);
@@ -973,47 +1015,33 @@ 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);
-
-#ifdef WITH_COMPOSITOR
- if (ntree->type == NTREE_COMPOSIT && (snode->flag & SNODE_SHOW_HIGHLIGHT)) {
- if (COM_isHighlightedbNode(node)) {
- UI_ThemeColorBlend(color_id, TH_ACTIVE, 0.5f);
- }
- }
-#else
- (void)ntree;
-#endif
+ 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);
-
- 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_GetThemeColorShadeAlpha4fv((node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, 0, -40, color);
+
+ UI_draw_roundbox_aa(false, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad, color);
}
/* custom color inline */
@@ -1021,18 +1049,19 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
- 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);
}
/* 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 */
{
@@ -1047,18 +1076,13 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b
UI_block_emboss_set(node->block, UI_EMBOSS);
/* 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));
@@ -1072,27 +1096,35 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b
}
/* scale widget thing */
- UI_ThemeColorShade(color_id, -10);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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(GWN_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_circle_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT);
- }
-
- for (sock = node->outputs.first; sock; sock = sock->next) {
- if (!nodeSocketIsHidden(sock))
- node_socket_circle_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT);
- }
-
+ immBegin(GWN_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();
+
+ immUnbindProgram();
+
+ node_draw_sockets(v2d, C, ntree, node, true, false);
+
UI_block_end(C, node->block);
UI_block_draw(C, node->block);
node->block = NULL;
@@ -1233,7 +1265,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));
}
@@ -1253,15 +1285,9 @@ static void snode_setup_v2d(SpaceNode *snode, ARegion *ar, const float center[2]
static void draw_nodetree(const bContext *C, ARegion *ar, bNodeTree *ntree, bNodeInstanceKey parent_key)
{
SpaceNode *snode = CTX_wm_space_node(C);
-
+
node_uiblocks_init(C, ntree);
-
-#ifdef WITH_COMPOSITOR
- if (ntree->type == NTREE_COMPOSIT) {
- COM_startReadHighlights();
- }
-#endif
-
+
node_update_nodetree(C, ntree);
node_draw_nodetree(C, ar, snode, ntree, parent_key);
}
@@ -1272,12 +1298,14 @@ 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);
+
+ 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);
+ UI_draw_roundbox_4fv(true, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 0, color);
glDisable(GL_BLEND);
/* set the block bounds to clip mouse events from underlying nodes */
@@ -1309,7 +1337,6 @@ void drawnodespace(const bContext *C, ARegion *ar)
/* only set once */
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_MAP1_VERTEX_3);
/* nodes */
snode_set_context(C);
@@ -1327,8 +1354,10 @@ void drawnodespace(const bContext *C, ARegion *ar)
path = snode->treepath.last;
/* update tree path name (drawn in the bottom left) */
- if (snode->id && UNLIKELY(!STREQ(path->node_name, snode->id->name + 2))) {
- BLI_strncpy(path->node_name, snode->id->name + 2, sizeof(path->node_name));
+ ID *name_id = (path->nodetree && path->nodetree != snode->nodetree) ? &path->nodetree->id : snode->id;
+
+ if (name_id && UNLIKELY(!STREQ(path->node_name, name_id->name + 2))) {
+ BLI_strncpy(path->node_name, name_id->name + 2, sizeof(path->node_name));
}
/* current View2D center, will be set temporarily for parent node trees */
@@ -1367,7 +1396,23 @@ void drawnodespace(const bContext *C, ARegion *ar)
/* backdrop */
draw_nodespace_back_pix(C, ar, snode, path->parent_key);
-
+
+ {
+ float original_proj[4][4];
+ gpuGetProjectionMatrix(original_proj);
+
+ gpuPushMatrix();
+ gpuLoadIdentity();
+
+ glaDefine2DArea(&ar->winrct);
+ wmOrtho2_pixelspace(ar->winx, ar->winy);
+
+ WM_manipulatormap_draw(ar->manipulator_map, C, WM_MANIPULATORMAP_DRAWSTEP_2D);
+
+ gpuPopMatrix();
+ gpuLoadProjectionMatrix(original_proj);
+ }
+
draw_nodetree(C, ar, ntree, path->parent_key);
}
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index ffe510016ff..33382af9087 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"
@@ -123,7 +124,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) {
@@ -328,11 +329,11 @@ void snode_dag_update(bContext *C, SpaceNode *snode)
if (snode->edittree != snode->nodetree) {
FOREACH_NODETREE(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)
@@ -397,7 +398,11 @@ 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)) {
+ if (BKE_scene_uses_blender_eevee(scene)) {
+ output_type = SH_NODE_OUTPUT_EEVEE_MATERIAL;
+ shader_type = SH_NODE_EEVEE_METALLIC;
+ }
+ else if (BKE_scene_use_new_shading_nodes(scene)) {
output_type = SH_NODE_OUTPUT_MATERIAL;
shader_type = SH_NODE_BSDF_DIFFUSE;
}
@@ -505,8 +510,6 @@ void ED_node_composit_default(const bContext *C, struct Scene *sce)
nodeAddLink(sce->nodetree, in, fromsock, out, tosock);
ntreeUpdateTree(CTX_data_main(C), sce->nodetree);
-
- // XXX ntreeCompositForceHidden(sce->nodetree);
}
/* assumes nothing being done in ntree yet, sets the default in/out node */
@@ -582,17 +585,11 @@ void snode_set_context(const bContext *C)
}
}
- if (snode->nodetree != ntree || snode->id != id || snode->from != from) {
+ if (snode->nodetree != ntree || snode->id != id || snode->from != from ||
+ (snode->treepath.last == NULL && ntree))
+ {
ED_node_tree_start(snode, ntree, id, from);
}
-
- /* XXX Legacy hack to update render layer node outputs.
- * This should be handled by the depsgraph eventually ...
- */
- if (ED_node_is_compositor(snode) && snode->nodetree) {
- /* update output sockets based on available layers */
- ntreeCompositForceHidden(snode->nodetree);
- }
}
void snode_update(SpaceNode *snode, bNode *node)
@@ -1069,12 +1066,9 @@ int node_find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **so
/* check if we click in a socket */
for (node = snode->edittree->nodes.first; node; node = node->next) {
-
- rect.xmin = cursor[0] - (NODE_SOCKSIZE + 4);
- rect.ymin = cursor[1] - (NODE_SOCKSIZE + 4);
- rect.xmax = cursor[0] + (NODE_SOCKSIZE + 4);
- rect.ymax = cursor[1] + (NODE_SOCKSIZE + 4);
-
+
+ BLI_rctf_init_pt_radius(&rect, cursor, NODE_SOCKSIZE + 4);
+
if (!(node->flag & NODE_HIDDEN)) {
/* extra padding inside and out - allow dragging on the text areas too */
if (in_out == SOCK_IN) {
@@ -2097,7 +2091,7 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
/* make sure all clipboard nodes would be valid in the target tree */
all_nodes_valid = true;
for (node = clipboard_nodes_lb->first; node; node = node->next) {
- if (!node->typeinfo->poll_instance(node, ntree)) {
+ if (!node->typeinfo->poll_instance || !node->typeinfo->poll_instance(node, ntree)) {
all_nodes_valid = false;
BKE_reportf(op->reports, RPT_ERROR, "Cannot add node %s into node tree %s", node->name, ntree->id.name + 2);
}
diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c
index 26eeaa91dd0..914f8ffbe10 100644
--- a/source/blender/editors/space_node/node_group.c
+++ b/source/blender/editors/space_node/node_group.c
@@ -92,9 +92,9 @@ static int node_group_operator_editable(bContext *C)
* Disabled otherwise to allow pynodes define their own operators
* with same keymap.
*/
- if (STREQ(snode->tree_idname, "ShaderNodeTree") ||
- STREQ(snode->tree_idname, "CompositorNodeTree") ||
- STREQ(snode->tree_idname, "TextureNodeTree"))
+ if (ED_node_is_shader(snode) ||
+ ED_node_is_compositor(snode) ||
+ ED_node_is_texture(snode))
{
return true;
}
@@ -112,11 +112,11 @@ static const char *group_node_idname(bContext *C)
{
SpaceNode *snode = CTX_wm_space_node(C);
- if (STREQ(snode->tree_idname, "ShaderNodeTree"))
+ if (ED_node_is_shader(snode))
return "ShaderNodeGroup";
- else if (STREQ(snode->tree_idname, "CompositorNodeTree"))
+ else if (ED_node_is_compositor(snode))
return "CompositorNodeGroup";
- else if (STREQ(snode->tree_idname, "TextureNodeTree"))
+ else if (ED_node_is_texture(snode))
return "TextureNodeGroup";
return "";
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index 6b8fa0b88fe..b425a92f601 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -67,12 +67,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_circle_draw(const struct bContext *C, struct bNodeTree *ntree, struct bNode *node,
- struct bNodeSocket *sock, float size, int 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);
@@ -220,6 +219,10 @@ 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_WGT_backdrop_transform(struct wmManipulatorGroupType *wgt);
+
+
extern const char *node_context_dir[];
// XXXXXX
diff --git a/source/blender/editors/space_node/node_manipulators.c b/source/blender/editors/space_node/node_manipulators.c
new file mode 100644
index 00000000000..8b4ebd70874
--- /dev/null
+++ b/source/blender/editors/space_node/node_manipulators.c
@@ -0,0 +1,119 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_manipulators.c
+ * \ingroup spnode
+ */
+
+#include "BKE_context.h"
+#include "BKE_image.h"
+
+#include "ED_screen.h"
+#include "ED_manipulator_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"
+
+
+static bool WIDGETGROUP_node_transform_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt))
+{
+ 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 && node->type == CMP_NODE_VIEWER) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void WIDGETGROUP_node_transform_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup)
+{
+ wmManipulatorWrapper *wwrapper = MEM_mallocN(sizeof(wmManipulatorWrapper), __func__);
+
+ wwrapper->manipulator = WM_manipulator_new("MANIPULATOR_WT_cage_2d", mgroup, "backdrop_cage", NULL);
+
+ RNA_enum_set(wwrapper->manipulator->ptr, "transform",
+ ED_MANIPULATOR_RECT_TRANSFORM_FLAG_TRANSLATE | ED_MANIPULATOR_RECT_TRANSFORM_FLAG_SCALE_UNIFORM);
+
+ mgroup->customdata = wwrapper;
+}
+
+static void WIDGETGROUP_node_transform_refresh(const bContext *C, wmManipulatorGroup *mgroup)
+{
+ wmManipulator *cage = ((wmManipulatorWrapper *)mgroup->customdata)->manipulator;
+ 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(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_manipulator_set_matrix_location(cage, origin);
+ WM_manipulator_set_flag(cage, WM_MANIPULATOR_HIDDEN, false);
+
+ /* need to set property here for undo. TODO would prefer to do this in _init */
+ SpaceNode *snode = CTX_wm_space_node(C);
+ PointerRNA nodeptr;
+ RNA_pointer_create(snode->id, &RNA_SpaceNodeEditor, snode, &nodeptr);
+ WM_manipulator_target_property_def_rna(cage, "offset", &nodeptr, "backdrop_offset", -1);
+ WM_manipulator_target_property_def_rna(cage, "scale", &nodeptr, "backdrop_zoom", -1);
+ }
+ else {
+ WM_manipulator_set_flag(cage, WM_MANIPULATOR_HIDDEN, true);
+ }
+
+ BKE_image_release_ibuf(ima, ibuf, lock);
+}
+
+void NODE_WGT_backdrop_transform(wmManipulatorGroupType *wgt)
+{
+ wgt->name = "Backdrop Transform Widgets";
+ wgt->idname = "NODE_WGT_backdrop_transform";
+
+ wgt->flag |= WM_MANIPULATORGROUPTYPE_PERSISTENT;
+
+ wgt->poll = WIDGETGROUP_node_transform_poll;
+ wgt->setup = WIDGETGROUP_node_transform_setup;
+ wgt->refresh = WIDGETGROUP_node_transform_refresh;
+}
diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c
index 7788173a8ee..5118d52efc4 100644
--- a/source/blender/editors/space_node/node_ops.c
+++ b/source/blender/editors/space_node/node_ops.c
@@ -295,7 +295,9 @@ void node_keymap(struct wmKeyConfig *keyconf)
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);
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index ea3869ef387..5f592431558 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -276,25 +276,16 @@ static bNodeSocket *best_socket_input(bNodeTree *ntree, bNode *node, int num, in
return NULL;
}
-static int snode_autoconnect_input(SpaceNode *snode, bNode *node_fr, bNodeSocket *sock_fr, bNode *node_to, bNodeSocket *sock_to, int replace)
+static bool snode_autoconnect_input(SpaceNode *snode, bNode *node_fr, bNodeSocket *sock_fr, bNode *node_to, bNodeSocket *sock_to, int replace)
{
bNodeTree *ntree = snode->edittree;
- bNodeLink *link;
/* then we can connect */
if (replace)
nodeRemSocketLinks(ntree, sock_to);
- link = nodeAddLink(ntree, node_fr, sock_fr, node_to, sock_to);
- /* validate the new link */
- ntreeUpdateTree(G.main, ntree);
- if (!(link->flag & NODE_LINK_VALID)) {
- nodeRemLink(ntree, link);
- return 0;
- }
-
- snode_update(snode, node_to);
- return 1;
+ nodeAddLink(ntree, node_fr, sock_fr, node_to, sock_to);
+ return true;
}
static void snode_autoconnect(SpaceNode *snode, const bool allow_multiple, const bool replace)
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
index 09594ab543c..ec525e684b0 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -428,6 +428,20 @@ static int ui_node_item_name_compare(const void *a, const void *b)
return BLI_natstrcmp(type_a->ui_name, type_b->ui_name);
}
+static bool ui_node_item_special_poll(const bNodeTree *UNUSED(ntree),
+ const bNodeType *ntype)
+{
+ if (STREQ(ntype->idname, "ShaderNodeUVAlongStroke")) {
+ /* TODO(sergey): Currently we don't have Freestyle nodes edited from
+ * the buttons context, so can ignore it's nodes completely.
+ *
+ * However, we might want to do some extra checks here later.
+ */
+ return false;
+ }
+ return true;
+}
+
static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
{
bNodeTree *ntree = arg->ntree;
@@ -452,11 +466,17 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
BLI_array_declare(sorted_ntypes);
NODE_TYPES_BEGIN(ntype) {
- if (compatibility && !(ntype->compatibility & compatibility))
+ if (compatibility && !(ntype->compatibility & compatibility)) {
continue;
+ }
- if (ntype->nclass != nclass)
+ if (ntype->nclass != nclass) {
continue;
+ }
+
+ if (!ui_node_item_special_poll(ntree, ntype)) {
+ continue;
+ }
BLI_array_append(sorted_ntypes, ntype);
}
diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c
index 8c5d2d82468..f497a06cb12 100644
--- a/source/blender/editors/space_node/node_view.c
+++ b/source/blender/editors/space_node/node_view.c
@@ -345,7 +345,7 @@ static int backimage_fit_exec(bContext *C, wmOperator *UNUSED(op))
ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
- if (ibuf == NULL) {
+ if ((ibuf == NULL) || (ibuf->x == 0) || (ibuf->y == 0)) {
BKE_image_release_ibuf(ima, ibuf, lock);
return OPERATOR_CANCELLED;
}
@@ -417,20 +417,18 @@ static void sample_draw(const bContext *C, ARegion *ar, void *arg_info)
}
}
-/* Returns color in the display space, matching ED_space_image_color_sample().
+/* Returns color in linear space, matching ED_space_image_color_sample().
* And here we've got recursion in the comments tips...
*/
-bool ED_space_node_color_sample(Scene *scene, SpaceNode *snode, ARegion *ar, int mval[2], float r_col[3])
+bool ED_space_node_color_sample(SpaceNode *snode, ARegion *ar, int mval[2], float r_col[3])
{
- const char *display_device = scene->display_settings.display_device;
- struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
void *lock;
Image *ima;
ImBuf *ibuf;
float fx, fy, bufx, bufy;
bool ret = false;
- if (STREQ(snode->tree_idname, ntreeType_Composite->idname) || (snode->flag & SNODE_BACKDRAW) == 0) {
+ if (!ED_node_is_compositor(snode) || (snode->flag & SNODE_BACKDRAW) == 0) {
/* use viewer image for color sampling only if we're in compositor tree
* with backdrop enabled
*/
@@ -471,10 +469,6 @@ bool ED_space_node_color_sample(Scene *scene, SpaceNode *snode, ARegion *ar, int
}
}
- if (ret) {
- IMB_colormanagement_scene_linear_to_display_v3(r_col, display);
- }
-
BKE_image_release_ibuf(ima, ibuf, lock);
return ret;
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index 4ef703c8994..c1099f38d92 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -57,6 +57,8 @@
#include "RNA_access.h"
+#include "WM_api.h"
+
#include "node_intern.h" /* own include */
@@ -381,12 +383,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(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, const Scene *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 = BKE_scene_use_new_shading_nodes(scene) ? snode->shaderfrom : SNODE_SHADER_OBJECT;
/* preview renders */
switch (wmn->category) {
@@ -643,6 +645,14 @@ static void node_main_region_init(wmWindowManager *wm, ARegion *ar)
UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
+ /* manipulators stay in the background for now - quick patchjob to make sure nodes themselves work */
+ if (ar->manipulator_map == NULL) {
+ ar->manipulator_map = WM_manipulatormap_new_from_type(
+ &(const struct wmManipulatorMapType_Params){SPACE_NODE, RGN_TYPE_WINDOW});
+ }
+
+ WM_manipulatormap_add_handlers(ar, ar->manipulator_map);
+
/* own keymaps */
keymap = WM_keymap_find(wm->defaultconf, "Node Generic", SPACE_NODE, 0);
WM_event_add_keymap_handler(&ar->handlers, keymap);
@@ -737,27 +747,55 @@ 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(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
+ wmManipulatorMap *mmap = ar->manipulator_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_manipulatormap_tag_refresh(mmap);
+ break;
+ }
break;
case NC_SCREEN:
+ if (wmn->data == ND_LAYOUTSET || wmn->action == NA_EDITED) {
+ WM_manipulatormap_tag_refresh(mmap);
+ }
switch (wmn->data) {
case ND_SCREENCAST:
case ND_ANIMPLAY:
+ case ND_LAYER:
ED_region_tag_redraw(ar);
break;
}
break;
+ case NC_WM:
+ if (wmn->data == ND_JOB)
+ ED_region_tag_redraw(ar);
+ break;
case NC_SCENE:
+ ED_region_tag_redraw(ar);
+ if (wmn->data == ND_RENDER_RESULT) {
+ WM_manipulatormap_tag_refresh(mmap);
+ }
+ break;
+ case NC_NODE:
+ ED_region_tag_redraw(ar);
+ if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
+ WM_manipulatormap_tag_refresh(mmap);
+ }
+ break;
case NC_MATERIAL:
case NC_TEXTURE:
case NC_WORLD:
- case NC_NODE:
case NC_LINESTYLE:
ED_region_tag_redraw(ar);
break;
@@ -822,6 +860,14 @@ 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 */
+ wmManipulatorMapType *mmap_type = WM_manipulatormaptype_ensure(
+ &(const struct wmManipulatorMapType_Params){SPACE_NODE, RGN_TYPE_WINDOW});
+ WM_manipulatorgrouptype_append_and_link(mmap_type, NODE_WGT_backdrop_transform);
+}
+
static void node_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
{
SpaceNode *snode = (SpaceNode *)slink;
@@ -855,6 +901,42 @@ static void node_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID
id_us_plus(new_id);
}
}
+ else if (GS(old_id->name) == ID_NT) {
+ bNodeTreePath *path, *path_next;
+
+ for (path = snode->treepath.first; path; path = path->next) {
+ if ((ID *)path->nodetree == old_id) {
+ path->nodetree = (bNodeTree *)new_id;
+ id_us_min(old_id);
+ id_us_plus(new_id);
+ }
+ if (path == snode->treepath.first) {
+ /* first nodetree in path is same as snode->nodetree */
+ snode->nodetree = path->nodetree;
+ }
+ if (path->nodetree == NULL) {
+ 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;
+ }
+ }
}
/* only called once, from space/spacetypes.c */
@@ -876,6 +958,7 @@ void ED_spacetype_node(void)
st->refresh = node_area_refresh;
st->context = node_context;
st->dropboxes = node_dropboxes;
+ st->manipulators = node_widgets;
st->id_remap = node_id_remap;
/* regions: main window */
diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt
index 289d6e715e1..96d27c6fd89 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,14 @@ set(INC_SYS
)
set(SRC
+ outliner_collections.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..2db87df8809
--- /dev/null
+++ b/source/blender/editors/space_outliner/outliner_collections.c
@@ -0,0 +1,469 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Foundation, Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_outliner/outliner_collections.c
+ * \ingroup spoutliner
+ */
+
+#include "BKE_context.h"
+#include "BKE_collection.h"
+#include "BKE_layer.h"
+#include "BKE_report.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "BLI_listbase.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 */
+
+/* -------------------------------------------------------------------- */
+
+static LayerCollection *outliner_collection_active(bContext *C)
+{
+ TODO_LAYER_OPERATORS;
+ /* consider that we may have overrides or objects active
+ * leading to no active collections */
+ return CTX_data_layer_collection(C);
+}
+
+SceneCollection *outliner_scene_collection_from_tree_element(TreeElement *te)
+{
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if (tselem->type == TSE_SCENE_COLLECTION) {
+ return te->directdata;
+ }
+ else if (tselem->type == TSE_LAYER_COLLECTION) {
+ LayerCollection *lc = te->directdata;
+ return lc->scene_collection;
+ }
+
+ return NULL;
+}
+
+#if 0
+static CollectionOverride *outliner_override_active(bContext *UNUSED(C))
+{
+ TODO_LAYER_OPERATORS;
+ TODO_LAYER_OVERRIDE;
+ return NULL;
+}
+#endif
+
+/* -------------------------------------------------------------------- */
+/* collection manager operators */
+
+/**
+ * Recursively get the collection for a given index
+ */
+static SceneCollection *scene_collection_from_index(ListBase *lb, const int number, int *i)
+{
+ for (SceneCollection *sc = lb->first; sc; sc = sc->next) {
+ if (*i == number) {
+ return sc;
+ }
+
+ (*i)++;
+
+ SceneCollection *sc_nested = scene_collection_from_index(&sc->scene_collections, number, i);
+ if (sc_nested) {
+ return sc_nested;
+ }
+ }
+ return NULL;
+}
+
+static int collection_link_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ SceneCollection *sc_master = BKE_collection_master(scene);
+ SceneCollection *sc;
+
+ int scene_collection_index = RNA_enum_get(op->ptr, "scene_collection");
+ if (scene_collection_index == 0) {
+ sc = sc_master;
+ }
+ else {
+ int index = 1;
+ sc = scene_collection_from_index(&sc_master->scene_collections, scene_collection_index, &index);
+ BLI_assert(sc);
+ }
+
+ BKE_collection_link(sl, sc);
+
+ DEG_relations_tag_update(CTX_data_main(C));
+
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update(&scene->id, 0);
+
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ return OPERATOR_FINISHED;
+}
+
+static int collection_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (BKE_collection_master(CTX_data_scene(C))->scene_collections.first == NULL) {
+ RNA_enum_set(op->ptr, "scene_collection", 0);
+ return collection_link_exec(C, op);
+ }
+ else {
+ return WM_enum_search_invoke(C, op, event);
+ }
+}
+
+static void collection_scene_collection_itemf_recursive(
+ EnumPropertyItem *tmp, EnumPropertyItem **item, int *totitem, int *value, SceneCollection *sc)
+{
+ tmp->value = *value;
+ tmp->icon = ICON_COLLAPSEMENU;
+ tmp->identifier = sc->name;
+ tmp->name = sc->name;
+ RNA_enum_item_add(item, totitem, tmp);
+
+ (*value)++;
+
+ for (SceneCollection *ncs = sc->scene_collections.first; ncs; ncs = ncs->next) {
+ collection_scene_collection_itemf_recursive(tmp, item, totitem, value, ncs);
+ }
+}
+
+static EnumPropertyItem *collection_scene_collection_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ EnumPropertyItem tmp = {0, "", 0, "", ""};
+ EnumPropertyItem *item = NULL;
+ int value = 0, totitem = 0;
+
+ Scene *scene = CTX_data_scene(C);
+ SceneCollection *sc = BKE_collection_master(scene);
+
+ collection_scene_collection_itemf_recursive(&tmp, &item, &totitem, &value, sc);
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+void OUTLINER_OT_collection_link(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Add Collection";
+ ot->idname = "OUTLINER_OT_collection_link";
+ ot->description = "Link a new collection to the active layer";
+
+ /* api callbacks */
+ ot->exec = collection_link_exec;
+ ot->invoke = collection_link_invoke;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ prop = RNA_def_enum(ot->srna, "scene_collection", DummyRNA_NULL_items, 0, "Scene Collection", "");
+ RNA_def_enum_funcs(prop, collection_scene_collection_itemf);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
+ ot->prop = prop;
+}
+
+/**
+ * Returns true if selected element is a collection directly
+ * linked to the active SceneLayer (not a nested collection)
+ */
+static int collection_unlink_poll(bContext *C)
+{
+ LayerCollection *lc = outliner_collection_active(C);
+
+ if (lc == NULL) {
+ return 0;
+ }
+
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ return BLI_findindex(&sl->layer_collections, lc) != -1 ? 1 : 0;
+}
+
+static int collection_unlink_exec(bContext *C, wmOperator *op)
+{
+ LayerCollection *lc = outliner_collection_active(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+
+ if (lc == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Active element is not a collection");
+ return OPERATOR_CANCELLED;
+ }
+
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ BKE_collection_unlink(sl, lc);
+
+ if (soops) {
+ outliner_cleanup_tree(soops);
+ }
+
+ DEG_relations_tag_update(CTX_data_main(C));
+
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update(&CTX_data_scene(C)->id, 0);
+
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_collection_unlink(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Collection";
+ ot->idname = "OUTLINER_OT_collection_unlink";
+ ot->description = "Unlink collection from the active layer";
+
+ /* api callbacks */
+ ot->exec = collection_unlink_exec;
+ ot->poll = collection_unlink_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int collection_new_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
+
+ SceneCollection *sc = BKE_collection_add(scene, NULL, NULL);
+ BKE_collection_link(sl, sc);
+
+ DEG_relations_tag_update(CTX_data_main(C));
+ 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 to the scene, and link it to the active layer";
+
+ /* api callbacks */
+ ot->exec = collection_new_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/**
+ * Returns true is selected element is a collection
+ */
+static int collection_override_new_poll(bContext *(C))
+{
+#ifdef TODO_LAYER_OVERRIDE
+ /* disable for now, since it's not implemented */
+ (void) C;
+ return 0;
+#else
+ return outliner_collection_active(C) ? 1 : 0;
+#endif
+}
+
+static int collection_override_new_invoke(bContext *UNUSED(C), wmOperator *op, const wmEvent *UNUSED(event))
+{
+ TODO_LAYER_OPERATORS;
+ TODO_LAYER_OVERRIDE;
+ BKE_report(op->reports, RPT_ERROR, "OUTLINER_OT_collections_override_new not implemented yet");
+ return OPERATOR_CANCELLED;
+}
+
+/* in the middle of renames remove s */
+void OUTLINER_OT_collection_override_new(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "New Override";
+ ot->idname = "OUTLINER_OT_collection_override_new";
+ ot->description = "Add a new override to the active collection";
+
+ /* api callbacks */
+ ot->invoke = collection_override_new_invoke;
+ ot->poll = collection_override_new_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+struct CollectionDeleteData {
+ Scene *scene;
+ SpaceOops *soops;
+};
+
+static TreeTraversalAction collection_delete_cb(TreeElement *te, void *customdata)
+{
+ struct CollectionDeleteData *data = customdata;
+ SceneCollection *scene_collection = outliner_scene_collection_from_tree_element(te);
+
+ if (!scene_collection) {
+ return TRAVERSE_SKIP_CHILDS;
+ }
+
+ if (scene_collection == BKE_collection_master(data->scene)) {
+ /* skip - showing warning/error message might be missleading
+ * when deleting multiple collections, so just do nothing */
+ }
+ else {
+ BKE_collection_remove(data->scene, scene_collection);
+ }
+
+ return TRAVERSE_CONTINUE;
+}
+
+static int collection_delete_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ struct CollectionDeleteData data = {.scene = scene, .soops = soops};
+
+ TODO_LAYER_OVERRIDE; /* handle overrides */
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_delete_cb, &data);
+
+ DEG_relations_tag_update(CTX_data_main(C));
+
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update(&scene->id, 0);
+
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_collections_delete(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete";
+ ot->idname = "OUTLINER_OT_collections_delete";
+ ot->description = "Delete selected overrides or collections";
+
+ /* api callbacks */
+ ot->exec = collection_delete_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int collection_select_exec(bContext *C, wmOperator *op)
+{
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ const int collection_index = RNA_int_get(op->ptr, "collection_index");
+ sl->active_collection = collection_index;
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_collection_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select";
+ ot->idname = "OUTLINER_OT_collection_select";
+ ot->description = "Change active collection or override";
+
+ /* api callbacks */
+ ot->exec = collection_select_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_int(ot->srna, "collection_index", 0, 0, INT_MAX, "Index",
+ "Index of collection to select", 0, INT_MAX);
+}
+
+/* -------------------------------------------------------------------- */
+
+static int stubs_invoke(bContext *UNUSED(C), wmOperator *op, const wmEvent *UNUSED(event))
+{
+ TODO_LAYER_OPERATORS;
+ BKE_report(op->reports, RPT_ERROR, "Operator not implemented yet");
+ return OPERATOR_CANCELLED;
+}
+
+void OUTLINER_OT_collection_objects_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Objects";
+ ot->idname = "OUTLINER_OT_collection_objects_add";
+ ot->description = "Add selected objects to collection";
+
+ /* api callbacks */
+ ot->invoke = stubs_invoke;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+void OUTLINER_OT_collection_objects_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Object";
+ ot->idname = "OUTLINER_OT_collection_objects_remove";
+ ot->description = "Remove objects from collection";
+
+ /* api callbacks */
+ ot->invoke = stubs_invoke;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+void OUTLINER_OT_collection_objects_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Objects";
+ ot->idname = "OUTLINER_OT_collection_objects_select";
+ ot->description = "Select collection objects";
+
+ /* api callbacks */
+ ot->invoke = stubs_invoke;
+
+ /* 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 collection objects";
+
+ /* api callbacks */
+ ot->invoke = stubs_invoke;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index d4553b650c5..7a1eca0f179 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -40,6 +40,7 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLI_mempool.h"
@@ -47,9 +48,9 @@
#include "BKE_context.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
@@ -57,6 +58,8 @@
#include "BKE_scene.h"
#include "BKE_object.h"
+#include "DEG_depsgraph.h"
+
#include "ED_armature.h"
#include "ED_keyframing.h"
#include "ED_object.h"
@@ -65,8 +68,7 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
+#include "GPU_immediate.h"
#include "UI_interface.h"
#include "UI_interface_icons.h"
@@ -155,7 +157,7 @@ static void restrictbutton_recursive_ebone(bContext *C, EditBone *ebone_parent,
}
}
-static void restrictbutton_recursive_bone(bContext *C, bArmature *arm, Bone *bone_parent, int flag, bool set_flag)
+static void restrictbutton_recursive_bone(Bone *bone_parent, int flag, bool set_flag)
{
Bone *bone;
for (bone = bone_parent->childbase.first; bone; bone = bone->next) {
@@ -166,119 +168,9 @@ static void restrictbutton_recursive_bone(bContext *C, bArmature *arm, Bone *bon
else {
bone->flag &= ~flag;
}
- restrictbutton_recursive_bone(C, arm, bone, flag, set_flag);
- }
-
-}
-
-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(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");
+ restrictbutton_recursive_bone(bone, flag, set_flag);
}
- 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))
@@ -290,33 +182,31 @@ static void restrictbutton_modifier_cb(bContext *C, void *UNUSED(poin), void *po
{
Object *ob = (Object *)poin2;
- 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);
}
-static void restrictbutton_bone_visibility_cb(bContext *C, void *poin, void *poin2)
+static void restrictbutton_bone_visibility_cb(bContext *C, void *UNUSED(poin), void *poin2)
{
- bArmature *arm = (bArmature *)poin;
Bone *bone = (Bone *)poin2;
if (bone->flag & BONE_HIDDEN_P)
bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
if (CTX_wm_window(C)->eventstate->ctrl) {
- restrictbutton_recursive_bone(C, arm, bone, BONE_HIDDEN_P, (bone->flag & BONE_HIDDEN_P) != 0);
+ restrictbutton_recursive_bone(bone, BONE_HIDDEN_P, (bone->flag & BONE_HIDDEN_P) != 0);
}
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
}
-static void restrictbutton_bone_select_cb(bContext *C, void *poin, void *poin2)
+static void restrictbutton_bone_select_cb(bContext *C, void *UNUSED(poin), void *poin2)
{
- bArmature *arm = (bArmature *)poin;
Bone *bone = (Bone *)poin2;
if (bone->flag & BONE_UNSELECTABLE)
bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
if (CTX_wm_window(C)->eventstate->ctrl) {
- restrictbutton_recursive_bone(C, arm, bone, BONE_UNSELECTABLE, (bone->flag & BONE_UNSELECTABLE) != 0);
+ restrictbutton_recursive_bone(bone, BONE_UNSELECTABLE, (bone->flag & BONE_UNSELECTABLE) != 0);
}
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
@@ -356,96 +246,14 @@ 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)
-{
- GroupObject *gob;
-
-#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
-}
-
-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
-}
-
-void restrictbutton_gr_restrict_flag(void *poin, void *poin2, int flag)
-{
- Scene *scene = (Scene *)poin;
- GroupObject *gob;
- Group *gr = (Group *)poin2;
-
- if (group_restrict_flag(gr, flag)) {
- for (gob = gr->gobject.first; gob; gob = gob->next) {
- if (ID_IS_LINKED_DATABLOCK(gob->ob))
- continue;
-
- gob->ob->restrictflag &= ~flag;
-
- if (flag == OB_RESTRICT_VIEW)
- if (gob->ob->flag & SELECT)
- ED_base_object_select(BKE_scene_base_find(scene, gob->ob), BA_DESELECT);
- }
- }
- else {
- for (gob = gr->gobject.first; gob; gob = gob->next) {
- if (ID_IS_LINKED_DATABLOCK(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);
- }
- }
- }
- }
- }
-}
-
-static void restrictbutton_gr_restrict_view(bContext *C, void *poin, void *poin2)
+static void restrictbutton_collection_flag_cb(bContext *C, void *poin, void *UNUSED(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)
-{
- restrictbutton_gr_restrict_flag(poin, poin2, OB_RESTRICT_RENDER);
- WM_event_add_notifier(C, NC_GROUP, NULL);
+ Scene *scene = poin;
+ /* hide and deselect bases that are directly influenced by this LayerCollection */
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update(&scene->id, 0);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, NULL);
}
static void restrictbutton_id_user_toggle(bContext *UNUSED(C), void *poin, void *UNUSED(poin2))
@@ -467,6 +275,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
{
SpaceOops *soops = CTX_wm_space_outliner(C);
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *obedit = CTX_data_edit_object(C);
BLI_mempool *ts = soops->treestore;
TreeStoreElem *tselem = tsep;
@@ -528,7 +337,7 @@ 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(obedit->data, oldname, newname);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, OBACT);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, OBACT_NEW);
}
break;
}
@@ -540,8 +349,8 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
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, sl, soops, te, OL_SETSEL_NORMAL, true);
+ ob = OBACT_NEW;
/* restore bone name */
BLI_strncpy(newname, bone->name, sizeof(bone->name));
@@ -557,8 +366,8 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
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, sl, soops, te, OL_SETSEL_NORMAL, true);
+ ob = OBACT_NEW;
BLI_assert(ob->type == OB_ARMATURE);
@@ -592,6 +401,13 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
}
case TSE_R_LAYER:
break;
+ case TSE_SCENE_COLLECTION:
+ case TSE_LAYER_COLLECTION:
+ {
+ SceneCollection *sc = outliner_scene_collection_from_tree_element(te);
+ BKE_collection_rename(scene, sc, te->name);
+ break;
+ }
}
}
tselem->flag &= ~TSE_TEXTBUT;
@@ -604,7 +420,6 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
TreeElement *te;
TreeStoreElem *tselem;
Object *ob = NULL;
- Group *gr = NULL;
PropertyRNA *object_prop_hide, *object_prop_hide_select, *object_prop_hide_render;
@@ -618,73 +433,8 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
for (te = lb->first; te; te = te->next) {
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;
-
- ob = (Object *)tselem->id;
- RNA_pointer_create((ID *)ob, &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,
- (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);
- UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
-
- bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, ICON_RESTRICT_SELECT_OFF,
- (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);
- UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
-
- bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, ICON_RESTRICT_RENDER_OFF,
- (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_DATABLOCK(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) {
+ 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,
@@ -806,6 +556,27 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
UI_block_emboss_set(block, UI_EMBOSS);
}
+ else if (tselem->type == TSE_LAYER_COLLECTION) {
+ LayerCollection *collection = te->directdata;
+
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+
+ bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_VISIBLE, 0, ICON_RESTRICT_VIEW_OFF,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &collection->flag, 0, 0, 0, 0,
+ TIP_("Restrict/Allow 3D View visibility of objects in the collection"));
+ UI_but_func_set(bt, restrictbutton_collection_flag_cb, scene, collection);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
+
+ bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_SELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &collection->flag, 0, 0, 0, 0,
+ TIP_("Restrict/Allow 3D View selection of objects in the collection"));
+ UI_but_func_set(bt, restrictbutton_collection_flag_cb, scene, collection);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
+
+ UI_block_emboss_set(block, UI_EMBOSS);
+ }
}
if (TSELEM_OPEN(tselem, soops)) outliner_draw_restrictbuts(block, scene, ar, soops, &te->subtree);
@@ -835,11 +606,11 @@ static void outliner_draw_userbuts(uiBlock *block, ARegion *ar, SpaceOops *soops
if (id->flag & LIB_FAKEUSER) {
icon = ICON_FILE_TICK;
- tip = TIP_("Datablock will be retained using a fake user");
+ tip = TIP_("Data-block will be retained using a fake user");
}
else {
icon = ICON_X;
- tip = TIP_("Datablock has no users and will be deleted");
+ 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,
@@ -852,14 +623,14 @@ static void outliner_draw_userbuts(uiBlock *block, ARegion *ar, SpaceOops *soops
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 datablock"));
+ 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_("Datablock has a 'fake' user which will keep it in the file "
+ 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);
@@ -879,21 +650,26 @@ 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);
+ glLineWidth(1.0f);
- /* draw column separator lines */
- fdrawline((float)sizex,
- v2d->cur.ymax,
- (float)sizex,
- miny);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShadeAlpha(TH_BACK, -15, -200);
- fdrawline((float)sizex + OL_RNA_COL_SIZEX,
- v2d->cur.ymax,
- (float)sizex + OL_RNA_COL_SIZEX,
- miny);
+ immBegin(GWN_PRIM_LINES, 4);
+
+ immVertex2f(pos, sizex, v2d->cur.ymax);
+ immVertex2f(pos, 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, Scene *scene, ARegion *ar, SpaceOops *soops, int sizex, ListBase *lb)
+static void outliner_draw_rnabuts(uiBlock *block, ARegion *ar, SpaceOops *soops, int sizex, ListBase *lb)
{
TreeElement *te;
TreeStoreElem *tselem;
@@ -932,7 +708,7 @@ static void outliner_draw_rnabuts(uiBlock *block, Scene *scene, ARegion *ar, Spa
}
}
- if (TSELEM_OPEN(tselem, soops)) outliner_draw_rnabuts(block, scene, 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);
@@ -988,7 +764,7 @@ static void tselem_draw_icon_uibut(struct DrawIconArg *arg, int icon)
/* 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);
+ UI_icon_draw_alpha(arg->x, arg->y, icon, arg->alpha);
glDisable(GL_BLEND);
}
else {
@@ -1041,9 +817,6 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
struct DrawIconArg arg;
float aspect;
- /* icons tiny bit away from text */
- x -= 0.15f * UI_UNIT_Y;
-
/* make function calls a bit compacter */
arg.block = block;
arg.id = tselem->id;
@@ -1051,189 +824,261 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
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;
- arg.x = x = x + 4.0f * aspect;
- arg.y = y = y + 0.1f * UI_UNIT_Y;
+ x += 2.0f * aspect;
+ y += 2.0f * aspect;
+ arg.x = x;
+ arg.y = y;
+
+#define ICON_DRAW(_icon) UI_icon_draw_alpha(x, y, _icon, alpha)
if (tselem->type) {
switch (tselem->type) {
case TSE_ANIM_DATA:
- UI_icon_draw(x, y, ICON_ANIM_DATA); break; // xxx
+ ICON_DRAW(ICON_ANIM_DATA); /* XXX */
+ break;
case TSE_NLA:
- UI_icon_draw(x, y, ICON_NLA); break;
+ ICON_DRAW(ICON_NLA);
+ break;
case TSE_NLA_TRACK:
- UI_icon_draw(x, y, ICON_NLA); break; // XXX
+ ICON_DRAW(ICON_NLA); /* XXX */
+ break;
case TSE_NLA_ACTION:
- UI_icon_draw(x, y, ICON_ACTION); break;
+ ICON_DRAW(ICON_ACTION);
+ break;
case TSE_DRIVER_BASE:
- UI_icon_draw(x, y, ICON_DRIVER); break;
+ ICON_DRAW(ICON_DRIVER);
+ break;
case TSE_DEFGROUP_BASE:
- UI_icon_draw(x, y, ICON_GROUP_VERTEX); break;
+ ICON_DRAW(ICON_GROUP_VERTEX);
+ break;
case TSE_BONE:
case TSE_EBONE:
- UI_icon_draw(x, y, ICON_BONE_DATA); break;
+ ICON_DRAW(ICON_BONE_DATA);
+ break;
case TSE_CONSTRAINT_BASE:
- UI_icon_draw(x, y, ICON_CONSTRAINT); break;
+ ICON_DRAW(ICON_CONSTRAINT);
+ break;
case TSE_MODIFIER_BASE:
- UI_icon_draw(x, y, ICON_MODIFIER); break;
+ ICON_DRAW(ICON_MODIFIER);
+ break;
case TSE_LINKED_OB:
- UI_icon_draw(x, y, ICON_OBJECT_DATA); break;
+ ICON_DRAW(ICON_OBJECT_DATA);
+ break;
case TSE_LINKED_PSYS:
- UI_icon_draw(x, y, ICON_PARTICLES); break;
+ ICON_DRAW(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_Subsurf:
+ ICON_DRAW(ICON_MOD_SUBSURF);
+ break;
+ case eModifierType_Armature:
+ ICON_DRAW(ICON_MOD_ARMATURE);
+ break;
+ case eModifierType_Lattice:
+ ICON_DRAW(ICON_MOD_LATTICE);
+ break;
+ case eModifierType_Curve:
+ ICON_DRAW(ICON_MOD_CURVE);
+ break;
+ case eModifierType_Build:
+ ICON_DRAW(ICON_MOD_BUILD);
+ break;
+ case eModifierType_Mirror:
+ ICON_DRAW(ICON_MOD_MIRROR);
+ break;
+ case eModifierType_Decimate:
+ ICON_DRAW(ICON_MOD_DECIM);
+ break;
+ case eModifierType_Wave:
+ ICON_DRAW(ICON_MOD_WAVE);
+ break;
+ case eModifierType_Hook:
+ ICON_DRAW(ICON_HOOK);
+ break;
+ case eModifierType_Softbody:
+ ICON_DRAW(ICON_MOD_SOFT);
+ break;
+ case eModifierType_Boolean:
+ ICON_DRAW(ICON_MOD_BOOLEAN);
+ break;
+ case eModifierType_ParticleSystem:
+ ICON_DRAW(ICON_MOD_PARTICLES);
+ break;
case eModifierType_ParticleInstance:
- UI_icon_draw(x, y, ICON_MOD_PARTICLES); break;
+ ICON_DRAW(ICON_MOD_PARTICLES);
+ break;
case eModifierType_EdgeSplit:
- UI_icon_draw(x, y, ICON_MOD_EDGESPLIT); break;
+ ICON_DRAW(ICON_MOD_EDGESPLIT);
+ break;
case eModifierType_Array:
- UI_icon_draw(x, y, ICON_MOD_ARRAY); break;
+ ICON_DRAW(ICON_MOD_ARRAY);
+ break;
case eModifierType_UVProject:
case eModifierType_UVWarp: /* TODO, get own icon */
- UI_icon_draw(x, y, ICON_MOD_UVPROJECT); break;
+ ICON_DRAW(ICON_MOD_UVPROJECT);
+ break;
case eModifierType_Displace:
- UI_icon_draw(x, y, ICON_MOD_DISPLACE); break;
+ ICON_DRAW(ICON_MOD_DISPLACE);
+ break;
case eModifierType_Shrinkwrap:
- UI_icon_draw(x, y, ICON_MOD_SHRINKWRAP); break;
+ ICON_DRAW(ICON_MOD_SHRINKWRAP);
+ break;
case eModifierType_Cast:
- UI_icon_draw(x, y, ICON_MOD_CAST); break;
+ ICON_DRAW(ICON_MOD_CAST);
+ break;
case eModifierType_MeshDeform:
- UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break;
+ case eModifierType_SurfaceDeform:
+ ICON_DRAW(ICON_MOD_MESHDEFORM);
+ break;
case eModifierType_Bevel:
- UI_icon_draw(x, y, ICON_MOD_BEVEL); break;
+ ICON_DRAW(ICON_MOD_BEVEL);
+ break;
case eModifierType_Smooth:
case eModifierType_LaplacianSmooth:
case eModifierType_CorrectiveSmooth:
- UI_icon_draw(x, y, ICON_MOD_SMOOTH); break;
+ ICON_DRAW(ICON_MOD_SMOOTH);
+ break;
case eModifierType_SimpleDeform:
- UI_icon_draw(x, y, ICON_MOD_SIMPLEDEFORM); break;
+ ICON_DRAW(ICON_MOD_SIMPLEDEFORM);
+ break;
case eModifierType_Mask:
- UI_icon_draw(x, y, ICON_MOD_MASK); break;
+ ICON_DRAW(ICON_MOD_MASK);
+ break;
case eModifierType_Cloth:
- UI_icon_draw(x, y, ICON_MOD_CLOTH); break;
+ ICON_DRAW(ICON_MOD_CLOTH);
+ break;
case eModifierType_Explode:
- UI_icon_draw(x, y, ICON_MOD_EXPLODE); break;
+ ICON_DRAW(ICON_MOD_EXPLODE);
+ break;
case eModifierType_Collision:
case eModifierType_Surface:
- UI_icon_draw(x, y, ICON_MOD_PHYSICS); break;
+ ICON_DRAW(ICON_MOD_PHYSICS);
+ break;
case eModifierType_Fluidsim:
- UI_icon_draw(x, y, ICON_MOD_FLUIDSIM); break;
+ ICON_DRAW(ICON_MOD_FLUIDSIM);
+ break;
case eModifierType_Multires:
- UI_icon_draw(x, y, ICON_MOD_MULTIRES); break;
+ ICON_DRAW(ICON_MOD_MULTIRES);
+ break;
case eModifierType_Smoke:
- UI_icon_draw(x, y, ICON_MOD_SMOKE); break;
+ ICON_DRAW(ICON_MOD_SMOKE);
+ break;
case eModifierType_Solidify:
- UI_icon_draw(x, y, ICON_MOD_SOLIDIFY); break;
+ ICON_DRAW(ICON_MOD_SOLIDIFY);
+ break;
case eModifierType_Screw:
- UI_icon_draw(x, y, ICON_MOD_SCREW); break;
+ ICON_DRAW(ICON_MOD_SCREW);
+ break;
case eModifierType_Remesh:
- UI_icon_draw(x, y, ICON_MOD_REMESH); break;
+ ICON_DRAW(ICON_MOD_REMESH);
+ break;
case eModifierType_WeightVGEdit:
case eModifierType_WeightVGMix:
case eModifierType_WeightVGProximity:
- UI_icon_draw(x, y, ICON_MOD_VERTEX_WEIGHT); break;
+ ICON_DRAW(ICON_MOD_VERTEX_WEIGHT);
+ break;
case eModifierType_DynamicPaint:
- UI_icon_draw(x, y, ICON_MOD_DYNAMICPAINT); break;
+ ICON_DRAW(ICON_MOD_DYNAMICPAINT);
+ break;
case eModifierType_Ocean:
- UI_icon_draw(x, y, ICON_MOD_OCEAN); break;
+ ICON_DRAW(ICON_MOD_OCEAN);
+ break;
case eModifierType_Warp:
- UI_icon_draw(x, y, ICON_MOD_WARP); break;
+ ICON_DRAW(ICON_MOD_WARP);
+ break;
case eModifierType_Skin:
- UI_icon_draw(x, y, ICON_MOD_SKIN); break;
+ ICON_DRAW(ICON_MOD_SKIN);
+ break;
case eModifierType_Triangulate:
- UI_icon_draw(x, y, ICON_MOD_TRIANGULATE); break;
+ ICON_DRAW(ICON_MOD_TRIANGULATE);
+ break;
case eModifierType_MeshCache:
- UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */
+ ICON_DRAW(ICON_MOD_MESHDEFORM); /* XXX, needs own icon */
+ break;
case eModifierType_MeshSequenceCache:
- UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */
+ ICON_DRAW(ICON_MOD_MESHDEFORM); /* XXX, needs own icon */
+ break;
case eModifierType_Wireframe:
- UI_icon_draw(x, y, ICON_MOD_WIREFRAME); break;
+ ICON_DRAW(ICON_MOD_WIREFRAME);
+ break;
case eModifierType_LaplacianDeform:
- UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */
+ ICON_DRAW(ICON_MOD_MESHDEFORM); /* XXX, needs own icon */
+ break;
case eModifierType_DataTransfer:
- UI_icon_draw(x, y, ICON_MOD_DATA_TRANSFER); break;
+ ICON_DRAW(ICON_MOD_DATA_TRANSFER);
+ break;
case eModifierType_NormalEdit:
- UI_icon_draw(x, y, ICON_MOD_NORMALEDIT); break;
+ ICON_DRAW(ICON_MOD_NORMALEDIT);
+ break;
/* Default */
case eModifierType_None:
case eModifierType_ShapeKey:
case NUM_MODIFIER_TYPES:
- UI_icon_draw(x, y, ICON_DOT); break;
+ ICON_DRAW(ICON_DOT);
+ break;
}
break;
}
case TSE_POSE_BASE:
- UI_icon_draw(x, y, ICON_ARMATURE_DATA); break;
+ ICON_DRAW(ICON_ARMATURE_DATA);
+ break;
case TSE_POSE_CHANNEL:
- UI_icon_draw(x, y, ICON_BONE_DATA); break;
+ ICON_DRAW(ICON_BONE_DATA);
+ break;
case TSE_PROXY:
- UI_icon_draw(x, y, ICON_GHOST); break;
+ ICON_DRAW(ICON_GHOST);
+ break;
case TSE_R_LAYER_BASE:
- UI_icon_draw(x, y, ICON_RENDERLAYERS); break;
+ ICON_DRAW(ICON_RENDERLAYERS);
+ break;
case TSE_R_LAYER:
- UI_icon_draw(x, y, ICON_RENDERLAYERS); break;
+ ICON_DRAW(ICON_RENDERLAYERS);
+ break;
case TSE_LINKED_LAMP:
- UI_icon_draw(x, y, ICON_LAMP_DATA); break;
+ ICON_DRAW(ICON_LAMP_DATA);
+ break;
case TSE_LINKED_MAT:
- UI_icon_draw(x, y, ICON_MATERIAL_DATA); break;
+ ICON_DRAW(ICON_MATERIAL_DATA);
+ break;
case TSE_POSEGRP_BASE:
- UI_icon_draw(x, y, ICON_GROUP_BONE); break;
+ ICON_DRAW(ICON_GROUP_BONE);
+ break;
case TSE_SEQUENCE:
if (te->idcode == SEQ_TYPE_MOVIE)
- UI_icon_draw(x, y, ICON_SEQUENCE);
+ ICON_DRAW(ICON_SEQUENCE);
else if (te->idcode == SEQ_TYPE_META)
- UI_icon_draw(x, y, ICON_DOT);
+ ICON_DRAW(ICON_DOT);
else if (te->idcode == SEQ_TYPE_SCENE)
- UI_icon_draw(x, y, ICON_SCENE);
+ ICON_DRAW(ICON_SCENE);
else if (te->idcode == SEQ_TYPE_SOUND_RAM)
- UI_icon_draw(x, y, ICON_SOUND);
+ ICON_DRAW(ICON_SOUND);
else if (te->idcode == SEQ_TYPE_IMAGE)
- UI_icon_draw(x, y, ICON_IMAGE_COL);
+ ICON_DRAW(ICON_IMAGE_COL);
else
- UI_icon_draw(x, y, ICON_PARTICLES);
+ ICON_DRAW(ICON_PARTICLES);
break;
case TSE_SEQ_STRIP:
- UI_icon_draw(x, y, ICON_LIBRARY_DATA_DIRECT);
+ ICON_DRAW(ICON_LIBRARY_DATA_DIRECT);
break;
case TSE_SEQUENCE_DUP:
- UI_icon_draw(x, y, ICON_OBJECT_DATA);
+ ICON_DRAW(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));
}
- else
- UI_icon_draw(x, y, RNA_struct_ui_icon(te->rnaptr.type));
+ else {
+ int icon = RNA_struct_ui_icon(te->rnaptr.type);
+ ICON_DRAW(icon);
+ }
break;
/* Removed the icons from outliner. Need a better structure with Layers, Palettes and Colors */
#if 0
@@ -1242,7 +1087,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
break;
#endif
default:
- UI_icon_draw(x, y, ICON_DOT); break;
+ ICON_DRAW(ICON_DOT);
+ break;
}
}
else if (tselem->id) {
@@ -1347,17 +1193,18 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
}
}
}
+
+#undef ICON_DRAW
}
-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 outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, SceneLayer *sl, SpaceOops *soops,
+ ListBase *lb, int level, int xmax, int *offsx, int ys, float alpha_fac)
{
TreeElement *te;
TreeStoreElem *tselem;
eOLDrawState active;
for (te = lb->first; te; te = te->next) {
-
/* exit drawing early */
if ((*offsx) - UI_UNIT_X > xmax)
break;
@@ -1370,34 +1217,38 @@ static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, Spa
/* 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_NEW == (Object *)tselem->id) ? OL_DRAWSEL_NORMAL : OL_DRAWSEL_NONE;
}
else if (scene->obedit && scene->obedit->data == tselem->id) {
active = OL_DRAWSEL_NORMAL;
}
else {
- active = tree_element_active(C, scene, soops, te, OL_SETSEL_NONE, false);
+ active = tree_element_active(C, scene, sl, 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, sl, soops, te, tselem, OL_SETSEL_NONE, false);
}
if (active != OL_DRAWSEL_NONE) {
float ufac = UI_UNIT_X / 20.0f;
+ float color[4] = {1.0f, 1.0f, 1.0f, 0.4f};
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- glColor4ub(255, 255, 255, 100);
- UI_draw_roundbox(
- (float) *offsx - 1.0f * ufac,
+ color[3] *= alpha_fac;
+
+ UI_draw_roundbox_aa(
+ true,
+ (float) *offsx + 1.0f * ufac,
(float)ys + 1.0f * ufac,
- (float)*offsx + UI_UNIT_X - 2.0f * ufac,
+ (float)*offsx + UI_UNIT_X - 1.0f * ufac,
(float)ys + UI_UNIT_Y - ufac,
- (float)UI_UNIT_Y / 2.0f - ufac);
+ (float)UI_UNIT_Y / 2.0f - ufac,
+ color);
glEnable(GL_BLEND); /* roundbox disables */
}
- tselem_draw_icon(block, xmax, (float)*offsx, (float)ys, tselem, te, 0.5f);
+ tselem_draw_icon(block, xmax, (float)*offsx, (float)ys, tselem, te, 0.5f * alpha_fac);
te->xs = *offsx;
te->ys = ys;
te->xend = (short)*offsx + UI_UNIT_X;
@@ -1408,45 +1259,52 @@ static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, Spa
/* 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);
+ outliner_draw_iconrow(C, block, scene, sl, soops, &te->subtree, level + 1, xmax, offsx, ys, alpha_fac);
}
}
/* closed tree element */
-static void outliner_set_coord_tree_element(SpaceOops *soops, TreeElement *te, int startx, int starty)
+static void outliner_set_coord_tree_element(TreeElement *te, int startx, int starty)
{
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(soops, ten, startx + UI_UNIT_X, starty);
+ outliner_set_coord_tree_element(ten, startx + UI_UNIT_X, starty);
}
}
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, SceneLayer *sl,
+ ARegion *ar, SpaceOops *soops, TreeElement *te, bool draw_grayed_out,
+ int startx, int *starty, TreeElement **te_edit, TreeElement **te_floating)
{
- 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 = 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;
}
+ if ((te->drag_data != NULL) && (*te_floating == NULL)) {
+ *te_floating = te;
+ }
/* icons can be ui buts, we don't want it to overlap with restrict */
if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0)
@@ -1454,50 +1312,24 @@ static void outliner_draw_tree_element(
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);
- }
-
/* colors for active/selected data */
if (tselem->type == 0) {
-
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;
- if (ob == OBACT || (ob->flag & SELECT)) {
+ if (ob == OBACT_NEW || (ob->flag & SELECT)) {
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 == OBACT_NEW) {
if (ob->flag & SELECT) {
UI_GetThemeColorType4ubv(TH_ACTIVE, SPACE_VIEW3D, col);
col[3] = alpha;
@@ -1509,38 +1341,36 @@ static void outliner_draw_tree_element(
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);
+ 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, sl, 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, sl, 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(
- (float)startx + UI_UNIT_X,
+ 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 - 2.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);
+ UI_UNIT_Y / 2.0f - 1.0f * ufac, color);
glEnable(GL_BLEND); /* roundbox disables it */
te->flag |= TE_ACTIVE; // for lookup in display hierarchies
@@ -1553,55 +1383,60 @@ static void outliner_draw_tree_element(
icon_x = startx;
else
icon_x = startx + 5 * ufac;
-
+
// icons a bit higher
if (TSELEM_OPEN(tselem, soops))
- UI_icon_draw((float)icon_x, (float)*starty + 2 * ufac, ICON_DISCLOSURE_TRI_DOWN);
+ UI_icon_draw_alpha((float)icon_x + 2 * ufac, (float)*starty + 1 * ufac, ICON_DISCLOSURE_TRI_DOWN,
+ alpha_fac);
else
- UI_icon_draw((float)icon_x, (float)*starty + 2 * ufac, ICON_DISCLOSURE_TRI_RIGHT);
+ 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;
+ tselem_draw_icon(block, xmax, (float)startx + offsx, (float)*starty, tselem, te, alpha_fac);
+ offsx += UI_UNIT_X + 2 * ufac;
}
else
offsx += 2 * ufac;
if (tselem->type == 0 && ID_IS_LINKED_DATABLOCK(tselem->id)) {
- glPixelTransferf(GL_ALPHA_SCALE, 0.5f);
if (tselem->id->tag & LIB_TAG_MISSING) {
- UI_icon_draw((float)startx + offsx, (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, (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, (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;
+ offsx += UI_UNIT_X + 2 * ufac;
}
glDisable(GL_BLEND);
/* 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));
@@ -1612,24 +1447,33 @@ 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);
-
+
glEnable(GL_BLEND);
- glPixelTransferf(GL_ALPHA_SCALE, 0.5);
-
- outliner_draw_iconrow(C, block, scene, soops, &te->subtree, 0, xmax, &tempx, *starty);
-
- glPixelTransferf(GL_ALPHA_SCALE, 1.0);
+
+ /* divider */
+ {
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_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, sl, soops, &te->subtree, 0, xmax, &tempx,
+ *starty, alpha_fac);
+
glDisable(GL_BLEND);
}
}
@@ -1639,132 +1483,298 @@ static void outliner_draw_tree_element(
te->xs = startx;
te->ys = *starty;
te->xend = startx + offsx;
-
+
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->drag_data != NULL);
+ outliner_draw_tree_element(C, block, fstyle, scene, sl, ar, soops, ten, draw_childs_grayed_out,
+ startx + UI_UNIT_X, starty, te_edit, te_floating);
}
}
else {
- for (ten = te->subtree.first; ten; ten = ten->next) {
- outliner_set_coord_tree_element(soops, ten, startx, *starty);
+ for (TreeElement *ten = te->subtree.first; ten; ten = ten->next) {
+ outliner_set_coord_tree_element(ten, startx, *starty);
}
*starty -= UI_UNIT_Y;
}
}
-static void outliner_draw_hierarchy(SpaceOops *soops, ListBase *lb, int startx, int *starty)
+static void outliner_draw_tree_element_floating(
+ const ARegion *ar, const TreeElement *te_floating)
+{
+ const TreeElement *te_insert = te_floating->drag_data->insert_handle;
+ const int line_width = 2;
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ int coord_y = te_insert->ys;
+ int coord_x = te_insert->xs;
+ float col[4];
+
+ if (te_insert == te_floating) {
+ /* don't draw anything */
+ return;
+ }
+
+ UI_GetThemeColorShade4fv(TH_BACK, -40, col);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ glEnable(GL_BLEND);
+
+ if (ELEM(te_floating->drag_data->insert_type, TE_INSERT_BEFORE, TE_INSERT_AFTER)) {
+ if (te_floating->drag_data->insert_type == TE_INSERT_BEFORE) {
+ coord_y += UI_UNIT_Y;
+ }
+ immUniformColor4fv(col);
+ glLineWidth(line_width);
+
+ immBegin(GWN_PRIM_LINE_STRIP, 2);
+ immVertex2f(pos, coord_x, coord_y);
+ immVertex2f(pos, ar->v2d.cur.xmax, coord_y);
+ immEnd();
+ }
+ else {
+ BLI_assert(te_floating->drag_data->insert_type == TE_INSERT_INTO);
+ immUniformColor3fvAlpha(col, col[3] * 0.5f);
+
+ immBegin(GWN_PRIM_TRI_STRIP, 4);
+ immVertex2f(pos, coord_x, coord_y + UI_UNIT_Y);
+ immVertex2f(pos, coord_x, coord_y);
+ immVertex2f(pos, ar->v2d.cur.xmax, coord_y + UI_UNIT_Y);
+ immVertex2f(pos, ar->v2d.cur.xmax, coord_y);
+ immEnd();
+ }
+
+ glDisable(GL_BLEND);
+ immUnbindProgram();
+}
+
+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;
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 (te = lb->first; te; te = te->next) {
+ bool draw_childs_grayed_out = draw_grayed_out || (te->drag_data != NULL);
y2 = *starty;
tselem = TREESTORE(te);
-
+
+ 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))
- glRecti(startx, *starty, startx + UI_UNIT_X, *starty - 1);
+ immRecti(pos, startx, *starty, startx + UI_UNIT_X, *starty - 1);
*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);
}
-
+
+ if (draw_grayed_out) {
+ immUniformColor3ubvAlpha(col, grayed_alpha);
+ }
+ else {
+ immUniformColor4ubv(col);
+ }
+
/* vertical line */
te = lb->last;
if (te->parent || lb->first != lb->last) {
tselem = TREESTORE(te);
- if (tselem->type == 0 && te->idcode == ID_OB) {
-
- glRecti(startx, y1 + UI_UNIT_Y, startx + 1, y2);
- }
+ if (tselem->type == 0 && te->idcode == ID_OB)
+ 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)
+{
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
+ unsigned char col[4];
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ UI_GetThemeColorBlend3ubv(TH_BACK, TH_TEXT, 0.4f, col);
+ col[3] = 255;
+
+ glEnable(GL_BLEND);
+ outliner_draw_hierarchy_lines_recursive(pos, soops, lb, startx, col, false, starty);
+ glDisable(GL_BLEND);
+
+ immUnbindProgram();
+}
+
+static void outliner_draw_struct_marks(ARegion *ar, SpaceOops *soops, ListBase *lb, int *starty)
{
TreeElement *te;
TreeStoreElem *tselem;
-
+
for (te = lb->first; te; te = te->next) {
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->type == TSE_RNA_STRUCT) {
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_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) {
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immThemeColorShadeAlpha(TH_BACK, -15, -200);
+
+ immBegin(GWN_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;
-
- for (te = lb->first; te; te = te->next) {
- tselem = TREESTORE(te);
-
+ const bool is_searching = SEARCHING_OUTLINER(soops) ||
+ (soops->outlinevis == SO_DATABLOCKS && soops->search_string[0] != 0);
+
+ 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);
+ }
+
+ /* search match highlights
+ * we don't expand items when searching in the datablocks but we
+ * still want to highlight any filter matches. */
+ if (is_searching && (tselem->flag & TSE_SEARCHMATCH)) {
+ immUniformColor4fv(col_searchmatch);
+ immRecti(pos, start_x, start_y + 1, ar->v2d.cur.xmax, start_y + UI_UNIT_Y - 1);
+ }
+
+ /* mouse hover highlights */
+ if ((tselem->flag & TSE_HIGHLIGHTED) || (te->drag_data != NULL)) {
+ immUniformColor4fv(col_highlight);
+ immRecti(pos, 0, start_y + 1, (int)ar->v2d.cur.xmax, 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;
+
+ glEnable(GL_BLEND);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_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();
+ glDisable(GL_BLEND);
+}
-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, SceneLayer *sl, ARegion *ar,
+ SpaceOops *soops, const bool has_restrict_icons,
+ TreeElement **te_edit)
{
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
- TreeElement *te;
+ TreeElement *te_floating = NULL;
int starty, startx;
- float col[3];
-
+
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // only once
-
+
if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) {
/* 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 */
+ GLfloat 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);
+
+ glGetFloatv(GL_SCISSOR_BOX, scissor);
+ glScissor(ar->winrct.xmin, ar->winrct.ymin, 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 = 6;
- 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, sl, ar, soops, te, te->drag_data != NULL,
+ startx, &starty, te_edit, &te_floating);
+ }
+ if (te_floating && te_floating->drag_data->insert_handle) {
+ outliner_draw_tree_element_floating(ar, te_floating);
+ }
+
+ if (has_restrict_icons) {
+ /* reset scissor */
+ glScissor(UNPACK4(scissor));
}
}
@@ -1773,53 +1783,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;
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_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(GWN_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;
-
- /* 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);
-
- 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((int)ar->v2d.cur.xmax - OL_TOGW, ystart, (int)ar->v2d.cur.xmax, ystart + UI_UNIT_Y);
- ystart -= 2 * UI_UNIT_Y;
- }
-
- UI_ThemeColorShadeAlpha(TH_BACK, -15, -200);
+ glLineWidth(1.0f);
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShadeAlpha(TH_BACK, -15, -200);
+ immBegin(GWN_PRIM_LINES, 6);
/* 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);
+ 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);
/* 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);
+ 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);
/* 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();
}
/* ****************************************************** */
@@ -1829,14 +1846,16 @@ void draw_outliner(const bContext *C)
{
Main *mainvar = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_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, sl, soops); // always
/* get extents of data */
outliner_height(soops, &soops->tree, &sizey);
@@ -1856,6 +1875,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,7 +1887,8 @@ void draw_outliner(const bContext *C)
// XXX this isn't that great yet...
if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0)
sizex += OL_TOGW * 3;
-
+
+ has_restrict_icons = !(soops->flag & SO_HIDE_RESTRICTCOLS);
}
/* adds vertical offset */
@@ -1884,19 +1905,19 @@ 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, sl, ar, soops, has_restrict_icons, &te_edit);
if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) {
/* draw rna buttons */
outliner_draw_rnacols(ar, sizex_rna);
- outliner_draw_rnabuts(block, scene, ar, soops, sizex_rna, &soops->tree);
+ outliner_draw_rnabuts(block, ar, soops, sizex_rna, &soops->tree);
}
- 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);
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 3c47f542dae..17d7c8967de 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -51,9 +51,9 @@
#include "BKE_animsys.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_idcode.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
@@ -64,6 +64,8 @@
#include "BKE_material.h"
#include "BKE_group.h"
+#include "DEG_depsgraph_build.h"
+
#include "../blenloader/BLO_readfile.h"
#include "ED_object.h"
@@ -117,9 +119,7 @@ static void outliner_open_reveal(SpaceOops *soops, ListBase *lb, TreeElement *te
}
#endif
-static TreeElement *outliner_dropzone_element(
- const SpaceOops *soops, TreeElement *te,
- const float fmval[2], const bool children)
+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 */
@@ -129,7 +129,7 @@ static TreeElement *outliner_dropzone_element(
/* 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(soops, te, fmval, children);
+ TreeElement *te_valid = outliner_dropzone_element(te, fmval, children);
if (te_valid)
return te_valid;
}
@@ -143,15 +143,53 @@ TreeElement *outliner_dropzone_find(const SpaceOops *soops, const float fmval[2]
TreeElement *te;
for (te = soops->tree.first; te; te = te->next) {
- TreeElement *te_valid = outliner_dropzone_element(soops, te, fmval, children);
+ TreeElement *te_valid = outliner_dropzone_element(te, fmval, children);
if (te_valid)
return te_valid;
}
return NULL;
}
+
/* ************************************************************** */
-/* Click Activated */
+
+/* Highlight --------------------------------------------------- */
+
+static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ 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;
+
+ if (!hovered_te || !(hovered_te->store_elem->flag & TSE_HIGHLIGHTED)) {
+ changed = outliner_set_flag(&soops->tree, TSE_HIGHLIGHTED, false);
+ if (hovered_te) {
+ hovered_te->store_elem->flag |= TSE_HIGHLIGHTED;
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ soops->storeflag |= SO_TREESTORE_REDRAW; /* only needs to redraw, no rebuild */
+ ED_region_tag_redraw(ar);
+ }
+
+ return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
+}
+
+void OUTLINER_OT_highlight_update(wmOperatorType *ot)
+{
+ ot->name = "Update Highlight";
+ ot->idname = "OUTLINER_OT_highlight_update";
+ ot->description = "Update the item highlight based on the current mouse position";
+
+ ot->invoke = outliner_highlight_update;
+
+ ot->poll = ED_operator_outliner_active;
+}
/* Toggle Open/Closed ------------------------------------------- */
@@ -164,7 +202,7 @@ static int do_outliner_item_openclose(bContext *C, SpaceOops *soops, TreeElement
/* all below close/open? */
if (all) {
tselem->flag &= ~TSE_CLOSED;
- outliner_set_flag(soops, &te->subtree, TSE_CLOSED, !outliner_has_one_flag(soops, &te->subtree, TSE_CLOSED, 1));
+ outliner_set_flag(&te->subtree, TSE_CLOSED, !outliner_has_one_flag(&te->subtree, TSE_CLOSED, 1));
}
else {
if (tselem->flag & TSE_CLOSED) tselem->flag &= ~TSE_CLOSED;
@@ -218,8 +256,11 @@ void OUTLINER_OT_item_openclose(wmOperatorType *ot)
/* Rename --------------------------------------------------- */
-static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem, ReportList *reports)
+static void do_item_rename(const Scene *scene, 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)) {
/* do nothing */;
@@ -232,6 +273,18 @@ static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem,
else if (ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {
BKE_report(reports, RPT_WARNING, "Cannot edit sequence name");
}
+ else if (ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION)) {
+ SceneCollection *master = BKE_collection_master(scene);
+
+ if ((tselem->type == TSE_SCENE_COLLECTION && te->directdata == master) ||
+ (((LayerCollection *)te->directdata)->scene_collection == master))
+ {
+ BKE_report(reports, RPT_WARNING, "Cannot edit name of master collection");
+ }
+ else {
+ add_textbut = true;
+ }
+ }
else if (ID_IS_LINKED_DATABLOCK(tselem->id)) {
BKE_report(reports, RPT_WARNING, "Cannot edit external libdata");
}
@@ -239,42 +292,44 @@ 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);
}
}
void item_rename_cb(
- bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te,
+ bContext *C, ReportList *reports, Scene *scene, TreeElement *te,
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
ARegion *ar = CTX_wm_region(C);
- ReportList *reports = CTX_wm_reports(C); // XXX
- do_item_rename(ar, te, tselem, reports);
+ do_item_rename(scene, ar, te, tselem, reports);
}
-static int do_outliner_item_rename(bContext *C, ARegion *ar, SpaceOops *soops, TreeElement *te, const float mval[2])
-{
- ReportList *reports = CTX_wm_reports(C); // XXX
-
+static int do_outliner_item_rename(const Scene *scene, 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);
/* click on name */
if (mval[0] > te->xs + UI_UNIT_X * 2 && mval[0] < te->xend) {
- do_item_rename(ar, te, tselem, reports);
+ do_item_rename(scene, ar, te, tselem, reports);
return 1;
}
return 0;
}
for (te = te->subtree.first; te; te = te->next) {
- if (do_outliner_item_rename(C, ar, soops, te, mval)) return 1;
+ if (do_outliner_item_rename(scene, reports, ar, te, mval)) return 1;
}
return 0;
}
-static int outliner_item_rename(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+static int outliner_item_rename(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
@@ -285,7 +340,7 @@ static int outliner_item_rename(bContext *C, wmOperator *UNUSED(op), const wmEve
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_item_rename(C, ar, soops, te, fmval)) {
+ if (do_outliner_item_rename(CTX_data_scene(C), op->reports, ar, te, fmval)) {
changed = true;
break;
}
@@ -314,16 +369,19 @@ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeSto
ID *id = tselem->id;
BLI_assert(te->idcode != 0 && id != NULL);
- BLI_assert(te->idcode != ID_LI || ((Library *)id)->parent == NULL);
UNUSED_VARS_NDEBUG(te);
+ if (te->idcode == ID_LI && ((Library *)id)->parent != NULL) {
+ BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked library '%s'", id->name);
+ return;
+ }
if (id->tag & LIB_TAG_INDIRECT) {
BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked id '%s'", id->name);
return;
}
else if (BKE_library_ID_is_indirectly_used(bmain, id) && ID_REAL_USERS(id) <= 1) {
BKE_reportf(reports, RPT_WARNING,
- "Cannot delete id '%s', indirectly used datablocks need at least one user",
+ "Cannot delete id '%s', indirectly used data-blocks need at least one user",
id->name);
return;
}
@@ -392,7 +450,7 @@ static int outliner_id_delete_invoke(bContext *C, wmOperator *op, const wmEvent
void OUTLINER_OT_id_delete(wmOperatorType *ot)
{
- ot->name = "Delete Datablock";
+ ot->name = "Delete Data-Block";
ot->idname = "OUTLINER_OT_id_delete";
ot->description = "Delete the ID under cursor";
@@ -425,7 +483,7 @@ static int outliner_id_remap_exec(bContext *C, wmOperator *op)
if (ID_IS_LINKED_DATABLOCK(old_id)) {
BKE_reportf(op->reports, RPT_WARNING,
- "Old ID '%s' is linked from a library, indirect usages of this datablock will not be remapped",
+ "Old ID '%s' is linked from a library, indirect usages of this data-block will not be remapped",
old_id->name);
}
@@ -435,7 +493,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_scene_relations_rebuild(bmain, scene);
/* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
GPU_materials_free();
@@ -521,7 +579,8 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot)
ot->flag = 0;
- RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", "");
+ prop = RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", "");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
prop = RNA_def_enum(ot->srna, "old_id", DummyRNA_NULL_items, 0, "Old ID", "Old ID to replace");
RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, outliner_id_itemf);
@@ -716,20 +775,20 @@ void lib_reload_cb(
/* Apply Settings ------------------------------- */
-static int outliner_count_levels(SpaceOops *soops, ListBase *lb, const int curlevel)
+static int outliner_count_levels(ListBase *lb, const int curlevel)
{
TreeElement *te;
int level = curlevel, lev;
for (te = lb->first; te; te = te->next) {
- lev = outliner_count_levels(soops, &te->subtree, curlevel + 1);
+ lev = outliner_count_levels(&te->subtree, curlevel + 1);
if (lev > level) level = lev;
}
return level;
}
-int outliner_has_one_flag(SpaceOops *soops, ListBase *lb, short flag, const int curlevel)
+int outliner_has_one_flag(ListBase *lb, short flag, const int curlevel)
{
TreeElement *te;
TreeStoreElem *tselem;
@@ -739,23 +798,40 @@ int outliner_has_one_flag(SpaceOops *soops, ListBase *lb, short flag, const int
tselem = TREESTORE(te);
if (tselem->flag & flag) return curlevel;
- level = outliner_has_one_flag(soops, &te->subtree, flag, curlevel + 1);
+ level = outliner_has_one_flag(&te->subtree, flag, curlevel + 1);
if (level) return level;
}
return 0;
}
-void outliner_set_flag(SpaceOops *soops, 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_set_flag(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);
- if (set == 0) tselem->flag &= ~flag;
- else tselem->flag |= flag;
- outliner_set_flag(soops, &te->subtree, flag, set);
+ 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_set_flag(&te->subtree, flag, set);
}
+
+ return changed;
}
/* Restriction Columns ------------------------------- */
@@ -783,166 +859,6 @@ int common_restrict_check(bContext *C, Object *ob)
}
/* =============================================== */
-/* Restriction toggles */
-
-/* Toggle Visibility ---------------------------------------- */
-
-void object_toggle_visibility_cb(
- bContext *C, ReportList *UNUSED(reports), Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
-{
- Base *base = (Base *)te->directdata;
- Object *ob = (Object *)tselem->id;
-
- /* 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 *UNUSED(reports), Scene *scene, TreeElement *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) {
- 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 *UNUSED(reports), Scene *scene, TreeElement *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) {
- 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) ---------------------------------------- */
@@ -952,10 +868,10 @@ static int outliner_toggle_expanded_exec(bContext *C, wmOperator *UNUSED(op))
SpaceOops *soops = CTX_wm_space_outliner(C);
ARegion *ar = CTX_wm_region(C);
- if (outliner_has_one_flag(soops, &soops->tree, TSE_CLOSED, 1))
- outliner_set_flag(soops, &soops->tree, TSE_CLOSED, 0);
+ if (outliner_has_one_flag(&soops->tree, TSE_CLOSED, 1))
+ outliner_set_flag(&soops->tree, TSE_CLOSED, 0);
else
- outliner_set_flag(soops, &soops->tree, TSE_CLOSED, 1);
+ outliner_set_flag(&soops->tree, TSE_CLOSED, 1);
ED_region_tag_redraw(ar);
@@ -984,10 +900,10 @@ static int outliner_toggle_selected_exec(bContext *C, wmOperator *UNUSED(op))
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
- if (outliner_has_one_flag(soops, &soops->tree, TSE_SELECTED, 1))
- outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 0);
+ if (outliner_has_one_flag(&soops->tree, TSE_SELECTED, 1))
+ outliner_set_flag(&soops->tree, TSE_SELECTED, 0);
else
- outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 1);
+ outliner_set_flag(&soops->tree, TSE_SELECTED, 1);
soops->storeflag |= SO_TREESTORE_REDRAW;
@@ -1063,14 +979,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);
+ SceneLayer *sl = CTX_data_scene_layer(C);
ARegion *ar = CTX_wm_region(C);
View2D *v2d = &ar->v2d;
TreeElement *te;
int xdelta, ytop;
- Object *obact = OBACT;
+ Object *obact = OBACT_NEW;
if (!obact)
return OPERATOR_CANCELLED;
@@ -1085,13 +1001,13 @@ static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
if (obact->mode & OB_MODE_POSE) {
bPoseChannel *pchan = CTX_data_active_pose_bone(C);
if (pchan) {
- te = outliner_find_posechannel(so, &te_obact->subtree, pchan);
+ te = outliner_find_posechannel(&te_obact->subtree, pchan);
}
}
else if (obact->mode & OB_MODE_EDIT) {
EditBone *ebone = CTX_data_active_bone(C);
if (ebone) {
- te = outliner_find_editbone(so, &te_obact->subtree, ebone);
+ te = outliner_find_editbone(&te_obact->subtree, ebone);
}
}
}
@@ -1286,7 +1202,7 @@ static void outliner_find_panel(Scene *UNUSED(scene), ARegion *ar, SpaceOops *so
/* Show One Level ----------------------------------------------- */
/* helper function for Show/Hide one level operator */
-static void outliner_openclose_level(SpaceOops *soops, ListBase *lb, int curlevel, int level, int open)
+static void outliner_openclose_level(ListBase *lb, int curlevel, int level, int open)
{
TreeElement *te;
TreeStoreElem *tselem;
@@ -1301,7 +1217,7 @@ static void outliner_openclose_level(SpaceOops *soops, ListBase *lb, int curleve
if (curlevel >= level) tselem->flag |= TSE_CLOSED;
}
- outliner_openclose_level(soops, &te->subtree, curlevel + 1, level, open);
+ outliner_openclose_level(&te->subtree, curlevel + 1, level, open);
}
}
@@ -1312,13 +1228,13 @@ static int outliner_one_level_exec(bContext *C, wmOperator *op)
const bool add = RNA_boolean_get(op->ptr, "open");
int level;
- level = outliner_has_one_flag(soops, &soops->tree, TSE_CLOSED, 1);
+ level = outliner_has_one_flag(&soops->tree, TSE_CLOSED, 1);
if (add == 1) {
- if (level) outliner_openclose_level(soops, &soops->tree, 1, level, 1);
+ if (level) outliner_openclose_level(&soops->tree, 1, level, 1);
}
else {
- if (level == 0) level = outliner_count_levels(soops, &soops->tree, 0);
- if (level) outliner_openclose_level(soops, &soops->tree, 1, level - 1, 0);
+ if (level == 0) level = outliner_count_levels(&soops->tree, 0);
+ if (level) outliner_openclose_level(&soops->tree, 1, level - 1, 0);
}
ED_region_tag_redraw(ar);
@@ -1349,7 +1265,7 @@ void OUTLINER_OT_show_one_level(wmOperatorType *ot)
/* Show Hierarchy ----------------------------------------------- */
/* helper function for tree_element_shwo_hierarchy() - recursively checks whether subtrees have any objects*/
-static int subtree_has_objects(SpaceOops *soops, ListBase *lb)
+static int subtree_has_objects(ListBase *lb)
{
TreeElement *te;
TreeStoreElem *tselem;
@@ -1357,7 +1273,7 @@ static int subtree_has_objects(SpaceOops *soops, ListBase *lb)
for (te = lb->first; te; te = te->next) {
tselem = TREESTORE(te);
if (tselem->type == 0 && te->idcode == ID_OB) return 1;
- if (subtree_has_objects(soops, &te->subtree)) return 1;
+ if (subtree_has_objects(&te->subtree)) return 1;
}
return 0;
}
@@ -1378,7 +1294,7 @@ static void tree_element_show_hierarchy(Scene *scene, SpaceOops *soops, ListBase
else tselem->flag &= ~TSE_CLOSED;
}
else if (te->idcode == ID_OB) {
- if (subtree_has_objects(soops, &te->subtree)) tselem->flag &= ~TSE_CLOSED;
+ if (subtree_has_objects(&te->subtree)) tselem->flag &= ~TSE_CLOSED;
else tselem->flag |= TSE_CLOSED;
}
}
@@ -1930,7 +1846,7 @@ static int outliner_orphans_purge_invoke(bContext *C, wmOperator *op, const wmEv
{
/* present a prompt to informing users that this change is irreversible */
return WM_operator_confirm_message(C, op,
- "Purging unused datablocks cannot be undone. "
+ "Purging unused data-blocks cannot be undone and saves to current .blend file. "
"Click here to proceed...");
}
@@ -1952,7 +1868,8 @@ void OUTLINER_OT_orphans_purge(wmOperatorType *ot)
/* identifiers */
ot->idname = "OUTLINER_OT_orphans_purge";
ot->name = "Purge All";
- ot->description = "Clear all orphaned datablocks without any users from the file (cannot be undone)";
+ ot->description = "Clear all orphaned data-blocks without any users from the file "
+ "(cannot be undone, saves to current .blend file)";
/* callbacks */
ot->invoke = outliner_orphans_purge_invoke;
@@ -1989,7 +1906,7 @@ static int parent_drop_exec(bContext *C, wmOperator *op)
ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, false, false, NULL);
- 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);
@@ -2005,6 +1922,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Main *bmain = CTX_data_main(C);
Scene *scene = NULL;
TreeElement *te = NULL;
+ TreeStoreElem *tselem;
char childname[MAX_ID_NAME];
char parname[MAX_ID_NAME];
int partype = 0;
@@ -2014,8 +1932,21 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* Find object hovered over */
te = outliner_dropzone_find(soops, fmval, true);
+ tselem = te ? TREESTORE(te) : NULL;
- if (te) {
+ if (tselem && ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION)) {
+ SceneCollection *sc = outliner_scene_collection_from_tree_element(te);
+
+ scene = BKE_scene_find_from_collection(bmain, sc);
+ BLI_assert(scene);
+ RNA_string_get(op->ptr, "child", childname);
+ ob = (Object *)BKE_libblock_find_name(ID_OB, childname);
+ BKE_collection_object_add(scene, sc, ob);
+
+ DEG_relations_tag_update(bmain);
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
+ }
+ else if (te) {
RNA_string_set(op->ptr, "parent", te->name);
/* Identify parent and child */
RNA_string_get(op->ptr, "child", childname);
@@ -2048,7 +1979,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
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);
+ 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);
}
@@ -2058,74 +1989,62 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
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;
- WM_operator_properties_create_ptr(&ptr, ot);
+ /* Cannot use uiItemEnumO()... have multiple properties to set. */
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_("Object"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_OBJECT);
- /* Cannot use uiItemEnumO()... have multiple properties to set. */
- uiItemFullO_ptr(layout, ot, IFACE_("Object"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
-
+
/* par becomes parent, make the associated menus */
if (par->type == OB_ARMATURE) {
- WM_operator_properties_create_ptr(&ptr, ot);
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_("Armature Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_ARMATURE);
- uiItemFullO_ptr(layout, ot, IFACE_("Armature Deform"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
-
- WM_operator_properties_create_ptr(&ptr, ot);
+
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_(" With Empty Groups"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
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 Empty Groups"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
-
- WM_operator_properties_create_ptr(&ptr, ot);
+
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_(" With Envelope Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
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 Envelope Weights"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
-
- WM_operator_properties_create_ptr(&ptr, ot);
+
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_(" With Automatic Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
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_(" With Automatic Weights"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
-
- WM_operator_properties_create_ptr(&ptr, ot);
+
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_("Bone"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_BONE);
- uiItemFullO_ptr(layout, ot, IFACE_("Bone"),
- 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
}
else if (par->type == OB_CURVE) {
- WM_operator_properties_create_ptr(&ptr, ot);
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_("Curve Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_CURVE);
- uiItemFullO_ptr(layout, ot, IFACE_("Curve Deform"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
-
- WM_operator_properties_create_ptr(&ptr, ot);
+
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_("Follow Path"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_FOLLOW);
- uiItemFullO_ptr(layout, ot, IFACE_("Follow Path"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
-
- WM_operator_properties_create_ptr(&ptr, ot);
+
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_("Path Constraint"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_PATH_CONST);
- uiItemFullO_ptr(layout, ot, IFACE_("Path Constraint"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
}
else if (par->type == OB_LATTICE) {
- WM_operator_properties_create_ptr(&ptr, ot);
+ ptr = uiItemFullO_ptr(layout, ot, IFACE_("Lattice Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_LATTICE);
- uiItemFullO_ptr(layout, ot, IFACE_("Lattice Deform"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
}
UI_popup_menu_end(C, pup);
@@ -2188,7 +2107,7 @@ static int parent_clear_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
ED_object_parent_clear(ob, RNA_enum_get(op->ptr, "type"));
- 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;
@@ -2231,8 +2150,6 @@ static int scene_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
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(ID_SCE, te->name);
@@ -2243,19 +2160,29 @@ static int scene_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
- base = ED_object_scene_link(scene, ob);
-
- if (base == NULL) {
+ if (BKE_scene_has_object(scene, ob)) {
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);
+ SceneCollection *sc;
+ if (scene != CTX_data_scene(C)) {
+ /* when linking to an inactive scene link to the master collection */
+ sc = BKE_collection_master(scene);
+ }
+ else {
+ sc = CTX_data_scene_collection(C);
}
- DAG_relations_tag_update(bmain);
+ BKE_collection_object_add(scene, sc, ob);
+
+ for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
+ Base *base = BKE_scene_layer_base_find(sl, ob);
+ if (base) {
+ ED_object_base_select(base, BA_SELECT);
+ }
+ }
+
+ DEG_relations_tag_update(bmain);
WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene);
@@ -2347,7 +2274,6 @@ 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;
@@ -2377,7 +2303,7 @@ static int group_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
- BKE_group_object_add(group, ob, scene, NULL);
+ BKE_group_object_add(group, ob);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index ca037cb20cc..f046e1c3176 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -37,13 +37,50 @@
/* internal exports only */
struct wmOperatorType;
+struct TreeElement;
struct TreeStoreElem;
+struct Main;
struct bContext;
struct Scene;
+struct SceneLayer;
struct ID;
struct Object;
struct bPoseChannel;
struct EditBone;
+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;
+
+/**
+ * Callback type for reinserting elements at a different position, used to allow user customizable element order.
+ * Passing scene right now, may be better to allow some custom data.
+ */
+typedef void (*TreeElementReinsertFunc)(struct Main *bmain, const struct Scene *scene,
+ struct TreeElement *insert_element,
+ struct TreeElement *insert_handle, TreeElementInsertType action);
+/**
+ * Executed on (almost) each mouse move while dragging. It's supposed to give info
+ * if reinserting insert_element before/after/into insert_handle would be allowed.
+ * It's allowed to change the reinsert info here for non const pointers.
+ */
+typedef bool (*TreeElementReinsertPollFunc)(const struct Scene *scene, const struct TreeElement *insert_element,
+ struct TreeElement **io_insert_handle, TreeElementInsertType *io_action);
+typedef TreeTraversalAction (*TreeTraversalFunc)(struct TreeElement *te, void *customdata);
+
typedef struct TreeElement {
struct TreeElement *next, *prev, *parent;
@@ -57,18 +94,32 @@ typedef struct TreeElement {
const char *name;
void *directdata; // Armature Bones, Base, Sequence, Strip...
PointerRNA rnaptr; // RNA Pointer
-} TreeElement;
+
+ /* callbacks - TODO should be moved into a type (like TreeElementType) */
+ TreeElementReinsertFunc reinsert;
+ TreeElementReinsertPollFunc reinsert_poll;
+
+ struct {
+ TreeElementInsertType insert_type;
+ /* the element before/after/into which we may insert the dragged one (NULL to insert at top) */
+ struct TreeElement *insert_handle;
+ } *drag_data;
+} TreeElement;
#define TREESTORE_ID_TYPE(_id) \
(ELEM(GS((_id)->name), ID_SCE, ID_LI, ID_OB, ID_ME, ID_CU, ID_MB, ID_NT, ID_MA, ID_TE, ID_IM, ID_LT, ID_LA, ID_CA) || \
- ELEM(GS((_id)->name), ID_KE, ID_WO, ID_SPK, ID_GR, ID_AR, ID_AC, ID_BR, ID_PA, ID_GD, ID_LS) || \
- ELEM(GS((_id)->name), ID_SCR, ID_WM, ID_TXT, ID_VF, ID_SO, ID_CF)) /* 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_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),
+};
/* button events */
#define OL_NAMEBUTTON 1
@@ -129,15 +180,9 @@ typedef enum {
void outliner_free_tree(ListBase *lb);
void outliner_cleanup_tree(struct SpaceOops *soops);
+void outliner_remove_treestore_element(struct SpaceOops *soops, TreeStoreElem *tselem);
-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(struct SpaceOops *soops, ListBase *lb, const struct bPoseChannel *pchan);
-TreeElement *outliner_find_editbone(struct SpaceOops *soops, 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 SpaceOops *soops);
+void outliner_build_tree(struct Main *mainvar, struct Scene *scene, struct SceneLayer *sl, struct SpaceOops *soops);
/* outliner_draw.c ---------------------------------------------- */
@@ -146,11 +191,11 @@ void restrictbutton_gr_restrict_flag(void *poin, void *poin2, int flag);
/* outliner_select.c -------------------------------------------- */
eOLDrawState tree_element_type_active(
- struct bContext *C, struct Scene *scene, struct SpaceOops *soops,
+ struct bContext *C, struct Scene *scene, struct SceneLayer *sl, 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 SceneLayer *sl, SpaceOops *soops,
TreeElement *te, const eOLSetState set, const bool handle_all_types);
-int outliner_item_do_activate(struct bContext *C, int x, int y, bool extend, bool recursive);
+int outliner_item_activate_or_toggle_closed(struct bContext *C, int x, int y, bool extend, bool recursive);
/* outliner_edit.c ---------------------------------------------- */
typedef void (*outliner_operation_cb)(
@@ -158,16 +203,16 @@ typedef void (*outliner_operation_cb)(
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_has_one_flag(struct SpaceOops *soops, ListBase *lb, short flag, const int curlevel);
-void outliner_set_flag(struct SpaceOops *soops, ListBase *lb, short flag, short set);
+int outliner_has_one_flag(ListBase *lb, short flag, const int curlevel);
+bool outliner_set_flag(ListBase *lb, short flag, short set);
void object_toggle_visibility_cb(
struct bContext *C, struct ReportList *reports, struct Scene *scene,
@@ -208,8 +253,11 @@ void id_remap_cb(
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 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);
@@ -229,10 +277,6 @@ 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);
@@ -261,10 +305,40 @@ 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);
+void OUTLINER_OT_collection_operation(struct wmOperatorType *ot);
/* ---------------------------------------------------------------- */
/* outliner_ops.c */
void outliner_operatortypes(void);
void outliner_keymap(struct wmKeyConfig *keyconf);
+/* outliner_collections.c */
+
+struct SceneCollection *outliner_scene_collection_from_tree_element(TreeElement *te);
+
+void OUTLINER_OT_collections_delete(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_select(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_link(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_unlink(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_new(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_override_new(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_objects_add(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_objects_remove(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_objects_select(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_objects_deselect(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_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 776717c8443..5466ef1a9ed 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.c
@@ -28,25 +28,265 @@
* \ingroup spoutliner
*/
-#include "DNA_space_types.h"
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+
+#include "ED_screen.h"
+
+#include "MEM_guardedalloc.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"
+enum {
+ OUTLINER_ITEM_DRAG_CANCEL,
+ OUTLINER_ITEM_DRAG_CONFIRM,
+};
+
+static int outliner_item_drag_drop_poll(bContext *C)
+{
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ return ED_operator_outliner_active(C) &&
+ /* Only collection display modes supported for now. Others need more design work */
+ ELEM(soops->outlinevis, SO_ACT_LAYER, SO_COLLECTIONS);
+}
+
+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 void outliner_item_drag_end(TreeElement *dragged_te)
+{
+ MEM_SAFE_FREE(dragged_te->drag_data);
+}
+
+static void outliner_item_drag_get_insert_data(
+ const SpaceOops *soops, ARegion *ar, const wmEvent *event, TreeElement *te_dragged,
+ TreeElement **r_te_insert_handle, TreeElementInsertType *r_insert_type)
+{
+ 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 */
+
+ if (te_hovered == te_dragged) {
+ *r_te_insert_handle = te_dragged;
+ }
+ else if (te_hovered != te_dragged) {
+ const float margin = UI_UNIT_Y * (1.0f / 4);
+
+ *r_te_insert_handle = te_hovered;
+ 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;
+ }
+ else {
+ *r_insert_type = TE_INSERT_BEFORE;
+ *r_te_insert_handle = te_hovered->subtree.first;
+ }
+ }
+ else {
+ *r_insert_type = TE_INSERT_AFTER;
+ }
+ }
+ else if (view_mval[1] > (te_hovered->ys + (3 * margin))) {
+ *r_insert_type = TE_INSERT_BEFORE;
+ }
+ else {
+ *r_insert_type = TE_INSERT_INTO;
+ }
+ }
+ }
+ 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_te_insert_handle = last;
+ *r_insert_type = TE_INSERT_AFTER;
+ }
+ else if (view_mval[1] > (first->ys + UI_UNIT_Y)) {
+ *r_te_insert_handle = first;
+ *r_insert_type = TE_INSERT_BEFORE;
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+}
+
+static void outliner_item_drag_handle(
+ const Scene *scene, SpaceOops *soops, ARegion *ar, const wmEvent *event, TreeElement *te_dragged)
+{
+ TreeElement *te_insert_handle;
+ TreeElementInsertType insert_type;
+
+ outliner_item_drag_get_insert_data(soops, ar, event, te_dragged, &te_insert_handle, &insert_type);
+
+ if (!te_dragged->reinsert_poll &&
+ /* there is no reinsert_poll, so we do some generic checks (same types and reinsert callback is available) */
+ (TREESTORE(te_dragged)->type == TREESTORE(te_insert_handle)->type) &&
+ te_dragged->reinsert)
+ {
+ /* pass */
+ }
+ else if (te_dragged == te_insert_handle) {
+ /* nothing will happen anyway, no need to do poll check */
+ }
+ else if (!te_dragged->reinsert_poll ||
+ !te_dragged->reinsert_poll(scene, te_dragged, &te_insert_handle, &insert_type))
+ {
+ te_insert_handle = NULL;
+ }
+ te_dragged->drag_data->insert_type = insert_type;
+ te_dragged->drag_data->insert_handle = te_insert_handle;
+}
+
+static bool outliner_item_drag_drop_apply(Main *bmain, const Scene *scene, TreeElement *dragged_te)
+{
+ TreeElement *insert_handle = dragged_te->drag_data->insert_handle;
+ TreeElementInsertType insert_type = dragged_te->drag_data->insert_type;
+
+ if ((insert_handle == dragged_te) || !insert_handle) {
+ /* No need to do anything */
+ }
+ else if (dragged_te->reinsert) {
+ BLI_assert(!dragged_te->reinsert_poll || dragged_te->reinsert_poll(scene, dragged_te, &insert_handle,
+ &insert_type));
+ /* call of assert above should not have changed insert_handle and insert_type at this point */
+ BLI_assert(dragged_te->drag_data->insert_handle == insert_handle &&
+ dragged_te->drag_data->insert_type == insert_type);
+ dragged_te->reinsert(bmain, scene, dragged_te, insert_handle, insert_type);
+ return true;
+ }
+
+ return false;
+}
+
+static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ARegion *ar = CTX_wm_region(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ TreeElement *te_dragged = op->customdata;
+ int retval = OPERATOR_RUNNING_MODAL;
+ bool redraw = false;
+ bool skip_rebuild = true;
+
+ switch (event->type) {
+ case EVT_MODAL_MAP:
+ if (event->val == OUTLINER_ITEM_DRAG_CONFIRM) {
+ if (outliner_item_drag_drop_apply(bmain, scene, te_dragged)) {
+ skip_rebuild = false;
+ }
+ retval = OPERATOR_FINISHED;
+ }
+ else if (event->val == OUTLINER_ITEM_DRAG_CANCEL) {
+ retval = OPERATOR_CANCELLED;
+ }
+ else {
+ BLI_assert(0);
+ }
+ WM_event_add_mousemove(C); /* update highlight */
+ outliner_item_drag_end(te_dragged);
+ redraw = true;
+ break;
+ case MOUSEMOVE:
+ outliner_item_drag_handle(scene, soops, ar, event, te_dragged);
+ redraw = true;
+ break;
+ }
+
+ if (skip_rebuild) {
+ soops->storeflag |= SO_TREESTORE_REDRAW; /* only needs to redraw, no rebuild */
+ }
+ if (redraw) {
+ ED_region_tag_redraw(ar);
+ }
+
+ return retval;
+}
+
+static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ TreeElement *te_dragged = outliner_item_drag_element_find(soops, ar, event);
+
+ if (!te_dragged) {
+ return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
+ }
+
+ op->customdata = te_dragged;
+ te_dragged->drag_data = MEM_callocN(sizeof(*te_dragged->drag_data), __func__);
+ /* by default we don't change the item position */
+ te_dragged->drag_data->insert_handle = te_dragged;
+ /* unset highlighted tree element, dragged one will be highlighted instead */
+ outliner_set_flag(&soops->tree, TSE_HIGHLIGHTED, false);
+
+ soops->storeflag |= SO_TREESTORE_REDRAW; /* only needs to redraw, no rebuild */
+ ED_region_tag_redraw(ar);
+
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/**
+ * Notes about Outliner Item Drag 'n Drop:
+ * Right now only collections display mode is supported. But ideally all/most modes would support this. There are
+ * just some open design questions that have to be answered: do we want to allow mixing order of different data types
+ * (like render-layers and objects)? Would that be a purely visual change or would that have any other effect? ...
+ */
+static void OUTLINER_OT_item_drag_drop(wmOperatorType *ot)
+{
+ ot->name = "Drag and Drop Item";
+ ot->idname = "OUTLINER_OT_item_drag_drop";
+ ot->description = "Change the hierarchical position of an item by repositioning it using drag and drop";
+
+ ot->invoke = outliner_item_drag_drop_invoke;
+ ot->modal = outliner_item_drag_drop_modal;
+
+ ot->poll = outliner_item_drag_drop_poll;
+
+ ot->flag = OPTYPE_UNDO;
+}
+
+
/* ************************** 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_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);
@@ -61,6 +301,7 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_action_set);
WM_operatortype_append(OUTLINER_OT_constraint_operation);
WM_operatortype_append(OUTLINER_OT_modifier_operation);
+ WM_operatortype_append(OUTLINER_OT_collection_operation);
WM_operatortype_append(OUTLINER_OT_show_one_level);
WM_operatortype_append(OUTLINER_OT_show_active);
@@ -70,10 +311,6 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_selected_toggle);
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);
@@ -87,13 +324,57 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_scene_drop);
WM_operatortype_append(OUTLINER_OT_material_drop);
WM_operatortype_append(OUTLINER_OT_group_link);
+
+ /* collections */
+ WM_operatortype_append(OUTLINER_OT_collections_delete);
+ WM_operatortype_append(OUTLINER_OT_collection_select);
+ WM_operatortype_append(OUTLINER_OT_collection_link);
+ WM_operatortype_append(OUTLINER_OT_collection_unlink);
+ WM_operatortype_append(OUTLINER_OT_collection_new);
+ WM_operatortype_append(OUTLINER_OT_collection_override_new);
+ WM_operatortype_append(OUTLINER_OT_collection_objects_add);
+ WM_operatortype_append(OUTLINER_OT_collection_objects_remove);
+ WM_operatortype_append(OUTLINER_OT_collection_objects_select);
+ WM_operatortype_append(OUTLINER_OT_collection_objects_deselect);
+}
+
+static wmKeyMap *outliner_item_drag_drop_modal_keymap(wmKeyConfig *keyconf)
+{
+ static EnumPropertyItem modal_items[] = {
+ {OUTLINER_ITEM_DRAG_CANCEL, "CANCEL", 0, "Cancel", ""},
+ {OUTLINER_ITEM_DRAG_CONFIRM, "CONFIRM", 0, "Confirm/Drop", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ const char *map_name = "Outliner Item Drap 'n Drop Modal Map";
+
+ wmKeyMap *keymap = WM_modalkeymap_get(keyconf, map_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, map_name, modal_items);
+
+ /* items for modal map */
+ WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, OUTLINER_ITEM_DRAG_CANCEL);
+ WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, OUTLINER_ITEM_DRAG_CANCEL);
+
+ WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, OUTLINER_ITEM_DRAG_CONFIRM);
+ WM_modalkeymap_add_item(keymap, RETKEY, KM_RELEASE, KM_ANY, 0, OUTLINER_ITEM_DRAG_CONFIRM);
+ WM_modalkeymap_add_item(keymap, PADENTER, KM_RELEASE, KM_ANY, 0, OUTLINER_ITEM_DRAG_CONFIRM);
+
+ WM_modalkeymap_assign(keymap, "OUTLINER_OT_item_drag_drop");
+
+ return keymap;
}
void outliner_keymap(wmKeyConfig *keyconf)
{
wmKeyMap *keymap = WM_keymap_find(keyconf, "Outliner", SPACE_OUTLINER, 0);
wmKeyMapItem *kmi;
-
+
+ WM_keymap_add_item(keymap, "OUTLINER_OT_highlight_update", MOUSEMOVE, KM_ANY, KM_ANY, 0);
+
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);
@@ -123,6 +404,8 @@ void outliner_keymap(wmKeyConfig *keyconf)
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_item_drag_drop", EVT_TWEAK_L, KM_ANY, 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);
@@ -140,11 +423,6 @@ void outliner_keymap(wmKeyConfig *keyconf)
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);
@@ -154,5 +432,7 @@ void outliner_keymap(wmKeyConfig *keyconf)
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);
+
+ outliner_item_drag_drop_modal_keymap(keyconf);
}
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 21bee2c7cce..d9590d2af7f 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -44,12 +44,14 @@
#include "BLI_listbase.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_object.h"
+#include "BKE_layer.h"
#include "BKE_scene.h"
#include "BKE_sequencer.h"
#include "BKE_armature.h"
+#include "DEG_depsgraph.h"
+
#include "ED_armature.h"
#include "ED_object.h"
#include "ED_screen.h"
@@ -68,61 +70,12 @@
#include "outliner_intern.h"
-/* ****************************************************** */
-/* Outliner Selection (gray-blue highlight for rows) */
-
-static int outliner_select(SpaceOops *soops, ListBase *lb, int *index, short *selecting)
-{
- 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;
- }
-
- /* set selection */
- if (*selecting)
- tselem->flag |= TSE_SELECTED;
- else
- tselem->flag &= ~TSE_SELECTED;
-
- changed |= true;
- }
- }
- 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)++;
- }
- }
-
- return changed;
-}
/* ****************************************************** */
/* Outliner Element Selection/Activation on Click */
static eOLDrawState tree_element_active_renderlayer(
- bContext *C, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set)
+ bContext *C, Scene *UNUSED(scene), SceneLayer *UNUSED(sl), TreeElement *te, TreeStoreElem *tselem, const eOLSetState set)
{
Scene *sce;
@@ -146,14 +99,14 @@ static eOLDrawState tree_element_active_renderlayer(
* CTRL+LMB: Select/Deselect object and all cildren
* 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(SceneLayer *sl, Object *ob_parent, bool select)
{
Base *base;
- for (base = FIRSTBASE; base; base = base->next) {
+ for (base = FIRSTBASE_NEW; 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_VISIBLED) == 0) && BKE_object_is_child_recursive(ob_parent, ob))) {
+ ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT);
}
}
}
@@ -184,7 +137,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, SceneLayer *sl, SpaceOops *soops,
TreeElement *te, const eOLSetState set, bool recursive)
{
TreeStoreElem *tselem = TREESTORE(te);
@@ -198,7 +151,7 @@ static eOLDrawState tree_element_set_active_object(
}
else {
ob = (Object *)outliner_search_back(soops, te, ID_OB);
- if (ob == OBACT) {
+ if (ob == OBACT_NEW) {
return OL_DRAWSEL_NONE;
}
}
@@ -208,34 +161,34 @@ 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_change_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_scene_layer_base_find(sl, ob);
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);
+ BKE_scene_layer_base_deselect_all(sl);
+ 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(sl, ob, (ob->flag & SELECT) != 0);
}
- if (C) {
- ED_base_object_activate(C, base); /* adds notifier */
+ if (set != OL_SETSEL_NONE) {
+ ED_object_base_activate(C, base); /* adds notifier */
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
}
@@ -247,7 +200,7 @@ static eOLDrawState tree_element_set_active_object(
}
static eOLDrawState tree_element_active_material(
- bContext *C, Scene *scene, SpaceOops *soops,
+ bContext *C, Scene *UNUSED(scene), SceneLayer *sl, SpaceOops *soops,
TreeElement *te, const eOLSetState set)
{
TreeElement *tes;
@@ -256,7 +209,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_NEW || ob->matbits == NULL) {
return OL_DRAWSEL_NONE; /* just paranoia */
}
@@ -293,19 +246,19 @@ 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),
+ bContext *C, Scene *scene, SceneLayer *sl, SpaceOops *UNUSED(soops),
TreeElement *te, const eOLSetState set)
{
TreeElement *tep;
TreeStoreElem /* *tselem,*/ *tselemp;
- Object *ob = OBACT;
+ Object *ob = OBACT_NEW;
SpaceButs *sbuts = NULL;
if (ob == NULL) {
@@ -387,14 +340,14 @@ static eOLDrawState tree_element_active_texture(
static eOLDrawState tree_element_active_lamp(
- bContext *UNUSED(C), Scene *scene, SpaceOops *soops,
+ bContext *UNUSED(C), Scene *UNUSED(scene), SceneLayer *sl, 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_NEW) {
/* just paranoia */
return OL_DRAWSEL_NONE;
}
@@ -410,7 +363,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, SceneLayer *UNUSED(sl), SpaceOops *soops,
TreeElement *te, const eOLSetState set)
{
Object *ob = (Object *)outliner_search_back(soops, te, ID_OB);
@@ -423,7 +376,7 @@ static eOLDrawState tree_element_active_camera(
}
static eOLDrawState tree_element_active_world(
- bContext *C, Scene *scene, SpaceOops *UNUSED(soops),
+ bContext *C, Scene *scene, SceneLayer *UNUSED(sl), SpaceOops *UNUSED(soops),
TreeElement *te, const eOLSetState set)
{
TreeElement *tep;
@@ -440,7 +393,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_change_active_scene(CTX_data_main(C), C, CTX_wm_window(C), sce);
}
}
@@ -456,7 +409,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, SceneLayer *sl, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set)
{
Object *ob;
@@ -466,11 +419,11 @@ 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_NEW)
if (ob->actdef == te->index + 1) {
return OL_DRAWSEL_NORMAL;
}
@@ -479,7 +432,7 @@ static eOLDrawState tree_element_active_defgroup(
}
static eOLDrawState tree_element_active_posegroup(
- bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set)
+ bContext *C, Scene *UNUSED(scene), SceneLayer *sl, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set)
{
Object *ob = (Object *)tselem->id;
@@ -490,7 +443,7 @@ static eOLDrawState tree_element_active_posegroup(
}
}
else {
- if (ob == OBACT && ob->pose) {
+ if (ob == OBACT_NEW && ob->pose) {
if (ob->pose->active_group == te->index + 1) {
return OL_DRAWSEL_NORMAL;
}
@@ -500,7 +453,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), SceneLayer *sl, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive)
{
Object *ob = (Object *)tselem->id;
bArmature *arm = ob->data;
@@ -534,7 +487,7 @@ static eOLDrawState tree_element_active_posechannel(
}
}
else {
- if (ob == OBACT && ob->pose) {
+ if (ob == OBACT_NEW && ob->pose) {
if (pchan->bone->flag & BONE_SELECTED) {
return OL_DRAWSEL_NORMAL;
}
@@ -544,14 +497,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, SceneLayer *sl, 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_NEW;
if (ob) {
if (set != OL_SETSEL_EXTEND) {
/* single select forces all other bones to get unselected */
@@ -580,7 +533,7 @@ static eOLDrawState tree_element_active_bone(
}
}
else {
- Object *ob = OBACT;
+ Object *ob = OBACT_NEW;
if (ob && ob->data == arm) {
if (bone->flag & BONE_SELECTED) {
@@ -653,7 +606,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), SceneLayer *UNUSED(sl), TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set)
{
if (set != OL_SETSEL_NONE) {
Object *ob = (Object *)tselem->id;
@@ -681,7 +634,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), SceneLayer *UNUSED(sl), TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set)
{
if (set != OL_SETSEL_NONE) {
Object *ob = (Object *)tselem->id;
@@ -694,7 +647,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), SceneLayer *UNUSED(sl), SpaceOops *UNUSED(soops),
TreeElement *UNUSED(te), int UNUSED(set))
{
// XXX removed
@@ -702,11 +655,16 @@ 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, Scene *scene, SceneLayer *sl, TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set)
{
Object *ob = (Object *)tselem->id;
- Base *base = BKE_scene_base_find(scene, ob);
-
+ Base *base = BKE_scene_layer_base_find(sl, ob);
+
+ if (base == NULL) {
+ /* Armature not instantiated in current scene (e.g. inside an appended group...). */
+ return OL_DRAWSEL_NONE;
+ }
+
if (set != OL_SETSEL_NONE) {
if (scene->obedit)
ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
@@ -786,7 +744,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), SceneLayer *UNUSED(sl), TreeElement *te, TreeStoreElem *UNUSED(tselem), const eOLSetState set)
{
wmKeyMapItem *kmi = te->directdata;
@@ -802,10 +760,42 @@ static eOLDrawState tree_element_active_keymap_item(
return OL_DRAWSEL_NONE;
}
+static eOLDrawState tree_element_active_collection(
+ bContext *C, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set)
+{
+ if (set == OL_SETSEL_NONE) {
+ LayerCollection *active = CTX_data_layer_collection(C);
+
+ /* sometimes the renderlayer has no LayerCollection at all */
+ if (active == NULL) {
+ return OL_DRAWSEL_NONE;
+ }
+
+ if ((tselem->type == TSE_SCENE_COLLECTION && active->scene_collection == te->directdata) ||
+ (tselem->type == TSE_LAYER_COLLECTION && active == te->directdata))
+ {
+ return OL_DRAWSEL_NORMAL;
+ }
+ }
+ /* don't allow selecting a scene collection, it can have multiple layer collection
+ * instances (which one would the user want to be selected then?) */
+ else if (tselem->type == TSE_LAYER_COLLECTION) {
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ LayerCollection *lc = te->directdata;
+ const int collection_index = BKE_layer_collection_findindex(sl, lc);
+
+ BLI_assert(collection_index >= 0);
+ sl->active_collection = collection_index;
+ 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, SceneLayer *sl, SpaceOops *soops, TreeElement *te,
const eOLSetState set, const bool handle_all_types)
{
switch (te->idcode) {
@@ -813,236 +803,243 @@ eOLDrawState tree_element_active(bContext *C, Scene *scene, SpaceOops *soops, Tr
* 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, sl, 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, sl, soops, te, set);
case ID_WO:
- return tree_element_active_world(C, scene, soops, te, set);
+ return tree_element_active_world(C, scene, sl, soops, te, set);
case ID_LA:
- return tree_element_active_lamp(C, scene, soops, te, set);
+ return tree_element_active_lamp(C, scene, sl, soops, te, set);
case ID_TE:
- return tree_element_active_texture(C, scene, soops, te, set);
+ return tree_element_active_texture(C, scene, sl, soops, te, set);
case ID_TXT:
- return tree_element_active_text(C, scene, soops, te, set);
+ return tree_element_active_text(C, scene, sl, soops, te, set);
case ID_CA:
- return tree_element_active_camera(C, scene, soops, te, set);
+ return tree_element_active_camera(C, scene, sl, 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, SceneLayer *sl, 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, sl, te, tselem, set);
case TSE_BONE:
- return tree_element_active_bone(C, scene, te, tselem, set, recursive);
+ return tree_element_active_bone(C, sl, te, tselem, set, recursive);
case TSE_EBONE:
return tree_element_active_ebone(C, scene, te, tselem, set, recursive);
case TSE_MODIFIER:
- return tree_element_active_modifier(C, te, tselem, set);
+ return tree_element_active_modifier(C, scene, sl, 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, sl, soops, te, set, false);
}
- else if (tselem->id == (ID *)OBACT) {
+ else if (tselem->id == (ID *)OBACT_NEW) {
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, scene, sl, 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, sl, te, tselem, set, recursive);
case TSE_CONSTRAINT:
- return tree_element_active_constraint(C, te, tselem, set);
+ return tree_element_active_constraint(C, scene, sl, te, tselem, set);
case TSE_R_LAYER:
- return tree_element_active_renderlayer(C, te, tselem, set);
+ return tree_element_active_renderlayer(C, scene, sl, te, tselem, set);
case TSE_POSEGRP:
- return tree_element_active_posegroup(C, scene, te, tselem, set);
+ return tree_element_active_posegroup(C, scene, sl, 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, sl, 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_SCENE_COLLECTION:
+ case TSE_LAYER_COLLECTION:
+ return tree_element_active_collection(C, te, tselem, set);
}
return OL_DRAWSEL_NONE;
}
/* ================================================ */
-static bool do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, SpaceOops *soops,
- TreeElement *te, bool extend, bool recursive, const float mval[2])
+static void outliner_item_activate(
+ bContext *C, SpaceOops *soops, TreeElement *te,
+ const bool extend, const bool recursive)
{
-
- 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;
- }
-
- if (openclose) {
- /* all below close/open? */
- if (extend) {
- tselem->flag &= ~TSE_CLOSED;
- outliner_set_flag(soops, &te->subtree, TSE_CLOSED, !outliner_has_one_flag(soops, &te->subtree, TSE_CLOSED, 1));
- }
- else {
- if (tselem->flag & TSE_CLOSED) tselem->flag &= ~TSE_CLOSED;
- else tselem->flag |= TSE_CLOSED;
-
+ Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ /* 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, TSE_LAYER_COLLECTION)) {
+ tree_element_set_active_object(C, scene, sl, soops, te,
+ (extend && tselem->type == 0) ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL,
+ recursive && tselem->type == 0);
+ }
+
+ if (tselem->type == 0) { // the lib blocks
+ /* editmode? */
+ if (te->idcode == ID_SCE) {
+ if (scene != (Scene *)tselem->id) {
+ WM_window_change_active_scene(CTX_data_main(C), C, CTX_wm_window(C), (Scene *)tselem->id);
}
-
- return true;
}
- /* name and first icon */
- else if (mval[0] > te->xs + UI_UNIT_X && mval[0] < te->xend) {
+ else if (te->idcode == ID_GR) {
+ Group *gr = (Group *)tselem->id;
+ GroupObject *gob;
- /* 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)) {
- tree_element_set_active_object(C, scene, soops, te,
- (extend && tselem->type == 0) ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL,
- recursive && tselem->type == 0);
- }
-
- if (tselem->type == 0) { // the lib blocks
- /* editmode? */
- if (te->idcode == ID_SCE) {
- if (scene != (Scene *)tselem->id) {
- ED_screen_set_scene(C, CTX_wm_screen(C), (Scene *)tselem->id);
- }
- }
- else if (te->idcode == ID_GR) {
- Group *gr = (Group *)tselem->id;
- GroupObject *gob;
-
- if (extend) {
- int sel = BA_SELECT;
- for (gob = gr->gobject.first; gob; gob = gob->next) {
- if (gob->ob->flag & SELECT) {
- sel = BA_DESELECT;
- break;
- }
- }
-
- for (gob = gr->gobject.first; gob; gob = gob->next) {
- ED_base_object_select(BKE_scene_base_find(scene, gob->ob), sel);
- }
- }
- 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);
- }
+ if (extend) {
+ int sel = BA_SELECT;
+ for (gob = gr->gobject.first; gob; gob = gob->next) {
+ if (gob->ob->flag & SELECT) {
+ sel = BA_DESELECT;
+ break;
}
-
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
- }
- else if (ELEM(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) {
- WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL);
- }
- else { // rest of types
- tree_element_active(C, scene, soops, te, OL_SETSEL_NORMAL, false);
}
+ for (gob = gr->gobject.first; gob; gob = gob->next) {
+ ED_object_base_select(BKE_scene_layer_base_find(sl, gob->ob), sel);
+ }
}
else {
- tree_element_type_active(C, scene, soops, te, tselem,
- extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL,
- recursive);
+ BKE_scene_layer_base_deselect_all(sl);
+
+ for (gob = gr->gobject.first; gob; gob = gob->next) {
+ Base *base = BKE_scene_layer_base_find(sl, gob->ob);
+ /* Object may not be in this scene */
+ if (base != NULL) {
+ if ((base->flag & BASE_SELECTED) == 0) {
+ ED_object_base_select(base, BA_SELECT);
+ }
+ }
+ }
}
- return true;
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
- }
-
- for (te = te->subtree.first; te; te = te->next) {
- if (do_outliner_item_activate(C, scene, ar, soops, te, extend, recursive, mval)) {
- return true;
+ else if (ELEM(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) {
+ WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL);
+ }
+ else { // rest of types
+ tree_element_active(C, scene, sl, soops, te, OL_SETSEL_NORMAL, false);
}
+
+ }
+ else {
+ tree_element_type_active(C, scene, sl, soops, te, tselem,
+ extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL,
+ recursive);
}
- return false;
}
-int outliner_item_do_activate(bContext *C, int x, int y, bool extend, bool recursive)
+/**
+ * \param extend: Don't deselect other items, only modify \a te.
+ * \param toggle: Select \a te when not selected, deselect when selected.
+ */
+static void outliner_item_select(SpaceOops *soops, const TreeElement *te, const bool extend, const bool toggle)
+{
+ TreeStoreElem *tselem = TREESTORE(te);
+ const short new_flag = toggle ? (tselem->flag ^ TSE_SELECTED) : (tselem->flag | TSE_SELECTED);
+
+ if (extend == false) {
+ outliner_set_flag(&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;
+
+ const bool all_opened = !outliner_has_one_flag(&te->subtree, TSE_CLOSED, 1);
+ outliner_set_flag(&te->subtree, TSE_CLOSED, all_opened);
+ }
+ else {
+ tselem->flag ^= TSE_CLOSED;
+ }
+}
+
+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 (!ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF) &&
+ !(soops->flag & SO_HIDE_RESTRICTCOLS) &&
+ (view_co_x > ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX));
+}
+
+int outliner_item_activate_or_toggle_closed(bContext *C, int x, int y, 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, x, y, &fmval[0], &fmval[1]);
+ UI_view2d_region_to_view(&ar->v2d, x, y, &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(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)) {
-
+ /* 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]);
+
+ outliner_item_select(soops, activate_te, extend, extend);
+ outliner_item_activate(C, soops, activate_te, extend, recursive);
+ changed = true;
+ }
+
+ if (changed) {
+ if (!rebuild_tree) {
+ /* only needs to redraw, no rebuild */
soops->storeflag |= SO_TREESTORE_REDRAW;
-
- /* no need for undo push here, only changing outliner data which is
- * scene level - campbell */
- /* ED_undo_push(C, "Outliner selection event"); */
}
+ ED_undo_push(C, "Outliner selection change");
+ ED_region_tag_redraw(ar);
}
-
- 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");
int x = event->mval[0];
int y = event->mval[1];
- return outliner_item_do_activate(C, x, y, extend, recursive);
+ return outliner_item_activate_or_toggle_closed(C, x, y, extend, recursive);
}
void OUTLINER_OT_item_activate(wmOperatorType *ot)
@@ -1051,7 +1048,7 @@ void OUTLINER_OT_item_activate(wmOperatorType *ot)
ot->idname = "OUTLINER_OT_item_activate";
ot->description = "Handle mouse clicks to activate/select items";
- ot->invoke = outliner_item_activate;
+ ot->invoke = outliner_item_activate_invoke;
ot->poll = ED_operator_outliner_active;
@@ -1062,7 +1059,7 @@ void OUTLINER_OT_item_activate(wmOperatorType *ot)
/* ****************************************************** */
/* **************** Border Select Tool ****************** */
-static void outliner_item_border_select(Scene *scene, SpaceOops *soops, rctf *rectf, TreeElement *te, int gesture_mode)
+static void outliner_item_border_select(Scene *scene, rctf *rectf, TreeElement *te, int gesture_mode)
{
TreeStoreElem *tselem = TREESTORE(te);
@@ -1078,7 +1075,7 @@ static void outliner_item_border_select(Scene *scene, SpaceOops *soops, rctf *re
/* Look at its children. */
if ((tselem->flag & TSE_CLOSED) == 0) {
for (te = te->subtree.first; te; te = te->next) {
- outliner_item_border_select(scene, soops, rectf, te, gesture_mode);
+ outliner_item_border_select(scene, rectf, te, gesture_mode);
}
}
}
@@ -1096,7 +1093,7 @@ 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, soops, &rectf, te, gesture_mode);
+ outliner_item_border_select(scene, &rectf, te, gesture_mode);
}
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index e38886abeac..f2d73f40039 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -53,9 +53,9 @@
#include "BKE_animsys.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_query.h"
#include "BKE_library_remap.h"
@@ -64,8 +64,12 @@
#include "BKE_scene.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_util.h"
@@ -235,8 +239,7 @@ static void unlink_group_cb(
}
else {
Main *bmain = CTX_data_main(C);
- BKE_libblock_unlink(bmain, group, false, false);
- BKE_libblock_free(bmain, group);
+ BKE_libblock_delete(bmain, group);
}
}
@@ -309,7 +312,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 {
@@ -360,15 +363,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;
-
- 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;
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *ob = (Object *)tselem->id;
+ Base *base = BKE_scene_layer_base_find(sl, ob);
+
+ if (base && ((base->flag & BASE_VISIBLED) != 0)) {
+ base->flag |= BASE_SELECTED;
}
}
@@ -380,55 +383,61 @@ static void object_select_hierarchy_cb(
wmWindow *win = CTX_wm_window(C);
int x = win->eventstate->mval[0];
int y = win->eventstate->mval[1];
- outliner_item_do_activate(C, x, y, true, true);
+ outliner_item_activate_or_toggle_closed(C, x, y, true, true);
}
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;
-
- if (base == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id);
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *ob = (Object *)tselem->id;
+ Base *base = BKE_scene_layer_base_find(sl, ob);
+
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 *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+ TreeStoreElem *tsep, TreeStoreElem *tselem, void *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) {
+ 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 (scene->obedit == ob)
ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
- ED_base_object_free_and_unlink(CTX_data_main(C), scene, base);
+ ED_base_object_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(
@@ -442,6 +451,9 @@ static void id_local_cb(
if (id_make_local(bmain, tselem->id, false, false) == false) {
id_clear_lib_data(bmain, tselem->id);
}
+ else {
+ BKE_main_id_clear_newpoins(bmain);
+ }
}
}
@@ -510,22 +522,25 @@ static void singleuser_world_cb(
}
static void group_linkobs2scene_cb(
- bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
+ bContext *C, ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ SceneCollection *sc = CTX_data_scene_collection(C);
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);
+ base = BKE_scene_layer_base_find(sl, gob->ob);
if (!base) {
/* link to scene */
- base = BKE_scene_base_add(scene, gob->ob);
- id_lib_extern((ID *)gob->ob); /* in case these are from a linked group */
+ BKE_collection_object_add(scene, sc, gob->ob);
+ base = BKE_scene_layer_base_find(sl, gob->ob);
+ id_us_plus(&gob->ob->id);
}
- base->object->flag |= SELECT;
- base->flag |= SELECT;
+
+ base->flag |= BASE_SELECTED;
}
}
@@ -558,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_change_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
@@ -645,6 +660,14 @@ typedef enum eOutliner_PropModifierOps {
OL_MODIFIER_OP_DELETE
} eOutliner_PropModifierOps;
+typedef enum eOutliner_PropCollectionOps {
+ OL_COLLECTION_OP_OBJECTS_ADD = 1,
+ OL_COLLECTION_OP_OBJECTS_REMOVE,
+ OL_COLLECTION_OP_COLLECTION_NEW,
+ OL_COLLECTION_OP_COLLECTION_DEL,
+ OL_COLLECTION_OP_COLLECTION_UNLINK,
+} eOutliner_PropCollectionOps;
+
static void pchan_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg))
{
bPoseChannel *pchan = (bPoseChannel *)te->directdata;
@@ -780,12 +803,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) {
@@ -795,6 +818,63 @@ static void modifier_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem
}
}
+static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *Carg)
+{
+ bContext *C = (bContext *)Carg;
+ Scene *scene = CTX_data_scene(C);
+ LayerCollection *lc = te->directdata;
+ SceneCollection *sc = lc->scene_collection;
+
+ if (event == OL_COLLECTION_OP_OBJECTS_ADD) {
+ CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
+ {
+ BKE_collection_object_add(scene, sc, ob);
+ }
+ CTX_DATA_END;
+
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
+ }
+ else if (event == OL_COLLECTION_OP_OBJECTS_REMOVE) {
+ Main *bmain = CTX_data_main(C);
+
+ CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
+ {
+ BKE_collection_object_remove(bmain, scene, sc, ob, true);
+ }
+ CTX_DATA_END;
+
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
+ te->store_elem->flag &= ~TSE_SELECTED;
+ }
+ else if (event == OL_COLLECTION_OP_COLLECTION_NEW) {
+ BKE_collection_add(scene, sc, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
+ }
+ else if (event == OL_COLLECTION_OP_COLLECTION_UNLINK) {
+ SceneLayer *sl = CTX_data_scene_layer(C);
+
+ if (BLI_findindex(&sl->layer_collections, lc) == -1) {
+ /* we can't unlink if the layer collection wasn't directly linked */
+ TODO_LAYER_OPERATORS; /* this shouldn't be in the menu in those cases */
+ }
+ else {
+ BKE_collection_unlink(sl, lc);
+ DEG_relations_tag_update(CTX_data_main(C));
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
+ }
+ }
+ else if (event == OL_COLLECTION_OP_COLLECTION_DEL) {
+ if (BKE_collection_remove(scene, sc)) {
+ DEG_relations_tag_update(CTX_data_main(C));
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
+ }
+ else {
+ /* we can't remove the master collection */
+ TODO_LAYER_OPERATORS; /* this shouldn't be in the menu in those cases */
+ }
+ }
+}
+
static void outliner_do_data_operation(SpaceOops *soops, int type, int event, ListBase *lb,
void (*operation_cb)(int, TreeElement *, TreeStoreElem *, void *),
void *arg)
@@ -819,12 +899,13 @@ static Base *outline_delete_hierarchy(bContext *C, ReportList *reports, Scene *s
{
Base *child_base, *base_next;
Object *parent;
+ SceneLayer *scene_layer = CTX_data_scene_layer(C);
if (!base) {
return NULL;
}
- for (child_base = scene->base.first; child_base; child_base = base_next) {
+ for (child_base = scene_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) {
@@ -839,13 +920,15 @@ static Base *outline_delete_hierarchy(bContext *C, ReportList *reports, Scene *s
BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2);
return base_next;
}
- else if (BKE_library_ID_is_indirectly_used(bmain, base->object) && ID_REAL_USERS(base->object) <= 1) {
+ else if (BKE_library_ID_is_indirectly_used(bmain, base->object) &&
+ ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 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);
return base_next;
}
- ED_base_object_free_and_unlink(CTX_data_main(C), scene, base);
+ ED_base_object_free_and_unlink(CTX_data_main(C), scene, base->object);
return base_next;
}
@@ -853,11 +936,12 @@ static void object_delete_hierarchy_cb(
bContext *C, ReportList *reports, Scene *scene,
TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
+ SceneLayer *sl = CTX_data_scene_layer(C);
Base *base = (Base *)te->directdata;
Object *obedit = scene->obedit;
if (!base) {
- base = BKE_scene_base_find(scene, (Object *)tselem->id);
+ base = BKE_scene_layer_base_find(sl, (Object *)tselem->id);
}
if (base) {
/* Check also library later. */
@@ -900,7 +984,7 @@ static EnumPropertyItem prop_object_op_types[] = {
{OL_OP_DELETE, "DELETE", 0, "Delete", ""},
{OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""},
{OL_OP_REMAP, "REMAP", 0, "Remap Users",
- "Make all users of selected datablocks to use instead a new chosen one"},
+ "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", ""},
@@ -912,6 +996,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;
@@ -926,7 +1011,7 @@ 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_change_active_scene(bmain, C, win, sce);
}
str = "Select Objects";
@@ -936,8 +1021,8 @@ 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_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_change_active_scene(bmain, C, win, sce);
+ }
str = "Select Object Hierarchy";
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
@@ -956,7 +1041,7 @@ 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";
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
}
@@ -966,7 +1051,7 @@ 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";
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
}
@@ -978,21 +1063,6 @@ 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";
@@ -1044,9 +1114,9 @@ static 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", "WARNING: no undo"},
+ {OL_GROUPOP_DELETE, "DELETE", 0, "Delete Group", ""},
{OL_GROUPOP_REMAP, "REMAP", 0, "Remap Users",
- "Make all users of selected datablocks to use instead current (clicked) one"},
+ "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", ""},
@@ -1080,23 +1150,14 @@ static int outliner_group_operation_exec(bContext *C, wmOperator *op)
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));
+ DEG_relations_tag_update(CTX_data_main(C));
break;
case OL_GROUPOP_DELETE:
- WM_operator_name_call(C, "OUTLINER_OT_id_delete", WM_OP_INVOKE_REGION_WIN, NULL);
+ 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;
@@ -1153,9 +1214,9 @@ static EnumPropertyItem prop_id_op_types[] = {
{OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""},
{OUTLINER_IDOP_DELETE, "DELETE", 0, "Delete", "WARNING: no undo"},
{OUTLINER_IDOP_REMAP, "REMAP", 0, "Remap Users",
- "Make all users of selected datablocks to use instead current (clicked) one"},
+ "Make all users of selected data-blocks to use instead current (clicked) one"},
{OUTLINER_IDOP_FAKE_ADD, "ADD_FAKE", 0, "Add Fake User",
- "Ensure datablock gets saved even if it isn't in use (e.g. for motion and material libraries)"},
+ "Ensure data-block gets saved even if it isn't in use (e.g. for motion and material libraries)"},
{OUTLINER_IDOP_FAKE_CLEAR, "CLEAR_FAKE", 0, "Clear Fake User", ""},
{OUTLINER_IDOP_RENAME, "RENAME", 0, "Rename", ""},
{OUTLINER_IDOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""},
@@ -1247,6 +1308,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
{
if (idlevel > 0) {
outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL);
+ ED_undo_push(C, "Delete");
}
break;
}
@@ -1254,6 +1316,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
{
if (idlevel > 0) {
outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL);
+ ED_undo_push(C, "Remap");
}
break;
}
@@ -1362,18 +1425,20 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL);
WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
- ED_undo_push(C, "Rename");
+ ED_undo_push(C, "Rename Library");
break;
}
case OL_LIB_DELETE:
{
outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL);
+ ED_undo_push(C, "Delete Library");
break;
}
case OL_LIB_RELOCATE:
{
/* rename */
outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, lib_relocate_cb, NULL);
+ ED_undo_push(C, "Relocate Library");
break;
}
case OL_LIB_RELOAD:
@@ -1476,8 +1541,8 @@ static int outliner_action_set_exec(bContext *C, wmOperator *op)
else if (act->idroot == 0) {
/* hopefully in this case (i.e. library of userless actions), the user knows what they're doing... */
BKE_reportf(op->reports, RPT_WARNING,
- "Action '%s' does not specify what datablocks it can be used on "
- "(try setting the 'ID Root Type' setting from the Datablocks Editor "
+ "Action '%s' does not specify what data-blocks it can be used on "
+ "(try setting the 'ID Root Type' setting from the data-blocks editor "
"for this action to avoid future problems)",
act->id.name + 2);
}
@@ -1614,7 +1679,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;
@@ -1732,6 +1797,52 @@ void OUTLINER_OT_modifier_operation(wmOperatorType *ot)
/* ******************** */
+static EnumPropertyItem prop_collection_op_types[] = {
+ {OL_COLLECTION_OP_OBJECTS_ADD, "OBJECTS_ADD", ICON_ZOOMIN, "Add Selected", "Add selected objects to collection"},
+ {OL_COLLECTION_OP_OBJECTS_REMOVE, "OBJECTS_REMOVE", ICON_X, "Remove Selected", "Remove selected objects from collection"},
+ {OL_COLLECTION_OP_COLLECTION_NEW, "COLLECTION_NEW", ICON_NEW, "New Collection", "Add a new nested collection"},
+ {OL_COLLECTION_OP_COLLECTION_UNLINK, "COLLECTION_UNLINK", ICON_UNLINKED, "Unlink", "Unlink collection"},
+ {OL_COLLECTION_OP_COLLECTION_DEL, "COLLECTION_NEW", ICON_X, "Delete Collection", "Delete the collection"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int outliner_collection_operation_exec(bContext *C, wmOperator *op)
+{
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
+ eOutliner_PropCollectionOps event;
+
+ event = RNA_enum_get(op->ptr, "type");
+ set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
+
+ outliner_do_data_operation(soops, datalevel, event, &soops->tree, collection_cb, C);
+
+ outliner_cleanup_tree(soops);
+
+ ED_undo_push(C, "Collection operation");
+
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_collection_operation(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Outliner Collection Operation";
+ ot->idname = "OUTLINER_OT_collection_operation";
+ ot->description = "";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = outliner_collection_operation_exec;
+ ot->poll = ED_operator_outliner_active;
+
+ ot->flag = 0;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_collection_op_types, 0, "Collection Operation", "");
+}
+
+/* ******************** */
+
// XXX: select linked is for RNA structs only
static EnumPropertyItem prop_data_op_types[] = {
{OL_DOP_SELECT, "SELECT", 0, "Select", ""},
@@ -1832,8 +1943,8 @@ void OUTLINER_OT_data_operation(wmOperatorType *ot)
/* ******************** */
-static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, SpaceOops *soops,
- TreeElement *te, const wmEvent *event, const float mval[2])
+static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soops,
+ TreeElement *te, const float mval[2])
{
ReportList *reports = CTX_wm_reports(C); // XXX...
@@ -1844,8 +1955,8 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S
/* select object that's clicked on and popup context menu */
if (!(tselem->flag & TSE_SELECTED)) {
- if (outliner_has_one_flag(soops, &soops->tree, TSE_SELECTED, 1))
- outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 0);
+ if (outliner_has_one_flag(&soops->tree, TSE_SELECTED, 1))
+ outliner_set_flag(&soops->tree, TSE_SELECTED, 0);
tselem->flag |= TSE_SELECTED;
/* redraw, same as outliner_select function */
@@ -1906,6 +2017,9 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S
else if (datalevel == TSE_MODIFIER) {
WM_operator_name_call(C, "OUTLINER_OT_modifier_operation", WM_OP_INVOKE_REGION_WIN, NULL);
}
+ else if (datalevel == TSE_LAYER_COLLECTION) {
+ WM_operator_name_call(C, "OUTLINER_OT_collection_operation", WM_OP_INVOKE_REGION_WIN, NULL);
+ }
else {
WM_operator_name_call(C, "OUTLINER_OT_data_operation", WM_OP_INVOKE_REGION_WIN, NULL);
}
@@ -1916,7 +2030,7 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S
}
for (te = te->subtree.first; te; te = te->next) {
- if (do_outliner_operation_event(C, scene, ar, soops, te, event, mval))
+ if (do_outliner_operation_event(C, ar, soops, te, mval))
return 1;
}
return 0;
@@ -1925,7 +2039,6 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S
static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
- Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
uiBut *but = UI_context_active_but_get(C);
@@ -1939,7 +2052,7 @@ 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, scene, ar, soops, te, event, fmval)) {
+ if (do_outliner_operation_event(C, ar, soops, te, fmval)) {
break;
}
}
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index 96bab3d5c1e..568927425a9 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -46,6 +46,7 @@
#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"
@@ -63,12 +64,15 @@
#include "BKE_fcurve.h"
#include "BKE_main.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_modifier.h"
#include "BKE_sequencer.h"
#include "BKE_idcode.h"
#include "BKE_outliner_treehash.h"
+#include "DEG_depsgraph_build.h"
+
#include "ED_armature.h"
#include "ED_screen.h"
@@ -83,6 +87,9 @@
# include "BLI_math_base.h" /* M_PI */
#endif
+/* prototypes */
+static void outliner_make_hierarchy(ListBase *lb);
+
/* ********************************************************* */
/* Persistent Data */
@@ -199,105 +206,6 @@ 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(SpaceOops *soops, 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(soops, &te->subtree, pchan);
- if (tes) {
- return tes;
- }
- }
- }
- return NULL;
-}
-
-TreeElement *outliner_find_editbone(SpaceOops *soops, 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(soops, &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;
-}
-
/* ********************************************************* */
@@ -308,7 +216,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
/* -------------------------------------------------------- */
/* special handling of hierarchical non-lib data */
-static void outliner_add_bone(SpaceOops *soops, ListBase *lb, ID *id, Bone *curBone,
+static void outliner_add_bone(SpaceOops *soops, ListBase *lb, ID *id, Bone *curBone,
TreeElement *parent, int *a)
{
TreeElement *te = outliner_add_element(soops, lb, id, parent, TSE_BONE, *a);
@@ -483,12 +391,57 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s
#endif
}
+static void outliner_object_reorder(
+ Main *UNUSED(bmain), const Scene *scene,
+ TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action)
+{
+ TreeStoreElem *tselem_insert = TREESTORE(insert_element);
+ Object *ob = (Object *)tselem_insert->id;
+ SceneCollection *sc = outliner_scene_collection_from_tree_element(insert_handle);
+ SceneCollection *sc_ob_parent = NULL;
+
+ BLI_assert(action == TE_INSERT_INTO);
+ UNUSED_VARS_NDEBUG(action);
+
+ /* find parent scene-collection of object */
+ if (insert_element->parent) {
+ for (TreeElement *te_ob_parent = insert_element->parent; te_ob_parent; te_ob_parent = te_ob_parent->parent) {
+ if (ELEM(TREESTORE(te_ob_parent)->type, TSE_SCENE_COLLECTION, TSE_LAYER_COLLECTION)) {
+ sc_ob_parent = outliner_scene_collection_from_tree_element(te_ob_parent);
+ break;
+ }
+ }
+ }
+ else {
+ sc_ob_parent = BKE_collection_master(scene);
+ }
+ BKE_collection_object_move(scene, sc, sc_ob_parent, ob);
+}
+
+static bool outliner_object_reorder_poll(
+ const Scene *UNUSED(scene), const TreeElement *insert_element,
+ TreeElement **io_insert_handle, TreeElementInsertType *io_action)
+{
+ TreeStoreElem *tselem_handle = TREESTORE(*io_insert_handle);
+ if (ELEM(tselem_handle->type, TSE_SCENE_COLLECTION, TSE_LAYER_COLLECTION) &&
+ (insert_element->parent != *io_insert_handle))
+ {
+ *io_action = TE_INSERT_INTO;
+ return true;
+ }
+
+ return false;
+}
+
// can be inlined if necessary
static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, Object *ob)
{
+ te->reinsert = outliner_object_reorder;
+ te->reinsert_poll = outliner_object_reorder_poll;
+
if (outliner_animdata_test(ob->adt))
outliner_add_element(soops, &te->subtree, ob, te, TSE_ANIM_DATA, 0);
-
+
outliner_add_element(soops, &te->subtree, ob->poselib, te, 0, 0); // XXX FIXME.. add a special type for this
if (ob->proxy && !ID_IS_LINKED_DATABLOCK(ob))
@@ -778,6 +731,14 @@ 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;
@@ -887,7 +848,7 @@ static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStor
// TODO: this function needs to be split up! It's getting a bit too large...
// Note: "ID" is not always a real ID
-static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *idv,
+static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *idv,
TreeElement *parent, short type, short index)
{
TreeElement *te;
@@ -903,8 +864,8 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
id = TREESTORE(parent)->id;
}
- /* One exception */
- if (type == TSE_ID_BASE) {
+ /* exceptions */
+ if (ELEM(type, TSE_ID_BASE, TSE_LAYER_COLLECTION)) {
/* pass */
}
else if (id == NULL) {
@@ -941,6 +902,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)) {
+ /* pass */
+ }
else if (type == TSE_ID_BASE) {
/* pass */
}
@@ -1080,6 +1044,12 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
PointerRNA pptr, propptr, *ptr = (PointerRNA *)idv;
PropertyRNA *prop, *iterprop;
PropertyType proptype;
+
+ /* Don't display arrays larger, weak but index is stored as a short,
+ * also the outliner isn't intended for editing such large data-sets. */
+ BLI_STATIC_ASSERT(sizeof(te->index) == 2, "Index is no longer short!");
+ const int tot_limit = SHRT_MAX;
+
int a, tot;
/* we do lazy build, for speed and to avoid infinite recusion */
@@ -1101,6 +1071,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
iterprop = RNA_struct_iterator_property(ptr->type);
tot = RNA_property_collection_length(ptr, iterprop);
+ CLAMP_MAX(tot, tot_limit);
/* auto open these cases */
if (!parent || (RNA_property_type(parent->directdata)) == PROP_POINTER)
@@ -1108,8 +1079,12 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
tselem->flag &= ~TSE_CLOSED;
if (TSELEM_OPEN(tselem, soops)) {
- for (a = 0; a < tot; a++)
- outliner_add_element(soops, &te->subtree, (void *)ptr, te, TSE_RNA_PROPERTY, a);
+ for (a = 0; a < tot; a++) {
+ RNA_property_collection_lookup_int(ptr, iterprop, a, &propptr);
+ if (!(RNA_property_flag(propptr.data) & PROP_HIDDEN)) {
+ outliner_add_element(soops, &te->subtree, (void *)ptr, te, TSE_RNA_PROPERTY, a);
+ }
+ }
}
else if (tot)
te->flag |= TE_LAZY_CLOSED;
@@ -1143,6 +1118,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
}
else if (proptype == PROP_COLLECTION) {
tot = RNA_property_collection_length(ptr, prop);
+ CLAMP_MAX(tot, tot_limit);
if (TSELEM_OPEN(tselem, soops)) {
for (a = 0; a < tot; a++) {
@@ -1155,6 +1131,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
}
else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
tot = RNA_property_array_length(ptr, prop);
+ CLAMP_MAX(tot, tot_limit);
if (TSELEM_OPEN(tselem, soops)) {
for (a = 0; a < tot; a++)
@@ -1229,6 +1206,15 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
return te;
}
+/**
+ * \note Really only removes \a tselem, not it's TreeElement instance or any children.
+ */
+void outliner_remove_treestore_element(SpaceOops *soops, TreeStoreElem *tselem)
+{
+ BKE_outliner_treehash_remove_element(soops->treehash, tselem);
+ BLI_mempool_free(soops->treestore, tselem);
+}
+
/* ======================================================= */
/* Sequencer mode tree building */
@@ -1366,6 +1352,141 @@ static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops)
}
}
+static void outliner_layer_collections_reorder(
+ Main *bmain, const Scene *scene,
+ TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action)
+{
+ LayerCollection *lc_insert = insert_element->directdata;
+ LayerCollection *lc_handle = insert_handle->directdata;
+
+ if (action == TE_INSERT_BEFORE) {
+ BKE_layer_collection_move_above(scene, lc_handle, lc_insert);
+ }
+ else if (action == TE_INSERT_AFTER) {
+ BKE_layer_collection_move_below(scene, lc_handle, lc_insert);
+ }
+ else if (action == TE_INSERT_INTO) {
+ BKE_layer_collection_move_into(scene, lc_handle, lc_insert);
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ DEG_relations_tag_update(bmain);
+}
+static bool outliner_layer_collections_reorder_poll(
+ const Scene *UNUSED(scene), const TreeElement *UNUSED(insert_element),
+ TreeElement **io_insert_handle, TreeElementInsertType *UNUSED(io_action))
+{
+ const TreeStoreElem *tselem_handle = TREESTORE(*io_insert_handle);
+ return ELEM(tselem_handle->type, TSE_LAYER_COLLECTION);
+}
+
+static void outliner_add_layer_collections_recursive(
+ SpaceOops *soops, ListBase *tree, ListBase *layer_collections, TreeElement *parent_ten)
+{
+ for (LayerCollection *collection = layer_collections->first; collection; collection = collection->next) {
+ TreeElement *ten = outliner_add_element(soops, tree, collection, parent_ten, TSE_LAYER_COLLECTION, 0);
+
+ ten->name = collection->scene_collection->name;
+ ten->directdata = collection;
+ ten->reinsert = outliner_layer_collections_reorder;
+ ten->reinsert_poll = outliner_layer_collections_reorder_poll;
+
+ outliner_add_layer_collections_recursive(soops, &ten->subtree, &collection->layer_collections, ten);
+ for (LinkData *link = collection->object_bases.first; link; link = link->next) {
+ Base *base = (Base *)link->data;
+ TreeElement *te_object = outliner_add_element(soops, &ten->subtree, base->object, ten, 0, 0);
+ te_object->directdata = base;
+ }
+ outliner_make_hierarchy(&ten->subtree);
+ }
+}
+static void outliner_add_collections_act_layer(SpaceOops *soops, SceneLayer *layer)
+{
+ outliner_add_layer_collections_recursive(soops, &soops->tree, &layer->layer_collections, NULL);
+}
+
+static void outliner_scene_collections_reorder(
+ Main *bmain, const Scene *scene,
+ TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action)
+{
+ SceneCollection *sc_insert = insert_element->directdata;
+ SceneCollection *sc_handle = insert_handle->directdata;
+
+ BLI_assert((action == TE_INSERT_INTO) || (sc_handle != BKE_collection_master(scene)));
+ if (action == TE_INSERT_BEFORE) {
+ BKE_collection_move_above(scene, sc_handle, sc_insert);
+ }
+ else if (action == TE_INSERT_AFTER) {
+ BKE_collection_move_below(scene, sc_handle, sc_insert);
+ }
+ else if (action == TE_INSERT_INTO) {
+ BKE_collection_move_into(scene, sc_handle, sc_insert);
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ DEG_relations_tag_update(bmain);
+}
+static bool outliner_scene_collections_reorder_poll(
+ const Scene *scene, const TreeElement *UNUSED(insert_element),
+ TreeElement **io_insert_handle, TreeElementInsertType *io_action)
+{
+ const TreeStoreElem *tselem_handle = TREESTORE(*io_insert_handle);
+ SceneCollection *sc_master = BKE_collection_master(scene);
+ SceneCollection *sc_handle = (*io_insert_handle)->directdata;
+
+ if (!ELEM(tselem_handle->type, TSE_SCENE_COLLECTION)) {
+ return false;
+ }
+
+ if (sc_handle == sc_master) {
+ /* exception: Can't insert before/after master selection, has to be one of its childs */
+ TreeElement *te_master = *io_insert_handle;
+ if (*io_action == TE_INSERT_BEFORE) {
+ /* can't go higher than master collection, insert into it */
+ *io_action = TE_INSERT_INTO;
+ }
+ else if (*io_action == TE_INSERT_AFTER) {
+ *io_insert_handle = te_master->subtree.last;
+ }
+ }
+ return true;
+}
+
+static void outliner_add_scene_collection_objects(
+ SpaceOops *soops, ListBase *tree, SceneCollection *collection, TreeElement *parent)
+{
+ for (LinkData *link = collection->objects.first; link; link = link->next) {
+ outliner_add_element(soops, tree, link->data, parent, 0, 0);
+ }
+ outliner_make_hierarchy(tree);
+}
+
+static void outliner_add_scene_collections_recursive(
+ SpaceOops *soops, ListBase *tree, ListBase *scene_collections, TreeElement *parent_ten)
+{
+ for (SceneCollection *collection = scene_collections->first; collection; collection = collection->next) {
+ TreeElement *ten = outliner_add_element(soops, tree, collection, parent_ten, TSE_SCENE_COLLECTION, 0);
+
+ ten->name = collection->name;
+ ten->directdata = collection;
+ ten->reinsert = outliner_scene_collections_reorder;
+ ten->reinsert_poll = outliner_scene_collections_reorder_poll;
+
+ outliner_add_scene_collections_recursive(soops, &ten->subtree, &collection->scene_collections, ten);
+ outliner_add_scene_collection_objects(soops, &ten->subtree, collection, ten);
+ }
+}
+static void outliner_add_collections_master(SpaceOops *soops, Scene *scene)
+{
+ SceneCollection *master = BKE_collection_master(scene);
+ outliner_add_scene_collections_recursive(soops, &soops->tree, &master->scene_collections, NULL);
+ outliner_add_scene_collection_objects(soops, &soops->tree, master, NULL);
+}
+
/* ======================================================= */
/* Generic Tree Building helpers - order these are called is top to bottom */
@@ -1475,25 +1596,19 @@ static int treesort_obtype_alpha(const void *v1, const void *v2)
#endif
/* sort happens on each subtree individual */
-static void outliner_sort(SpaceOops *soops, ListBase *lb)
+static void outliner_sort(ListBase *lb)
{
TreeElement *te;
TreeStoreElem *tselem;
- int totelem = 0;
-
- if (soops->flag & SO_SKIP_SORT_ALPHA)
- return;
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");
tTreeSort *tp = tear;
@@ -1537,7 +1652,7 @@ static void outliner_sort(SpaceOops *soops, ListBase *lb)
}
for (te = lb->first; te; te = te->next) {
- outliner_sort(soops, &te->subtree);
+ outliner_sort(&te->subtree);
}
}
@@ -1618,9 +1733,8 @@ static int outliner_filter_tree(SpaceOops *soops, ListBase *lb)
/* 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, SceneLayer *sl, SpaceOops *soops)
{
- Base *base;
TreeElement *te = NULL, *ten;
TreeStoreElem *tselem;
int show_opened = !soops->treestore || !BLI_mempool_count(soops->treestore); /* on first view, we open scenes */
@@ -1644,11 +1758,6 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
outliner_free_tree(&soops->tree);
outliner_storage_cleanup(soops);
- /* clear ob id.new flags */
- for (Object *ob = mainvar->object.first; ob; ob = ob->id.next) {
- ob->id.newid = NULL;
- }
-
/* options */
if (soops->outlinevis == SO_LIBRARIES) {
Library *lib;
@@ -1706,31 +1815,42 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
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;
+
+ FOREACH_SCENE_OBJECT(scene, ob)
+ {
+ outliner_add_element(soops, &te->subtree, ob, te, 0, 0);
}
+ FOREACH_SCENE_OBJECT_END
+
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;
+ FOREACH_SCENE_OBJECT(scene, ob)
+ {
+ ob->id.newid = NULL;
+ }
+ FOREACH_SCENE_OBJECT_END
}
}
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;
+
+ FOREACH_SCENE_OBJECT(scene, ob)
+ {
+ outliner_add_element(soops, &soops->tree, ob, NULL, 0, 0);
}
+ FOREACH_SCENE_OBJECT_END
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);
+ FOREACH_VISIBLE_BASE(sl, base)
+ {
+ ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
+ ten->directdata = base;
+
}
+ FOREACH_VISIBLE_BASE_END
outliner_make_hierarchy(&soops->tree);
}
else if (soops->outlinevis == SO_GROUPS) {
@@ -1742,8 +1862,7 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
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_add_element(soops, &te->subtree, go->ob, te, 0, 0);
}
outliner_make_hierarchy(&te->subtree);
/* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */
@@ -1752,26 +1871,25 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
}
}
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;
+ Object *ob_active = OBACT_NEW;
+ if (ob_active) {
+ FOREACH_SCENE_OBJECT(scene, ob)
+ {
+ if (ob->type == ob_active->type) {
+ outliner_add_element(soops, &soops->tree, ob, NULL, 0, 0);
}
}
+ FOREACH_SCENE_OBJECT_END
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;
- }
- }
+ FOREACH_SELECTED_BASE(sl, base)
+ {
+ ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
+ ten->directdata = base;
}
+ FOREACH_SELECTED_BASE_END
outliner_make_hierarchy(&soops->tree);
}
else if (soops->outlinevis == SO_SEQUENCE) {
@@ -1825,13 +1943,23 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
else if (soops->outlinevis == SO_ID_ORPHANS) {
outliner_add_orphaned_datablocks(mainvar, soops);
}
+ else if (soops->outlinevis == SO_ACT_LAYER) {
+ outliner_add_collections_act_layer(soops, BKE_scene_layer_context_active_PLACEHOLDER(scene));
+ }
+ else if (soops->outlinevis == SO_COLLECTIONS) {
+ outliner_add_collections_master(soops, scene);
+ }
else {
- ten = outliner_add_element(soops, &soops->tree, OBACT, NULL, 0, 0);
- if (ten) ten->directdata = BASACT;
+ ten = outliner_add_element(soops, &soops->tree, OBACT_NEW, NULL, 0, 0);
+ ten->directdata = BASACT_NEW;
}
- outliner_sort(soops, &soops->tree);
+ if ((soops->flag & SO_SKIP_SORT_ALPHA) == 0) {
+ outliner_sort(&soops->tree);
+ }
outliner_filter_tree(soops, &soops->tree);
+
+ 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..f123b240efc
--- /dev/null
+++ b/source/blender/editors/space_outliner/outliner_utils.c
@@ -0,0 +1,234 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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 "BKE_outliner_treehash.h"
+
+#include "BLI_utildefines.h"
+
+#include "DNA_action_types.h"
+#include "DNA_space_types.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;
+}
+
+/* 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)
+{
+ 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 76bf9c701ed..346e567dd8d 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -102,10 +102,14 @@ static int outliner_parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *e
if (GS(id->name) == ID_OB) {
/* Ensure item under cursor is valid drop target */
TreeElement *te = outliner_dropzone_find(soops, fmval, true);
+ TreeStoreElem *tselem = te ? TREESTORE(te) : NULL;
- if (te && te->idcode == ID_OB && TREESTORE(te)->type == 0) {
+ if (!te) {
+ /* pass */
+ }
+ else if (te->idcode == ID_OB && tselem->type == 0) {
Scene *scene;
- ID *te_id = TREESTORE(te)->id;
+ ID *te_id = tselem->id;
/* check if dropping self or parent */
if (te_id == id || (Object *)te_id == ((Object *)id)->parent)
@@ -122,6 +126,10 @@ static int outliner_parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *e
return 1;
}
}
+ else if (ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION)) {
+ /* support adding object from different scene to collection */
+ return 1;
+ }
}
}
return 0;
@@ -292,7 +300,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(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -306,7 +316,9 @@ static void outliner_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(s
case ND_KEYINGSET:
case ND_FRAME:
case ND_RENDER_OPTIONS:
+ case ND_SEQUENCER:
case ND_LAYER:
+ case ND_LAYER_CONTENT:
case ND_WORLD:
ED_region_tag_redraw(ar);
break;
@@ -391,6 +403,11 @@ 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;
}
}
@@ -413,7 +430,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(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
diff --git a/source/blender/editors/space_script/space_script.c b/source/blender/editors/space_script/space_script.c
index 4228635ccd6..fb8de02d3bd 100644
--- a/source/blender/editors/space_script/space_script.c
+++ b/source/blender/editors/space_script/space_script.c
@@ -176,7 +176,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(
+ bScreen *UNUSED(sc), 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/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index ede6b7ce469..46f212e3679 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -38,6 +38,8 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+
#include "DNA_scene_types.h"
#include "DNA_mask_types.h"
@@ -445,6 +447,7 @@ void SEQUENCER_OT_movieclip_strip_add(struct wmOperatorType *ot)
sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME);
prop = RNA_def_enum(ot->srna, "clip", DummyRNA_NULL_items, 0, "Clip", "");
RNA_def_enum_funcs(prop, RNA_movieclip_itemf);
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_MOVIECLIP);
RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
ot->prop = prop;
}
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index e1768e4aedc..e541c4be653 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -55,10 +55,11 @@
#include "IMB_colormanagement.h"
#include "IMB_imbuf.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 "ED_anim_api.h"
#include "ED_gpencil.h"
@@ -190,25 +191,35 @@ 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;
bSound *sound = seq->sound;
SoundWaveform *waveform;
-
+
+ if (length < 2) {
+ return;
+ }
+
if (!sound->spinlock) {
sound->spinlock = MEM_mallocN(sizeof(SpinLock), "sound_spinlock");
BLI_spin_init(sound->spinlock);
@@ -241,21 +252,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);
- glColor4f(1.0f, 1.0f, 1.0f, 0.5);
glEnable(GL_BLEND);
- glBegin(GL_TRIANGLE_STRIP);
+
+ immBegin(GWN_PRIM_TRI_STRIP, length * 2);
+
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];
@@ -265,34 +282,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);
-
- glEnable(GL_LINE_STIPPLE);
- glLineStipple(1, 0x8888);
- }
- else {
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- glDisable(GL_LINE_STIPPLE);
+ immEnd();
+
+ glDisable(GL_BLEND);
}
}
-
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
@@ -325,9 +328,6 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1,
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- if (seqm->flag & SEQ_MUTE)
- drawmeta_stipple(1);
-
for (seq = seqbase->first; seq; seq = seq->next) {
chan_min = min_ii(chan_min, seq->machine);
chan_max = max_ii(chan_max, seq->machine);
@@ -338,6 +338,10 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1,
col[3] = 196; /* alpha, used for all meta children */
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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;
@@ -348,12 +352,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;
@@ -362,20 +370,12 @@ 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);
}
@@ -391,7 +391,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,21 +433,31 @@ static void draw_seq_handle(View2D *v2d, Sequence *seq, const float handsize_cla
glBlendFunc(GL_SRC_ALPHA, GL_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);
-
- glRectf(rx1, y1, rx2, y2);
-
- if (seq->flag & whichsel) glColor4ub(255, 255, 255, 200);
- else glColor4ub(0, 0, 0, 50);
+ 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);
+ }
- glEnable(GL_POLYGON_SMOOTH);
- glBegin(GL_TRIANGLES);
- glVertex2fv(v1); glVertex2fv(v2); glVertex2fv(v3);
- glEnd();
+ immRectf(pos, rx1, y1, rx2, y2);
- glDisable(GL_POLYGON_SMOOTH);
+ if (seq->flag & whichsel) {
+ immUniformColor4ub(255, 255, 255, 200);
+ }
+ else {
+ immUniformColor4ub(0, 0, 0, 50);
+ }
+
+ immBegin(GWN_PRIM_TRIS, 3);
+ immVertex2fv(pos, v1);
+ immVertex2fv(pos, v2);
+ immVertex2fv(pos, v3);
+ immEnd();
+
glDisable(GL_BLEND);
}
@@ -545,7 +555,8 @@ static void draw_seq_text(View2D *v2d, SpaceSeq *sseq, Sequence *seq, float x1,
if ((sseq->flag & SEQ_ALL_WAVEFORMS) || (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM)) {
str[0] = 0;
str_len = 0;
- } else if (seq->sound) {
+ }
+ else if (seq->sound) {
str_len = BLI_snprintf(str, sizeof(str), "%s: %s | %d",
name, seq->sound->name, seq->len);
}
@@ -585,67 +596,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)
+static void draw_sequence_extensions(Scene *scene, ARegion *ar, Sequence *seq, unsigned int pos)
{
- 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)
-{
- 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;
@@ -659,90 +613,82 @@ void draw_sequence_extensions(Scene *scene, ARegion *ar, Sequence *seq)
if (pixely <= 0) return; /* can happen when the view is split/resized */
blendcol[0] = blendcol[1] = blendcol[2] = 120;
-
- if (seq->startofs) {
+
+ if (seq->startofs || seq->endofs) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_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);
-
- fdrawbox((float)(seq->start), y1 - SEQ_STRIP_OFSBOTTOM, x1, y1); //outline
-
- glDisable(GL_BLEND);
+ }
+
+ if (seq->startofs) {
+ immUniformColor4ubv(col);
+ immRectf(pos, (float)(seq->start), y1 - SEQ_STRIP_OFSBOTTOM, x1, y1);
+
+ immUniformColor3ubvAlpha(col, col[3] + 50);
+
+ imm_draw_line_box(pos, (float)(seq->start), y1 - SEQ_STRIP_OFSBOTTOM, x1, y1); /* outline */
}
if (seq->endofs) {
+ immUniformColor4ubv(col);
+ immRectf(pos, x2, y2, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM);
+
+ immUniformColor3ubvAlpha(col, col[3] + 50);
+
+ imm_draw_line_box(pos, x2, y2, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM); /* outline */
+ }
+
+ if (seq->startofs || seq->endofs) {
+ glDisable(GL_BLEND);
+ }
+
+ if (seq->startstill || seq->endstill) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_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_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.5f, 60);
+
+ if (seq->flag & SEQ_MUTE) {
+ col[3] = 96;
}
else {
- UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.6, 0);
- glColor4ub(col[0], col[1], col[2], 110);
+ if (seq->flag & SELECT) {
+ col[3] = 255;
+ }
+ else {
+ col[3] = 170;
+ }
}
-
- glRectf(x2, y2, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM);
-
- if (seq->flag & SELECT) glColor4ub(col[0], col[1], col[2], 255);
- else glColor4ub(col[0], col[1], col[2], 160);
-
- fdrawbox(x2, y2, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM); //outline
-
- glDisable(GL_BLEND);
+
+ immUniformColor4ubv(col);
}
+
if (seq->startstill) {
- color3ubv_from_seq(scene, seq, col);
- UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.75, 40);
- glColor3ubv((GLubyte *)col);
-
- 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);
-
- glColor3ubv((GLubyte *)col);
-
- for (a = y1; a < y2; a += pixely * 2.0f) {
- fdrawline(x1, a, (float)(seq->start), a);
- }
+ 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);
-
- for (a = y1; a < y2; a += pixely * 2.0f) {
- fdrawline((float)(seq->start + seq->len), a, x2, a);
- }
+ immRectf(pos, (float)(seq->start + seq->len), y1, x2, y2);
+ }
+
+ if (seq->startstill || seq->endstill) {
+ glDisable(GL_BLEND);
}
}
@@ -756,7 +702,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 */
@@ -768,72 +714,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;
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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;
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_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) {
+ glDisable(GL_BLEND);
}
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 the strip outline */
+ draw_seq_handle(v2d, seq, handsize_clamped, SEQ_LEFTHANDLE, pos);
+ draw_seq_handle(v2d, seq, handsize_clamped, SEQ_RIGHTHANDLE, pos);
+
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);
- /* light stripes */
- glColor4ub(255, 255, 255, 32);
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_DIAG_STRIPES);
- glRectf(x1, y1, x2, y2);
+ pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_DIAG_STRIPES);
+
+ 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);
+
+ immUnbindProgram();
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
glDisable(GL_BLEND);
}
if (!BKE_sequence_is_valid_check(seq)) {
- GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
+ glEnable(GL_BLEND);
+
+ pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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();
+
+ glDisable(GL_BLEND);
}
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;
@@ -850,19 +829,27 @@ static void draw_seq_strip(const bContext *C, SpaceSeq *sseq, Scene *scene, AReg
drawmeta_contents(scene, seq, x1, y1, x2, y2);
}
+ pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ /* TODO: add back stippled line for muted strips? */
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
if (seq->flag & SEQ_MUTE) {
- glEnable(GL_LINE_STIPPLE);
- glLineStipple(1, 0x8888);
+ col[3] = 96;
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ immUniformColor4ubv(col);
}
-
- glColor3ubv((GLubyte *)col);
-
- UI_draw_roundbox_shade_x(GL_LINE_LOOP, x1, y1, x2, y2, 0.0, 0.1, 0.0);
-
- if (seq->flag & SEQ_MUTE) {
- glDisable(GL_LINE_STIPPLE);
+ else {
+ immUniformColor3ubv(col);
}
-
+
+ imm_draw_line_box(pos, x1, y1, x2, y2); /* outline */
+
+ immUnbindProgram();
+
/* calculate if seq is long enough to print a name */
x1 = seq->startdisp + handsize_clamped;
x2 = seq->enddisp - handsize_clamped;
@@ -1046,33 +1033,39 @@ static void sequencer_draw_borders(const SpaceSeq *sseq, const View2D *v2d, cons
glLineWidth(1.0f);
/* border */
- setlinestyle(3);
+ const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniformThemeColor(TH_BACK);
+ immUniform1i("num_colors", 0); /* Simple dashes. */
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
+
+ imm_draw_line_box(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 */
@@ -1087,11 +1080,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_checker_box(v2d->tot.xmin, v2d->tot.ymin, v2d->tot.xmax, v2d->tot.ymax);
}
}
}
@@ -1135,9 +1124,6 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
glClear(GL_COLOR_BUFFER_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;
@@ -1152,15 +1138,16 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
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;
}
@@ -1229,6 +1216,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) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ /* Format needs to be created prior to any immBindProgram call.
+ * Do it here because OCIO binds it's own shader.
+ */
+ Gwn_VertFormat *imm_format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(imm_format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int texCoord = GWN_vertformat_attr_add(imm_format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
if (scope) {
IMB_freeImBuf(ibuf);
ibuf = scope;
@@ -1301,9 +1300,12 @@ 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? */
+ gpuPushMatrix();
+ gpuLoadIdentity();
+ }
- GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
glGenTextures(1, (GLuint *)&texid);
glBindTexture(GL_TEXTURE_2D, texid);
@@ -1316,15 +1318,13 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
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", GL_TEXTURE0);
}
- glBegin(GL_QUADS);
+
+ immBegin(GWN_PRIM_TRI_FAN, 4);
if (draw_overlay) {
if (sseq->overlay_type == SEQ_DRAW_OVERLAY_RECT) {
@@ -1334,16 +1334,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);
+ immAttrib2f(texCoord, scene->ed->over_border.xmin, scene->ed->over_border.ymin);
+ immVertex2f(pos, tot_clip.xmin, tot_clip.ymin);
+
+ immAttrib2f(texCoord, scene->ed->over_border.xmin, scene->ed->over_border.ymax);
+ immVertex2f(pos, tot_clip.xmin, tot_clip.ymax);
+
+ immAttrib2f(texCoord, scene->ed->over_border.xmax, scene->ed->over_border.ymax);
+ immVertex2f(pos, tot_clip.xmax, tot_clip.ymax);
+
+ immAttrib2f(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);
+ immAttrib2f(texCoord, 0.0f, 0.0f);
+ immVertex2f(pos, v2d->tot.xmin, v2d->tot.ymin);
+
+ immAttrib2f(texCoord, 0.0f, 1.0f);
+ immVertex2f(pos, v2d->tot.xmin, v2d->tot.ymax);
+
+ immAttrib2f(texCoord, 1.0f, 1.0f);
+ immVertex2f(pos, v2d->tot.xmax, v2d->tot.ymax);
+
+ immAttrib2f(texCoord, 1.0f, 0.0f);
+ immVertex2f(pos, v2d->tot.xmax, v2d->tot.ymin);
}
}
else if (draw_backdrop) {
@@ -1362,25 +1376,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);
+ immAttrib2f(texCoord, 0.0f, 0.0f);
+ immVertex2f(pos, -imagex, -imagey);
+
+ immAttrib2f(texCoord, 0.0f, 1.0f);
+ immVertex2f(pos, -imagex, imagey);
+
+ immAttrib2f(texCoord, 1.0f, 1.0f);
+ immVertex2f(pos, imagex, imagey);
+
+ immAttrib2f(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);
+ immAttrib2f(texCoord, 0.0f, 0.0f);
+ immVertex2f(pos, v2d->tot.xmin, v2d->tot.ymin);
+
+ immAttrib2f(texCoord, 0.0f, 1.0f);
+ immVertex2f(pos, v2d->tot.xmin, v2d->tot.ymax);
+
+ immAttrib2f(texCoord, 1.0f, 1.0f);
+ immVertex2f(pos, v2d->tot.xmax, v2d->tot.ymax);
+
+ immAttrib2f(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)
+
+ if (!glsl_used) {
+ immUnbindProgram();
+ }
+
+ if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA) {
glDisable(GL_BLEND);
+ }
+
glDeleteTextures(1, &texid);
if (glsl_used)
@@ -1397,10 +1432,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);
+ gpuPopMatrix();
return;
}
@@ -1474,42 +1506,42 @@ void drawprefetchseqspace(Scene *scene, ARegion *UNUSED(ar), SpaceSeq *sseq)
static void draw_seq_backdrop(View2D *v2d)
{
int i;
-
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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);
-
- glVertex2f(v2d->cur.xmax, i);
- glVertex2f(v2d->cur.xmin, i);
- glVertex2f(v2d->cur.xmin, i + 1);
- glVertex2f(v2d->cur.xmax, i + 1);
+ if (i & 1) {
+ immUniformThemeColorShade(TH_BACK, -15);
+ }
+ else {
+ immUniformThemeColorShade(TH_BACK, -25);
+ }
+
+ 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_ct = (int)v2d->cur.ymax - i + 1;
+ immUniformThemeColor(TH_GRID);
+ immBegin(GWN_PRIM_LINES, line_ct * 2);
+ while (line_ct--) {
+ immVertex2f(pos, v2d->cur.xmax, i);
+ immVertex2f(pos, v2d->cur.xmin, i);
}
- glEnd();
+ immEnd();
+
+ immUnbindProgram();
}
/* draw the contents of the sequencer strips view */
@@ -1525,7 +1557,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) {
@@ -1553,8 +1585,15 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *ar)
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);
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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();
+
glDisable(GL_BLEND);
}
}
@@ -1566,36 +1605,56 @@ static void seq_draw_sfra_efra(Scene *scene, View2D *v2d)
const int frame_end = PEFRA + 1;
glEnable(GL_BLEND);
-
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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(GWN_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);
- UI_ThemeColorShade(TH_BACK, -40);
+ immBegin(GWN_PRIM_LINES, 4);
- 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[0], v2d->cur.ymin);
+ immVertex2f(pos, ms->disp_range[0], v2d->cur.ymax);
+
+ immVertex2f(pos, ms->disp_range[1], v2d->cur.ymin);
+ immVertex2f(pos, ms->disp_range[1], v2d->cur.ymax);
+
+ immEnd();
}
+ immUnbindProgram();
+
glDisable(GL_BLEND);
}
@@ -1670,16 +1729,20 @@ 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();
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor3f(0.2f, 0.2f, 0.2f);
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2f(pos, cfra_over, v2d->cur.ymin);
+ immVertex2f(pos, cfra_over, v2d->cur.ymax);
+ immEnd();
+
+ immUnbindProgram();
}
-
+
/* callback */
ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 8ae89941bdb..650687429b4 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -562,7 +562,7 @@ int seq_effect_find_selected(Scene *scene, Sequence *activeseq, int type, Sequen
}
if (seq1 == NULL) seq1 = seq2;
if (seq3 == NULL) seq3 = seq2;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case 2:
if (seq1 == NULL || seq2 == NULL) {
*error_str = N_("2 selected sequence strips are needed");
@@ -1256,7 +1256,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;
@@ -1291,21 +1290,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;
@@ -1354,7 +1338,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);
@@ -1384,8 +1367,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);
@@ -1527,7 +1508,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;
@@ -1585,7 +1565,6 @@ 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);
@@ -1614,8 +1593,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);
@@ -3352,6 +3329,9 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op)
if (seq_act->sound) BKE_sound_add_scene_sound_defaults(scene, seq_act);
if (seq_other->sound) BKE_sound_add_scene_sound_defaults(scene, seq_other);
+ BKE_sequence_invalidate_cache(scene, seq_act);
+ BKE_sequence_invalidate_cache(scene, seq_other);
+
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@@ -3509,7 +3489,7 @@ static int sequencer_enable_proxies_exec(bContext *C, wmOperator *op)
bool proxy_50 = RNA_boolean_get(op->ptr, "proxy_50");
bool proxy_75 = RNA_boolean_get(op->ptr, "proxy_75");
bool proxy_100 = RNA_boolean_get(op->ptr, "proxy_100");
- bool override = RNA_boolean_get(op->ptr, "override");
+ bool overwrite = RNA_boolean_get(op->ptr, "overwrite");
bool turnon = true;
if (ed == NULL || !(proxy_25 || proxy_50 || proxy_75 || proxy_100)) {
@@ -3545,7 +3525,7 @@ static int sequencer_enable_proxies_exec(bContext *C, wmOperator *op)
else
seq->strip->proxy->build_size_flags &= ~SEQ_PROXY_IMAGE_SIZE_100;
- if (!override)
+ if (!overwrite)
seq->strip->proxy->build_flags |= SEQ_PROXY_SKIP_EXISTING;
else
seq->strip->proxy->build_flags &= ~SEQ_PROXY_SKIP_EXISTING;
@@ -3577,7 +3557,7 @@ void SEQUENCER_OT_enable_proxies(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "proxy_50", false, "50%", "");
RNA_def_boolean(ot->srna, "proxy_75", false, "75%", "");
RNA_def_boolean(ot->srna, "proxy_100", false, "100%", "");
- RNA_def_boolean(ot->srna, "override", false, "Override", "");
+ RNA_def_boolean(ot->srna, "overwrite", false, "Overwrite", "");
}
/* change ops */
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index 730cc117287..7ce2f73cbef 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -56,8 +56,6 @@ 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);
diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c
index 655e029cfdd..a3cfcae77b8 100644
--- a/source/blender/editors/space_sequencer/sequencer_ops.c
+++ b/source/blender/editors/space_sequencer/sequencer_ops.c
@@ -201,7 +201,9 @@ void sequencer_keymap(wmKeyConfig *keyconf)
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);
@@ -340,7 +342,9 @@ void sequencer_keymap(wmKeyConfig *keyconf)
/* Preview Region ----------------------------------------------------------- */
keymap = WM_keymap_find(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);
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 48c49f36471..d88ed36e392 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -683,7 +683,7 @@ static int sequencer_select_less_exec(bContext *C, wmOperator *UNUSED(op))
if (!select_more_less_seq__internal(scene, false, false))
return OPERATOR_CANCELLED;
-
+
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index a2a80297041..b3ec2948c8c 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -337,7 +337,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(
+ bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -490,7 +491,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(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -596,7 +599,9 @@ static void sequencer_preview_region_draw(const bContext *C, ARegion *ar)
}
}
-static void sequencer_preview_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void sequencer_preview_region_listener(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -662,7 +667,9 @@ static void sequencer_buttons_region_draw(const bContext *C, ARegion *ar)
ED_region_panels(C, ar, NULL, -1, true);
}
-static void sequencer_buttons_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void sequencer_buttons_region_listener(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
diff --git a/source/blender/editors/space_text/CMakeLists.txt b/source/blender/editors/space_text/CMakeLists.txt
index de85ddc40ab..39b48f5b52c 100644
--- a/source/blender/editors/space_text/CMakeLists.txt
+++ b/source/blender/editors/space_text/CMakeLists.txt
@@ -43,6 +43,8 @@ set(SRC
text_format.c
text_format_lua.c
text_format_osl.c
+ text_format_pov.c
+ text_format_pov_ini.c
text_format_py.c
text_header.c
text_ops.c
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index 686a10fc785..ed1ef080e0c 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -125,7 +125,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(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, const Scene *UNUSED(scene))
{
SpaceText *st = sa->spacedata.first;
@@ -158,7 +158,7 @@ static void text_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
}
ED_area_tag_redraw(sa);
- /* fall-through */ /* fall down to tag redraw */
+ ATTR_FALLTHROUGH; /* fall down to tag redraw */
case NA_ADDED:
case NA_REMOVED:
ED_area_tag_redraw(sa);
@@ -636,5 +636,7 @@ void ED_spacetype_text(void)
ED_text_format_register_py();
ED_text_format_register_osl();
ED_text_format_register_lua();
+ ED_text_format_register_pov();
+ ED_text_format_register_pov_ini();
}
diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c
index c38c57b9528..da5fa9da046 100644
--- a/source/blender/editors/space_text/text_autocomplete.c
+++ b/source/blender/editors/space_text/text_autocomplete.c
@@ -328,7 +328,7 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e
if (tools & TOOL_SUGG_LIST) {
texttool_suggest_clear();
}
- if (tools & TOOL_DOCUMENT) {
+ if (tools & TOOL_DOCUMENT) {
texttool_docs_clear();
doc_scroll = 0;
}
@@ -455,7 +455,7 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e
break;
case PAGEDOWNKEY:
scroll = SUGG_LIST_SIZE - 1;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case WHEELDOWNMOUSE:
case DOWNARROWKEY:
if (event->val == KM_PRESS) {
@@ -489,7 +489,7 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e
break;
case PAGEUPKEY:
scroll = SUGG_LIST_SIZE - 1;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case WHEELUPMOUSE:
case UPARROWKEY:
if (event->val == KM_PRESS) {
diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c
index 81605a80f69..fcb675abcf2 100644
--- a/source/blender/editors/space_text/text_draw.c
+++ b/source/blender/editors/space_text/text_draw.c
@@ -49,6 +49,8 @@
#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_immediate.h"
+
#include "UI_interface.h"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -123,38 +125,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 +431,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 +454,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 +507,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,26 +908,28 @@ 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 */
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_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 *******************************/
+#if 0
static void draw_documentation(const SpaceText *st, ARegion *ar)
{
TextDrawContext tdc = {0};
@@ -962,26 +966,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);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_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(GWN_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(GWN_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(GWN_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++) {
@@ -1008,12 +1018,8 @@ 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
/*********************** draw suggestion list *******************************/
@@ -1059,10 +1065,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);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_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) ;
@@ -1077,11 +1088,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);
+ unsigned int posi = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_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;
@@ -1090,42 +1106,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;
+ }
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_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;
@@ -1141,35 +1172,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);
@@ -1185,36 +1205,38 @@ 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);
+ immRecti(pos, x1 - 4, y1, x2, y2);
glDisable(GL_BLEND);
}
}
-
+
if (!hidden) {
/* Draw the cursor itself (we draw the sel. cursor as this is the leading edge) */
x = st->showlinenrs ? TXT_OFFSET + TEXTXLOC : TXT_OFFSET;
x += vselc * st->cwidth;
y = ar->winy - vsell * lheight;
-
+
+ immUniformThemeColor(TH_HILITE);
+
if (st->overwrite) {
char ch = text->sell->line[text->selc];
-
+
y += TXT_LINE_SPACING;
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 *********************/
@@ -1315,7 +1337,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;
@@ -1420,8 +1442,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);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_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 */
@@ -1430,11 +1455,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)
@@ -1442,16 +1467,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) {
@@ -1472,22 +1501,31 @@ 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 = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniform1i("num_colors", 0); /* "simple" mode */
+ immUniformThemeColor(TH_GRID); /* same color as line number background */
+ immUniform1f("dash_width", 2.0f);
+ immUniform1f("dash_factor", 0.5f);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2i(shdr_pos, margin_column_x, 0);
+ immVertex2i(shdr_pos, margin_column_x, ar->winy - 2);
+ immEnd();
+ immUnbindProgram();
}
}
/* draw other stuff */
draw_brackets(st, &tdc, ar);
draw_textscroll(st, &scroll, &back);
- draw_documentation(st, ar);
+ /* draw_documentation(st, ar); - No longer supported */
draw_suggestion_list(st, &tdc, ar);
text_font_end(&tdc);
diff --git a/source/blender/editors/space_text/text_format.h b/source/blender/editors/space_text/text_format.h
index b901ec83a9c..d7cf31d0b41 100644
--- a/source/blender/editors/space_text/text_format.h
+++ b/source/blender/editors/space_text/text_format.h
@@ -102,6 +102,8 @@ void ED_text_format_register(TextFormatType *tft);
void ED_text_format_register_py(void);
void ED_text_format_register_osl(void);
void ED_text_format_register_lua(void);
+void ED_text_format_register_pov(void);
+void ED_text_format_register_pov_ini(void);
#define STR_LITERAL_STARTSWITH(str, str_literal, len_var) \
(strncmp(str, str_literal, len_var = (sizeof(str_literal) - 1)) == 0)
diff --git a/source/blender/editors/space_text/text_format_pov.c b/source/blender/editors/space_text/text_format_pov.c
new file mode 100644
index 00000000000..0d19c503798
--- /dev/null
+++ b/source/blender/editors/space_text/text_format_pov.c
@@ -0,0 +1,809 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_text/text_format_pov.c
+ * \ingroup sptext
+ */
+
+#include <string.h>
+
+#include "BLI_blenlib.h"
+
+#include "DNA_text_types.h"
+#include "DNA_space_types.h"
+
+#include "BKE_text.h"
+
+#include "text_format.h"
+
+/* *** POV Keywords (for format_line) *** */
+
+/* Checks the specified source string for a POV keyword (minus boolean & 'nil').
+ * This name must start at the beginning of the source string and must be
+ * followed by a non-identifier (see text_check_identifier(char)) or null char.
+ *
+ * If a keyword is found, the length of the matching word is returned.
+ * Otherwise, -1 is returned.
+ *
+ * See:
+ * http://www.povray.org/documentation/view/3.7.0/212/
+ */
+
+static int txtfmt_pov_find_keyword(const char *string)
+{
+ int i, len;
+ /* Language Directives */
+ if (STR_LITERAL_STARTSWITH(string, "append", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "break", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "case", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "debug", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "declare", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "default", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "elseif", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "else", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "end", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "error", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fclose", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fopen", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "for", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ifndef", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ifdef", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "if", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "include", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "local", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "macro", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "range", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "read", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "render", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "statistics", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "switch", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "undef", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "version", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "warning", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "while", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "write", len)) i = len;
+ else i = 0;
+
+ /* If next source char is an identifier (eg. 'i' in "definate") no match */
+ return (i == 0 || text_check_identifier(string[i])) ? -1 : i;
+}
+
+static int txtfmt_pov_find_reserved_keywords(const char *string)
+{
+ int i, len;
+ /* POV-Ray Built-in Variables
+ * list is from...
+ * http://www.povray.org/documentation/view/3.7.0/212/
+ */
+ /* Language Keywords */
+ if (STR_LITERAL_STARTSWITH(string, "aa_level", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "aa_threshold", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "absorption", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "accuracy", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "adc_bailout", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "albedo", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "all_intersections", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "translucency", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "all", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "alpha", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "altitude", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "always_sample", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ambient_light", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ambient", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "angle", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "aperture", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "arc_angle", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "area_light", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "area_illumination", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "array", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "assumed_gamma", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "autostop", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "black_hole", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "blur_samples", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "brightness", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "brilliance", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "caustics", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "charset", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "collect", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "component", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "composite", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "confidence", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "conserve_energy", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "contained_by", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "coords", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "count", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "crand", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cube", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cutaway_textures", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "diffuse", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "direction", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "dispersion_samples", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "dispersion", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "dist_exp", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "distance", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "eccentricity", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "emission", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "error_bound", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "evaluate", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "expand_thresholds", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "exponent", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "exterior", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "extinction", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "face_indices", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "falloff_angle", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "falloff", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "file_gamma", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "flatness", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "flip", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "focal_point", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fog_alt", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fog_offset", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fog_type", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "form", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fresnel", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "function", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "gamma", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "gather", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "global_settings", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "gray_threshold", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "hf_gray_16", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "hierarchy", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "hypercomplex", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "importance", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "inside_vector", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "internal", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "intervals", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ior", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "irid_wavelength", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "irid", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "load_file", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "location", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "look_at", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "looks_like", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "low_error_factor", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "major_radius", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "max_distance", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "max_extent", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "max_gradient", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "max_intersections", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "max_iteration", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "max_sample", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "max_trace_level", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "max_trace", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "maximum_reuse", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "metallic", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "method", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "metric", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "minimum_reuse", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "nearest_count", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "normal_indices", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "normal_vectors", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "now", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "number_of_waves", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "offset", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "open", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "orientation", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pass_through", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pattern", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "phong_size", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "phong", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "point_at", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pot", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "precision", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "precompute", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pretrace_end", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pretrace_start", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "prod", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pwr", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "quaternion", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "radiosity", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "radius", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ratio", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "reciprocal", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "recursion_limit", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "reflection_exponent", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "reflection", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "refraction", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "repeat", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "right", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "roughness", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "samples", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "save_file", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "scattering", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "size", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sky", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "slice", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "smooth", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "solid", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "spacing", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "specular", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "split_union", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "spotlight", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "strength", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sturm", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sum", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "target", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "texture_list", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "thickness", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "threshold", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tightness", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tolerance", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "toroidal", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ttf", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "turb_depth", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "type", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "u_steps", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "up", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "use_alpha", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "uv_indices", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "uv_vectors", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "v_steps", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "variance", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "vertex_vectors", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "water_level", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "width", len)) i = len;
+
+ else i = 0;
+
+ /* If next source char is an identifier (eg. 'i' in "definate") no match */
+ return (i == 0 || text_check_identifier(string[i])) ? -1 : i;
+}
+
+
+static int txtfmt_pov_find_reserved_builtins(const char *string)
+{
+ int i, len;
+
+ /* POV-Ray Built-in Variables
+ * list is from...
+ * http://www.povray.org/documentation/view/3.7.0/212/
+ */
+ if (STR_LITERAL_STARTSWITH(string, "clock_delta", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "clock", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "clock_on", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "final_clock", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "final_frame", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "frame_number", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "initial_clock", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "initial_frame", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "image_height", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "image_width", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "input_file_name", len)) i = len;
+ /* Color Identifiers */
+ else if (STR_LITERAL_STARTSWITH(string, "blue", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "filter", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "gray", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "green", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "red", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "rgbft", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "rgbf", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "rgbt", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "rgb", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "srgb", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sRGB", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "SRGB", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "srgbft", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "srgbf", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "srgbt", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "transmit", len)) i = len;
+ /* Patterns */
+ else if (STR_LITERAL_STARTSWITH(string, "agate", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "aoi", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "average", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "boxed", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "bozo", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "brick", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "bumps", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cells", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "checker", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "crackle", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cubic", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cylindrical", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "density_file", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "dents", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "facets", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "gradient", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "granite", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "hexagon", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "image_pattern", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "julia", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "leopard", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "magnet", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "mandel", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "marble", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "onion", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pavement", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pigment_pattern", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "planar", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "quilted", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "radial", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ripples", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "slope", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "spherical", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "spiral1", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "spiral2", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "spotted", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "square", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tile2", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tiling", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tiles", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "triangular", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "waves", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "wood", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "wrinkles", len)) i = len;
+ /* Objects */
+ else if (STR_LITERAL_STARTSWITH(string, "background", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "bicubic_patch", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "blob", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "box", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "camera", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cone", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cubic", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cylinder", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "difference", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "disc", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fog", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "height_field", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "intersection", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "isosurface", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "julia_fractal", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "lathe", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "light_group", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "light_source", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "merge", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "mesh2", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "mesh", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "object", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ovus", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "lemon", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "parametric", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "plane", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "poly", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "polygon", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "polynomial", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "prism", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "quadric", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "quartic", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "rainbow", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sky_sphere", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "smooth_triangle", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cubic_spline", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sphere_sweep", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sphere", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "spline", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "superellipsoid", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sor", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "text", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "torus", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "triangle", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "union", len)) i = len;
+ /* Filetypes */
+ else if (STR_LITERAL_STARTSWITH(string, "df3", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "exr", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "gif", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "hdr", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "iff", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "jpeg", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pgm", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "png", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ppm", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sys", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tga", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tiff", len)) i = len;
+ /* Spline Identifiers */
+ else if (STR_LITERAL_STARTSWITH(string, "b_spline", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "bezier_spline", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "conic_sweep", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cubic_spline", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "linear_spline", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "linear_sweep", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "natural_spline", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "quadratic_spline", len)) i = len;
+ /* Encodings */
+ else if (STR_LITERAL_STARTSWITH(string, "ascii", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "utf8", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "uint8", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "uint16be", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "uint16le", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sint8", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sint16be", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sint16le", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sint32be", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sint32le", len)) i = len;
+ /* Camera Types */
+ else if (STR_LITERAL_STARTSWITH(string, "fisheye", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "mesh_camera", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "omnimax", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "orthographic", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "panoramic", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "perspective", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ultra_wide_angle", len)) i = len;
+ /* Built-in Vectors */
+ else if (STR_LITERAL_STARTSWITH(string, "t", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "u", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "v", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "x", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "y", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "z", len)) i = len;
+
+ else i = 0;
+
+ /* If next source char is an identifier (eg. 'i' in "definate") no match */
+ return (i == 0 || text_check_identifier(string[i])) ? -1 : i;
+}
+
+
+/* Checks the specified source string for a POV modifiers. This
+ * name must start at the beginning of the source string and must be followed
+ * by a non-identifier (see text_check_identifier(char)) or null character.
+ *
+ * If a special name is found, the length of the matching name is returned.
+ * Otherwise, -1 is returned.
+ *
+ * See:
+ * http://www.povray.org/documentation/view/3.7.0/212/
+ */
+
+static int txtfmt_pov_find_specialvar(const char *string)
+{
+ int i, len;
+ /* Modifiers */
+ if (STR_LITERAL_STARTSWITH(string, "interior_texture", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "double_illuminate", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "media_interaction", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "media_attenuation", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "projected_through", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "noise_generator", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "agate_turb", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "bounded_by", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "brick_size", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "bump_map", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "bump_size", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "circular", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "clipped_by", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cubic", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "color_map", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "color", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "colour_map", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "colour", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "control0", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "control1", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cubic_wave", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "density_map", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "density", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fade_color", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fade_colour", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fade_distance", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fade_power", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "frequency", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "global_lights", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "hollow", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "image_map", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "adaptive", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "interior", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "interpolate", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "inverse", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "jitter", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "lambda", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "map_type", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "material_map", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "material", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "matrix", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "media", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "mm_per_unit", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "mortar", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "no_bump_scale", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "no_image", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "no_radiosity", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "no_reflection", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "no_shadow", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "normal_map", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "normal", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "octaves", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "omega", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "once", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "orient", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "parallel", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "phase", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "photons", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pigment_map", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pigment", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "finish", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "poly_wave", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "quick_color", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "quick_colour", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ramp_wave", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "rotate", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "scale", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "scallop_wave", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "shadowless", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sine_wave", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "slope_map", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "subsurface", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "texture_map", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "texture", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "transform", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "translate", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "triangle_wave", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "turbulence", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "use_color", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "use_colour", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "use_index", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "uv_mapping", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "warp", len)) i = len;
+
+ /* Vector Functions */
+ else if (STR_LITERAL_STARTSWITH(string, "max_extent", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "min_extent", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "trace", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "vaxis_rotate", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "vcross", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "vnormalize", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "vrotate", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "vturbulence", len)) i = len;
+ /* String Functions */
+ else if (STR_LITERAL_STARTSWITH(string, "chr", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "concat", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "datetime", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "str", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "strlwr", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "strupr", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "substr", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "vstr", len)) i = len;
+ /* Float Functions */
+ else if (STR_LITERAL_STARTSWITH(string, "abs", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "acosh", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "acos", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "asc", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "asinh", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "asin", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "atan2", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "atand", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "atanh", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "atan", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "bitwise_and", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "bitwise_or", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "bitwise_xor", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ceil", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cosh", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "cos", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "defined", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "degrees", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "dimension_size", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "dimensions", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "div", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "exp", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "file_exists", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "floor", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "inside", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "int", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ln", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "log", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "max", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "min", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "mod", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pow", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "radians", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "rand", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "seed", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "select", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sinh", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sin", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sqrt", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sqr", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "strcmp", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "strlen", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tanh", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tan", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "val", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "vdot", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "vlength", len)) i = len;
+ else i = 0;
+
+ /* If next source char is an identifier (eg. 'i' in "definate") no match */
+ return (i == 0 || text_check_identifier(string[i])) ? -1 : i;
+}
+
+static int txtfmt_pov_find_bool(const char *string)
+{
+ int i, len;
+ /*Built-in Constants*/
+ if (STR_LITERAL_STARTSWITH(string, "false", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "no", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "off", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "true", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "yes", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "on", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pi", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tau", len)) i = len;
+ else i = 0;
+
+ /* If next source char is an identifier (eg. 'i' in "Nonetheless") no match */
+ return (i == 0 || text_check_identifier(string[i])) ? -1 : i;
+}
+
+static char txtfmt_pov_format_identifier(const char *str)
+{
+ char fmt;
+ if ((txtfmt_pov_find_specialvar(str)) != -1) fmt = FMT_TYPE_SPECIAL;
+ else if ((txtfmt_pov_find_keyword(str)) != -1) fmt = FMT_TYPE_KEYWORD;
+ else if ((txtfmt_pov_find_reserved_keywords(str)) != -1) fmt = FMT_TYPE_RESERVED;
+ else if ((txtfmt_pov_find_reserved_builtins(str)) != -1) fmt = FMT_TYPE_RESERVED;
+ else fmt = FMT_TYPE_DEFAULT;
+ return fmt;
+}
+
+static void txtfmt_pov_format_line(SpaceText *st, TextLine *line, const bool do_next)
+{
+ FlattenString fs;
+ const char *str;
+ char *fmt;
+ char cont_orig, cont, find, prev = ' ';
+ int len, i;
+
+ /* Get continuation from previous line */
+ if (line->prev && line->prev->format != NULL) {
+ fmt = line->prev->format;
+ cont = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
+ BLI_assert((FMT_CONT_ALL & cont) == cont);
+ }
+ else {
+ cont = FMT_CONT_NOP;
+ }
+
+ /* Get original continuation from this line */
+ if (line->format != NULL) {
+ fmt = line->format;
+ cont_orig = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
+ BLI_assert((FMT_CONT_ALL & cont_orig) == cont_orig);
+ }
+ else {
+ cont_orig = 0xFF;
+ }
+
+ len = flatten_string(st, &fs, line->line);
+ str = fs.buf;
+ if (!text_check_format_len(line, len)) {
+ flatten_string_free(&fs);
+ return;
+ }
+ fmt = line->format;
+
+ while (*str) {
+ /* Handle escape sequences by skipping both \ and next char */
+ if (*str == '\\') {
+ *fmt = prev; fmt++; str++;
+ if (*str == '\0') break;
+ *fmt = prev; fmt++; str += BLI_str_utf8_size_safe(str);
+ continue;
+ }
+ /* Handle continuations */
+ else if (cont) {
+ /* C-Style comments */
+ if (cont & FMT_CONT_COMMENT_C) {
+ if (*str == '*' && *(str + 1) == '/') {
+ *fmt = FMT_TYPE_COMMENT; fmt++; str++;
+ *fmt = FMT_TYPE_COMMENT;
+ cont = FMT_CONT_NOP;
+ }
+ else {
+ *fmt = FMT_TYPE_COMMENT;
+ }
+ /* Handle other comments */
+ }
+ else {
+ find = (cont & FMT_CONT_QUOTEDOUBLE) ? '"' : '\'';
+ if (*str == find) cont = 0;
+ *fmt = FMT_TYPE_STRING;
+ }
+
+ str += BLI_str_utf8_size_safe(str) - 1;
+ }
+ /* Not in a string... */
+ else {
+ /* C-Style (multi-line) comments */
+ if (*str == '/' && *(str + 1) == '*') {
+ cont = FMT_CONT_COMMENT_C;
+ *fmt = FMT_TYPE_COMMENT; fmt++; str++;
+ *fmt = FMT_TYPE_COMMENT;
+ }
+ /* Single line comment */
+ else if (*str == '/' && *(str + 1) == '/') {
+ text_format_fill(&str, &fmt, FMT_TYPE_COMMENT, len - (int)(fmt - line->format));
+ }
+ else if (*str == '"' || *str == '\'') {
+ /* Strings */
+ find = *str;
+ cont = (*str == '"') ? FMT_CONT_QUOTEDOUBLE : FMT_CONT_QUOTESINGLE;
+ *fmt = FMT_TYPE_STRING;
+ }
+ /* Whitespace (all ws. has been converted to spaces) */
+ else if (*str == ' ') {
+ *fmt = FMT_TYPE_WHITESPACE;
+ }
+ /* Numbers (digits not part of an identifier and periods followed by digits) */
+ else if ((prev != FMT_TYPE_DEFAULT && text_check_digit(*str)) ||
+ (*str == '.' && text_check_digit(*(str + 1))))
+ {
+ *fmt = FMT_TYPE_NUMERAL;
+ }
+ /* Booleans */
+ else if (prev != FMT_TYPE_DEFAULT && (i = txtfmt_pov_find_bool(str)) != -1) {
+ if (i > 0) {
+ text_format_fill_ascii(&str, &fmt, FMT_TYPE_NUMERAL, i);
+ }
+ else {
+ str += BLI_str_utf8_size_safe(str) - 1;
+ *fmt = FMT_TYPE_DEFAULT;
+ }
+ }
+ /* Punctuation */
+ else if (text_check_delim(*str)) {
+ *fmt = FMT_TYPE_SYMBOL;
+ }
+ /* Identifiers and other text (no previous ws. or delims. so text continues) */
+ else if (prev == FMT_TYPE_DEFAULT) {
+ str += BLI_str_utf8_size_safe(str) - 1;
+ *fmt = FMT_TYPE_DEFAULT;
+ }
+ /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */
+ else {
+ /* Special vars(v) or built-in keywords(b) */
+ /* keep in sync with 'txtfmt_pov_format_identifier()' */
+ if ((i = txtfmt_pov_find_specialvar(str)) != -1) prev = FMT_TYPE_SPECIAL;
+ else if ((i = txtfmt_pov_find_keyword(str)) != -1) prev = FMT_TYPE_KEYWORD;
+ else if ((i = txtfmt_pov_find_reserved_keywords(str)) != -1) prev = FMT_TYPE_RESERVED;
+ else if ((i = txtfmt_pov_find_reserved_builtins(str)) != -1) prev = FMT_TYPE_RESERVED;
+
+ if (i > 0) {
+ text_format_fill_ascii(&str, &fmt, prev, i);
+ }
+ else {
+ str += BLI_str_utf8_size_safe(str) - 1;
+ *fmt = FMT_TYPE_DEFAULT;
+ }
+ }
+ }
+ prev = *fmt; fmt++; str++;
+ }
+
+ /* Terminate and add continuation char */
+ *fmt = '\0'; fmt++;
+ *fmt = cont;
+
+ /* If continuation has changed and we're allowed, process the next line */
+ if (cont != cont_orig && do_next && line->next) {
+ txtfmt_pov_format_line(st, line->next, do_next);
+ }
+
+ flatten_string_free(&fs);
+}
+
+void ED_text_format_register_pov(void)
+{
+ static TextFormatType tft = {NULL};
+ static const char *ext[] = {"pov", "inc", "mcr", "mac", NULL};
+
+ tft.format_identifier = txtfmt_pov_format_identifier;
+ tft.format_line = txtfmt_pov_format_line;
+ tft.ext = ext;
+
+ ED_text_format_register(&tft);
+}
diff --git a/source/blender/editors/space_text/text_format_pov_ini.c b/source/blender/editors/space_text/text_format_pov_ini.c
new file mode 100644
index 00000000000..719f4e3c036
--- /dev/null
+++ b/source/blender/editors/space_text/text_format_pov_ini.c
@@ -0,0 +1,488 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_text/text_format_pov_ini.c
+ * \ingroup sptext
+ */
+
+#include <string.h>
+
+#include "BLI_blenlib.h"
+
+#include "DNA_text_types.h"
+#include "DNA_space_types.h"
+
+#include "BKE_text.h"
+
+#include "text_format.h"
+
+/* *** POV INI Keywords (for format_line) *** */
+
+/* Checks the specified source string for a POV INI keyword (minus boolean & 'nil').
+ * This name must start at the beginning of the source string and must be
+ * followed by a non-identifier (see text_check_identifier(char)) or null char.
+ *
+ * If a keyword is found, the length of the matching word is returned.
+ * Otherwise, -1 is returned.
+ *
+ * See:
+ * http://www.povray.org/documentation/view/3.7.0/212/
+ */
+
+static int txtfmt_ini_find_keyword(const char *string)
+{
+ int i, len;
+ /* Language Directives */
+ if (STR_LITERAL_STARTSWITH(string, "append", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "break", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "case", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "debug", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "declare", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "default", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "elseif", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "else", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "end", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "error", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fclose", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "fopen", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "for", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ifdef", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ifndef", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "if", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "include", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "local", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "macro", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "range", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "read", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "render", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "statistics", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "switch", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "undef", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "version", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "warning", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "while", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "write", len)) i = len;
+
+ else if (STR_LITERAL_STARTSWITH(string, "I", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "S", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "A", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Q", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "U", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "F", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "C", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "N", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "P", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "T", len)) i = len;
+
+ else i = 0;
+
+ /* If next source char is an identifier (eg. 'i' in "definate") no match */
+ return (i == 0 || text_check_identifier(string[i])) ? -1 : i;
+}
+
+static int txtfmt_ini_find_reserved(const char *string)
+{
+ int i, len;
+ /* POV-Ray Built-in INI Variables
+ * list is from...
+ * http://www.povray.org/documentation/view/3.7.0/212/
+ */
+ if (STR_LITERAL_STARTSWITH(string, "Antialias_Threshold", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Bounding_Method", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Antialias_Gamma", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Antialias_Depth", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "clock_delta", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "clock_on", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "clock", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "final_clock", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "final_frame", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "frame_number", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "initial_clock", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "initial_frame", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "image_height", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "image_width", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "input_file_name", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Subset_Start_Frame", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Subset_End_Frame", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Frame_Step", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Cyclic_Animation", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Field_Render", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Odd_Field", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Height", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Width", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Start_Column", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Start_Row", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "End_Column", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "End_Row", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Test_Abort_Count", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Test_Abort", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Continue_Trace", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Create_Continue_Trace_Log", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Create_Ini", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Display_Gamma", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Display", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Version", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Pause_When_Done", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Verbose", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Preview_Start_Size", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Preview_End_Size", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Output_to_File", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Input_File_Name", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Output_File_Name", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Output_File_Type", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Output_Alpha", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Bits_Per_Color", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Compression", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Dither_Method", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Dither", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Pre_Scene_Command", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Pre_Frame_Command", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Post_Scene_Command", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Post_Frame_Command", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "User_Abort_Command", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Fatal_Error_Command", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Pre_Scene_Return", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Pre_Frame_Return", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Post_Scene_Return", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Post_Frame_Return", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "User_Abort_Return", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Fatal_Error_Return", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Include_Header", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Library_Path", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Debug_Console", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Fatal_Console", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Render_Console", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Statistic_Console", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Warning_Console", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Warning_Level", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "All_Console", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Debug_File", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Fatal_File", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Render_File", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Statistic_File", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Warning_File", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "All_File", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Quality", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Bounding_Threshold", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Bounding", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Light_Buffer", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Vista_Buffer", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Remove_Bounds", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Split_Unions", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Antialias", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Sampling_Method", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Jitter_Amount", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Jitter", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Antialias_Depth", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "CheckNewVersion", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "RunCount", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "CommandLine", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "TextColour", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "WarningColour", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ErrorColour", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "BackgroundColour", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "DropToEditor", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "LastRenderName", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "LastRenderPath", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "LastQueuePath", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "SecondaryINISection", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "BetaVersionNo64", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "LastBitmapName", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "LastBitmapPath", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "LastINIPath", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "SecondaryINIFile", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "BackgroundFile", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "SaveSettingsOnExit", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "TileBackground", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "HideNewUserHelp", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "SendSystemInfo", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ItsAboutTime", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "LastPath", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Band0Width", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Band1Width", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Band2Width", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Band3Width", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Band4Width", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ShowCmd", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "NormalPositionLeft", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "NormalPositionTop", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "NormalPositionRight", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "NormalPositionBottom", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "UseToolbar", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "UseTooltips", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "NormalPositionX", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "NormalPositionY", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Flags", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Transparency", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Use8BitMode", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "MakeActive", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "KeepAboveMain", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "HideWhenMainMinimized", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "AutoClose", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "PreserveBitmap", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "FontSize", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "FontWeight", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Font", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "KeepMessages", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "AlertSound", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Completion", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Priority", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "DutyCycle", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "AlertOnCompletion", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "AutoRender", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "PreventSleep", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "NoShelloutWait", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "SystemNoActive", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "RenderCompleteSoundEnabled", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ParseErrorSoundEnabled", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "RenderErrorSoundEnabled", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "RenderCompleteSound", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ParseErrorSound", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "RenderErrorSound", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "UseExtensions", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ReadWriteSourceDir", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "NoShellOuts", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "VideoSource", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "SceneFile", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "OutputFile", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "IniOutputFile", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "CurrentDirectory", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "SourceFile", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Rendering", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "RenderwinClose", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Append_File", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "Warning Level", len)) i = len;
+ /* Filetypes */
+ else if (STR_LITERAL_STARTSWITH(string, "df3", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "exr", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "gif", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "hdr", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "iff", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "jpeg", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pgm", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "png", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "ppm", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sys", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tga", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tiff", len)) i = len;
+ /* Encodings */
+ else if (STR_LITERAL_STARTSWITH(string, "ascii", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "utf8", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "uint8", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "uint16be", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "uint16le", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sint8", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sint16be", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sint16le", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sint32be", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "sint32le", len)) i = len;
+
+ else i = 0;
+
+ /* If next source char is an identifier (eg. 'i' in "definate") no match */
+ return (i == 0 || text_check_identifier(string[i])) ? -1 : i;
+}
+
+
+
+
+static int txtfmt_ini_find_bool(const char *string)
+{
+ int i, len;
+ /* Built-in Constants */
+ if (STR_LITERAL_STARTSWITH(string, "false", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "no", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "off", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "true", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "yes", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "on", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "pi", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "tau", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "%o", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "%s", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "%n", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "%k", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "%h", len)) i = len;
+ else if (STR_LITERAL_STARTSWITH(string, "%w", len)) i = len;
+ else i = 0;
+
+ /* If next source char is an identifier (eg. 'i' in "Nonetheless") no match */
+ return (i == 0 || text_check_identifier(string[i])) ? -1 : i;
+}
+
+static char txtfmt_pov_ini_format_identifier(const char *str)
+{
+ char fmt;
+ if ((txtfmt_ini_find_keyword(str)) != -1) fmt = FMT_TYPE_KEYWORD;
+ else if ((txtfmt_ini_find_reserved(str)) != -1) fmt = FMT_TYPE_RESERVED;
+ else fmt = FMT_TYPE_DEFAULT;
+ return fmt;
+}
+
+static void txtfmt_pov_ini_format_line(SpaceText *st, TextLine *line, const bool do_next)
+{
+ FlattenString fs;
+ const char *str;
+ char *fmt;
+ char cont_orig, cont, find, prev = ' ';
+ int len, i;
+
+ /* Get continuation from previous line */
+ if (line->prev && line->prev->format != NULL) {
+ fmt = line->prev->format;
+ cont = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
+ BLI_assert((FMT_CONT_ALL & cont) == cont);
+ }
+ else {
+ cont = FMT_CONT_NOP;
+ }
+
+ /* Get original continuation from this line */
+ if (line->format != NULL) {
+ fmt = line->format;
+ cont_orig = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
+ BLI_assert((FMT_CONT_ALL & cont_orig) == cont_orig);
+ }
+ else {
+ cont_orig = 0xFF;
+ }
+
+ len = flatten_string(st, &fs, line->line);
+ str = fs.buf;
+ if (!text_check_format_len(line, len)) {
+ flatten_string_free(&fs);
+ return;
+ }
+ fmt = line->format;
+
+ while (*str) {
+ /* Handle escape sequences by skipping both \ and next char */
+ if (*str == '\\') {
+ *fmt = prev; fmt++; str++;
+ if (*str == '\0') break;
+ *fmt = prev; fmt++; str += BLI_str_utf8_size_safe(str);
+ continue;
+ }
+ /* Handle continuations */
+ else if (cont) {
+ /* Multi-line comments */
+ if (cont & FMT_CONT_COMMENT_C) {
+ if (*str == ']' && *(str + 1) == ']') {
+ *fmt = FMT_TYPE_COMMENT; fmt++; str++;
+ *fmt = FMT_TYPE_COMMENT;
+ cont = FMT_CONT_NOP;
+ }
+ else {
+ *fmt = FMT_TYPE_COMMENT;
+ }
+ /* Handle other comments */
+ }
+ else {
+ find = (cont & FMT_CONT_QUOTEDOUBLE) ? '"' : '\'';
+ if (*str == find) cont = 0;
+ *fmt = FMT_TYPE_STRING;
+ }
+
+ str += BLI_str_utf8_size_safe(str) - 1;
+ }
+ /* Not in a string... */
+ else {
+ /* Multi-line comments not supported */
+ /* Single line comment */
+ if (*str == ';') {
+ text_format_fill(&str, &fmt, FMT_TYPE_COMMENT, len - (int)(fmt - line->format));
+ }
+ else if (*str == '"' || *str == '\'') {
+ /* Strings */
+ find = *str;
+ cont = (*str == '"') ? FMT_CONT_QUOTEDOUBLE : FMT_CONT_QUOTESINGLE;
+ *fmt = FMT_TYPE_STRING;
+ }
+ /* Whitespace (all ws. has been converted to spaces) */
+ else if (*str == ' ') {
+ *fmt = FMT_TYPE_WHITESPACE;
+ }
+ /* Numbers (digits not part of an identifier and periods followed by digits) */
+ else if ((prev != FMT_TYPE_DEFAULT && text_check_digit(*str)) ||
+ (*str == '.' && text_check_digit(*(str + 1))))
+ {
+ *fmt = FMT_TYPE_NUMERAL;
+ }
+ /* Booleans */
+ else if (prev != FMT_TYPE_DEFAULT && (i = txtfmt_ini_find_bool(str)) != -1) {
+ if (i > 0) {
+ text_format_fill_ascii(&str, &fmt, FMT_TYPE_NUMERAL, i);
+ }
+ else {
+ str += BLI_str_utf8_size_safe(str) - 1;
+ *fmt = FMT_TYPE_DEFAULT;
+ }
+ }
+ /* Punctuation */
+ else if ((*str != '#') && text_check_delim(*str)) {
+ *fmt = FMT_TYPE_SYMBOL;
+ }
+ /* Identifiers and other text (no previous ws. or delims. so text continues) */
+ else if (prev == FMT_TYPE_DEFAULT) {
+ str += BLI_str_utf8_size_safe(str) - 1;
+ *fmt = FMT_TYPE_DEFAULT;
+ }
+ /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */
+ else {
+ /* Special vars(v) or built-in keywords(b) */
+ /* keep in sync with 'txtfmt_ini_format_identifier()' */
+ if ((i = txtfmt_ini_find_keyword(str)) != -1) prev = FMT_TYPE_KEYWORD;
+ else if ((i = txtfmt_ini_find_reserved(str)) != -1) prev = FMT_TYPE_RESERVED;
+
+ if (i > 0) {
+ text_format_fill_ascii(&str, &fmt, prev, i);
+ }
+ else {
+ str += BLI_str_utf8_size_safe(str) - 1;
+ *fmt = FMT_TYPE_DEFAULT;
+ }
+ }
+ }
+ prev = *fmt; fmt++; str++;
+ }
+
+ /* Terminate and add continuation char */
+ *fmt = '\0'; fmt++;
+ *fmt = cont;
+
+ /* If continuation has changed and we're allowed, process the next line */
+ if (cont != cont_orig && do_next && line->next) {
+ txtfmt_pov_ini_format_line(st, line->next, do_next);
+ }
+
+ flatten_string_free(&fs);
+}
+
+void ED_text_format_register_pov_ini(void)
+{
+ static TextFormatType tft = {NULL};
+ static const char *ext[] = {"ini", NULL};
+
+ tft.format_identifier = txtfmt_pov_ini_format_identifier;
+ tft.format_line = txtfmt_pov_ini_format_line;
+ tft.ext = ext;
+
+ ED_text_format_register(&tft);
+}
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index e7428fd79d9..548cf157c0f 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -197,7 +197,7 @@ void TEXT_OT_new(wmOperatorType *ot)
/* identifiers */
ot->name = "Create Text Block";
ot->idname = "TEXT_OT_new";
- ot->description = "Create a new text data block";
+ ot->description = "Create a new text data-block";
/* api callbacks */
ot->exec = text_new_exec;
@@ -248,12 +248,14 @@ static int text_open_exec(bContext *C, wmOperator *op)
pprop = op->customdata;
if (pprop->prop) {
+ id_us_ensure_real(&text->id);
RNA_id_pointer_create(&text->id, &idptr);
RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr);
RNA_property_update(C, &pprop->ptr, pprop->prop);
}
else if (st) {
st->text = text;
+ id_us_ensure_real(&text->id);
st->left = 0;
st->top = 0;
st->scroll_accum[0] = 0.0f;
@@ -288,7 +290,7 @@ void TEXT_OT_open(wmOperatorType *ot)
/* identifiers */
ot->name = "Open Text Block";
ot->idname = "TEXT_OT_open";
- ot->description = "Open a new text data block";
+ ot->description = "Open a new text data-block";
/* api callbacks */
ot->exec = text_open_exec;
@@ -348,7 +350,7 @@ void TEXT_OT_reload(wmOperatorType *ot)
/* identifiers */
ot->name = "Reload";
ot->idname = "TEXT_OT_reload";
- ot->description = "Reload active text data block from its file";
+ ot->description = "Reload active text data-block from its file";
/* api callbacks */
ot->exec = text_reload_exec;
@@ -397,7 +399,7 @@ void TEXT_OT_unlink(wmOperatorType *ot)
/* identifiers */
ot->name = "Unlink";
ot->idname = "TEXT_OT_unlink";
- ot->description = "Unlink active text data block";
+ ot->description = "Unlink active text data-block";
/* api callbacks */
ot->exec = text_unlink_exec;
@@ -512,7 +514,7 @@ void TEXT_OT_save(wmOperatorType *ot)
/* identifiers */
ot->name = "Save";
ot->idname = "TEXT_OT_save";
- ot->description = "Save active text data block";
+ ot->description = "Save active text data-block";
/* api callbacks */
ot->exec = text_save_exec;
@@ -692,7 +694,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
@@ -3187,7 +3189,7 @@ void TEXT_OT_to_3d_object(wmOperatorType *ot)
/* identifiers */
ot->name = "To 3D Object";
ot->idname = "TEXT_OT_to_3d_object";
- ot->description = "Create 3D text object from active text data block";
+ ot->description = "Create 3D text object from active text data-block";
/* api callbacks */
ot->exec = text_to_3d_object_exec;
diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c
index 021c4a54b0a..4672cc073fc 100644
--- a/source/blender/editors/space_time/space_time.c
+++ b/source/blender/editors/space_time/space_time.c
@@ -60,7 +60,6 @@
#include "WM_types.h"
#include "BIF_gl.h"
-#include "BIF_glutil.h"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -69,6 +68,9 @@
#include "ED_space_api.h"
#include "ED_markers.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+
#include "time_intern.h"
/* ************************ main time area region *********************** */
@@ -80,28 +82,42 @@ static void time_draw_sfra_efra(Scene *scene, View2D *v2d)
*/
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
- glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
-
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4f(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);
+ immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax);
+ immRectf(pos, (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);
+ immRectf(pos, 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);
+ immUniformThemeColorShade(TH_BACK, -60);
+
+ immBegin(GWN_PRIM_LINES, 4);
+
+ immVertex2f(pos, (float)PSFRA, v2d->cur.ymin);
+ immVertex2f(pos, (float)PSFRA, v2d->cur.ymax);
+
+ immVertex2f(pos, (float)PEFRA, v2d->cur.ymin);
+ immVertex2f(pos, (float)PEFRA, v2d->cur.ymax);
+
+ immEnd();
+ immUnbindProgram();
}
static void time_draw_cache(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;
@@ -110,12 +126,13 @@ static void time_draw_cache(SpaceTime *stime, Object *ob, Scene *scene)
BKE_ptcache_ids_from_object(&pidlist, ob, scene, 0);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
/* 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;
+ float col[4];
switch (pid->type) {
case PTCACHE_TYPE_SOFTBODY:
@@ -142,43 +159,9 @@ static void time_draw_cache(SpaceTime *stime, Object *ob, Scene *scene)
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);
+ gpuPushMatrix();
+ gpuTranslate2f(0.0, (float)V2D_SCROLL_HEIGHT + yoffs);
+ gpuScale2f(1.0, cache_draw_height);
switch (pid->type) {
case PTCACHE_TYPE_SOFTBODY:
@@ -212,12 +195,15 @@ static void time_draw_cache(SpaceTime *stime, Object *ob, Scene *scene)
BLI_assert(0);
break;
}
- glColor4fv(col);
-
+
+ const int sta = pid->cache->startframe, end = pid->cache->endframe;
+ const int len = (end - sta + 1) * 6;
+
glEnable(GL_BLEND);
-
- glRectf((float)sta, 0.0, (float)end, 1.0);
-
+
+ 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;
@@ -225,52 +211,38 @@ static void time_draw_cache(SpaceTime *stime, Object *ob, Scene *scene)
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;
- }
+ immUniformColor4fv(col);
- BLI_freelistN(&pidlist);
+ if (len > 0) {
+ immBeginAtMost(GWN_PRIM_TRIS, len);
- /* free excessive caches */
- while (stc) {
- SpaceTimeCache *tmp = stc->next;
- BLI_remlink(&stime->caches, stc);
- MEM_freeN(stc->array);
- MEM_freeN(stc);
- stc = tmp;
- }
-}
+ /* draw a quad for each cached frame */
+ for (int i = sta; i <= end; i++) {
+ if (pid->cache->cached_frames[i - sta]) {
+ immVertex2f(pos, (float)i - 0.5f, 0.0f);
+ immVertex2f(pos, (float)i - 0.5f, 1.0f);
+ immVertex2f(pos, (float)i + 0.5f, 1.0f);
-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;
+ immVertex2f(pos, (float)i - 0.5f, 0.0f);
+ immVertex2f(pos, (float)i + 0.5f, 1.0f);
+ immVertex2f(pos, (float)i + 0.5f, 0.0f);
+ }
+ }
+
+ immEnd();
}
+
+ glDisable(GL_BLEND);
+
+ gpuPopMatrix();
+
+ yoffs += cache_draw_height;
}
-
- BLI_freelistN(&stime->caches);
-}
-static void time_cache_refresh(SpaceTime *stime)
-{
- /* Free previous caches to indicate full refresh */
- time_cache_free(stime);
+ immUnbindProgram();
+
+ BLI_freelistN(&pidlist);
}
/* helper function - find actkeycolumn that occurs on cframe, or the nearest one if not found */
@@ -296,7 +268,7 @@ static ActKeyColumn *time_cfra_find_ak(ActKeyColumn *ak, float cframe)
}
/* helper for time_draw_keyframes() */
-static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel)
+static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel, const unsigned char color[3])
{
bDopeSheet ads = {NULL};
DLRBT_Tree keys;
@@ -339,21 +311,42 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel)
* 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);
+
+ ActKeyColumn *link;
+ int max_len = 0;
+
+ ak = time_cfra_find_ak(keys.root, v2d->cur.xmin);
+
+ for (link = ak; link; link = link->next) {
+ max_len++;
}
- glEnd(); // GL_LINES
-
+
+ if (max_len > 0) {
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3ubv(color);
+
+ immBeginAtMost(GWN_PRIM_LINES, max_len * 2);
+
+ for (; (ak) && (ak->cfra <= v2d->cur.xmax);
+ ak = ak->next)
+ {
+ immVertex2f(pos, ak->cfra, ymin);
+ immVertex2f(pos, ak->cfra, ymax);
+ }
+
+ immEnd();
+ immUnbindProgram();
+ }
+
/* free temp stuff */
BLI_dlrbTree_free(&keys);
}
-static void time_draw_caches_keyframes(Main *bmain, Scene *scene, View2D *v2d, bool onlysel)
+static void time_draw_caches_keyframes(Main *bmain, SceneLayer *sl, View2D *v2d, bool onlysel, const unsigned char color[3])
{
CacheFile *cache_file;
@@ -364,7 +357,7 @@ static void time_draw_caches_keyframes(Main *bmain, Scene *scene, View2D *v2d, b
cache_file->draw_flag &= ~CACHEFILE_KEYFRAME_DRAWN;
}
- for (Base *base = scene->base.first; base; base = base->next) {
+ for (Base *base = sl->object_bases.first; base; base = base->next) {
Object *ob = base->object;
ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);
@@ -380,7 +373,7 @@ static void time_draw_caches_keyframes(Main *bmain, Scene *scene, View2D *v2d, b
cache_file->draw_flag |= CACHEFILE_KEYFRAME_DRAWN;
- time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel);
+ time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel, color);
}
for (bConstraint *con = ob->constraints.first; con; con = con->next) {
@@ -398,7 +391,7 @@ static void time_draw_caches_keyframes(Main *bmain, Scene *scene, View2D *v2d, b
cache_file->draw_flag |= CACHEFILE_KEYFRAME_DRAWN;
- time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel);
+ time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel, color);
}
}
}
@@ -407,24 +400,27 @@ static void time_draw_caches_keyframes(Main *bmain, Scene *scene, View2D *v2d, b
static void time_draw_keyframes(const bContext *C, ARegion *ar)
{
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *ob = CTX_data_active_object(C);
View2D *v2d = &ar->v2d;
bool onlysel = ((scene->flag & SCE_KEYS_NO_SELONLY) == 0);
+ unsigned char color[3];
/* 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);
+ UI_GetThemeColor3ubv(TH_TIME_KEYFRAME, color);
+ time_draw_caches_keyframes(CTX_data_main(C), sl, v2d, onlysel, color);
/* draw grease pencil keyframes (if available) */
- UI_ThemeColor(TH_TIME_GP_KEYFRAME);
+ UI_GetThemeColor3ubv(TH_TIME_GP_KEYFRAME, color);
+
if (scene->gpd) {
- time_draw_idblock_keyframes(v2d, (ID *)scene->gpd, onlysel);
+ time_draw_idblock_keyframes(v2d, (ID *)scene->gpd, onlysel, color);
}
if (ob && ob->gpd) {
- time_draw_idblock_keyframes(v2d, (ID *)ob->gpd, onlysel);
+ time_draw_idblock_keyframes(v2d, (ID *)ob->gpd, onlysel, color);
}
/* draw scene keyframes first
@@ -433,8 +429,8 @@ static void time_draw_keyframes(const bContext *C, ARegion *ar)
*/
if (onlysel == 0) {
/* set draw color */
- UI_ThemeColorShade(TH_TIME_KEYFRAME, -50);
- time_draw_idblock_keyframes(v2d, (ID *)scene, onlysel);
+ UI_GetThemeColorShade3ubv(TH_TIME_KEYFRAME, -50, color);
+ time_draw_idblock_keyframes(v2d, (ID *)scene, onlysel, color);
}
/* draw keyframes from selected objects
@@ -442,11 +438,11 @@ static void time_draw_keyframes(const bContext *C, ARegion *ar)
* OR the onlysel flag was set, which means that only active object's keyframes should
* be considered
*/
- UI_ThemeColor(TH_TIME_KEYFRAME);
-
+ UI_GetThemeColor3ubv(TH_TIME_KEYFRAME, color);
+
if (ob && ((ob->mode == OB_MODE_POSE) || onlysel)) {
/* draw keyframes for active object only */
- time_draw_idblock_keyframes(v2d, (ID *)ob, onlysel);
+ time_draw_idblock_keyframes(v2d, (ID *)ob, onlysel, color);
}
else {
bool active_done = false;
@@ -455,7 +451,7 @@ static void time_draw_keyframes(const bContext *C, ARegion *ar)
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);
+ time_draw_idblock_keyframes(v2d, (ID *)obsel, 0, color);
/* if this object is the active one, set flag so that we don't draw again */
if (obsel == ob)
@@ -465,24 +461,14 @@ static void time_draw_keyframes(const bContext *C, ARegion *ar)
/* if active object hasn't been done yet, draw it... */
if (ob && (active_done == 0))
- time_draw_idblock_keyframes(v2d, (ID *)ob, 0);
+ time_draw_idblock_keyframes(v2d, (ID *)ob, 0, color);
}
}
/* ---------------- */
-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)
+static void time_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* mainly for updating cache display */
@@ -623,7 +609,9 @@ static void time_main_region_draw(const bContext *C, ARegion *ar)
UI_view2d_scrollers_free(scrollers);
}
-static void time_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void time_main_region_listener(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -652,6 +640,11 @@ static void time_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa),
if (wmn->data == ND_DATA)
ED_region_tag_redraw(ar);
break;
+ case NC_SCREEN:
+ if (ELEM(wmn->data, ND_LAYER)) {
+ ED_region_tag_redraw(ar);
+ }
+ break;
}
}
@@ -668,7 +661,9 @@ 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)
+static void time_header_region_listener(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -752,13 +747,6 @@ static SpaceLink *time_new(const bContext *C)
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 */
@@ -766,8 +754,6 @@ 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);
@@ -796,13 +782,11 @@ void ED_spacetype_time(void)
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");
@@ -813,6 +797,7 @@ void ED_spacetype_time(void)
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 */
diff --git a/source/blender/editors/space_time/time_ops.c b/source/blender/editors/space_time/time_ops.c
index 7dd45327352..872793128f0 100644
--- a/source/blender/editors/space_time/time_ops.c
+++ b/source/blender/editors/space_time/time_ops.c
@@ -219,7 +219,9 @@ void time_keymap(wmKeyConfig *keyconf)
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_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c
index aeba4a86f3e..f640fe63f93 100644
--- a/source/blender/editors/space_userpref/space_userpref.c
+++ b/source/blender/editors/space_userpref/space_userpref.c
@@ -136,12 +136,16 @@ 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))
+static void userpref_main_region_listener(
+ bScreen *UNUSED(sc), 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(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar),
+ wmNotifier *UNUSED(wmn), const Scene *UNUSED(scene))
{
/* context changes */
#if 0
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index da793361ede..c442b1a377d 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
@@ -53,11 +54,13 @@ set(SRC
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_manipulators.c
view3d_ops.c
view3d_project.c
view3d_ruler.c
@@ -91,8 +94,8 @@ if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
-if(WITH_LEGACY_DEPSGRAPH)
- add_definitions(-DWITH_LEGACY_DEPSGRAPH)
+if(WITH_MOD_SMOKE)
+ add_definitions(-DWITH_SMOKE)
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
index cf738de0202..66355a50478 100644
--- a/source/blender/editors/space_view3d/drawanimviz.c
+++ b/source/blender/editors/space_view3d/drawanimviz.c
@@ -49,7 +49,8 @@
#include "BKE_animsys.h"
#include "BKE_action.h"
-#include "BIF_gl.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
#include "ED_keyframes_draw.h"
@@ -71,8 +72,88 @@ void draw_motion_paths_init(View3D *v3d, ARegion *ar)
if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
- glPushMatrix();
- glLoadMatrixf(rv3d->viewmat);
+ gpuPushMatrix();
+ gpuLoadMatrix(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], unsigned color)
+{
+ int frame = sfra + i;
+ int blend_base = (abs(frame - CFRA) == 1) ? TH_CFRAME : TH_BACK; /* "bleed" cframe color to ease color blending */
+ unsigned char ubcolor[3];
+
+#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 */
+ rgb_float_to_uchar(ubcolor, 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_GetThemeColorBlend3ubv(TH_WIRE, blend_base, intensity, ubcolor);
+ }
+ }
+ else if (frame > CFRA) {
+ if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) {
+ /* Custom color: next frames color is equal to user selected color */
+ rgb_float_to_uchar(ubcolor, 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_GetThemeColorBlend3ubv(TH_BONE_POSE, blend_base, intensity, ubcolor);
+ }
+ }
+ else {
+ if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) {
+ /* Custom color: current frame color is slightly darker than user selected color */
+ rgb_float_to_uchar(ubcolor, frame_color);
+ }
+ else {
+ /* green - on cfra */
+ if (sel) {
+ intensity = 0.5f;
+ }
+ else {
+ intensity = 0.99f;
+ }
+ UI_GetThemeColorBlendShade3ubv(TH_CFRAME, TH_BACK, intensity, 10, ubcolor);
+ }
+ }
+
+ immAttrib3ubv(color, ubcolor);
+
+#undef SET_INTENSITY
}
/* Draw the given motion path for an Object or a Bone
@@ -86,6 +167,28 @@ void draw_motion_path_instance(Scene *scene,
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) {
@@ -130,96 +233,89 @@ void draw_motion_path_instance(Scene *scene,
mpv_start = (mpath->points + sind);
/* draw curve-line of path */
-
- 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);
- float intensity; /* how faint */
-
- int frame = sfra + i;
- int blend_base = (abs(frame - CFRA) == 1) ? TH_CFRAME : TH_BACK; /* "bleed" cframe color to ease color blending */
-
- /* 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
- */
-#define SET_INTENSITY(A, B, C, min, max) (((1.0f - ((C - B) / (C - A))) * (max - min)) + min)
- if (frame < CFRA) {
- /* 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) {
- /* 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 {
- /* green - on cfra */
- if (sel) {
- intensity = 0.5f;
- }
- else {
- intensity = 0.99f;
- }
- UI_ThemeColorBlendShade(TH_CFRAME, TH_BACK, intensity, 10);
+ /* Draw lines only if line drawing option is enabled */
+ if (mpath->flag & MOTIONPATH_FLAG_LINES) {
+ /* set line thickness */
+ glLineWidth(mpath->line_thickness);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR);
+
+ immBegin(GWN_PRIM_LINE_STRIP, len);
+
+ 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, color);
+
+ /* draw a vertex with this color */
+ immVertex3fv(pos, mpv->co);
}
-#undef SET_INTENSITY
- /* draw a vertex with this color */
- glVertex3fv(mpv->co);
+ immEnd();
+
+ immUnbindProgram();
+
+ /* back to old line thickness */
+ glLineWidth(old_width);
}
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ /* Point must be bigger than line thickness */
+ glPointSize(mpath->line_thickness + 1.0);
- glEnd();
-
- glPointSize(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 */
- 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 little black point at each frame */
+ immUniformColor3ub(0, 0, 0);
+
+ immBegin(GWN_PRIM_POINTS, len);
+
+ for (i = 0, mpv = mpv_start; i < len; i++, mpv++) {
+ immVertex3fv(pos, mpv->co);
+ }
+
+ immEnd();
+
+ /* Draw little white dots at each framestep value or replace with custom color */
+ if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) {
+ immUniformColor3fv(mpath->color);
+ }
+ else {
+ immUniformThemeColor(TH_TEXT_HI);
+ }
+
+ immBegin(GWN_PRIM_POINTS, (len + stepsize - 1) / stepsize);
+
+ for (i = 0, mpv = mpv_start; i < len; i += stepsize, mpv += stepsize) {
+ immVertex3fv(pos, mpv->co);
+ }
+
+ immEnd();
/* 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))
+ (sfra < CFRA) && (CFRA <= efra))
{
- UI_ThemeColor(TH_CFRAME);
- glPointSize(6.0f);
-
- glBegin(GL_POINTS);
+ glPointSize(mpath->line_thickness + 5.0);
+ immUniformThemeColor(TH_CFRAME);
+
+ immBegin(GWN_PRIM_POINTS, 1);
+
mpv = mpv_start + (CFRA - sfra);
- glVertex3fv(mpv->co);
- glEnd();
-
- UI_ThemeColor(TH_TEXT_HI);
+ immVertex3fv(pos, mpv->co);
+
+ immEnd();
}
+
+ immUnbindProgram();
/* XXX, this isn't up to date but probably should be kept so. */
invert_m4_m4(ob->imat, ob->obmat);
@@ -289,18 +385,28 @@ void draw_motion_path_instance(Scene *scene,
UI_GetThemeColor3ubv(TH_VERTEX_SELECT, col);
col[3] = 255;
- glPointSize(4.0f);
- glColor3ubv(col);
+ /* point must be bigger than line */
+ glPointSize(mpath->line_thickness + 3.0);
+
+ pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor3ubv(col);
- glBegin(GL_POINTS);
+ immBeginAtMost(GWN_PRIM_POINTS, len);
+
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);
+ if (BLI_dlrbTree_search_exact(&keys, compare_ak_cfraPtr, &mframe)) {
+ immVertex3fv(pos, mpv->co);
+ }
}
- glEnd();
+
+ immEnd();
+
+ immUnbindProgram();
/* Draw frame numbers of keyframes */
if (avs->path_viewflag & MOTIONPATH_VIEW_KFNOS) {
@@ -328,5 +434,5 @@ void draw_motion_path_instance(Scene *scene,
void draw_motion_paths_cleanup(View3D *v3d)
{
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
- glPopMatrix();
+ gpuPopMatrix();
}
diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c
index 1d9a515a5f2..115574a5ffe 100644
--- a/source/blender/editors/space_view3d/drawarmature.c
+++ b/source/blender/editors/space_view3d/drawarmature.c
@@ -55,14 +55,16 @@
#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 "GPU_batch.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
#include "UI_resources.h"
@@ -74,8 +76,10 @@
/* global here is reset before drawing each bone */
static ThemeWireColor *bcolor = NULL;
+static float fcolor[4] = {0.0f};
+static bool flat_color;
-/* values of colCode for set_pchan_glcolor */
+/* values of colCode for set_pchan_color */
enum {
PCHAN_COLOR_NORMAL = 0, /* normal drawing */
PCHAN_COLOR_SOLID, /* specific case where "solid" color is needed */
@@ -128,7 +132,7 @@ static void set_pchan_colorset(Object *ob, bPoseChannel *pchan)
}
}
-/* This function is for brightening/darkening a given color (like UI_ThemeColorShade()) */
+/* This function is for brightening/darkening a given color (like UI_GetThemeColorShade3ubv()) */
static void cp_shade_color3ub(unsigned char cp[3], const int offset)
{
int r, g, b;
@@ -146,13 +150,13 @@ static void cp_shade_color3ub(unsigned char cp[3], const int offset)
}
/* 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)
+static bool set_pchan_color(short colCode, int boneflag, short constflag)
{
switch (colCode) {
case PCHAN_COLOR_NORMAL:
{
if (bcolor) {
- unsigned char cp[3];
+ unsigned char cp[4] = {255};
if (boneflag & BONE_DRAW_ACTIVE) {
copy_v3_v3_char((char *)cp, bcolor->active);
@@ -169,20 +173,20 @@ static bool set_pchan_glColor(short colCode, int boneflag, short constflag)
cp_shade_color3ub(cp, -50);
}
- glColor3ubv(cp);
+ rgb_uchar_to_float(fcolor, cp);
}
else {
if ((boneflag & BONE_DRAW_ACTIVE) && (boneflag & BONE_SELECTED)) {
- UI_ThemeColor(TH_BONE_POSE_ACTIVE);
+ UI_GetThemeColor4fv(TH_BONE_POSE_ACTIVE, fcolor);
}
else if (boneflag & BONE_DRAW_ACTIVE) {
- UI_ThemeColorBlend(TH_WIRE, TH_BONE_POSE, 0.15f); /* unselected active */
+ UI_GetThemeColorBlendShade4fv(TH_WIRE, TH_BONE_POSE, 0.15f, 0, fcolor);
}
else if (boneflag & BONE_SELECTED) {
- UI_ThemeColor(TH_BONE_POSE);
+ UI_GetThemeColor4fv(TH_BONE_POSE, fcolor);
}
else {
- UI_ThemeColor(TH_WIRE);
+ UI_GetThemeColor4fv(TH_WIRE, fcolor);
}
}
@@ -191,21 +195,25 @@ static bool set_pchan_glColor(short colCode, int boneflag, short constflag)
case PCHAN_COLOR_SOLID:
{
if (bcolor) {
- glColor3ubv((unsigned char *)bcolor->solid);
+ rgb_uchar_to_float(fcolor, (unsigned char *)bcolor->solid);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor);
}
- 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);
-
+ unsigned char 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);
+
+ rgba_uchar_to_float(fcolor, cp);
+
return true;
}
return false;
@@ -213,7 +221,7 @@ static bool set_pchan_glColor(short colCode, int boneflag, short constflag)
case PCHAN_COLOR_SPHEREBONE_BASE:
{
if (bcolor) {
- unsigned char cp[3];
+ unsigned char cp[4] = {255};
if (boneflag & BONE_DRAW_ACTIVE) {
copy_v3_v3_char((char *)cp, bcolor->active);
@@ -225,12 +233,18 @@ static bool set_pchan_glColor(short colCode, int boneflag, short constflag)
copy_v3_v3_char((char *)cp, bcolor->solid);
}
- glColor3ubv(cp);
+ rgb_uchar_to_float(fcolor, 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);
+ 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;
@@ -238,7 +252,7 @@ static bool set_pchan_glColor(short colCode, int boneflag, short constflag)
case PCHAN_COLOR_SPHEREBONE_END:
{
if (bcolor) {
- unsigned char cp[3];
+ unsigned char cp[4] = {255};
if (boneflag & BONE_DRAW_ACTIVE) {
copy_v3_v3_char((char *)cp, bcolor->active);
@@ -253,12 +267,18 @@ static bool set_pchan_glColor(short colCode, int boneflag, short constflag)
cp_shade_color3ub(cp, -30);
}
- glColor3ubv(cp);
+ rgb_uchar_to_float(fcolor, 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);
+ 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;
}
@@ -266,19 +286,24 @@ static bool set_pchan_glColor(short colCode, int boneflag, short constflag)
{
/* 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 */
+ unsigned char 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;
- glColor4ub(cp[0], cp[1], cp[2], 204);
+ rgb_uchar_to_float(fcolor, (unsigned char *)cp);
+ fcolor[3] = 204.f / 255.f;
+ }
+ else {
+ UI_GetThemeColorShade4fv(TH_BACK, -30, fcolor);
}
- else
- UI_ThemeColorShade(TH_BACK, -30);
}
return true;
@@ -288,26 +313,37 @@ static bool set_pchan_glColor(short colCode, int boneflag, short constflag)
return false;
}
-static void set_ebone_glColor(const unsigned int boneflag)
+static void set_ebone_color(const unsigned int boneflag)
{
if ((boneflag & BONE_DRAW_ACTIVE) && (boneflag & BONE_SELECTED)) {
- UI_ThemeColor(TH_EDGE_SELECT);
+ UI_GetThemeColor4fv(TH_EDGE_SELECT, fcolor);
}
else if (boneflag & BONE_DRAW_ACTIVE) {
- UI_ThemeColorBlend(TH_WIRE_EDIT, TH_EDGE_SELECT, 0.15f); /* unselected active */
+ UI_GetThemeColorBlendShade4fv(TH_WIRE_EDIT, TH_EDGE_SELECT, 0.15f, 0, fcolor);
}
else if (boneflag & BONE_SELECTED) {
- UI_ThemeColorShade(TH_EDGE_SELECT, -20);
+ UI_GetThemeColorShade4fv(TH_EDGE_SELECT, -20, fcolor);
}
else {
- UI_ThemeColor(TH_WIRE_EDIT);
+ UI_GetThemeColor4fv(TH_WIRE_EDIT, fcolor);
}
}
/* *************** Armature drawing, helper calls for parts ******************* */
+static void add_solid_flat_triangle(Gwn_VertBuf *vbo, unsigned int *vertex, unsigned int pos, unsigned int nor,
+ const float p1[3], const float p2[3], const float p3[3], const float n[3])
+{
+ GWN_vertbuf_attr_set(vbo, nor, *vertex, n);
+ GWN_vertbuf_attr_set(vbo, pos, (*vertex)++, p1);
+ GWN_vertbuf_attr_set(vbo, nor, *vertex, n);
+ GWN_vertbuf_attr_set(vbo, pos, (*vertex)++, p2);
+ GWN_vertbuf_attr_set(vbo, nor, *vertex, n);
+ GWN_vertbuf_attr_set(vbo, pos, (*vertex)++, p3);
+}
+
/* half the cube, in Y */
-static const float cube[8][3] = {
+static const float cube_vert[8][3] = {
{-1.0, 0.0, -1.0},
{-1.0, 0.0, 1.0},
{-1.0, 1.0, 1.0},
@@ -318,128 +354,184 @@ static const float cube[8][3] = {
{ 1.0, 1.0, -1.0},
};
+static const float cube_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,
+};
+
static void drawsolidcube_size(float xsize, float ysize, float zsize)
{
- static GLuint displist = 0;
- float n[3] = {0.0f};
-
- glScalef(xsize, ysize, zsize);
+ static Gwn_VertFormat format = {0};
+ static Gwn_VertBuf vbo = {{0}};
+ static Gwn_Batch batch = {{0}};
+ const float light_vec[3] = {0.0f, 0.0f, 1.0f};
+
+ if (format.attrib_ct == 0) {
+ unsigned int i = 0;
+ float n[3] = {0.0f};
+ /* Vertex format */
+ unsigned int pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ unsigned int nor = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ /* Vertices */
+ GWN_vertbuf_init_with_format(&vbo, &format);
+ GWN_vertbuf_data_alloc(&vbo, 36);
- 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]);
+ add_solid_flat_triangle(&vbo, &i, pos, nor, cube_vert[0], cube_vert[1], cube_vert[2], n);
+ add_solid_flat_triangle(&vbo, &i, pos, nor, cube_vert[2], cube_vert[3], cube_vert[0], n);
n[0] = 0;
n[1] = -1.0;
- glNormal3fv(n);
- glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[1]);
+ add_solid_flat_triangle(&vbo, &i, pos, nor, cube_vert[0], cube_vert[4], cube_vert[5], n);
+ add_solid_flat_triangle(&vbo, &i, pos, nor, cube_vert[5], cube_vert[1], cube_vert[0], n);
n[1] = 0;
n[0] = 1.0;
- glNormal3fv(n);
- glVertex3fv(cube[4]); glVertex3fv(cube[7]); glVertex3fv(cube[6]); glVertex3fv(cube[5]);
+ add_solid_flat_triangle(&vbo, &i, pos, nor, cube_vert[4], cube_vert[7], cube_vert[6], n);
+ add_solid_flat_triangle(&vbo, &i, pos, nor, cube_vert[6], cube_vert[5], cube_vert[4], n);
n[0] = 0;
n[1] = 1.0;
- glNormal3fv(n);
- glVertex3fv(cube[7]); glVertex3fv(cube[3]); glVertex3fv(cube[2]); glVertex3fv(cube[6]);
+ add_solid_flat_triangle(&vbo, &i, pos, nor, cube_vert[7], cube_vert[3], cube_vert[2], n);
+ add_solid_flat_triangle(&vbo, &i, pos, nor, cube_vert[2], cube_vert[6], cube_vert[7], n);
n[1] = 0;
n[2] = 1.0;
- glNormal3fv(n);
- glVertex3fv(cube[1]); glVertex3fv(cube[5]); glVertex3fv(cube[6]); glVertex3fv(cube[2]);
+ add_solid_flat_triangle(&vbo, &i, pos, nor, cube_vert[1], cube_vert[5], cube_vert[6], n);
+ add_solid_flat_triangle(&vbo, &i, pos, nor, cube_vert[6], cube_vert[2], cube_vert[1], n);
n[2] = -1.0;
- glNormal3fv(n);
- glVertex3fv(cube[7]); glVertex3fv(cube[4]); glVertex3fv(cube[0]); glVertex3fv(cube[3]);
- glEnd();
+ add_solid_flat_triangle(&vbo, &i, pos, nor, cube_vert[7], cube_vert[4], cube_vert[0], n);
+ add_solid_flat_triangle(&vbo, &i, pos, nor, cube_vert[0], cube_vert[3], cube_vert[7], n);
- glEndList();
+ GWN_batch_init(&batch, GWN_PRIM_TRIS, &vbo, NULL);
}
- glCallList(displist);
+ gpuPushMatrix();
+ gpuScale3f(xsize, ysize, zsize);
+
+ if (flat_color) {
+ Batch_set_builtin_program(&batch, GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+ else {
+ /* TODO replace with good default lighting shader ? */
+ Batch_set_builtin_program(&batch, GPU_SHADER_SIMPLE_LIGHTING);
+ GWN_batch_uniform_3fv(&batch, "light", light_vec);
+ }
+ GWN_batch_uniform_4fv(&batch, "color", fcolor);
+ GWN_batch_draw(&batch);
+
+ gpuPopMatrix();
}
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();
+ static Gwn_VertFormat format = {0};
+ static Gwn_VertBuf vbo = {{0}};
+ static Gwn_IndexBufBuilder elb = {0};
+ static Gwn_IndexBuf el = {0};
+ static Gwn_Batch batch = {{0}};
+
+ if (format.attrib_ct == 0) {
+ /* Vertex format */
+ unsigned int pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ /* Elements */
+ GWN_indexbuf_init(&elb, GWN_PRIM_LINES, 12, 8);
+ for (int i = 0; i < 12; ++i) {
+ GWN_indexbuf_add_line_verts(&elb, cube_wire[i*2], cube_wire[i*2+1]);
+ }
+ GWN_indexbuf_build_in_place(&elb, &el);
+
+ /* Vertices */
+ GWN_vertbuf_init_with_format(&vbo, &format);
+ GWN_vertbuf_data_alloc(&vbo, 8);
+ for (int i = 0; i < 8; ++i) {
+ GWN_vertbuf_attr_set(&vbo, pos, i, cube_vert[i]);
+ }
+
+ GWN_batch_init(&batch, GWN_PRIM_LINES, &vbo, &el);
+ Batch_set_builtin_program(&batch, GPU_SHADER_3D_UNIFORM_COLOR);
}
- glScalef(xsize, ysize, zsize);
- glCallList(displist);
-
+ gpuPushMatrix();
+ gpuScale3f(xsize, ysize, zsize);
+
+ GWN_batch_program_use_begin(&batch);
+ GWN_batch_uniform_4fv(&batch, "color", fcolor);
+ GWN_batch_draw(&batch);
+
+ gpuPopMatrix();
}
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();
+ static Gwn_VertFormat format = {0};
+ static Gwn_VertBuf vbo = {{0}};
+ static Gwn_Batch batch = {{0}};
+
+ if (format.attrib_ct == 0) {
+ /* Vertex format */
+ unsigned int pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ /* Vertices */
+ GWN_vertbuf_init_with_format(&vbo, &format);
+ GWN_vertbuf_data_alloc(&vbo, 96);
+ for (int i = 0; i < 16; ++i) {
+ float vert[3] = {0.f, 0.f, 0.f};
+ const float r = 0.05f;
+
+ vert[0] = r * cosf(2 * M_PI * i / 16.f);
+ vert[1] = r * sinf(2 * M_PI * i / 16.f);
+ GWN_vertbuf_attr_set(&vbo, pos, i * 6 + 0, vert);
+ vert[0] = r * cosf(2 * M_PI * (i + 1) / 16.f);
+ vert[1] = r * sinf(2 * M_PI * (i + 1) / 16.f);
+ GWN_vertbuf_attr_set(&vbo, pos, i * 6 + 1, vert);
+
+ vert[0] = 0.f;
+ vert[1] = r * cosf(2 * M_PI * i / 16.f);
+ vert[2] = r * sinf(2 * M_PI * i / 16.f);
+ GWN_vertbuf_attr_set(&vbo, pos, i * 6 + 2, vert);
+ vert[1] = r * cosf(2 * M_PI * (i + 1) / 16.f);
+ vert[2] = r * sinf(2 * M_PI * (i + 1) / 16.f);
+ GWN_vertbuf_attr_set(&vbo, pos, i * 6 + 3, vert);
+
+ vert[1] = 0.f;
+ vert[0] = r * cosf(2 * M_PI * i / 16.f);
+ vert[2] = r * sinf(2 * M_PI * i / 16.f);
+ GWN_vertbuf_attr_set(&vbo, pos, i * 6 + 4, vert);
+ vert[0] = r * cosf(2 * M_PI * (i + 1) / 16.f);
+ vert[2] = r * sinf(2 * M_PI * (i + 1) / 16.f);
+ GWN_vertbuf_attr_set(&vbo, pos, i * 6 + 5, vert);
+ }
+
+ GWN_batch_init(&batch, GWN_PRIM_LINES, &vbo, NULL);
+ Batch_set_builtin_program(&batch, GPU_SHADER_3D_UNIFORM_COLOR);
}
- glCallList(displist);
+ GWN_batch_program_use_begin(&batch);
+ GWN_batch_uniform_4fv(&batch, "color", fcolor);
+ GWN_batch_draw(&batch);
}
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();
+ Gwn_Batch *batch = Batch_get_sphere(0);
+ const float light_vec[3] = {0.0f, 0.0f, 1.0f};
+
+ gpuPushMatrix();
+ gpuScaleUniform(0.05);
+
+ if (flat_color) {
+ Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+ else {
+ /* TODO replace with good default lighting shader ? */
+ Batch_set_builtin_program(batch, GPU_SHADER_SIMPLE_LIGHTING);
+ GWN_batch_uniform_3fv(batch, "light", light_vec);
}
+ GWN_batch_uniform_4fv(batch, "color", fcolor);
+ GWN_batch_draw(batch);
- glCallList(displist);
+ gpuPopMatrix();
}
static const float bone_octahedral_verts[6][3] = {
@@ -451,8 +543,11 @@ static const float bone_octahedral_verts[6][3] = {
{ 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_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,
+};
static const unsigned int bone_octahedral_solid_tris[8][3] = {
{2, 1, 0}, /* bottom */
@@ -480,70 +575,78 @@ static const float bone_octahedral_solid_normals[8][3] = {
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();
+ static Gwn_VertFormat format = {0};
+ static Gwn_VertBuf vbo = {{0}};
+ static Gwn_IndexBufBuilder elb = {0};
+ static Gwn_IndexBuf el = {0};
+ static Gwn_Batch batch = {{0}};
+
+ if (format.attrib_ct == 0) {
+ /* Vertex format */
+ unsigned int pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ /* Elements */
+ GWN_indexbuf_init(&elb, GWN_PRIM_LINES, 12, 6);
+ for (int i = 0; i < 12; ++i) {
+ GWN_indexbuf_add_line_verts(&elb, bone_octahedral_wire[i*2], bone_octahedral_wire[i*2+1]);
+ }
+ GWN_indexbuf_build_in_place(&elb, &el);
+
+ /* Vertices */
+ GWN_vertbuf_init_with_format(&vbo, &format);
+ GWN_vertbuf_data_alloc(&vbo, 6);
+ for (int i = 0; i < 6; ++i) {
+ GWN_vertbuf_attr_set(&vbo, pos, i, bone_octahedral_verts[i]);
+ }
+
+ GWN_batch_init(&batch, GWN_PRIM_LINES, &vbo, &el);
+ Batch_set_builtin_program(&batch, GPU_SHADER_3D_UNIFORM_COLOR);
}
- glCallList(displist);
-}
+ GWN_batch_program_use_begin(&batch);
+ GWN_batch_uniform_4fv(&batch, "color", fcolor);
+ GWN_batch_draw(&batch);
+}
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
+ static Gwn_VertFormat format = {0};
+ static Gwn_VertBuf vbo = {{0}};
+ static Gwn_Batch batch = {{0}};
+ const float light_vec[3] = {0.0f, 0.0f, 1.0f};
+
+ if (format.attrib_ct == 0) {
+ unsigned int v_idx = 0;
+ /* Vertex format */
+ unsigned int pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ unsigned int nor = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ /* Vertices */
+ GWN_vertbuf_init_with_format(&vbo, &format);
+ GWN_vertbuf_data_alloc(&vbo, 24);
+
+ for (int i = 0; i < 8; i++) {
+ add_solid_flat_triangle(&vbo, &v_idx, pos, nor,
+ bone_octahedral_verts[bone_octahedral_solid_tris[i][0]],
+ bone_octahedral_verts[bone_octahedral_solid_tris[i][1]],
+ bone_octahedral_verts[bone_octahedral_solid_tris[i][2]],
+ bone_octahedral_solid_normals[i]);
+ }
- glEndList();
+ GWN_batch_init(&batch, GWN_PRIM_TRIS, &vbo, NULL);
}
- glCallList(displist);
-}
+ if (flat_color) {
+ Batch_set_builtin_program(&batch, GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+ else {
+ /* TODO replace with good default lighting shader ? */
+ Batch_set_builtin_program(&batch, GPU_SHADER_SIMPLE_LIGHTING);
+ GWN_batch_uniform_3fv(&batch, "light", light_vec);
+ }
+ GWN_batch_uniform_4fv(&batch, "color", fcolor);
+ GWN_batch_draw(&batch);
+}
/* *************** Armature drawing, bones ******************* */
@@ -557,15 +660,20 @@ static void draw_bone_points(const short dt, int armflag, unsigned int boneflag,
if (dt <= OB_WIRE) {
if (armflag & ARM_EDITMODE) {
- if (boneflag & BONE_ROOTSEL) UI_ThemeColor(TH_VERTEX_SELECT);
- else UI_ThemeColor(TH_VERTEX);
+ if (boneflag & BONE_ROOTSEL) {
+ UI_GetThemeColor4fv(TH_VERTEX_SELECT, fcolor);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_VERTEX, fcolor);
+ }
}
}
else {
if (armflag & ARM_POSEMODE)
- set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, 0);
- else
- UI_ThemeColor(TH_BONE_SOLID);
+ set_pchan_color(PCHAN_COLOR_SOLID, boneflag, 0);
+ else {
+ UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor);
+ }
}
if (dt > OB_WIRE)
@@ -580,24 +688,29 @@ static void draw_bone_points(const short dt, int armflag, unsigned int boneflag,
if (dt <= OB_WIRE) {
if (armflag & ARM_EDITMODE) {
- if (boneflag & BONE_TIPSEL) UI_ThemeColor(TH_VERTEX_SELECT);
- else UI_ThemeColor(TH_VERTEX);
+ if (boneflag & BONE_TIPSEL) {
+ UI_GetThemeColor4fv(TH_VERTEX_SELECT, fcolor);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_VERTEX, fcolor);
+ }
}
}
else {
if (armflag & ARM_POSEMODE)
- set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, 0);
- else
- UI_ThemeColor(TH_BONE_SOLID);
+ set_pchan_color(PCHAN_COLOR_SOLID, boneflag, 0);
+ else {
+ UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor);
+ }
}
- glTranslatef(0.0f, 1.0f, 0.0f);
+ gpuPushMatrix();
+ gpuTranslate2f(0.0f, 1.0f);
if (dt > OB_WIRE)
draw_bonevert_solid();
else
draw_bonevert();
- glTranslatef(0.0f, -1.0f, 0.0f);
-
+ gpuPopMatrix();
}
/* 16 values of sin function (still same result!) */
@@ -696,8 +809,13 @@ static void draw_sphere_bone_dist(float smat[4][4], float imat[4][4], bPoseChann
//mul_v3_fl(dirvec, head);
cross_v3_v3v3(norvec, dirvec, imat[2]);
-
- glBegin(GL_QUAD_STRIP);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immBegin(GWN_PRIM_TRI_STRIP, 66);
+ immUniformColor4ub(255, 255, 255, 50);
for (a = 0; a < 16; a++) {
vec[0] = -si[a] * dirvec[0] + co[a] * norvec[0];
@@ -707,10 +825,8 @@ static void draw_sphere_bone_dist(float smat[4][4], float imat[4][4], bPoseChann
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);
+ immVertex3fv(pos, vec1);
+ immVertex3fv(pos, vec2);
}
for (a = 15; a >= 0; a--) {
@@ -721,10 +837,8 @@ static void draw_sphere_bone_dist(float smat[4][4], float imat[4][4], bPoseChann
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);
+ immVertex3fv(pos, vec1);
+ immVertex3fv(pos, vec2);
}
/* make it cyclic... */
@@ -735,12 +849,11 @@ static void draw_sphere_bone_dist(float smat[4][4], float imat[4][4], bPoseChann
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);
+ immVertex3fv(pos, vec1);
+ immVertex3fv(pos, vec2);
- glEnd();
+ immEnd();
+ immUnbindProgram();
}
}
@@ -752,6 +865,11 @@ static void draw_sphere_bone_wire(float smat[4][4], float imat[4][4],
{
float head, tail /*, length*/;
float *headvec, *tailvec, dirvec[3];
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* figure out the sizes of spheres */
if (ebone) {
@@ -780,35 +898,49 @@ static void draw_sphere_bone_wire(float smat[4][4], float imat[4][4],
/* sphere root color */
if (armflag & ARM_EDITMODE) {
- if (boneflag & BONE_ROOTSEL) UI_ThemeColor(TH_VERTEX_SELECT);
- else UI_ThemeColor(TH_VERTEX);
+ if (boneflag & BONE_ROOTSEL) {
+ UI_GetThemeColor4fv(TH_VERTEX_SELECT, fcolor);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_VERTEX, fcolor);
+ }
}
else if (armflag & ARM_POSEMODE)
- set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag);
-
+ set_pchan_color(PCHAN_COLOR_NORMAL, boneflag, constflag);
+
+ immUniformColor4fv(fcolor);
+
/* 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);
+ imm_drawcircball(headvec, head, imat, pos);
}
/* Draw tip point */
if (armflag & ARM_EDITMODE) {
- if (boneflag & BONE_TIPSEL) UI_ThemeColor(TH_VERTEX_SELECT);
- else UI_ThemeColor(TH_VERTEX);
+ if (boneflag & BONE_TIPSEL) {
+ UI_GetThemeColor4fv(TH_VERTEX_SELECT, fcolor);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_VERTEX, fcolor);
+ }
}
if (id != -1)
GPU_select_load_id(id | BONESEL_TIP);
- drawcircball(GL_LINE_LOOP, tailvec, tail, imat);
+ imm_drawcircball(tailvec, tail, imat, pos);
/* base */
if (armflag & ARM_EDITMODE) {
- if (boneflag & BONE_SELECTED) UI_ThemeColor(TH_SELECT);
- else UI_ThemeColor(TH_WIRE_EDIT);
+ if (boneflag & BONE_SELECTED){
+ UI_GetThemeColor4fv(TH_SELECT, fcolor);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_WIRE_EDIT, fcolor);
+ }
}
sub_v3_v3v3(dirvec, tailvec, headvec);
@@ -834,34 +966,40 @@ static void draw_sphere_bone_wire(float smat[4][4], float imat[4][4],
if (id != -1)
GPU_select_load_id(id | BONESEL_BONE);
- glBegin(GL_LINES);
+ immBegin(GWN_PRIM_LINES, 4);
add_v3_v3v3(vec, headvec, norvech);
- glVertex3fv(vec);
+ immVertex3fv(pos, vec);
add_v3_v3v3(vec, tailvec, norvect);
- glVertex3fv(vec);
+ immVertex3fv(pos, vec);
sub_v3_v3v3(vec, headvec, norvech);
- glVertex3fv(vec);
+ immVertex3fv(pos, vec);
sub_v3_v3v3(vec, tailvec, norvect);
- glVertex3fv(vec);
+ immVertex3fv(pos, vec);
- glEnd();
+ immEnd();
}
+
+ immUnbindProgram();
}
/* 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;
+ Gwn_Batch *sphere = Batch_get_sphere(1);
float head, tail, length;
- float fac1, fac2;
-
- glPushMatrix();
- qobj = gluNewQuadric();
+ float fac1, fac2, size1, size2;
+ const float light_vec[3] = {0.0f, 0.0f, 1.0f};
+
+ /* dt is always OB_SOlID */
+ Batch_set_builtin_program(sphere, GPU_SHADER_SIMPLE_LIGHTING);
+ GWN_batch_uniform_3fv(sphere, "light", light_vec);
+
+ gpuPushMatrix();
/* figure out the sizes of spheres */
if (ebone) {
@@ -882,110 +1020,124 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co
}
/* move to z-axis space */
- glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
+ gpuRotateAxis(-90.0f, 'X');
- 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);
+ if (boneflag & BONE_ROOTSEL)
+ UI_GetThemeColor4fv(TH_VERTEX_SELECT, fcolor);
+ else
+ UI_GetThemeColorShade4fv(TH_BONE_SOLID, -30, fcolor);
}
else if (armflag & ARM_POSEMODE)
- set_pchan_glColor(PCHAN_COLOR_SPHEREBONE_END, boneflag, constflag);
+ set_pchan_color(PCHAN_COLOR_SPHEREBONE_END, boneflag, constflag);
else if (dt == OB_SOLID)
- UI_ThemeColorShade(TH_BONE_SOLID, -30);
+ UI_GetThemeColorShade4fv(TH_BONE_SOLID, -30, fcolor);
/* 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);
+ gpuPushMatrix();
+ gpuScaleUniform(head);
+ GWN_batch_uniform_4fv(sphere, "color", fcolor);
+ GWN_batch_draw(sphere);
+ gpuPopMatrix();
}
/* Draw tip point */
if (armflag & ARM_EDITMODE) {
- if (boneflag & BONE_TIPSEL) UI_ThemeColor(TH_VERTEX_SELECT);
- else UI_ThemeColorShade(TH_BONE_SOLID, -30);
+ if (boneflag & BONE_TIPSEL) UI_GetThemeColor4fv(TH_VERTEX_SELECT, fcolor);
+ else UI_GetThemeColorShade4fv(TH_BONE_SOLID, -30, fcolor);
}
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);
+ gpuTranslate3f(0.0f, 0.0f, length);
+
+ gpuPushMatrix();
+ gpuScaleUniform(tail);
+ GWN_batch_program_use_begin(sphere); /* hack to make the following uniforms stick */
+ GWN_batch_uniform_4fv(sphere, "color", fcolor);
+ GWN_batch_draw(sphere);
+ gpuPopMatrix();
+
+ gpuTranslate3f(0.0f, 0.0f, -length);
/* base */
if (armflag & ARM_EDITMODE) {
- if (boneflag & BONE_SELECTED) UI_ThemeColor(TH_SELECT);
- else UI_ThemeColor(TH_BONE_SOLID);
+ if (boneflag & BONE_SELECTED) UI_GetThemeColor4fv(TH_SELECT, fcolor);
+ else UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor);
}
else if (armflag & ARM_POSEMODE)
- set_pchan_glColor(PCHAN_COLOR_SPHEREBONE_BASE, boneflag, constflag);
+ set_pchan_color(PCHAN_COLOR_SPHEREBONE_BASE, boneflag, constflag);
else if (dt == OB_SOLID)
- UI_ThemeColor(TH_BONE_SOLID);
+ UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor);
+
+ GWN_batch_program_use_begin(sphere); /* hack to make the following uniforms stick */
+ GWN_batch_uniform_4fv(sphere, "color", fcolor);
fac1 = (length - head) / length;
fac2 = (length - tail) / length;
if (length > (head + tail)) {
+ size1 = fac2 * tail + (1.0f - fac2) * head;
+ size2 = fac1 * head + (1.0f - fac1) * tail;
+
if (id != -1)
GPU_select_load_id(id | BONESEL_BONE);
+ /* draw sphere on extrema */
+ gpuPushMatrix();
+ gpuTranslate3f(0.0f, 0.0f, length - tail);
+ gpuScaleUniform(size1);
+
+ GWN_batch_draw(sphere);
+ gpuPopMatrix();
+
+ gpuPushMatrix();
+ gpuTranslate3f(0.0f, 0.0f, head);
+ gpuScaleUniform(size2);
+
+ GWN_batch_draw(sphere);
+ gpuPopMatrix();
+
+ /* draw cynlinder between spheres */
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);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ unsigned int nor = GWN_vertformat_attr_add(format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_SIMPLE_LIGHTING);
+ immUniformColor4fv(fcolor);
+ immUniform3fv("light", light_vec);
+
+ gpuTranslate3f(0.0f, 0.0f, head);
+ imm_draw_cylinder_fill_normal_3d(pos, nor, size2, size1, length - head - tail, 16, 1);
+
+ immUnbindProgram();
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 {
+ size1 = fac1 * head + (1.0f - fac1) * tail;
+
/* 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);
+ gpuTranslate3f(0.0f, 0.0f, (head + length - tail) / 2.0f);
+
+ gpuScaleUniform(size1);
+ GWN_batch_draw(sphere);
}
- glPopMatrix();
- gluDeleteQuadric(qobj);
+ gpuPopMatrix();
}
-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)
@@ -993,103 +1145,119 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned
else
length = ebone->length;
- glPushMatrix();
- glScalef(length, length, length);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ gpuPushMatrix();
+ gpuScaleUniform(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);
- }
+ glPointSize(8.0f);
if (armflag & ARM_POSEMODE)
- set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag);
+ set_pchan_color(PCHAN_COLOR_NORMAL, boneflag, constflag);
else if (armflag & ARM_EDITMODE) {
- UI_ThemeColor(TH_WIRE_EDIT);
+ UI_GetThemeColor4fv(TH_WIRE_EDIT, fcolor);
}
-
+
+ /* line */
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor4fv(fcolor);
+
+ if (id != -1)
+ GPU_select_load_id(id | BONESEL_BONE);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex3f(pos, 0.0f, 1.0f, 0.0f);
+ immVertex3f(pos, 0.0f, 0.0f, 0.0f);
+ immEnd();
+
+ immUnbindProgram();
+
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR);
+ immUniformColor4fv(fcolor);
+
/* Draw root point if we are not connected */
if ((boneflag & BONE_CONNECTED) == 0) {
- if (G.f & G_PICKSEL) {
+ 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);
- }
+
+ immBegin(GWN_PRIM_POINTS, 1);
+ immVertex3f(pos, 0.0f, 0.0f, 0.0f);
+ immEnd();
}
-
- 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... */
+ if (G.f & G_PICKSEL)
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);
- }
-
+
+ immBegin(GWN_PRIM_POINTS, 1);
+ immVertex3f(pos, 0.0f, 1.0f, 0.0f);
+ immEnd();
+
+ immUnbindProgram();
+
+
/* 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);
+ set_pchan_color(PCHAN_COLOR_LINEBONE, boneflag, constflag);
}
-
- glLineWidth(2.0);
-
+
+ /* Now draw the inner color */
+ glLineWidth(2.0f);
+ glPointSize(5.0f);
+
+ /* line */
+ if (armflag & ARM_EDITMODE) {
+ if (boneflag & BONE_SELECTED) UI_GetThemeColor4fv(TH_EDGE_SELECT, fcolor);
+ else UI_GetThemeColorShade4fv(TH_BACK, -30, fcolor);
+ }
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor4fv(fcolor);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex3f(pos, 0.0f, 1.0f, 0.0f);
+ immVertex3f(pos, 0.0f, 0.0f, 0.0f);
+ immEnd();
+
+ immUnbindProgram();
+
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR);
+
/*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_ROOTSEL) UI_GetThemeColor4fv(TH_VERTEX_SELECT, fcolor);
+ else UI_GetThemeColor4fv(TH_VERTEX, fcolor);
}
+ immUniformColor4fv(fcolor);
+ immBegin(GWN_PRIM_POINTS, 1);
+ immVertex3f(pos, 0.0f, 0.0f, 0.0f);
+ immEnd();
}
-
- 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);
+ if (boneflag & BONE_TIPSEL) UI_GetThemeColor4fv(TH_VERTEX_SELECT, fcolor);
+ else UI_GetThemeColor4fv(TH_VERTEX, fcolor);
}
- glRasterPos3f(0.0f, 1.0f, 0.0f);
- glBitmap(8, 8, 4, 4, 0, 0, bm_dot5);
+ immUniformColor4fv(fcolor);
+ immBegin(GWN_PRIM_POINTS, 1);
+ immVertex3f(pos, 0.0f, 1.0f, 0.0f);
+ immEnd();
}
-
- glPopMatrix();
+
+ immUnbindProgram();
+
+ gpuPopMatrix();
}
/* A partial copy of b_bone_spline_setup(), with just the parts for previewing editmode curve settings
@@ -1188,18 +1356,16 @@ static void draw_b_bone_boxes(const short dt, bPoseChannel *pchan, EditBone *ebo
}
for (a = 0; a < segments; a++) {
- glPushMatrix();
- glMultMatrixf(bbone[a].mat);
+ gpuPushMatrix();
+ gpuMultMatrix(bbone[a].mat);
if (dt == OB_SOLID) drawsolidcube_size(xwidth, dlen, zwidth);
else drawcube_size(xwidth, dlen, zwidth);
- glPopMatrix();
+ gpuPopMatrix();
}
}
else {
- glPushMatrix();
if (dt == OB_SOLID) drawsolidcube_size(xwidth, length, zwidth);
else drawcube_size(xwidth, length, zwidth);
- glPopMatrix();
}
}
@@ -1222,26 +1388,27 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl
/* draw points only if... */
if (armflag & ARM_EDITMODE) {
/* move to unitspace */
- glPushMatrix();
- glScalef(length, length, length);
+ gpuPushMatrix();
+ gpuScaleUniform(length);
draw_bone_points(dt, armflag, boneflag, id);
- glPopMatrix();
+ gpuPopMatrix();
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);
+ set_pchan_color(PCHAN_COLOR_NORMAL, boneflag, constflag);
else
- set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, constflag);
+ set_pchan_color(PCHAN_COLOR_SOLID, boneflag, constflag);
}
else if (armflag & ARM_EDITMODE) {
if (dt == OB_WIRE) {
- set_ebone_glColor(boneflag);
+ set_ebone_color(boneflag);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor);
}
- else
- UI_ThemeColor(TH_BONE_SOLID);
}
if (id != -1) {
@@ -1250,33 +1417,31 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl
/* 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);
+ set_pchan_color(PCHAN_COLOR_SOLID, boneflag, constflag);
+ else {
+ UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor);
+ }
+ flat_color = false;
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) {
+ if (constflag && ((G.f & G_PICKSEL) == 0)) {
/* set constraint colors */
- if (set_pchan_glColor(PCHAN_COLOR_CONSTS, boneflag, constflag)) {
+ if (set_pchan_color(PCHAN_COLOR_CONSTS, boneflag, constflag)) {
glEnable(GL_BLEND);
+ flat_color = true;
draw_b_bone_boxes(OB_SOLID, pchan, ebone, xwidth, length, zwidth);
glDisable(GL_BLEND);
}
/* restore colors */
- set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag);
+ set_pchan_color(PCHAN_COLOR_NORMAL, boneflag, constflag);
}
}
@@ -1286,33 +1451,41 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl
static void draw_wire_bone_segments(bPoseChannel *pchan, Mat4 *bbones, float length, int segments)
{
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor4fv(fcolor);
+
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();
+ gpuPushMatrix();
+ gpuMultMatrix(bbone->mat);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex3f(pos, 0.0f, 0.0f, 0.0f);
+ immVertex3f(pos, 0.0f, dlen, 0.0f);
+ immEnd();
+
+ gpuPopMatrix();
}
}
else {
- glPushMatrix();
-
- glBegin(GL_LINES);
- glVertex3f(0.0f, 0.0f, 0.0f);
- glVertex3f(0.0f, length, 0.0f);
- glEnd();
-
- glPopMatrix();
+ gpuPushMatrix();
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex3f(pos, 0.0f, 0.0f, 0.0f);
+ immVertex3f(pos, 0.0f, length, 0.0f);
+ immEnd();
+
+ gpuPopMatrix();
}
+
+ immUnbindProgram();
}
static void draw_wire_bone(const short dt, int armflag, int boneflag, short constflag, unsigned int id,
@@ -1338,10 +1511,11 @@ static void draw_wire_bone(const short dt, int armflag, int boneflag, short cons
/* draw points only if... */
if (armflag & ARM_EDITMODE) {
/* move to unitspace */
- glPushMatrix();
- glScalef(length, length, length);
+ gpuPushMatrix();
+ gpuScaleUniform(length);
+ flat_color = true;
draw_bone_points(dt, armflag, boneflag, id);
- glPopMatrix();
+ gpuPopMatrix();
length *= 0.95f; /* make vertices visible */
}
@@ -1359,10 +1533,10 @@ static void draw_wire_bone(const short dt, int armflag, int boneflag, short cons
/* colors for modes */
if (armflag & ARM_POSEMODE) {
- set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag);
+ set_pchan_color(PCHAN_COLOR_NORMAL, boneflag, constflag);
}
else if (armflag & ARM_EDITMODE) {
- set_ebone_glColor(boneflag);
+ set_ebone_color(boneflag);
}
/* draw normal */
@@ -1372,23 +1546,23 @@ static void draw_wire_bone(const short dt, int armflag, int boneflag, short cons
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);
+ /* Draw a 3d octahedral bone, we use normalized space based on length */
+ gpuScaleUniform(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);
+ UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor);
+ flat_color = false;
}
+ else
+ flat_color = true;
/* colors for posemode */
if (armflag & ARM_POSEMODE) {
if (dt <= OB_WIRE)
- set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag);
+ set_pchan_color(PCHAN_COLOR_NORMAL, boneflag, constflag);
else
- set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, constflag);
+ set_pchan_color(PCHAN_COLOR_SOLID, boneflag, constflag);
}
@@ -1403,12 +1577,12 @@ static void draw_bone(const short dt, int armflag, int boneflag, short constflag
if (dt <= OB_WIRE) {
/* colors */
if (armflag & ARM_EDITMODE) {
- set_ebone_glColor(boneflag);
+ set_ebone_color(boneflag);
}
else if (armflag & ARM_POSEMODE) {
- if (constflag) {
+ if (constflag && ((G.f & G_PICKSEL) == 0)) {
/* draw constraint colors */
- if (set_pchan_glColor(PCHAN_COLOR_CONSTS, boneflag, constflag)) {
+ if (set_pchan_color(PCHAN_COLOR_CONSTS, boneflag, constflag)) {
glEnable(GL_BLEND);
draw_bone_solid_octahedral();
@@ -1417,7 +1591,7 @@ static void draw_bone(const short dt, int armflag, int boneflag, short constflag
}
/* restore colors */
- set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag);
+ set_pchan_color(PCHAN_COLOR_NORMAL, boneflag, constflag);
}
}
draw_bone_octahedral();
@@ -1425,35 +1599,31 @@ static void draw_bone(const short dt, int armflag, int boneflag, short constflag
else {
/* solid */
if (armflag & ARM_POSEMODE)
- set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, constflag);
+ set_pchan_color(PCHAN_COLOR_SOLID, boneflag, constflag);
else
- UI_ThemeColor(TH_BONE_SOLID);
- draw_bone_solid_octahedral();
- }
+ UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor);
- /* disable solid drawing */
- if (dt > OB_WIRE) {
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ draw_bone_solid_octahedral();
}
}
-static void draw_custom_bone(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob,
+static void draw_custom_bone(Scene *scene, SceneLayer *sl, 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);
+ gpuScaleUniform(length);
/* colors for posemode */
if (armflag & ARM_POSEMODE) {
- set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, 0);
+ set_pchan_color(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);
+
+ draw_object_instance(scene, sl, v3d, rv3d, ob, dt, armflag & ARM_POSEMODE, fcolor);
}
@@ -1461,7 +1631,20 @@ static void pchan_draw_IK_root_lines(bPoseChannel *pchan, short only_temp)
{
bConstraint *con;
bPoseChannel *parchan;
-
+
+ const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("num_colors", 0); /* "simple" mode */
+ immUniformColor4fv(fcolor);
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
+
for (con = pchan->constraints.first; con; con = con->next) {
if (con->enforce == 0.0f)
continue;
@@ -1471,47 +1654,45 @@ static void pchan_draw_IK_root_lines(bPoseChannel *pchan, short only_temp)
{
bKinematicConstraint *data = (bKinematicConstraint *)con->data;
int segcount = 0;
+ float ik_tip[3];
/* 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);
+ copy_v3_v3(ik_tip, parchan->pose_tail);
/* Find the chain's root */
while (parchan->parent) {
segcount++;
- if (segcount == data->rootbone || segcount > 255) {
- break; /* 255 is weak */
- }
+ /* FIXME: revise the breaking conditions */
+ if (segcount == data->rootbone || segcount > 255) break; /* 255 is weak */
parchan = parchan->parent;
}
- if (parchan)
- glVertex3fv(parchan->pose_head);
+
+ if (parchan) {
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex3fv(shdr_pos, ik_tip);
+ immVertex3fv(shdr_pos, parchan->pose_head);
+ immEnd();
+ }
- glEnd();
- setlinestyle(0);
break;
}
case CONSTRAINT_TYPE_SPLINEIK:
{
bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
int segcount = 0;
-
- setlinestyle(3);
- glBegin(GL_LINES);
+ float ik_tip[3];
parchan = pchan;
- glVertex3fv(parchan->pose_tail);
+ copy_v3_v3(ik_tip, parchan->pose_tail);
/* Find the chain's root */
while (parchan->parent) {
@@ -1521,18 +1702,21 @@ static void pchan_draw_IK_root_lines(bPoseChannel *pchan, short only_temp)
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);
+ if (parchan != pchan) { /* XXX revise the breaking conditions to only stop at the tail? */
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex3fv(shdr_pos, ik_tip);
+ immVertex3fv(shdr_pos, parchan->pose_head);
+ immEnd();
+ }
break;
}
}
}
+
+ immUnbindProgram();
}
-static void bgl_sphere_project(float ax, float az)
+static void imm_sphere_project(unsigned int pos, float ax, float az)
{
float dir[3], sine, q3;
@@ -1543,11 +1727,13 @@ static void bgl_sphere_project(float ax, float az)
dir[1] = 1.0f - 2.0f * sine;
dir[2] = ax * q3;
- glVertex3fv(dir);
+ immVertex3fv(pos, dir);
}
-static void draw_dof_ellipse(float ax, float az)
+static void draw_dof_ellipse(unsigned int pos, float ax, float az)
{
+ const int n = 16;
+ const int tri = n*n - 2*n + 1; /* Yay fancy math ! */
const float staticSine[16] = {
0.0f, 0.104528463268f, 0.207911690818f, 0.309016994375f,
0.406736643076f, 0.5f, 0.587785252292f, 0.669130606359f,
@@ -1556,15 +1742,15 @@ static void draw_dof_ellipse(float ax, float az)
0.994521895368f, 1.0f
};
- int i, j, n = 16;
+ int i, j;
float x, z, px, pz;
glEnable(GL_BLEND);
glDepthMask(0);
- glColor4ub(70, 70, 70, 50);
+ immUniformColor4ub(70, 70, 70, 50);
- glBegin(GL_QUADS);
+ immBegin(GWN_PRIM_TRIS, tri*3);
pz = 0.0f;
for (i = 1; i < n; i++) {
z = staticSine[i];
@@ -1574,36 +1760,35 @@ static void draw_dof_ellipse(float ax, float az)
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);
+ imm_sphere_project(pos, ax * px, az * z);
+ imm_sphere_project(pos, ax * px, az * pz);
+ imm_sphere_project(pos, ax * x, az * pz);
}
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);
+ imm_sphere_project(pos, ax * x, az * z);
+ imm_sphere_project(pos, ax * x, az * pz);
+ imm_sphere_project(pos, ax * px, az * pz);
+
+ imm_sphere_project(pos, ax * px, az * pz);
+ imm_sphere_project(pos, ax * px, az * z);
+ imm_sphere_project(pos, ax * x, az * z);
}
px = x;
}
pz = z;
}
- glEnd();
+ immEnd();
glDisable(GL_BLEND);
glDepthMask(1);
- glColor3ub(0, 0, 0);
+ immUniformColor3ub(0, 0, 0);
- glBegin(GL_LINE_STRIP);
+ immBegin(GWN_PRIM_LINE_STRIP, n);
for (i = 0; i < n; i++)
- bgl_sphere_project(staticSine[n - i - 1] * ax, staticSine[i] * az);
- glEnd();
+ imm_sphere_project(pos, staticSine[n - i - 1] * ax, staticSine[i] * az);
+ immEnd();
}
static void draw_pose_dofs(Object *ob)
@@ -1611,7 +1796,12 @@ static void draw_pose_dofs(Object *ob)
bArmature *arm = ob->data;
bPoseChannel *pchan;
Bone *bone;
-
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
bone = pchan->bone;
@@ -1625,54 +1815,55 @@ static void draw_pose_dofs(Object *ob)
int a, i;
/* in parent-bone pose, but own restspace */
- glPushMatrix();
+ gpuPushMatrix();
copy_v3_v3(posetrans, pchan->pose_mat[3]);
- glTranslate3fv(posetrans);
+ gpuTranslate3fv(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);
+ gpuMultMatrix(mat);
}
copy_m4_m3(mat, pchan->bone->bone_mat);
- glMultMatrixf(mat);
+ gpuMultMatrix(mat);
scale = bone->length * pchan->size[1];
- glScalef(scale, scale, scale);
+ gpuScaleUniform(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);
+ if (((pchan->ikflag & BONE_IK_XLIMIT) != 0) &&
+ ((pchan->ikflag & BONE_IK_ZLIMIT) != 0))
+ {
+ 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);
}
+
+ gpuScale3f(1.0f, -1.0f, 1.0f);
+ if ((amin[0] != 0.0f) && (amin[2] != 0.0f))
+ draw_dof_ellipse(pos, amin[0], amin[2]);
+ if ((amin[0] != 0.0f) && (amax[2] != 0.0f))
+ draw_dof_ellipse(pos, amin[0], amax[2]);
+ if ((amax[0] != 0.0f) && (amin[2] != 0.0f))
+ draw_dof_ellipse(pos, amax[0], amin[2]);
+ if ((amax[0] != 0.0f) && (amax[2] != 0.0f))
+ draw_dof_ellipse(pos, amax[0], amax[2]);
+ gpuScale3f(1.0f, -1.0f, 1.0f); /* XXX same as above, is this intentional? */
}
/* 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);
+ gpuPushMatrix();
+ gpuRotateAxis(theta, 'Z');
- glColor3ub(50, 50, 255); /* blue, Z axis limit */
- glBegin(GL_LINE_STRIP);
+ immUniformColor3ub(50, 50, 255); /* blue, Z axis limit */
+ immBegin(GWN_PRIM_LINE_STRIP, 33);
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;
@@ -1683,20 +1874,21 @@ static void draw_pose_dofs(Object *ob)
corner[i][0] = sinf(phi);
corner[i][1] = cosf(phi);
corner[i][2] = 0.0f;
- glVertex3fv(corner[i]);
+ immVertex3fv(pos, corner[i]);
}
- glEnd();
+ immEnd();
- glRotatef(-theta, 0.0f, 0.0f, 1.0f);
+ gpuPopMatrix();
}
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);
+ gpuPushMatrix();
+ gpuRotateAxis(theta, 'X');
- glColor3ub(255, 50, 50); /* Red, X axis limit */
- glBegin(GL_LINE_STRIP);
+ immUniformColor3ub(255, 50, 50); /* Red, X axis limit */
+ immBegin(GWN_PRIM_LINE_STRIP, 33);
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;
@@ -1706,21 +1898,23 @@ static void draw_pose_dofs(Object *ob)
corner[i][0] = 0.0f;
corner[i][1] = sinf(phi);
corner[i][2] = cosf(phi);
- glVertex3fv(corner[i]);
+ immVertex3fv(pos, corner[i]);
}
- glEnd();
+ immEnd();
- glRotatef(-theta, 1.0f, 0.0f, 0.0f);
+ gpuPopMatrix();
}
/* out of cone, out of bone */
- glPopMatrix();
+ gpuPopMatrix();
}
}
}
}
}
}
+
+ immUnbindProgram();
}
static void bone_matrix_translate_y(float mat[4][4], float y)
@@ -1733,7 +1927,7 @@ static void bone_matrix_translate_y(float mat[4][4], float y)
}
/* assumes object is Armature with pose */
-static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
+static void draw_pose_bones(Scene *scene, SceneLayer *sl, 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)
{
@@ -1756,7 +1950,9 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
/* being set below */
arm->layer_used = 0;
-
+
+ rgba_uchar_to_float(fcolor, ob_wire_col);
+
/* precalc inverse matrix for drawing screen aligned */
if (arm->drawtype == ARM_ENVELOPE) {
/* precalc inverse matrix for drawing screen aligned */
@@ -1805,7 +2001,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
/* 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;
+ index = base->object->select_color;
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
bone = pchan->bone;
@@ -1817,13 +2013,13 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
{
if (bone->layer & arm->layer) {
const bool use_custom = (pchan->custom) && !(arm->flag & ARM_NO_CUSTOM);
- glPushMatrix();
+ gpuPushMatrix();
if (use_custom && pchan->custom_tx) {
- glMultMatrixf(pchan->custom_tx->pose_mat);
+ gpuMultMatrix(pchan->custom_tx->pose_mat);
}
else {
- glMultMatrixf(pchan->pose_mat);
+ gpuMultMatrix(pchan->pose_mat);
}
/* catch exception for bone with hidden parent */
@@ -1858,7 +2054,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
glDisable(GL_CULL_FACE);
}
- draw_custom_bone(scene, v3d, rv3d, pchan->custom,
+ draw_custom_bone(scene, sl, v3d, rv3d, pchan->custom,
OB_SOLID, arm->flag, flag, index, PCHAN_CUSTOM_DRAW_SIZE(pchan));
}
}
@@ -1885,7 +2081,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
}
}
- glPopMatrix();
+ gpuPopMatrix();
}
}
@@ -1903,12 +2099,17 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
}
}
+ /* 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;
+ index = base->object->select_color;
/* only draw custom bone shapes that need to be drawn as wires */
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
@@ -1921,13 +2122,13 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
if (bone->layer & arm->layer) {
if (pchan->custom) {
if ((dt < OB_SOLID) || (bone->flag & BONE_DRAWWIRE)) {
- glPushMatrix();
+ gpuPushMatrix();
if (pchan->custom_tx) {
- glMultMatrixf(pchan->custom_tx->pose_mat);
+ gpuMultMatrix(pchan->custom_tx->pose_mat);
}
else {
- glMultMatrixf(pchan->pose_mat);
+ gpuMultMatrix(pchan->pose_mat);
}
/* prepare colors */
@@ -1937,7 +2138,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
else if (arm->flag & ARM_POSEMODE)
set_pchan_colorset(ob, pchan);
else {
- glColor3ubv(ob_wire_col);
+ rgba_uchar_to_float(fcolor, ob_wire_col);
}
/* catch exception for bone with hidden parent */
@@ -1949,10 +2150,10 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
if (bone == arm->act_bone)
flag |= BONE_DRAW_ACTIVE;
- draw_custom_bone(scene, v3d, rv3d, pchan->custom,
+ draw_custom_bone(scene, sl, v3d, rv3d, pchan->custom,
OB_WIRE, arm->flag, flag, index, PCHAN_CUSTOM_DRAW_SIZE(pchan));
- glPopMatrix();
+ gpuPopMatrix();
}
}
}
@@ -1968,18 +2169,13 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
index = -1;
}
}
-
- /* custom bone may draw outline double-width */
- if (arm->flag & ARM_POSEMODE) {
- glLineWidth(1.0f);
- }
/* 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;
+ index = base->object->select_color;
}
/* if solid && posemode, we draw again with polygonoffset */
else if ((dt > OB_WIRE) && (arm->flag & ARM_POSEMODE)) {
@@ -1988,7 +2184,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
else {
/* and we use selection indices if not done yet */
if (arm->flag & ARM_POSEMODE)
- index = base->selcol;
+ index = base->object->select_color;
}
if (is_cull_enabled == false) {
@@ -2011,16 +2207,30 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
* - only if V3D_HIDE_HELPLINES is enabled...
*/
if ((do_dashed & DASH_HELP_LINES) && ((bone->flag & BONE_CONNECTED) == 0)) {
+ const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("num_colors", 0); /* "simple" mode */
+ immUniformColor4fv(fcolor);
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
+
if (arm->flag & ARM_POSEMODE) {
GPU_select_load_id(index & 0xFFFF); /* object tag, for bordersel optim */
- UI_ThemeColor(TH_WIRE);
+ immUniformThemeColor(TH_WIRE);
}
- setlinestyle(3);
- glBegin(GL_LINES);
- glVertex3fv(pchan->pose_head);
- glVertex3fv(pchan->parent->pose_tail);
- glEnd();
- setlinestyle(0);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex3fv(shdr_pos, pchan->parent->pose_tail);
+ immVertex3fv(shdr_pos, pchan->pose_head);
+ immEnd();
+
+ immUnbindProgram();
}
/* Draw a line to IK root bone
@@ -2029,8 +2239,8 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
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! */
+ if (constflag & PCHAN_HAS_TARGET) rgba_float_args_set(fcolor, 200.f/255.f, 120.f/255.f, 0.f/255.f, 1.0f);
+ else rgba_float_args_set(fcolor, 200.f/255.f, 200.f/255.f, 50.f/255.f, 1.0f); /* add theme! */
GPU_select_load_id(index & 0xFFFF);
pchan_draw_IK_root_lines(pchan, !(do_dashed & DASH_HELP_LINES));
@@ -2038,7 +2248,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
}
else if (constflag & PCHAN_HAS_SPLINEIK) {
if (bone->flag & BONE_SELECTED) {
- glColor3ub(150, 200, 50); /* add theme! */
+ rgba_float_args_set(fcolor, 150.f/255.f, 200.f/255.f, 50.f/255.f, 1.0f); /* add theme! */
GPU_select_load_id(index & 0xFFFF);
pchan_draw_IK_root_lines(pchan, !(do_dashed & DASH_HELP_LINES));
@@ -2047,9 +2257,9 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
}
}
- glPushMatrix();
+ gpuPushMatrix();
if (arm->drawtype != ARM_ENVELOPE)
- glMultMatrixf(pchan->pose_mat);
+ gpuMultMatrix(pchan->pose_mat);
/* catch exception for bone with hidden parent */
flag = bone->flag;
@@ -2086,7 +2296,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
else
draw_bone(OB_WIRE, arm->flag, flag, constflag, index, bone->length);
- glPopMatrix();
+ gpuPopMatrix();
}
}
@@ -2106,7 +2316,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
/* draw DoFs */
if (arm->flag & ARM_POSEMODE) {
- if (((base->flag & OB_FROMDUPLI) == 0) && ((v3d->flag & V3D_HIDE_HELPLINES) == 0)) {
+ if (((base->flag_legacy & OB_FROMDUPLI) == 0) && ((v3d->flag & V3D_HIDE_HELPLINES) == 0)) {
draw_pose_dofs(ob);
}
}
@@ -2114,26 +2324,17 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
/* finally names and axes */
if ((arm->flag & (ARM_DRAWNAMES | ARM_DRAWAXES)) &&
(is_outline == 0) &&
- ((base->flag & OB_FROMDUPLI) == 0))
+ ((base->flag_legacy & 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;
- }
+ 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);
@@ -2156,18 +2357,16 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
/* Draw additional axes on the bone tail */
if ((arm->flag & ARM_DRAWAXES) && (arm->flag & ARM_POSEMODE)) {
- glPushMatrix();
+ gpuPushMatrix();
copy_m4_m4(bmat, pchan->pose_mat);
bone_matrix_translate_y(bmat, pchan->bone->length);
- glMultMatrixf(bmat);
+ gpuMultMatrix(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);
+ drawaxes(viewmat_pchan, pchan->bone->length * 0.25f, OB_ARROWS, col);
- glPopMatrix();
+ gpuPopMatrix();
}
}
}
@@ -2233,9 +2432,9 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt)
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();
+ gpuPushMatrix();
get_matrix_editbone(eBone, bmat);
- glMultMatrixf(bmat);
+ gpuMultMatrix(bmat);
/* catch exception for bone with hidden parent */
flag = eBone->flag;
@@ -2257,7 +2456,7 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt)
draw_bone(OB_SOLID, arm->flag, flag, 0, index, eBone->length);
}
- glPopMatrix();
+ gpuPopMatrix();
}
}
}
@@ -2295,9 +2494,9 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt)
draw_sphere_bone_wire(smat, imat, arm->flag, flag, 0, index, NULL, eBone);
}
else {
- glPushMatrix();
+ gpuPushMatrix();
get_matrix_editbone(eBone, bmat);
- glMultMatrixf(bmat);
+ gpuMultMatrix(bmat);
if (arm->drawtype == ARM_LINE)
draw_line_bone(arm->flag, flag, 0, index, NULL, eBone);
@@ -2308,21 +2507,32 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt)
else
draw_bone(OB_WIRE, arm->flag, flag, 0, index, eBone->length);
- glPopMatrix();
+ gpuPopMatrix();
}
/* offset to parent */
if (eBone->parent) {
- UI_ThemeColor(TH_WIRE_EDIT);
+ const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
GPU_select_load_id(-1); /* -1 here is OK! */
- setlinestyle(3);
-
- glBegin(GL_LINES);
- glVertex3fv(eBone->parent->tail);
- glVertex3fv(eBone->head);
- glEnd();
-
- setlinestyle(0);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("num_colors", 0); /* "simple" mode */
+ immUniformThemeColor(TH_WIRE_EDIT);
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex3fv(shdr_pos, eBone->parent->tail);
+ immVertex3fv(shdr_pos, eBone->head);
+ immEnd();
+
+ immUnbindProgram();
}
}
}
@@ -2360,23 +2570,20 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt)
/* Draw name */
if (arm->flag & ARM_DRAWNAMES) {
mid_v3_v3v3(vec, eBone->head, eBone->tail);
- glRasterPos3fv(vec);
view3d_cached_text_draw_add(vec, eBone->name, strlen(eBone->name), 10, 0, col);
}
/* Draw additional axes */
if (arm->flag & ARM_DRAWAXES) {
- glPushMatrix();
+ gpuPushMatrix();
get_matrix_editbone(eBone, bmat);
bone_matrix_translate_y(bmat, eBone->length);
- glMultMatrixf(bmat);
-
- glColor3ubv(col);
+ gpuMultMatrix(bmat);
float viewmat_ebone[4][4];
mul_m4_m4m4(viewmat_ebone, rv3d->viewmatob, bmat);
- drawaxes(viewmat_ebone, eBone->length * 0.25f, OB_ARROWS);
+ drawaxes(viewmat_ebone, eBone->length * 0.25f, OB_ARROWS, col);
- glPopMatrix();
+ gpuPopMatrix();
}
}
@@ -2449,7 +2656,7 @@ static void ghost_poses_tag_unselected(Object *ob, short unset)
/* 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)
+static void draw_ghost_poses_range(Scene *scene, SceneLayer *sl, View3D *v3d, ARegion *ar, Base *base)
{
Object *ob = base->object;
AnimData *adt = BKE_animdata_from_id(&ob->id);
@@ -2457,12 +2664,17 @@ static void draw_ghost_poses_range(Scene *scene, View3D *v3d, ARegion *ar, Base
bPose *posen, *poseo;
float start, end, stepsize, range, colfac;
int cfrao, flago;
+ unsigned char col[4];
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);
@@ -2485,11 +2697,11 @@ static void draw_ghost_poses_range(Scene *scene, View3D *v3d, ARegion *ar, Base
/* 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)));
+ UI_GetThemeColorShadeAlpha4ubv(TH_WIRE, 0, -128 - (int)(120.0f * sqrtf(colfac)), col);
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);
+ draw_pose_bones(scene, sl, v3d, ar, base, OB_WIRE, col, true, false);
}
glDisable(GL_BLEND);
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
@@ -2511,7 +2723,7 @@ static void draw_ghost_poses_range(Scene *scene, View3D *v3d, ARegion *ar, Base
/* 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)
+static void draw_ghost_poses_keys(Scene *scene, SceneLayer *sl, View3D *v3d, ARegion *ar, BaseLegacy *base)
{
Object *ob = base->object;
AnimData *adt = BKE_animdata_from_id(&ob->id);
@@ -2522,6 +2734,7 @@ static void draw_ghost_poses_keys(Scene *scene, View3D *v3d, ARegion *ar, Base *
ActKeyColumn *ak, *akn;
float start, end, range, colfac, i;
int cfrao, flago;
+ unsigned char col[4];
start = (float)arm->ghostsf;
end = (float)arm->ghostef;
@@ -2563,13 +2776,13 @@ static void draw_ghost_poses_keys(Scene *scene, View3D *v3d, ARegion *ar, Base *
/* 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)));
+ UI_GetThemeColorShadeAlpha4ubv(TH_WIRE, 0, -128 - (int)(120.0f * sqrtf(colfac)), col);
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);
+ draw_pose_bones(scene, sl, v3d, ar, base, OB_WIRE, col, true, false);
}
glDisable(GL_BLEND);
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
@@ -2592,7 +2805,7 @@ static void draw_ghost_poses_keys(Scene *scene, View3D *v3d, ARegion *ar, Base *
/* 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)
+static void draw_ghost_poses(Scene *scene, SceneLayer *sl, View3D *v3d, ARegion *ar, Base *base)
{
Object *ob = base->object;
AnimData *adt = BKE_animdata_from_id(&ob->id);
@@ -2600,6 +2813,7 @@ static void draw_ghost_poses(Scene *scene, View3D *v3d, ARegion *ar, Base *base)
bPose *posen, *poseo;
float cur, start, end, stepsize, range, colfac, actframe, ctime;
int cfrao, flago;
+ unsigned char col[4];
/* pre conditions, get an action with sufficient frames */
if (ELEM(NULL, adt, adt->action))
@@ -2608,7 +2822,11 @@ static void draw_ghost_poses(Scene *scene, View3D *v3d, ARegion *ar, Base *base)
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 */
@@ -2633,7 +2851,7 @@ static void draw_ghost_poses(Scene *scene, View3D *v3d, ARegion *ar, Base *base)
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)));
+ UI_GetThemeColorShadeAlpha4ubv(TH_WIRE, 0, -128 - (int)(120.0f * sqrtf(colfac)), col);
/* only within action range */
if (actframe + ctime >= start && actframe + ctime <= end) {
@@ -2642,13 +2860,13 @@ static void draw_ghost_poses(Scene *scene, View3D *v3d, ARegion *ar, Base *base)
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);
+ draw_pose_bones(scene, sl, v3d, ar, base, OB_WIRE, col, 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)));
+ UI_GetThemeColorShadeAlpha4ubv(TH_WIRE, 0, -128 - (int)(120.0f * sqrtf(colfac)), col);
/* only within action range */
if ((actframe - ctime >= start) && (actframe - ctime <= end)) {
@@ -2657,7 +2875,7 @@ static void draw_ghost_poses(Scene *scene, View3D *v3d, ARegion *ar, Base *base)
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);
+ draw_pose_bones(scene, sl, v3d, ar, base, OB_WIRE, col, true, false);
}
}
}
@@ -2682,7 +2900,7 @@ static void draw_ghost_poses(Scene *scene, View3D *v3d, ARegion *ar, Base *base)
/* 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,
+bool draw_armature(Scene *scene, SceneLayer *sl, View3D *v3d, ARegion *ar, Base *base,
const short dt, const short dflag, const unsigned char ob_wire_col[4],
const bool is_outline)
{
@@ -2693,11 +2911,7 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
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 0 /* Not used until lighting is properly reimplemented */
if (dt > OB_WIRE) {
/* we use color for solid lighting */
if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) {
@@ -2712,7 +2926,8 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); /* only for lighting... */
}
}
-
+#endif
+
/* arm->flag is being used to detect mode... */
/* editmode? */
if (arm->edbo) {
@@ -2723,8 +2938,13 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
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 (!(base->flag_legacy & OB_FROMDUPLI)) {
if (G.f & G_PICKSEL) {
#if 0
/* nifty but actually confusing to allow bone selection out of posemode */
@@ -2740,31 +2960,28 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
}
else if (ob->mode & OB_MODE_POSE) {
if (arm->ghosttype == ARM_GHOST_RANGE) {
- draw_ghost_poses_range(scene, v3d, ar, base);
+ draw_ghost_poses_range(scene, sl, v3d, ar, base);
}
else if (arm->ghosttype == ARM_GHOST_KEYS) {
- draw_ghost_poses_keys(scene, v3d, ar, base);
+ draw_ghost_poses_keys(scene, sl, v3d, ar, base);
}
else if (arm->ghosttype == ARM_GHOST_CUR) {
if (arm->ghostep)
- draw_ghost_poses(scene, v3d, ar, base);
+ draw_ghost_poses(scene, sl, v3d, ar, base);
}
if ((dflag & DRAW_SCENESET) == 0) {
- if (ob == OBACT)
+ if (ob == OBACT_NEW)
arm->flag |= ARM_POSEMODE;
- else if (OBACT && (OBACT->mode & OB_MODE_WEIGHT_PAINT)) {
- if (ob == modifiers_isDeformedByArmature(OBACT))
+ else if (OBACT_NEW && (OBACT_NEW->mode & OB_MODE_WEIGHT_PAINT)) {
+ if (ob == modifiers_isDeformedByArmature(OBACT_NEW))
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);
+ draw_pose_bones(scene, sl, 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;
@@ -2773,9 +2990,5 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
/* 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
index 74a50497164..719fb6f764f 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -55,7 +55,6 @@
#include "BKE_editmesh.h"
#include "BKE_scene.h"
-#include "BIF_gl.h"
#include "BIF_glutil.h"
#include "UI_resources.h"
@@ -64,6 +63,7 @@
#include "GPU_material.h"
#include "GPU_basic_shader.h"
#include "GPU_shader.h"
+#include "GPU_matrix.h"
#include "RE_engine.h"
@@ -77,20 +77,6 @@ typedef struct drawMeshFaceSelect_userData {
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 */
@@ -213,560 +199,6 @@ void draw_mesh_face_select(RegionView3D *rv3d, Mesh *me, DerivedMesh *dm, bool d
/***************************** 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;
- }
- 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);
- }
- 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)
{
@@ -777,282 +209,6 @@ static DMDrawOption wpaint__setSolidDrawOptions_facemask(void *userData, int ind
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). */
-
- 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 {
@@ -1064,187 +220,11 @@ typedef struct TexMatCallback {
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->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,
+void draw_mesh_textured(Scene *scene, SceneLayer *sl, 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);
- }
+ UNUSED_VARS(scene, sl, v3d, rv3d, ob, dm, draw_flags);
+ return;
}
/* Vertex Paint and Weight Paint */
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 578570ade3c..cec13651292 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -63,6 +63,7 @@
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_key.h"
+#include "BKE_layer.h"
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
@@ -91,6 +92,10 @@
#include "GPU_select.h"
#include "GPU_basic_shader.h"
#include "GPU_shader.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_batch.h"
+#include "GPU_matrix.h"
#include "ED_mesh.h"
#include "ED_particle.h"
@@ -106,6 +111,11 @@
#include "view3d_intern.h" /* bad level include */
+#include "../../draw/intern/draw_cache_impl.h" /* bad level include (temporary) */
+
+/* prototypes */
+static void imm_draw_box(const float vec[8][3], bool solid, unsigned pos);
+
/* Workaround for sequencer scene render mode.
*
* Strips doesn't use DAG to update objects or so, which
@@ -130,6 +140,7 @@ typedef struct drawDMVerts_userData {
BMVert *eve_act;
char sel;
+ unsigned int pos, color;
/* cached theme values */
unsigned char th_editmesh_active[4];
@@ -182,6 +193,7 @@ typedef struct drawDMFacesSel_userData {
} drawDMFacesSel_userData;
typedef struct drawDMNormal_userData {
+ unsigned int pos;
BMesh *bm;
int uniform_scale;
float normalsize;
@@ -190,6 +202,7 @@ typedef struct drawDMNormal_userData {
} drawDMNormal_userData;
typedef struct drawMVertOffset_userData {
+ unsigned int pos, col;
MVert *mvert;
int offset;
} drawMVertOffset_userData;
@@ -197,9 +210,11 @@ typedef struct drawMVertOffset_userData {
typedef struct drawDMLayer_userData {
BMesh *bm;
int cd_layer_offset;
+ unsigned int pos, col;
} drawDMLayer_userData;
typedef struct drawBMOffset_userData {
+ unsigned int pos, col;
BMesh *bm;
int offset;
} drawBMOffset_userData;
@@ -207,25 +222,23 @@ typedef struct drawBMOffset_userData {
typedef struct drawBMSelect_userData {
BMesh *bm;
bool select;
+ unsigned int pos;
} 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 drawcube_size(float size, unsigned pos);
+static void drawcircle_size(float size, unsigned pos);
+static void draw_empty_sphere(float size, unsigned pos);
+static void draw_empty_cone(float size, unsigned pos);
-static void ob_wire_color_blend_theme_id(const unsigned char ob_wire_col[4], const int theme_id, float fac)
+static void ob_wire_color_blend_theme_id(const unsigned char ob_wire_col[4], const int theme_id, float fac, float r_col[3])
{
- float col_wire[3], col_bg[3], col[3];
+ float col_wire[3], col_bg[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);
+ interp_v3_v3v3(r_col, col_bg, col_wire, fac);
}
int view3d_effective_drawtype(const struct View3D *v3d)
@@ -297,13 +310,13 @@ static bool check_ob_drawface_dot(Scene *sce, View3D *vd, char dt)
/* check for glsl drawing */
-bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt)
+bool draw_glsl_material(Scene *scene, SceneLayer *sl, 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))
+ if (ob == OBACT_NEW && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))
return false;
if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP)
@@ -319,7 +332,7 @@ bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt)
static bool check_alpha_pass(Base *base)
{
- if (base->flag & OB_FROMDUPLI)
+ if (base->flag_legacy & OB_FROMDUPLI)
return false;
if (G.f & G_PICKSEL)
@@ -415,9 +428,9 @@ static const float cosval[CIRCLE_RESOL] = {
* \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)
+static void draw_xyz_wire(const float viewmat_local_unit[3][3], const float c[3], float size, int axis, unsigned pos)
{
- int line_type;
+ Gwn_PrimType line_type = GWN_PRIM_LINES;
float buffer[4][3];
int n = 0;
@@ -430,8 +443,6 @@ static void draw_xyz_wire(const float viewmat_local_unit[3][3], const float c[3]
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);
@@ -451,8 +462,6 @@ static void draw_xyz_wire(const float viewmat_local_unit[3][3], const float c[3]
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);
@@ -473,7 +482,7 @@ static void draw_xyz_wire(const float viewmat_local_unit[3][3], const float c[3]
break;
case 2: /* z axis */
- line_type = GL_LINE_STRIP;
+ line_type = GWN_PRIM_LINE_STRIP;
/* start at top left */
negate_v3_v3(v1, dx);
@@ -502,54 +511,60 @@ static void draw_xyz_wire(const float viewmat_local_unit[3][3], const float c[3]
return;
}
+ immBegin(line_type, n);
for (int i = 0; i < n; i++) {
mul_transposed_m3_v3((float (*)[3])viewmat_local_unit, buffer[i]);
add_v3_v3(buffer[i], c);
+ immVertex3fv(pos, buffer[i]);
}
+ immEnd();
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, buffer);
- glDrawArrays(line_type, 0, n);
- glDisableClientState(GL_VERTEX_ARRAY);
+ /* TODO: recode this function for clarity once we're not in a hurry to modernize GL usage */
}
-void drawaxes(const float viewmat_local[4][4], float size, char drawtype)
+void drawaxes(const float viewmat_local[4][4], float size, char drawtype, const unsigned char color[4])
{
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);
+ glLineWidth(1.0f);
- switch (drawtype) {
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ if (color) {
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor4ubv(color);
+ }
+ else {
+ immBindBuiltinProgram(GPU_SHADER_3D_DEPTH_ONLY);
+ }
+ switch (drawtype) {
case OB_PLAINAXES:
+ immBegin(GWN_PRIM_LINES, 6);
for (axis = 0; axis < 3; axis++) {
- glBegin(GL_LINES);
-
v1[axis] = size;
v2[axis] = -size;
- glVertex3fv(v1);
- glVertex3fv(v2);
+ immVertex3fv(pos, v1);
+ immVertex3fv(pos, v2);
/* reset v1 & v2 to zero */
v1[axis] = v2[axis] = 0.0f;
-
- glEnd();
}
+ immEnd();
break;
- case OB_SINGLE_ARROW:
- glBegin(GL_LINES);
+ case OB_SINGLE_ARROW:
+ immBegin(GWN_PRIM_LINES, 2);
/* in positive z direction only */
v1[2] = size;
- glVertex3fv(v1);
- glVertex3fv(v2);
- glEnd();
+ immVertex3fv(pos, v1);
+ immVertex3fv(pos, v2);
+ immEnd();
/* square pyramid */
- glBegin(GL_TRIANGLES);
+ immBegin(GWN_PRIM_TRIS, 12);
v2[0] = size * 0.035f; v2[1] = size * 0.035f;
v3[0] = size * -0.035f; v3[1] = size * 0.035f;
@@ -565,28 +580,27 @@ void drawaxes(const float viewmat_local[4][4], float size, char drawtype)
v3[0] = -v3[0];
}
- glVertex3fv(v1);
- glVertex3fv(v2);
- glVertex3fv(v3);
-
+ immVertex3fv(pos, v1);
+ immVertex3fv(pos, v2);
+ immVertex3fv(pos, v3);
}
- glEnd();
-
+ immEnd();
break;
+
case OB_CUBE:
- drawcube_size(size);
+ drawcube_size(size, pos);
break;
case OB_CIRCLE:
- drawcircle_size(size);
+ drawcircle_size(size, pos);
break;
case OB_EMPTY_SPHERE:
- draw_empty_sphere(size);
+ draw_empty_sphere(size, pos);
break;
case OB_EMPTY_CONE:
- draw_empty_cone(size);
+ draw_empty_cone(size, pos);
break;
case OB_ARROWS:
@@ -600,63 +614,74 @@ void drawaxes(const float viewmat_local[4][4], float size, char drawtype)
for (axis = 0; axis < 3; axis++) {
const int arrow_axis = (axis == 0) ? 1 : 0;
- glBegin(GL_LINES);
+ immBegin(GWN_PRIM_LINES, 6);
v2[axis] = size;
- glVertex3fv(v1);
- glVertex3fv(v2);
-
+ immVertex3fv(pos, v1);
+ immVertex3fv(pos, v2);
+
v1[axis] = size * 0.85f;
v1[arrow_axis] = -size * 0.08f;
- glVertex3fv(v1);
- glVertex3fv(v2);
-
+ immVertex3fv(pos, v1);
+ immVertex3fv(pos, v2);
+
v1[arrow_axis] = size * 0.08f;
- glVertex3fv(v1);
- glVertex3fv(v2);
+ immVertex3fv(pos, v1);
+ immVertex3fv(pos, v2);
- glEnd();
-
- v2[axis] += size * 0.125f;
+ immEnd();
- draw_xyz_wire(viewmat_local_unit, v2, size, axis);
+ v2[axis] += size * 0.125f;
+ draw_xyz_wire(viewmat_local_unit, v2, size, axis, pos);
/* reset v1 & v2 to zero */
v1[arrow_axis] = v1[axis] = v2[axis] = 0.0f;
}
- break;
}
}
+
+ immUnbindProgram();
}
/* 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])
+static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4], StereoViews sview)
{
Image *ima = ob->data;
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, ob->iuser, NULL);
- if (ibuf && (ibuf->rect == NULL) && (ibuf->rect_float != NULL)) {
- IMB_rect_from_float(ibuf);
- }
+ const float ob_alpha = ob->col[3];
+ float ima_x, ima_y;
+
+ int bindcode = 0;
- int ima_x, ima_y;
+ if (ima) {
+ 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);
+ }
+
+ if (ob_alpha > 0.0f) {
+ bindcode = GPU_verify_image(ima, &iuser, GL_TEXTURE_2D, 0, false, false, false);
+ /* don't bother drawing the image if alpha = 0 */
+ }
- /* Get the buffer dimensions so we can fallback to fake ones */
- if (ibuf && ibuf->rect) {
- ima_x = ibuf->x;
- ima_y = ibuf->y;
+ int w, h;
+ BKE_image_get_size(ima, &iuser, &w, &h);
+ ima_x = w;
+ ima_y = h;
}
else {
- ima_x = 1;
- ima_y = 1;
+ /* if no image, make it a 1x1 empty square, honor scale & offset */
+ ima_x = ima_y = 1.0f;
}
- float sca_x = 1.0f;
- float sca_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;
@@ -666,61 +691,98 @@ static void draw_empty_image(Object *ob, const short dflag, const unsigned char
}
}
- /* 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;
+ float scale_x;
+ float scale_y;
+ {
+ 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) {
+ scale_x = ob->empty_drawsize;
+ scale_y = ob->empty_drawsize * (scale_y_inv / scale_x_inv);
+ }
+ else {
+ scale_x = ob->empty_drawsize * (scale_x_inv / scale_y_inv);
+ scale_y = ob->empty_drawsize;
+ }
+ }
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
+ const float ofs_x = ob->ima_ofs[0] * scale_x;
+ const float ofs_y = ob->ima_ofs[1] * scale_y;
- /* Calculate Image scale */
- float scale = ob->empty_drawsize / max_ff((float)ima_x * sca_x, (float)ima_y * sca_y);
+ const rctf rect = {
+ .xmin = ofs_x,
+ .xmax = ofs_x + scale_x,
+ .ymin = ofs_y,
+ .ymax = ofs_y + scale_y,
+ };
- /* Set the object scale */
- glScalef(scale * sca_x, scale * sca_y, 1.0f);
+ bool use_blend = false;
- 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 (bindcode) {
+ use_blend = ob_alpha < 1.0f || BKE_image_has_alpha(ima);
- if (use_clip) {
- glEnable(GL_ALPHA_TEST);
- glAlphaFunc(GL_GREATER, U.glalphaclip);
+ if (use_blend) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
- /* Use the object color and alpha */
- glColor4fv(ob->col);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int texCoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_MODULATE_ALPHA);
+ immUniform1f("alpha", ob_alpha);
+ immUniform1i("image", 0); /* default GL_TEXTURE0 unit */
- /* Draw the Image on the screen */
- glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_RGBA, GL_UNSIGNED_BYTE, zoomfilter, ibuf->rect);
+ immBegin(GWN_PRIM_TRI_FAN, 4);
+ immAttrib2f(texCoord, 0.0f, 0.0f);
+ immVertex2f(pos, rect.xmin, rect.ymin);
- glDisable(GL_BLEND);
+ immAttrib2f(texCoord, 1.0f, 0.0f);
+ immVertex2f(pos, rect.xmax, rect.ymin);
- if (use_clip) {
- glDisable(GL_ALPHA_TEST);
- glAlphaFunc(GL_ALWAYS, 0.0f);
- }
+ immAttrib2f(texCoord, 1.0f, 1.0f);
+ immVertex2f(pos, rect.xmax, rect.ymax);
+
+ immAttrib2f(texCoord, 0.0f, 1.0f);
+ immVertex2f(pos, rect.xmin, rect.ymax);
+ immEnd();
+
+ immUnbindProgram();
+
+ glBindTexture(GL_TEXTURE_2D, 0); /* necessary? */
}
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- glColor3ubv(ob_wire_col);
+ /* Draw the image outline */
+ glLineWidth(1.5f);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ const bool picking = dflag & DRAW_CONSTCOLOR;
+ if (picking) {
+ /* TODO: deal with picking separately, use this function just to draw */
+ immBindBuiltinProgram(GPU_SHADER_3D_DEPTH_ONLY);
+ if (use_blend) {
+ glDisable(GL_BLEND);
+ }
+
+ imm_draw_line_box(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
}
+ else {
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor3ubv(ob_wire_col);
+ glEnable(GL_LINE_SMOOTH);
- /* 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();
+ if (!use_blend) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ imm_draw_line_box(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
- /* Reset GL settings */
- glPopMatrix();
+ glDisable(GL_LINE_SMOOTH);
+ glDisable(GL_BLEND);
+ }
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ immUnbindProgram();
}
static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3], float rad, const float tmat[4][4])
@@ -738,62 +800,65 @@ 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);
+ immBegin(GWN_PRIM_LINE_LOOP, CIRCLE_RESOL);
+ for (int i = 0; i < CIRCLE_RESOL; ++i) {
+ immVertex3fv(pos, verts[i]);
+ }
+ immEnd();
}
/* 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)
+static void drawcentercircle(View3D *v3d, RegionView3D *UNUSED(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];
+ const float outlineWidth = 1.0f * U.pixelsize;
+ const float size = U.obcenter_dia * U.pixelsize + outlineWidth;
+
+ if (v3d->zbuf) {
+ glDisable(GL_DEPTH_TEST);
+ /* TODO(merwin): fit things like this into plates/buffers design */
+ }
- /* 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);
-
+ GPU_enable_program_point_size();
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
+ immUniform1f("size", size);
+
if (special_color) {
- if (selstate == ACTIVE || selstate == SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155);
- else glColor4ub(0x55, 0xCC, 0xCC, 155);
+ if (selstate == ACTIVE || selstate == SELECT) immUniformColor4ub(0x88, 0xFF, 0xFF, 155);
+ else immUniformColor4ub(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);
+ if (selstate == ACTIVE) immUniformThemeColorShadeAlpha(TH_ACTIVE, 0, -80);
+ else if (selstate == SELECT) immUniformThemeColorShadeAlpha(TH_SELECT, 0, -80);
+ else if (selstate == DESELECT) immUniformThemeColorShadeAlpha(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);
+ /* set up outline */
+ float outlineColor[4];
+ UI_GetThemeColorShadeAlpha4fv(TH_WIRE, 0, -30, outlineColor);
+ immUniform4fv("outlineColor", outlineColor);
+ immUniform1f("outlineWidth", outlineWidth);
- /* 2. draw outline */
- glLineWidth(1);
- UI_ThemeColorShadeAlpha(TH_WIRE, 0, -30);
- glDrawArrays(GL_LINE_LOOP, 0, CIRCLE_RESOL);
+ immBegin(GWN_PRIM_POINTS, 1);
+ immVertex3fv(pos, co);
+ immEnd();
- /* finish up */
- glDisableClientState(GL_VERTEX_ARRAY);
+ immUnbindProgram();
- glDepthRange(0.0, 1.0);
+ GPU_disable_program_point_size();
glDisable(GL_BLEND);
- if (v3d->zbuf) glDepthFunc(GL_LEQUAL);
+ if (v3d->zbuf) {
+ glEnable(GL_DEPTH_TEST);
+ }
}
/* *********** text drawing for object/particles/armature ************* */
@@ -858,7 +923,7 @@ void view3d_cached_text_draw_add(const float co[3],
memcpy(vos->str, str, alloc_len);
}
-void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, float mat[4][4])
+void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write)
{
RegionView3D *rv3d = ar->regiondata;
ViewCachedString *vos;
@@ -868,9 +933,6 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, flo
/* project first and test */
for (vos = g_v3d_strings[g_v3d_string_level]; vos; vos = vos->next) {
- if (mat && !(vos->flag & V3D_CACHE_TEXT_WORLDSPACE))
- mul_m4_v3(mat, vos->vec);
-
if (ED_view3d_project_short_ex(ar,
(vos->flag & V3D_CACHE_TEXT_GLOBALSPACE) ? rv3d->persmat : rv3d->persmatob,
(vos->flag & V3D_CACHE_TEXT_LOCALCLIP) != 0,
@@ -887,36 +949,30 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, flo
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();
+ float original_proj[4][4];
+ gpuGetProjectionMatrix(original_proj);
wmOrtho2_region_pixelspace(ar);
- glLoadIdentity();
+
+ gpuPushMatrix();
+ gpuLoadIdentity();
if (depth_write) {
if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
}
else {
- glDepthMask(0);
+ glDepthMask(GL_FALSE);
}
+ const int font_id = BLF_default();
+
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);
+ BLF_color3ubv(font_id, vos->col.ub);
col_pack_prev = vos->col.pack;
}
@@ -935,13 +991,11 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, flo
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
}
else {
- glDepthMask(1);
+ glDepthMask(GL_TRUE);
}
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
+ gpuPopMatrix();
+ gpuLoadProjectionMatrix(original_proj);
if (rv3d->rflag & RV3D_CLIPPING) {
ED_view3d_clipping_enable();
@@ -965,9 +1019,9 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, flo
/* 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)
+static void drawcube_size(float size, unsigned pos)
{
- const GLfloat pos[8][3] = {
+ const float verts[8][3] = {
{-size, -size, -size},
{-size, -size, size},
{-size, size, -size},
@@ -980,13 +1034,21 @@ static void drawcube_size(float 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};
+#if 0
glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, pos);
+ glVertexPointer(3, GL_FLOAT, 0, verts);
glDrawRangeElements(GL_LINES, 0, 7, 24, GL_UNSIGNED_BYTE, indices);
glDisableClientState(GL_VERTEX_ARRAY);
+#else
+ immBegin(GWN_PRIM_LINES, 24);
+ for (int i = 0; i < 24; ++i) {
+ immVertex3fv(pos, verts[indices[i]]);
+ }
+ immEnd();
+#endif
}
-static void drawshadbuflimits(Lamp *la, float mat[4][4])
+static void drawshadbuflimits(const Lamp *la, const float mat[4][4], unsigned pos)
{
float sta[3], end[3], lavec[3];
@@ -996,16 +1058,16 @@ static void drawshadbuflimits(Lamp *la, float mat[4][4])
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();
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex3fv(pos, sta);
+ immVertex3fv(pos, end);
+ immEnd();
- glPointSize(3.0);
- glBegin(GL_POINTS);
- glVertex3fv(sta);
- glVertex3fv(end);
- glEnd();
+ glPointSize(3.0f);
+ immBegin(GWN_PRIM_POINTS, 2);
+ immVertex3fv(pos, sta);
+ immVertex3fv(pos, end);
+ immEnd();
}
static void spotvolume(float lvec[3], float vvec[3], const float inp)
@@ -1071,62 +1133,63 @@ static void spotvolume(float lvec[3], float vvec[3], const float inp)
mul_m3_v3(mat2, vvec);
}
-static void draw_spot_cone(Lamp *la, float x, float z)
+static void draw_spot_cone(Lamp *la, float x, float z, unsigned pos)
{
z = fabsf(z);
- glBegin(GL_TRIANGLE_FAN);
- glVertex3f(0.0f, 0.0f, -x);
+ const bool square = (la->mode & LA_SQUARE);
+
+ immBegin(GWN_PRIM_TRI_FAN, square ? 6 : 34);
+ immVertex3f(pos, 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);
+ if (square) {
+ immVertex3f(pos, z, z, 0);
+ immVertex3f(pos, -z, z, 0);
+ immVertex3f(pos, -z, -z, 0);
+ immVertex3f(pos, z, -z, 0);
+ immVertex3f(pos, 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);
+ immVertex3f(pos, z * cosf(angle), z * sinf(angle), 0.0f);
}
}
- glEnd();
+ immEnd();
}
-static void draw_transp_spot_volume(Lamp *la, float x, float z)
+static void draw_transp_spot_volume(Lamp *la, float x, float z, unsigned pos)
{
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
- glDepthMask(0);
+ glDepthMask(GL_FALSE);
/* draw backside darkening */
glCullFace(GL_FRONT);
glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
- glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
+ immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f);
- draw_spot_cone(la, x, z);
+ draw_spot_cone(la, x, z, pos);
/* draw front side lighting */
glCullFace(GL_BACK);
glBlendFunc(GL_ONE, GL_ONE);
- glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
+ immUniformColor3f(0.2f, 0.2f, 0.2f);
- draw_spot_cone(la, x, z);
+ draw_spot_cone(la, x, z, pos);
/* restore state */
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_BLEND);
- glDepthMask(1);
+ glDepthMask(GL_TRUE);
glDisable(GL_CULL_FACE);
- glCullFace(GL_BACK);
}
#ifdef WITH_GAMEENGINE
-static void draw_transp_sun_volume(Lamp *la)
+static void draw_transp_sun_volume(Lamp *la, unsigned pos)
{
float box[8][3];
@@ -1139,50 +1202,46 @@ static void draw_transp_sun_volume(Lamp *la)
box[1][2] = box[2][2] = box[5][2] = box[6][2] = -la->clipsta;
/* draw edges */
- draw_box(box, false);
+ imm_draw_box(box, false, pos);
/* draw faces */
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
- glDepthMask(0);
+ glDepthMask(GL_FALSE);
/* draw backside darkening */
glCullFace(GL_FRONT);
glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
- glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
+ immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f);
- draw_box(box, true);
+ imm_draw_box(box, true, pos);
/* draw front side lighting */
glCullFace(GL_BACK);
glBlendFunc(GL_ONE, GL_ONE);
- glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
+ immUniformColor3f(0.2f, 0.2f, 0.2f);
- draw_box(box, true);
+ imm_draw_box(box, true, pos);
/* restore state */
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_BLEND);
- glDepthMask(1);
+ glDepthMask(GL_TRUE);
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)
+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);
@@ -1190,7 +1249,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
!(G.f & G_PICKSEL) &&
(la->type == LA_SPOT) &&
(la->mode & LA_SHOW_CONE) &&
- !(base->flag & OB_FROMDUPLI) &&
+ !(base->flag_legacy & OB_FROMDUPLI) &&
!is_view);
#ifdef WITH_GAMEENGINE
@@ -1202,7 +1261,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
((la->mode & LA_SHAD_BUF) ||
(la->mode & LA_SHAD_RAY)) &&
(la->mode & LA_SHOW_SHADOW_BOX) &&
- !(base->flag & OB_FROMDUPLI) &&
+ !(base->flag_legacy & OB_FROMDUPLI) &&
!is_view);
#else
const bool drawshadowbox = false;
@@ -1210,118 +1269,159 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
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);
+ ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag);
return;
}
-
+
/* we first draw only the screen aligned & fixed scale stuff */
- glPushMatrix();
- glLoadMatrixf(rv3d->viewmat);
+ gpuPushMatrix();
+ gpuLoadMatrix(rv3d->viewmat);
/* lets calculate the scale: */
- lampsize = pixsize * ((float)U.obcenter_dia * 0.5f);
+ const float lampsize_px = U.obcenter_dia;
+ const float lampsize = pixsize * lampsize_px * 0.5f;
/* and view aligned matrix: */
copy_m4_m4(imat, rv3d->viewinv);
normalize_v3(imat[0]);
normalize_v3(imat[1]);
+ const unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
/* lamp center */
copy_v3_v3(vec, ob->obmat[3]);
+ float curcol[4];
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);
+ rgb_uchar_to_float(curcol, ob_wire_col);
+ curcol[3] = 0.6f;
+ /* TODO: pay attention to GL_BLEND */
}
- glLineWidth(1);
+ glLineWidth(1.0f);
+ setlinestyle(3);
if (lampsize > 0.0f) {
+ const float outlineWidth = 1.5f * U.pixelsize;
+ const float lampdot_size = lampsize_px * U.pixelsize + outlineWidth;
+ /* Inner Circle */
if ((dflag & DRAW_CONSTCOLOR) == 0) {
+ const float *color = curcol;
if (ob->id.us > 1) {
- if (is_obact || (ob->flag & SELECT)) {
- glColor4ub(0x88, 0xFF, 0xFF, 155);
+ if (is_obact || ((base->flag & BASE_SELECTED) != 0)) {
+ static const float active_color[4] = {0.533f, 1.0f, 1.0f, 1.0f};
+ color = active_color;
}
else {
- glColor4ub(0x77, 0xCC, 0xCC, 155);
+ static const float inactive_color[4] = {0.467f, 0.8f, 0.8f, 1.0f};
+ color = inactive_color;
}
}
+
+ GPU_enable_program_point_size();
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
+ immUniform1f("size", lampdot_size);
+ immUniform1f("outlineWidth", outlineWidth);
+ immUniformColor3fvAlpha(color, 0.3f);
+ immUniform4fv("outlineColor", color);
+
+ immBegin(GWN_PRIM_POINTS, 1);
+ immVertex3fv(pos, vec);
+ immEnd();
+
+ immUnbindProgram();
+
+ glDisable(GL_BLEND);
+ GPU_disable_program_point_size();
}
-
- /* Inner Circle */
- glEnable(GL_BLEND);
- drawcircball(GL_LINE_LOOP, vec, lampsize, imat);
- glDisable(GL_BLEND);
- drawcircball(GL_POLYGON, vec, lampsize, imat);
-
+ else {
+ /* CONSTCOLOR in effect */
+ /* TODO: separate picking from drawing */
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR);
+ /* color doesn't matter, so don't set */
+ glPointSize(lampdot_size);
+
+ immBegin(GWN_PRIM_POINTS, 1);
+ immVertex3fv(pos, vec);
+ immEnd();
+
+ immUnbindProgram();
+ }
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ /* TODO(merwin): short term, use DEPTH_ONLY for picking
+ * long term, separate picking from drawing
+ */
+
/* restore */
if ((dflag & DRAW_CONSTCOLOR) == 0) {
- if (ob->id.us > 1)
- glColor4ubv(curcol);
+ immUniformColor4fv(curcol);
}
/* Outer circle */
circrad = 3.0f * lampsize;
- setlinestyle(3);
- drawcircball(GL_LINE_LOOP, vec, circrad, imat);
+ imm_drawcircball(vec, circrad, imat, pos);
/* 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);
+ imm_drawcircball(vec, circrad + 3.0f * pixsize, imat, pos);
}
}
}
else {
- setlinestyle(3);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ if ((dflag & DRAW_CONSTCOLOR) == 0) {
+ immUniformColor4fv(curcol);
+ }
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);
-
+ gpuPushMatrix();
+ gpuTranslate3fv(vec);
+
setlinestyle(3);
-
- glBegin(GL_LINES);
+
+ immBegin(GWN_PRIM_LINES, 16);
for (axis = 0; axis < 8; axis++) {
- glVertex3fv(v1);
- glVertex3fv(v2);
+ immVertex3fv(pos, v1);
+ immVertex3fv(pos, v2);
mul_m3_v3(mat, v1);
mul_m3_v3(mat, v2);
}
- glEnd();
-
- glTranslatef(-vec[0], -vec[1], -vec[2]);
+ immEnd();
+ gpuPopMatrix();
}
-
+
if (la->type == LA_LOCAL) {
if (la->mode & LA_SPHERE) {
- drawcircball(GL_LINE_LOOP, vec, la->dist, imat);
+ imm_drawcircball(vec, la->dist, imat, pos);
}
}
-
- glPopMatrix(); /* back in object space */
+
+ gpuPopMatrix(); /* back in object space */
zero_v3(vec);
-
+
if (is_view) {
/* skip drawing extra info */
}
@@ -1353,24 +1453,18 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
{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);
+ immBegin(GWN_PRIM_LINES, 16);
+ for (int i = 1; i <= 4; ++i) {
+ immVertex3fv(pos, vertices[0]); /* apex to corner */
+ immVertex3fv(pos, vertices[i]);
+ int next_i = (i == 4) ? 1 : (i + 1);
+ immVertex3fv(pos, vertices[i]); /* corner to next corner */
+ immVertex3fv(pos, vertices[next_i]);
+ }
+ immEnd();
- glTranslatef(0.0f, 0.0f, x);
+ gpuTranslate3f(0.0f, 0.0f, x);
/* draw the square representing spotbl */
if (la->type == LA_SPOT) {
@@ -1380,22 +1474,21 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
* 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);
+ imm_draw_line_box_3d(pos, blend, -blend, -blend, blend);
}
}
}
else {
-
/* draw the angled sides of the cone */
- glBegin(GL_LINE_STRIP);
- glVertex3fv(vvec);
- glVertex3fv(vec);
- glVertex3fv(lvec);
- glEnd();
+ immBegin(GWN_PRIM_LINE_STRIP, 3);
+ immVertex3fv(pos, vvec);
+ immVertex3fv(pos, vec);
+ immVertex3fv(pos, lvec);
+ immEnd();
/* draw the circle at the end of the cone */
- glTranslatef(0.0f, 0.0f, x);
- circ(0.0f, 0.0f, z_abs);
+ gpuTranslate3f(0.0f, 0.0f, x);
+ imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, z_abs, 32);
/* draw the circle representing spotbl */
if (la->type == LA_SPOT) {
@@ -1405,17 +1498,17 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
* 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);
+ imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, blend, 32);
}
}
}
if (drawcone)
- draw_transp_spot_volume(la, x, z);
+ draw_transp_spot_volume(la, x, z, pos);
/* 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);
+ gpuTranslate3f(0.0f, 0.0f, -x); /* reverse translation above */
+ immBegin(GWN_PRIM_LINES, 2);
if (la->type == LA_SPOT && (la->mode & LA_SHAD_BUF)) {
float lvec_clip[3];
float vvec_clip[3];
@@ -1424,41 +1517,40 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
interp_v3_v3v3(lvec_clip, vec, lvec, clipsta_fac);
interp_v3_v3v3(vvec_clip, vec, vvec, clipsta_fac);
- glVertex3fv(lvec_clip);
- glVertex3fv(vvec_clip);
+ immVertex3fv(pos, lvec_clip);
+ immVertex3fv(pos, 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);
+ immVertex3f(pos, 0.0f, 0.0f, -circrad);
+ immVertex3f(pos, 0.0f, 0.0f, -la->dist);
}
- glEnd();
+ immEnd();
}
else if (ELEM(la->type, LA_HEMI, LA_SUN)) {
-
/* draw the line from the circle along the dist */
- glBegin(GL_LINES);
+ immBegin(GWN_PRIM_LINES, 2);
vec[2] = -circrad;
- glVertex3fv(vec);
+ immVertex3fv(pos, vec);
vec[2] = -la->dist;
- glVertex3fv(vec);
- glEnd();
-
+ immVertex3fv(pos, vec);
+ immEnd();
+
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;
-
+ outdist = 0.14f; mul = 1.4f; 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);
-
+ float v[3] = {0.0f, 0.0f, 0.0f};
+ zdist = 0.02f;
+
+ immBegin(GWN_PRIM_LINE_STRIP, 6);
+
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 */
@@ -1471,13 +1563,13 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
}
v[2] = v[2] - steps * zdist;
-
- glVertex3fv(v);
-
+
+ immVertex3fv(pos, v);
+
zdist = zdist * mul;
}
-
- glEnd();
+
+ immEnd();
/* flip the direction */
dir = -dir;
}
@@ -1485,96 +1577,92 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
#ifdef WITH_GAMEENGINE
if (drawshadowbox) {
- draw_transp_sun_volume(la);
+ draw_transp_sun_volume(la, pos);
}
#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);
+ imm_draw_line_box_3d(pos, -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);
+ imm_draw_line_box_3d(pos, -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();
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex3f(pos, 0.0f, 0.0f, -circrad);
+ immVertex3f(pos, 0.0f, 0.0f, -la->dist);
+ immEnd();
}
-
+
/* and back to viewspace */
- glPushMatrix();
- glLoadMatrixf(rv3d->viewmat);
+ gpuPushMatrix();
+ gpuLoadMatrix(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);
+ drawshadbuflimits(la, ob->obmat, pos);
}
-
+
if ((dflag & DRAW_CONSTCOLOR) == 0) {
- UI_GetThemeColor4ubv(TH_LAMP, col);
- glColor4ubv(col);
+ immUniformThemeColor(TH_LAMP);
}
glEnable(GL_BLEND);
-
+
if (vec[2] > 0) vec[2] -= circrad;
else vec[2] += circrad;
-
- glBegin(GL_LINES);
- glVertex3fv(vec);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex3fv(pos, vec);
vec[2] = 0;
- glVertex3fv(vec);
- glEnd();
-
- glPointSize(2.0);
- glBegin(GL_POINTS);
- glVertex3fv(vec);
- glEnd();
-
+ immVertex3fv(pos, vec);
+ immEnd();
+
+ glPointSize(2.0f);
+ immBegin(GWN_PRIM_POINTS, 1);
+ immVertex3fv(pos, vec);
+ immEnd();
+
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();
+
+ immUnbindProgram();
+ gpuPopMatrix();
}
-static void draw_limit_line(float sta, float end, const short dflag, const unsigned char col[3])
+static void draw_limit_line(float sta, float end, const short dflag, const unsigned char col[3], unsigned pos)
{
- glBegin(GL_LINES);
- glVertex3f(0.0, 0.0, -sta);
- glVertex3f(0.0, 0.0, -end);
- glEnd();
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex3f(pos, 0.0f, 0.0f, -sta);
+ immVertex3f(pos, 0.0f, 0.0f, -end);
+ immEnd();
if (!(dflag & DRAW_PICKING)) {
- glPointSize(3.0);
- glBegin(GL_POINTS);
+ glPointSize(3.0f);
+ /* would like smooth round points here, but that means binding another shader...
+ * if it's really desired, pull these points into their own function to be called after */
+ immBegin(GWN_PRIM_POINTS, 2);
if ((dflag & DRAW_CONSTCOLOR) == 0) {
- glColor3ubv(col);
+ immUniformColor3ubv(col);
}
- glVertex3f(0.0, 0.0, -sta);
- glVertex3f(0.0, 0.0, -end);
- glEnd();
+ immVertex3f(pos, 0.0f, 0.0f, -sta);
+ immVertex3f(pos, 0.0f, 0.0f, -end);
+ immEnd();
}
}
/* 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)
+static void draw_focus_cross(float dist, float size, unsigned pos)
{
- glBegin(GL_LINES);
- glVertex3f(-size, 0.0f, -dist);
- glVertex3f(size, 0.0f, -dist);
- glVertex3f(0.0f, -size, -dist);
- glVertex3f(0.0f, size, -dist);
- glEnd();
+ immBegin(GWN_PRIM_LINES, 4);
+ immVertex3f(pos, -size, 0.0f, -dist);
+ immVertex3f(pos, size, 0.0f, -dist);
+ immVertex3f(pos, 0.0f, -size, -dist);
+ immVertex3f(pos, 0.0f, size, -dist);
+ immEnd();
}
#ifdef VIEW3D_CAMERA_BORDER_HACK
@@ -1584,28 +1672,8 @@ bool view3d_camera_border_hack_test = false;
/* ****************** 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,
+ Scene *scene, BaseLegacy *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)
@@ -1629,7 +1697,7 @@ static void draw_viewport_object_reconstruction(
if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0)
mul_v3_fl(camera_size, tracking_object->scale);
- glPushMatrix();
+ gpuPushMatrix();
if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
/* current ogl matrix is translated in camera space, bundles should
@@ -1637,8 +1705,8 @@ static void draw_viewport_object_reconstruction(
* from current ogl matrix */
invert_m4_m4(imat, base->object->obmat);
- glMultMatrixf(imat);
- glMultMatrixf(mat);
+ gpuMultMatrix(imat);
+ gpuMultMatrix(mat);
}
else {
float obmat[4][4];
@@ -1647,7 +1715,7 @@ static void draw_viewport_object_reconstruction(
BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, framenr, obmat);
invert_m4_m4(imat, obmat);
- glMultMatrixf(imat);
+ gpuMultMatrix(imat);
}
for (track = tracksbase->first; track; track = track->next) {
@@ -1660,66 +1728,93 @@ static void draw_viewport_object_reconstruction(
continue;
if (dflag & DRAW_PICKING)
- GPU_select_load_id(base->selcol + (tracknr << 16));
+ GPU_select_load_id(base->object->select_color + (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]);
+ gpuPushMatrix();
+ gpuTranslate3fv(track->bundle_pos);
+ gpuScale3f(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) {
+ unsigned char color[4];
+ const unsigned char *color_ptr = NULL;
if ((dflag & DRAW_CONSTCOLOR) == 0) {
if (selected && (track->flag & TRACK_CUSTOMCOLOR) == 0) {
- glColor3ubv(ob_wire_col);
+ color_ptr = ob_wire_col;
}
else {
- glColor3fv(track->color);
+ rgba_float_to_uchar(color, track->color);
+ color_ptr = color;
}
}
- drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype);
+ drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype, color_ptr);
}
else if (v3d_drawtype > OB_WIRE) {
if (v3d->bundle_drawtype == OB_EMPTY_SPHERE) {
+ Gwn_Batch *batch;
+
+ gpuScaleUniform(0.05f);
+
/* selection outline */
if (selected) {
+ batch = Batch_get_sphere_wire(1);
+
if ((dflag & DRAW_CONSTCOLOR) == 0) {
- glColor3ubv(ob_wire_col);
+ Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR);
+ GWN_batch_uniform_4f(batch, "color",
+ ob_wire_col[0] / 255.f,
+ ob_wire_col[1] / 255.f,
+ ob_wire_col[2] / 255.f, 1.0f);
+ }
+ else {
+ Batch_set_builtin_program(batch, GPU_SHADER_3D_DEPTH_ONLY);
}
-
glLineWidth(2.0f);
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- draw_bundle_sphere();
-
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ GWN_batch_draw(batch);
}
+ batch = Batch_get_sphere(0);
+
if ((dflag & DRAW_CONSTCOLOR) == 0) {
- if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
- else UI_ThemeColor(TH_BUNDLE_SOLID);
+ const float light[3] = {0.0f, 0.0f, 1.0f};
+ float col[3];
+ Batch_set_builtin_program(batch, GPU_SHADER_SIMPLE_LIGHTING);
+ GWN_batch_uniform_3fv(batch, "light", light);
+
+ if (track->flag & TRACK_CUSTOMCOLOR) copy_v3_v3(col, track->color);
+ else UI_GetThemeColor3fv(TH_BUNDLE_SOLID, col);
+ GWN_batch_uniform_4f(batch, "color", col[0], col[1], col[2], 1.0f);
+ }
+ else {
+ Batch_set_builtin_program(batch, GPU_SHADER_3D_DEPTH_ONLY);
}
- draw_bundle_sphere();
+ GWN_batch_draw(batch);
}
else {
+ unsigned char color[4];
+ const unsigned char *color_ptr = NULL;
if ((dflag & DRAW_CONSTCOLOR) == 0) {
if (selected) {
- glColor3ubv(ob_wire_col);
+ color_ptr = ob_wire_col;
}
else {
- if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
- else UI_ThemeColor(TH_WIRE);
+ if (track->flag & TRACK_CUSTOMCOLOR) rgba_float_to_uchar(color, track->color);
+ else UI_GetThemeColor4ubv(TH_WIRE, color);
+
+ color_ptr = color;
}
}
- drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype);
+ drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype, color_ptr);
}
}
- glPopMatrix();
+ gpuPopMatrix();
if ((dflag & DRAW_PICKING) == 0 && (v3d->flag2 & V3D_SHOW_BUNDLENAME)) {
float pos[3];
@@ -1739,28 +1834,33 @@ static void draw_viewport_object_reconstruction(
MovieTrackingReconstruction *reconstruction;
reconstruction = BKE_tracking_object_get_reconstruction(tracking, tracking_object);
- if (reconstruction->camnr) {
+ if (reconstruction->camnr >= 2) {
MovieReconstructedCamera *camera = reconstruction->cameras;
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformThemeColor(TH_CAMERA_PATH);
- UI_ThemeColor(TH_CAMERA_PATH);
glLineWidth(2.0f);
- glBegin(GL_LINE_STRIP);
+ immBegin(GWN_PRIM_LINE_STRIP, reconstruction->camnr);
for (int a = 0; a < reconstruction->camnr; a++, camera++) {
- glVertex3fv(camera->mat[3]);
+ immVertex3fv(pos, camera->mat[3]);
}
- glEnd();
+ immEnd();
+
+ immUnbindProgram();
}
}
}
- glPopMatrix();
+ gpuPopMatrix();
*global_track_index = tracknr;
}
static void draw_viewport_reconstruction(
- Scene *scene, Base *base, const View3D *v3d, const RegionView3D *rv3d, MovieClip *clip,
+ Scene *scene, BaseLegacy *base, const View3D *v3d, const RegionView3D *rv3d, MovieClip *clip,
const short dflag, const unsigned char ob_wire_col[4],
const bool draw_selected)
{
@@ -1789,67 +1889,65 @@ static void draw_viewport_reconstruction(
/* 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);
+ GPU_select_load_id(base->object->select_color);
}
-static void drawcamera_volume(float near_plane[4][3], float far_plane[4][3], const GLenum mode)
+/* camera frame */
+static void drawcamera_frame(float vec[4][3], bool filled, unsigned pos)
{
- 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(near_plane[1]);
- glVertex3fv(far_plane[1]);
- glVertex3fv(far_plane[2]);
- glEnd();
-
- glBegin(mode);
- glVertex3fv(far_plane[0]);
- glVertex3fv(near_plane[0]);
- glVertex3fv(near_plane[3]);
- glVertex3fv(far_plane[3]);
- glEnd();
+ immBegin(filled ? GWN_PRIM_TRI_FAN : GWN_PRIM_LINE_LOOP, 4);
+ immVertex3fv(pos, vec[0]);
+ immVertex3fv(pos, vec[1]);
+ immVertex3fv(pos, vec[2]);
+ immVertex3fv(pos, vec[3]);
+ immEnd();
}
-/* camera frame */
-static void drawcamera_frame(float vec[4][3], const GLenum mode)
+/* center point to camera frame */
+static void drawcamera_framelines(float vec[4][3], float origin[3], unsigned pos)
{
- glBegin(mode);
- glVertex3fv(vec[0]);
- glVertex3fv(vec[1]);
- glVertex3fv(vec[2]);
- glVertex3fv(vec[3]);
- glEnd();
+ immBegin(GWN_PRIM_LINES, 8);
+ immVertex3fv(pos, origin);
+ immVertex3fv(pos, vec[0]);
+ immVertex3fv(pos, origin);
+ immVertex3fv(pos, vec[1]);
+ immVertex3fv(pos, origin);
+ immVertex3fv(pos, vec[2]);
+ immVertex3fv(pos, origin);
+ immVertex3fv(pos, vec[3]);
+ immEnd();
}
-/* center point to camera frame */
-static void drawcamera_framelines(float vec[4][3], float origin[3])
+static void drawcamera_volume(float near_plane[4][3], float far_plane[4][3], bool filled, unsigned pos)
{
- glBegin(GL_LINE_STRIP);
- glVertex3fv(vec[1]);
- glVertex3fv(origin);
- glVertex3fv(vec[0]);
- glVertex3fv(vec[3]);
- glVertex3fv(origin);
- glVertex3fv(vec[2]);
- glEnd();
+ drawcamera_frame(near_plane, filled, pos);
+ drawcamera_frame(far_plane, filled, pos);
+
+ if (filled) {
+ immBegin(GWN_PRIM_TRI_STRIP, 10);
+
+ immVertex3fv(pos, near_plane[0]);
+ immVertex3fv(pos, far_plane[0]);
+ immVertex3fv(pos, near_plane[1]);
+ immVertex3fv(pos, far_plane[1]);
+ immVertex3fv(pos, near_plane[2]);
+ immVertex3fv(pos, far_plane[2]);
+ immVertex3fv(pos, near_plane[3]);
+ immVertex3fv(pos, far_plane[3]);
+ immVertex3fv(pos, near_plane[0]);
+ immVertex3fv(pos, far_plane[0]);
+
+ immEnd();
+ }
+ else {
+ immBegin(GWN_PRIM_LINES, 8);
+ for (int i = 0; i < 4; ++i) {
+ immVertex3fv(pos, near_plane[i]);
+ immVertex3fv(pos, far_plane[i]);
+ }
+ immEnd();
+ }
}
static bool drawcamera_is_stereo3d(Scene *scene, View3D *v3d, Object *ob)
@@ -1861,7 +1959,7 @@ static bool drawcamera_is_stereo3d(Scene *scene, View3D *v3d, Object *ob)
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 vec[4][3], float drawsize, const float scale[3], unsigned pos)
{
float obmat[4][4];
float vec_lr[2][4][3];
@@ -1877,15 +1975,15 @@ static void drawcamera_stereo3d(
zero_v3(tvec);
- glPushMatrix();
+ /* caller bound GPU_SHADER_3D_UNIFORM_COLOR, passed in pos attribute ID */
for (int i = 0; i < 2; i++) {
ob = BKE_camera_multiview_render(scene, ob, names[i]);
cam_lr[i] = ob->data;
- glLoadMatrixf(rv3d->viewmat);
+ gpuLoadMatrix(rv3d->viewmat);
BKE_camera_multiview_model_matrix(&scene->r, ob, names[i], obmat);
- glMultMatrixf(obmat);
+ gpuMultMatrix(obmat);
copy_m3_m3(vec_lr[i], vec);
copy_v3_v3(vec_lr[i][3], vec[3]);
@@ -1902,10 +2000,10 @@ static void drawcamera_stereo3d(
if (is_stereo3d_cameras) {
/* camera frame */
- drawcamera_frame(vec_lr[i], GL_LINE_LOOP);
+ drawcamera_frame(vec_lr[i], false, pos);
/* center point to camera frame */
- drawcamera_framelines(vec_lr[i], tvec);
+ drawcamera_framelines(vec_lr[i], tvec, pos);
}
/* connecting line */
@@ -1919,21 +2017,20 @@ static void drawcamera_stereo3d(
}
}
-
/* the remaining drawing takes place in the view space */
- glLoadMatrixf(rv3d->viewmat);
+ gpuLoadMatrix(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);
+ glLineStipple(2, 0xAAAA);
+ glEnable(GL_LINE_STIPPLE);
- glBegin(GL_LINES);
- glVertex3fv(origin[0]);
- glVertex3fv(origin[1]);
- glEnd();
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex3fv(pos, origin[0]);
+ immVertex3fv(pos, origin[1]);
+ immEnd();
- GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ glDisable(GL_LINE_STIPPLE);
}
/* draw convergence plane */
@@ -1958,21 +2055,21 @@ static void drawcamera_stereo3d(
add_v3_v3(local_plane[i], axis_center);
}
- glColor3f(0.0f, 0.0f, 0.0f);
+ immUniformColor3f(0.0f, 0.0f, 0.0f);
/* camera frame */
- drawcamera_frame(local_plane, GL_LINE_LOOP);
+ drawcamera_frame(local_plane, false, pos);
if (v3d->stereo3d_convergence_alpha > 0.0f) {
glEnable(GL_BLEND);
- glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
+ glDepthMask(GL_FALSE); /* disable write in zbuffer, needed for nice transp */
- glColor4f(0.0f, 0.0f, 0.0f, v3d->stereo3d_convergence_alpha);
+ immUniformColor4f(0.0f, 0.0f, 0.0f, v3d->stereo3d_convergence_alpha);
- drawcamera_frame(local_plane, GL_QUADS);
+ drawcamera_frame(local_plane, true, pos);
glDisable(GL_BLEND);
- glDepthMask(1); /* restore write in zbuffer */
+ glDepthMask(GL_TRUE); /* restore write in zbuffer */
}
}
@@ -1997,37 +2094,31 @@ static void drawcamera_stereo3d(
}
/* camera frame */
- glColor3f(0.0f, 0.0f, 0.0f);
+ immUniformColor3f(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);
+ drawcamera_volume(near_plane, far_plane, false, pos);
if (v3d->stereo3d_volume_alpha > 0.0f) {
glEnable(GL_BLEND);
- glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
+ glDepthMask(GL_FALSE); /* disable write in zbuffer, needed for nice transp */
if (i == 0)
- glColor4f(0.0f, 1.0f, 1.0f, v3d->stereo3d_volume_alpha);
+ immUniformColor4f(0.0f, 1.0f, 1.0f, v3d->stereo3d_volume_alpha);
else
- glColor4f(1.0f, 0.0f, 0.0f, v3d->stereo3d_volume_alpha);
+ immUniformColor4f(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);
+ drawcamera_volume(near_plane, far_plane, true, pos);
glDisable(GL_BLEND);
- glDepthMask(1); /* restore write in zbuffer */
+ glDepthMask(GL_TRUE); /* 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])
+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;
@@ -2090,8 +2181,12 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
BKE_camera_view_frame_ex(scene, cam, cam->drawsize, is_view, scale,
asp, shift, &drawsize, vec);
- glDisable(GL_CULL_FACE);
- glLineWidth(1);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ if (ob_wire_col) {
+ immUniformColor3ubv(ob_wire_col);
+ }
+ glLineWidth(1.0f);
/* camera frame */
if (!is_stereo3d_cameras) {
@@ -2100,27 +2195,29 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
float obmat[4][4];
bool is_left = v3d->multiview_eye == STEREO_LEFT_ID;
- glPushMatrix();
- glLoadMatrixf(rv3d->viewmat);
+ gpuPushMatrix();
+ gpuLoadMatrix(rv3d->viewmat);
BKE_camera_multiview_model_matrix(&scene->r, ob, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, obmat);
- glMultMatrixf(obmat);
+ gpuMultMatrix(obmat);
- drawcamera_frame(vec, GL_LINE_LOOP);
- glPopMatrix();
+ drawcamera_frame(vec, false, pos);
+ gpuPopMatrix();
}
else {
- drawcamera_frame(vec, GL_LINE_LOOP);
+ drawcamera_frame(vec, false, pos);
}
}
- if (is_view)
+ if (is_view) {
+ immUnbindProgram();
return;
+ }
zero_v3(tvec);
/* center point to camera frame */
if (!is_stereo3d_cameras)
- drawcamera_framelines(vec, tvec);
+ drawcamera_framelines(vec, tvec, pos);
/* arrow on top */
tvec[2] = vec[1][2]; /* copy the depth */
@@ -2129,22 +2226,25 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
* 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);
+ if (i == 0) immBegin(GWN_PRIM_LINE_LOOP, 3);
+ else if (i == 1 && is_active) {
+ glDisable(GL_CULL_FACE); /* TODO: declarative state tracking */
+ immBegin(GWN_PRIM_TRIS, 3);
+ }
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 */
+ immVertex3fv(pos, tvec); /* left */
tvec[0] = shift[0] + ((0.7f * drawsize) * scale[0]);
- glVertex3fv(tvec); /* right */
+ immVertex3fv(pos, tvec); /* right */
tvec[0] = shift[0];
tvec[1] = shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]);
- glVertex3fv(tvec); /* top */
+ immVertex3fv(pos, tvec); /* top */
- glEnd();
+ immEnd();
}
if ((dflag & DRAW_SCENESET) == 0) {
@@ -2155,16 +2255,15 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
copy_m4_m4(nobmat, ob->obmat);
normalize_m4(nobmat);
- glPushMatrix();
- glLoadMatrixf(rv3d->viewmat);
- glMultMatrixf(nobmat);
+ gpuLoadMatrix(rv3d->viewmat);
+ gpuMultMatrix(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));
+ draw_limit_line(cam->clipsta, cam->clipend, dflag, (is_active ? col_hi : col), pos);
/* 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);
+ draw_focus_cross(BKE_camera_object_dof_distance(ob), cam->drawsize, pos);
}
if (cam->flag & CAM_SHOWMIST) {
@@ -2173,69 +2272,79 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
if (world) {
draw_limit_line(world->miststa, world->miststa + world->mistdist,
- dflag, (is_active ? col_hi : col));
+ dflag, (is_active ? col_hi : col), pos);
}
}
- glPopMatrix();
}
}
/* stereo cameras drawing */
if (is_stereo3d) {
- drawcamera_stereo3d(scene, v3d, rv3d, ob, cam, vec, drawsize, scale);
+ drawcamera_stereo3d(scene, v3d, rv3d, ob, cam, vec, drawsize, scale, pos);
}
+
+ immUnbindProgram();
}
/* flag similar to draw_object() */
-static void drawspeaker(Scene *UNUSED(scene), View3D *UNUSED(v3d), RegionView3D *UNUSED(rv3d),
- Object *UNUSED(ob), int UNUSED(flag))
+void drawspeaker(const unsigned char ob_wire_col[3])
{
- float vec[3];
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
- glEnable(GL_BLEND);
- glLineWidth(1);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ if (ob_wire_col) {
+ immUniformColor3ubv(ob_wire_col);
+ }
+
+ glLineWidth(1.0f);
+
+ const int segments = 16;
for (int j = 0; j < 3; j++) {
- vec[2] = 0.25f * j - 0.125f;
+ float z = 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);
+ immBegin(GWN_PRIM_LINE_LOOP, segments);
+ for (int i = 0; i < segments; i++) {
+ float x = cosf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
+ float y = sinf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
+ immVertex3f(pos, x, y, z);
}
- glEnd();
+ immEnd();
}
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);
+ float x = (((j + 1) % 2) * (j - 1)) * 0.5f;
+ float y = ((j % 2) * (j - 2)) * 0.5f;
+ immBegin(GWN_PRIM_LINE_STRIP, 3);
for (int i = 0; i < 3; i++) {
if (i == 1) {
- vec[0] *= 0.5f;
- vec[1] *= 0.5f;
+ x *= 0.5f;
+ y *= 0.5f;
}
- vec[2] = 0.25f * i - 0.125f;
- glVertex3fv(vec);
+ float z = 0.25f * i - 0.125f;
+ immVertex3f(pos, x, y, z);
}
- glEnd();
+ immEnd();
}
- glDisable(GL_BLEND);
+ immUnbindProgram();
}
-static void lattice_draw_verts(Lattice *lt, DispList *dl, BPoint *actbp, short sel)
+static void lattice_draw_verts(Lattice *lt, DispList *dl, BPoint *actbp, short sel,
+ unsigned int pos, unsigned int color)
{
BPoint *bp = lt->def;
const float *co = dl ? dl->verts : NULL;
+ float active_color[4], draw_color[4];
- const int color = sel ? TH_VERTEX_SELECT : TH_VERTEX;
- UI_ThemeColor(color);
+ UI_GetThemeColor4fv(sel ? TH_VERTEX_SELECT : TH_VERTEX, draw_color);
+ UI_GetThemeColor4fv(TH_ACTIVE_VERT, active_color);
glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
- glBegin(GL_POINTS);
+ immBeginAtMost(GWN_PRIM_POINTS, lt->pntsw * lt->pntsv * lt->pntsu);
for (int w = 0; w < lt->pntsw; w++) {
int wxt = (w == 0 || w == lt->pntsw - 1);
@@ -2247,12 +2356,12 @@ static void lattice_draw_verts(Lattice *lt, DispList *dl, BPoint *actbp, short s
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);
+ immAttrib4fv(color, active_color);
+ immVertex3fv(pos, dl ? co : bp->vec);
}
else if ((bp->f1 & SELECT) == sel) {
- glVertex3fv(dl ? co : bp->vec);
+ immAttrib4fv(color, draw_color);
+ immVertex3fv(pos, dl ? co : bp->vec);
}
}
}
@@ -2260,27 +2369,26 @@ static void lattice_draw_verts(Lattice *lt, DispList *dl, BPoint *actbp, short s
}
}
- glEnd();
+ immEnd();
}
-static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int actdef_wcol)
+static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int actdef_wcol,
+ unsigned int pos, unsigned int color)
{
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);
-
+ immAttrib3fv(color, col);
}
if (dl) {
- glVertex3fv(&dl->verts[index * 3]);
+ immVertex3fv(pos, &dl->verts[index * 3]);
}
else {
- glVertex3fv(lt->def[index].vec);
+ immVertex3fv(pos, lt->def[index].vec);
}
}
@@ -2328,7 +2436,7 @@ static void ensure_curve_cache(Scene *scene, Object *object)
#endif
/* lattice color is hardcoded, now also shows weightgroup values in edit mode */
-static void drawlattice(View3D *v3d, Object *ob)
+static void drawlattice(View3D *v3d, Object *ob, const short dflag, const unsigned char ob_wire_col[4])
{
Lattice *lt = ob->data;
DispList *dl;
@@ -2341,15 +2449,37 @@ static void drawlattice(View3D *v3d, Object *ob)
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);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int color, pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ if (actdef_wcol) {
+ color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR);
+ }
+ else {
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ if (is_edit) {
+ immUniformThemeColor(TH_WIRE_EDIT);
+ }
+ else {
+ if ((dflag & DRAW_CONSTCOLOR) == 0) {
+ immUniformColor3ubv(ob_wire_col);
+ }
+ else {
+ immUniformColor3f(0.0f, 0.0f, 0.0f);
+ }
+ }
+ }
+
+ glLineWidth(1.0f);
+ immBeginAtMost(GWN_PRIM_LINES, lt->pntsw * lt->pntsv * lt->pntsu * 6);
+
for (w = 0; w < lt->pntsw; w++) {
int wxt = (w == 0 || w == lt->pntsw - 1);
for (v = 0; v < lt->pntsv; v++) {
@@ -2358,30 +2488,40 @@ static void drawlattice(View3D *v3d, Object *ob)
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);
+ drawlattice__point(lt, dl, u, v, w - 1, actdef_wcol, pos, color);
+ drawlattice__point(lt, dl, u, v, w, actdef_wcol, pos, color);
}
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);
+ drawlattice__point(lt, dl, u, v - 1, w, actdef_wcol, pos, color);
+ drawlattice__point(lt, dl, u, v, w, actdef_wcol, pos, color);
}
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);
+ drawlattice__point(lt, dl, u - 1, v, w, actdef_wcol, pos, color);
+ drawlattice__point(lt, dl, u, v, w, actdef_wcol, pos, color);
}
}
}
}
- glEnd();
+
+ immEnd();
+ immUnbindProgram();
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);
-
+
+ Gwn_VertFormat *v_format = immVertexFormat();
+ unsigned int v_pos = GWN_vertformat_attr_add(v_format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ unsigned int v_color = GWN_vertformat_attr_add(v_format, "color", GWN_COMP_F32, 4, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR);
+
+ lattice_draw_verts(lt, dl, actbp, 0, v_pos, v_color);
+ lattice_draw_verts(lt, dl, actbp, 1, v_pos, v_color);
+
+ immUnbindProgram();
+
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
}
}
@@ -2395,6 +2535,7 @@ typedef struct drawDMVertSel_userData {
int active;
unsigned char *col[3]; /* (base, sel, act) */
char sel_prev;
+ unsigned int pos, color;
} drawDMVertSel_userData;
static void drawSelectedVertices__mapFunc(void *userData, int index, const float co[3],
@@ -2406,17 +2547,18 @@ static void drawSelectedVertices__mapFunc(void *userData, int index, const float
if (!(mv->flag & ME_HIDE)) {
const char sel = (index == data->active) ? 2 : (mv->flag & SELECT);
if (sel != data->sel_prev) {
- glColor3ubv(data->col[sel]);
+ immAttrib3ubv(data->color, data->col[sel]);
data->sel_prev = sel;
}
- glVertex3fv(co);
+ immVertex3fv(data->pos, co);
}
}
static void drawSelectedVertices(DerivedMesh *dm, Mesh *me)
{
drawDMVertSel_userData data;
+ Gwn_VertFormat *format = immVertexFormat();
/* TODO define selected color */
unsigned char base_col[3] = {0x0, 0x0, 0x0};
@@ -2431,9 +2573,18 @@ static void drawSelectedVertices(DerivedMesh *dm, Mesh *me)
data.col[1] = sel_col;
data.col[2] = act_col;
- glBegin(GL_POINTS);
+ data.color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ if (dm->getNumVerts(dm) == 0) return;
+
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
+
+ immBeginAtMost(GWN_PRIM_POINTS, dm->getNumVerts(dm));
dm->foreachMappedVert(dm, drawSelectedVertices__mapFunc, &data, DM_FOREACH_NOP);
- glEnd();
+ immEnd();
+
+ immUnbindProgram();
}
/* ************** DRAW MESH ****************** */
@@ -2480,25 +2631,34 @@ static void draw_dm_face_normals__mapFunc(void *userData, int index, const float
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);
+ immVertex3fv(data->pos, cent);
+ immVertex3f(data->pos, 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)
+static void draw_dm_face_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm, int theme_id)
{
+ Gwn_VertFormat *format = immVertexFormat();
drawDMNormal_userData data;
data.bm = em->bm;
data.normalsize = scene->toolsettings->normalsize;
+ data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
calcDrawDMNormalScale(ob, &data);
- glBegin(GL_LINES);
+ if (dm->getNumPolys(dm) == 0) return;
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformThemeColor(theme_id);
+
+ immBeginAtMost(GWN_PRIM_LINES, dm->getNumPolys(dm) * 2);
dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
- glEnd();
+ immEnd();
+
+ immUnbindProgram();
}
static void draw_dm_face_centers__mapFunc(void *userData, int index, const float cent[3], const float UNUSED(no[3]))
@@ -2509,16 +2669,28 @@ static void draw_dm_face_centers__mapFunc(void *userData, int index, const float
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) &&
(BM_elem_flag_test(efa, BM_ELEM_SELECT) == data->select))
{
- glVertex3fv(cent);
+ immVertex3fv(data->pos, cent);
}
}
-static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, bool select)
+static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, bool select, const unsigned char fcol[3])
{
- drawBMSelect_userData data = {em->bm, select};
+ Gwn_VertFormat *format = immVertexFormat();
- glBegin(GL_POINTS);
+ drawBMSelect_userData data;
+ data.bm = em->bm;
+ data.select = select;
+ data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ if (dm->getNumPolys(dm) == 0) return;
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor3ubv(fcol);
+
+ immBeginAtMost(GWN_PRIM_POINTS, dm->getNumPolys(dm));
dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, &data, DM_FOREACH_NOP);
- glEnd();
+ immEnd();
+
+ immUnbindProgram();
}
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])
@@ -2545,71 +2717,83 @@ static void draw_dm_vert_normals__mapFunc(void *userData, int index, const float
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);
+ immVertex3fv(data->pos, co);
+ immVertex3f(data->pos, 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)
+static void draw_dm_vert_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm, int theme_id)
{
drawDMNormal_userData data;
+ Gwn_VertFormat *format = immVertexFormat();
data.bm = em->bm;
data.normalsize = scene->toolsettings->normalsize;
+ data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
calcDrawDMNormalScale(ob, &data);
- glBegin(GL_LINES);
+ if (dm->getNumVerts(dm) == 0) return;
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformThemeColor(theme_id);
+
+ immBeginAtMost(GWN_PRIM_LINES, dm->getNumVerts(dm) * 2);
dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
- glEnd();
+ immEnd();
+
+ immUnbindProgram();
}
-/* 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]))
+static void draw_dm_verts_skin_root__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);
- }
+ 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;
+ imm_drawcircball(co, radius, data->imat, data->pos);
}
+ }
+}
+
+/* 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) {
/* 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);
+ immAttrib4ubv(data->color, data->th_editmesh_active);
+ immVertex3fv(data->pos, co);
}
else {
- glVertex3fv(co);
+ immAttrib4ubv(data->color, data->sel ? data->th_vertex_select : data->th_vertex);
+ immVertex3fv(data->pos, co);
}
}
}
static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, const char sel, BMVert *eve_act,
- RegionView3D *rv3d)
+ RegionView3D *rv3d, const unsigned char col[4])
{
+ Gwn_VertFormat *format = immVertexFormat();
+
drawDMVerts_userData data;
data.sel = sel;
data.eve_act = eve_act;
data.bm = em->bm;
+ data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ data.color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
/* Cache theme values */
UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, data.th_editmesh_active);
@@ -2617,16 +2801,37 @@ static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, const char sel, BMVer
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);
+ /* Set correct alpha */
+ data.th_editmesh_active[3] = data.th_vertex_select[3] = data.th_vertex[3] = data.th_skin_root[3] = col[3];
+
/* view-aligned matrix */
mul_m4_m4m4(data.imat, rv3d->viewmat, em->ob->obmat);
invert_m4(data.imat);
+ if (dm->getNumVerts(dm) == 0) return;
+
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
+
glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
- glBegin(GL_POINTS);
+
+ immBeginAtMost(GWN_PRIM_POINTS, dm->getNumVerts(dm));
dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data, DM_FOREACH_NOP);
- glEnd();
+ immEnd();
+
+ immUnbindProgram();
+
+ /* For skin root drawing */
+ data.cd_vskin_offset = CustomData_get_offset(&em->bm->vdata, CD_MVERT_SKIN);
+
+ if (data.cd_vskin_offset != -1) {
+ data.pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor4ubv(data.th_skin_root);
+
+ dm->foreachMappedVert(dm, draw_dm_verts_skin_root__mapFunc, &data, DM_FOREACH_NOP);
+
+ immUnbindProgram();
+ }
}
/* Draw edges with color set based on selection */
@@ -2932,24 +3137,32 @@ static void draw_dm_loop_normals__mapFunc(void *userData, int vertex_index, int
}
mul_v3_fl(vec, data->normalsize);
add_v3_v3(vec, co);
- glVertex3fv(co);
- glVertex3fv(vec);
+ immVertex3fv(data->pos, co);
+ immVertex3fv(data->pos, vec);
}
}
}
-static void draw_dm_loop_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
+static void draw_dm_loop_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm, int theme_id)
{
drawDMNormal_userData data;
data.bm = em->bm;
data.normalsize = scene->toolsettings->normalsize;
+ data.pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ if (dm->getNumLoops(dm) == 0) return;
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformThemeColor(theme_id);
calcDrawDMNormalScale(ob, &data);
- glBegin(GL_LINES);
+ immBeginAtMost(GWN_PRIM_LINES, dm->getNumLoops(dm) * 2);
dm->foreachMappedLoop(dm, draw_dm_loop_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
- glEnd();
+ immEnd();
+
+ immUnbindProgram();
}
/* Draw faces with color set based on selection
@@ -3066,7 +3279,7 @@ static void draw_dm_creases(BMEditMesh *em, DerivedMesh *dm)
data.cd_layer_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE);
if (data.cd_layer_offset != -1) {
- glLineWidth(3.0);
+ glLineWidth(3.0f);
dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, &data);
}
}
@@ -3080,7 +3293,7 @@ static DMDrawOption draw_dm_bweights__setDrawOptions(void *userData, int 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_SELECT, bweight);
+ UI_ThemeColorBlend(TH_WIRE_EDIT, TH_EDGE_BEVEL, bweight);
return DM_DRAW_OPTION_NORMAL;
}
}
@@ -3096,8 +3309,10 @@ static void draw_dm_bweights__mapFunc(void *userData, int index, const float co[
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_SELECT, bweight);
- glVertex3fv(co);
+ unsigned char col[3];
+ UI_GetThemeColorBlend3ubv(TH_VERTEX, TH_VERTEX_BEVEL, bweight, col);
+ immAttrib3ubv(data->col, col);
+ immVertex3fv(data->pos, co);
}
}
}
@@ -3111,11 +3326,21 @@ static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
data.bm = em->bm;
data.cd_layer_offset = CustomData_get_offset(&em->bm->vdata, CD_BWEIGHT);
+ /* is that ever true? */
if (data.cd_layer_offset != -1) {
- glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2);
- glBegin(GL_POINTS);
+ Gwn_VertFormat *format = immVertexFormat();
+ data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ data.col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
+
+ glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2.0f);
+
+ immBeginAtMost(GWN_PRIM_POINTS, dm->getNumVerts(dm));
dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, &data, DM_FOREACH_NOP);
- glEnd();
+ immEnd();
+
+ immUnbindProgram();
}
}
else {
@@ -3125,7 +3350,7 @@ static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
data.cd_layer_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT);
if (data.cd_layer_offset != -1) {
- glLineWidth(3.0);
+ glLineWidth(3.0f);
dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, &data);
}
}
@@ -3146,7 +3371,7 @@ static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit,
{
ToolSettings *ts = scene->toolsettings;
- if (v3d->zbuf) glDepthMask(0); /* disable write in zbuffer, zbuf select */
+ if (v3d->zbuf) glDepthMask(GL_FALSE); /* disable write in zbuffer, zbuf select */
for (int sel = 0; sel < 2; sel++) {
unsigned char col[4], fcol[4];
@@ -3176,15 +3401,12 @@ static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit,
}
if (ts->selectmode & SCE_SELECT_VERTEX) {
- glPointSize(size);
- glColor4ubv(col);
- draw_dm_verts(em, cageDM, sel, eve_act, rv3d);
+ draw_dm_verts(em, cageDM, sel, eve_act, rv3d, col);
}
if (check_ob_drawface_dot(scene, v3d, obedit->dt)) {
glPointSize(fsize);
- glColor4ubv(fcol);
- draw_dm_face_centers(em, cageDM, sel);
+ draw_dm_face_centers(em, cageDM, sel, fcol);
}
if (pass == 0) {
@@ -3194,7 +3416,7 @@ static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit,
}
}
- if (v3d->zbuf) glDepthMask(1);
+ if (v3d->zbuf) glDepthMask(GL_TRUE);
}
static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d,
@@ -3301,11 +3523,9 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
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);
+ ED_view3d_clipping_calc(&bb, clip_planes, ar, em->ob, &rect);
}
if (me->drawflag & ME_DRAWEXTRA_EDGELEN) {
@@ -3669,7 +3889,7 @@ static DMDrawOption draw_em_fancy__setGLSLFaceOpts(void *userData, int index)
}
}
-static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
+static void draw_em_fancy(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d,
Object *ob, BMEditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, const char dt)
{
@@ -3678,7 +3898,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
const bool use_occlude_wire = (dt > OB_WIRE) && (v3d->flag2 & V3D_OCCLUDE_WIRE);
bool use_depth_offset = false;
- glLineWidth(1);
+ glLineWidth(1.0f);
BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE | BM_FACE);
@@ -3687,7 +3907,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
draw_mesh_paint_weight_faces(finalDM, true, draw_em_fancy__setFaceOpts, me->edit_btmesh);
ED_view3d_polygon_offset(rv3d, 1.0);
- glDepthMask(0);
+ glDepthMask(GL_FALSE);
use_depth_offset = true;
}
else {
@@ -3707,7 +3927,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
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)) {
+ if (draw_glsl_material(scene, sl, ob, v3d, dt)) {
glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
finalDM->drawMappedFacesGLSL(finalDM, GPU_object_material_bind,
@@ -3717,7 +3937,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
glFrontFace(GL_CCW);
}
else {
- draw_mesh_textured(scene, v3d, rv3d, ob, finalDM, 0);
+ draw_mesh_textured(scene, sl, v3d, rv3d, ob, finalDM, 0);
}
}
else {
@@ -3734,7 +3954,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
UI_ThemeColor(TH_WIRE_EDIT);
ED_view3d_polygon_offset(rv3d, 1.0);
- glDepthMask(0);
+ glDepthMask(GL_FALSE);
use_depth_offset = true;
}
else {
@@ -3784,7 +4004,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
#endif
glEnable(GL_BLEND);
- glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
+ glDepthMask(GL_FALSE); /* 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))
@@ -3800,7 +4020,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
#endif
glDisable(GL_BLEND);
- glDepthMask(1); /* restore write in zbuffer */
+ glDepthMask(GL_TRUE); /* restore write in zbuffer */
}
else if (efa_act) {
/* even if draw faces is off it would be nice to draw the stipple face
@@ -3815,7 +4035,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
glEnable(GL_BLEND);
- glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
+ glDepthMask(GL_FALSE); /* disable write in zbuffer, needed for nice transp */
#ifdef WITH_FREESTYLE
draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act);
@@ -3824,7 +4044,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
#endif
glDisable(GL_BLEND);
- glDepthMask(1); /* restore write in zbuffer */
+ glDepthMask(GL_TRUE); /* restore write in zbuffer */
}
/* here starts all fancy draw-extra over */
@@ -3838,7 +4058,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
else {
if (me->drawflag & ME_DRAWSEAMS) {
UI_ThemeColor(TH_EDGE_SEAM);
- glLineWidth(2);
+ glLineWidth(2.0f);
draw_dm_edges_seams(em, cageDM);
@@ -3847,7 +4067,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
if (me->drawflag & ME_DRAWSHARP) {
UI_ThemeColor(TH_EDGE_SHARP);
- glLineWidth(2);
+ glLineWidth(2.0f);
draw_dm_edges_sharp(em, cageDM);
@@ -3857,7 +4077,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
#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);
+ glLineWidth(2.0f);
draw_dm_edges_freestyle(em, cageDM);
@@ -3872,7 +4092,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
draw_dm_bweights(em, scene, cageDM);
}
- glLineWidth(1);
+ glLineWidth(1.0f);
draw_em_fancy_edges(em, scene, v3d, me, cageDM, 0, eed_act);
}
@@ -3880,16 +4100,13 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
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);
+ draw_dm_face_normals(em, scene, ob, cageDM, TH_NORMAL);
}
if (me->drawflag & ME_DRAW_VNORMALS) {
- UI_ThemeColor(TH_VNORMAL);
- draw_dm_vert_normals(em, scene, ob, cageDM);
+ draw_dm_vert_normals(em, scene, ob, cageDM, TH_VNORMAL);
}
if (me->drawflag & ME_DRAW_LNORMALS) {
- UI_ThemeColor(TH_LNORMAL);
- draw_dm_loop_normals(em, scene, ob, cageDM);
+ draw_dm_loop_normals(em, scene, ob, cageDM, TH_LNORMAL);
}
if ((me->drawflag & (ME_DRAWEXTRA_EDGELEN |
@@ -3910,7 +4127,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
}
if (use_depth_offset) {
- glDepthMask(1);
+ glDepthMask(GL_TRUE);
ED_view3d_polygon_offset(rv3d, 0.0);
GPU_object_material_unbind();
}
@@ -3921,15 +4138,97 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
#endif
}
+static void draw_em_fancy_new(Scene *UNUSED(scene), ARegion *UNUSED(ar), View3D *UNUSED(v3d),
+ Object *UNUSED(ob), Mesh *me, BMEditMesh *UNUSED(em), DerivedMesh *UNUSED(cageDM), DerivedMesh *UNUSED(finalDM), const char UNUSED(dt))
+{
+ /* for now... something simple! */
+ Gwn_Batch *surface = DRW_mesh_batch_cache_get_all_triangles(me);
+
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LEQUAL);
+
+ glEnable(GL_BLEND);
+
+ /* disable depth writes for transparent surface, so it doesn't interfere with itself */
+ glDepthMask(GL_FALSE);
+
+ Batch_set_builtin_program(surface, GPU_SHADER_3D_UNIFORM_COLOR);
+ GWN_batch_uniform_4f(surface, "color", 1.0f, 0.5f, 0.0f, 0.5f);
+ GWN_batch_draw(surface);
+
+#if 0 /* until I understand finalDM better */
+ if (finalDM != cageDM) {
+ puts("finalDM != cageDM");
+ Gwn_Batch *finalSurface = MBC_get_all_triangles(finalDM);
+ Batch_set_builtin_program(finalSurface, GPU_SHADER_3D_UNIFORM_COLOR);
+ GWN_batch_uniform_4f(finalSurface, "color", 0.0f, 0.0f, 0.0f, 0.05f);
+ GWN_batch_draw(finalSurface);
+ }
+#endif
+
+ glDepthMask(GL_TRUE);
+
+ /* now write surface depth so other objects won't poke through
+ * NOTE: does not help as much as desired
+ * TODO: draw edit object last to avoid this mess
+ */
+ Batch_set_builtin_program(surface, GPU_SHADER_3D_DEPTH_ONLY);
+ GWN_batch_draw(surface);
+
+ if (GLEW_VERSION_3_2) {
+#if 0
+ Gwn_Batch *overlay = DRW_mesh_batch_cache_get_overlay_edges(me);
+ Batch_set_builtin_program(overlay, GPU_SHADER_EDGES_OVERLAY);
+ GWN_batch_uniform_2f(overlay, "viewportSize", ar->winx, ar->winy);
+ GWN_batch_draw(overlay);
+#endif
+
+#if 0 /* TODO: use this SIMPLE variant for pure triangle meshes */
+ Batch_set_builtin_program(surface, GPU_SHADER_EDGES_OVERLAY_SIMPLE);
+ /* use these defaults:
+ * const float edgeColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
+ * GWN_batch_uniform_4f(surface, "fillColor", edgeColor[0], edgeColor[1], edgeColor[2], 0.0f);
+ * GWN_batch_uniform_4fv(surface, "outlineColor", edgeColor);
+ * GWN_batch_uniform_1f(surface, "outlineWidth", 1.0f);
+ */
+ GWN_batch_uniform_2f(surface, "viewportSize", ar->winx, ar->winy);
+ GWN_batch_draw(surface);
+#endif
+ }
+ else {
+ Gwn_Batch *edges = DRW_mesh_batch_cache_get_all_edges(me);
+ Batch_set_builtin_program(edges, GPU_SHADER_3D_UNIFORM_COLOR);
+ GWN_batch_uniform_4f(edges, "color", 0.0f, 0.0f, 0.0f, 1.0f);
+ glEnable(GL_LINE_SMOOTH);
+ glLineWidth(1.5f);
+ GWN_batch_draw(edges);
+ glDisable(GL_LINE_SMOOTH);
+ }
+
+#if 0 /* looks good even without points */
+ Gwn_Batch *verts = MBC_get_all_verts(me);
+ glEnable(GL_BLEND);
+
+ Batch_set_builtin_program(verts, GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
+ GWN_batch_uniform_4f(verts, "color", 0.0f, 0.0f, 0.0f, 1.0f);
+ GWN_batch_uniform_1f(verts, "size", UI_GetThemeValuef(TH_VERTEX_SIZE) * 1.5f);
+ GWN_batch_draw(verts);
+
+ glDisable(GL_BLEND);
+#endif
+}
+
/* Mesh drawing routines */
-static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm)
+void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm, const unsigned char ob_wire_col[4]) /* LEGACY */
{
if ((v3d->transp == false) && /* not when we draw the transparent pass */
(ob->mode & OB_MODE_ALL_BRUSH) == false) /* not when painting (its distracting) - campbell */
{
glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
- glDepthMask(0);
+ glDepthMask(GL_FALSE);
+
+ if (ob_wire_col) glColor4ubv(ob_wire_col);
/* if transparent, we cannot draw the edges for solid select... edges
* have no material info. GPU_object_material_visible will skip the
@@ -3943,7 +4242,49 @@ static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm)
dm->drawEdges(dm, 0, 1);
}
- glDepthMask(1);
+ glDepthMask(GL_TRUE);
+ }
+}
+
+static void draw_mesh_object_outline_new(View3D *v3d, RegionView3D *rv3d, Object *ob, Mesh *me, const bool is_active)
+{
+ 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(GL_FALSE);
+
+ float outline_color[4];
+ UI_GetThemeColor4fv((is_active ? TH_ACTIVE : TH_SELECT), outline_color);
+
+#if 1 /* new version that draws only silhouette edges */
+ Gwn_Batch *fancy_edges = DRW_mesh_batch_cache_get_fancy_edges(me);
+
+ if (rv3d->persp == RV3D_ORTHO) {
+ Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_ORTHO);
+ /* set eye vector, transformed to object coords */
+ float eye[3] = { 0.0f, 0.0f, 1.0f }; /* looking into the screen */
+ mul_m3_v3(gpuGetNormalMatrixInverse(NULL), eye);
+ GWN_batch_uniform_3fv(fancy_edges, "eye", eye);
+ }
+ else {
+ Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_PERSP);
+ }
+
+ GWN_batch_uniform_1b(fancy_edges, "drawFront", false);
+ GWN_batch_uniform_1b(fancy_edges, "drawBack", false);
+ GWN_batch_uniform_1b(fancy_edges, "drawSilhouette", true);
+ GWN_batch_uniform_4fv(fancy_edges, "silhouetteColor", outline_color);
+
+ GWN_batch_draw(fancy_edges);
+#else /* alternate version that matches look of old viewport (but more efficient) */
+ Gwn_Batch *batch = MBC_get_all_edges(dm);
+ Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR);
+ GWN_batch_uniform_4fv(batch, "color", outline_color);
+ GWN_batch_draw(batch);
+#endif
+
+ glDepthMask(GL_TRUE);
}
}
@@ -3953,11 +4294,11 @@ static bool object_is_halo(Scene *scene, Object *ob)
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,
+static void draw_mesh_fancy(Scene *scene, SceneLayer *sl, 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;
+ Object *ob = (rv3d->rflag & RV3D_IS_GAME_ENGINE) ? BKE_object_lod_meshob_get(base->object, sl) : base->object;
#else
Object *ob = base->object;
#endif
@@ -3965,7 +4306,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
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);
+ const bool is_obact = (ob == OBACT_NEW);
int draw_flags = (is_obact && BKE_paint_select_face_test(ob)) ? DRAW_FACE_SELECT : 0;
if (!dm)
@@ -4001,12 +4342,12 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
if (dt == OB_BOUNDBOX) {
if (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_WIRE) == 0)
- draw_bounding_volume(ob, ob->boundtype);
+ draw_bounding_volume(ob, ob->boundtype, ob_wire_col);
}
else if ((no_faces && no_edges) ||
((!is_obact || (ob->mode == OB_MODE_OBJECT)) && object_is_halo(scene, ob)))
{
- glPointSize(1.5);
+ glPointSize(1.5f);
dm->drawVerts(dm);
}
else if ((dt == OB_WIRE) || no_faces) {
@@ -4019,19 +4360,19 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
if ((v3d->flag & V3D_SELECT_OUTLINE) &&
((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
- (base->flag & SELECT) &&
+ (base->flag & BASE_SELECTED) &&
!(G.f & G_PICKSEL || (draw_flags & DRAW_FACE_SELECT)) &&
(draw_wire == OBDRAW_WIRE_OFF))
{
- draw_mesh_object_outline(v3d, ob, dm);
+ draw_mesh_object_outline(v3d, ob, dm, ob_wire_col);
}
- if (draw_glsl_material(scene, ob, v3d, dt) && !(draw_flags & DRAW_MODIFIERS_PREVIEW)) {
+ if (draw_glsl_material(scene, sl, 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))) {
+ if ((v3d->flag2 & V3D_SHOW_SOLID_MATCAP) && ob->sculpt && (p = BKE_paint_get_active(scene, sl))) {
GPUVertexAttribs gattribs;
float planes[4][4];
float (*fpl)[4] = NULL;
@@ -4039,7 +4380,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
if (ob->sculpt->partial_redraw) {
if (ar->do_draw & RGN_DRAW_PARTIAL) {
- ED_sculpt_redraw_planes_get(planes, ar, rv3d, ob);
+ ED_sculpt_redraw_planes_get(planes, ar, ob);
fpl = planes;
ob->sculpt->partial_redraw = 0;
}
@@ -4064,7 +4405,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
draw_mesh_face_select(rv3d, me, dm, false);
}
else {
- draw_mesh_textured(scene, v3d, rv3d, ob, dm, draw_flags);
+ draw_mesh_textured(scene, sl, v3d, rv3d, ob, dm, draw_flags);
}
if (draw_loose && !(draw_flags & DRAW_FACE_SELECT)) {
@@ -4090,11 +4431,11 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
/* draw outline */
if ((v3d->flag & V3D_SELECT_OUTLINE) &&
((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
- (base->flag & SELECT) &&
+ (base->flag & BASE_SELECTED) &&
(draw_wire == OBDRAW_WIRE_OFF) &&
(ob->sculpt == NULL))
{
- draw_mesh_object_outline(v3d, ob, dm);
+ draw_mesh_object_outline(v3d, ob, dm, ob_wire_col);
}
/* materials arent compatible with vertex colors */
@@ -4114,23 +4455,23 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
if ((v3d->flag & V3D_SELECT_OUTLINE) &&
((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
- (base->flag & SELECT) &&
+ (base->flag & BASE_SELECTED) &&
(draw_wire == OBDRAW_WIRE_OFF) &&
(ob->sculpt == NULL))
{
- draw_mesh_object_outline(v3d, ob, dm);
+ draw_mesh_object_outline(v3d, ob, dm, ob_wire_col);
}
glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
- if (ob->sculpt && (p = BKE_paint_get_active(scene))) {
+ if (ob->sculpt && (p = BKE_paint_get_active(scene, sl))) {
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);
+ ED_sculpt_redraw_planes_get(planes, ar, ob);
fpl = planes;
ob->sculpt->partial_redraw = 0;
}
@@ -4171,7 +4512,9 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
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);
+ float color[3];
+ ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.15f, color);
+ glColor3fv(color);
}
else {
glColor3ubv(ob_wire_col);
@@ -4189,21 +4532,20 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
*/
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 */
+ glDepthMask(GL_FALSE); /* 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);
+ glDepthMask(GL_TRUE);
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;
- glColor3f(0.0f, 0.0f, 0.0f);
glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
if (!use_depth) glDisable(GL_DEPTH_TEST);
@@ -4216,7 +4558,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
}
/* 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,
+static bool draw_mesh_object(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d, RegionView3D *rv3d, BaseLegacy *base,
const char dt, const unsigned char ob_wire_col[4], const short dflag)
{
Object *ob = base->object;
@@ -4270,13 +4612,13 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3
if (use_material) {
if (dt > OB_WIRE) {
- const bool glsl = draw_glsl_material(scene, ob, v3d, dt);
+ const bool glsl = draw_glsl_material(scene, sl, ob, v3d, dt);
- GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
+ GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, glsl, NULL);
}
}
- draw_em_fancy(scene, ar, v3d, ob, em, cageDM, finalDM, dt);
+ draw_em_fancy(scene, sl, ar, v3d, ob, em, cageDM, finalDM, dt);
if (use_material) {
GPU_end_object_materials();
@@ -4289,16 +4631,16 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3
/* 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);
+ const bool glsl = draw_glsl_material(scene, sl, 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,
+ GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, glsl,
(check_alpha) ? &do_alpha_after : NULL);
}
}
- draw_mesh_fancy(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag);
+ draw_mesh_fancy(scene, sl, ar, v3d, rv3d, base, dt, ob_wire_col, dflag);
GPU_end_object_materials();
@@ -4306,7 +4648,7 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3
}
}
- if ((dflag & DRAW_PICKING) == 0 && (base->flag & OB_FROMDUPLI) == 0 && (v3d->flag2 & V3D_RENDER_SHADOW) == 0) {
+ if ((dflag & DRAW_PICKING) == 0 && (base->flag_legacy & 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) {
@@ -4330,18 +4672,547 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3
return retval;
}
+static void make_color_variations(const unsigned char base_ubyte[4], float low[4], float med[4], float high[4], const bool other_obedit)
+{
+ /* original idea: nice variations (lighter & darker shades) of base color
+ * current implementation uses input color as high; med & low get closer to background color
+ */
+
+ float bg[3];
+ UI_GetThemeColor3fv(TH_BACK, bg);
+
+ float base[4];
+ rgba_uchar_to_float(base, base_ubyte);
+
+ if (other_obedit) {
+ /* this object should fade away so user can focus on the object being edited */
+ interp_v3_v3v3(low, bg, base, 0.1f);
+ interp_v3_v3v3(med, bg, base, 0.2f);
+ interp_v3_v3v3(high, bg, base, 0.25f);
+ }
+ else {
+ interp_v3_v3v3(low, bg, base, 0.333f);
+ interp_v3_v3v3(med, bg, base, 0.667f);
+ copy_v3_v3(high, base);
+ }
+
+ /* use original alpha */
+ low[3] = base[3];
+ med[3] = base[3];
+ high[3] = base[3];
+}
+
+static void draw_mesh_fancy_new(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base,
+ const char dt, const unsigned char ob_wire_col[4], const short dflag, const bool other_obedit)
+{
+ if (dflag & (DRAW_PICKING | DRAW_CONSTCOLOR)) {
+ /* too complicated! use existing methods */
+ /* TODO: move this into a separate depth pre-pass */
+ draw_mesh_fancy(scene, sl, ar, v3d, rv3d, base, dt, ob_wire_col, dflag);
+ return;
+ }
+
+#ifdef WITH_GAMEENGINE
+ Object *ob = (rv3d->rflag & RV3D_IS_GAME_ENGINE) ? BKE_object_lod_meshob_get(base->object, sl) : base->object;
+#else
+ Object *ob = base->object;
+#endif
+ Mesh *me = ob->data;
+ eWireDrawMode draw_wire = OBDRAW_WIRE_OFF; /* could be bool draw_wire_overlay */
+ bool no_edges, no_faces;
+ DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
+ const bool is_obact = (ob == OBACT_NEW);
+ int draw_flags = (is_obact && BKE_paint_select_face_test(ob)) ? DRAW_FACE_SELECT : 0;
+
+ if (!dm)
+ return;
+
+ const bool solid = dt >= OB_SOLID;
+ if (solid) {
+ 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;
+ }
+
+ /* 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);
+ }
+
+ if (solid) {
+ /* 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, ob_wire_col);
+ }
+ else if ((no_faces && no_edges) ||
+ ((!is_obact || (ob->mode == OB_MODE_OBJECT)) && object_is_halo(scene, ob)))
+ {
+ glPointSize(1.5f);
+ // dm->drawVerts(dm);
+ // TODO: draw smooth round points as a batch
+ }
+ else if ((dt == OB_WIRE) || no_faces) {
+ draw_wire = OBDRAW_WIRE_ON;
+
+ /* enable depth for wireframes */
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+
+ glLineWidth(1.0f);
+
+#if 1 /* fancy wireframes */
+
+ Gwn_Batch *fancy_edges = DRW_mesh_batch_cache_get_fancy_edges(me);
+
+ if (rv3d->persp == RV3D_ORTHO) {
+ Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_ORTHO);
+ /* set eye vector, transformed to object coords */
+ float eye[3] = { 0.0f, 0.0f, 1.0f }; /* looking into the screen */
+ mul_m3_v3(gpuGetNormalMatrixInverse(NULL), eye);
+ GWN_batch_uniform_3fv(fancy_edges, "eye", eye);
+ }
+ else {
+ Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_PERSP);
+ }
+
+ float frontColor[4];
+ float backColor[4];
+ float outlineColor[4];
+ make_color_variations(ob_wire_col, backColor, frontColor, outlineColor, other_obedit);
+
+ GWN_batch_uniform_4fv(fancy_edges, "frontColor", frontColor);
+ GWN_batch_uniform_4fv(fancy_edges, "backColor", backColor);
+ GWN_batch_uniform_1b(fancy_edges, "drawFront", true);
+ GWN_batch_uniform_1b(fancy_edges, "drawBack", true); /* false here = backface cull */
+ GWN_batch_uniform_1b(fancy_edges, "drawSilhouette", false);
+
+ GWN_batch_draw(fancy_edges);
+
+ /* extra oomph for the silhouette contours */
+ glLineWidth(2.0f);
+ GWN_batch_program_use_begin(fancy_edges); /* hack to make the following uniforms stick */
+ GWN_batch_uniform_1b(fancy_edges, "drawFront", false);
+ GWN_batch_uniform_1b(fancy_edges, "drawBack", false);
+ GWN_batch_uniform_1b(fancy_edges, "drawSilhouette", true);
+ GWN_batch_uniform_4fv(fancy_edges, "silhouetteColor", outlineColor);
+
+ GWN_batch_draw(fancy_edges);
+
+#else /* simple wireframes */
+
+ Gwn_Batch *batch = MBC_get_all_edges(dm);
+ Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR);
+
+ float color[4];
+ rgba_uchar_to_float(color, ob_wire_col);
+
+ GWN_batch_uniform_4fv(batch, "color", color);
+
+ GWN_batch_draw(batch);
+#endif
+ }
+ 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 & BASE_SELECTED) &&
+ !(G.f & G_PICKSEL || (draw_flags & DRAW_FACE_SELECT)) &&
+ (draw_wire == OBDRAW_WIRE_OFF))
+ {
+ draw_mesh_object_outline_new(v3d, rv3d, ob, me, (ob == OBACT_NEW));
+ }
+
+ if (draw_glsl_material(scene, sl, 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, sl))) {
+ 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, 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);
+
+ 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, sl, 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)) {
+ /* TODO: draw basic faces with GPU_SHADER_3D_DEPTH_ONLY */
+ }
+ else {
+ const float specular[3] = {0.47f, 0.47f, 0.47f};
+
+ /* draw outline */
+ /* TODO: move this into a separate pass */
+ if ((v3d->flag & V3D_SELECT_OUTLINE) &&
+ ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
+ (base->flag & BASE_SELECTED) &&
+ (draw_wire == OBDRAW_WIRE_OFF) &&
+ (ob->sculpt == NULL))
+ {
+ draw_mesh_object_outline_new(v3d, rv3d, ob, me, (ob == OBACT_NEW));
+ }
+
+ /* 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 & BASE_SELECTED) &&
+ (draw_wire == OBDRAW_WIRE_OFF) &&
+ (ob->sculpt == NULL))
+ {
+ /* TODO: move this into a separate pass */
+ draw_mesh_object_outline_new(v3d, rv3d, ob, me, (ob == OBACT_NEW));
+ }
+
+ glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
+
+ if (ob->sculpt && (p = BKE_paint_get_active(scene, sl))) {
+ 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, 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)) // <-- is this "== 0" in the right spot???
+ {
+ /* 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) {
+ /* TODO:
+ * Batch_UniformColor4ubv(ob_wire_col);
+ */
+ }
+
+ /* If drawing wire and drawtype is not OB_WIRE then we are
+ * overlaying the wires.
+ *
+ * No need for polygon offset because new technique is AWESOME.
+ */
+#if 0
+ glLineWidth(1.0f);
+ dm->drawEdges(dm, ((dt == OB_WIRE) || no_faces), (ob->dtx & OB_DRAW_ALL_EDGES) != 0);
+#else
+ /* something */
+#endif
+ }
+
+#if 0 // (merwin) what is this for?
+ 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);
+ }
+#endif
+
+ dm->release(dm);
+}
+
+static bool UNUSED_FUNCTION(draw_mesh_object_new)(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d, RegionView3D *rv3d, BaseLegacy *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 (v3d->flag2 & V3D_RENDER_SHADOW) {
+ /* TODO: handle shadow pass separately */
+ 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 */
+ const bool solid = dt > OB_WIRE;
+ const bool cullBackface = solid && (v3d->flag2 & V3D_BACKFACE_CULLING);
+ if (cullBackface) {
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ }
+
+ if (ob == obedit || drawlinked) {
+ DerivedMesh *finalDM, *cageDM;
+
+ if (obedit != ob) {
+ /* linked to the edit object */
+ 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 = solid && ((me->drawflag & ME_DRAWEIGHT) == 0);
+
+#if 0 // why update if not being used?
+ DM_update_materials(finalDM, ob);
+ if (cageDM != finalDM) {
+ DM_update_materials(cageDM, ob);
+ }
+#endif // moved to below
+
+ if (use_material) {
+ DM_update_materials(finalDM, ob);
+ if (cageDM != finalDM) {
+ DM_update_materials(cageDM, ob);
+ }
+
+ const bool glsl = draw_glsl_material(scene, sl, ob, v3d, dt);
+
+ GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, glsl, NULL);
+ }
+
+ draw_em_fancy_new(scene, ar, v3d, ob, me, 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 (solid) {
+ const bool glsl = draw_glsl_material(scene, sl, ob, v3d, dt);
+
+ if (dt == OB_SOLID || glsl) {
+ const bool check_alpha = check_alpha_pass(base);
+ GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, glsl,
+ (check_alpha) ? &do_alpha_after : NULL);
+ }
+ }
+
+ const bool other_obedit = obedit && (obedit != ob);
+
+ draw_mesh_fancy_new(scene, sl, ar, v3d, rv3d, base, dt, ob_wire_col, dflag, other_obedit);
+
+ GPU_end_object_materials();
+
+ if (me->totvert == 0) retval = true;
+ }
+ }
+
+ if (cullBackface)
+ glDisable(GL_CULL_FACE);
+
+ return retval;
+}
+
/* ************** DRAW DISPLIST ****************** */
+static void drawDispListVerts(Gwn_PrimType prim_type, const void *data, unsigned int vert_ct, const unsigned char wire_col[3])
+{
+ Gwn_VertFormat format = {0};
+ unsigned int pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, vert_ct);
+
+ GWN_vertbuf_attr_fill(vbo, pos_id, data);
+
+ Gwn_Batch *batch = GWN_batch_create(prim_type, vbo, NULL);
+ Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR);
+ if (wire_col) {
+ GWN_batch_uniform_4f(batch, "color", wire_col[0] / 255.0f, wire_col[1] / 255.0f, wire_col[2] / 255.0f, 1.0f);
+ }
+ GWN_batch_draw(batch);
+ GWN_batch_discard_all(batch);
+}
+
+/* convert dispList with elem indices to batch, only support triangles and quads
+ * XXX : This is a huge perf issue. We should cache the resulting batches inside the object instead.
+ * But new viewport will do it anyway
+ * TODO implement flat drawing */
+static void drawDispListElem(
+ bool quads, bool UNUSED(smooth), bool ndata_is_single,
+ const float *data, const float *ndata, unsigned int data_len,
+ const int *elem, unsigned int elem_len, const unsigned char wire_col[3])
+{
+ Gwn_VertFormat format = {0};
+ int i;
+ const int *idx = elem;
+ unsigned int pos_id, nor_id;
+
+ pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ if (ndata) {
+ if (ndata_is_single) {
+ /* pass */
+ }
+ else {
+ nor_id = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+ }
+
+ Gwn_IndexBufBuilder elb;
+ GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, (quads) ? elem_len * 2 : elem_len, 0xffffffff);
+
+ if (quads) {
+ for (i = elem_len; i; --i, idx += 4) {
+ GWN_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]);
+ GWN_indexbuf_add_tri_verts(&elb, idx[0], idx[2], idx[3]);
+ }
+ }
+ else {
+ for (i = elem_len; i; --i, idx += 3) {
+ GWN_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]);
+ }
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, data_len);
+
+ GWN_vertbuf_attr_fill(vbo, pos_id, data);
+
+ if (ndata) {
+ if (ndata_is_single) {
+ /* TODO: something like glNormal for a single value */
+ }
+ else {
+ GWN_vertbuf_attr_fill(vbo, nor_id, ndata);
+ }
+ }
+
+ Gwn_Batch *batch = GWN_batch_create(GWN_PRIM_TRIS, vbo, GWN_indexbuf_build(&elb));
+ Batch_set_builtin_program(batch, GPU_SHADER_SIMPLE_LIGHTING);
+ if (wire_col) {
+ GWN_batch_uniform_4f(batch, "color", wire_col[0] / 255.0f, wire_col[1] / 255.0f, wire_col[2] / 255.0f, 1.0f);
+ }
+ GWN_batch_uniform_4f(batch, "color", 0.8f, 0.8f, 0.8f, 1.0f);
+ GWN_batch_uniform_3f(batch, "light", 0.0f, 0.0f, 1.0f);
+ GWN_batch_draw(batch);
+ GWN_batch_discard_all(batch);
+}
/**
* \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)
+static bool drawDispListwire_ex(ListBase *dlbase, unsigned int dl_type_mask, const unsigned char wire_col[3])
{
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) {
@@ -4352,83 +5223,76 @@ static bool drawDispListwire_ex(ListBase *dlbase, unsigned int dl_type_mask)
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);
-
+ drawDispListVerts(GWN_PRIM_LINE_STRIP, data + (parts * dl->nr * 3), dl->nr, wire_col);
break;
- case DL_POLY:
-
- glVertexPointer(3, GL_FLOAT, 0, data);
+ case DL_POLY:
for (parts = 0; parts < dl->parts; parts++)
- glDrawArrays(GL_LINE_LOOP, parts * dl->nr, dl->nr);
-
+ drawDispListVerts(GWN_PRIM_LINE_LOOP, data + (parts * dl->nr * 3), dl->nr, wire_col);
break;
- case DL_SURF:
-
- glVertexPointer(3, GL_FLOAT, 0, data);
+ case DL_SURF:
for (parts = 0; parts < dl->parts; parts++) {
if (dl->flag & DL_CYCL_U)
- glDrawArrays(GL_LINE_LOOP, parts * dl->nr, dl->nr);
+ drawDispListVerts(GWN_PRIM_LINE_LOOP, data + (parts * dl->nr * 3), dl->nr, wire_col);
else
- glDrawArrays(GL_LINE_STRIP, parts * dl->nr, dl->nr);
+ drawDispListVerts(GWN_PRIM_LINE_STRIP, data + (parts * dl->nr * 3), dl->nr, wire_col);
}
+ float *data_aligned = MEM_mallocN(sizeof(float) * 3 * dl->parts, "aligned data");
for (int nr = 0; nr < dl->nr; nr++) {
int ofs = 3 * dl->nr;
+ int idx = 0;
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);
+ copy_v3_v3(data_aligned + idx, data);
data += ofs;
+ idx += 3;
}
- 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
+ if (dl->flag & DL_CYCL_V)
+ drawDispListVerts(GWN_PRIM_LINE_LOOP, data_aligned, dl->parts, wire_col);
+ else
+ drawDispListVerts(GWN_PRIM_LINE_STRIP, data_aligned, dl->parts, wire_col);
}
+
+ if (data_aligned)
+ MEM_freeN(data_aligned);
+
break;
case DL_INDEX3:
- glVertexPointer(3, GL_FLOAT, 0, dl->verts);
- glDrawElements(GL_TRIANGLES, 3 * dl->parts, GL_UNSIGNED_INT, dl->index);
+ drawDispListElem(
+ false, true, false,
+ dl->verts, NULL, dl->nr,
+ dl->index, dl->parts, wire_col);
break;
case DL_INDEX4:
- glVertexPointer(3, GL_FLOAT, 0, dl->verts);
- glDrawElements(GL_QUADS, 4 * dl->parts, GL_UNSIGNED_INT, dl->index);
+ drawDispListElem(
+ true, true, false,
+ dl->verts, NULL, dl->nr,
+ dl->index, dl->parts, wire_col);
break;
}
}
- glDisableClientState(GL_VERTEX_ARRAY);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
return false;
}
-static bool drawDispListwire(ListBase *dlbase, const short ob_type)
+static bool drawDispListwire(ListBase *dlbase, const short ob_type, const unsigned char wire_col[3])
{
unsigned int dl_mask = 0xffffffff;
@@ -4437,27 +5301,25 @@ static bool drawDispListwire(ListBase *dlbase, const short ob_type)
dl_mask &= ~((1 << DL_INDEX3) | (1 << DL_INDEX4));
}
- return drawDispListwire_ex(dlbase, dl_mask);
+ return drawDispListwire_ex(dlbase, dl_mask, wire_col);
}
static bool index3_nors_incr = true;
-static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
+static void drawDispListsolid(ListBase *lb, Object *ob, const short UNUSED(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;
+ //const float *ndata = dl->nors;
switch (dl->type) {
case DL_SEGM:
@@ -4467,15 +5329,7 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
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();
+ drawDispListVerts(GWN_PRIM_LINE_STRIP, data, dl->nr, ob_wire_col);
}
break;
case DL_POLY:
@@ -4485,14 +5339,7 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
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();
+ drawDispListVerts(GWN_PRIM_LINE_LOOP, data, dl->nr, ob_wire_col);
}
break;
case DL_SURF:
@@ -4502,15 +5349,12 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
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);
+ const unsigned int verts_len = dl->nr * dl->parts;
- 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);
+ drawDispListElem(
+ true, (dl->rt & CU_SMOOTH) != 0, false,
+ dl->verts, dl->nors, verts_len,
+ dl->index, dl->totindex, ob_wire_col);
}
break;
@@ -4520,8 +5364,7 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
col = dl->col;
}
- glVertexPointer(3, GL_FLOAT, 0, dl->verts);
-
+#if 0
/* for polys only one normal needed */
if (index3_nors_incr) {
glEnableClientState(GL_NORMAL_ARRAY);
@@ -4529,11 +5372,17 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
}
else
glNormal3fv(ndata);
+#endif
+ /* special case, 'nors' is a single value */
+ drawDispListElem(
+ false, (dl->rt & CU_SMOOTH) != 0, true,
+ dl->verts, dl->nors, dl->nr,
+ dl->index, dl->parts, ob_wire_col);
- glDrawElements(GL_TRIANGLES, 3 * dl->parts, GL_UNSIGNED_INT, dl->index);
-
+#if 0
if (index3_nors_incr)
glDisableClientState(GL_NORMAL_ARRAY);
+#endif
break;
@@ -4543,18 +5392,16 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
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);
+ drawDispListElem(
+ true, true, false,
+ dl->verts, dl->nors, dl->nr,
+ dl->index, dl->parts, ob_wire_col);
break;
}
dl = dl->next;
}
- glDisableClientState(GL_VERTEX_ARRAY);
glFrontFace(GL_CCW);
if (col != -1) {
@@ -4569,7 +5416,7 @@ static void drawCurveDMWired(Object *ob)
}
/* return true when nothing was drawn */
-static bool drawCurveDerivedMesh(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, const char dt)
+static bool drawCurveDerivedMesh(Scene *scene, SceneLayer *sl, View3D *v3d, RegionView3D *rv3d, BaseLegacy *base, const char dt)
{
Object *ob = base->object;
DerivedMesh *dm = ob->derivedFinal;
@@ -4583,8 +5430,8 @@ static bool drawCurveDerivedMesh(Scene *scene, View3D *v3d, RegionView3D *rv3d,
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);
+ bool glsl = draw_glsl_material(scene, sl, ob, v3d, dt);
+ GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, glsl, NULL);
if (!glsl)
dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind);
@@ -4605,7 +5452,7 @@ static bool drawCurveDerivedMesh(Scene *scene, View3D *v3d, RegionView3D *rv3d,
* Only called by #drawDispList
* \return true when nothing was drawn
*/
-static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
+static bool drawDispList_nobackface(Scene *scene, SceneLayer *sl, View3D *v3d, RegionView3D *rv3d, Base *base,
const char dt, const short dflag, const unsigned char ob_wire_col[4])
{
Object *ob = base->object;
@@ -4635,10 +5482,10 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3
if (!render_only) {
/* when we have faces, only draw loose-wire */
if (has_faces) {
- drawDispListwire_ex(lb, (1 << DL_SEGM));
+ drawDispListwire_ex(lb, (1 << DL_SEGM), ob_wire_col);
}
else {
- drawDispListwire(lb, ob->type);
+ drawDispListwire(lb, ob->type, ob_wire_col);
}
}
@@ -4646,26 +5493,26 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3
/* pass */
}
else {
- if (draw_glsl_material(scene, ob, v3d, dt)) {
- GPU_begin_object_materials(v3d, rv3d, scene, ob, 1, NULL);
+ if (draw_glsl_material(scene, sl, ob, v3d, dt)) {
+ GPU_begin_object_materials(v3d, rv3d, scene, sl, 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);
+ GPU_begin_object_materials(v3d, rv3d, scene, sl, 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);
+ unsigned char col[4] = {0, 0, 0, 0};
+ drawDispListwire(lb, ob->type, col);
}
}
index3_nors_incr = true;
}
else {
if (!render_only || BKE_displist_has_faces(lb)) {
- return drawDispListwire(lb, ob->type);
+ return drawDispListwire(lb, ob->type, ob_wire_col);
}
}
break;
@@ -4681,19 +5528,19 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3
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);
+ if (draw_glsl_material(scene, sl, ob, v3d, dt)) {
+ GPU_begin_object_materials(v3d, rv3d, scene, sl, 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);
+ GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, 0, NULL);
drawDispListsolid(lb, ob, dflag, ob_wire_col, false);
GPU_end_object_materials();
}
}
else {
- return drawDispListwire(lb, ob->type);
+ return drawDispListwire(lb, ob->type, ob_wire_col);
}
break;
case OB_MBALL:
@@ -4706,19 +5553,19 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3
if (solid) {
- if (draw_glsl_material(scene, ob, v3d, dt)) {
- GPU_begin_object_materials(v3d, rv3d, scene, ob, 1, NULL);
+ if (draw_glsl_material(scene, sl, ob, v3d, dt)) {
+ GPU_begin_object_materials(v3d, rv3d, scene, sl, 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);
+ GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, 0, NULL);
drawDispListsolid(lb, ob, dflag, ob_wire_col, false);
GPU_end_object_materials();
}
}
else {
- return drawDispListwire(lb, ob->type);
+ return drawDispListwire(lb, ob->type, ob_wire_col);
}
}
break;
@@ -4726,7 +5573,7 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3
return false;
}
-static bool drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
+static bool drawDispList(Scene *scene, SceneLayer *sl, View3D *v3d, RegionView3D *rv3d, Base *base,
const char dt, const short dflag, const unsigned char ob_wire_col[4])
{
bool retval;
@@ -4742,7 +5589,7 @@ static bool drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *ba
ensure_curve_cache(scene, base->object);
#endif
- if (drawCurveDerivedMesh(scene, v3d, rv3d, base, dt) == false) {
+ if (drawCurveDerivedMesh(scene, sl, v3d, rv3d, base, dt) == false) {
retval = false;
}
else {
@@ -4758,7 +5605,7 @@ static bool drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *ba
glFrontFace(mode);
- retval = drawDispList_nobackface(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
+ retval = drawDispList_nobackface(scene, sl, v3d, rv3d, base, dt, dflag, ob_wire_col);
if (mode != GL_CCW) {
glFrontFace(GL_CCW);
@@ -4773,16 +5620,63 @@ static bool drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *ba
}
/* *********** drawing for particles ************* */
-static void draw_particle_arrays(int draw_as, int totpoint, int ob_dt, int select)
+/* stride : offset size in bytes
+ * col[4] : the color to use when *color is NULL, can be also NULL */
+static void draw_vertex_array(Gwn_PrimType prim_type, const float *vert, const float *nor, const float *color, int stride, int vert_ct, float col[4])
+{
+ Gwn_VertFormat format = {0};
+ unsigned int pos_id, nor_id, col_id;
+ pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ if (nor) nor_id = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ if (color) col_id = GWN_vertformat_attr_add(&format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, vert_ct);
+
+ if (stride == 0) {
+ GWN_vertbuf_attr_fill(vbo, pos_id, vert);
+ if (nor) GWN_vertbuf_attr_fill(vbo, nor_id, nor);
+ if (color) GWN_vertbuf_attr_fill(vbo, col_id, color);
+ }
+ else {
+ GWN_vertbuf_attr_fill_stride(vbo, pos_id, stride, vert);
+ if (nor) GWN_vertbuf_attr_fill_stride(vbo, nor_id, stride, nor);
+ if (color) GWN_vertbuf_attr_fill_stride(vbo, col_id, stride, color);
+ }
+
+ Gwn_Batch *batch = GWN_batch_create(prim_type, vbo, NULL);
+ if (nor && color) {
+ Batch_set_builtin_program(batch, GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR);
+ GWN_batch_uniform_3f(batch, "light", 0.0f, 0.0f, 1.0f);
+ }
+ else if (nor) {
+ Batch_set_builtin_program(batch, GPU_SHADER_SIMPLE_LIGHTING);
+ GWN_batch_uniform_3f(batch, "light", 0.0f, 0.0f, 1.0f);
+ if (col) GWN_batch_uniform_4fv(batch, "color", col);
+ }
+ else if (color) {
+ Batch_set_builtin_program(batch, GPU_SHADER_3D_SMOOTH_COLOR);
+ }
+ else {
+ Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR);
+ if (col) GWN_batch_uniform_4fv(batch, "color", col);
+ }
+ GWN_batch_draw(batch);
+ GWN_batch_discard_all(batch);
+}
+
+static void draw_particle_arrays_new(int draw_as, int ob_dt, int select,
+ const float *vert, const float *nor, const float *color,
+ int totpoint, float col[4])
{
/* draw created data arrays */
switch (draw_as) {
case PART_DRAW_AXIS:
case PART_DRAW_CROSS:
- glDrawArrays(GL_LINES, 0, 6 * totpoint);
+ draw_vertex_array(GWN_PRIM_LINES, vert, nor, color, 0, 6 * totpoint, col);
break;
case PART_DRAW_LINE:
- glDrawArrays(GL_LINES, 0, 2 * totpoint);
+ draw_vertex_array(GWN_PRIM_LINES, vert, nor, color, 0, 2 * totpoint, col);
break;
case PART_DRAW_BB:
if (ob_dt <= OB_WIRE || select)
@@ -4790,15 +5684,16 @@ static void draw_particle_arrays(int draw_as, int totpoint, int ob_dt, int selec
else
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- glDrawArrays(GL_QUADS, 0, 4 * totpoint);
+ draw_vertex_array(GWN_PRIM_TRIS, vert, nor, color, 0, 6 * totpoint, col);
break;
default:
- glDrawArrays(GL_POINTS, 0, totpoint);
+ draw_vertex_array(GWN_PRIM_POINTS, vert, nor, color, 0, totpoint, col);
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 imat[4][4], const float draw_line[2], ParticleBillboardData *bb, ParticleDrawData *pdd,
+ unsigned int pos)
{
float vec[3], vec2[3];
float *vd = NULL;
@@ -4908,24 +5803,19 @@ static void draw_particle(ParticleKey *state, int draw_as, short draw, float pix
}
case PART_DRAW_CIRC:
{
- drawcircball(GL_LINE_LOOP, state->co, pixsize, imat);
+ imm_drawcircball(state->co, pixsize, imat, pos);
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);
-
+
+ /* First tri */
add_v3_v3v3(pdd->vd, bb_center, xvec);
add_v3_v3(pdd->vd, yvec); pdd->vd += 3;
@@ -4935,13 +5825,24 @@ static void draw_particle(ParticleKey *state, int draw_as, short draw, float pix
sub_v3_v3v3(pdd->vd, bb_center, xvec);
sub_v3_v3v3(pdd->vd, pdd->vd, yvec); pdd->vd += 3;
+ /* Second tri */
+ 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);
+ 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;
+ if (cd) {
+ for (int i = 0; i < 6; i++, cd += 3, pdd->cd += 3) {
+ copy_v3_v3(cd, ma_col);
+ }
+ }
+ for (int i = 0; i < 6; i++, pdd->nd += 3) {
+ copy_v3_v3(pdd->nd, zvec);
+ }
break;
}
}
@@ -4949,7 +5850,8 @@ static void draw_particle(ParticleKey *state, int draw_as, short draw, float pix
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)
+ const float ct, const float pa_size, const float r_tilt, const float pixsize_scale,
+ unsigned int pos)
{
ParticleSettings *part = psys->part;
float pixsize;
@@ -4980,7 +5882,7 @@ static void draw_particle_data(ParticleSystem *psys, RegionView3D *rv3d,
pixsize = ED_view3d_pixel_size(rv3d, state->co) * pixsize_scale;
- draw_particle(state, draw_as, part->draw, pixsize, imat, part->draw_line, bb, pdd);
+ draw_particle(state, draw_as, part->draw, pixsize, imat, part->draw_line, bb, pdd, pos);
}
/* unified drawing of all new particle systems draw types except dupli ob & group
* mostly tries to use vertex arrays for speed
@@ -5013,10 +5915,11 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
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;
+ bool select = (base->flag & BASE_SELECTED) != 0, create_cdata = false, need_v = false;
GLint polygonmode[2];
char numstr[32];
unsigned char tcol[4] = {0, 0, 0, 255};
+ unsigned int pos;
/* 1. */
if (part == NULL || !psys_check_enabled(ob, psys, G.is_rendering))
@@ -5078,16 +5981,12 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
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)) {
+ if ((ob->flag & OB_FROMGROUP) != 0) {
float mat[4][4];
mul_m4_m4m4(mat, ob->obmat, psys->imat);
- glMultMatrixf(mat);
+ gpuMultMatrix(mat);
}
/* needed for text display */
@@ -5115,7 +6014,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
copy_m4_m4(imat, rv3d->viewinv);
normalize_v3(imat[0]);
normalize_v3(imat[1]);
- /* fall-through */
+ ATTR_FALLTHROUGH;
case PART_DRAW_CROSS:
case PART_DRAW_AXIS:
/* lets calculate the scale: */
@@ -5207,7 +6106,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
tot_vec_size *= 2;
break;
case PART_DRAW_BB:
- tot_vec_size *= 4;
+ tot_vec_size *= 6; /* New OGL only understands tris, no choice here. */
create_ndata = 1;
break;
}
@@ -5261,6 +6160,11 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
totpoint = pdd->totpoint; /* draw data is up to date */
}
else {
+ if ((draw_as == PART_DRAW_CIRC) || (part->draw & PART_DRAW_SIZE)) {
+ pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ imm_cpack(0xFFFFFF);
+ }
for (a = 0, pa = pars; a < totpart + totchild; a++, pa++) {
/* setup per particle individual stuff */
if (a < totpart) {
@@ -5331,7 +6235,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
draw_particle_data(psys, rv3d,
&state, draw_as, imat, &bb, psys->pdd,
- ct, pa_size, r_tilt, pixsize_scale);
+ ct, pa_size, r_tilt, pixsize_scale, pos);
totpoint++;
drawn = 1;
@@ -5343,7 +6247,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
draw_particle_data(psys, rv3d,
&state, draw_as, imat, &bb, psys->pdd,
- pa_time, pa_size, r_tilt, pixsize_scale);
+ pa_time, pa_size, r_tilt, pixsize_scale, pos);
totpoint++;
drawn = 1;
@@ -5365,7 +6269,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
if (part->draw & PART_DRAW_SIZE) {
setlinestyle(3);
- drawcircball(GL_LINE_LOOP, state.co, pa_size, imat);
+ imm_drawcircball(state.co, pa_size, imat, pos);
setlinestyle(0);
}
@@ -5402,31 +6306,19 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
}
}
}
+ if ((draw_as == PART_DRAW_CIRC) || (part->draw & PART_DRAW_SIZE)) {
+ immUnbindProgram();
+ }
}
}
/* 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)
@@ -5437,41 +6329,28 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
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);
- }
- }
+ if (((dflag & DRAW_CONSTCOLOR) == 0) && (part->draw_col == PART_DRAW_COL_MAT)) {
+ draw_vertex_array(GWN_PRIM_LINE_STRIP, path->co, path->vel, path->col, sizeof(ParticleCacheKey), path->segments + 1, NULL);
+ }
+ else {
+ float color[4];
+ rgba_uchar_to_float(color, tcol);
+ draw_vertex_array(GWN_PRIM_LINE_STRIP, path->co, path->vel, NULL, sizeof(ParticleCacheKey), path->segments + 1, color);
}
-
- 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);
+ /* XXX use proper theme color here */
+ float color[4] = {0.58f, 0.67f, 1.0f, 1.0f};
+ draw_vertex_array(GWN_PRIM_LINE_STRIP, hkey->world_co, NULL, NULL, sizeof(HairKey), pa->totkey, color);
}
}
@@ -5479,30 +6358,36 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
MVert *mvert = hair_dm->getVertArray(hair_dm);
int i;
- glColor3f(0.9f, 0.4f, 0.4f);
-
- glBegin(GL_LINES);
+ unsigned int pos_id = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor3f(0.9f, 0.4f, 0.4f);
+
+ unsigned int count = 0;
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);
+ count += MAX2(pa->totkey - 1, 0);
+ }
+
+ if (count > 0) {
+ immBegin(GWN_PRIM_LINES, count * 2);
+ 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);
+
+ immVertex3fv(pos_id, v1);
+ immVertex3fv(pos_id, v2);
+ }
}
+ immEnd();
}
- glEnd();
+
+ immUnbindProgram();
}
-
- 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) {
@@ -5513,64 +6398,69 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
int *res = clmd->hair_grid_res;
int i;
- glDisableClientState(GL_NORMAL_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
-
+ unsigned int pos_id = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
if (select)
- UI_ThemeColor(TH_ACTIVE);
+ immUniformThemeColor(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]);
+ immUniformThemeColor(TH_WIRE);
+
+ immBegin(GWN_PRIM_LINES, 24);
+ immVertex3f(pos_id, gmin[0], gmin[1], gmin[2]); immVertex3f(pos_id, gmax[0], gmin[1], gmin[2]);
+ immVertex3f(pos_id, gmax[0], gmin[1], gmin[2]); immVertex3f(pos_id, gmax[0], gmax[1], gmin[2]);
+ immVertex3f(pos_id, gmax[0], gmax[1], gmin[2]); immVertex3f(pos_id, gmin[0], gmax[1], gmin[2]);
+ immVertex3f(pos_id, gmin[0], gmax[1], gmin[2]); immVertex3f(pos_id, 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]);
+ immVertex3f(pos_id, gmin[0], gmin[1], gmax[2]); immVertex3f(pos_id, gmax[0], gmin[1], gmax[2]);
+ immVertex3f(pos_id, gmax[0], gmin[1], gmax[2]); immVertex3f(pos_id, gmax[0], gmax[1], gmax[2]);
+ immVertex3f(pos_id, gmax[0], gmax[1], gmax[2]); immVertex3f(pos_id, gmin[0], gmax[1], gmax[2]);
+ immVertex3f(pos_id, gmin[0], gmax[1], gmax[2]); immVertex3f(pos_id, 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();
+ immVertex3f(pos_id, gmin[0], gmin[1], gmin[2]); immVertex3f(pos_id, gmin[0], gmin[1], gmax[2]);
+ immVertex3f(pos_id, gmax[0], gmin[1], gmin[2]); immVertex3f(pos_id, gmax[0], gmin[1], gmax[2]);
+ immVertex3f(pos_id, gmin[0], gmax[1], gmin[2]); immVertex3f(pos_id, gmin[0], gmax[1], gmax[2]);
+ immVertex3f(pos_id, gmax[0], gmax[1], gmin[2]); immVertex3f(pos_id, gmax[0], gmax[1], gmax[2]);
+ immEnd();
if (select)
- UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -100);
+ immUniformThemeColorShadeAlpha(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);
+ immUniformThemeColorShadeAlpha(TH_WIRE, 0, -100);
+
+ int count = 0;
+ count += MAX2(0, res[0] - 2) * 8;
+ count += MAX2(0, res[1] - 2) * 8;
+ count += MAX2(0, res[2] - 2) * 8;
+
+ if (count >= 2) {
+ glEnable(GL_BLEND);
+ immBegin(GWN_PRIM_LINES, count);
+ for (i = 1; i < res[0] - 1; ++i) {
+ float f = interpf(gmax[0], gmin[0], (float)i / (float)(res[0] - 1));
+ immVertex3f(pos_id, f, gmin[1], gmin[2]); immVertex3f(pos_id, f, gmax[1], gmin[2]);
+ immVertex3f(pos_id, f, gmax[1], gmin[2]); immVertex3f(pos_id, f, gmax[1], gmax[2]);
+ immVertex3f(pos_id, f, gmax[1], gmax[2]); immVertex3f(pos_id, f, gmin[1], gmax[2]);
+ immVertex3f(pos_id, f, gmin[1], gmax[2]); immVertex3f(pos_id, 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));
+ immVertex3f(pos_id, gmin[0], f, gmin[2]); immVertex3f(pos_id, gmax[0], f, gmin[2]);
+ immVertex3f(pos_id, gmax[0], f, gmin[2]); immVertex3f(pos_id, gmax[0], f, gmax[2]);
+ immVertex3f(pos_id, gmax[0], f, gmax[2]); immVertex3f(pos_id, gmin[0], f, gmax[2]);
+ immVertex3f(pos_id, gmin[0], f, gmax[2]); immVertex3f(pos_id, 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));
+ immVertex3f(pos_id, gmin[0], gmin[1], f); immVertex3f(pos_id, gmax[0], gmin[1], f);
+ immVertex3f(pos_id, gmax[0], gmin[1], f); immVertex3f(pos_id, gmax[0], gmax[1], f);
+ immVertex3f(pos_id, gmax[0], gmax[1], f); immVertex3f(pos_id, gmin[0], gmax[1], f);
+ immVertex3f(pos_id, gmin[0], gmax[1], f); immVertex3f(pos_id, gmin[0], gmin[1], f);
+ }
+ immEnd();
+ glDisable(GL_BLEND);
}
- 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);
+
+ immUnbindProgram();
}
}
}
@@ -5579,27 +6469,17 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
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);
- }
- }
+ if (((dflag & DRAW_CONSTCOLOR) == 0) && (part->draw_col == PART_DRAW_COL_MAT)) {
+ draw_vertex_array(GWN_PRIM_LINE_STRIP, path->co, path->vel, path->col, sizeof(ParticleCacheKey), path->segments + 1, NULL);
+ }
+ else {
+ float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ draw_vertex_array(GWN_PRIM_LINE_STRIP, path->co, path->vel, NULL, sizeof(ParticleCacheKey), path->segments + 1, color);
}
-
- 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;
@@ -5619,19 +6499,11 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
}
}
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);
+ float color[4];
+ UI_GetThemeColor4fv(TH_ACTIVE, color);
if (part->draw_size)
glPointSize(part->draw_size + 2);
@@ -5640,48 +6512,39 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
glLineWidth(3.0);
- draw_particle_arrays(draw_as, totpoint, ob_dt, 1);
+ draw_particle_arrays_new(draw_as, ob_dt, 1, pdd->vdata, NULL, NULL, totpoint, color);
}
- /* restore from select */
- glColor3fv(ma_col);
- }
-
- glPointSize(part->draw_size ? part->draw_size : 2.0);
- glLineWidth(1.0);
-
- /* enable other data arrays */
+ glPointSize(part->draw_size ? part->draw_size : 2.0);
+ glLineWidth(1.0);
- /* 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);
+#if 0
+ /* enable other data arrays */
+ /* billboards are drawn this way */
+ if (pdd->ndata && ob_dt > OB_WIRE) {
+ 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);
+ }
}
+#endif
+
+ draw_particle_arrays_new(draw_as, ob_dt, 0, pdd->vdata, pdd->ndata, pdd->cdata, totpoint, NULL);
}
- 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);
+ float color[4] = {0.75f, 0.75f, 0.75f, 1.0f};
+ draw_vertex_array(GWN_PRIM_LINES, pdd->vedata, NULL, NULL, 0, 2 * totve, color);
}
glPolygonMode(GL_FRONT, polygonmode[0]);
@@ -5690,9 +6553,6 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
/* 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);
@@ -5715,15 +6575,15 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
pdd->ma_col = NULL;
}
- if ((base->flag & OB_FROMDUPLI) && (ob->flag & OB_FROMGROUP)) {
- glLoadMatrixf(rv3d->viewmat);
+ if ((ob->flag & OB_FROMGROUP) != 0) {
+ gpuLoadMatrix(rv3d->viewmat);
}
}
-static void draw_update_ptcache_edit(Scene *scene, Object *ob, PTCacheEdit *edit)
+static void draw_update_ptcache_edit(Scene *scene, SceneLayer *sl, Object *ob, PTCacheEdit *edit)
{
if (edit->psys && edit->psys->flag & PSYS_HAIR_UPDATED)
- PE_update_object(scene, ob, 0);
+ PE_update_object(scene, sl, ob, 0);
/* create path and child path cache if it doesn't exist already */
if (edit->pathcache == NULL)
@@ -5732,15 +6592,9 @@ static void draw_update_ptcache_edit(Scene *scene, Object *ob, PTCacheEdit *edit
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;
+ const int totpoint = edit->totpoint;
+ const bool timed = (pset->flag & PE_FADE_TIME) ? pset->fade_frames : false;
if (edit->pathcache == NULL)
return;
@@ -5752,50 +6606,71 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
glDisable(GL_DEPTH_TEST);
/* get selection theme colors */
+ float sel_col[3], nosel_col[3];
UI_GetThemeColor3fv(TH_VERTEX_SELECT, sel_col);
UI_GetThemeColor3fv(TH_VERTEX, nosel_col);
/* draw paths */
- totkeys = (*edit->pathcache)->segments + 1;
+ const int totkeys = (*edit->pathcache)->segments + 1;
glEnable(GL_BLEND);
- pathcol = MEM_callocN(totkeys * 4 * sizeof(float), "particle path color data");
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_COLOR_ARRAY);
+ float *pathcol = MEM_callocN(totkeys * 4 * sizeof(float), "particle path color data");
if (pset->brushtype == PE_BRUSH_WEIGHT)
glLineWidth(2.0f);
- cache = edit->pathcache;
+ ParticleCacheKey **cache = edit->pathcache;
+ PTCacheEditPoint *point;
+ int i;
+
for (i = 0, point = edit->points; i < totpoint; i++, point++) {
- path = cache[i];
- glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co);
+ ParticleCacheKey *path = cache[i];
+
+ Gwn_VertFormat format = {0};
+ unsigned int pos_id, col_id, col_comp;
+
+ col_comp = ((point->flag & PEP_HIDE) || timed) ? 4 : 3;
+
+ pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ col_id = GWN_vertformat_attr_add(&format, "color", GWN_COMP_F32, col_comp, GWN_FETCH_FLOAT);
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, path->segments + 1);
+
+ GWN_vertbuf_attr_fill_stride(vbo, pos_id, sizeof(ParticleCacheKey), path->co);
+
+ float *pcol = pathcol;
if (point->flag & PEP_HIDE) {
- for (k = 0, pcol = pathcol; k < totkeys; k++, pcol += 4) {
+ for (int k = 0; k < totkeys; k++, pcol += 4) {
copy_v3_v3(pcol, path->col);
pcol[3] = 0.25f;
}
- glColorPointer(4, GL_FLOAT, 4 * sizeof(float), pathcol);
+ GWN_vertbuf_attr_fill(vbo, col_id, pathcol);
}
else if (timed) {
- for (k = 0, pcol = pathcol, pkey = path; k < totkeys; k++, pkey++, pcol += 4) {
+ ParticleCacheKey *pkey = path;
+ for (int k = 0; 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);
+ GWN_vertbuf_attr_fill(vbo, col_id, pathcol);
+ }
+ else {
+ /* FIXME: shader wants 4 color components but the cache only contains ParticleCacheKey
+ * So alpha is random */
+ GWN_vertbuf_attr_fill_stride(vbo, col_id, sizeof(ParticleCacheKey), path->col);
}
- else
- glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
- glDrawArrays(GL_LINE_STRIP, 0, path->segments + 1);
+ Gwn_Batch *batch = GWN_batch_create(GWN_PRIM_LINE_STRIP, vbo, NULL);
+ Batch_set_builtin_program(batch, GPU_SHADER_3D_SMOOTH_COLOR);
+ GWN_batch_draw(batch);
+ GWN_batch_discard_all(batch);
}
- if (pathcol) { MEM_freeN(pathcol); pathcol = pcol = NULL; }
-
+ if (pathcol) { MEM_freeN(pathcol); pathcol = NULL; }
/* draw edit vertices */
if (pset->selectmode != SCE_SELECT_PATH) {
@@ -5806,6 +6681,10 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
float *cd = NULL, *cdata = NULL;
int totkeys_visible = 0;
+ Gwn_VertFormat format = {0};
+ unsigned int pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ unsigned int col_id = GWN_vertformat_attr_add(&format, "color", GWN_COMP_F32, (timed ? 4 : 3), GWN_FETCH_FLOAT);
+
for (i = 0, point = edit->points; i < totpoint; i++, point++)
if (!(point->flag & PEP_HIDE))
totkeys_visible += point->totkey;
@@ -5820,7 +6699,8 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
if (point->flag & PEP_HIDE)
continue;
- for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
+ PTCacheEditKey *key = point->keys;
+ for (int k = 0; k < point->totkey; k++, key++) {
if (pd) {
copy_v3_v3(pd, key->co);
pd += 3;
@@ -5845,14 +6725,20 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
if (point->flag & PEP_HIDE || point->totkey == 0)
continue;
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, point->totkey);
+
if (point->keys->flag & PEK_USE_WCO)
- glVertexPointer(3, GL_FLOAT, sizeof(PTCacheEditKey), point->keys->world_co);
+ GWN_vertbuf_attr_fill_stride(vbo, pos_id, sizeof(PTCacheEditKey), point->keys->world_co);
else
- glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), pd);
+ GWN_vertbuf_attr_fill(vbo, pos_id, pd);
- glColorPointer((timed ? 4 : 3), GL_FLOAT, (timed ? 4 : 3) * sizeof(float), cd);
+ GWN_vertbuf_attr_fill(vbo, col_id, cd);
- glDrawArrays(GL_POINTS, 0, point->totkey);
+ Gwn_Batch *batch = GWN_batch_create(GWN_PRIM_POINTS, vbo, NULL);
+ Batch_set_builtin_program(batch, GPU_SHADER_3D_SMOOTH_COLOR);
+ GWN_batch_draw(batch);
+ GWN_batch_discard_all(batch);
pd += pd ? 3 * point->totkey : 0;
cd += (timed ? 4 : 3) * point->totkey;
@@ -5861,23 +6747,30 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
if (cdata) { MEM_freeN(cdata); cd = cdata = NULL; }
}
else if (pset->selectmode == SCE_SELECT_END) {
- glBegin(GL_POINTS);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos_id = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ unsigned int col_id = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
+ immBeginAtMost(GWN_PRIM_POINTS, totpoint);
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);
+ PTCacheEditKey *key = point->keys + point->totkey - 1;
+ if ((key->flag & PEK_SELECT) != 0) {
+ immAttrib3fv(col_id, sel_col);
+ }
+ else {
+ immAttrib3fv(col_id, 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);
+ immVertex3fv(pos_id, (key->flag & PEK_USE_WCO) ? key->world_co : key->co);
}
}
- glEnd();
+ immEnd();
+ immUnbindProgram();
}
}
glDisable(GL_BLEND);
- glDisableClientState(GL_COLOR_ARRAY);
- glDisableClientState(GL_NORMAL_ARRAY);
- glDisableClientState(GL_VERTEX_ARRAY);
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
}
@@ -5890,130 +6783,137 @@ static void ob_draw_RE_motion(float com[3], float rotscale[3][3], float itw, flo
float tw = itw * drw_size;
float th = ith * drw_size;
- glBegin(GL_LINES);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ unsigned int col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
+
+ immBegin(GWN_PRIM_LINES, 30);
- glColor4ub(0x7F, 0x00, 0x00, 155);
+ immAttrib4ub(col, 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);
+ immVertex3fv(pos, root);
tip[1] = tip[2] = 0.0f;
tip[0] = drw_size;
mul_m3_v3(tr, tip);
add_v3_v3(tip, com);
- glVertex3fv(tip);
+ immVertex3fv(pos, 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);
+ immVertex3fv(pos, root);
+ immVertex3fv(pos, 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);
+ immVertex3fv(pos, root);
+ immVertex3fv(pos, 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);
+ immVertex3fv(pos, root);
+ immVertex3fv(pos, 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);
+ immVertex3fv(pos, root);
+ immVertex3fv(pos, tip);
- glColor4ub(0x00, 0x7F, 0x00, 155);
+ immAttrib4ub(col, 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);
+ immVertex3fv(pos, root);
tip[0] = tip[2] = 0.0f;
tip[1] = drw_size;
mul_m3_v3(tr, tip);
add_v3_v3(tip, com);
- glVertex3fv(tip);
+ immVertex3fv(pos, 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);
+ immVertex3fv(pos, root);
+ immVertex3fv(pos, 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);
+ immVertex3fv(pos, root);
+ immVertex3fv(pos, 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);
+ immVertex3fv(pos, root);
+ immVertex3fv(pos, 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);
+ immVertex3fv(pos, root);
+ immVertex3fv(pos, tip);
- glColor4ub(0x00, 0x00, 0x7F, 155);
+ immAttrib4ub(col, 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);
+ immVertex3fv(pos, root);
tip[0] = tip[1] = 0.0f;
tip[2] = drw_size;
mul_m3_v3(tr, tip);
add_v3_v3(tip, com);
- glVertex3fv(tip);
+ immVertex3fv(pos, 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);
+ immVertex3fv(pos, root);
+ immVertex3fv(pos, 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);
+ immVertex3fv(pos, root);
+ immVertex3fv(pos, 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);
+ immVertex3fv(pos, root);
+ immVertex3fv(pos, 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);
+ immVertex3fv(pos, root);
+ immVertex3fv(pos, tip);
- glEnd();
+ immEnd();
+
+ immUnbindProgram();
}
/* place to add drawers */
@@ -6022,7 +6922,7 @@ static void drawhandlesN(Nurb *nu, const char sel, const bool hide_handles)
{
if (nu->hide || hide_handles) return;
- if (nu->type == CU_BEZIER) {
+ if (nu->type == CU_BEZIER && nu->pntsu > 0) {
const float *fp;
@@ -6035,9 +6935,14 @@ static void drawhandlesN(Nurb *nu, const char sel, const bool hide_handles)
UI_GetThemeColor3ubv(basecol + a, handle_cols[a]);
}
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ unsigned int col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
+
glLineWidth(1.0f);
- glBegin(GL_LINES);
+ immBeginAtMost(GWN_PRIM_LINES, nu->pntsu * 4);
BezTriple *bezt = nu->bezt;
int a = nu->pntsu;
@@ -6046,33 +6951,35 @@ static void drawhandlesN(Nurb *nu, const char sel, const bool hide_handles)
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);
+ immAttrib3ubv(col, handle_cols[MIN2(bezt->h1, TH_HANDLE_COL_TOT - 1)]);
+ immVertex3fv(pos, fp);
+ immVertex3fv(pos, fp + 3);
- glColor3ubv(handle_cols[MIN2(bezt->h2, TH_HANDLE_COL_TOT - 1)]);
- glVertex3fv(fp + 3);
- glVertex3fv(fp + 6);
+ immAttrib3ubv(col, handle_cols[MIN2(bezt->h2, TH_HANDLE_COL_TOT - 1)]);
+ immVertex3fv(pos, fp + 3);
+ immVertex3fv(pos, 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);
+ immAttrib3ubv(col, handle_cols[MIN2(bezt->h1, TH_HANDLE_COL_TOT - 1)]);
+ immVertex3fv(pos, fp);
+ immVertex3fv(pos, 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);
+ immAttrib3ubv(col, handle_cols[MIN2(bezt->h2, TH_HANDLE_COL_TOT - 1)]);
+ immVertex3fv(pos, fp);
+ immVertex3fv(pos, fp + 3);
}
}
bezt++;
}
- glEnd();
+ immEnd();
+
+ immUnbindProgram();
#undef TH_HANDLE_COL_TOT
@@ -6083,153 +6990,196 @@ 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 && nu->pntsu > 0) {
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformThemeColor(TH_ACTIVE_SPLINE);
+ glLineWidth(2.0f);
- if (nu->type == CU_BEZIER) {
+ immBeginAtMost(GWN_PRIM_LINES, nu->pntsu * 4);
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);
+ immVertex3fv(pos, fp);
+ immVertex3fv(pos, fp + 3);
- glVertex3fv(fp + 3);
- glVertex3fv(fp + 6);
+ immVertex3fv(pos, fp + 3);
+ immVertex3fv(pos, fp + 6);
}
bezt++;
}
+ immEnd();
+ immUnbindProgram();
}
- glEnd();
-
- glColor3ub(0, 0, 0);
}
-static void drawvertsN(Nurb *nu, const char sel, const bool hide_handles, const void *vert)
+static void drawvertsN(const Nurb *nurb, const bool hide_handles, const void *vert)
{
- if (nu->hide) return;
+ const Nurb *nu;
- const int color = sel ? TH_VERTEX_SELECT : TH_VERTEX;
+ // just quick guesstimate of how many verts to draw
+ int count = 0;
+ for (nu = nurb; nu; nu = nu->next) {
+ if (!nu->hide) {
+ if (nu->type == CU_BEZIER) {
+ count += nu->pntsu * 3;
+ }
+ else {
+ count += nu->pntsu * nu->pntsv;
+ }
+ }
+ }
+ if (count == 0) return;
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
- UI_ThemeColor(color);
+ unsigned char vert_color[3];
+ unsigned char vert_color_select[3];
+ unsigned char vert_color_active[3];
+ UI_GetThemeColor3ubv(TH_VERTEX, vert_color);
+ UI_GetThemeColor3ubv(TH_VERTEX_SELECT, vert_color_select);
+ UI_GetThemeColor3ubv(TH_ACTIVE_VERT, vert_color_active);
glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
+
+ immBeginAtMost(GWN_PRIM_POINTS, count);
- glBegin(GL_POINTS);
-
- if (nu->type == CU_BEZIER) {
+ for (nu = nurb; nu; nu = nu->next) {
- 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 (nu->hide) continue;
- 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]);
- }
+ if (nu->type == CU_BEZIER) {
- 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]);
+ const BezTriple *bezt = nu->bezt;
+ int a = nu->pntsu;
+ while (a--) {
+ if (bezt->hide == 0) {
+ if (bezt == vert) {
+ immAttrib3ubv(color, bezt->f2 & SELECT ? vert_color_active : vert_color);
+ immVertex3fv(pos, bezt->vec[1]);
+ if (!hide_handles) {
+ immAttrib3ubv(color, bezt->f1 & SELECT ? vert_color_active : vert_color);
+ immVertex3fv(pos, bezt->vec[0]);
+ immAttrib3ubv(color, bezt->f3 & SELECT ? vert_color_active : vert_color);
+ immVertex3fv(pos, bezt->vec[2]);
+ }
+ }
+ else {
+ immAttrib3ubv(color, bezt->f2 & SELECT ? vert_color_select : vert_color);
+ immVertex3fv(pos, bezt->vec[1]);
+ if (!hide_handles) {
+ immAttrib3ubv(color, bezt->f1 & SELECT ? vert_color_select : vert_color);
+ immVertex3fv(pos, bezt->vec[0]);
+ immAttrib3ubv(color, bezt->f3 & SELECT ? vert_color_select : vert_color);
+ immVertex3fv(pos, bezt->vec[2]);
+ }
+ }
}
+ bezt++;
}
- 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);
+ else {
+ const BPoint *bp = nu->bp;
+ int a = nu->pntsu * nu->pntsv;
+ while (a--) {
+ if (bp->hide == 0) {
+ if (bp == vert) {
+ immAttrib3ubv(color, vert_color_active);
+ }
+ else {
+ immAttrib3ubv(color, bp->f1 & SELECT ? vert_color_select : vert_color);
+ }
+ immVertex3fv(pos, bp->vec);
}
+ bp++;
}
- bp++;
}
}
-
- glEnd();
+
+ immEnd();
+ immUnbindProgram();
}
static void editnurb_draw_active_poly(Nurb *nu)
{
- UI_ThemeColor(TH_ACTIVE_SPLINE);
- glLineWidth(2);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformThemeColor(TH_ACTIVE_SPLINE);
+
+ glLineWidth(2.0f);
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);
+ if (nu->pntsu >= 2) {
+ if (nu->flagu & 1) immBegin(GWN_PRIM_LINE_LOOP, nu->pntsu);
+ else immBegin(GWN_PRIM_LINE_STRIP, nu->pntsu);
- for (int a = 0; a < nu->pntsu; a++, bp++) {
- glVertex3fv(bp->vec);
- }
+ for (int a = 0; a < nu->pntsu; a++, bp++) {
+ immVertex3fv(pos, bp->vec);
+ }
- glEnd();
+ immEnd();
+ }
}
- glColor3ub(0, 0, 0);
+ immUnbindProgram();
}
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++;
+ if (nu->pntsv > 0) {
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformThemeColor(TH_ACTIVE_SPLINE);
- 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;
- }
- }
+ glLineWidth(2.0f);
+ // just quick guesstimate of how many verts to draw
+ int count = (nu->pntsu - 1) * nu->pntsv * 2;
+ if (nu->pntsv > 1) count += (nu->pntsv - 1) * nu->pntsu * 2;
+ if (count < 2) return;
- if (nu->pntsv > 1) { /* surface */
+ immBeginAtMost(GWN_PRIM_LINES, count);
+ BPoint *bp = nu->bp;
+ for (int b = 0; b < nu->pntsv; b++) {
+ BPoint *bp1 = bp;
+ bp++;
- 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) {
+ for (int a = nu->pntsu - 1; a > 0; a--, bp++) {
if (bp->hide == 0 && bp1->hide == 0) {
- glVertex3fv(bp->vec);
- glVertex3fv(bp1->vec);
+ immVertex3fv(pos, bp->vec);
+ immVertex3fv(pos, bp1->vec);
}
bp1 = bp;
}
}
- }
- glEnd();
+ 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) {
+ immVertex3fv(pos, bp->vec);
+ immVertex3fv(pos, bp1->vec);
+ }
+ bp1 = bp;
+ }
+ }
+ }
+
+ immEnd();
- glColor3ub(0, 0, 0);
+ immUnbindProgram();
+ }
}
static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel)
@@ -6237,6 +7187,9 @@ static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel)
BPoint *bp, *bp1;
int a, b;
Curve *cu = ob->data;
+ Gwn_VertFormat *format;
+ unsigned int pos, col;
+ unsigned char color[3];
int index = 0;
Nurb *nu = nurb;
@@ -6244,35 +7197,55 @@ static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel)
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);
+ format = immVertexFormat();
+ pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
- UI_ThemeColor(TH_NURB_ULINE);
+ glLineWidth(1.0f);
+
+ immUniformThemeColor(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);
+ if (nu->pntsu >= 2) {
+ if (nu->flagu & 1) immBegin(GWN_PRIM_LINE_LOOP, nu->pntsu);
+ else immBegin(GWN_PRIM_LINE_STRIP, nu->pntsu);
- for (a = 0; a < nu->pntsu; a++, bp++) {
- glVertex3fv(bp->vec);
- }
+ for (a = 0; a < nu->pntsu; a++, bp++) {
+ immVertex3fv(pos, bp->vec);
+ }
- glEnd();
+ immEnd();
+ }
}
+ immUnbindProgram();
break;
+ }
case CU_NURBS:
+ {
if (!sel && index == cu->actnu) {
/* we should draw active spline highlight below everything */
editnurb_draw_active_nurbs(nu);
}
- glLineWidth(1);
+ format = immVertexFormat();
+ pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
+
+ // just quick guesstimate of how many verts to draw
+ int count = (nu->pntsu - 1) * nu->pntsv * 2;
+ if (nu->pntsv > 1) count += (nu->pntsv - 1) * nu->pntsu * 2;
+ if (count < 2) return;
+
+ glLineWidth(1.0f);
- glBegin(GL_LINES);
+ immBeginAtMost(GWN_PRIM_LINES, count);
bp = nu->bp;
for (b = 0; b < nu->pntsv; b++) {
@@ -6282,10 +7255,10 @@ static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel)
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);
+ UI_GetThemeColor3ubv(TH_NURB_SEL_ULINE, color);
+ immAttrib3ubv(col, color);
+ immVertex3fv(pos, bp->vec);
+ immVertex3fv(pos, bp1->vec);
}
}
else {
@@ -6293,10 +7266,10 @@ static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel)
/* pass */
}
else {
- UI_ThemeColor(TH_NURB_ULINE);
-
- glVertex3fv(bp->vec);
- glVertex3fv(bp1->vec);
+ UI_GetThemeColor3ubv(TH_NURB_ULINE, color);
+ immAttrib3ubv(col, color);
+ immVertex3fv(pos, bp->vec);
+ immVertex3fv(pos, bp1->vec);
}
}
}
@@ -6313,10 +7286,10 @@ static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel)
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);
+ UI_GetThemeColor3ubv(TH_NURB_SEL_VLINE, color);
+ immAttrib3ubv(col, color);
+ immVertex3fv(pos, bp->vec);
+ immVertex3fv(pos, bp1->vec);
}
}
else {
@@ -6324,10 +7297,10 @@ static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel)
/* pass */
}
else {
- UI_ThemeColor(TH_NURB_VLINE);
-
- glVertex3fv(bp->vec);
- glVertex3fv(bp1->vec);
+ UI_GetThemeColor3ubv(TH_NURB_VLINE, color);
+ immAttrib3ubv(col, color);
+ immVertex3fv(pos, bp->vec);
+ immVertex3fv(pos, bp1->vec);
}
}
}
@@ -6335,9 +7308,10 @@ static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel)
}
}
}
-
- glEnd();
+ immEnd();
+ immUnbindProgram();
break;
+ }
}
}
@@ -6347,8 +7321,8 @@ static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel)
}
static void draw_editnurb(
- Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, Nurb *nurb,
- const char dt, const short dflag, const unsigned char ob_wire_col[4])
+ Scene *scene, SceneLayer *sl, View3D *v3d, RegionView3D *rv3d, Base *base, Nurb *nurb,
+ const char dt, const short dflag, const unsigned char UNUSED(ob_wire_col[4]))
{
ToolSettings *ts = scene->toolsettings;
Object *ob = base->object;
@@ -6360,9 +7334,8 @@ static void draw_editnurb(
/* DispList */
UI_GetThemeColor3ubv(TH_WIRE_EDIT, wire_col);
- glColor3ubv(wire_col);
- drawDispList(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
+ drawDispList(scene, sl, v3d, rv3d, base, dt, dflag, wire_col);
/* for shadows only show solid faces */
if (v3d->flag2 & V3D_RENDER_SHADOW)
@@ -6386,103 +7359,131 @@ static void draw_editnurb(
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;
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformThemeColor(TH_WIRE_EDIT);
+
glLineWidth(1.0f);
+
+ int count = 0;
+ int count_used = 0;
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;
-
+
+#if 0
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 */
+ count += 4;
+ nr -= skip;
+ }
+#else
+ /* Same as loop above */
+ count += 4 * max_ii((nr + max_ii(skip - 1, 0)) / (skip + 1), 0);
+#endif
+ }
- vec_a[0] = fac;
- vec_a[1] = 0.0f;
- vec_a[2] = 0.0f;
+ if (count > 2) {
+ immBegin(GWN_PRIM_LINES, count);
+ 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;
- vec_b[0] = -fac;
- vec_b[1] = 0.0f;
- vec_b[2] = 0.0f;
-
- mul_qt_v3(bevp->quat, vec_a);
- mul_qt_v3(bevp->quat, vec_b);
- add_v3_v3(vec_a, bevp->vec);
- add_v3_v3(vec_b, bevp->vec);
-
- madd_v3_v3fl(vec_a, bevp->dir, -fac);
- madd_v3_v3fl(vec_b, bevp->dir, -fac);
-
- glBegin(GL_LINE_STRIP);
- glVertex3fv(vec_a);
- glVertex3fv(bevp->vec);
- glVertex3fv(vec_b);
- glEnd();
-
- bevp += skip + 1;
- nr -= skip;
+ 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);
+
+ immVertex3fv(pos, vec_a);
+ immVertex3fv(pos, bevp->vec);
+ immVertex3fv(pos, bevp->vec);
+ immVertex3fv(pos, vec_b);
+
+ bevp += skip + 1;
+ nr -= skip;
+ count_used += 4;
+ }
}
+ BLI_assert(count == count_used);
+ UNUSED_VARS_NDEBUG(count_used);
+
+ immEnd();
}
+ immUnbindProgram();
}
- 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);
+ if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
+
+ drawvertsN(nurb, hide_handles, vert);
+
+ if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
}
static void draw_editfont_textcurs(RegionView3D *rv3d, float textcurs[4][2])
{
- cpack(0);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
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();
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ imm_cpack(0);
+ immBegin(GWN_PRIM_TRI_FAN, 4);
+ immVertex2fv(pos, textcurs[0]);
+ immVertex2fv(pos, textcurs[1]);
+ immVertex2fv(pos, textcurs[2]);
+ immVertex2fv(pos, textcurs[3]);
+ immEnd();
set_inverted_drawing(0);
ED_view3d_polygon_offset(rv3d, 0.0);
+ immUnbindProgram();
}
-static void draw_editfont(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
+static void draw_editfont(Scene *scene, SceneLayer *sl, 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];
- int selstart, selend;
draw_editfont_textcurs(rv3d, ef->textcurs);
if (cu->flag & CU_FAST) {
- cpack(0xFFFFFF);
+ imm_cpack(0xFFFFFF);
set_inverted_drawing(1);
- drawDispList(scene, v3d, rv3d, base, OB_WIRE, dflag, ob_wire_col);
+ drawDispList(scene, sl, v3d, rv3d, base, OB_WIRE, dflag, ob_wire_col);
set_inverted_drawing(0);
}
else {
- drawDispList(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
+ drawDispList(scene, sl, v3d, rv3d, base, dt, dflag, ob_wire_col);
}
if (cu->linewidth != 0.0f) {
- UI_ThemeColor(TH_WIRE_EDIT);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColor(TH_WIRE_EDIT);
copy_v3_v3(vec1, ob->orig);
copy_v3_v3(vec2, ob->orig);
vec1[0] += cu->linewidth;
@@ -6490,47 +7491,52 @@ static void draw_editfont(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *b
vec1[1] += cu->linedist * cu->fsize;
vec2[1] -= cu->lines * cu->linedist * cu->fsize;
setlinestyle(3);
- glBegin(GL_LINES);
- glVertex2fv(vec1);
- glVertex2fv(vec2);
- glEnd();
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2fv(pos, vec1);
+ immVertex2fv(pos, vec2);
+ immEnd();
setlinestyle(0);
+ immUnbindProgram();
}
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);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformThemeColor(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);
+ immBegin(GWN_PRIM_LINE_STRIP, 5);
+ immVertex3fv(pos, vec1);
vec1[0] += cu->tb[i].w;
- glVertex3fv(vec1);
+ immVertex3fv(pos, vec1);
vec1[1] -= cu->tb[i].h;
- glVertex3fv(vec1);
+ immVertex3fv(pos, vec1);
vec1[0] -= cu->tb[i].w;
- glVertex3fv(vec1);
+ immVertex3fv(pos, vec1);
vec1[1] += cu->tb[i].h;
- glVertex3fv(vec1);
- glEnd();
+ immVertex3fv(pos, vec1);
+ immEnd();
+ immUnbindProgram();
}
}
setlinestyle(0);
- if (BKE_vfont_select_get(ob, &selstart, &selend) && ef->selboxes) {
- const int seltot = selend - selstart;
+ if (ef->selboxes && ef->selboxes_len) {
float selboxw;
- cpack(0xffffff);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ imm_cpack(0xffffff);
set_inverted_drawing(1);
- for (int i = 0; i <= seltot; i++) {
+ for (int i = 0; i < ef->selboxes_len; i++) {
EditFontSelBox *sb = &ef->selboxes[i];
float tvec[3];
- if (i != seltot) {
+ if (i + 1 != ef->selboxes_len) {
if (ef->selboxes[i + 1].y == sb->y)
selboxw = ef->selboxes[i + 1].x - sb->x;
else
@@ -6543,20 +7549,20 @@ static void draw_editfont(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *b
/* fill in xy below */
tvec[2] = 0.001;
- glBegin(GL_QUADS);
+ immBegin(GWN_PRIM_TRI_FAN, 4);
if (sb->rot == 0.0f) {
copy_v2_fl2(tvec, sb->x, sb->y);
- glVertex3fv(tvec);
+ immVertex3fv(pos, tvec);
copy_v2_fl2(tvec, sb->x + selboxw, sb->y);
- glVertex3fv(tvec);
+ immVertex3fv(pos, tvec);
copy_v2_fl2(tvec, sb->x + selboxw, sb->y + sb->h);
- glVertex3fv(tvec);
+ immVertex3fv(pos, tvec);
copy_v2_fl2(tvec, sb->x, sb->y + sb->h);
- glVertex3fv(tvec);
+ immVertex3fv(pos, tvec);
}
else {
float mat[2][2];
@@ -6564,84 +7570,87 @@ static void draw_editfont(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *b
angle_to_mat2(mat, sb->rot);
copy_v2_fl2(tvec, sb->x, sb->y);
- glVertex3fv(tvec);
+ immVertex3fv(pos, tvec);
copy_v2_fl2(tvec, selboxw, 0.0f);
mul_m2v2(mat, tvec);
add_v2_v2(tvec, &sb->x);
- glVertex3fv(tvec);
+ immVertex3fv(pos, tvec);
copy_v2_fl2(tvec, selboxw, sb->h);
mul_m2v2(mat, tvec);
add_v2_v2(tvec, &sb->x);
- glVertex3fv(tvec);
+ immVertex3fv(pos, tvec);
copy_v2_fl2(tvec, 0.0f, sb->h);
mul_m2v2(mat, tvec);
add_v2_v2(tvec, &sb->x);
- glVertex3fv(tvec);
+ immVertex3fv(pos, tvec);
}
- glEnd();
+ immEnd();
}
set_inverted_drawing(0);
+ immUnbindProgram();
}
}
/* 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);
+static void draw_empty_sphere(float size, unsigned pos)
+{
+#define NSEGMENTS 16
+ /* 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] = size * cosf(angle);
+ p[i][1] = size * sinf(angle);
+ }
+
+ immBegin(GWN_PRIM_LINE_LOOP, NSEGMENTS);
+ for (int i = 0; i < NSEGMENTS; ++i)
+ immVertex3f(pos, p[i][0], p[i][1], 0.0f);
+ immEnd();
+ immBegin(GWN_PRIM_LINE_LOOP, NSEGMENTS);
+ for (int i = 0; i < NSEGMENTS; ++i)
+ immVertex3f(pos, p[i][0], 0.0f, p[i][1]);
+ immEnd();
+ immBegin(GWN_PRIM_LINE_LOOP, NSEGMENTS);
+ for (int i = 0; i < NSEGMENTS; ++i)
+ immVertex3f(pos, 0.0f, p[i][0], p[i][1]);
+ immEnd();
+#undef NSEGMENTS
}
/* draw a cone for use as an empty drawtype */
-static void draw_empty_cone(float size)
+static void draw_empty_cone(float size, unsigned pos)
{
- const float radius = size;
+#define NSEGMENTS 8
+ /* 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] = size * cosf(angle);
+ p[i][1] = size * sinf(angle);
+ }
- 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);
+ /* cone sides */
+ immBegin(GWN_PRIM_LINES, NSEGMENTS * 2);
+ for (int i = 0; i < NSEGMENTS; ++i) {
+ immVertex3f(pos, 0.0f, 2.0f * size, 0.0f);
+ immVertex3f(pos, p[i][0], 0.0f, p[i][1]);
+ }
+ immEnd();
- glPopMatrix();
-
- gluDeleteQuadric(qobj);
+ /* end ring */
+ immBegin(GWN_PRIM_LINE_LOOP, NSEGMENTS);
+ for (int i = 0; i < NSEGMENTS; ++i)
+ immVertex3f(pos, p[i][0], 0.0f, p[i][1]);
+ immEnd();
+#undef NSEGMENTS
}
-static void drawspiral(const float cent[3], float rad, float tmat[4][4], int start)
+static void drawspiral(unsigned int pos, 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;
@@ -6657,11 +7666,11 @@ static void drawspiral(const float cent[3], float rad, float tmat[4][4], int sta
mul_v3_v3fl(vx, tmat[0], rad);
mul_v3_v3fl(vy, tmat[1], rad);
- glBegin(GL_LINE_STRIP);
+ immBegin(GWN_PRIM_LINE_STRIP, CIRCLE_RESOL + 1);
if (inverse == 0) {
copy_v3_v3(vec, cent);
- glVertex3fv(vec);
+ immVertex3fv(pos, vec);
for (a = 0; a < CIRCLE_RESOL; a++) {
if (a + start >= CIRCLE_RESOL)
@@ -6675,7 +7684,7 @@ static void drawspiral(const float cent[3], float rad, float tmat[4][4], int sta
vec[1] = cent[1] + (x * vx[1] + y * vy[1]);
vec[2] = cent[2] + (x * vx[2] + y * vy[2]);
- glVertex3fv(vec);
+ immVertex3fv(pos, vec);
}
}
else {
@@ -6687,7 +7696,7 @@ static void drawspiral(const float cent[3], float rad, float tmat[4][4], int sta
vec[1] = cent[1] + (x * vx[1] + y * vy[1]);
vec[2] = cent[2] + (x * vx[2] + y * vy[2]);
- glVertex3fv(vec);
+ immVertex3fv(pos, vec);
for (a = 0; a < CIRCLE_RESOL; a++) {
if (a + start >= CIRCLE_RESOL)
@@ -6700,78 +7709,77 @@ static void drawspiral(const float cent[3], float rad, float tmat[4][4], int sta
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);
+ immVertex3fv(pos, vec);
}
}
- glEnd();
+ immEnd();
}
/* 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)
+static void drawcircle_size(float size, unsigned pos)
{
- glBegin(GL_LINE_LOOP);
+ immBegin(GWN_PRIM_LINE_LOOP, CIRCLE_RESOL);
/* 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);
+
+ immVertex3f(pos, x * size, 0.0f, y * size);
}
-
- glEnd();
+ immEnd();
}
/* needs fixing if non-identity matrix used */
-static void drawtube(const float vec[3], float radius, float height, float tmat[4][4])
+static void imm_drawtube(const float vec[3], float radius, float height, float tmat[4][4], unsigned pos)
{
float cur[3];
- drawcircball(GL_LINE_LOOP, vec, radius, tmat);
+ imm_drawcircball(vec, radius, tmat, pos);
copy_v3_v3(cur, vec);
cur[2] += height;
- drawcircball(GL_LINE_LOOP, cur, radius, tmat);
+ imm_drawcircball(cur, radius, tmat, pos);
- 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();
+ immBegin(GWN_PRIM_LINES, 8);
+ immVertex3f(pos, vec[0] + radius, vec[1], vec[2]);
+ immVertex3f(pos, cur[0] + radius, cur[1], cur[2]);
+ immVertex3f(pos, vec[0] - radius, vec[1], vec[2]);
+ immVertex3f(pos, cur[0] - radius, cur[1], cur[2]);
+ immVertex3f(pos, vec[0], vec[1] + radius, vec[2]);
+ immVertex3f(pos, cur[0], cur[1] + radius, cur[2]);
+ immVertex3f(pos, vec[0], vec[1] - radius, vec[2]);
+ immVertex3f(pos, cur[0], cur[1] - radius, cur[2]);
+ immEnd();
}
/* needs fixing if non-identity matrix used */
-static void drawcone(const float vec[3], float radius, float height, float tmat[4][4])
+static void imm_drawcone(const float vec[3], float radius, float height, float tmat[4][4], unsigned pos)
{
float cur[3];
copy_v3_v3(cur, vec);
cur[2] += height;
- drawcircball(GL_LINE_LOOP, cur, radius, tmat);
+ imm_drawcircball(cur, radius, tmat, pos);
- 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();
+ immBegin(GWN_PRIM_LINES, 8);
+ immVertex3f(pos, vec[0], vec[1], vec[2]);
+ immVertex3f(pos, cur[0] + radius, cur[1], cur[2]);
+ immVertex3f(pos, vec[0], vec[1], vec[2]);
+ immVertex3f(pos, cur[0] - radius, cur[1], cur[2]);
+ immVertex3f(pos, vec[0], vec[1], vec[2]);
+ immVertex3f(pos, cur[0], cur[1] + radius, cur[2]);
+ immVertex3f(pos, vec[0], vec[1], vec[2]);
+ immVertex3f(pos, cur[0], cur[1] - radius, cur[2]);
+ immEnd();
}
/* return true if nothing was drawn */
-static bool drawmball(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
+static bool drawmball(Scene *scene, SceneLayer *sl, View3D *v3d, RegionView3D *rv3d, Base *base,
const char dt, const short dflag, const unsigned char ob_wire_col[4])
{
Object *ob = base->object;
@@ -6785,15 +7793,13 @@ static bool drawmball(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
if ((G.f & G_PICKSEL) == 0) {
unsigned char wire_col[4];
UI_GetThemeColor4ubv(TH_WIRE_EDIT, wire_col);
- glColor3ubv(wire_col);
-
- drawDispList(scene, v3d, rv3d, base, dt, dflag, wire_col);
+ drawDispList(scene, sl, v3d, rv3d, base, dt, dflag, wire_col);
}
ml = mb->editelems->first;
}
else {
- if ((base->flag & OB_FROMDUPLI) == 0) {
- drawDispList(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
+ if ((base->flag_legacy & OB_FROMDUPLI) == 0) {
+ drawDispList(scene, sl, v3d, rv3d, base, dt, dflag, ob_wire_col);
}
ml = mb->elems.first;
}
@@ -6810,20 +7816,25 @@ static bool drawmball(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
normalize_v3(imat[0]);
normalize_v3(imat[1]);
+#if 0 /* no purpose? */
if (mb->editelems == NULL) {
if ((dflag & DRAW_CONSTCOLOR) == 0) {
glColor3ubv(ob_wire_col);
}
}
-
+#endif
+
glLineWidth(1.0f);
+ const unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
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 ((ml->flag & SELECT) && (ml->flag & MB_SCALE_RAD)) imm_cpack(0xA0A0F0);
+ else imm_cpack(0x3030A0);
}
if (G.f & G_PICKSEL) {
@@ -6831,24 +7842,26 @@ static bool drawmball(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
GPU_select_load_id(code++);
}
}
- drawcircball(GL_LINE_LOOP, &(ml->x), ml->rad, imat);
+ imm_drawcircball(&(ml->x), ml->rad, imat, pos);
/* 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 ((ml->flag & SELECT) && !(ml->flag & MB_SCALE_RAD)) imm_cpack(0xA0F0A0);
+ else imm_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);
+ imm_drawcircball(&(ml->x), ml->rad * atanf(ml->s) / (float)M_PI_2, imat, pos);
}
ml = ml->next;
}
+
+ immUnbindProgram();
return false;
}
@@ -6858,6 +7871,7 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d,
PartDeflect *pd = ob->pd;
float imat[4][4], tmat[4][4];
float vec[3] = {0.0, 0.0, 0.0};
+ float draw_color[3] = {0.0f, 0.0f, 0.0f};
/* scale size of circle etc with the empty drawsize */
const float size = (ob->type == OB_EMPTY) ? ob->empty_drawsize : 1.0f;
@@ -6867,35 +7881,53 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d,
normalize_v3(imat[0]); /* we don't do this because field doesnt scale either... apart from wind! */
normalize_v3(imat[1]);
#endif
+
+ const unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor3fv(draw_color);
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);
+ ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.5f, draw_color);
+ immUniformColor3fv(draw_color);
}
unit_m4(tmat);
force_val *= 0.1f;
- drawcircball(GL_LINE_LOOP, vec, size, tmat);
+ imm_drawcircball(vec, size, tmat, pos);
vec[2] = 0.5f * force_val;
- drawcircball(GL_LINE_LOOP, vec, size, tmat);
+ imm_drawcircball(vec, size, tmat, pos);
vec[2] = 1.0f * force_val;
- drawcircball(GL_LINE_LOOP, vec, size, tmat);
+ imm_drawcircball(vec, size, tmat, pos);
vec[2] = 1.5f * force_val;
- drawcircball(GL_LINE_LOOP, vec, size, tmat);
+ imm_drawcircball(vec, size, tmat, pos);
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);
+ if ((dflag & DRAW_CONSTCOLOR) == 0) {
+ ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.5f, draw_color);
+ immUniformColor3fv(draw_color);
+ }
+
+ imm_drawcircball(vec, size, imat, pos);
+
+ 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), draw_color);
+ immUniformColor3fv(draw_color);
+ }
+
+ imm_drawcircball(vec, size * 1.5f, imat, pos);
+
+ 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), draw_color);
+ immUniformColor3fv(draw_color);
+ }
+
+ imm_drawcircball(vec, size * 2.0f, imat, pos);
}
else if (pd->forcefield == PFIELD_VORTEX) {
float force_val = pd->f_strength;
@@ -6903,16 +7935,17 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d,
unit_m4(tmat);
if ((dflag & DRAW_CONSTCOLOR) == 0) {
- ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.7f);
+ ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.7f, draw_color);
+ immUniformColor3fv(draw_color);
}
if (force_val < 0) {
- drawspiral(vec, size, tmat, 1);
- drawspiral(vec, size, tmat, 16);
+ drawspiral(pos, vec, size, tmat, 1);
+ drawspiral(pos, vec, size, tmat, 16);
}
else {
- drawspiral(vec, size, tmat, -1);
- drawspiral(vec, size, tmat, -16);
+ drawspiral(pos, vec, size, tmat, -1);
+ drawspiral(pos, vec, size, tmat, -16);
}
}
else if (pd->forcefield == PFIELD_GUIDE && ob->type == OB_CURVE) {
@@ -6922,18 +7955,19 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d,
float mindist = pd->f_strength;
if ((dflag & DRAW_CONSTCOLOR) == 0) {
- ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.5f);
+ ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.5f, draw_color);
+ immUniformColor3fv(draw_color);
}
/* path end */
setlinestyle(3);
where_on_path(ob, 1.0f, guidevec1, guidevec2, NULL, NULL, NULL);
- drawcircball(GL_LINE_LOOP, guidevec1, mindist, imat);
+ imm_drawcircball(guidevec1, mindist, imat, pos);
/* path beginning */
setlinestyle(0);
where_on_path(ob, 0.0f, guidevec1, guidevec2, NULL, NULL, NULL);
- drawcircball(GL_LINE_LOOP, guidevec1, mindist, imat);
+ imm_drawcircball(guidevec1, mindist, imat, pos);
copy_v3_v3(vec, guidevec1); /* max center */
}
@@ -6942,16 +7976,19 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d,
setlinestyle(3);
if ((dflag & DRAW_CONSTCOLOR) == 0) {
- ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.5f);
+ ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.5f, draw_color);
+ immUniformColor3fv(draw_color);
}
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_USEMAX) != 0) {
+ imm_drawcircball(vec, pd->maxdist, imat, pos);
+ }
- if (pd->flag & PFIELD_USEMIN)
- drawcircball(GL_LINE_LOOP, vec, pd->mindist, imat);
+ if ((pd->flag & PFIELD_USEMIN) != 0) {
+ imm_drawcircball(vec, pd->mindist, imat, pos);
+ }
}
else if (pd->falloff == PFIELD_FALL_TUBE) {
float radius, distance;
@@ -6964,16 +8001,18 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d,
vec[2] = distance;
distance = (pd->flag & PFIELD_POSZ) ? -distance : -2.0f * distance;
- if (pd->flag & (PFIELD_USEMAX | PFIELD_USEMAXR))
- drawtube(vec, radius, distance, tmat);
+ if (pd->flag & (PFIELD_USEMAX | PFIELD_USEMAXR)) {
+ imm_drawtube(vec, radius, distance, tmat, pos);
+ }
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);
+ if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR)) {
+ imm_drawtube(vec, radius, distance, tmat, pos);
+ }
}
else if (pd->falloff == PFIELD_FALL_CONE) {
float radius, distance;
@@ -6984,46 +8023,54 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d,
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);
+ imm_drawcone(vec, distance * sinf(radius), distance * cosf(radius), tmat, pos);
if ((pd->flag & PFIELD_POSZ) == 0)
- drawcone(vec, distance * sinf(radius), -distance * cosf(radius), tmat);
+ imm_drawcone(vec, distance * sinf(radius), -distance * cosf(radius), tmat, pos);
}
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);
+ imm_drawcone(vec, distance * sinf(radius), distance * cosf(radius), tmat, pos);
if ((pd->flag & PFIELD_POSZ) == 0)
- drawcone(vec, distance * sinf(radius), -distance * cosf(radius), tmat);
+ imm_drawcone(vec, distance * sinf(radius), -distance * cosf(radius), tmat, pos);
}
}
setlinestyle(0);
+
+ immUnbindProgram();
}
-static void draw_box(const float vec[8][3], bool solid)
+static void imm_draw_box(const float vec[8][3], bool solid, unsigned pos)
{
- 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);
+ /* Adpated from "Optimizing Triangle Strips for Fast Rendering" by F. Evans, S. Skiena and A. Varshney
+ * (http://www.cs.umd.edu/gvil/papers/av_ts.pdf). */
+ static const GLubyte tris_strip_indices[14] = {0,1,3,2,6,1,5,0,4,3,7,6,4,5};
+ immBegin(GWN_PRIM_TRI_STRIP, 14);
+ for (int i = 0; i < 14; ++i) {
+ immVertex3fv(pos, vec[tris_strip_indices[i]]);
+ }
+ immEnd();
}
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);
+ static const GLubyte line_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};
+ immBegin(GWN_PRIM_LINES, 24);
+ for (int i = 0; i < 24; ++i) {
+ immVertex3fv(pos, vec[line_indices[i]]);
+ }
+ immEnd();
}
- glDisableClientState(GL_VERTEX_ARRAY);
}
-static void draw_bb_quadric(BoundBox *bb, char type, bool around_origin)
+static void imm_draw_bb(BoundBox *bb, char type, bool around_origin, const unsigned char ob_wire_col[4])
{
float size[3], cent[3];
- GLUquadricObj *qobj = gluNewQuadric();
-
- gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
+ Gwn_Batch *sphere = Batch_get_sphere_wire(0);
+ Batch_set_builtin_program(sphere, GPU_SHADER_3D_UNIFORM_COLOR);
+ if (ob_wire_col) GWN_batch_uniform_4f(sphere, "color", ob_wire_col[0] / 255.0f, ob_wire_col[1] / 255.0f, ob_wire_col[2] / 255.0f, 1.0f);
BKE_boundbox_calc_size_aabb(bb, size);
@@ -7034,40 +8081,51 @@ static void draw_bb_quadric(BoundBox *bb, char type, bool around_origin)
BKE_boundbox_calc_center_aabb(bb, cent);
}
- glPushMatrix();
+ gpuPushMatrix();
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ if (ob_wire_col) immUniformColor3ubv(ob_wire_col);
+
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);
+ gpuTranslate3fv(cent);
+ gpuRotateAxis(90, 'X');
+ gpuScaleUniform(scale);
+ GWN_batch_draw(sphere);
}
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);
+ gpuTranslate3f(cent[0], cent[1], cent[2] - size[2]);
+ gpuScale3f(radius, radius, 2.0f * size[2]);
+ imm_draw_cylinder_wire_3d(pos, 1.0f, 1.0f, 1.0f, 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);
+ gpuTranslate3f(cent[0], cent[1], cent[2] - size[2]);
+ gpuScale3f(radius, radius, 2.0f * size[2]);
+ imm_draw_cylinder_wire_3d(pos, 1.0f, 0.0f, 1.0f, 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);
+ gpuTranslate3f(cent[0], cent[1], cent[2] - length * 0.5f);
+ imm_draw_cylinder_wire_3d(pos, radius, radius, length, 8, 1);
+
+ gpuRotateAxis(90, 'X');
+ gpuScaleUniform(radius);
+ GWN_batch_draw(sphere);
+
+ gpuTranslate3f(0.0f, length / radius, 0.0f);
+ GWN_batch_draw(sphere);
}
- glPopMatrix();
-
- gluDeleteQuadric(qobj);
+
+ gpuPopMatrix();
+ immUnbindProgram();
}
-static void draw_bounding_volume(Object *ob, char type)
+void draw_bounding_volume(Object *ob, char type, const unsigned char ob_wire_col[4])
{
BoundBox bb_local;
BoundBox *bb = NULL;
@@ -7097,12 +8155,16 @@ static void draw_bounding_volume(Object *ob, char type)
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];
-
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ if (ob_wire_col) immUniformColor3ubv(ob_wire_col);
+
BKE_boundbox_calc_size_aabb(bb, size);
vec[0][0] = vec[1][0] = vec[2][0] = vec[3][0] = -size[0];
@@ -7112,21 +8174,31 @@ static void draw_bounding_volume(Object *ob, char type)
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);
+ imm_draw_box(vec, false, pos);
+
+ immUnbindProgram();
}
else {
- draw_bb_quadric(bb, type, true);
+ imm_draw_bb(bb, type, true, ob_wire_col);
}
}
else {
- if (type == OB_BOUND_BOX)
- draw_box(bb->vec, false);
+ if (type == OB_BOUND_BOX) {
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ if (ob_wire_col) immUniformColor3ubv(ob_wire_col);
+
+ imm_draw_box(bb->vec, false, pos);
+
+ immUnbindProgram();
+ }
else
- draw_bb_quadric(bb, type, false);
+ imm_draw_bb(bb, type, false, ob_wire_col);
}
+
}
-static void drawtexspace(Object *ob)
+static void drawtexspace(Object *ob, const unsigned char ob_wire_col[3])
{
float vec[8][3], loc[3], size[3];
@@ -7156,19 +8228,32 @@ static void drawtexspace(Object *ob)
setlinestyle(2);
- draw_box(vec, false);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ if (ob_wire_col) {
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor3ubv(ob_wire_col);
+ }
+ else {
+ immBindBuiltinProgram(GPU_SHADER_3D_DEPTH_ONLY);
+ }
+
+ imm_draw_box(vec, false, pos);
+
+ immUnbindProgram();
setlinestyle(0);
}
/* draws wire outline */
-static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
- const unsigned char ob_wire_col[4])
+static void draw_object_selected_outline(
+ Scene *scene, SceneLayer *sl, View3D *v3d, ARegion *ar, Base *base,
+ const unsigned char ob_wire_col[4])
{
RegionView3D *rv3d = ar->regiondata;
Object *ob = base->object;
- glDepthMask(0);
+ glDepthMask(GL_FALSE);
if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
bool has_faces = false;
@@ -7192,46 +8277,41 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
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);
+ draw_mesh_object_outline(v3d, ob, dm, ob_wire_col);
}
else {
/* only draw 'solid' parts of the display list as wire. */
- drawDispListwire_ex(&ob->curve_cache->disp, (DL_INDEX3 | DL_INDEX4 | DL_SURF));
+ drawDispListwire_ex(&ob->curve_cache->disp, (DL_INDEX3 | DL_INDEX4 | DL_SURF), ob_wire_col);
}
}
}
else if (ob->type == OB_MBALL) {
if (BKE_mball_is_basis(ob)) {
- if ((base->flag & OB_FROMDUPLI) == 0) {
+ if ((base->flag_legacy & OB_FROMDUPLI) == 0) {
glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
- drawDispListwire(&ob->curve_cache->disp, ob->type);
+ drawDispListwire(&ob->curve_cache->disp, ob->type, ob_wire_col);
}
}
}
else if (ob->type == OB_ARMATURE) {
- if (!(ob->mode & OB_MODE_POSE && base == scene->basact)) {
+ if (!(ob->mode & OB_MODE_POSE && base == sl->basact)) {
glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
- draw_armature(scene, v3d, ar, base, OB_WIRE, 0, ob_wire_col, true);
+ draw_armature(scene, sl, v3d, ar, base, OB_WIRE, 0, ob_wire_col, true);
}
}
- glDepthMask(1);
+ glDepthMask(GL_TRUE);
}
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);
- }
+ unsigned char wire_edit_col[4];
+ UI_GetThemeColor4ubv(TH_WIRE_EDIT, wire_edit_col);
ED_view3d_polygon_offset(rv3d, 1.0);
- glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */
- glLineWidth(1);
+ glDepthMask(GL_FALSE); /* disable write in zbuffer, selected edge wires show better */
+ glLineWidth(1.0f);
if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
if (ED_view3d_boundbox_clip(rv3d, ob->bb)) {
@@ -7240,23 +8320,23 @@ static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, const
drawCurveDMWired(ob);
}
else {
- drawDispListwire(&ob->curve_cache->disp, ob->type);
+ drawDispListwire(&ob->curve_cache->disp, ob->type, (scene->obedit == ob) ? wire_edit_col : ob_wire_col);
}
}
}
else if (ob->type == OB_MBALL) {
if (BKE_mball_is_basis(ob)) {
- drawDispListwire(&ob->curve_cache->disp, ob->type);
+ drawDispListwire(&ob->curve_cache->disp, ob->type, (scene->obedit == ob) ? wire_edit_col : ob_wire_col);
}
}
- glDepthMask(1);
+ glDepthMask(GL_TRUE);
ED_view3d_polygon_offset(rv3d, 0.0);
}
}
/* should be called in view space */
-static void draw_hooks(Object *ob)
+static void draw_hooks(Object *ob, unsigned int pos)
{
for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Hook) {
@@ -7267,17 +8347,17 @@ static void draw_hooks(Object *ob)
if (hmd->object) {
setlinestyle(3);
- glBegin(GL_LINES);
- glVertex3fv(hmd->object->obmat[3]);
- glVertex3fv(vec);
- glEnd();
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex3fv(pos, hmd->object->obmat[3]);
+ immVertex3fv(pos, vec);
+ immEnd();
setlinestyle(0);
}
- glPointSize(3.0);
- glBegin(GL_POINTS);
- glVertex3fv(vec);
- glEnd();
+ glPointSize(3.0f);
+ immBegin(GWN_PRIM_POINTS, 1);
+ immVertex3fv(pos, vec);
+ immEnd();
}
}
}
@@ -7288,9 +8368,16 @@ static void draw_rigid_body_pivot(bRigidBodyJointConstraint *data,
const char *axis_str[3] = {"px", "py", "pz"};
float mat[4][4];
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ if (ob_wire_col) immUniformColor3ubv(ob_wire_col);
+
eul_to_mat4(mat, &data->axX);
glLineWidth(4.0f);
setlinestyle(2);
+
+ immBegin(GWN_PRIM_LINES, 6);
for (int axis = 0; axis < 3; axis++) {
float dir[3] = {0, 0, 0};
float v[3];
@@ -7298,12 +8385,10 @@ static void draw_rigid_body_pivot(bRigidBodyJointConstraint *data,
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();
+ immVertex3fv(pos, &data->pivX);
+ immVertex3fv(pos, v);
/* 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 */
@@ -7311,11 +8396,15 @@ static void draw_rigid_body_pivot(bRigidBodyJointConstraint *data,
view3d_cached_text_draw_add(v, axis_str[axis], 2, 0, V3D_CACHE_TEXT_ASCII, ob_wire_col);
}
}
+ immEnd();
setlinestyle(0);
+ glLineWidth(1.0f);
+
+ immUnbindProgram();
}
-static void draw_object_wire_color(Scene *scene, Base *base, unsigned char r_ob_wire_col[4])
+void draw_object_wire_color(Scene *scene, SceneLayer *sl, Base *base, unsigned char r_ob_wire_col[4])
{
Object *ob = base->object;
int colindex = 0;
@@ -7329,24 +8418,24 @@ static void draw_object_wire_color(Scene *scene, Base *base, unsigned char r_ob_
if ((scene->obedit == NULL) &&
(G.moving & G_TRANSFORM_OBJ) &&
- (base->flag & (SELECT + BA_WAS_SEL)))
+ ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL)))
{
theme_id = TH_TRANSFORM;
}
else {
/* Sets the 'colindex' */
if (ID_IS_LINKED_DATABLOCK(ob)) {
- colindex = (base->flag & (SELECT + BA_WAS_SEL)) ? 2 : 1;
+ colindex = ((base->flag & BASE_SELECTED) || (base->flag_legacy & 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)) {
+ if ((ob->flag & OB_FROMGROUP) != 0) {
+ if ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL)) {
/* uses darker active color for non-active + selected */
theme_id = TH_GROUP_ACTIVE;
- if (scene->basact != base) {
- theme_shade = -16;
+ if (sl->basact != base) {
+ theme_shade = -32;
}
}
else {
@@ -7354,8 +8443,8 @@ static void draw_object_wire_color(Scene *scene, Base *base, unsigned char r_ob_
}
}
else {
- if (base->flag & (SELECT + BA_WAS_SEL)) {
- theme_id = scene->basact == base ? TH_ACTIVE : TH_SELECT;
+ if ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL)) {
+ theme_id = sl->basact == base ? TH_ACTIVE : TH_SELECT;
}
else {
if (ob->type == OB_LAMP) theme_id = TH_LAMP;
@@ -7409,10 +8498,11 @@ static void draw_object_matcap_check(View3D *v3d, Object *ob)
v3d->flag2 |= V3D_SHOW_SOLID_MATCAP;
}
-static void draw_rigidbody_shape(Object *ob)
+void draw_rigidbody_shape(Object *ob, const unsigned char ob_wire_col[4])
{
BoundBox *bb = NULL;
float size[3], vec[8][3];
+ unsigned int pos;
if (ob->type == OB_MESH) {
bb = BKE_mesh_boundbox_get(ob);
@@ -7425,6 +8515,10 @@ static void draw_rigidbody_shape(Object *ob)
case RB_SHAPE_BOX:
BKE_boundbox_calc_size_aabb(bb, size);
+ pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ if (ob_wire_col) immUniformColor3ubv(ob_wire_col);
+
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];
@@ -7432,19 +8526,20 @@ static void draw_rigidbody_shape(Object *ob)
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);
+ imm_draw_box(vec, false, pos);
+ immUnbindProgram();
break;
case RB_SHAPE_SPHERE:
- draw_bb_quadric(bb, OB_BOUND_SPHERE, true);
+ imm_draw_bb(bb, OB_BOUND_SPHERE, true, ob_wire_col);
break;
case RB_SHAPE_CONE:
- draw_bb_quadric(bb, OB_BOUND_CONE, true);
+ imm_draw_bb(bb, OB_BOUND_CONE, true, ob_wire_col);
break;
case RB_SHAPE_CYLINDER:
- draw_bb_quadric(bb, OB_BOUND_CYLINDER, true);
+ imm_draw_bb(bb, OB_BOUND_CYLINDER, true, ob_wire_col);
break;
case RB_SHAPE_CAPSULE:
- draw_bb_quadric(bb, OB_BOUND_CAPSULE, true);
+ imm_draw_bb(bb, OB_BOUND_CAPSULE, true, ob_wire_col);
break;
}
}
@@ -7453,17 +8548,16 @@ static void draw_rigidbody_shape(Object *ob)
* main object drawing function, draws in selection
* \param dflag (draw flag) can be DRAW_PICKING and/or DRAW_CONSTCOLOR, DRAW_SCENESET
*/
-void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short dflag)
+void draw_object(Scene *scene, SceneLayer *sl, 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 is_obact = (ob == OBACT_NEW);
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);
@@ -7503,7 +8597,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
}
}
- if (((base->flag & OB_FROMDUPLI) == 0) &&
+ if (((base->flag_legacy & OB_FROMDUPLI) == 0) &&
(md = modifiers_findByType(ob, eModifierType_Smoke)) &&
(modifier_isEnabled(scene, md, eModifierMode_Realtime)))
{
@@ -7527,7 +8621,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
/* xray delay? */
- if ((dflag & DRAW_PICKING) == 0 && (base->flag & OB_FROMDUPLI) == 0 && (v3d->flag2 & V3D_RENDER_SHADOW) == 0) {
+ if ((dflag & DRAW_PICKING) == 0 && (base->flag_legacy & 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 */
@@ -7580,10 +8674,10 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
ED_view3d_project_base(ar, base);
- draw_object_wire_color(scene, base, _ob_wire_col);
+ draw_object_wire_color(scene, sl, base, _ob_wire_col);
ob_wire_col = _ob_wire_col;
- glColor3ubv(ob_wire_col);
+ //glColor3ubv(ob_wire_col);
}
/* maximum drawtype */
@@ -7634,19 +8728,23 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
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 | OB_MODE_HAIR_EDIT)) == 0 &&
- (dflag & DRAW_SCENESET) == 0)
- {
- if (!(ob->dtx & OB_DRAWWIRE) && (ob->flag & SELECT) && !(dflag & (DRAW_PICKING | DRAW_CONSTCOLOR))) {
- drawObjectSelect(scene, v3d, ar, base, ob_wire_col);
+ if (dt > OB_WIRE && (ob->mode & (OB_MODE_EDIT | OB_MODE_HAIR_EDIT)) == 0 && (dflag & DRAW_SCENESET) == 0) {
+ if (!(ob->dtx & OB_DRAWWIRE) && (base->flag & BASE_SELECTED) && !(dflag & (DRAW_PICKING | DRAW_CONSTCOLOR))) {
+ draw_object_selected_outline(scene, sl, v3d, ar, base, ob_wire_col);
}
}
}
+ /* TODO Viewport: draw only for selection */
+ if ((dflag & DRAW_PICKING) == 0) {
+ if ((dt == OB_BOUNDBOX) || ELEM(ob->type, OB_EMPTY, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
+ goto afterdraw;
+ }
+ }
+
switch (ob->type) {
case OB_MESH:
- empty_object = draw_mesh_object(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag);
+ empty_object = draw_mesh_object(scene, sl, ar, v3d, rv3d, base, dt, ob_wire_col, dflag);
if ((dflag & DRAW_CONSTCOLOR) == 0) {
/* mesh draws wire itself */
dtx &= ~OB_DRAWWIRE;
@@ -7656,18 +8754,18 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
case OB_FONT:
cu = ob->data;
if (cu->editfont) {
- draw_editfont(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
+ draw_editfont(scene, sl, 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(scene, base->object);
#endif
- draw_bounding_volume(ob, ob->boundtype);
+ draw_bounding_volume(ob, ob->boundtype, ob_wire_col);
}
}
else if (ED_view3d_boundbox_clip(rv3d, ob->bb)) {
- empty_object = drawDispList(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
+ empty_object = drawDispList(scene, sl, v3d, rv3d, base, dt, dflag, ob_wire_col);
}
break;
@@ -7677,18 +8775,18 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if (cu->editnurb) {
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- draw_editnurb(scene, v3d, rv3d, base, nurbs->first, dt, dflag, ob_wire_col);
+ draw_editnurb(scene, sl, 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(scene, base->object);
#endif
- draw_bounding_volume(ob, ob->boundtype);
+ draw_bounding_volume(ob, ob->boundtype, ob_wire_col);
}
}
else if (ED_view3d_boundbox_clip(rv3d, ob->bb)) {
- empty_object = drawDispList(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
+ empty_object = drawDispList(scene, sl, v3d, rv3d, base, dt, dflag, ob_wire_col);
}
break;
case OB_MBALL:
@@ -7696,26 +8794,26 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
MetaBall *mb = ob->data;
if (mb->editelems)
- drawmball(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
+ drawmball(scene, sl, 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(scene, base->object);
#endif
- draw_bounding_volume(ob, ob->boundtype);
+ draw_bounding_volume(ob, ob->boundtype, ob_wire_col);
}
}
else
- empty_object = drawmball(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
+ empty_object = drawmball(scene, sl, 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);
+ draw_empty_image(ob, dflag, ob_wire_col, v3d->multiview_eye);
}
else {
- drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype);
+ drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype, ob_wire_col);
}
}
break;
@@ -7733,7 +8831,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
break;
case OB_SPEAKER:
if (!render_override)
- drawspeaker(scene, v3d, rv3d, ob, dflag);
+ drawspeaker(ob_wire_col);
break;
case OB_LATTICE:
if (!render_override) {
@@ -7741,13 +8839,13 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if ((dt == OB_BOUNDBOX) && (ob->mode & OB_MODE_EDIT))
dt = OB_WIRE;
if (dt == OB_BOUNDBOX) {
- draw_bounding_volume(ob, ob->boundtype);
+ draw_bounding_volume(ob, ob->boundtype, ob_wire_col);
}
else {
#ifdef SEQUENCER_DAG_WORKAROUND
ensure_curve_cache(scene, ob);
#endif
- drawlattice(v3d, ob);
+ drawlattice(v3d, ob, dflag, ob_wire_col);
}
}
break;
@@ -7757,21 +8855,33 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
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);
+ draw_bounding_volume(ob, ob->boundtype, ob_wire_col);
}
else {
+ unsigned char arm_col[4];
glLineWidth(1.0f);
- empty_object = draw_armature(scene, v3d, ar, base, dt, dflag, ob_wire_col, false);
+
+ if (ob_wire_col == NULL) {
+ float fcol[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ rgba_float_to_uchar(arm_col, fcol);
+ }
+ else
+ copy_v4_v4_uchar(arm_col, ob_wire_col);
+
+ empty_object = draw_armature(scene, sl, v3d, ar, base, dt, dflag, arm_col, false);
}
}
break;
default:
if (!render_override) {
- drawaxes(rv3d->viewmatob, 1.0, OB_ARROWS);
+ drawaxes(rv3d->viewmatob, 1.0, OB_ARROWS, ob_wire_col);
}
break;
}
+ /* TODO Viewport: some elements are being drawn for object selection only */
+afterdraw:
+
if (!render_override) {
if (ob->soft /*&& dflag & OB_SBMOTION*/) {
float mrt[3][3], msc[3][3], mtr[3][3];
@@ -7780,12 +8890,12 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if ((sb = ob->soft)) {
if (sb->solverflags & SBSO_ESTIMATEIPO) {
- glLoadMatrixf(rv3d->viewmat);
+ gpuLoadMatrix(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);
+ gpuMultMatrix(ob->obmat);
}
}
}
@@ -7802,15 +8912,9 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
{
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);
+ gpuLoadMatrix(rv3d->viewmat);
view3d_cached_text_draw_begin();
@@ -7820,19 +8924,18 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if (ob->mode & OB_MODE_PARTICLE_EDIT && is_obact) {
PTCacheEdit *edit = PE_create_current(scene, ob);
if (edit && edit->psys == psys)
- draw_update_ptcache_edit(scene, ob, edit);
+ draw_update_ptcache_edit(scene, sl, 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, NULL);
+ view3d_cached_text_draw_end(v3d, ar, 0);
- glMultMatrixf(ob->obmat);
+ gpuMultMatrix(ob->obmat);
//glDepthMask(GL_TRUE);
- if (col) cpack(col);
}
/* draw edit particles last so that they can draw over child particles */
@@ -7843,10 +8946,10 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if (ob->mode & OB_MODE_PARTICLE_EDIT && is_obact) {
PTCacheEdit *edit = PE_create_current(scene, ob);
if (edit) {
- glLoadMatrixf(rv3d->viewmat);
- draw_update_ptcache_edit(scene, ob, edit);
+ gpuLoadMatrix(rv3d->viewmat);
+ draw_update_ptcache_edit(scene, sl, ob, edit);
draw_ptcache_edit(scene, v3d, edit);
- glMultMatrixf(ob->obmat);
+ gpuMultMatrix(ob->obmat);
}
}
@@ -7858,121 +8961,81 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
}
}
- /* draw code for smoke */
- if (smd) {
-#if 0
- /* draw collision objects */
- if ((smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll) {
- SmokeCollSettings *scs = smd->coll;
- if (scs->points) {
- size_t i;
-
- glLoadMatrixf(rv3d->viewmat);
+ /* draw code for smoke, only draw domains */
+ if (smd && smd->domain) {
+ SmokeDomainSettings *sds = smd->domain;
+ const bool show_smoke = (CFRA >= sds->point_cache[0]->startframe);
+ float viewnormal[3];
- if (col || (ob->flag & SELECT)) cpack(0xFFFFFF);
- glDepthMask(GL_FALSE);
- glEnable(GL_BLEND);
-
+ gpuLoadMatrix(rv3d->viewmat);
+ gpuMultMatrix(ob->obmat);
- // glPointSize(3.0);
- glBegin(GL_POINTS);
-
- for (i = 0; i < scs->numpoints; i++)
- {
- glVertex3fv(&scs->points[3 * i]);
- }
-
- glEnd();
-
- glMultMatrixf(ob->obmat);
- glDisable(GL_BLEND);
- glDepthMask(GL_TRUE);
- if (col) cpack(col);
+ if (!render_override) {
+ BoundBox bb;
+ float p0[3], p1[3];
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ if (ob_wire_col) immUniformColor3ubv(ob_wire_col);
+
+ /* 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);
+ imm_draw_box(bb.vec, false, pos);
}
- }
-#endif
- /* only draw domains */
- if (smd->domain) {
- SmokeDomainSettings *sds = smd->domain;
- float viewnormal[3];
+ /* draw a single voxel to hint the user about the resolution of the fluid */
+ copy_v3_v3(p0, sds->p0);
- glLoadMatrixf(rv3d->viewmat);
- glMultMatrixf(ob->obmat);
+ 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);
+ }
- if (!render_override) {
- BoundBox bb;
- float p0[3], p1[3];
+ BKE_boundbox_init_from_minmax(&bb, p0, p1);
+ imm_draw_box(bb.vec, false, pos);
- /* draw adaptive domain bounds */
- if ((sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN)) {
- /* draw domain max bounds */
- 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);
- }
+ immUnbindProgram();
+ }
-#if 0
- /* draw base resolution bounds */
- BKE_boundbox_init_from_minmax(&bb, sds->p0, sds->p1);
- draw_box(bb.vec);
-#endif
+ /* don't show smoke before simulation starts, this could be made an option in the future */
+ if (sds->fluid && show_smoke) {
+ 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);
- /* draw a single voxel to hint the user about the resolution of the fluid */
- copy_v3_v3(p0, sds->p0);
+ /* 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->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);
- }
+ 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);
+ }
- 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 */
-#ifdef SMOKE_DEBUG_VELOCITY
- draw_smoke_velocity(smd->domain, ob);
-#endif
-#ifdef SMOKE_DEBUG_HEAT
- draw_smoke_heat(smd->domain, ob);
-#endif
+ /* smoke debug render */
+ if (!render_override && sds->draw_velocity) {
+ draw_smoke_velocity(sds, viewnormal);
}
}
}
@@ -7991,29 +9054,37 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
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);
+ draw_bounding_volume(ob, ob->collision_boundtype, ob_wire_col);
setlinestyle(0);
}
}
if (ob->rigidbody_object) {
- draw_rigidbody_shape(ob);
+ draw_rigidbody_shape(ob, ob_wire_col);
}
/* 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 ((dflag & DRAW_CONSTCOLOR) == 0) {
+ /* prevent random colors being used */
+ drawaxes(rv3d->viewmatob, 1.0f, OB_ARROWS, ob_wire_col);
+ }
+ else {
+ drawaxes(rv3d->viewmatob, 1.0f, OB_ARROWS, NULL);
+ }
}
if (dtx & OB_DRAWBOUNDOX) {
- draw_bounding_volume(ob, ob->boundtype);
+ draw_bounding_volume(ob, ob->boundtype, ob_wire_col);
}
if (dtx & OB_TEXSPACE) {
if ((dflag & DRAW_CONSTCOLOR) == 0) {
/* prevent random colors being used */
- glColor3ubv(ob_wire_col);
+ drawtexspace(ob, ob_wire_col);
+ }
+ else {
+ drawtexspace(ob, NULL);
}
- drawtexspace(ob);
}
if (dtx & OB_DRAWNAME) {
/* patch for several 3d cards (IBM mostly) that crash on GL_SELECT with text drawing */
@@ -8040,32 +9111,37 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
{
float imat[4][4], vec[3] = {0.0f, 0.0f, 0.0f};
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
invert_m4_m4(imat, rv3d->viewmatob);
if ((dflag & DRAW_CONSTCOLOR) == 0) {
/* prevent random colors being used */
- glColor3ubv(ob_wire_col);
+ immUniformColor3ubv(ob_wire_col);
}
setlinestyle(2);
- drawcircball(GL_LINE_LOOP, vec, ob->inertia, imat);
+ imm_drawcircball(vec, ob->inertia, imat, pos);
setlinestyle(0);
+
+ immUnbindProgram();
}
}
/* return warning, this is cached text draw */
invert_m4_m4(ob->imat, ob->obmat);
- view3d_cached_text_draw_end(v3d, ar, 1, NULL);
+ view3d_cached_text_draw_end(v3d, ar, 1);
/* return warning, clear temp flag */
v3d->flag2 &= ~V3D_SHOW_SOLID_MATCAP;
- glLoadMatrixf(rv3d->viewmat);
+ gpuLoadMatrix(rv3d->viewmat);
if (zbufoff) {
glDisable(GL_DEPTH_TEST);
}
- if ((base->flag & OB_FROMDUPLI) || render_override) {
+ if ((base->flag_legacy & OB_FROMDUPLI) || render_override) {
ED_view3d_clear_mats_rv3d(rv3d);
return;
}
@@ -8079,7 +9155,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
}
else if (is_obact)
do_draw_center = ACTIVE;
- else if (base->flag & SELECT)
+ else if (base->flag & BASE_SELECTED)
do_draw_center = SELECT;
else if (empty_object || (v3d->flag & V3D_DRAW_CENTERS))
do_draw_center = DESELECT;
@@ -8090,10 +9166,15 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if ((base->sx != IS_CLIPPED) &&
(U.obcenter_dia != 0.0))
{
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR);
+ /* TODO: short term, use DEPTH_ONLY shader or set appropriate color */
+ /* TODO: long term, solve picking & selection problem better */
glPointSize(U.obcenter_dia);
- glBegin(GL_POINTS);
- glVertex3fv(ob->obmat[3]);
- glEnd();
+ immBegin(GWN_PRIM_POINTS, 1);
+ immVertex3fv(pos, ob->obmat[3]);
+ immEnd();
+ immUnbindProgram();
}
}
else if ((dflag & DRAW_CONSTCOLOR) == 0) {
@@ -8114,18 +9195,24 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
ListBase *list;
RigidBodyCon *rbc = ob->rigidbody_constraint;
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor3ubv(ob_wire_col);
+
/* draw hook center and offset line */
if (ob != scene->obedit)
- draw_hooks(ob);
+ draw_hooks(ob, pos);
/* 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);
+ if (ob != scene->obedit && ob->parent) {
+ if ((ob->parent->base_flag & BASE_VISIBLED) != 0) {
+ setlinestyle(3);
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex3fv(pos, ob->obmat[3]);
+ immVertex3fv(pos, ob->orig);
+ immEnd();
+ setlinestyle(0);
+ }
}
/* Drawing the constraint lines */
@@ -8138,7 +9225,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
UI_GetThemeColor3ubv(TH_GRID, col1);
UI_make_axis_color(col1, col2, 'Z');
- glColor3ubv(col2);
+ immUniformColor3ubv(col2);
cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
@@ -8163,10 +9250,10 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if (camob) {
setlinestyle(3);
- glBegin(GL_LINES);
- glVertex3fv(camob->obmat[3]);
- glVertex3fv(ob->obmat[3]);
- glEnd();
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex3fv(pos, camob->obmat[3]);
+ immVertex3fv(pos, ob->obmat[3]);
+ immEnd();
setlinestyle(0);
}
}
@@ -8187,10 +9274,10 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
unit_m4(ct->matrix);
setlinestyle(3);
- glBegin(GL_LINES);
- glVertex3fv(ct->matrix[3]);
- glVertex3fv(ob->obmat[3]);
- glEnd();
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex3fv(pos, ct->matrix[3]);
+ immVertex3fv(pos, ob->obmat[3]);
+ immEnd();
setlinestyle(0);
}
@@ -8203,26 +9290,71 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
BKE_constraints_clear_evalob(cob);
}
/* draw rigid body constraint lines */
- if (rbc) {
- UI_ThemeColor(TH_WIRE);
+ if (rbc && (rbc->ob1 || rbc->ob2)) {
+ immUniformThemeColor(TH_WIRE);
+
setlinestyle(3);
- glBegin(GL_LINES);
+ immBegin(GWN_PRIM_LINES, ((int)((bool)rbc->ob1) + (int)((bool)rbc->ob2)) * 2);
if (rbc->ob1) {
- glVertex3fv(ob->obmat[3]);
- glVertex3fv(rbc->ob1->obmat[3]);
+ immVertex3fv(pos, ob->obmat[3]);
+ immVertex3fv(pos, rbc->ob1->obmat[3]);
}
if (rbc->ob2) {
- glVertex3fv(ob->obmat[3]);
- glVertex3fv(rbc->ob2->obmat[3]);
+ immVertex3fv(pos, ob->obmat[3]);
+ immVertex3fv(pos, rbc->ob2->obmat[3]);
}
- glEnd();
+ immEnd();
setlinestyle(0);
}
+
+ immUnbindProgram();
}
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(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d, Base *base, const short dflag)
+{
+ BLI_assert(dflag & DRAW_PICKING && dflag & DRAW_CONSTCOLOR);
+ draw_object(scene, sl, ar, v3d, base, dflag);
+
+ /* we draw duplicators for selection too */
+ if ((base->object->transflag & OB_DUPLI)) {
+ ListBase *lb;
+ DupliObject *dob;
+ Base tbase;
+
+ tbase.flag_legacy = OB_FROMDUPLI;
+ lb = object_duplilist(G.main->eval_ctx, scene, base->object);
+
+ for (dob = lb->first; dob; dob = dob->next) {
+ float omat[4][4];
+
+ 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 */
+ char dt = tbase.object->dt; tbase.object->dt = MIN2(tbase.object->dt, base->object->dt);
+ short dtx = tbase.object->dtx; tbase.object->dtx = base->object->dtx;
+
+ draw_object(scene, sl, 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],
@@ -8232,8 +9364,10 @@ static void bbs_obmode_mesh_verts__mapFunc(void *userData, int index, const floa
MVert *mv = &data->mvert[index];
if (!(mv->flag & ME_HIDE)) {
- GPU_select_index_set(data->offset + index);
- glVertex3fv(co);
+ int selcol;
+ GPU_select_index_get(data->offset + index, &selcol);
+ immAttrib1u(data->col, selcol);
+ immVertex3fv(data->pos, co);
}
}
@@ -8244,10 +9378,24 @@ static void bbs_obmode_mesh_verts(Object *ob, DerivedMesh *dm, int offset)
MVert *mvert = me->mvert;
data.mvert = mvert;
data.offset = offset;
+
+ const int imm_len = dm->getNumVerts(dm);
+
+ if (imm_len == 0) return;
+
+ Gwn_VertFormat *format = immVertexFormat();
+ data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ data.col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U32, 1, GWN_FETCH_INT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR_U32);
+
glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
- glBegin(GL_POINTS);
+
+ immBeginAtMost(GWN_PRIM_POINTS, imm_len);
dm->foreachMappedVert(dm, bbs_obmode_mesh_verts__mapFunc, &data, DM_FOREACH_NOP);
- glEnd();
+ immEnd();
+
+ immUnbindProgram();
}
static void bbs_mesh_verts__mapFunc(void *userData, int index, const float co[3],
@@ -8257,97 +9405,170 @@ static void bbs_mesh_verts__mapFunc(void *userData, int index, const float co[3]
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);
+ int selcol;
+ GPU_select_index_get(data->offset + index, &selcol);
+ immAttrib1u(data->col, selcol);
+ immVertex3fv(data->pos, co);
}
}
static void bbs_mesh_verts(BMEditMesh *em, DerivedMesh *dm, int offset)
{
- drawBMOffset_userData data = {em->bm, offset};
+ drawBMOffset_userData data;
+ data.bm = em->bm;
+ data.offset = offset;
+ Gwn_VertFormat *format = immVertexFormat();
+ data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ data.col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U32, 1, GWN_FETCH_INT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR_U32);
+
glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
- glBegin(GL_POINTS);
+
+ immBeginAtMost(GWN_PRIM_POINTS, em->bm->totvert);
dm->foreachMappedVert(dm, bbs_mesh_verts__mapFunc, &data, DM_FOREACH_NOP);
- glEnd();
+ immEnd();
+
+ immUnbindProgram();
}
-static DMDrawOption bbs_mesh_wire__setDrawOptions(void *userData, int index)
+static void bbs_mesh_wire__mapFunc(void *userData, int index, const float v0co[3], const float v1co[3])
{
drawBMOffset_userData *data = userData;
BMEdge *eed = BM_edge_at_index(data->bm, index);
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;
+ int selcol;
+ GPU_select_index_get(data->offset + index, &selcol);
+ immAttrib1u(data->col, selcol);
+ immVertex3fv(data->pos, v0co);
+ immVertex3fv(data->pos, v1co);
}
}
+
static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset)
{
- drawBMOffset_userData data = {em->bm, offset};
- dm->drawMappedEdges(dm, bbs_mesh_wire__setDrawOptions, &data);
+ drawBMOffset_userData data;
+ data.bm = em->bm;
+ data.offset = offset;
+
+ Gwn_VertFormat *format = immVertexFormat();
+
+ const int imm_len = dm->getNumEdges(dm) * 2;
+
+ if (imm_len == 0) return;
+
+ data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ data.col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U32, 1, GWN_FETCH_INT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR_U32);
+
+ glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
+
+ immBeginAtMost(GWN_PRIM_LINES, imm_len);
+ dm->foreachMappedEdge(dm, bbs_mesh_wire__mapFunc, &data);
+ immEnd();
+
+ immUnbindProgram();
}
-/**
- * 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_face(BMEditMesh *em, DerivedMesh *dm, const bool use_select)
{
- BMFace *efa = BM_face_at_index(userData, index);
-
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- return DM_DRAW_OPTION_NORMAL;
+ UNUSED_VARS(dm);
+
+ drawBMOffset_userData data;
+ data.bm = em->bm;
+
+ const int tri_len = em->tottri;
+ const int imm_len = tri_len * 3;
+ const char hflag_skip = use_select ? BM_ELEM_HIDDEN : (BM_ELEM_HIDDEN | BM_ELEM_SELECT);
+
+ if (imm_len == 0) return;
+
+ Gwn_VertFormat *format = immVertexFormat();
+ data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ data.col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U32, 1, GWN_FETCH_INT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR_U32);
+
+ immBeginAtMost(GWN_PRIM_TRIS, imm_len);
+
+ if (use_select == false) {
+ int selcol;
+ GPU_select_index_get(0, &selcol);
+ immAttrib1u(data.col, selcol);
}
- else {
- return DM_DRAW_OPTION_SKIP;
+
+ int index = 0;
+ while (index < tri_len) {
+ const BMFace *f = em->looptris[index][0]->f;
+ const int ntris = f->len - 2;
+ if (!BM_elem_flag_test(f, hflag_skip)) {
+ if (use_select) {
+ int selcol;
+ GPU_select_index_get(BM_elem_index_get(f) + 1, &selcol);
+ immAttrib1u(data.col, selcol);
+ }
+ for (int t = 0; t < ntris; t++) {
+ immVertex3fv(data.pos, em->looptris[index][0]->v->co);
+ immVertex3fv(data.pos, em->looptris[index][1]->v->co);
+ immVertex3fv(data.pos, em->looptris[index][2]->v->co);
+ index++;
+ }
+ }
+ else {
+ index += ntris;
+ }
}
+ immEnd();
+
+ immUnbindProgram();
}
-static DMDrawOption bbs_mesh_solid__setSolidDrawOptions(void *userData, int index)
+static void bbs_mesh_solid__drawCenter(void *userData, int index, const float cent[3], const float UNUSED(no[3]))
{
+ drawBMOffset_userData *data = (drawBMOffset_userData *)userData;
BMFace *efa = BM_face_at_index(userData, index);
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- GPU_select_index_set(index + 1);
- return DM_DRAW_OPTION_NORMAL;
- }
- else {
- return DM_DRAW_OPTION_SKIP;
+ int selcol;
+ GPU_select_index_get(index + 1, &selcol);
+ immAttrib1u(data->col, selcol);
+ immVertex3fv(data->pos, cent);
}
}
-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, DerivedMesh *dm)
{
- BMFace *efa = BM_face_at_index(userData, index);
+ drawBMOffset_userData data; /* don't use offset */
+ data.bm = em->bm;
+ Gwn_VertFormat *format = immVertexFormat();
+ data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ data.col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U32, 1, GWN_FETCH_INT);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- GPU_select_index_set(index + 1);
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR_U32);
- glVertex3fv(cent);
- }
+ glPointSize(UI_GetThemeValuef(TH_FACEDOT_SIZE));
+
+ immBeginAtMost(GWN_PRIM_POINTS, em->bm->totface);
+ dm->foreachMappedFaceCenter(dm, bbs_mesh_solid__drawCenter, &data, DM_FOREACH_NOP);
+ immEnd();
+
+ immUnbindProgram();
}
/* two options, facecolors or black */
static void bbs_mesh_solid_EM(BMEditMesh *em, Scene *scene, View3D *v3d,
Object *ob, DerivedMesh *dm, 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, dm, 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, dm);
}
-
}
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);
+ bbs_mesh_face(em, dm, false);
}
}
@@ -8362,7 +9583,6 @@ 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 {
@@ -8387,13 +9607,16 @@ static void bbs_mesh_solid_verts(Scene *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);
- dm->drawMappedFaces(dm, bbs_mesh_solid_hide2__setDrawOpts, GPU_object_material_bind, NULL, me, DM_DRAW_SKIP_HIDDEN);
+ /* 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;
- GPU_object_material_unbind();
+ dm->drawMappedFaces(dm, bbs_mesh_solid_hide2__setDrawOpts, NULL, NULL, me, DM_DRAW_SKIP_HIDDEN);
+
+ G.f |= (G_f_orig & G_BACKBUFSEL);
bbs_obmode_mesh_verts(ob, dm, 1);
bm_vertoffs = me->totvert + 1;
@@ -8402,26 +9625,24 @@ static void bbs_mesh_solid_verts(Scene *scene, Object *ob)
static void bbs_mesh_solid_faces(Scene *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);
+ UNUSED_VARS(scene, bbs_mesh_solid_hide__setDrawOpts, bbs_mesh_solid__setDrawOpts);
+ Gwn_Batch *batch;
+ if ((me->editflag & ME_EDIT_PAINT_FACE_SEL)) {
+ batch = DRW_mesh_batch_cache_get_triangles_with_select_id(me, true);
+ }
+ else {
+ batch = DRW_mesh_batch_cache_get_triangles_with_select_id(me, false);
+ }
+ Batch_set_builtin_program(batch, GPU_SHADER_3D_FLAT_COLOR_U32);
+ GWN_batch_draw(batch);
}
void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob)
{
ToolSettings *ts = scene->toolsettings;
- glMultMatrixf(ob->obmat);
+ gpuMultMatrix(ob->obmat);
glClearDepth(1.0); glClear(GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
@@ -8450,8 +9671,8 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
bbs_mesh_wire(em, dm, bm_solidoffs);
bm_wireoffs = bm_solidoffs + em->bm->totedge;
- /* we draw verts if vert select mode or if in transform (for snap). */
- if ((ts->selectmode & SCE_SELECT_VERTEX) || (G.moving & G_TRANSFORM_EDIT)) {
+ /* we draw verts if vert select mode. */
+ if (ts->selectmode & SCE_SELECT_VERTEX) {
bbs_mesh_verts(em, dm, bm_wireoffs);
bm_vertoffs = bm_wireoffs + em->bm->totvert;
}
@@ -8481,7 +9702,7 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
break;
}
- glLoadMatrixf(rv3d->viewmat);
+ gpuLoadMatrix(rv3d->viewmat);
}
@@ -8489,8 +9710,8 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
/* 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)
+static void draw_object_mesh_instance(Scene *scene, SceneLayer *sl, View3D *v3d, RegionView3D *rv3d,
+ Object *ob, const short dt, int outline, const unsigned char ob_wire_col[4])
{
Mesh *me = ob->data;
DerivedMesh *dm = NULL, *edm = NULL;
@@ -8505,6 +9726,7 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r
}
if (dt <= OB_WIRE) {
+ glColor4ubv(ob_wire_col);
if (dm)
dm->drawEdges(dm, 1, 0);
else if (edm)
@@ -8512,11 +9734,11 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r
}
else {
if (outline)
- draw_mesh_object_outline(v3d, ob, dm ? dm : edm);
+ draw_mesh_object_outline(v3d, ob, dm ? dm : edm, ob_wire_col);
if (dm) {
- bool glsl = draw_glsl_material(scene, ob, v3d, dt);
- GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
+ bool glsl = draw_glsl_material(scene, sl, ob, v3d, dt);
+ GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, glsl, NULL);
}
glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
@@ -8535,23 +9757,147 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r
if (dm) dm->release(dm);
}
-void draw_object_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, const char dt, int outline)
+void draw_object_instance(Scene *scene, SceneLayer *sl, View3D *v3d, RegionView3D *rv3d, Object *ob, const char dt, int outline, const float wire_col[4])
{
if (ob == NULL)
return;
+ unsigned char bcol[4];
+ rgba_float_to_uchar(bcol, wire_col);
+
switch (ob->type) {
case OB_MESH:
- draw_object_mesh_instance(scene, v3d, rv3d, ob, dt, outline);
+ draw_object_mesh_instance(scene, sl, v3d, rv3d, ob, dt, outline, bcol);
break;
case OB_EMPTY:
if (ob->empty_drawtype == OB_EMPTY_IMAGE) {
- /* CONSTCOLOR == no wire outline */
- draw_empty_image(ob, DRAW_CONSTCOLOR, NULL);
+ draw_empty_image(ob, 0, bcol, v3d->multiview_eye);
}
else {
- drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype);
+ drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype, bcol);
}
break;
}
}
+
+void ED_draw_object_facemap(Scene *scene, Object *ob, const float col[4], const int facemap)
+{
+ DerivedMesh *dm = NULL;
+
+ /* happens on undo */
+ if (ob->type != OB_MESH || !ob->data)
+ return;
+
+ dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
+ if (!dm || !CustomData_has_layer(&dm->polyData, CD_FACEMAP))
+ return;
+
+
+ glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
+
+#if 0
+ DM_update_materials(dm, ob);
+
+ /* add polygon offset so we draw above the original surface */
+ glPolygonOffset(1.0, 1.0);
+
+ GPU_facemap_setup(dm);
+
+ glColor4fv(col);
+
+ gpuPushAttrib(GL_ENABLE_BIT);
+ glEnable(GL_BLEND);
+ glDisable(GL_LIGHTING);
+
+ /* always draw using backface culling */
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+
+ if (dm->drawObject->facemapindices) {
+ glDrawElements(GL_TRIANGLES, dm->drawObject->facemap_count[facemap] * 3, GL_UNSIGNED_INT,
+ (int *)NULL + dm->drawObject->facemap_start[facemap] * 3);
+ }
+ gpuPopAttrib();
+
+ GPU_buffers_unbind();
+
+ glPolygonOffset(0.0, 0.0);
+
+#else
+
+ /* Just to create the data to pass to immediate mode, grr! */
+ Mesh *me = ob->data;
+ const int *facemap_data = CustomData_get_layer(&me->pdata, CD_FACEMAP);
+ if (facemap_data) {
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor4fv(col);
+
+ /* XXX, alpha isn't working yet, not sure why. */
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+
+ MVert *mvert;
+
+ MPoly *mpoly;
+ int mpoly_len;
+
+ MLoop *mloop;
+ int mloop_len;
+
+ if (dm && CustomData_has_layer(&dm->polyData, CD_FACEMAP)) {
+ mvert = dm->getVertArray(dm);
+ mpoly = dm->getPolyArray(dm);
+ mloop = dm->getLoopArray(dm);
+
+ mpoly_len = dm->getNumPolys(dm);
+ mloop_len = dm->getNumLoops(dm);
+
+ facemap_data = CustomData_get_layer(&dm->polyData, CD_FACEMAP);
+ }
+ else {
+ mvert = me->mvert;
+ mpoly = me->mpoly;
+ mloop = me->mloop;
+
+ mpoly_len = me->totpoly;
+ mloop_len = me->totloop;
+
+ facemap_data = CustomData_get_layer(&me->pdata, CD_FACEMAP);
+ }
+
+ /* use gawain immediate mode fore now */
+ const int looptris_len = poly_to_tri_count(mpoly_len, mloop_len);
+ immBeginAtMost(GWN_PRIM_TRIS, looptris_len * 3);
+
+ MPoly *mp;
+ int i;
+ for (mp = mpoly, i = 0; i < mpoly_len; i++, mp++) {
+ if (facemap_data[i] == facemap) {
+ /* Weak, fan-fill, use until we have derived-mesh replaced. */
+ 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++) {
+ immVertex3fv(pos, mvert[ml_start->v].co);
+ immVertex3fv(pos, mvert[ml_a->v].co);
+ immVertex3fv(pos, mvert[ml_b->v].co);
+
+ ml_a++;
+ ml_b++;
+ }
+ }
+ }
+ immEnd();
+
+ immUnbindProgram();
+
+ glDisable(GL_BLEND);
+ }
+#endif
+
+ dm->release(dm);
+}
+
diff --git a/source/blender/editors/space_view3d/drawsimdebug.c b/source/blender/editors/space_view3d/drawsimdebug.c
index 91adc905816..14708ca67bc 100644
--- a/source/blender/editors/space_view3d/drawsimdebug.c
+++ b/source/blender/editors/space_view3d/drawsimdebug.c
@@ -40,105 +40,154 @@
#include "BKE_effect.h"
-#include "view3d_intern.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
-#include "BIF_gl.h"
+#include "view3d_intern.h"
static void draw_sim_debug_elements(SimDebugData *debug_data, float imat[4][4])
{
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
+
+ /* count element types */
GHashIterator iter;
+ int num_dots = 0;
+ int num_circles = 0;
+ int num_lines = 0;
+ int num_vectors = 0;
+ for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
+ SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
+ switch (elem->type) {
+ case SIM_DEBUG_ELEM_DOT: ++num_dots; break;
+ case SIM_DEBUG_ELEM_CIRCLE: ++num_circles; break;
+ case SIM_DEBUG_ELEM_LINE: ++num_lines; break;
+ case SIM_DEBUG_ELEM_VECTOR: ++num_vectors; break;
+ }
+ }
/**** dots ****/
glPointSize(3.0f);
- glBegin(GL_POINTS);
+ immBegin(GWN_PRIM_POINTS, num_dots);
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]);
+ immAttrib3fv(color, elem->color);
+ immVertex3fv(pos, elem->v1);
}
- glEnd();
+ immEnd();
/**** circles ****/
{
- float circle[16][2] = {
+#define CIRCLERES 16
+ float circle[CIRCLERES][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} };
+
+ immBegin(GWN_PRIM_LINES, num_circles * CIRCLERES * 2);
+
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];
+ float co[3], nco[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);
+ immAttrib3fv(color, elem->color);
+ zero_v3(co);
+ for (i = 0; i <= CIRCLERES; ++i) {
+ int ni = i % CIRCLERES;
+ nco[0] = radius * circle[ni][0];
+ nco[1] = radius * circle[ni][1];
+ nco[2] = 0.0f;
+ mul_mat3_m4_v3(imat, nco);
+ add_v3_v3(nco, elem->v1);
+
+ if (i > 0) {
+ immVertex3fv(pos, co);
+ immVertex3fv(pos, nco);
+ }
- glVertex3f(co[0], co[1], co[2]);
+ copy_v3_v3(co, nco);
}
- glEnd();
}
+
+ immEnd();
+#undef CIRCLERES
}
/**** lines ****/
- glBegin(GL_LINES);
+ immBegin(GWN_PRIM_LINES, num_lines * 2);
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]);
+ immAttrib3fv(color, elem->color);
+ immVertex3fv(pos, elem->v1);
+ immVertex3fv(pos, elem->v2);
}
- glEnd();
+ immEnd();
/**** vectors ****/
glPointSize(2.0f);
- glBegin(GL_POINTS);
+ immBegin(GWN_PRIM_POINTS, num_vectors);
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]);
+ immAttrib3fv(color, elem->color);
+ immVertex3fv(pos, elem->v1);
}
- glEnd();
+ immEnd();
- glBegin(GL_LINES);
+ immBegin(GWN_PRIM_LINES, num_vectors * 2);
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]);
+ immAttrib3fv(color, elem->color);
+ immVertex3fv(pos, elem->v1);
add_v3_v3v3(t, elem->v1, elem->v2);
- glVertex3f(t[0], t[1], t[2]);
+ immVertex3fv(pos, t);
+ }
+ immEnd();
+
+ immUnbindProgram();
+
+ /**** 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);
}
- glEnd();
}
-void draw_sim_debug_data(Scene *UNUSED(scene), View3D *UNUSED(v3d), ARegion *ar)
+void draw_sim_debug_data(Scene *UNUSED(scene), View3D *v3d, ARegion *ar)
{
RegionView3D *rv3d = ar->regiondata;
/*Object *ob = base->object;*/
@@ -149,16 +198,12 @@ void draw_sim_debug_data(Scene *UNUSED(scene), View3D *UNUSED(v3d), ARegion *ar)
invert_m4_m4(imat, rv3d->viewmatob);
-// glDepthMask(GL_FALSE);
-// glEnable(GL_BLEND);
+ gpuPushMatrix();
+ gpuLoadMatrix(rv3d->viewmat);
- 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);
+ gpuPopMatrix();
}
diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c
index 8dbc2788744..3a80624acd9 100644
--- a/source/blender/editors/space_view3d/drawvolume.c
+++ b/source/blender/editors/space_view3d/drawvolume.c
@@ -1,4 +1,4 @@
-/*
+/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
@@ -40,13 +40,14 @@
#include "BLI_utildefines.h"
#include "BLI_math.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_texture.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"
@@ -61,28 +62,33 @@ struct GPUTexture;
# include "PIL_time_utildefines.h"
#endif
-static GPUTexture *create_flame_spectrum_texture(void)
+/* *************************** Transfer functions *************************** */
+
+enum {
+ TFUNC_FLAME_SPECTRUM = 0,
+ TFUNC_COLOR_RAMP = 1,
+};
+
+#define TFUNC_WIDTH 256
+
+static void create_flame_spectrum_texture(float *data)
{
-#define SPEC_WIDTH 256
#define FIRE_THRESH 7
#define MAX_FIRE_ALPHA 0.06f
#define FULL_ON_FIRE 100
- GPUTexture *tex;
- int i, j, k;
- float *spec_data = MEM_mallocN(SPEC_WIDTH * 4 * sizeof(float), "spec_data");
- float *spec_pixels = MEM_mallocN(SPEC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels");
+ float *spec_pixels = MEM_mallocN(TFUNC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels");
- blackbody_temperature_to_rgb_table(spec_data, SPEC_WIDTH, 1500, 3000);
+ blackbody_temperature_to_rgb_table(data, TFUNC_WIDTH, 1500, 3000);
- for (i = 0; i < 16; i++) {
- for (j = 0; j < 16; j++) {
- for (k = 0; k < SPEC_WIDTH; k++) {
- int index = (j * SPEC_WIDTH * 16 + i * SPEC_WIDTH + k) * 4;
+ 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] = (spec_data[k * 4]);
- spec_pixels[index + 1] = (spec_data[k * 4 + 1]);
- spec_pixels[index + 2] = (spec_data[k * 4 + 2]);
+ 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));
}
@@ -93,19 +99,69 @@ static GPUTexture *create_flame_spectrum_texture(void)
}
}
- tex = GPU_texture_create_1D(SPEC_WIDTH, spec_pixels, NULL);
+ memcpy(data, spec_pixels, sizeof(float) * 4 * TFUNC_WIDTH);
- MEM_freeN(spec_data);
MEM_freeN(spec_pixels);
-#undef SPEC_WIDTH
#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++) {
+ do_colorband(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_custom(sds->res[0], sds->res[1], sds->res[2], 1, GPU_R8, field, NULL);
+}
+
typedef struct VolumeSlicer {
float size[3];
float min[3];
@@ -113,6 +169,63 @@ typedef struct VolumeSlicer {
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:
@@ -288,6 +401,135 @@ static int create_view_aligned_slices(VolumeSlicer *slicer,
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])
@@ -299,14 +541,32 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) && sds->tex_flame;
- GPUShader *shader = GPU_shader_get_builtin_shader(
- (use_fire) ? GPU_SHADER_SMOKE_FIRE : GPU_SHADER_SMOKE);
+ 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]),
@@ -320,54 +580,27 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
TIMEIT_START(draw);
#endif
- /* setup smoke shader */
-
- int soot_location = GPU_shader_get_uniform(shader, "soot_texture");
- int spec_location = GPU_shader_get_uniform(shader, "spectrum_texture");
- int shadow_location = GPU_shader_get_uniform(shader, "shadow_texture");
- int flame_location = GPU_shader_get_uniform(shader, "flame_texture");
- int actcol_location = GPU_shader_get_uniform(shader, "active_color");
- int stepsize_location = GPU_shader_get_uniform(shader, "step_size");
- int densityscale_location = GPU_shader_get_uniform(shader, "density_scale");
- 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");
-
- GPU_shader_bind(shader);
-
- 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);
-
- GPUTexture *tex_spec = NULL;
+ /* setup slicing information */
- if (use_fire) {
- GPU_texture_bind(sds->tex_flame, 2);
- GPU_shader_uniform_texture(shader, flame_location, sds->tex_flame);
+ const bool view_aligned = (sds->slice_method == MOD_SMOKE_SLICE_VIEW_ALIGNED);
+ int max_slices, max_points, axis = 0;
- tex_spec = create_flame_spectrum_texture();
- GPU_texture_bind(tex_spec, 3);
- GPU_shader_uniform_texture(shader, spec_location, tex_spec);
+ 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;
+ }
- float active_color[3] = { 0.9, 0.9, 0.9 };
- float density_scale = 10.0f;
- 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);
- GPU_shader_uniform_vector(shader, stepsize_location, 1, 1, &sds->dx);
- GPU_shader_uniform_vector(shader, densityscale_location, 1, 1, &density_scale);
- 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);
-
- /* setup slicing information */
-
- const int max_slices = 256;
- const int max_points = max_slices * 12;
+ max_points = max_slices * 6;
+ }
VolumeSlicer slicer;
copy_v3_v3(slicer.min, min);
@@ -375,7 +608,22 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
copy_v3_v3(slicer.size, size);
slicer.verts = MEM_mallocN(sizeof(float) * 3 * max_points, "smoke_slice_vertices");
- const int num_points = create_view_aligned_slices(&slicer, max_slices, viewnormal);
+ 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 */
@@ -387,43 +635,23 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-
- 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);
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, NULL);
- glDrawArrays(GL_TRIANGLES, 0, num_points);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ draw_buffer(sds, shader, &slicer, ob_sizei, invsize, num_points, false);
- glDisableClientState(GL_VERTEX_ARRAY);
+ /* 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
- /* cleanup */
-
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glDeleteBuffers(1, &vertex_buffer);
-
- GPU_texture_unbind(sds->tex);
- GPU_texture_unbind(sds->tex_shadow);
-
- if (use_fire) {
- GPU_texture_unbind(sds->tex_flame);
- GPU_texture_unbind(tex_spec);
- GPU_texture_free(tex_spec);
- }
-
MEM_freeN(slicer.verts);
- GPU_shader_unbind();
-
glDepthMask(gl_depth_write);
if (!gl_blend) {
@@ -435,105 +663,190 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
}
}
-#ifdef SMOKE_DEBUG_VELOCITY
-void draw_smoke_velocity(SmokeDomainSettings *domain, Object *ob)
+#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])
{
- float x, y, z;
- float x0, y0, z0;
- int *base_res = domain->base_res;
- int *res = domain->res;
- int *res_min = domain->res_min;
- int *res_max = domain->res_max;
- float *vel_x = smoke_get_velocity_x(domain->fluid);
- float *vel_y = smoke_get_velocity_y(domain->fluid);
- float *vel_z = smoke_get_velocity_z(domain->fluid);
+ copy_v3_v3(verts[*offset + 0], p1);
+ copy_v3_v3(verts[*offset + 1], p2);
+ copy_v3_v3(verts[*offset + 2], p3);
- float min[3];
- float *cell_size = domain->cell_size;
- float step_size = ((float)max_iii(base_res[0], base_res[1], base_res[2])) / 16.f;
- float vf = domain->scale / 16.f * 2.f; /* velocity factor */
+ copy_v3_v3(colors[*offset + 0], rgb);
+ copy_v3_v3(colors[*offset + 1], rgb);
+ copy_v3_v3(colors[*offset + 2], rgb);
- glLineWidth(1.0f);
+ *offset += 3;
+}
- /* set first position so that it doesn't jump when domain moves */
- x0 = res_min[0] + fmod(-(float)domain->shift[0] + res_min[0], step_size);
- y0 = res_min[1] + fmod(-(float)domain->shift[1] + res_min[1], step_size);
- z0 = res_min[2] + fmod(-(float)domain->shift[2] + res_min[2], step_size);
- if (x0 < res_min[0]) x0 += step_size;
- if (y0 < res_min[1]) y0 += step_size;
- if (z0 < res_min[2]) z0 += step_size;
- add_v3_v3v3(min, domain->p0, domain->obj_shift_f);
-
- for (x = floor(x0); x < res_max[0]; x += step_size)
- for (y = floor(y0); y < res_max[1]; y += step_size)
- for (z = floor(z0); 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];
+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 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 = sqrtf(vel_x[index] * vel_x[index] + vel_y[index] * vel_y[index] + vel_z[index] * vel_z[index]);
-
- /* draw heat as scaled "arrows" */
- if (vel >= 0.01f) {
- float col_g = 1.0f - vel;
- CLAMP(col_g, 0.0f, 1.0f);
- glColor3f(1.0f, col_g, 0.0f);
- glPointSize(10.0f * vel);
-
- glBegin(GL_LINES);
- glVertex3f(pos[0], pos[1], pos[2]);
- glVertex3f(pos[0] + vel_x[index] * vf, pos[1] + vel_y[index] * vf, pos[2] + vel_z[index] * vf);
- glEnd();
- glBegin(GL_POINTS);
- glVertex3f(pos[0] + vel_x[index] * vf, pos[1] + vel_y[index] * vf, pos[2] + vel_z[index] * vf);
- glEnd();
- }
- }
+ 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);
}
-#endif
-#ifdef SMOKE_DEBUG_HEAT
-void draw_smoke_heat(SmokeDomainSettings *domain, Object *ob)
+static void add_streamline(float (*verts)[3], float(*colors)[3], float center[3],
+ float dir[3], float scale, float voxel_size, int *offset)
{
- float x, y, z;
- float x0, y0, z0;
- int *base_res = domain->base_res;
- int *res = domain->res;
- int *res_min = domain->res_min;
- int *res_max = domain->res_max;
- float *heat = smoke_get_heat(domain->fluid);
+ const float len = len_v3(dir);
- float min[3];
- float *cell_size = domain->cell_size;
- float step_size = ((float)max_iii(base_res[0], base_res[1], base_res[2])) / 16.f;
- float vf = domain->scale / 16.f * 2.f; /* velocity factor */
+ 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 */
- x0 = res_min[0] + fmod(-(float)domain->shift[0] + res_min[0], step_size);
- y0 = res_min[1] + fmod(-(float)domain->shift[1] + res_min[1], step_size);
- z0 = res_min[2] + fmod(-(float)domain->shift[2] + res_min[2], step_size);
- if (x0 < res_min[0]) x0 += step_size;
- if (y0 < res_min[1]) y0 += step_size;
- if (z0 < res_min[2]) z0 += step_size;
- add_v3_v3v3(min, domain->p0, domain->obj_shift_f);
-
- for (x = floor(x0); x < res_max[0]; x += step_size)
- for (y = floor(y0); y < res_max[1]; y += step_size)
- for (z = floor(z0); z < res_max[2]; z += step_size) {
+ 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 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]
+ };
- /* draw heat as different sized points */
- if (heat[index] >= 0.01f) {
- float col_gb = 1.0f - heat[index];
- CLAMP(col_gb, 0.0f, 1.0f);
- glColor3f(1.0f, col_gb, col_gb);
- glPointSize(24.0f * heat[index]);
+ float vel[3] = {
+ vel_x[index], vel_y[index], vel_z[index]
+ };
- glBegin(GL_POINTS);
- glVertex3f(pos[0], pos[1], pos[2]);
- glEnd();
- }
+ 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 d80e2531c44..10d4af0bb77 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -43,22 +43,26 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
+#include "BKE_curve.h"
#include "BKE_icons.h"
+#include "BKE_lattice.h"
#include "BKE_library.h"
#include "BKE_main.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 "BIF_gl.h"
+#include "GPU_viewport.h"
+#include "GPU_matrix.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -180,8 +184,8 @@ bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_ar)
View3D *v3d = (View3D *)sa->spacedata.first;
if (ar) {
- RegionView3D *rv3d = ar->regiondata;
- if (rv3d && (rv3d->viewlock & RV3D_LOCKED) == 0) {
+ RegionView3D *rv3d;
+ if ((ar->regiontype == RGN_TYPE_WINDOW) && (rv3d = ar->regiondata) && (rv3d->viewlock & RV3D_LOCKED) == 0) {
*r_v3d = v3d;
*r_ar = ar;
return true;
@@ -250,7 +254,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);
+ gpuMultMatrix(ob->obmat);
}
#ifdef DEBUG
@@ -304,7 +308,7 @@ void ED_view3d_shade_update(Main *bmain, Scene *scene, View3D *v3d, ScrArea *sa)
}
else if (scene->obedit != NULL && scene->obedit->type == OB_MESH) {
/* Tag mesh to load edit data. */
- DAG_id_tag_update(scene->obedit->data, 0);
+ DEG_id_tag_update(scene->obedit->data, 0);
}
}
@@ -340,7 +344,7 @@ static SpaceLink *view3d_new(const bContext *C)
v3d->near = 0.01f;
v3d->far = 1000.0f;
- v3d->twflag |= U.tw_flag & V3D_USE_MANIPULATOR;
+ v3d->twflag |= U.manipulator_flag & V3D_MANIPULATOR_DRAW;
v3d->twtype = V3D_MANIP_TRANSLATE;
v3d->around = V3D_AROUND_CENTER_MEAN;
@@ -487,6 +491,13 @@ static void view3d_main_region_init(wmWindowManager *wm, ARegion *ar)
ListBase *lb;
wmKeyMap *keymap;
+ if (ar->manipulator_map == NULL) {
+ ar->manipulator_map = WM_manipulatormap_new_from_type(
+ &(const struct wmManipulatorMapType_Params) {SPACE_VIEW3D, RGN_TYPE_WINDOW});
+ }
+
+ WM_manipulatormap_add_handlers(ar, ar->manipulator_map);
+
/* object ops. */
/* important to be before Pose keymap since they can both be enabled at once */
@@ -585,6 +596,12 @@ static void view3d_main_region_exit(wmWindowManager *wm, ARegion *ar)
GPU_fx_compositor_destroy(rv3d->compositor);
rv3d->compositor = NULL;
}
+
+ if (rv3d->viewport) {
+ GPU_viewport_free(rv3d->viewport);
+ MEM_freeN(rv3d->viewport);
+ rv3d->viewport = NULL;
+ }
}
static int view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
@@ -644,7 +661,7 @@ static int view3d_ima_bg_drop_poll(bContext *C, wmDrag *drag, const wmEvent *eve
static int view3d_ima_empty_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
- Base *base = ED_view3d_give_base_under_cursor(C, event->mval);
+ BaseLegacy *base = ED_view3d_give_base_under_cursor(C, event->mval);
/* either holding and ctrl and no object, or dropping to empty */
if (((base == NULL) && event->ctrl) ||
@@ -658,7 +675,7 @@ static int view3d_ima_empty_drop_poll(bContext *C, wmDrag *drag, const wmEvent *
static int view3d_ima_mesh_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
- Base *base = ED_view3d_give_base_under_cursor(C, event->mval);
+ BaseLegacy *base = ED_view3d_give_base_under_cursor(C, event->mval);
if (base && base->object->type == OB_MESH)
return view3d_ima_drop_poll(C, drag, event);
@@ -715,6 +732,16 @@ static void view3d_dropboxes(void)
WM_dropbox_add(lb, "OBJECT_OT_group_instance_add", view3d_group_drop_poll, view3d_group_drop_copy);
}
+static void view3d_widgets(void)
+{
+ wmManipulatorMapType *mmap_type = WM_manipulatormaptype_ensure(
+ &(const struct wmManipulatorMapType_Params){SPACE_VIEW3D, RGN_TYPE_WINDOW});
+
+ WM_manipulatorgrouptype_append_and_link(mmap_type, TRANSFORM_WGT_manipulator);
+ WM_manipulatorgrouptype_append_and_link(mmap_type, VIEW3D_WGT_lamp);
+ WM_manipulatorgrouptype_append_and_link(mmap_type, VIEW3D_WGT_force_field);
+ WM_manipulatorgrouptype_append_and_link(mmap_type, VIEW3D_WGT_camera);
+}
/* type callback, not region itself */
@@ -742,6 +769,10 @@ static void view3d_main_region_free(ARegion *ar)
if (rv3d->compositor) {
GPU_fx_compositor_destroy(rv3d->compositor);
}
+ if (rv3d->viewport) {
+ GPU_viewport_free(rv3d->viewport);
+ MEM_freeN(rv3d->viewport);
+ }
MEM_freeN(rv3d);
ar->regiondata = NULL;
@@ -766,18 +797,18 @@ static void *view3d_main_region_duplicate(void *poin)
new->sms = NULL;
new->smooth_timer = NULL;
new->compositor = NULL;
+ new->viewport = NULL;
return new;
}
return NULL;
}
-static void view3d_recalc_used_layers(ARegion *ar, wmNotifier *wmn, Scene *scene)
+static void view3d_recalc_used_layers(ARegion *ar, wmNotifier *wmn, const Scene *scene)
{
wmWindow *win = wmn->wm->winactive;
- ScrArea *sa;
unsigned int lay_used = 0;
- Base *base;
+ BaseLegacy *base;
if (!win) return;
@@ -791,7 +822,8 @@ static void view3d_recalc_used_layers(ARegion *ar, wmNotifier *wmn, Scene *scene
base = base->next;
}
- 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_VIEW3D) {
if (BLI_findindex(&sa->regionbase, ar) != -1) {
View3D *v3d = sa->spacedata.first;
@@ -802,13 +834,21 @@ static void view3d_recalc_used_layers(ARegion *ar, wmNotifier *wmn, Scene *scene
}
}
-static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmNotifier *wmn)
+static void view3d_main_region_listener(
+ bScreen *UNUSED(sc), ScrArea *sa, ARegion *ar,
+ wmNotifier *wmn, const Scene *scene)
{
- Scene *scene = sc->scene;
View3D *v3d = sa->spacedata.first;
-
+ RegionView3D *rv3d = ar->regiondata;
+ wmManipulatorMap *mmap = ar->manipulator_map;
+
/* context changes */
switch (wmn->category) {
+ case NC_WM:
+ if (ELEM(wmn->data, ND_UNDO)) {
+ WM_manipulatormap_tag_refresh(mmap);
+ }
+ break;
case NC_ANIMATION:
switch (wmn->data) {
case ND_KEYFRAME_PROP:
@@ -828,21 +868,31 @@ 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_manipulatormap_tag_refresh(mmap);
+ break;
+ case ND_LAYER:
+ if (wmn->reference) {
+ BKE_screen_view3d_sync(v3d, wmn->reference);
+ }
+ ED_region_tag_redraw(ar);
break;
- case ND_FRAME:
- case ND_TRANSFORM:
case ND_OB_ACTIVE:
case ND_OB_SELECT:
+ DEG_id_tag_update((ID *)&scene->id, DEG_TAG_COPY_ON_WRITE);
+ 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_manipulatormap_tag_refresh(mmap);
break;
case ND_WORLD:
/* handled by space_view3d_listener() for v3d access */
@@ -850,7 +900,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);
}
@@ -872,8 +921,10 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w
case ND_CONSTRAINT:
case ND_KEYS:
case ND_PARTICLE:
+ case ND_POINTCACHE:
case ND_LOD:
ED_region_tag_redraw(ar);
+ WM_manipulatormap_tag_refresh(mmap);
break;
}
switch (wmn->action) {
@@ -884,9 +935,30 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w
break;
case NC_GEOM:
switch (wmn->data) {
+ case ND_SELECT:
+ {
+ WM_manipulatormap_tag_refresh(mmap);
+
+ if (scene->obedit) {
+ Object *ob = scene->obedit;
+ switch (ob->type) {
+ case OB_MESH:
+ BKE_mesh_batch_cache_dirty(ob->data, BKE_CURVE_BATCH_DIRTY_SELECT);
+ break;
+ // case OB_FONT: /* handled by text_update_edited */
+ case OB_CURVE:
+ case OB_SURF:
+ BKE_curve_batch_cache_dirty(ob->data, BKE_CURVE_BATCH_DIRTY_SELECT);
+ break;
+ case OB_LATTICE:
+ BKE_lattice_batch_cache_dirty(ob->data, BKE_CURVE_BATCH_DIRTY_SELECT);
+ break;
+ }
+ }
+ ATTR_FALLTHROUGH;
+ }
case ND_DATA:
case ND_VERTEX_GROUP:
- case ND_SELECT:
ED_region_tag_redraw(ar);
break;
}
@@ -901,7 +973,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);
}
@@ -930,21 +1001,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);
@@ -956,20 +1019,23 @@ 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_manipulatormap_tag_refresh(mmap);
break;
}
break;
@@ -989,10 +1055,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_manipulatormap_tag_refresh(mmap);
}
break;
case NC_ID:
@@ -1005,15 +1071,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_manipulatormap_tag_refresh(mmap);
+ ED_region_tag_redraw(ar);
+ break;
+ case ND_LAYER:
ED_region_tag_redraw(ar);
break;
}
@@ -1030,7 +1094,7 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w
/* concept is to retrieve cursor type context-less */
static void view3d_main_region_cursor(wmWindow *win, ScrArea *UNUSED(sa), ARegion *UNUSED(ar))
{
- Scene *scene = win->screen->scene;
+ const Scene *scene = WM_window_get_active_scene(win);
if (scene->obedit) {
WM_cursor_set(win, CURSOR_EDIT);
@@ -1055,7 +1119,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(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -1101,7 +1167,9 @@ static void view3d_buttons_region_draw(const bContext *C, ARegion *ar)
ED_region_panels(C, ar, 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(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -1207,7 +1275,9 @@ 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)
+static void view3d_props_region_listener(
+ bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -1227,7 +1297,8 @@ static void view3d_props_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa
}
/* area (not region) level listener */
-static void space_view3d_listener(bScreen *UNUSED(sc), ScrArea *sa, struct wmNotifier *wmn)
+static void space_view3d_listener(
+ bScreen *UNUSED(sc), ScrArea *sa, struct wmNotifier *wmn, const Scene *UNUSED(scene))
{
View3D *v3d = sa->spacedata.first;
@@ -1259,26 +1330,9 @@ static void space_view3d_listener(bScreen *UNUSED(sc), ScrArea *sa, struct wmNot
}
break;
}
-
- /* removed since BKE_image_user_frame_calc is now called in view3d_draw_bgpic because screen_ops doesnt call the notifier. */
-#if 0
- if (wmn->category == NC_SCENE && wmn->data == ND_FRAME) {
- View3D *v3d = area->spacedata.first;
- BGpic *bgpic = v3d->bgpicbase.first;
-
- for (; bgpic; bgpic = bgpic->next) {
- if (bgpic->ima) {
- Scene *scene = wmn->reference;
- BKE_image_user_frame_calc(&bgpic->iuser, scene->r.cfra, 0);
- }
- }
- }
-#endif
}
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
};
@@ -1289,109 +1343,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;
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ if (sl->basact) {
+ Object *ob = sl->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 ((sl->basact->flag & BASE_VISIBLED) != 0 || (ob->mode & OB_MODE_EDIT)) {
+ CTX_data_pointer_set(result, &scene->id, &RNA_ObjectBase, sl->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);
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ if (sl->basact) {
+ Object *ob = sl->basact->object;
+ /* if hidden but in edit mode, we still display, can happen with animation */
+ if ((sl->basact->flag & BASE_VISIBLED) != 0 || (ob->mode & OB_MODE_EDIT) != 0) {
+ CTX_data_id_pointer_set(result, &ob->id);
+ }
}
return 1;
@@ -1483,6 +1455,7 @@ void ED_spacetype_view3d(void)
st->operatortypes = view3d_operatortypes;
st->keymap = view3d_keymap;
st->dropboxes = view3d_dropboxes;
+ st->manipulators = view3d_widgets;
st->context = view3d_context;
st->id_remap = view3d_id_remap;
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index b9c8c98b62f..a8e5e1ad536 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -55,13 +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 "DEG_depsgraph.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -476,7 +477,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN,
totedgedata == 1 ? IFACE_("Crease:") : IFACE_("Mean Crease:"),
0, yi -= buth + but_margin, 200, buth,
- &(tfp->ve_median[M_CREASE]), 0.0, 1.0, 1, 2, TIP_("Weight used by SubSurf modifier"));
+ &(tfp->ve_median[M_CREASE]), 0.0, 1.0, 1, 2, TIP_("Weight used by the Subdivision Surface modifier"));
}
}
/* Curve... */
@@ -491,7 +492,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
else if (totcurvedata > 1) {
uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Weight:"),
0, yi -= buth + but_margin, 200, buth,
- &(tfp->ve_median[C_WEIGHT]), 0.0, 1.0, 1, 3, TIP_("Weight used for SoftBody Goal"));
+ &(tfp->ve_median[C_WEIGHT]), 0.0, 1.0, 1, 3, TIP_("Weight used for Soft Body Goal"));
uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Radius:"),
0, yi -= buth + but_margin, 200, buth,
&(tfp->ve_median[C_RADIUS]), 0.0, 100.0, 1, 3, TIP_("Radius of curve control points"));
@@ -509,7 +510,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
else if (totlattdata > 1) {
uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Weight:"),
0, yi -= buth + but_margin, 200, buth,
- &(tfp->ve_median[L_WEIGHT]), 0.0, 1.0, 1, 3, TIP_("Weight used for SoftBody Goal"));
+ &(tfp->ve_median[L_WEIGHT]), 0.0, 1.0, 1, 3, TIP_("Weight used for Soft Body Goal"));
}
UI_block_align_end(block);
@@ -776,18 +777,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;
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *ob = sl->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 int view3d_panel_vgroup_poll(const bContext *C, PanelType *UNUSED(pt))
{
- Scene *scene = CTX_data_scene(C);
- Object *ob = OBACT;
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *ob = OBACT_NEW;
if (ob && (BKE_object_is_in_editmode_vgroup(ob) ||
BKE_object_is_in_wpaint_select_vert(ob)))
{
@@ -805,7 +806,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;
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *ob = sl->basact->object;
MDeformVert *dv;
@@ -814,10 +816,6 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa)
if (dv && dv->totweight) {
ToolSettings *ts = scene->toolsettings;
- wmOperatorType *ot_weight_set_active = WM_operatortype_find("OBJECT_OT_vertex_weight_set_active", true);
- wmOperatorType *ot_weight_paste = WM_operatortype_find("OBJECT_OT_vertex_weight_paste", true);
- wmOperatorType *ot_weight_delete = WM_operatortype_find("OBJECT_OT_vertex_weight_delete", true);
-
wmOperatorType *ot;
PointerRNA op_ptr, tools_ptr;
PointerRNA *but_ptr;
@@ -856,7 +854,7 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa)
/* The Weight Group Name */
- ot = ot_weight_set_active;
+ ot = WM_operatortype_find("OBJECT_OT_vertex_weight_set_active", true);
but = uiDefButO_ptr(block, UI_BTYPE_BUT, ot, WM_OP_EXEC_DEFAULT, dg->name,
xco, yco, (x = UI_UNIT_X * 5), UI_UNIT_Y, "");
but_ptr = UI_but_operator_ptr_get(but);
@@ -882,23 +880,16 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa)
xco += x;
/* The weight group paste function */
-
- ot = ot_weight_paste;
- WM_operator_properties_create_ptr(&op_ptr, ot);
- RNA_int_set(&op_ptr, "weight_group", i);
icon = (locked) ? ICON_BLANK1 : ICON_PASTEDOWN;
- uiItemFullO_ptr(row, ot, "", icon, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
+ op_ptr = uiItemFullO(row, "OBJECT_OT_vertex_weight_paste", "", icon, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ RNA_int_set(&op_ptr, "weight_group", i);
/* The weight entry delete function */
-
- ot = ot_weight_delete;
- WM_operator_properties_create_ptr(&op_ptr, ot);
- RNA_int_set(&op_ptr, "weight_group", i);
icon = (locked) ? ICON_LOCKED : ICON_X;
- uiItemFullO_ptr(row, ot, "", icon, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
+ op_ptr = uiItemFullO(row, "OBJECT_OT_vertex_weight_delete", "", icon, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+ RNA_int_set(&op_ptr, "weight_group", i);
yco -= UI_UNIT_Y;
-
}
}
}
@@ -1106,9 +1097,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);
+ SceneLayer *sl = CTX_data_scene_layer(C);
View3D *v3d = CTX_wm_view3d(C);
- Object *ob = OBACT;
+ Object *ob = OBACT_NEW;
switch (event) {
@@ -1119,7 +1110,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;
}
@@ -1130,16 +1121,17 @@ static void do_view3d_region_buttons(bContext *C, void *UNUSED(index), int event
static int view3d_panel_transform_poll(const bContext *C, PanelType *UNUSED(pt))
{
- Scene *scene = CTX_data_scene(C);
- return (scene->basact != NULL);
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ return (sl->basact != NULL);
}
static void view3d_panel_transform(const bContext *C, Panel *pa)
{
uiBlock *block;
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *obedit = CTX_data_edit_object(C);
- Object *ob = scene->basact->object;
+ Object *ob = sl->basact->object;
uiLayout *col;
block = uiLayoutGetBlock(pa->layout);
diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c
index f717f1c0a43..8beb0ff84b0 100644
--- a/source/blender/editors/space_view3d/view3d_camera_control.c
+++ b/source/blender/editors/space_view3d/view3d_camera_control.c
@@ -55,7 +55,7 @@
#include "BKE_object.h"
-#include "BKE_depsgraph.h" /* for object updating */
+#include "DEG_depsgraph.h"
#include "ED_screen.h"
@@ -242,7 +242,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 +264,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,7 +299,7 @@ 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*/
@@ -311,7 +311,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 1de06af0478..835c4573801 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -28,942 +28,280 @@
* \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_math.h"
-#include "BLI_jitter.h"
-#include "BLI_utildefines.h"
-#include "BLI_endian_switch.h"
-#include "BLI_threads.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
-#include "BKE_anim.h"
#include "BKE_camera.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 "BLF_api.h"
-#include "IMB_imbuf_types.h"
-#include "IMB_imbuf.h"
-#include "IMB_colormanagement.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_rect.h"
+#include "BLI_string.h"
+#include "BLI_threads.h"
+#include "BLI_jitter.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_keyframing.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 "ED_gpencil.h"
-#include "UI_interface.h"
-#include "UI_interface_icons.h"
-#include "UI_resources.h"
+#include "DEG_depsgraph_query.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_viewport.h"
#include "GPU_compositing.h"
-#include "GPU_extensions.h"
-
-#include "view3d_intern.h" /* own include */
-
-/* prototypes */
-static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar);
-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);
- }
-}
+#include "MEM_guardedalloc.h"
-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);
- }
-}
+#include "UI_interface.h"
+#include "UI_resources.h"
-/* use these to temp disable/enable clipping when 'rv3d->rflag & RV3D_CLIPPING' is set */
-void ED_view3d_clipping_disable(void)
-{
- unsigned int a;
+#include "RE_engine.h"
- for (a = 0; a < 6; a++) {
- glDisable(GL_CLIP_PLANE0 + a);
- }
-}
-void ED_view3d_clipping_enable(void)
-{
- unsigned int a;
+#include "WM_api.h"
+#include "WM_types.h"
- for (a = 0; a < 6; a++) {
- glEnable(GL_CLIP_PLANE0 + a);
- }
-}
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
-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;
+#include "view3d_intern.h" /* own include */
- return true;
-}
+/* ******************** general functions ***************** */
-/* 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)
+static bool use_depth_doit(Scene *scene, View3D *v3d)
{
- 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];
+ if (v3d->drawtype > OB_WIRE)
+ return true;
- x += (wx);
- y += (wy);
-
- /* set fixed 'Y' */
- verts[0][1] = 0.0f;
- verts[1][1] = (double)ar->winy;
-
- /* iter over 'X' */
- verts[0][0] = verts[1][0] = x - dx * floor(x / dx);
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(2, GL_DOUBLE, 0, verts);
-
- while (verts[0][0] < ar->winx) {
- glDrawArrays(GL_LINES, 0, 2);
- verts[0][0] = verts[1][0] = verts[0][0] + dx;
- }
-
- /* set fixed 'X' */
- verts[0][0] = 0.0f;
- verts[1][0] = (double)ar->winx;
-
- /* 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;
+ /* 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) {
+ return true;
+ }
+ }
}
-
- glDisableClientState(GL_VERTEX_ARRAY);
+ return false;
}
-#define GRID_MIN_PX_D 6.0
-#define GRID_MIN_PX_F 6.0f
-
-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(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;
+ /* setup window matrices */
+ if (winmat)
+ copy_m4_m4(rv3d->winmat, winmat);
+ else
+ view3d_winmatrix_set(ar, v3d, rect);
- /* 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);
+ /* setup view matrix */
+ if (viewmat)
+ copy_m4_m4(rv3d->viewmat, viewmat);
+ else
+ view3d_viewmatrix_set(scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */
- /* tweak to have the fade a bit nicer */
- blend_fac = (blend_fac * blend_fac) * 2.0f;
- CLAMP(blend_fac, 0.3f, 1.0f);
+ /* 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 */
- UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, blend_fac);
+ /* 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);
- drawgrid_draw(ar, wx, wy, x, y, dx_scalar);
- }
- }
+ rv3d->viewcamtexcofac[2] = -rv3d->viewcamtexcofac[0] * cameraborder.xmin / (float)ar->winx;
+ rv3d->viewcamtexcofac[3] = -rv3d->viewcamtexcofac[1] * cameraborder.ymin / (float)ar->winy;
}
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);
- }
- }
+ rv3d->viewcamtexcofac[0] = rv3d->viewcamtexcofac[1] = 1.0f;
+ rv3d->viewcamtexcofac[2] = rv3d->viewcamtexcofac[3] = 0.0f;
}
+ /* 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;
- 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);
-
- /* 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);
-
- fdrawline(x, 0.0, x, (float)ar->winy);
-
- 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(
+ 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;
+ RegionView3D *rv3d = ar->regiondata;
- glDrawArrays(GL_LINES, 0, 4);
- }
+ ED_view3d_update_viewmat(scene, v3d, ar, viewmat, winmat, rect);
- glDisableClientState(GL_VERTEX_ARRAY);
- }
-
- /* 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();
- }
-
- glDepthMask(GL_TRUE);
+ /* set for opengl */
+ gpuLoadProjectionMatrix(rv3d->winmat);
+ gpuLoadMatrix(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);
-}
-
-/* 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);
-}
-
-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;
- }
+/* 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;
- 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
-}
+ /* show only left or right camera */
+ if (v3d->stereo3d_camera != STEREO_3D_ID)
+ v3d->multiview_eye = v3d->stereo3d_camera;
-/* draw info beside axes in bottom left-corner:
- * framenum, object name, bone name (if available), marker name (if available)
- */
+ is_left = v3d->multiview_eye == STEREO_LEFT_ID;
+ viewname = names[is_left ? STEREO_LEFT_ID : STEREO_RIGHT_ID];
-static void draw_selected_name(Scene *scene, Object *ob, rcti *rect)
-{
- const int cfra = CFRA;
- const char *msg_pin = " (Pinned)";
- const char *msg_sep = " : ";
+ /* 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;
- char info[300];
- const char *markern;
- char *s = info;
- short offset = 1.5f * UI_UNIT_X + rect->xmin;
+ data = (Camera *)v3d->camera->data;
+ shiftx = data->shiftx;
- s += sprintf(s, "(%d)", cfra);
+ BLI_lock_thread(LOCK_VIEW3D);
+ data->shiftx = BKE_camera_multiview_shift_x(&scene->r, v3d->camera, viewname);
- /*
- * 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)
- */
+ BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat);
+ view3d_main_region_setup_view(scene, v3d, ar, viewmat, NULL, rect);
- /* get name of marker on current frame (if available) */
- markern = BKE_scene_find_marker_name(scene, cfra);
-
- /* check if there is an object */
- if (ob) {
- *s++ = ' ';
- s += BLI_strcpy_rlen(s, ob->id.name + 2);
+ data->shiftx = shiftx;
+ BLI_unlock_thread(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);
- /* name(s) to display depends on type of object */
- if (ob->type == OB_ARMATURE) {
- bArmature *arm = ob->data;
-
- /* 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) {
+ BLI_lock_thread(LOCK_VIEW3D);
+ v3d->camera = camera;
- 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;
+ BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat);
+ view3d_main_region_setup_view(scene, v3d, ar, viewmat, NULL, rect);
- /* try to display active bone and active shapekey too (if they exist) */
+ v3d->camera = view_ob;
+ BLI_unlock_thread(LOCK_VIEW3D);
+ }
+}
- 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);
- }
- }
- }
- }
+/**
+ * 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;
- 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));
- }
- }
- }
- }
-
- /* 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(scene, v3d, ar, rect);
}
else {
- /* no object */
- /* color is always white */
- UI_ThemeColor(TH_TEXT_HI);
+ view3d_main_region_setup_view(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,
rctf *r_viewborder, const bool no_shift, const bool no_zoom)
@@ -1017,7 +355,7 @@ void ED_view3d_calc_camera_border(
view3d_camera_border(scene, 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;
@@ -1026,29 +364,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(GWN_PRIM_LINES, 8);
+
+ immVertex2f(shdr_pos, x1, y3);
+ immVertex2f(shdr_pos, x2, y3);
+
+ immVertex2f(shdr_pos, x1, y4);
+ immVertex2f(shdr_pos, x2, y4);
- glVertex2f(x1, y4);
- glVertex2f(x2, y4);
+ immVertex2f(shdr_pos, x3, y1);
+ immVertex2f(shdr_pos, x3, y2);
- glVertex2f(x3, y1);
- glVertex2f(x3, y2);
+ immVertex2f(shdr_pos, x4, y1);
+ immVertex2f(shdr_pos, x4, y2);
- glVertex2f(x4, y1);
- glVertex2f(x4, y2);
- glEnd();
+ 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(GWN_PRIM_LINES, 6);
+
if (w > h) {
if (golden) {
ofs = w * (1.0f - (1.0f / 1.61803399f));
@@ -1058,14 +400,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) {
@@ -1076,16 +418,17 @@ 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)
@@ -1122,58 +465,76 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
y1i = (int)(y1 - 1.0001f);
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);
- if (ca->passepartalpha == 1.0f) {
- glColor3f(0, 0, 0);
+ uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ /* First, solid lines. */
+ {
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ /* 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);
+
+ float alpha = 1.0f;
+
+ if (ca->passepartalpha != 1.0f) {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+ alpha = ca->passepartalpha;
+ }
+
+ immUniformColor4f(0.0f, 0.0f, 0.0f, alpha);
+
+ 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);
+
+ glDisable(GL_BLEND);
}
- else {
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
- glColor4f(0, 0, 0, ca->passepartalpha);
+
+ immUniformThemeColor(TH_BACK);
+ imm_draw_line_box(shdr_pos, x1i, y1i, x2i, y2i);
+
+#ifdef VIEW3D_CAMERA_BORDER_HACK
+ if (view3d_camera_border_hack_test == true) {
+ immUniformColor3ubv(view3d_camera_border_hack_col);
+ imm_draw_line_box(shdr_pos, x1i + 1, y1i + 1, x2i - 1, y2i - 1);
+ view3d_camera_border_hack_test = false;
}
+#endif
- 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);
-
- glDisable(GL_BLEND);
+ immUnbindProgram();
}
- setlinestyle(0);
+ /* And now, the dashed lines! */
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
- UI_ThemeColor(TH_BACK);
-
- fdrawbox(x1i, y1i, x2i, y2i);
+ {
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
-#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;
- }
-#endif
+ immUniform1i("num_colors", 0); /* "simple" mode */
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
- setlinestyle(3);
+ /* outer line not to confuse with object selection */
+ if (v3d->flag2 & V3D_LOCK_CAMERA) {
+ immUniformThemeColor(TH_REDALERT);
+ imm_draw_line_box(shdr_pos, x1i - 1, y1i - 1, x2i + 1, y2i + 1);
+ }
- /* 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);
+ immUniformThemeColor(TH_VIEW_OVERLAY);
+ imm_draw_line_box(shdr_pos, x1i, y1i, x2i, y2i);
}
- UI_ThemeColor(TH_VIEW_OVERLAY);
- fdrawbox(x1i, y1i, x2i, y2i);
-
/* border */
if (scene->r.mode & R_BORDER) {
float x3, y3, x4, y4;
@@ -1183,82 +544,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_line_box(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(GWN_PRIM_LINES, 4);
- glVertex2f(x3, y1);
- glVertex2f(x3, y2);
- glEnd();
+ immVertex2f(shdr_pos, x1, y3);
+ immVertex2f(shdr_pos, x2, y3);
+
+ immVertex2f(shdr_pos, x3, y1);
+ immVertex2f(shdr_pos, x3, y2);
+
+ immEnd();
}
if (ca->dtx & CAM_DTX_CENTER_DIAG) {
- UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0);
+ immBegin(GWN_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);
}
}
@@ -1294,1684 +649,1283 @@ 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_line_box(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)
+static void drawrenderborder(ARegion *ar, View3D *v3d)
{
- RegionView3D *rv3d = ar->regiondata;
- struct Base *base = scene->basact;
- int multisample_enabled;
+ /* use the same program for everything */
+ uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
- BLI_assert(ar->regiontype == RGN_TYPE_WINDOW);
+ glLineWidth(1.0f);
- if (base && (base->object->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT) ||
- BKE_paint_select_face_test(base->object)))
- {
- /* do nothing */
- }
- /* texture paint mode sampling */
- else if (base && (base->object->mode & OB_MODE_TEXTURE_PAINT) &&
- (v3d->drawtype > OB_WIRE))
- {
- /* do nothing */
- }
- else if ((base && (base->object->mode & OB_MODE_PARTICLE_EDIT)) &&
- V3D_IS_ZBUF(v3d))
- {
- /* do nothing */
- }
- else if (scene->obedit &&
- V3D_IS_ZBUF(v3d))
- {
- /* do nothing */
- }
- else {
- v3d->flag &= ~V3D_INVALID_BACKBUF;
- return;
- }
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
- if (!(v3d->flag & V3D_INVALID_BACKBUF))
- return;
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
-#if 0
- if (test) {
- if (qtest()) {
- addafterqueue(ar->win, BACKBUFDRAW, 1);
- return;
- }
- }
-#endif
+ immUniform1i("num_colors", 0); /* "simple" mode */
+ immUniform4f("color", 1.0f, 0.25f, 0.25f, 1.0f);
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
- if (v3d->drawtype > OB_WIRE) v3d->zbuf = true;
-
- /* dithering and AA break color coding, so disable */
- glDisable(GL_DITHER);
-
- multisample_enabled = glIsEnabled(GL_MULTISAMPLE);
- if (multisample_enabled)
- glDisable(GL_MULTISAMPLE);
-
- 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];
-
- if (rv3d->gpuoffscreen) {
- if (GPU_offscreen_width(rv3d->gpuoffscreen) != w ||
- GPU_offscreen_height(rv3d->gpuoffscreen) != h)
- {
- GPU_offscreen_free(rv3d->gpuoffscreen);
- rv3d->gpuoffscreen = NULL;
- }
- }
+ imm_draw_line_box(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 (!rv3d->gpuoffscreen) {
- rv3d->gpuoffscreen = GPU_offscreen_create(w, h, 0, error);
+ immUnbindProgram();
+}
- if (!rv3d->gpuoffscreen)
- fprintf(stderr, "Failed to create offscreen selection buffer for multisample: %s\n", error);
- }
- }
+void ED_view3d_draw_depth(
+ struct Depsgraph *graph,
+ ARegion *ar, View3D *v3d, bool alphaoverride)
+{
+ Scene *scene = DEG_get_evaluated_scene(graph);
+ RegionView3D *rv3d = ar->regiondata;
- 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));
+ 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;
- 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);
+ ED_view3d_draw_setup_view(NULL, scene, ar, v3d, NULL, NULL, NULL);
+
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ if (rv3d->rflag & RV3D_CLIPPING) {
+ ED_view3d_clipping_set(rv3d);
}
- else {
- glClear(GL_COLOR_BUFFER_BIT);
- glDisable(GL_DEPTH_TEST);
+ /* get surface depth without bias */
+ rv3d->rflag |= RV3D_ZOFFSET_DISABLED;
+
+ v3d->zbuf = true;
+ glEnable(GL_DEPTH_TEST);
+
+#ifdef WITH_OPENGL_LEGACY
+ if (IS_VIEWPORT_LEGACY(vc->v3d)) {
+ /* temp, calls into view3d_draw_legacy.c */
+ ED_view3d_draw_depth_loop(scene, ar, v3d);
}
-
- if (rv3d->rflag & RV3D_CLIPPING)
- ED_view3d_clipping_set(rv3d);
-
- G.f |= G_BACKBUFSEL;
-
- if (base && (base->lay & v3d->lay))
- draw_object_backbufsel(scene, v3d, rv3d, base->object);
-
- if (rv3d->gpuoffscreen)
- GPU_offscreen_unbind(rv3d->gpuoffscreen, true);
else
- ar->swap = 0; /* mark invalid backbuf for wm draw */
+#endif /* WITH_OPENGL_LEGACY */
+ {
+ DRW_draw_depth_loop(graph, ar, v3d);
+ }
- v3d->flag &= ~V3D_INVALID_BACKBUF;
+ if (rv3d->rflag & RV3D_CLIPPING) {
+ ED_view3d_clipping_disable();
+ }
+ rv3d->rflag &= ~RV3D_ZOFFSET_DISABLED;
- G.f &= ~G_BACKBUFSEL;
- v3d->zbuf = false;
- glDisable(GL_DEPTH_TEST);
- glEnable(GL_DITHER);
- if (multisample_enabled)
- glEnable(GL_MULTISAMPLE);
+ v3d->zbuf = zbuf;
+ if (!v3d->zbuf) glDisable(GL_DEPTH_TEST);
- if (rv3d->rflag & RV3D_CLIPPING)
- ED_view3d_clipping_disable();
+ U.glalphaclip = glalphaclip;
+ v3d->flag = flag;
+ U.obcenter_dia = obcenter_dia;
}
-void view3d_opengl_read_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data)
+/* ******************** background plates ***************** */
+
+static void view3d_draw_background_gradient(void)
{
- RegionView3D *rv3d = ar->regiondata;
+ /* TODO: finish 2D API & draw background with that */
- 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);
- }
-}
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ unsigned char col_hi[3], col_lo[3];
-/* 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)
-{
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
- glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data);
-}
+ UI_GetThemeColor3ubv(TH_LOW_GRAD, col_lo);
+ UI_GetThemeColor3ubv(TH_HIGH_GRAD, col_hi);
-void ED_view3d_backbuf_validate(ViewContext *vc)
-{
- if (vc->v3d->flag & V3D_INVALID_BACKBUF)
- backdrawview3d(vc->scene, vc->win, vc->ar, vc->v3d);
+ immBegin(GWN_PRIM_TRI_FAN, 4);
+ immAttrib3ubv(color, col_lo);
+ immVertex2f(pos, -1.0f, -1.0f);
+ immVertex2f(pos, 1.0f, -1.0f);
+
+ immAttrib3ubv(color, col_hi);
+ immVertex2f(pos, 1.0f, 1.0f);
+ immVertex2f(pos, -1.0f, 1.0f);
+ immEnd();
+
+ immUnbindProgram();
}
-/**
- * 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)
+static void view3d_draw_background_none(void)
{
- return (int)min_ff(ceilf(dist), (float)max_ii(ar->winx, ar->winx));
+ UI_ThemeClearColorAlpha(TH_HIGH_GRAD, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
}
-/* samples a single pixel (copied from vpaint) */
-unsigned int ED_view3d_backbuf_sample(ViewContext *vc, int x, int y)
+static void view3d_draw_background_world(Scene *scene, View3D *v3d, RegionView3D *rv3d)
{
- unsigned int col;
-
- if (x >= vc->ar->winx || y >= vc->ar->winy) {
- return 0;
- }
+ if (scene->world) {
+ GPUMaterial *gpumat = GPU_material_world(scene, scene->world);
- ED_view3d_backbuf_validate(vc);
+ /* calculate full shader for background */
+ GPU_material_bind(gpumat, 1, 1, 1.0f, false, rv3d->viewmat, rv3d->viewinv, rv3d->viewcamtexcofac, (v3d->scenelock != 0));
- 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);
-}
+ if (GPU_material_bound(gpumat)) {
+ /* TODO viewport (dfelinto): GPU_material_bind relies on immediate mode,
+ * we can't get rid of the following code without a bigger refactor
+ * or we dropping this functionality. */
-/* reads full rect, converts indices */
-ImBuf *ED_view3d_backbuf_read(ViewContext *vc, int xmin, int ymin, int xmax, int ymax)
-{
- 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;
+ glBegin(GL_TRIANGLE_STRIP);
+ glVertex2f(-1.0f, -1.0f);
+ glVertex2f(1.0f, -1.0f);
+ glVertex2f(-1.0f, 1.0f);
+ glVertex2f(1.0f, 1.0f);
+ glEnd();
+
+ GPU_material_unbind(gpumat);
+ return;
+ }
}
- ibuf_clip = IMB_allocImBuf(size_clip[0], size_clip[1], 32, IB_rect);
+ /* if any of the above fails */
+ view3d_draw_background_none();
+}
- ED_view3d_backbuf_validate(vc);
+/* ******************** other elements ***************** */
- 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);
+#define DEBUG_GRID 0
- if (ENDIAN_ORDER == B_ENDIAN) {
- IMB_convert_rgba_to_abgr(ibuf_clip);
- }
+static void gridline_range(double x0, double dx, double max, int *r_first, int *r_count)
+{
+ /* determine range of gridlines that appear in this Area -- similar calc but separate ranges for x & y
+ * x0 is gridline 0, the axis in screen space
+ * Area covers [0 .. max) pixels */
- 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;
+ int first = (int)ceil(-x0 / dx);
+ int last = (int)floor((max - x0) / dx);
+
+ if (first <= last) {
+ *r_first = first;
+ *r_count = last - first + 1;
}
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;
+ *r_first = 0;
+ *r_count = 0;
}
+
+#if DEBUG_GRID
+ printf(" first %d * dx = %f\n", first, x0 + first * dx);
+ printf(" last %d * dx = %f\n", last, x0 + last * dx);
+ printf(" count = %d\n", *count_out);
+#endif
}
-/* 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)
+static int gridline_count(ARegion *ar, double x0, double y0, double dx)
{
- 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;
+ /* x0 & y0 establish the "phase" of the grid within this 2D region
+ * dx is the frequency, shared by x & y directions
+ * pass in dx of smallest (highest precision) grid we want to draw */
- amount = (size - 1) / 2;
+#if DEBUG_GRID
+ printf(" %s(%f, %f, dx:%f)\n", __FUNCTION__, x0, y0, dx);
+#endif
- 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;
+ int first, x_ct, y_ct;
- 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;
- }
-
- tbuf += (dirvec[rc][0] + dirvec[rc][1]);
-
- if (tbuf < bufmin || tbuf >= bufmax) {
- goto exit;
- }
- }
- rc++;
- rc &= 3;
- }
- }
+ gridline_range(x0, dx, ar->winx, &first, &x_ct);
+ gridline_range(y0, dx, ar->winy, &first, &y_ct);
-exit:
- IMB_freeImBuf(buf);
- return index;
-}
+ int total_ct = x_ct + y_ct;
+#if DEBUG_GRID
+ printf(" %d + %d = %d gridlines\n", x_ct, y_ct, total_ct);
+#endif
-/* ************************************************************* */
+ return total_ct;
+}
-static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, ImageUser *iuser)
+static bool drawgrid_draw(ARegion *ar, double x0, double y0, double dx, int skip_mod, unsigned pos, unsigned col, GLubyte col_value[3])
{
- if (BKE_image_is_stereo(ima)) {
- iuser->flag |= IMA_SHOW_STEREO;
+ /* skip every skip_mod lines relative to each axis; they will be overlaid by another drawgrid_draw
+ * always skip exact x0 & y0 axes; they will be drawn later in color
+ *
+ * set grid color once, just before the first line is drawn
+ * it's harmless to set same color for every line, or every vertex
+ * but if no lines are drawn, color must not be set! */
- 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;
+#if DEBUG_GRID
+ printf(" %s(%f, %f, dx:%f, skip_mod:%d)\n", __FUNCTION__, x0, y0, dx, skip_mod);
+#endif
+
+ const float x_max = (float)ar->winx;
+ const float y_max = (float)ar->winy;
+
+ int first, ct;
+ int x_ct = 0, y_ct = 0; /* count of lines actually drawn */
+ int lines_skipped_for_next_unit = 0;
+
+ /* draw vertical lines */
+ gridline_range(x0, dx, x_max, &first, &ct);
+
+ for (int i = first; i < first + ct; ++i) {
+ if (i == 0)
+ continue;
+ else if (skip_mod && (i % skip_mod) == 0) {
+ ++lines_skipped_for_next_unit;
+ continue;
}
- BKE_image_multiview_index(ima, iuser);
+ if (x_ct == 0)
+ immAttrib3ub(col, col_value[0], col_value[1], col_value[2]);
+
+ float x = (float)(x0 + i * dx);
+ immVertex2f(pos, x, 0.0f);
+ immVertex2f(pos, x, y_max);
+ ++x_ct;
}
- else {
- iuser->flag &= ~IMA_SHOW_STEREO;
+
+ /* draw horizontal lines */
+ gridline_range(y0, dx, y_max, &first, &ct);
+
+ for (int i = first; i < first + ct; ++i) {
+ if (i == 0)
+ continue;
+ else if (skip_mod && (i % skip_mod) == 0) {
+ ++lines_skipped_for_next_unit;
+ continue;
+ }
+
+ if (x_ct + y_ct == 0)
+ immAttrib3ub(col, col_value[0], col_value[1], col_value[2]);
+
+ float y = (float)(y0 + i * dx);
+ immVertex2f(pos, 0.0f, y);
+ immVertex2f(pos, x_max, y);
+ ++y_ct;
}
+
+#if DEBUG_GRID
+ int total_ct = x_ct + y_ct;
+ printf(" %d + %d = %d gridlines drawn, %d skipped for next unit\n", x_ct, y_ct, total_ct, lines_skipped_for_next_unit);
+#endif
+
+ return lines_skipped_for_next_unit > 0;
}
-static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
- const bool do_foreground, const bool do_camera_frame)
+#define GRID_MIN_PX_D 6.0
+#define GRID_MIN_PX_F 6.0f
+
+static void drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **grid_unit)
{
RegionView3D *rv3d = ar->regiondata;
- BGpic *bgpic;
- int fg_flag = do_foreground ? V3D_BGPIC_FOREGROUND : 0;
- for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
- bgpic->iuser.scene = scene; /* Needed for render results. */
+#if DEBUG_GRID
+ printf("%s width %d, height %d\n", __FUNCTION__, ar->winx, ar->winy);
+#endif
- if ((bgpic->flag & V3D_BGPIC_FOREGROUND) != fg_flag)
- continue;
+ double fx = rv3d->persmat[3][0];
+ double fy = rv3d->persmat[3][1];
+ double fw = rv3d->persmat[3][3];
- 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)
+ const double wx = 0.5 * ar->winx; /* use double precision to avoid rounding errors */
+ const double wy = 0.5 * ar->winy;
+
+ double x = wx * fx / fw;
+ double y = wy * fy / fw;
+
+ double vec4[4] = { v3d->grid, v3d->grid, 0.0, 1.0 };
+ mul_m4_v4d(rv3d->persmat, vec4);
+ fx = vec4[0];
+ fy = vec4[1];
+ fw = vec4[3];
+
+ double dx = fabs(x - wx * fx / fw);
+ if (dx == 0) dx = fabs(y - wy * fy / fw);
+
+ x += wx;
+ y += wy;
+
+ /* now x, y, and dx have their final values
+ * (x,y) is the world origin (0,0,0) mapped to Area-relative screen space
+ * dx is the distance in pixels between grid lines -- same for horiz or vert grid lines */
+
+ glLineWidth(1.0f);
+
+#if 0 /* TODO: write to UI/widget depth buffer, not scene depth */
+ glDepthMask(GL_FALSE); /* disable write in zbuffer */
+#endif
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+
+ unsigned char col[3], col2[3];
+ UI_GetThemeColor3ubv(TH_GRID, col);
+
+ if (unit->system) {
+ const void *usys;
+ int len;
+
+ bUnit_GetSystem(unit->system, B_UNIT_LENGTH, &usys, &len);
+
+ bool first = true;
+
+ if (usys) {
+ int i = len;
+ while (i--) {
+ double scalar = bUnit_GetScaler(usys, i);
+
+ double dx_scalar = dx * scalar / (double)unit->scale_length;
+ if (dx_scalar < (GRID_MIN_PX_D * 2.0)) {
+ /* very very small grid items are less useful when dealing with units */
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;
+
+ if (first) {
+ first = false;
+
+ /* Store the smallest drawn grid size units name so users know how big each grid cell is */
+ *grid_unit = bUnit_GetNameDisplay(usys, i);
+ rv3d->gridview = (float)((scalar * (double)v3d->grid) / (double)unit->scale_length);
+
+ int gridline_ct = gridline_count(ar, x, y, dx_scalar);
+ if (gridline_ct == 0)
+ goto drawgrid_cleanup; /* nothing to draw */
+
+ immBegin(GWN_PRIM_LINES, gridline_ct * 2);
}
- image_aspect[0] = ima->aspx;
- image_aspect[1] = ima->aspy;
+ float 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_GetThemeColorBlend3ubv(TH_HIGH_GRAD, TH_GRID, blend_fac, col2);
+
+ const int skip_mod = (i == 0) ? 0 : (int)round(bUnit_GetScaler(usys, i - 1) / scalar);
+#if DEBUG_GRID
+ printf("%s %f, ", bUnit_GetNameDisplay(usys, i), scalar);
+ if (i > 0)
+ printf("next unit is %d times larger\n", skip_mod);
+ else
+ printf("largest unit\n");
+#endif
+ if (!drawgrid_draw(ar, x, y, dx_scalar, skip_mod, pos, color, col2))
+ break;
}
- else if (bgpic->source == V3D_BGPIC_MOVIE) {
- /* TODO: skip drawing when out of frame range (as image sequences do above) */
+ }
+ }
+ else {
+ const double sublines = v3d->gridsubdiv;
+ const float sublines_fl = v3d->gridsubdiv;
+
+ int grids_to_draw = 2; /* first the faint fine grid, then the bold coarse grid */
- if (bgpic->flag & V3D_BGPIC_CAMERACLIP) {
- if (scene->camera)
- clip = BKE_object_movieclip_get(scene, scene->camera, true);
+ 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;
+ grids_to_draw = (dx < GRID_MIN_PX_D) ? 0 : 1;
}
- else {
- clip = bgpic->clip;
+ }
+ }
+ 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)) {
+ grids_to_draw = 1;
+ }
}
+ }
+ }
- if (clip == NULL)
- continue;
+ int gridline_ct = gridline_count(ar, x, y, dx);
+ if (gridline_ct == 0)
+ goto drawgrid_cleanup; /* nothing to draw */
- BKE_movieclip_user_set_frame(&bgpic->cuser, CFRA);
- ibuf = BKE_movieclip_get_ibuf(clip, &bgpic->cuser);
+ immBegin(GWN_PRIM_LINES, gridline_ct * 2);
- image_aspect[0] = clip->aspx;
- image_aspect[1] = clip->aspy;
+ if (grids_to_draw == 2) {
+ UI_GetThemeColorBlend3ubv(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0), col2);
+ if (drawgrid_draw(ar, x, y, dx, v3d->gridsubdiv, pos, color, col2))
+ drawgrid_draw(ar, x, y, dx * sublines, 0, pos, color, col);
+ }
+ else if (grids_to_draw == 1) {
+ drawgrid_draw(ar, x, y, dx, 0, pos, color, col);
+ }
+ }
- /* 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);
- }
+ /* draw visible axes */
+ /* horizontal line */
+ if (0 <= y && y < ar->winy) {
+ UI_make_axis_color(col, col2, ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT) ? 'Y' : 'X');
+ immAttrib3ub(color, col2[0], col2[1], col2[2]);
+ immVertex2f(pos, 0.0f, y);
+ immVertex2f(pos, (float)ar->winx, y);
+ }
- if (ibuf == NULL)
- continue;
+ /* vertical line */
+ if (0 <= x && x < ar->winx) {
+ UI_make_axis_color(col, col2, ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM) ? 'Y' : 'Z');
+ immAttrib3ub(color, col2[0], col2[1], col2[2]);
+ immVertex2f(pos, x, 0.0f);
+ immVertex2f(pos, x, (float)ar->winy);
+ }
- 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);
+ immEnd();
- continue;
- }
+drawgrid_cleanup:
+ immUnbindProgram();
- if (ibuf->rect == NULL)
- IMB_rect_from_float(ibuf);
+#if 0 /* depth write is left enabled above */
+ glDepthMask(GL_TRUE); /* enable write in zbuffer */
+#endif
+}
- if (rv3d->persp == RV3D_CAMOB) {
+#undef DEBUG_GRID
+#undef GRID_MIN_PX_D
+#undef GRID_MIN_PX_F
- 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;
- }
+static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool write_depth)
+{
+ /* draw only if there is something to draw */
+ if (v3d->gridflag & (V3D_SHOW_FLOOR | V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_Z)) {
+ /* draw how many lines?
+ * trunc(v3d->gridlines / 2) * 4
+ * + 2 for xy axes (possibly with special colors)
+ * + 1 for z axis (the only line not in xy plane)
+ * even v3d->gridlines are honored, odd rounded down */
+ const int gridlines = v3d->gridlines / 2;
+ const float grid_scale = ED_view3d_grid_scale(scene, v3d, grid_unit);
+ const float grid = gridlines * grid_scale;
- /* 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;
- }
+ const bool show_floor = (v3d->gridflag & V3D_SHOW_FLOOR) && gridlines >= 1;
- centx = (x1 + x2) / 2.0f;
- centy = (y1 + y2) / 2.0f;
+ bool show_axis_x = v3d->gridflag & V3D_SHOW_X;
+ bool show_axis_y = v3d->gridflag & V3D_SHOW_Y;
+ bool show_axis_z = v3d->gridflag & V3D_SHOW_Z;
- /* 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];
+ unsigned char col_grid[3], col_axis[3];
- /* destination aspect is already applied from the camera frame */
- const float w_dst = x1 - x2;
- const float h_dst = y1 - y2;
+ glLineWidth(1.0f);
- const float asp_src = w_src / h_src;
- const float asp_dst = w_dst / h_dst;
+ UI_GetThemeColor3ubv(TH_GRID, col_grid);
- 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 (!write_depth)
+ glDepthMask(GL_FALSE);
- /* complete clip? */
- BLI_rctf_init(&clip_rect, x1, x2, y1, y2);
- if (bgpic->rotation) {
- BLI_rctf_rotate_expand(&clip_rect, &clip_rect, bgpic->rotation);
- }
+ if (show_floor) {
+ const unsigned vertex_ct = 2 * (gridlines * 4 + 2);
+ const int sublines = v3d->gridsubdiv;
- 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);
+ unsigned char col_bg[3], col_grid_emphasise[3], col_grid_light[3];
- continue;
- }
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
- zoomx = (x2 - x1) / ibuf->x;
- zoomy = (y2 - y1) / ibuf->y;
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
- /* 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;
+ immBegin(GWN_PRIM_LINES, vertex_ct);
- 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++;
+ /* draw normal grid lines */
+ UI_GetColorPtrShade3ubv(col_grid, col_grid_light, 10);
+
+ for (int a = 1; a <= gridlines; a++) {
+ /* skip emphasised divider lines */
+ if (a % sublines != 0) {
+ const float line = a * grid_scale;
+
+ immAttrib3ubv(color, col_grid_light);
+
+ immVertex2f(pos, -grid, -line);
+ immVertex2f(pos, +grid, -line);
+ immVertex2f(pos, -grid, +line);
+ immVertex2f(pos, +grid, +line);
+
+ immVertex2f(pos, -line, -grid);
+ immVertex2f(pos, -line, +grid);
+ immVertex2f(pos, +line, -grid);
+ immVertex2f(pos, +line, +grid);
}
- if (mip > 0)
- ibuf = ibuf->mipmap[mip - 1];
}
- if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
- glDepthMask(0);
+ /* draw emphasised grid lines */
+ 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_emphasise,
+ (col_grid[0] + col_grid[1] + col_grid[2] + 30 >
+ col_bg[0] + col_bg[1] + col_bg[2]) ? 20 : -10);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ if (sublines <= gridlines) {
+ immAttrib3ubv(color, col_grid_emphasise);
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- ED_region_pixelspace(ar);
+ for (int a = sublines; a <= gridlines; a += sublines) {
+ const float line = a * grid_scale;
- glTranslatef(centx, centy, 0.0);
- glRotatef(RAD2DEGF(-bgpic->rotation), 0.0f, 0.0f, 1.0f);
+ immVertex2f(pos, -grid, -line);
+ immVertex2f(pos, +grid, -line);
+ immVertex2f(pos, -grid, +line);
+ immVertex2f(pos, +grid, +line);
- if (bgpic->flag & V3D_BGPIC_FLIP_X) {
- zoomx *= -1.0f;
- x1 = x2;
- }
- if (bgpic->flag & V3D_BGPIC_FLIP_Y) {
- zoomy *= -1.0f;
- y1 = y2;
+ immVertex2f(pos, -line, -grid);
+ immVertex2f(pos, -line, +grid);
+ immVertex2f(pos, +line, -grid);
+ immVertex2f(pos, +line, +grid);
+ }
}
- 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);
+ /* draw X axis */
+ if (show_axis_x) {
+ show_axis_x = false; /* drawing now, won't need to draw later */
+ UI_make_axis_color(col_grid, col_axis, 'X');
+ immAttrib3ubv(color, col_axis);
+ }
+ else
+ immAttrib3ubv(color, col_grid_emphasise);
- glPixelZoom(1.0, 1.0);
- glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
+ immVertex2f(pos, -grid, 0.0f);
+ immVertex2f(pos, +grid, 0.0f);
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
+ /* draw Y axis */
+ if (show_axis_y) {
+ show_axis_y = false; /* drawing now, won't need to draw later */
+ UI_make_axis_color(col_grid, col_axis, 'Y');
+ immAttrib3ubv(color, col_axis);
+ }
+ else
+ immAttrib3ubv(color, col_grid_emphasise);
- glDisable(GL_BLEND);
+ immVertex2f(pos, 0.0f, -grid);
+ immVertex2f(pos, 0.0f, +grid);
- glDepthMask(1);
- if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
+ immEnd();
+ immUnbindProgram();
- if (freeibuf)
- IMB_freeImBuf(freeibuf);
- if (releaseibuf)
- BKE_image_release_ibuf(ima, releaseibuf, lock);
+ /* done with XY plane */
}
- }
-}
-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;
+ if (show_axis_x || show_axis_y || show_axis_z) {
+ /* draw axis lines -- sometimes grid floor is off, other times we still need to draw the Z axis */
- if ((v3d->flag & V3D_DISPBGPICS) == 0)
- return;
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
- /* 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
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
+ immBegin(GWN_PRIM_LINES, (show_axis_x + show_axis_y + show_axis_z) * 2);
- 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);
- }
-}
+ if (show_axis_x) {
+ UI_make_axis_color(col_grid, col_axis, 'X');
+ immAttrib3ubv(color, col_axis);
+ immVertex3f(pos, -grid, 0.0f, 0.0f);
+ immVertex3f(pos, +grid, 0.0f, 0.0f);
+ }
-/* ****************** View3d afterdraw *************** */
+ if (show_axis_y) {
+ UI_make_axis_color(col_grid, col_axis, 'Y');
+ immAttrib3ubv(color, col_axis);
+ immVertex3f(pos, 0.0f, -grid, 0.0f);
+ immVertex3f(pos, 0.0f, +grid, 0.0f);
+ }
-typedef struct View3DAfter {
- struct View3DAfter *next, *prev;
- struct Base *base;
- short dflag;
-} View3DAfter;
+ if (show_axis_z) {
+ UI_make_axis_color(col_grid, col_axis, 'Z');
+ immAttrib3ubv(color, col_axis);
+ immVertex3f(pos, 0.0f, 0.0f, -grid);
+ immVertex3f(pos, 0.0f, 0.0f, +grid);
+ }
-/* 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;
-}
+ immEnd();
+ immUnbindProgram();
+ }
-/* disables write in zbuffer and draws it over */
-static void view3d_draw_transp(Scene *scene, ARegion *ar, View3D *v3d)
-{
- View3DAfter *v3da;
-
- glDepthMask(GL_FALSE);
- v3d->transp = true;
-
- while ((v3da = BLI_pophead(&v3d->afterdraw_transp))) {
- draw_object(scene, ar, v3d, v3da->base, v3da->dflag);
- MEM_freeN(v3da);
+ if (!write_depth)
+ glDepthMask(GL_TRUE);
}
- v3d->transp = false;
-
- glDepthMask(GL_TRUE);
-
}
-/* clears zbuffer and draws it over */
-static void view3d_draw_xray(Scene *scene, ARegion *ar, View3D *v3d, bool *clear)
+/** could move this elsewhere, but tied into #ED_view3d_grid_scale */
+float ED_scene_grid_scale(Scene *scene, const char **grid_unit)
{
- View3DAfter *v3da;
+ /* apply units */
+ if (scene->unit.system) {
+ const void *usys;
+ int len;
- if (*clear && v3d->zbuf) {
- glClear(GL_DEPTH_BUFFER_BIT);
- *clear = false;
- }
+ bUnit_GetSystem(scene->unit.system, B_UNIT_LENGTH, &usys, &len);
- v3d->xray = true;
- while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) {
- draw_object(scene, ar, v3d, v3da->base, v3da->dflag);
- MEM_freeN(v3da);
+ 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;
+ }
}
- v3d->xray = false;
+
+ 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);
+}
-/* clears zbuffer and draws it over */
-static void view3d_draw_xraytransp(Scene *scene, ARegion *ar, View3D *v3d, const bool clear)
+static bool is_cursor_visible(Scene *scene, SceneLayer *sl)
{
- View3DAfter *v3da;
+ Object *ob = OBACT_NEW;
- if (clear && v3d->zbuf)
- glClear(GL_DEPTH_BUFFER_BIT);
+ /* 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, sl);
- v3d->xray = true;
- v3d->transp = true;
-
- glDepthMask(GL_FALSE);
+ if (p && p->brush && p->brush->imagepaint_tool == PAINT_TOOL_CLONE) {
+ if ((scene->toolsettings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) == 0) {
+ return true;
+ }
+ }
+ }
- while ((v3da = BLI_pophead(&v3d->afterdraw_xraytransp))) {
- draw_object(scene, ar, v3d, v3da->base, v3da->dflag);
- MEM_freeN(v3da);
+ /* no exception met? then don't draw cursor! */
+ return false;
}
- v3d->transp = false;
- v3d->xray = false;
-
- glDepthMask(GL_TRUE);
-}
-
-/* *********************** */
-
-/*
- * 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
- */
-
-#if 0
-int dupli_ob_sort(void *arg1, void *arg2)
-{
- 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;
+ return true;
}
-#endif
-
-static DupliObject *dupli_step(DupliObject *dob)
+static void drawcursor(Scene *scene, ARegion *ar, View3D *v3d)
{
- while (dob && dob->no_draw)
- dob = dob->next;
- return dob;
-}
+ int co[2];
-static void draw_dupli_objects_color(
- Scene *scene, ARegion *ar, View3D *v3d, Base *base,
- const short dflag, const int color)
-{
- 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);
- }
+ /* 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.0f);
- tbase.flag = OB_FROMDUPLI | base->flag;
- lb = object_duplilist(G.main->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. */
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
- apply_data = duplilist_apply(base->object, scene, lb);
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
- dob = dupli_step(lb->first);
- if (dob) dob_next = dupli_step(dob->next);
+ const int segments = 16;
- for (; dob; dob_prev = dob, dob = dob_next, dob_next = dob_next ? dupli_step(dob_next->next) : NULL) {
- bool testbb = false;
+ immBegin(GWN_PRIM_LINE_LOOP, segments);
- tbase.object = dob->ob;
+ for (int i = 0; i < segments; ++i) {
+ float angle = 2 * M_PI * ((float)i / (float)segments);
+ float x = co[0] + f10 * cosf(angle);
+ float y = co[1] + f10 * sinf(angle);
- /* Make sure lod is updated from dupli's position */
- savedlod = dob->ob->currentlod;
+ if (i % 2 == 0)
+ immAttrib3ub(color, 255, 0, 0);
+ else
+ immAttrib3ub(color, 255, 255, 255);
-#ifdef WITH_GAMEENGINE
- if (rv3d->rflag & RV3D_IS_GAME_ENGINE) {
- BKE_object_lod_update(dob->ob, rv3d->viewinv[3]);
+ immVertex2f(pos, x, y);
}
-#endif
+ immEnd();
- /* 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);
+ immUnbindProgram();
- /* 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;
+ GWN_vertformat_clear(format);
+ pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
- /* negative scale flag has to propagate */
- transflag = tbase.object->transflag;
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- 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;
- }
-
- if ((bb_tmp = BKE_object_boundbox_get(dob->ob))) {
- bb = *bb_tmp; /* must make a copy */
- testbb = true;
- }
+ unsigned char crosshair_color[3];
+ UI_GetThemeColor3ubv(TH_VIEW_OVERLAY, crosshair_color);
+ immUniformColor3ubv(crosshair_color);
- 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;
- }
- 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(scene, ar, v3d, &tbase, dflag_dupli);
- glEndList();
-
- use_displist = true;
- BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 0);
- }
- }
-
- 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(scene, ar, v3d, &tbase, dflag_dupli);
- GPU_end_dupli_object();
- }
- }
-
- tbase.object->dt = dt;
- tbase.object->dtx = dtx;
- tbase.object->transflag = transflag;
- tbase.object->currentlod = savedlod;
- }
+ immBegin(GWN_PRIM_LINES, 8);
+ immVertex2f(pos, co[0] - f20, co[1]);
+ immVertex2f(pos, co[0] - f5, co[1]);
+ immVertex2f(pos, co[0] + f5, co[1]);
+ immVertex2f(pos, co[0] + f20, co[1]);
+ immVertex2f(pos, co[0], co[1] - f20);
+ immVertex2f(pos, co[0], co[1] - f5);
+ immVertex2f(pos, co[0], co[1] + f5);
+ immVertex2f(pos, co[0], co[1] + f20);
+ immEnd();
- if (apply_data) {
- duplilist_restore(lb, apply_data);
- duplilist_free_apply_data(apply_data);
+ immUnbindProgram();
}
-
- free_object_duplilist(lb);
-
- if (use_displist)
- glDeleteLists(displist, 1);
-}
-
-static void draw_dupli_objects(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(scene, ar, v3d, base, 0, color);
}
-/* XXX warning, not using gpu offscreen here */
-void view3d_update_depths_rect(ARegion *ar, ViewDepths *d, rcti *rect)
+static void draw_view_axis(RegionView3D *rv3d, rcti *rect)
{
- int x, y, w, h;
- rcti r;
- /* clamp rect by region */
+ const float k = U.rvisize * U.pixelsize; /* axis size */
+ const int bright = - 20 * (10 - U.rvibright); /* axis alpha offset (rvibright has range 0-10) */
- r.xmin = 0;
- r.xmax = ar->winx - 1;
- r.ymin = 0;
- r.ymax = ar->winy - 1;
+ const float startx = rect->xmin + k + 1.0f; /* axis center in screen coordinates, x=y */
+ const float starty = rect->ymin + k + 1.0f;
- /* Constrain rect to depth bounds */
- BLI_rcti_isect(&r, rect, rect);
+ float axis_pos[3][2];
+ unsigned char axis_col[3][4];
- /* assign values to compare with the ViewDepths */
- x = rect->xmin;
- y = rect->ymin;
+ int axis_order[3] = {0, 1, 2};
+ axis_sort_v3(rv3d->viewinv[2], axis_order);
- w = BLI_rcti_size_x(rect);
- h = BLI_rcti_size_y(rect);
+ for (int axis_i = 0; axis_i < 3; axis_i++) {
+ int i = axis_order[axis_i];
- if (w <= 0 || h <= 0) {
- if (d->depths)
- MEM_freeN(d->depths);
- d->depths = NULL;
+ /* 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;
- d->damaged = false;
+ /* 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 */
}
- 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);
+ /* draw axis lines */
+ glLineWidth(2.0f);
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths Subset");
-
- d->damaged = true;
- }
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBegin(GWN_PRIM_LINES, 6);
+
+ for (int axis_i = 0; axis_i < 3; axis_i++) {
+ int i = axis_order[axis_i];
- 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;
+ immAttrib4ubv(col, axis_col[i]);
+ immVertex2f(pos, startx, starty);
+ immVertex2fv(pos, axis_pos[i]);
}
-}
-/* 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;
- }
+ immEnd();
+ immUnbindProgram();
+ glDisable(GL_LINE_SMOOTH);
+
+ /* draw axis names */
+ for (int axis_i = 0; axis_i < 3; axis_i++) {
+ int i = axis_order[axis_i];
+
+ 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);
}
}
-/* utility function to find the closest Z value, use for autodepth */
-float view3d_depth_near(ViewDepths *d)
+#ifdef WITH_INPUT_NDOF
+/* draw center and axis of rotation for ongoing 3D mouse navigation */
+static void UNUSED_FUNCTION(draw_rotation_guide)(RegionView3D *rv3d)
{
- /* 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;
- }
- }
+ float o[3]; /* center of rotation */
+ float end[3]; /* endpoints for drawing */
- return far == far_real ? FLT_MAX : far;
-}
+ GLubyte color[4] = {0, 108, 255, 255}; /* bright blue so it matches device LEDs */
-void ED_view3d_draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d)
-{
- short zbuf = v3d->zbuf;
- RegionView3D *rv3d = ar->regiondata;
+ negate_v3_v3(o, rv3d->ofs);
- view3d_winmatrix_set(ar, v3d, NULL);
- view3d_viewmatrix_set(scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDepthMask(GL_FALSE); /* don't overwrite zbuf */
- mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
- invert_m4_m4(rv3d->persinv, rv3d->persmat);
- invert_m4_m4(rv3d->viewinv, rv3d->viewmat);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ unsigned int col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
- glClear(GL_DEPTH_BUFFER_BIT);
+ immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR);
- glLoadMatrixf(rv3d->viewmat);
+ 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);
- v3d->zbuf = true;
- glEnable(GL_DEPTH_TEST);
- if (v3d->flag2 & V3D_SHOW_GPENCIL) {
- ED_gpencil_draw_view3d(NULL, scene, v3d, ar, true);
- }
-
- v3d->zbuf = zbuf;
+ immBegin(GWN_PRIM_LINE_STRIP, 3);
+ color[3] = 0; /* more transparent toward the ends */
+ immAttrib4ubv(col, color);
+ add_v3_v3v3(end, o, scaled_axis);
+ immVertex3fv(pos, 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
-void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaoverride)
-{
- RegionView3D *rv3d = ar->regiondata;
- Base *base;
- short zbuf = v3d->zbuf;
- short flag = v3d->flag;
- float glalphaclip = U.glalphaclip;
- int obcenter_dia = U.obcenter_dia;
- /* no need for color when drawing depth buffer */
- const short dflag_depth = DRAW_CONSTCOLOR;
- /* 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;
-
- view3d_winmatrix_set(ar, v3d, NULL);
- view3d_viewmatrix_set(scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */
-
- mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
- invert_m4_m4(rv3d->persinv, rv3d->persmat);
- invert_m4_m4(rv3d->viewinv, rv3d->viewmat);
-
- glClear(GL_DEPTH_BUFFER_BIT);
-
- glLoadMatrixf(rv3d->viewmat);
-
- if (rv3d->rflag & RV3D_CLIPPING) {
- ED_view3d_clipping_set(rv3d);
- }
- /* get surface depth without bias */
- rv3d->rflag |= RV3D_ZOFFSET_DISABLED;
+ color[3] = 127; /* more opaque toward the center */
+ immAttrib4ubv(col, color);
+ immVertex3fv(pos, o);
- v3d->zbuf = true;
- glEnable(GL_DEPTH_TEST);
-
- /* draw set first */
- if (scene->set) {
- Scene *sce_iter;
- for (SETLOOPER(scene->set, sce_iter, base)) {
- if (v3d->lay & base->lay) {
- draw_object(scene, ar, v3d, base, 0);
- if (base->object->transflag & OB_DUPLI) {
- draw_dupli_objects_color(scene, ar, v3d, base, dflag_depth, TH_UNDEFINED);
- }
- }
- }
- }
-
- 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(scene, ar, v3d, base, dflag_depth, TH_UNDEFINED);
+ color[3] = 0;
+ immAttrib4ubv(col, color);
+ sub_v3_v3v3(end, o, scaled_axis);
+ immVertex3fv(pos, end);
+ immEnd();
+
+ /* -- 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 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);
}
- draw_object(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);
+ immBegin(GWN_PRIM_LINE_LOOP, ROT_AXIS_DETAIL);
+ color[3] = 63; /* somewhat faint */
+ immAttrib4ubv(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};
+ if (!upright) {
+ mul_qt_v3(q, p);
+ }
- 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(scene, ar, v3d, v3da->base, dflag_depth);
+ add_v3_v3(p, o);
+ immVertex3fv(pos, p);
}
- glDepthFunc(GL_LEQUAL); /* Now write the depth buffer normally */
- }
+ immEnd();
- /* draw 3 passes, transp/xray/xraytransp */
- v3d->xray = false;
- v3d->transp = true;
- while ((v3da = BLI_pophead(&v3d->afterdraw_transp))) {
- draw_object(scene, ar, v3d, v3da->base, dflag_depth);
- MEM_freeN(v3da);
+#undef ROT_AXIS_DETAIL
}
- v3d->xray = true;
- v3d->transp = false;
- while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) {
- draw_object(scene, ar, v3d, v3da->base, dflag_depth);
- MEM_freeN(v3da);
- }
+ color[3] = 255; /* solid dot */
+ }
+ else
+ color[3] = 127; /* see-through dot */
- v3d->xray = true;
- v3d->transp = true;
- while ((v3da = BLI_pophead(&v3d->afterdraw_xraytransp))) {
- draw_object(scene, ar, v3d, v3da->base, dflag_depth);
- MEM_freeN(v3da);
- }
+ immUnbindProgram();
-
- v3d->xray = false;
- v3d->transp = false;
+ /* -- draw rotation center -- */
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR);
+ glPointSize(5.0f);
+ immBegin(GWN_PRIM_POINTS, 1);
+ immAttrib4ubv(col, color);
+ immVertex3fv(pos, o);
+ immEnd();
+ immUnbindProgram();
- glDepthMask(mask_orig);
- }
-
- if (rv3d->rflag & RV3D_CLIPPING) {
- ED_view3d_clipping_disable();
- }
- rv3d->rflag &= ~RV3D_ZOFFSET_DISABLED;
-
- v3d->zbuf = zbuf;
- if (!v3d->zbuf) glDisable(GL_DEPTH_TEST);
+#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
- U.glalphaclip = glalphaclip;
- v3d->flag = flag;
- U.obcenter_dia = obcenter_dia;
+ glDisable(GL_BLEND);
+ glDepthMask(GL_TRUE);
}
+#endif /* WITH_INPUT_NDOF */
-typedef struct View3DShadow {
- struct View3DShadow *next, *prev;
- GPULamp *lamp;
-} View3DShadow;
+/* ******************** info ***************** */
-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)
+/**
+* Render and camera border
+*/
+static void view3d_draw_border(const bContext *C, ARegion *ar)
{
- 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_override_visible(lamp, srl, NULL))
- {
- shadow = MEM_callocN(sizeof(View3DShadow), "View3DShadow");
- shadow->lamp = lamp;
- BLI_addtail(shadows, shadow);
- }
+ Scene *scene = CTX_data_scene(C);
+ RegionView3D *rv3d = ar->regiondata;
+ View3D *v3d = CTX_wm_view3d(C);
+
+ if (rv3d->persp == RV3D_CAMOB) {
+ drawviewborder(scene, ar, v3d);
+ }
+ else if (v3d->flag2 & V3D_RENDER_BORDER) {
+ drawrenderborder(ar, v3d);
}
}
-static void gpu_update_lamps_shadows_world(Scene *scene, View3D *v3d)
+/**
+* Grease Pencil
+*/
+static void view3d_draw_grease_pencil(const bContext *UNUSED(C))
{
- 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(G.main->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);
- }
- }
-
- /* 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(
- 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;
- }
-
- 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);
- }
+ /* TODO viewport */
}
-/* *********************** customdata **************** */
-CustomDataMask ED_view3d_datamask(const Scene *scene, const View3D *v3d)
+/**
+* Viewport Name
+*/
+static const char *view3d_get_name(View3D *v3d, RegionView3D *rv3d)
{
- CustomDataMask mask = 0;
- const int drawtype = view3d_effective_drawtype(v3d);
+ const char *name = NULL;
- 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;
+ 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;
- 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;
+ 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");
}
- }
}
- return mask;
+ return name;
}
-/* goes over all modes and view3d settings */
-CustomDataMask ED_view3d_screen_datamask(const bScreen *screen)
+static void draw_viewport_name(ARegion *ar, View3D *v3d, rcti *rect)
{
- 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);
- }
+ 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;
}
- return mask;
+ UI_FontThemeColor(BLF_default(), 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
}
/**
- * \note keep this synced with #ED_view3d_mats_rv3d_backup/#ED_view3d_mats_rv3d_restore
+ * draw info beside axes in bottom left-corner:
+ * framenum, object name, bone name (if available), marker name (if available)
*/
-void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4])
-{
- RegionView3D *rv3d = ar->regiondata;
- rctf cameraborder;
-
- /* setup window matrices */
- if (winmat)
- copy_m4_m4(rv3d->winmat, winmat);
- else
- view3d_winmatrix_set(ar, v3d, NULL);
-
- /* setup view matrix */
- if (viewmat)
- copy_m4_m4(rv3d->viewmat, viewmat);
- else
- view3d_viewmatrix_set(scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */
- /* update utilitity 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 */
+static void draw_selected_name(Scene *scene, Object *ob, rcti *rect)
+{
+ const int cfra = CFRA;
+ const char *msg_pin = " (Pinned)";
+ const char *msg_sep = " : ";
- /* store window coordinates scaling/offset */
- if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
- 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);
-
- 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;
- }
-
- /* 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;
+ const int font_id = BLF_default();
- v1[0] = rv3d->persmat[0][0];
- v1[1] = rv3d->persmat[1][0];
- v1[2] = rv3d->persmat[2][0];
+ char info[300];
+ char *s = info;
+ short offset = 1.5f * UI_UNIT_X + rect->xmin;
- v2[0] = rv3d->persmat[0][1];
- v2[1] = rv3d->persmat[1][1];
- v2[2] = rv3d->persmat[2][1];
+ s += sprintf(s, "(%d)", cfra);
- len_px = 2.0f / sqrtf(min_ff(len_squared_v3(v1), len_squared_v3(v2)));
- len_sc = (float)MAX2(ar->winx, ar->winy);
+ /*
+ * 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)
+ */
- rv3d->pixsize = len_px / len_sc;
- }
-}
+ /* get name of marker on current frame (if available) */
+ const char *markern = BKE_scene_find_marker_name(scene, cfra);
-/**
- * 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,
- Scene *scene, View3D *v3d, ARegion *ar,
- const char **grid_unit,
- const bool do_bgpic, const bool draw_offscreen, GPUFX *fx)
-{
- 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);
- }
+ /* check if there is an object */
+ if (ob) {
+ *s++ = ' ';
+ s += BLI_strcpy_rlen(s, ob->id.name + 2);
- if (rv3d->rflag & RV3D_CLIPPING)
- view3d_draw_clipping(rv3d);
+ /* name(s) to display depends on type of object */
+ if (ob->type == OB_ARMATURE) {
+ bArmature *arm = ob->data;
- /* set zbuffer after we draw clipping region */
- if (v3d->drawtype > OB_WIRE) {
- v3d->zbuf = true;
- }
- else {
- v3d->zbuf = false;
- }
+ /* 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) {
- /* 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;
+ if (arm->act_bone->layer & arm->layer) {
+ s += BLI_strcpy_rlen(s, msg_sep);
+ s += BLI_strcpy_rlen(s, arm->act_bone->name);
+ }
+ }
}
}
- }
-
- if (v3d->zbuf) {
- glEnable(GL_DEPTH_TEST);
- }
+ else if (ELEM(ob->type, OB_MESH, OB_LATTICE, OB_CURVE)) {
+ /* try to display active bone and active shapekey too (if they exist) */
- /* 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 (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);
+ }
+ }
+ }
+ }
- 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);
+ 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));
+ }
+ }
+ }
}
- }
- /* important to do before clipping */
- if (do_bgpic) {
- view3d_draw_bgpic_test(scene, ar, v3d, false, do_camera_frame);
+ /* 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);
}
-
- if (rv3d->rflag & RV3D_CLIPPING) {
- ED_view3d_clipping_set(rv3d);
+ 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);
}
- /* 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(scene, ar, v3d, base, dflag);
-
- if (base->object->transflag & OB_DUPLI) {
- draw_dupli_objects_color(scene, ar, v3d, base, dflag, TH_UNDEFINED);
- }
- }
- }
-
- /* Transp and X-ray afterdraw stuff for sets is done later */
+ if (markern) {
+ s += sprintf(s, " <%s>", markern);
}
+ if (U.uiflag & USER_SHOW_ROTVIEWICON)
+ offset = U.widget_unit + (U.rvisize * 2) + rect->xmin;
- 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(scene, ar, v3d, base);
+ BLF_draw_default(offset, 0.5f * U.widget_unit, 0.0f, info, sizeof(info));
+}
- draw_object(scene, ar, v3d, base, 0);
- }
- }
- }
- else {
- unsigned int lay_used = 0;
+/* ******************** view loop ***************** */
- /* then draw not selected and the duplis, but skip editmode object */
- for (base = scene->base.first; base; base = base->next) {
- lay_used |= base->lay;
+/**
+* Information drawn on top of the solid plates and composed data
+*/
+void view3d_draw_region_info(const bContext *C, ARegion *ar, const int offset)
+{
+ RegionView3D *rv3d = ar->regiondata;
+ View3D *v3d = CTX_wm_view3d(C);
+ Scene *scene = CTX_data_scene(C);
+ wmWindowManager *wm = CTX_wm_manager(C);
- if (v3d->lay & base->lay) {
+ /* correct projection matrix */
+ ED_region_pixelspace(ar);
- /* dupli drawing */
- if (base->object->transflag & OB_DUPLI) {
- draw_dupli_objects(scene, ar, v3d, base);
- }
- if ((base->flag & SELECT) == 0) {
- if (base->object != scene->obedit)
- draw_object(scene, ar, v3d, base, 0);
- }
- }
- }
+ /* local coordinate visible rect inside region, to accomodate overlapping ui */
+ rcti rect;
+ ED_region_visible_rect(ar, &rect);
- /* mask out localview */
- v3d->lay_used = lay_used & ((1 << 20) - 1);
+ /* Leave room for previously drawn info. */
+ rect.ymax -= offset;
- /* 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(scene, ar, v3d, base, 0);
- }
- }
- }
- }
+ view3d_draw_border(C, ar);
+ view3d_draw_grease_pencil(C);
- /* perspective floor goes last to use scene depth and avoid writing to depth buffer */
- if (draw_grids_after) {
- drawfloor(scene, v3d, grid_unit, false);
+ if (U.uiflag & USER_SHOW_ROTVIEWICON) {
+ draw_view_axis(rv3d, &rect);
}
- /* 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);
+ 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);
}
- /* transp and X-ray afterdraw stuff */
- if (v3d->afterdraw_transp.first) view3d_draw_transp(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 (U.uiflag & USER_DRAWVIEWINFO) {
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *ob = OBACT_NEW;
+ draw_selected_name(scene, ob, &rect);
}
+#if 0 /* TODO */
+ if (grid_unit) { /* draw below the viewport name */
+ char numstr[32] = "";
- if (v3d->afterdraw_xray.first) view3d_draw_xray(scene, ar, v3d, &xrayclear);
- if (v3d->afterdraw_xraytransp.first) view3d_draw_xraytransp(scene, ar, v3d, xrayclear);
+ UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
+ if (v3d->grid != 1.0f) {
+ BLI_snprintf(numstr, sizeof(numstr), "%s x %.4g", grid_unit, v3d->grid);
+ }
- if (fx && do_composite_xray) {
- GPU_fx_compositor_XRay_resolve(fx);
+ 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));
}
+#endif
+}
- if (!draw_offscreen) {
- ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
- }
+static void view3d_draw_view(const bContext *C, ARegion *ar)
+{
+ ED_view3d_draw_setup_view(CTX_wm_window(C), CTX_data_scene(C), ar, CTX_wm_view3d(C), NULL, NULL, NULL);
- if (rv3d->rflag & RV3D_CLIPPING)
- ED_view3d_clipping_disable();
+ /* Only 100% compliant on new spec goes bellow */
+ DRW_draw_view(C);
+}
- /* important to do after clipping */
- if (do_bgpic) {
- view3d_draw_bgpic_test(scene, ar, v3d, true, do_camera_frame);
- }
+void view3d_main_region_draw(const bContext *C, ARegion *ar)
+{
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ RegionView3D *rv3d = ar->regiondata;
+ /* XXX: In the future we should get RE from Layers/Depsgraph */
+ RenderEngineType *type = RE_engines_find(scene->r.engine);
- if (!draw_offscreen) {
- BIF_draw_manipulator(C);
+ /* Provisory Blender Internal drawing */
+ if (type->flag & RE_USE_LEGACY_PIPELINE) {
+ view3d_main_region_draw_legacy(C, ar);
+ return;
}
- /* cleanup */
- if (v3d->zbuf) {
- v3d->zbuf = false;
- glDisable(GL_DEPTH_TEST);
+ if (!rv3d->viewport) {
+ rv3d->viewport = GPU_viewport_create();
}
- if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) {
- GPU_free_images_old();
- }
+ GPU_viewport_bind(rv3d->viewport, &ar->winrct);
+ view3d_draw_view(C, ar);
+ GPU_viewport_unbind(rv3d->viewport);
+
+ v3d->flag |= V3D_INVALID_BACKBUF;
}
-static void view3d_main_region_setup_view(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4])
-{
- RegionView3D *rv3d = ar->regiondata;
- ED_view3d_update_viewmat(scene, v3d, ar, viewmat, winmat);
+/* -------------------------------------------------------------------- */
- /* set for opengl */
- glMatrixMode(GL_PROJECTION);
- glLoadMatrixf(rv3d->winmat);
- glMatrixMode(GL_MODELVIEW);
- glLoadMatrixf(rv3d->viewmat);
-}
+/** \name Offscreen Drawing
+ * \{ */
-/**
- * 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;
-};
-
-void *ED_view3d_mats_rv3d_backup(struct RegionView3D *rv3d)
+static void view3d_stereo3d_setup_offscreen(
+ Scene *scene, View3D *v3d, ARegion *ar,
+ float winmat[4][4], const char *viewname)
{
- 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;
-}
+ /* 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);
-void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, void *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;
+ 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);
+ }
}
-void ED_view3d_draw_offscreen_init(Scene *scene, View3D *v3d)
+void ED_view3d_draw_offscreen_init(Scene *scene, SceneLayer *sl, View3D *v3d)
{
- /* shadow buffers, before we setup matrices */
- if (draw_glsl_material(scene, NULL, v3d, v3d->drawtype))
- gpu_update_lamps_shadows_world(scene, v3d);
+ RenderEngineType *type = RE_engines_find(scene->r.engine);
+ if (type->flag & RE_USE_LEGACY_PIPELINE) {
+ /* shadow buffers, before we setup matrices */
+ if (draw_glsl_material(scene, sl, NULL, v3d, v3d->drawtype)) {
+ VP_deprecated_gpu_update_lamps_shadows_world(scene, v3d);
+ }
+ }
}
/*
@@ -2979,202 +1933,13 @@ void ED_view3d_draw_offscreen_init(Scene *scene, View3D *v3d)
*/
static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar)
{
- if (scene->world && (v3d->flag3 & V3D_SHOW_WORLD)) {
- bool glsl = GPU_glsl_support();
- if (glsl) {
- 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();
- }
-
- GPU_material_unbind(gpumat);
-
- glDepthFunc(GL_LEQUAL);
- glDisable(GL_DEPTH_TEST);
- }
- else if (scene->world->skytype & WO_SKYBLEND) { /* blend sky */
- int x, y;
- float col_hor[3];
- float col_zen[3];
-
-#define VIEWGRAD_RES_X 16
-#define VIEWGRAD_RES_Y 16
-
- GLubyte grid_col[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][4];
- static float grid_pos[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][3];
- static GLushort indices[VIEWGRAD_RES_X - 1][VIEWGRAD_RES_X - 1][4];
- static bool buf_calculated = false;
-
- IMB_colormanagement_pixel_to_display_space_v3(col_hor, &scene->world->horr, &scene->view_settings,
- &scene->display_settings);
- IMB_colormanagement_pixel_to_display_space_v3(col_zen, &scene->world->zenr, &scene->view_settings,
- &scene->display_settings);
-
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
-
- /* calculate buffers the first time only */
- if (!buf_calculated) {
- for (x = 0; x < VIEWGRAD_RES_X; x++) {
- for (y = 0; y < VIEWGRAD_RES_Y; y++) {
- const float xf = (float)x / (float)(VIEWGRAD_RES_X - 1);
- const float yf = (float)y / (float)(VIEWGRAD_RES_Y - 1);
-
- /* -1..1 range */
- grid_pos[x][y][0] = (xf - 0.5f) * 2.0f;
- grid_pos[x][y][1] = (yf - 0.5f) * 2.0f;
- grid_pos[x][y][2] = 1.0;
- }
- }
-
- for (x = 0; x < VIEWGRAD_RES_X - 1; x++) {
- for (y = 0; y < VIEWGRAD_RES_Y - 1; y++) {
- indices[x][y][0] = x * VIEWGRAD_RES_X + y;
- indices[x][y][1] = x * VIEWGRAD_RES_X + y + 1;
- indices[x][y][2] = (x + 1) * VIEWGRAD_RES_X + y + 1;
- indices[x][y][3] = (x + 1) * VIEWGRAD_RES_X + y;
- }
- }
-
- buf_calculated = true;
- }
-
- for (x = 0; x < VIEWGRAD_RES_X; x++) {
- for (y = 0; y < VIEWGRAD_RES_Y; y++) {
- const float xf = (float)x / (float)(VIEWGRAD_RES_X - 1);
- const float yf = (float)y / (float)(VIEWGRAD_RES_Y - 1);
- const float mval[2] = {xf * (float)ar->winx, yf * ar->winy};
- const float z_up[3] = {0.0f, 0.0f, 1.0f};
- float out[3];
- GLubyte *col_ub = grid_col[x][y];
-
- float col_fac;
- float col_fl[3];
-
- ED_view3d_win_to_vector(ar, mval, out);
-
- if (scene->world->skytype & WO_SKYPAPER) {
- if (scene->world->skytype & WO_SKYREAL) {
- col_fac = fabsf(((float)y / (float)VIEWGRAD_RES_Y) - 0.5f) * 2.0f;
- }
- else {
- col_fac = (float)y / (float)VIEWGRAD_RES_Y;
- }
- }
- else {
- if (scene->world->skytype & WO_SKYREAL) {
- col_fac = fabsf((angle_normalized_v3v3(z_up, out) / (float)M_PI) - 0.5f) * 2.0f;
- }
- else {
- col_fac = 1.0f - (angle_normalized_v3v3(z_up, out) / (float)M_PI);
- }
- }
-
- interp_v3_v3v3(col_fl, col_hor, col_zen, col_fac);
-
- rgb_float_to_uchar(col_ub, col_fl);
- col_ub[3] = 255;
- }
- }
-
- glEnable(GL_DEPTH_TEST);
- glDepthFunc(GL_ALWAYS);
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_COLOR_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, grid_pos);
- glColorPointer(4, GL_UNSIGNED_BYTE, 0, grid_col);
-
- glDrawElements(GL_QUADS, (VIEWGRAD_RES_X - 1) * (VIEWGRAD_RES_Y - 1) * 4, GL_UNSIGNED_SHORT, indices);
-
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
-
- glDepthFunc(GL_LEQUAL);
- glDisable(GL_DEPTH_TEST);
-
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
-
-#undef VIEWGRAD_RES_X
-#undef VIEWGRAD_RES_Y
- }
- else { /* solid sky */
- float col_hor[3];
- IMB_colormanagement_pixel_to_display_space_v3(col_hor, &scene->world->horr, &scene->view_settings,
- &scene->display_settings);
+ glClear(GL_DEPTH_BUFFER_BIT);
- glClearColor(col_hor[0], col_hor[1], col_hor[2], 1.0);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- }
+ if (scene->world && (v3d->flag3 & V3D_SHOW_WORLD)) {
+ VP_view3d_draw_background_world(scene, v3d, ar->regiondata);
}
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);
- }
+ VP_view3d_draw_background_none();
}
}
@@ -3182,24 +1947,19 @@ static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar)
* stuff like shadow buffers
*/
void ED_view3d_draw_offscreen(
- Scene *scene, View3D *v3d, ARegion *ar, int winx, int winy,
+ Scene *scene, SceneLayer *sl, 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)
{
- struct bThemeState theme_state;
- int bwinx, bwiny;
- rcti brect;
bool do_compositing = false;
RegionView3D *rv3d = ar->regiondata;
- glPushMatrix();
-
/* 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;
@@ -3208,6 +1968,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);
@@ -3220,26 +1981,10 @@ void ED_view3d_draw_offscreen(
GPU_free_images_anim();
}
- /* setup view matrices before fx or unbinding the offscreen buffers will cause issues */
- if ((viewname != NULL && viewname[0] != '\0') && (viewmat == NULL) && rv3d->persp == RV3D_CAMOB && v3d->camera)
- view3d_stereo3d_setup_offscreen(scene, v3d, ar, winmat, viewname);
- else
- view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat);
-
- /* 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;
- }
+ gpuPushProjectionMatrix();
+ gpuLoadIdentity();
+ gpuPushMatrix();
+ gpuLoadIdentity();
/* clear opengl buffers */
if (do_sky) {
@@ -3250,28 +1995,56 @@ void ED_view3d_draw_offscreen(
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
+ if ((viewname != NULL && viewname[0] != '\0') && (viewmat == NULL) && rv3d->persp == RV3D_CAMOB && v3d->camera)
+ view3d_stereo3d_setup_offscreen(scene, v3d, ar, winmat, viewname);
+ else
+ view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat, NULL);
+
/* main drawing call */
- view3d_draw_objects(NULL, scene, v3d, ar, NULL, do_bgpic, true, do_compositing ? fx : NULL);
+ RenderEngineType *type = RE_engines_find(scene->r.engine);
+ if (type->flag & RE_USE_LEGACY_PIPELINE) {
- /* post process */
- if (do_compositing) {
- if (!winmat)
- is_persp = rv3d->is_persp;
- GPU_fx_do_composite_pass(fx, winmat, is_persp, scene, ofs);
- }
+ /* framebuffer fx needed, we need to draw offscreen first */
+ if (v3d->fx_settings.fx_flag && fx) {
+ GPUSSAOSettings *ssao = NULL;
- if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) {
- /* draw grease-pencil stuff */
- ED_region_pixelspace(ar);
+ 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 (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);
+ if (ssao)
+ v3d->fx_settings.ssao = ssao;
}
- /* freeing the images again here could be done after the operator runs, leaving for now */
- GPU_free_images_anim();
+ VP_deprecated_view3d_draw_objects(NULL, 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();
+ }
+ }
+ else {
+ /* XXX, should take depsgraph as arg */
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, sl);
+ DRW_draw_render_loop_offscreen(depsgraph, ar, v3d, ofs);
}
/* restore size */
@@ -3279,7 +2052,8 @@ void ED_view3d_draw_offscreen(
ar->winy = bwiny;
ar->winrct = brect;
- glPopMatrix();
+ gpuPopProjectionMatrix();
+ gpuPopMatrix();
UI_Theme_Restore(&theme_state);
@@ -3293,14 +2067,13 @@ void ED_view3d_draw_offscreen(
* (avoids re-creating when doing multiple GL renders).
*/
ImBuf *ED_view3d_draw_offscreen_imbuf(
- Scene *scene, View3D *v3d, ARegion *ar, int sizex, int sizey,
+ Scene *scene, SceneLayer *sl, View3D *v3d, ARegion *ar, int sizex, int sizey,
unsigned int flag, bool draw_background,
int alpha_mode, int samples, bool full_samples, const char *viewname,
/* output vars */
GPUFX *fx, GPUOffScreen *ofs, char err_out[256])
{
RegionView3D *rv3d = ar->regiondata;
- ImBuf *ibuf;
const bool draw_sky = (alpha_mode == R_ADDSKY);
/* view state */
@@ -3323,12 +2096,12 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(
}
}
- ED_view3d_draw_offscreen_init(scene, v3d);
+ ED_view3d_draw_offscreen_init(scene, sl, 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) {
@@ -3365,7 +2138,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(
if ((samples && full_samples) == 0) {
/* Single-pass render, common case */
ED_view3d_draw_offscreen(
- scene, v3d, ar, sizex, sizey, NULL, winmat,
+ scene, sl, v3d, ar, sizex, sizey, NULL, winmat,
draw_background, draw_sky, !is_ortho, viewname,
fx, &fx_settings, ofs);
@@ -3384,25 +2157,23 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(
/* 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;
BLI_jitter_init(jit_ofs, samples);
/* first sample buffer, also initializes 'rv3d->persmat' */
ED_view3d_draw_offscreen(
- scene, v3d, ar, sizex, sizey, NULL, winmat,
+ scene, sl, 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;
+ unsigned i = sizex * sizey * 4;
while (i--) {
accum_buffer[i] = rect_temp[i];
}
/* 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,
@@ -3410,7 +2181,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(
(jit_ofs[j][1] * 2.0f) / sizey);
ED_view3d_draw_offscreen(
- scene, v3d, ar, sizex, sizey, NULL, winmat_jitter,
+ scene, sl, 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);
@@ -3461,7 +2232,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(
* \note used by the sequencer
*/
ImBuf *ED_view3d_draw_offscreen_imbuf_simple(
- Scene *scene, Object *camera, int width, int height,
+ Scene *scene, SceneLayer *sl, Object *camera, int width, int height,
unsigned int flag, int drawtype, bool use_solid_tex, bool use_gpencil, bool draw_background,
int alpha_mode, int samples, bool full_samples, const char *viewname,
GPUFX *fx, GPUOffScreen *ofs, char err_out[256])
@@ -3479,13 +2250,13 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(
v3d.lay = scene->lay;
v3d.drawtype = drawtype;
v3d.flag2 = V3D_RENDER_OVERRIDE;
-
+
if (use_gpencil)
v3d.flag2 |= V3D_SHOW_GPENCIL;
if (use_solid_tex)
v3d.flag2 |= V3D_SOLID_TEX;
-
+
if (draw_background)
v3d.flag3 |= V3D_SHOW_WORLD;
@@ -3515,656 +2286,103 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(
invert_m4_m4(rv3d.persinv, rv3d.viewinv);
return ED_view3d_draw_offscreen_imbuf(
- scene, &v3d, &ar, width, height, flag,
+ scene, sl, &v3d, &ar, width, height, flag,
draw_background, alpha_mode, samples, full_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(Scene *scene)
-{
- RenderEngineType *type = RE_engines_find(scene->r.engine);
+/* -------------------------------------------------------------------- */
- return (type && type->view_update && type->view_draw);
-}
+/** \name Legacy Interface
+ *
+ * This will be removed once the viewport gets replaced
+ * meanwhile it should keep the old viewport working.
+ *
+ * \{ */
-bool ED_view3d_calc_render_border(Scene *scene, View3D *v3d, ARegion *ar, rcti *rect)
+void VP_legacy_drawcursor(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d)
{
- 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);
+ if (is_cursor_visible(scene, sl)) {
+ drawcursor(scene, ar, v3d);
}
- 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)
+void VP_legacy_draw_view_axis(RegionView3D *rv3d, rcti *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);
-
- /* 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;
+ draw_view_axis(rv3d, rect);
}
-static void view3d_main_region_draw_engine_info(View3D *v3d, RegionView3D *rv3d, ARegion *ar, bool render_border)
+void VP_legacy_draw_viewport_name(ARegion *ar, View3D *v3d, rcti *rect)
{
- 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);
+ draw_viewport_name(ar, v3d, rect);
}
-static bool view3d_stereo3d_active(const bContext *C, Scene *scene, View3D *v3d, RegionView3D *rv3d)
+void VP_legacy_draw_selected_name(Scene *scene, Object *ob, rcti *rect)
{
- wmWindow *win = CTX_wm_window(C);
-
- if ((scene->r.scemode & R_MULTIVIEW) == 0)
- return false;
-
- if (WM_stereo3d_enabled(win, true) == false)
- return false;
-
- if ((v3d->camera == NULL) || (v3d->camera->type != OB_CAMERA) || rv3d->persp != RV3D_CAMOB)
- return false;
-
- if (scene->r.views_format & SCE_VIEWS_FORMAT_MULTIVIEW) {
- if (v3d->stereo3d_camera == STEREO_MONO_ID)
- return false;
-
- return BKE_scene_multiview_is_stereo3d(&scene->r);
- }
-
- return true;
+ draw_selected_name(scene, ob, rect);
}
-/* 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)
+void VP_legacy_drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **grid_unit)
{
- 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_lock_thread(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);
-
- data->shiftx = shiftx;
- BLI_unlock_thread(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_lock_thread(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);
-
- v3d->camera = view_ob;
- BLI_unlock_thread(LOCK_VIEW3D);
- }
+ drawgrid(unit, ar, v3d, grid_unit);
}
-static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *ar,
- float winmat[4][4], const char *viewname)
+void VP_legacy_drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool write_depth)
{
- /* 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);
- }
- 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);
- }
+ drawfloor(scene, v3d, grid_unit, write_depth);
}
-#ifdef WITH_GAMEENGINE
-static void update_lods(Scene *scene, float camera_pos[3])
+void VP_legacy_view3d_main_region_setup_view(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4])
{
- Scene *sce_iter;
- Base *base;
- Object *ob;
-
- for (SETLOOPER(scene, sce_iter, base)) {
- ob = base->object;
- BKE_object_lod_update(ob, camera_pos);
- }
+ view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat, NULL);
}
-#endif
-static void view3d_main_region_draw_objects(const bContext *C, Scene *scene, View3D *v3d,
- ARegion *ar, const char **grid_unit)
+bool VP_legacy_view3d_stereo3d_active(const bContext *C, Scene *scene, View3D *v3d, RegionView3D *rv3d)
{
- 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(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 */
- if (view3d_stereo3d_active(C, scene, v3d, rv3d))
- view3d_stereo3d_setup(scene, v3d, ar);
- else
- view3d_main_region_setup_view(scene, v3d, ar, 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, 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);
- }
-
- 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);
-
+ return view3d_stereo3d_active(CTX_wm_window(C), scene, v3d, rv3d);
}
-static bool is_cursor_visible(Scene *scene)
+void VP_legacy_view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar)
{
- 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;
+ view3d_stereo3d_setup(scene, v3d, ar, NULL);
}
-static void view3d_main_region_draw_info(const bContext *C, Scene *scene,
- ARegion *ar, View3D *v3d,
- const char *grid_unit, bool render_border)
+bool VP_legacy_use_depth(Scene *scene, View3D *v3d)
{
- 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));
- }
- }
+ return use_depth_doit(scene, v3d);
}
-void view3d_main_region_draw(const bContext *C, ARegion *ar)
+void VP_drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
{
- 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));
+ drawviewborder(scene, ar, v3d);
}
-#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)
+void VP_drawrenderborder(ARegion *ar, View3D *v3d)
{
- _bl_debug_draw_color = color;
+ drawrenderborder(ar, v3d);
}
-void bl_debug_draw_quad_add(const float v0[3], const float v1[3], const float v2[3], const float v3[3])
+
+void VP_view3d_draw_background_none(void)
{
- if (_bl_debug_draw_quads_tot >= _DEBUG_DRAW_QUAD_TOT) {
- printf("%s: max quad count hit %d!", __func__, _bl_debug_draw_quads_tot);
+ if (UI_GetThemeValue(TH_SHOW_BACK_GRAD)) {
+ view3d_draw_background_gradient();
}
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++;
+ view3d_draw_background_none();
}
}
-void bl_debug_draw_edge_add(const float v0[3], const float v1[3])
+
+void VP_view3d_draw_background_world(Scene *scene, View3D *v3d, RegionView3D *rv3d)
{
- 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++;
- }
+ view3d_draw_background_world(scene, v3d, rv3d);
}
-static void bl_debug_draw(void)
+
+void VP_view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar)
{
- 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();
- }
+ view3d_main_region_clear(scene, v3d, ar);
}
-#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..a7ed6fcc30c
--- /dev/null
+++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c
@@ -0,0 +1,2160 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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_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_math.h"
+#include "BLI_jitter.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_DerivedMesh.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 "RE_engine.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_lamp.h"
+#include "GPU_material.h"
+#include "GPU_compositing.h"
+#include "GPU_extensions.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_select.h"
+#include "GPU_matrix.h"
+
+#include "RE_engine.h"
+
+#include "DRW_engine.h"
+
+#include "view3d_intern.h" /* own include */
+
+/* ********* 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;
+
+ 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);
+}
+
+/* ********* end custom clipping *********** */
+
+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);
+}
+
+/* *********************** backdraw for selection *************** */
+
+static void backdrawview3d(Scene *scene, SceneLayer *sl, wmWindow *win, ARegion *ar, View3D *v3d)
+{
+ RegionView3D *rv3d = ar->regiondata;
+ struct Base *base = sl->basact;
+ int multisample_enabled;
+
+ BLI_assert(ar->regiontype == RGN_TYPE_WINDOW);
+
+ if (base && (base->object->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT) ||
+ BKE_paint_select_face_test(base->object)))
+ {
+ /* do nothing */
+ }
+ /* texture paint mode sampling */
+ else if (base && (base->object->mode & OB_MODE_TEXTURE_PAINT) &&
+ (v3d->drawtype > OB_WIRE))
+ {
+ /* do nothing */
+ }
+ else if ((base && (base->object->mode & OB_MODE_PARTICLE_EDIT)) &&
+ V3D_IS_ZBUF(v3d))
+ {
+ /* do nothing */
+ }
+ else if (scene->obedit &&
+ 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 (v3d->drawtype > OB_WIRE) v3d->zbuf = true;
+
+ /* dithering and AA break color coding, so disable */
+ glDisable(GL_DITHER);
+
+ multisample_enabled = glIsEnabled(GL_MULTISAMPLE);
+ if (multisample_enabled)
+ glDisable(GL_MULTISAMPLE);
+
+ 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];
+
+ 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, 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
+ glScissor(ar->winrct.xmin, ar->winrct.ymin, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct));
+
+ 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);
+ }
+
+ if (rv3d->rflag & RV3D_CLIPPING)
+ ED_view3d_clipping_set(rv3d);
+
+ G.f |= G_BACKBUFSEL;
+
+ if (base && ((base->flag & BASE_VISIBLED) != 0))
+ draw_object_backbufsel(scene, v3d, rv3d, base->object);
+
+ if (rv3d->gpuoffscreen)
+ GPU_offscreen_unbind(rv3d->gpuoffscreen, true);
+ else
+ ar->swap = 0; /* mark invalid backbuf for wm draw */
+
+ v3d->flag &= ~V3D_INVALID_BACKBUF;
+
+ G.f &= ~G_BACKBUFSEL;
+ v3d->zbuf = false;
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_DITHER);
+ if (multisample_enabled)
+ glEnable(GL_MULTISAMPLE);
+
+ 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(ViewContext *vc)
+{
+ if (vc->v3d->flag & V3D_INVALID_BACKBUF)
+ backdrawview3d(vc->scene, vc->scene_layer, vc->win, vc->ar, vc->v3d);
+}
+
+/**
+ * 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, ARegion *ar, View3D *v3d,
+ const bool do_foreground, const bool do_camera_frame)
+{
+ RegionView3D *rv3d = ar->regiondata;
+ int fg_flag = do_foreground ? V3D_BGPIC_FOREGROUND : 0;
+
+ for (BGpic *bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
+ bgpic->iuser.scene = scene; /* Needed for render results. */
+
+ if ((bgpic->flag & V3D_BGPIC_FOREGROUND) != fg_flag)
+ continue;
+
+ 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 x1, y1, x2, y2, centx, centy;
+
+ void *lock;
+
+ Image *ima = NULL;
+
+ /* disable individual images */
+ if ((bgpic->flag & V3D_BGPIC_DISABLED))
+ continue;
+
+ ImBuf *ibuf = NULL;
+ ImBuf *freeibuf = NULL;
+ ImBuf *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;
+ }
+
+ 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) */
+ MovieClip *clip = NULL;
+
+ if (bgpic->flag & V3D_BGPIC_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, CFRA);
+ 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);
+
+ if (rv3d->persp == RV3D_CAMOB) {
+
+ 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;
+ }
+
+ /* 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;
+ }
+
+ centx = (x1 + x2) * 0.5f;
+ centy = (y1 + y2) * 0.5f;
+
+ /* 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];
+
+ /* 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 & 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};
+
+ /* calc window coord */
+ float zfac = ED_view3d_calc_zfac(rv3d, co_zero, NULL);
+ ED_view3d_win_to_delta(ar, mval_f, tvec, zfac);
+ float fac = 1.0f / max_ff(fabsf(tvec[0]), max_ff(fabsf(tvec[1]), fabsf(tvec[2]))); /* largest abs axis */
+ float 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;
+ }
+
+ /* 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];
+ }
+
+ if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
+ glDepthMask(GL_FALSE);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ gpuPushProjectionMatrix();
+ gpuPushMatrix();
+ ED_region_pixelspace(ar);
+
+ gpuTranslate2f(centx, centy);
+ gpuRotate2D(RAD2DEGF(-bgpic->rotation));
+
+ if (bgpic->flag & V3D_BGPIC_FLIP_X) {
+ zoomx *= -1.0f;
+ x1 = x2;
+ }
+ if (bgpic->flag & V3D_BGPIC_FLIP_Y) {
+ zoomy *= -1.0f;
+ y1 = y2;
+ }
+
+ float col[4] = {1.0f, 1.0f, 1.0f, 1.0f - bgpic->blend};
+ 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);
+
+ gpuPopProjectionMatrix();
+ gpuPopMatrix();
+
+ glDisable(GL_BLEND);
+
+ glDepthMask(GL_TRUE);
+ if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
+
+ if (freeibuf)
+ IMB_freeImBuf(freeibuf);
+ if (releaseibuf)
+ BKE_image_release_ibuf(ima, releaseibuf, lock);
+ }
+ }
+}
+
+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;
+
+ if ((v3d->flag & V3D_DISPBGPICS) == 0)
+ 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, 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 BaseLegacy *base;
+ short dflag;
+} View3DAfter;
+
+/* temp storage of Objects that need to be drawn as last */
+void ED_view3d_after_add(ListBase *lb, BaseLegacy *base, const short dflag)
+{
+ View3DAfter *v3da = MEM_callocN(sizeof(View3DAfter), "View 3d after");
+ BLI_assert((base->flag_legacy & 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(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d)
+{
+ View3DAfter *v3da;
+
+ glDepthMask(GL_FALSE);
+ v3d->transp = true;
+
+ while ((v3da = BLI_pophead(&v3d->afterdraw_transp))) {
+ draw_object(scene, sl, ar, v3d, v3da->base, v3da->dflag);
+ MEM_freeN(v3da);
+ }
+ v3d->transp = false;
+
+ glDepthMask(GL_TRUE);
+
+}
+
+/* clears zbuffer and draws it over */
+static void view3d_draw_xray(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d, bool *clear)
+{
+ if (*clear && v3d->zbuf) {
+ glClear(GL_DEPTH_BUFFER_BIT);
+ *clear = false;
+ }
+
+ v3d->xray = true;
+ View3DAfter *v3da;
+ while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) {
+ draw_object(scene, sl, ar, v3d, v3da->base, v3da->dflag);
+ MEM_freeN(v3da);
+ }
+ v3d->xray = false;
+}
+
+
+/* clears zbuffer and draws it over */
+static void view3d_draw_xraytransp(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d, const bool clear)
+{
+ if (clear && v3d->zbuf)
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ v3d->xray = true;
+ v3d->transp = true;
+
+ glDepthMask(GL_FALSE);
+
+ View3DAfter *v3da;
+ while ((v3da = BLI_pophead(&v3d->afterdraw_xraytransp))) {
+ draw_object(scene, sl, ar, v3d, v3da->base, v3da->dflag);
+ MEM_freeN(v3da);
+ }
+
+ v3d->transp = false;
+ v3d->xray = false;
+
+ glDepthMask(GL_TRUE);
+}
+
+/* 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(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d, bool *clear)
+{
+ /* 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);
+ }
+
+ View3DAfter *v3da;
+ if (*clear && v3d->zbuf) {
+ glClear(GL_DEPTH_BUFFER_BIT);
+ *clear = false;
+ }
+
+ v3d->xray = true;
+ while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) {
+ if (GPU_select_load_id(v3da->base->object->select_color)) {
+ draw_object_select(scene, sl, ar, v3d, v3da->base, v3da->dflag);
+ }
+ MEM_freeN(v3da);
+ }
+ 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
+ */
+
+#if 0
+int dupli_ob_sort(void *arg1, void *arg2)
+{
+ 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;
+}
+#endif
+
+
+static DupliObject *dupli_step(DupliObject *dob)
+{
+ while (dob && dob->no_draw)
+ dob = dob->next;
+ return dob;
+}
+
+static void draw_dupli_objects_color(
+ Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d, BaseLegacy *base,
+ const short dflag, const int color)
+{
+ RegionView3D *rv3d = ar->regiondata;
+ ListBase *lb;
+ LodLevel *savedlod;
+ Base tbase = {NULL};
+ BoundBox bb, *bb_tmp; /* use a copy because draw_object, calls clear_mesh_caches */
+ unsigned char color_rgb[3];
+ const short dflag_dupli = dflag | DRAW_CONSTCOLOR;
+ short transflag;
+ char dt;
+ short dtx;
+ DupliApplyData *apply_data;
+
+ if ((base->flag & BASE_VISIBLED) == 0) 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_legacy = OB_FROMDUPLI | base->flag_legacy;
+ tbase.flag = base->flag;
+ lb = object_duplilist(G.main->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);
+
+ DupliObject *dob_next = NULL;
+ DupliObject *dob = dupli_step(lb->first);
+ if (dob) dob_next = dupli_step(dob->next);
+
+ for (; 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);
+ }
+
+ if ((bb_tmp = BKE_object_boundbox_get(dob->ob))) {
+ bb = *bb_tmp; /* must make a copy */
+ testbb = true;
+ }
+
+ if (!testbb || ED_view3d_boundbox_clip_ex(rv3d, &bb, dob->mat)) {
+ copy_m4_m4(dob->ob->obmat, dob->mat);
+ GPU_begin_dupli_object(dob);
+ draw_object(scene, sl, ar, v3d, &tbase, dflag_dupli);
+ GPU_end_dupli_object();
+ }
+
+ 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);
+}
+
+void draw_dupli_objects(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d, BaseLegacy *base)
+{
+ /* define the color here so draw_dupli_objects_color can be called
+ * from the set loop */
+
+ int color = (base->flag & BASE_SELECTED) ? TH_SELECT : TH_WIRE;
+ /* debug */
+ if (base->object->dup_group && base->object->dup_group->id.us < 1)
+ color = TH_REDALERT;
+
+ draw_dupli_objects_color(scene, sl, ar, v3d, base, 0, color);
+}
+
+/* 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(Scene *scene, ARegion *ar, View3D *v3d)
+{
+ bool zbuf = v3d->zbuf;
+
+ /* Setup view matrix. */
+ ED_view3d_draw_setup_view(NULL, scene, ar, v3d, NULL, NULL, NULL);
+
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ v3d->zbuf = true;
+ glEnable(GL_DEPTH_TEST);
+
+ if (v3d->flag2 & V3D_SHOW_GPENCIL) {
+ ED_gpencil_draw_view3d(NULL, scene, v3d, ar, true);
+ }
+
+ v3d->zbuf = zbuf;
+ if (!zbuf) glDisable(GL_DEPTH_TEST);
+}
+
+void ED_view3d_draw_depth_loop(Scene *scene, ARegion *ar, View3D *v3d)
+{
+ Base *base;
+ SceneLayer *sl = BKE_scene_layer_context_active_PLACEHOLDER(scene);
+ /* 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 ((base->flag & BASE_VISIBLED) != 0) {
+ draw_object(scene, sl, ar, v3d, base, 0);
+ if (base->object->transflag & OB_DUPLI) {
+ draw_dupli_objects_color(scene, sl, ar, v3d, base, dflag_depth, TH_UNDEFINED);
+ }
+ }
+ }
+ }
+
+ for (base = sl->object_bases.first; base; base = base->next) {
+ if ((base->flag & BASE_VISIBLED) != 0) {
+ /* dupli drawing */
+ if (base->object->transflag & OB_DUPLI) {
+ draw_dupli_objects_color(scene, sl, ar, v3d, base, dflag_depth, TH_UNDEFINED);
+ }
+ draw_object(scene, sl, 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);
+
+
+ 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(scene, sl, ar, v3d, v3da->base, dflag_depth);
+ }
+ 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(scene, sl, ar, v3d, v3da->base, dflag_depth);
+ MEM_freeN(v3da);
+ }
+
+ v3d->xray = true;
+ v3d->transp = false;
+ while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) {
+ draw_object(scene, sl, ar, v3d, v3da->base, dflag_depth);
+ MEM_freeN(v3da);
+ }
+
+ v3d->xray = true;
+ v3d->transp = true;
+ while ((v3da = BLI_pophead(&v3d->afterdraw_xraytransp))) {
+ draw_object(scene, sl, ar, v3d, v3da->base, dflag_depth);
+ MEM_freeN(v3da);
+ }
+
+
+ v3d->xray = false;
+ v3d->transp = false;
+
+ glDepthMask(mask_orig);
+ }
+}
+
+void ED_view3d_draw_select_loop(
+ ViewContext *vc, Scene *scene, SceneLayer *sl, 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(scene, sl, ar, v3d, BASACT_NEW, dflag);
+ }
+ else if ((vc->obedit && vc->obedit->type == OB_ARMATURE)) {
+ /* if not drawing sketch, draw bones */
+ if (!BDR_drawSketchNames(vc)) {
+ draw_object(scene, sl, ar, v3d, BASACT_NEW, dflag);
+ }
+ }
+ else {
+ Base *base;
+
+ for (base = sl->object_bases.first; base; base = base->next) {
+ if ((base->flag & BASE_VISIBLED) != 0) {
+ if (((base->flag & BASE_SELECTABLED) == 0) ||
+ (use_obedit_skip && (scene->obedit->data == base->object->data)))
+ {
+ base->object->select_color = 0;
+ }
+ else {
+ base->object->select_color = code;
+
+ 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(scene, sl, ar, v3d, base, dflag);
+ }
+ }
+ code++;
+ }
+ }
+ }
+
+ if (use_nearest) {
+ bool xrayclear = true;
+ if (v3d->afterdraw_xray.first) {
+ view3d_draw_xray_select(scene, sl, ar, v3d, &xrayclear);
+ }
+ }
+ }
+}
+
+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 = GPU_lamp_from_blender(scene, ob, par);
+
+ if (lamp) {
+ Lamp *la = (Lamp *)ob->data;
+
+ GPU_lamp_update(lamp, lay, (ob->restrictflag & OB_RESTRICT_RENDER), obmat);
+ GPU_lamp_update_colors(lamp, la->r, la->g, la->b, la->energy);
+
+ unsigned int 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_override_visible(lamp, srl, NULL))
+ {
+ View3DShadow *shadow = MEM_callocN(sizeof(View3DShadow), "View3DShadow");
+ shadow->lamp = lamp;
+ BLI_addtail(shadows, shadow);
+ }
+ }
+}
+
+static void gpu_update_lamps_shadows_world(Scene *scene, View3D *v3d)
+{
+ ListBase shadows;
+ Scene *sce_iter;
+ Base *base;
+ 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)) {
+ Object *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(G.main->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);
+ }
+ }
+
+ /* render shadows after updating all lamps, nested object_duplilist
+ * don't work correct since it's replacing object matrices */
+ for (View3DShadow *shadow = shadows.first; shadow; shadow = shadow->next) {
+ /* this needs to be done better .. */
+ float viewmat[4][4], winmat[4][4];
+ ARegion ar = {NULL};
+ RegionView3D rv3d = {{{0}}};
+
+ int drawtype = v3d->drawtype;
+ int lay = v3d->lay;
+ int flag2 = v3d->flag2;
+
+ 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;
+
+ int winsize;
+ 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(
+ scene, BKE_scene_layer_context_active_PLACEHOLDER(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;
+ }
+
+ 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);
+ }
+}
+
+/* *********************** 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_MLOOPUV | CD_MASK_MLOOPCOL;
+
+ 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;
+ }
+ }
+ }
+
+ 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;
+}
+
+/**
+ * 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,
+ Scene *scene, View3D *v3d, ARegion *ar,
+ const char **grid_unit,
+ const bool do_bgpic, const bool draw_offscreen, GPUFX *fx)
+{
+ SceneLayer *sl = C ? CTX_data_scene_layer(C) : BKE_scene_layer_from_scene_get(scene);
+ 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 */
+ v3d->zbuf = VP_legacy_use_depth(scene, v3d);
+
+ if (v3d->zbuf) {
+ glEnable(GL_DEPTH_TEST);
+ }
+
+ /* 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... */
+ VP_legacy_drawgrid(&scene->unit, ar, v3d, grid_unit);
+ gpuLoadProjectionMatrix(rv3d->winmat);
+ gpuLoadMatrix(rv3d->viewmat);
+ }
+ else if (!draw_grids_after) {
+ VP_legacy_drawfloor(scene, v3d, grid_unit, true);
+ }
+ }
+
+ /* 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 ((base->flag & BASE_VISIBLED) != 0) {
+ UI_ThemeColorBlend(TH_WIRE, TH_BACK, 0.6f);
+ draw_object(scene, sl, ar, v3d, base, dflag);
+
+ if (base->object->transflag & OB_DUPLI) {
+ draw_dupli_objects_color(scene, sl, ar, v3d, base, dflag, TH_UNDEFINED);
+ }
+ }
+ }
+
+ /* Transp and X-ray afterdraw stuff for sets is done later */
+ }
+
+ if (draw_offscreen) {
+ for (base = sl->object_bases.first; base; base = base->next) {
+ if ((base->flag & BASE_VISIBLED) != 0) {
+ /* dupli drawing */
+ if (base->object->transflag & OB_DUPLI)
+ draw_dupli_objects(scene, sl, ar, v3d, base);
+
+ draw_object(scene, sl, ar, v3d, base, 0);
+ }
+ }
+ }
+ else {
+ unsigned int lay_used = 0;
+
+ /* then draw not selected and the duplis, but skip editmode object */
+ for (base = sl->object_bases.first; base; base = base->next) {
+ lay_used |= base->lay;
+
+ if ((base->flag & BASE_VISIBLED) != 0) {
+
+ /* dupli drawing */
+ if (base->object->transflag & OB_DUPLI) {
+ draw_dupli_objects(scene, sl, ar, v3d, base);
+ }
+ if ((base->flag & BASE_SELECTED) == 0) {
+ if (base->object != scene->obedit)
+ draw_object(scene, sl, ar, v3d, base, 0);
+ }
+ }
+ }
+
+ /* mask out localview */
+ v3d->lay_used = lay_used & ((1 << 20) - 1);
+
+ /* draw selected and editmode */
+ for (base = sl->object_bases.first; base; base = base->next) {
+ if ((base->flag & BASE_VISIBLED) != 0) {
+ if (base->object == scene->obedit || (base->flag & BASE_SELECTED)) {
+ draw_object(scene, sl, ar, v3d, base, 0);
+ }
+ }
+ }
+ }
+
+ /* perspective floor goes last to use scene depth and avoid writing to depth buffer */
+ if (draw_grids_after) {
+ VP_legacy_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(scene, sl, 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(scene, sl, ar, v3d, &xrayclear);
+ if (v3d->afterdraw_xraytransp.first) view3d_draw_xraytransp(scene, sl, 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 (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);
+ }
+
+ /* cleanup */
+ if (v3d->zbuf) {
+ v3d->zbuf = false;
+ glDisable(GL_DEPTH_TEST);
+ }
+
+ if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) {
+ GPU_free_images_old();
+ }
+}
+
+/**
+ * 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, const rcti *rect)
+{
+ 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));
+ }
+
+#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->render_to_view);
+}
+
+bool ED_view3d_calc_render_border(const Scene *scene, View3D *v3d, ARegion *ar, rcti *rect)
+{
+ RegionView3D *rv3d = ar->regiondata;
+ 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) {
+ rctf viewborder;
+ 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;
+}
+
+/**
+ * IMPORTANT: this is deprecated, any changes made in this function should
+ * be mirrored in view3d_draw_render_draw() in view3d_draw.c
+ */
+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->render_to_view))
+ 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 */
+ VP_legacy_view3d_main_region_setup_view(scene, v3d, ar, 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
+ imm_draw_checker_box(0, 0, ar->winx, ar->winy);
+
+ /* render result draw */
+ type = rv3d->render_engine->type;
+ type->render_to_view(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);
+}
+
+#ifdef WITH_GAMEENGINE
+static void update_lods(Scene *scene, float camera_pos[3])
+{
+ Scene *sce_iter;
+ Base *base;
+
+ for (SETLOOPER(scene, sce_iter, base)) {
+ Object *ob = base->object;
+ BKE_object_lod_update(ob, camera_pos);
+ }
+}
+#endif
+
+static void view3d_main_region_draw_objects(const bContext *C, Scene *scene, SceneLayer *sl, View3D *v3d,
+ ARegion *ar, const char **grid_unit)
+{
+ 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, sl, NULL, v3d, v3d->drawtype))
+ gpu_update_lamps_shadows_world(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 */
+ if (VP_legacy_view3d_stereo3d_active(C, scene, v3d, rv3d))
+ VP_legacy_view3d_stereo3d_setup(scene, v3d, ar);
+ else
+ VP_legacy_view3d_main_region_setup_view(scene, v3d, ar, 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) {
+ BKE_screen_gpu_fx_validate(&v3d->fx_settings);
+ GPUFXSettings 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);
+ }
+
+ /* enables anti-aliasing for 3D view drawing */
+ if (win->multisamples != USER_MULTISAMPLE_NONE) {
+ glEnable(GL_MULTISAMPLE);
+ }
+
+ /* main drawing call */
+ view3d_draw_objects(C, scene, v3d, ar, grid_unit, true, false, do_compositing ? rv3d->compositor : NULL);
+
+ /* draw depth culled manipulators - manipulators need to be updated *after* view matrix was set up */
+ /* TODO depth culling manipulators is not yet supported, just drawing _3D here, should
+ * later become _IN_SCENE (and draw _3D separate) */
+ WM_manipulatormap_draw(ar->manipulator_map, C, WM_MANIPULATORMAP_DRAWSTEP_3D);
+
+ /* 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);
+ }
+}
+
+static void view3d_main_region_draw_info(const bContext *C, Scene *scene,
+ ARegion *ar, View3D *v3d,
+ const char *grid_unit, bool render_border)
+{
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ 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) {
+ VP_drawviewborder(scene, ar, v3d);
+ }
+ else if (v3d->flag2 & V3D_RENDER_BORDER) {
+ VP_drawrenderborder(ar, v3d);
+ }
+
+ 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) {
+ VP_legacy_drawcursor(scene, sl, ar, v3d); /* 3D cursor */
+
+ if (U.uiflag & USER_SHOW_ROTVIEWICON)
+ VP_legacy_draw_view_axis(rv3d, &rect);
+ else
+ draw_view_icon(rv3d, &rect);
+
+ if (U.uiflag & USER_DRAWVIEWINFO) {
+ Object *ob = OBACT_NEW;
+ VP_legacy_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) {
+ VP_legacy_draw_viewport_name(ar, v3d, &rect);
+ }
+
+ if (grid_unit) { /* draw below the viewport name */
+ char numstr[32] = "";
+
+ UI_FontThemeColor(BLF_default(), 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_legacy(const bContext *C, ARegion *ar)
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ const char *grid_unit = NULL;
+ rcti border_rect;
+
+ /* if we only redraw render border area, skip opengl draw and also
+ * don't do scissor because it's already set */
+ bool render_border = ED_view3d_calc_render_border(scene, v3d, ar, &border_rect);
+ bool clip_border = (render_border && !BLI_rcti_compare(&ar->drawrct, &border_rect));
+
+ gpuPushProjectionMatrix();
+ gpuLoadIdentityProjectionMatrix();
+ gpuPushMatrix();
+ gpuLoadIdentity();
+
+ /* draw viewport using opengl */
+ if (v3d->drawtype != OB_RENDER || !view3d_main_region_do_render_draw(scene) || clip_border) {
+ VP_view3d_main_region_clear(scene, v3d, ar); /* background */
+ view3d_main_region_draw_objects(C, scene, sl, v3d, ar, &grid_unit);
+
+ if (G.debug & G_DEBUG_SIMDATA)
+ draw_sim_debug_data(scene, v3d, ar);
+
+ glDisable(GL_DEPTH_TEST);
+ 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);
+
+ VP_legacy_view3d_main_region_setup_view(scene, v3d, ar, NULL, NULL);
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ WM_manipulatormap_draw(ar->manipulator_map, C, WM_MANIPULATORMAP_DRAWSTEP_2D);
+
+ ED_region_pixelspace(ar);
+
+ view3d_main_region_draw_info(C, scene, ar, v3d, grid_unit, render_border);
+
+ gpuPopProjectionMatrix();
+ gpuPopMatrix();
+
+ 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));
+}
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Deprecated Interface
+ *
+ * New viewport sometimes has a check for new/old viewport code.
+ * Use these functions so new viewport can *optionally* call.
+ *
+ * \{ */
+
+
+void VP_deprecated_view3d_draw_objects(
+ const bContext *C,
+ Scene *scene, View3D *v3d, ARegion *ar,
+ const char **grid_unit,
+ const bool do_bgpic, const bool draw_offscreen, GPUFX *fx)
+{
+ view3d_draw_objects(C, scene, v3d, ar, grid_unit, do_bgpic, draw_offscreen, fx);
+}
+
+void VP_deprecated_gpu_update_lamps_shadows_world(Scene *scene, View3D *v3d)
+{
+ gpu_update_lamps_shadows_world(scene, v3d);
+}
+
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 215d90a8878..8bb0619c45b 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -41,6 +41,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_bitmap_draw_2d.h"
#include "BLI_blenlib.h"
#include "BLI_kdopbvh.h"
#include "BLI_math.h"
@@ -57,11 +58,10 @@
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_action.h"
-#include "BKE_depsgraph.h" /* for ED_view3d_camera_lock_sync */
+#include "DEG_depsgraph.h"
#include "BIF_gl.h"
-#include "BIF_glutil.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -78,30 +78,21 @@
#include "ED_gpencil.h"
#include "ED_view3d.h"
+#include "DEG_depsgraph_query.h"
+
#include "UI_resources.h"
#include "PIL_time.h" /* smoothview */
#include "view3d_intern.h" /* own include */
+static bool view3d_ensure_persp(struct View3D *v3d, ARegion *ar);
+
bool ED_view3d_offset_lock_check(const View3D *v3d, const RegionView3D *rv3d)
{
return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_centre_cursor || v3d->ob_centre);
}
-static bool view3d_operator_offset_lock_check(bContext *C, wmOperator *op)
-{
- View3D *v3d = CTX_wm_view3d(C);
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- if (ED_view3d_offset_lock_check(v3d, rv3d)) {
- BKE_report(op->reports, RPT_WARNING, "View offset is locked");
- return true;
- }
- else {
- return false;
- }
-}
-
/* ********************** view3d_edit: view manipulations ********************* */
/**
@@ -173,7 +164,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;
}
@@ -185,7 +176,7 @@ bool ED_view3d_camera_lock_sync(View3D *v3d, RegionView3D *rv3d)
ED_view3d_to_object(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);
}
@@ -565,22 +556,20 @@ typedef struct ViewOpsData {
static void calctrackballvec(const rcti *rect, int mx, int my, float vec[3])
{
- float x, y, radius, d, z, t;
-
- radius = TRACKBALLSIZE;
+ const float radius = TRACKBALLSIZE;
+ const float t = radius / (float)M_SQRT2;
+ float x, y, z, d;
/* normalize x and y */
x = BLI_rcti_cent_x(rect) - mx;
x /= (float)(BLI_rcti_size_x(rect) / 4);
y = BLI_rcti_cent_y(rect) - my;
y /= (float)(BLI_rcti_size_y(rect) / 2);
-
d = sqrtf(x * x + y * y);
- if (d < radius * (float)M_SQRT1_2) { /* Inside sphere */
+ if (d < t) { /* Inside sphere */
z = sqrtf(radius * radius - d * d);
}
else { /* On hyperbola */
- t = radius / (float)M_SQRT2;
z = t * t / d;
}
@@ -633,7 +622,8 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
bool is_set = false;
Scene *scene = CTX_data_scene(C);
- Object *ob_act = OBACT;
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *ob_act = OBACT_NEW;
if (ob_act && (ob_act->mode & OB_MODE_ALL_PAINT) &&
/* with weight-paint + pose-mode, fall through to using calculateTransformCenter */
@@ -670,14 +660,13 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
}
else if (ob_act == NULL || ob_act->mode == OB_MODE_OBJECT) {
/* object mode use boundbox centers */
- View3D *v3d = CTX_wm_view3d(C);
Base *base;
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 = FIRSTBASE_NEW; base; base = base->next) {
+ if (TESTBASE_NEW(base)) {
/* use the boundbox if we can */
Object *ob = base->object;
@@ -711,16 +700,69 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
return is_set;
}
+enum eViewOpsOrbit {
+ VIEWOPS_ORBIT_SELECT = (1 << 0),
+ VIEWOPS_ORBIT_DEPTH = (1 << 1),
+};
+
+static enum eViewOpsOrbit viewops_orbit_mode_ex(bool use_select, bool use_depth)
+{
+ enum eViewOpsOrbit flag = 0;
+ if (use_select) {
+ flag |= VIEWOPS_ORBIT_SELECT;
+ }
+ if (use_depth) {
+ flag |= VIEWOPS_ORBIT_DEPTH;
+ }
+
+ return flag;
+}
+
+static enum eViewOpsOrbit viewops_orbit_mode(void)
+{
+ return viewops_orbit_mode_ex(
+ (U.uiflag & USER_ORBIT_SELECTION) != 0,
+ (U.uiflag & USER_ZBUF_ORBIT) != 0);
+}
+
/**
* Calculate the values for #ViewOpsData
*/
-static void viewops_data_create_ex(bContext *C, wmOperator *op, const wmEvent *event,
- const bool use_orbit_select,
- const bool use_orbit_zbuf)
+static void viewops_data_create_ex(
+ bContext *C, wmOperator *op, const wmEvent *event,
+ bool switch_from_camera, enum eViewOpsOrbit orbit_mode)
{
ViewOpsData *vod = op->customdata;
RegionView3D *rv3d = vod->rv3d;
+ /* we need the depth info before changing any viewport options */
+ if (orbit_mode & VIEWOPS_ORBIT_DEPTH) {
+ struct Depsgraph *graph = CTX_data_depsgraph(C);
+ float fallback_depth_pt[3];
+
+ view3d_operator_needs_opengl(C); /* needed for zbuf drawing */
+
+ negate_v3_v3(fallback_depth_pt, rv3d->ofs);
+
+ vod->use_dyn_ofs = ED_view3d_autodist(
+ graph, vod->ar, vod->v3d,
+ event->mval, vod->dyn_ofs, true, fallback_depth_pt);
+ }
+ else {
+ vod->use_dyn_ofs = false;
+ }
+
+ if (switch_from_camera) {
+ /* switch from camera view when: */
+ if (view3d_ensure_persp(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.
+ */
+ ED_region_tag_redraw(vod->ar);
+ }
+ }
+
/* 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);
@@ -732,28 +774,19 @@ static void viewops_data_create_ex(bContext *C, wmOperator *op, const wmEvent *e
vod->origx = vod->oldx = event->x;
vod->origy = vod->oldy = event->y;
vod->origkey = event->type; /* the key that triggered the operator. */
- vod->use_dyn_ofs = false;
copy_v3_v3(vod->ofs, rv3d->ofs);
- if (use_orbit_select) {
-
- vod->use_dyn_ofs = true;
-
- view3d_orbit_calc_center(C, vod->dyn_ofs);
-
- negate_v3(vod->dyn_ofs);
+ if (orbit_mode & VIEWOPS_ORBIT_SELECT) {
+ float ofs[3];
+ if (view3d_orbit_calc_center(C, ofs) || (vod->use_dyn_ofs == false)) {
+ vod->use_dyn_ofs = true;
+ negate_v3_v3(vod->dyn_ofs, ofs);
+ orbit_mode &= ~VIEWOPS_ORBIT_DEPTH;
+ }
}
- else if (use_orbit_zbuf) {
- Scene *scene = CTX_data_scene(C);
- float fallback_depth_pt[3];
-
- view3d_operator_needs_opengl(C); /* needed for zbuf drawing */
- negate_v3_v3(fallback_depth_pt, rv3d->ofs);
-
- if ((vod->use_dyn_ofs = ED_view3d_autodist(scene, vod->ar, vod->v3d,
- event->mval, vod->dyn_ofs, true, fallback_depth_pt)))
- {
+ if (orbit_mode & VIEWOPS_ORBIT_DEPTH) {
+ if (vod->use_dyn_ofs) {
if (rv3d->is_persp) {
float my_origin[3]; /* original G.vd->ofs */
float my_pivot[3]; /* view */
@@ -788,7 +821,7 @@ static void viewops_data_create_ex(bContext *C, wmOperator *op, const wmEvent *e
(float)vod->ar->winx / 2.0f,
(float)vod->ar->winy / 2.0f};
- ED_view3d_win_to_3d(vod->ar, vod->dyn_ofs, mval_ar_mid, rv3d->ofs);
+ ED_view3d_win_to_3d(vod->v3d, vod->ar, vod->dyn_ofs, mval_ar_mid, rv3d->ofs);
negate_v3(rv3d->ofs);
}
negate_v3(vod->dyn_ofs);
@@ -822,19 +855,18 @@ static void viewops_data_create_ex(bContext *C, wmOperator *op, const wmEvent *e
rv3d->rflag |= RV3D_NAVIGATING;
}
-static void viewops_data_create(bContext *C, wmOperator *op, const wmEvent *event)
+static void viewops_data_create(bContext *C, wmOperator *op, const wmEvent *event, bool switch_from_camera)
{
- viewops_data_create_ex(
- C, op, event,
- (U.uiflag & USER_ORBIT_SELECTION) != 0,
- (U.uiflag & USER_ZBUF_ORBIT) != 0);
+ enum eViewOpsOrbit orbit_mode = viewops_orbit_mode();
+ viewops_data_create_ex(C, op, event, switch_from_camera, orbit_mode);
}
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;
@@ -850,7 +882,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);
}
/** \} */
@@ -1233,16 +1267,7 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
- /* switch from camera view when: */
- if (view3d_ensure_persp(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.
- */
- ED_region_tag_redraw(vod->ar);
- }
-
- viewops_data_create(C, op, event);
+ viewops_data_create(C, op, event, true);
if (ELEM(event->type, MOUSEPAN, MOUSEROTATE)) {
/* Rotate direction we keep always same */
@@ -1329,6 +1354,8 @@ void VIEW3D_OT_rotate(wmOperatorType *ot)
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
}
+#ifdef WITH_INPUT_NDOF
+
/** \name NDOF Utility Functions
* \{ */
@@ -1649,8 +1676,9 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
const wmNDOFMotionData *ndof = event->customdata;
viewops_data_alloc(C, op);
- viewops_data_create_ex(C, op, event,
- (U.uiflag & USER_ORBIT_SELECTION) != 0, false);
+ viewops_data_create_ex(
+ C, op, event,
+ viewops_orbit_mode_ex((U.uiflag & USER_ORBIT_SELECTION) != 0, false), false);
vod = op->customdata;
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
@@ -1717,8 +1745,9 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev
const wmNDOFMotionData *ndof = event->customdata;
viewops_data_alloc(C, op);
- viewops_data_create_ex(C, op, event,
- (U.uiflag & USER_ORBIT_SELECTION) != 0, false);
+ viewops_data_create_ex(
+ C, op, event,
+ viewops_orbit_mode_ex((U.uiflag & USER_ORBIT_SELECTION) != 0, false), false);
vod = op->customdata;
@@ -1894,6 +1923,8 @@ void VIEW3D_OT_ndof_all(struct wmOperatorType *ot)
ot->flag = 0;
}
+#endif /* WITH_INPUT_NDOF */
+
/* ************************ viewmove ******************************** */
@@ -2030,7 +2061,7 @@ static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* makes op->customdata */
viewops_data_alloc(C, op);
- viewops_data_create(C, op, event);
+ viewops_data_create(C, op, event, false);
vod = op->customdata;
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
@@ -2511,7 +2542,7 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* makes op->customdata */
viewops_data_alloc(C, op);
- viewops_data_create(C, op, event);
+ viewops_data_create(C, op, event, false);
vod = op->customdata;
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
@@ -2593,6 +2624,19 @@ void VIEW3D_OT_zoom(wmOperatorType *ot)
/* ************************ viewdolly ******************************** */
+static bool viewdolly_offset_lock_check(bContext *C, wmOperator *op)
+{
+ View3D *v3d = CTX_wm_view3d(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if (ED_view3d_offset_lock_check(v3d, rv3d)) {
+ BKE_report(op->reports, RPT_WARNING, "Cannot dolly when the view offset is locked");
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
static void view_dolly_mouseloc(ARegion *ar, float orig_ofs[3], float dvec[3], float dfac)
{
RegionView3D *rv3d = ar->regiondata;
@@ -2743,7 +2787,7 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewOpsData *vod;
- if (view3d_operator_offset_lock_check(C, op))
+ if (viewdolly_offset_lock_check(C, op))
return OPERATOR_CANCELLED;
/* makes op->customdata */
@@ -2771,7 +2815,7 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
ED_region_tag_redraw(vod->ar);
}
- viewops_data_create(C, op, event);
+ viewops_data_create(C, op, event, false);
/* if one or the other zoom position aren't set, set from event */
@@ -2937,6 +2981,7 @@ static int view3d_all_exec(bContext *C, wmOperator *op) /* was view3d_home() in
ARegion *ar = CTX_wm_region(C);
View3D *v3d = CTX_wm_view3d(C);
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Base *base;
float *curs;
const bool use_all_regions = RNA_boolean_get(op->ptr, "use_all_regions");
@@ -2960,8 +3005,8 @@ static int view3d_all_exec(bContext *C, wmOperator *op) /* was view3d_home() in
INIT_MINMAX(min, max);
}
- for (base = scene->base.first; base; base = base->next) {
- if (BASE_VISIBLE(v3d, base)) {
+ for (base = sl->object_bases.first; base; base = base->next) {
+ if (BASE_VISIBLE_NEW(base)) {
changed = true;
if (skip_camera && base->object == v3d->camera) {
@@ -3021,9 +3066,10 @@ static int viewselected_exec(bContext *C, wmOperator *op)
ARegion *ar = CTX_wm_region(C);
View3D *v3d = CTX_wm_view3d(C);
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
bGPdata *gpd = CTX_data_gpencil_data(C);
const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE));
- Object *ob = OBACT;
+ Object *ob = OBACT_NEW;
Object *obedit = CTX_data_edit_object(C);
float min[3], max[3];
bool ok = false, ok_dist = true;
@@ -3043,8 +3089,8 @@ static int viewselected_exec(bContext *C, wmOperator *op)
/* 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)) {
+ for (base = sl->object_bases.first; base; base = base->next) {
+ if (TESTBASELIB_NEW(base)) {
if (base->object->type == OB_ARMATURE)
if (base->object->mode & OB_MODE_POSE)
break;
@@ -3077,7 +3123,7 @@ static int viewselected_exec(bContext *C, wmOperator *op)
ok = paintface_minmax(ob, min, max);
}
else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
- ok = PE_minmax(scene, min, max);
+ ok = PE_minmax(scene, sl, min, max);
}
else if (ob &&
(ob->mode & (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)))
@@ -3089,8 +3135,8 @@ static int viewselected_exec(bContext *C, wmOperator *op)
}
else {
Base *base;
- for (base = FIRSTBASE; base; base = base->next) {
- if (TESTBASE(v3d, base)) {
+ for (base = FIRSTBASE_NEW; base; base = base->next) {
+ if (TESTBASE_NEW(base)) {
if (skip_camera && base->object == v3d->camera) {
continue;
@@ -3267,10 +3313,10 @@ static int viewcenter_pick_invoke(bContext *C, wmOperator *op, const wmEvent *ev
{
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 *graph = CTX_data_depsgraph(C);
float new_ofs[3];
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
@@ -3278,13 +3324,13 @@ static int viewcenter_pick_invoke(bContext *C, wmOperator *op, const wmEvent *ev
view3d_operator_needs_opengl(C);
- if (ED_view3d_autodist(scene, ar, v3d, event->mval, new_ofs, false, NULL)) {
+ if (ED_view3d_autodist(graph, ar, v3d, event->mval, new_ofs, false, NULL)) {
/* pass */
}
else {
/* fallback to simple pan */
negate_v3_v3(new_ofs, rv3d->ofs);
- ED_view3d_win_to_3d_int(ar, new_ofs, event->mval, new_ofs);
+ ED_view3d_win_to_3d_int(v3d, ar, new_ofs, event->mval, new_ofs);
}
negate_v3(new_ofs);
ED_view3d_smooth_view(
@@ -3536,7 +3582,6 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
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);
int gesture_mode;
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
@@ -3550,9 +3595,8 @@ 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 p[3];
/* note; otherwise opengl won't work */
view3d_operator_needs_opengl(C);
@@ -3566,8 +3610,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(scene, ar, v3d, true);
+ ED_view3d_draw_depth(CTX_data_depsgraph(C), ar, v3d, true);
{
/* avoid allocating the whole depth buffer */
@@ -3582,11 +3625,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;
+ float centx = (((float)rect.xmin) + ((float)rect.xmax)) / 2;
+ float centy = (((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) {
@@ -3594,23 +3637,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, centx, centy, 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);
@@ -3625,13 +3659,9 @@ 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]))
+ if (depth_close != FLT_MAX && ED_view3d_unproject(ar, centx, centy, depth_close, p))
{
- new_ofs[0] = -p[0];
- new_ofs[1] = -p[1];
- new_ofs[2] = -p[2];
+ negate_v3_v3(new_ofs, p);
}
else {
float mval_f[2];
@@ -3868,6 +3898,7 @@ static int viewnumpad_exec(bContext *C, wmOperator *op)
ARegion *ar;
RegionView3D *rv3d;
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
static int perspo = RV3D_PERSP;
int viewnum, nextperspo;
bool align_active;
@@ -3902,7 +3933,7 @@ static int viewnumpad_exec(bContext *C, wmOperator *op)
/* lastview - */
if (rv3d->persp != RV3D_CAMOB) {
- Object *ob = OBACT;
+ Object *ob = OBACT_NEW;
if (!rv3d->smooth_timer) {
/* store settings of current view before allowing overwriting with camera view
@@ -4061,6 +4092,9 @@ static int vieworbit_exec(bContext *C, wmOperator *op)
mul_qt_qtqt(quat_new, rv3d->viewquat, quat_mul);
+ /* avoid precision loss over time */
+ normalize_qt(quat_new);
+
if (view_opposite != RV3D_VIEW_USER) {
rv3d->view = view_opposite;
/* avoid float in-precision, just get a new orientation */
@@ -4127,6 +4161,10 @@ static void view_roll_angle(ARegion *ar, float quat[4], const float orig_quat[4]
axis_angle_normalized_to_quat(quat_mul, dvec, angle);
mul_qt_qtqt(quat, orig_quat, quat_mul);
+
+ /* avoid precision loss over time */
+ normalize_qt(quat);
+
rv3d->view = RV3D_VIEW_USER;
}
@@ -4288,7 +4326,7 @@ static int viewroll_invoke(bContext *C, wmOperator *op, const wmEvent *event)
else {
/* makes op->customdata */
viewops_data_alloc(C, op);
- viewops_data_create(C, op, event);
+ viewops_data_create(C, op, event, false);
vod = op->customdata;
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar);
@@ -4354,41 +4392,24 @@ static EnumPropertyItem prop_view_pan_items[] = {
{0, NULL, 0, NULL, NULL}
};
-static int viewpan_exec(bContext *C, wmOperator *op)
+static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
- View3D *v3d = CTX_wm_view3d(C);
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- float vec[3];
- const float co_zero[3] = {0.0f};
- float mval_f[2] = {0.0f, 0.0f};
- float zfac;
- int pandir;
+ int x = 0, y = 0;
+ int pandir = RNA_enum_get(op->ptr, "type");
- if (view3d_operator_offset_lock_check(C, op))
- return OPERATOR_CANCELLED;
-
- pandir = RNA_enum_get(op->ptr, "type");
-
- ED_view3d_camera_lock_init(v3d, rv3d);
+ if (pandir == V3D_VIEW_PANRIGHT) { x = -32; }
+ else if (pandir == V3D_VIEW_PANLEFT) { x = 32; }
+ else if (pandir == V3D_VIEW_PANUP) { y = -25; }
+ else if (pandir == V3D_VIEW_PANDOWN) { y = 25; }
- zfac = ED_view3d_calc_zfac(rv3d, co_zero, NULL);
- if (pandir == V3D_VIEW_PANRIGHT) { mval_f[0] = -32.0f; }
- else if (pandir == V3D_VIEW_PANLEFT) { mval_f[0] = 32.0f; }
- else if (pandir == V3D_VIEW_PANUP) { mval_f[1] = -25.0f; }
- else if (pandir == V3D_VIEW_PANDOWN) { mval_f[1] = 25.0f; }
- ED_view3d_win_to_delta(ar, mval_f, vec, zfac);
- add_v3_v3(rv3d->ofs, vec);
-
- if (rv3d->viewlock & RV3D_BOXVIEW)
- view3d_boxview_sync(sa, ar);
-
- ED_view3d_depth_tag_update(rv3d);
+ viewops_data_alloc(C, op);
+ viewops_data_create(C, op, event, false);
+ ViewOpsData *vod = op->customdata;
- ED_view3d_camera_lock_sync(v3d, rv3d);
+ viewmove_apply(vod, vod->oldx + x, vod->oldy + y);
- ED_region_tag_redraw(ar);
+ ED_view3d_depth_tag_update(vod->rv3d);
+ viewops_data_free(C, op);
return OPERATOR_FINISHED;
}
@@ -4401,7 +4422,7 @@ void VIEW3D_OT_view_pan(wmOperatorType *ot)
ot->idname = "VIEW3D_OT_view_pan";
/* api callbacks */
- ot->exec = viewpan_exec;
+ ot->invoke = viewpan_invoke;
ot->poll = ED_operator_region_view3d_active;
/* flags */
@@ -4606,9 +4627,8 @@ void ED_view3d_clipping_local(RegionView3D *rv3d, float mat[4][4])
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);
@@ -4616,12 +4636,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);
-
- view3d_set_viewcontext(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;
}
@@ -4673,7 +4689,6 @@ void VIEW3D_OT_clip_border(wmOperatorType *ot)
/* note: cannot use event->mval here (called by object_add() */
void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2])
{
- Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = ar->regiondata;
@@ -4695,15 +4710,17 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2])
}
if (U.uiflag & USER_ZBUF_CURSOR) { /* maybe this should be accessed some other way */
+ struct Depsgraph *graph = CTX_data_depsgraph(C);
view3d_operator_needs_opengl(C);
- if (ED_view3d_autodist(scene, ar, v3d, mval, fp, true, NULL))
+ if (ED_view3d_autodist(graph, ar, v3d, mval, fp, true, NULL)) {
depth_used = true;
+ }
}
if (depth_used == false) {
float depth_pt[3];
copy_v3_v3(depth_pt, fp);
- ED_view3d_win_to_3d_int(ar, depth_pt, mval, fp);
+ ED_view3d_win_to_3d_int(v3d, ar, depth_pt, mval, fp);
}
}
@@ -4769,43 +4786,6 @@ void VIEW3D_OT_cursor3d(wmOperatorType *ot)
/* ***************** manipulator op ******************* */
-
-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;
-
- /* only no modifier or shift */
- if (event->keymodifier != 0 && event->keymodifier != KM_SHIFT) return OPERATOR_PASS_THROUGH;
-
- /* note; otherwise opengl won't work */
- view3d_operator_needs_opengl(C);
-
- if (0 == BIF_do_manipulator(C, event, op))
- return OPERATOR_PASS_THROUGH;
-
- return OPERATOR_FINISHED;
-}
-
-void VIEW3D_OT_manipulator(wmOperatorType *ot)
-{
-
- /* 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);
-}
-
static int enable_manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
View3D *v3d = CTX_wm_view3d(C);
@@ -4892,11 +4872,7 @@ static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int marg
rect.ymax = mval[1] + 1;
}
else {
- rect.xmax = mval[0] + margin;
- rect.ymax = mval[1] + margin;
-
- rect.xmin = mval[0] - margin;
- rect.ymin = mval[1] - margin;
+ BLI_rcti_init_pt_radius(&rect, mval, margin);
}
view3d_update_depths_rect(ar, &depth_temp, &rect);
@@ -4913,22 +4889,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(
- Scene *scene, ARegion *ar, View3D *v3d,
+ struct Depsgraph *graph, 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(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(graph, ar, v3d, alphaoverride);
/* Attempt with low margin's first */
i = 0;
@@ -4938,21 +4909,17 @@ 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]))
+ if (ED_view3d_unproject(ar, centx, centy, depth_close, mouse_worldloc))
{
- mouse_worldloc[0] = (float)p[0];
- mouse_worldloc[1] = (float)p[1];
- mouse_worldloc[2] = (float)p[2];
return true;
}
}
if (fallback_depth_pt) {
- ED_view3d_win_to_3d_int(ar, fallback_depth_pt, mval, mouse_worldloc);
+ ED_view3d_win_to_3d_int(v3d, ar, fallback_depth_pt, mval, mouse_worldloc);
return true;
}
else {
@@ -4960,16 +4927,21 @@ bool ED_view3d_autodist(
}
}
-void ED_view3d_autodist_init(Scene *scene, ARegion *ar, View3D *v3d, int mode)
+void ED_view3d_autodist_init(
+ struct Depsgraph *graph,
+ ARegion *ar, View3D *v3d, int mode)
{
/* Get Z Depths, needed for perspective, nice for ortho */
switch (mode) {
case 0:
- ED_view3d_draw_depth(scene, ar, v3d, true);
+ ED_view3d_draw_depth(graph, ar, v3d, true);
break;
case 1:
+ {
+ Scene *scene = DEG_get_evaluated_scene(graph);
ED_view3d_draw_depth_gpencil(scene, ar, v3d);
break;
+ }
}
}
@@ -4977,9 +4949,7 @@ void ED_view3d_autodist_init(Scene *scene, ARegion *ar, View3D *v3d, int mode)
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)
@@ -4990,21 +4960,9 @@ bool ED_view3d_autodist_simple(ARegion *ar, const int mval[2], float mouse_world
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)
@@ -5048,7 +5006,7 @@ bool ED_view3d_autodist_depth_seg(ARegion *ar, const int mval_sta[2], const int
copy_v2_v2_int(p1, mval_sta);
copy_v2_v2_int(p2, mval_end);
- plot_line_v2v2i(p1, p2, depth_segment_cb, &data);
+ BLI_bitmap_draw_2d_line_v2v2i(p1, p2, depth_segment_cb, &data);
*depth = data.depth;
diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c
index 31377d0fce8..85f44b528bc 100644
--- a/source/blender/editors/space_view3d/view3d_fly.c
+++ b/source/blender/editors/space_view3d/view3d_fly.c
@@ -26,8 +26,10 @@
/* defines VIEW3D_OT_fly modal operator */
-//#define NDOF_FLY_DEBUG
-//#define NDOF_FLY_DRAW_TOOMUCH /* is this needed for ndof? - commented so redraw doesnt thrash - campbell */
+#ifdef WITH_INPUT_NDOF
+//# define NDOF_FLY_DEBUG
+//# define NDOF_FLY_DRAW_TOOMUCH /* is this needed for ndof? - commented so redraw doesnt thrash - campbell */
+#endif /* WITH_INPUT_NDOF */
#include "DNA_object_types.h"
@@ -54,6 +56,8 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "GPU_immediate.h"
+
#include "view3d_intern.h" /* own include */
/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
@@ -203,7 +207,10 @@ typedef struct FlyInfo {
int mval[2]; /* latest 2D mouse values */
int center_mval[2]; /* center mouse values */
float width, height; /* camera viewport dimensions */
+
+#ifdef WITH_INPUT_NDOF
wmNDOFMotionData *ndof; /* latest 3D mouse values */
+#endif
/* fly state state */
float speed; /* the speed the view is moving per redraw */
@@ -252,36 +259,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);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformThemeColor(TH_VIEW_OVERLAY);
+
+ immBegin(GWN_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)
@@ -381,7 +397,10 @@ static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent
fly->timer = WM_event_add_timer(CTX_wm_manager(C), win, TIMER, 0.01f);
copy_v2_v2_int(fly->mval, event->mval);
+
+#ifdef WITH_INPUT_NDOF
fly->ndof = NULL;
+#endif
fly->time_lastdraw = fly->time_lastwheel = PIL_check_seconds_timer();
@@ -449,8 +468,10 @@ static int flyEnd(bContext *C, FlyInfo *fly)
rv3d->rflag &= ~RV3D_NAVIGATING;
+#ifdef WITH_INPUT_NDOF
if (fly->ndof)
MEM_freeN(fly->ndof);
+#endif
if (fly->state == FLY_CONFIRM) {
MEM_freeN(fly);
@@ -469,6 +490,7 @@ static void flyEvent(bContext *C, wmOperator *op, FlyInfo *fly, const wmEvent *e
else if (event->type == MOUSEMOVE) {
copy_v2_v2_int(fly->mval, event->mval);
}
+#ifdef WITH_INPUT_NDOF
else if (event->type == NDOF_MOTION) {
/* do these automagically get delivered? yes. */
// puts("ndof motion detected in fly mode!");
@@ -478,15 +500,15 @@ static void flyEvent(bContext *C, wmOperator *op, FlyInfo *fly, const wmEvent *e
switch (incoming_ndof->progress) {
case P_STARTING:
/* start keeping track of 3D mouse position */
-#ifdef NDOF_FLY_DEBUG
+# ifdef NDOF_FLY_DEBUG
puts("start keeping track of 3D mouse position");
-#endif
+# endif
/* fall-through */
case P_IN_PROGRESS:
/* update 3D mouse position */
-#ifdef NDOF_FLY_DEBUG
+# ifdef NDOF_FLY_DEBUG
putchar('.'); fflush(stdout);
-#endif
+# endif
if (fly->ndof == NULL) {
// fly->ndof = MEM_mallocN(sizeof(wmNDOFMotionData), tag_name);
fly->ndof = MEM_dupallocN(incoming_ndof);
@@ -498,9 +520,9 @@ static void flyEvent(bContext *C, wmOperator *op, FlyInfo *fly, const wmEvent *e
break;
case P_FINISHING:
/* stop keeping track of 3D mouse position */
-#ifdef NDOF_FLY_DEBUG
+# ifdef NDOF_FLY_DEBUG
puts("stop keeping track of 3D mouse position");
-#endif
+# endif
if (fly->ndof) {
MEM_freeN(fly->ndof);
// free(fly->ndof);
@@ -513,6 +535,7 @@ static void flyEvent(bContext *C, wmOperator *op, FlyInfo *fly, const wmEvent *e
break; /* should always be one of the above 3 */
}
}
+#endif /* WITH_INPUT_NDOF */
/* handle modal keymap first */
else if (event->type == EVT_MODAL_MAP) {
switch (event->val) {
@@ -959,6 +982,7 @@ static int flyApply(bContext *C, FlyInfo *fly)
return OPERATOR_FINISHED;
}
+#ifdef WITH_INPUT_NDOF
static void flyApply_ndof(bContext *C, FlyInfo *fly)
{
Object *lock_ob = ED_view3d_cameracontrol_object_get(fly->v3d_camera_control);
@@ -977,6 +1001,7 @@ static void flyApply_ndof(bContext *C, FlyInfo *fly)
}
}
}
+#endif /* WITH_INPUT_NDOF */
static int fly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
@@ -1023,12 +1048,15 @@ static int fly_modal(bContext *C, wmOperator *op, const wmEvent *event)
flyEvent(C, op, fly, event);
+#ifdef WITH_INPUT_NDOF
if (fly->ndof) { /* 3D mouse overrules [2D mouse + timer] */
if (event->type == NDOF_MOTION) {
flyApply_ndof(C, fly);
}
}
- else if (event->type == TIMER && event->customdata == fly->timer) {
+ else
+#endif /* WITH_INPUT_NDOF */
+ if (event->type == TIMER && event->customdata == fly->timer) {
flyApply(C, fly);
}
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index e864d83a9c4..e2ca076e5ad 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"
@@ -71,11 +72,10 @@ static void do_view3d_header_buttons(bContext *C, void *arg, int event);
/* 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 */
@@ -83,10 +83,6 @@ static void handle_view3d_lock(bContext *C)
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);
}
@@ -172,7 +168,7 @@ static int view3d_layers_exec(bContext *C, wmOperator *op)
if (v3d->scenelock) handle_view3d_lock(C);
- DAG_on_visible_update(CTX_data_main(C), false);
+ DEG_on_visible_update(CTX_data_main(C), false);
ED_area_tag_redraw(sa);
@@ -284,15 +280,16 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
ScrArea *sa = CTX_wm_area(C);
View3D *v3d = sa->spacedata.first;
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
ToolSettings *ts = CTX_data_tool_settings(C);
PointerRNA v3dptr, toolsptr, sceneptr;
- Object *ob = OBACT;
+ Object *ob = OBACT_NEW;
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);
@@ -303,47 +300,14 @@ 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);
- {
- 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);
+ 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);
}
- /* Draw type */
- uiItemR(layout, &v3dptr, "viewport_shade", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
-
if (obedit == NULL && is_paint) {
- if (ob->mode & OB_MODE_ALL_PAINT) {
- /* Only for Weight Paint. makes no sense in other paint modes. */
- row = uiLayoutRow(layout, true);
- uiItemR(row, &v3dptr, "pivot_point", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
- }
-
/* Manipulators aren't used in paint modes */
if (!ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_PARTICLE_EDIT, OB_MODE_HAIR_EDIT)) {
/* masks aren't used for sculpt and particle painting */
@@ -361,32 +325,16 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
}
}
else {
- row = uiLayoutRow(layout, true);
- uiItemR(row, &v3dptr, "pivot_point", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
-
- /* pose/object only however we want to allow in weight paint mode too
- * so don't be totally strict and just check not-editmode for now
- * XXX We never get here when we are in Weight Paint mode
- */
- if (obedit == NULL) {
- uiItemR(row, &v3dptr, "use_pivot_point_align", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
- }
-
/* Transform widget / manipulators */
row = uiLayoutRow(layout, true);
uiItemR(row, &v3dptr, "show_manipulator", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
- if (v3d->twflag & V3D_USE_MANIPULATOR) {
+ if (v3d->twflag & V3D_MANIPULATOR_DRAW) {
uiItemR(row, &v3dptr, "transform_manipulators", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
}
uiItemR(row, &v3dptr, "transform_orientation", 0, "", ICON_NONE);
}
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);
}
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index 6d8b87158b1..b3b40b5eb83 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -38,6 +38,7 @@
struct ARegion;
struct ARegionType;
struct BoundBox;
+struct Gwn_Batch;
struct DerivedMesh;
struct Object;
struct SmokeDomainSettings;
@@ -46,11 +47,13 @@ struct bContext;
struct bMotionPath;
struct bPoseChannel;
struct Mesh;
+struct SceneLayer;
struct BMEditStrands;
-struct wmNDOFMotionData;
+
struct wmOperatorType;
struct wmWindowManager;
struct wmKeyConfig;
+struct wmManipulatorGroupType;
/* drawing flags: */
enum {
@@ -77,10 +80,12 @@ void VIEW3D_OT_dolly(struct wmOperatorType *ot);
void VIEW3D_OT_zoom_camera_1_to_1(struct wmOperatorType *ot);
void VIEW3D_OT_move(struct wmOperatorType *ot);
void VIEW3D_OT_rotate(struct wmOperatorType *ot);
+#ifdef WITH_INPUT_NDOF
void VIEW3D_OT_ndof_orbit(struct wmOperatorType *ot);
void VIEW3D_OT_ndof_orbit_zoom(struct wmOperatorType *ot);
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_selected(struct wmOperatorType *ot);
@@ -99,7 +104,6 @@ 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_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);
@@ -112,11 +116,15 @@ void view3d_orbit_apply_dyn_ofs(
float r_ofs[3], const float ofs_old[3], const float viewquat_old[4],
const float viewquat_new[4], const float dyn_ofs[3]);
+#ifdef WITH_INPUT_NDOF
+struct wmNDOFMotionData;
+
void view3d_ndof_fly(
const struct wmNDOFMotionData *ndof,
struct View3D *v3d, struct RegionView3D *rv3d,
const bool use_precision, const short protectflag,
bool *r_has_translate, bool *r_has_rotate);
+#endif /* WITH_INPUT_NDOF */
/* view3d_fly.c */
void view3d_keymap(struct wmKeyConfig *keyconf);
@@ -138,17 +146,31 @@ void draw_motion_paths_cleanup(View3D *v3d);
/* drawobject.c */
-void draw_object(Scene *scene, struct 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(Scene *scene, struct SceneLayer *sl, struct ARegion *ar, View3D *v3d, BaseLegacy *base, const short dflag);
+void draw_object_select(Scene *scene, struct SceneLayer *sl, struct ARegion *ar, View3D *v3d, Base *base, const short dflag);
+
+void draw_mesh_object_outline(View3D *v3d, Object *ob, struct DerivedMesh *dm, const unsigned char ob_wire_col[4]);
+
+bool draw_glsl_material(Scene *scene, struct SceneLayer *sl, struct Object *ob, View3D *v3d, const char dt);
+void draw_object_instance(Scene *scene, struct SceneLayer *sl, View3D *v3d, RegionView3D *rv3d, struct Object *ob, const char dt, int outline, const float wire_col[4]);
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 draw_object_wire_color(Scene *scene, struct SceneLayer *, Base *base, unsigned char r_ob_wire_col[4]);
+void drawaxes(const float viewmat_local[4][4], float size, char drawtype, const unsigned char color[4]);
+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);
+void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
+ const short dflag, const unsigned char ob_wire_col[4]);
+void drawspeaker(const unsigned char ob_wire_col[3]);
+void draw_bounding_volume(struct Object *ob, char type, const unsigned char ob_wire_col[4]);
+void draw_rigidbody_shape(struct Object *ob, const unsigned char ob_wire_col[4]);
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, float mat[4][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);
@@ -163,12 +185,12 @@ enum {
int view3d_effective_drawtype(const struct View3D *v3d);
/* drawarmature.c */
-bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
+bool draw_armature(Scene *scene, struct SceneLayer *sl, 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,
+void draw_mesh_textured(Scene *scene, struct SceneLayer *sl, 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,
@@ -192,12 +214,24 @@ void draw_strands_edit_hair(Scene *scene, View3D *v3d, ARegion *ar, struct BMEdi
/* view3d_draw.c */
void view3d_main_region_draw(const struct bContext *C, struct ARegion *ar);
-void ED_view3d_draw_depth(Scene *scene, struct ARegion *ar, View3D *v3d, bool alphaoverride);
+void view3d_draw_region_info(const struct bContext *C, struct ARegion *ar, const int offset);
+
+void ED_view3d_draw_depth(
+ struct Depsgraph *graph,
+ struct ARegion *ar, View3D *v3d, bool alphaoverride);
+
+/* view3d_draw_legacy.c */
+void view3d_main_region_draw_legacy(const struct bContext *C, struct ARegion *ar);
void ED_view3d_draw_depth_gpencil(Scene *scene, 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 ED_view3d_draw_select_loop(
+ ViewContext *vc, Scene *scene, struct SceneLayer *sl, View3D *v3d, ARegion *ar,
+ bool use_obedit_skip, bool use_nearest);
+
+void ED_view3d_draw_depth_loop(Scene *scene, ARegion *ar, View3D *v3d);
+
+void ED_view3d_after_add(ListBase *lb, BaseLegacy *base, const short dflag);
+
void view3d_update_depths_rect(struct ARegion *ar, struct ViewDepths *d, struct rcti *rect);
float view3d_depth_near(struct ViewDepths *d);
@@ -212,7 +246,6 @@ 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);
@@ -240,7 +273,7 @@ void ED_view3d_smooth_view_force_finish(
struct bContext *C,
struct View3D *v3d, struct ARegion *ar);
-void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rctf *rect);
+void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rcti *rect);
void view3d_viewmatrix_set(Scene *scene, const View3D *v3d, RegionView3D *rv3d);
void fly_modal_keymap(struct wmKeyConfig *keyconf);
@@ -290,20 +323,18 @@ ARegion *view3d_has_tools_region(ScrArea *sa);
extern const char *view3d_context_dir[]; /* doc access */
+/* view3d_widgets.c */
+void VIEW3D_WGT_lamp (struct wmManipulatorGroupType *wgt);
+void VIEW3D_WGT_camera (struct wmManipulatorGroupType *wgt);
+void VIEW3D_WGT_force_field (struct wmManipulatorGroupType *wgt);
+void VIEW3D_WGT_armature_facemaps(struct wmManipulatorGroupType *wgt);
+
/* draw_volume.c */
void draw_smoke_volume(struct SmokeDomainSettings *sds, struct Object *ob,
const float min[3], const float max[3],
const float viewnormal[3]);
-//#define SMOKE_DEBUG_VELOCITY
-//#define SMOKE_DEBUG_HEAT
-
-#ifdef SMOKE_DEBUG_VELOCITY
-void draw_smoke_velocity(struct SmokeDomainSettings *domain, struct Object *ob);
-#endif
-#ifdef SMOKE_DEBUG_HEAT
-void draw_smoke_heat(struct SmokeDomainSettings *domain, struct Object *ob);
-#endif
+void draw_smoke_velocity(struct SmokeDomainSettings *domain, float viewnormal[3]);
/* workaround for trivial but noticeable camera bug caused by imprecision
* between view border calculation in 2D/3D space, workaround for bug [#28037].
@@ -316,5 +347,30 @@ extern unsigned char view3d_camera_border_hack_col[3];
extern bool view3d_camera_border_hack_test;
#endif
-#endif /* __VIEW3D_INTERN_H__ */
+/* temporary for legacy viewport to work */
+void VP_legacy_drawcursor(Scene *scene, struct SceneLayer *sl, ARegion *ar, View3D *v3d);
+void VP_legacy_draw_view_axis(RegionView3D *rv3d, rcti *rect);
+void VP_legacy_draw_viewport_name(ARegion *ar, View3D *v3d, rcti *rect);
+void VP_legacy_draw_selected_name(Scene *scene, Object *ob, rcti *rect);
+void VP_legacy_drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **grid_unit);
+void VP_legacy_drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool write_depth);
+void VP_legacy_view3d_main_region_setup_view(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4]);
+bool VP_legacy_view3d_stereo3d_active(const struct bContext *C, Scene *scene, View3D *v3d, RegionView3D *rv3d);
+void VP_legacy_view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar);
+void draw_dupli_objects(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d, BaseLegacy *base);
+bool VP_legacy_use_depth(Scene *scene, View3D *v3d);
+void VP_drawviewborder(Scene *scene, ARegion *ar, View3D *v3d);
+void VP_drawrenderborder(ARegion *ar, View3D *v3d);
+void VP_view3d_draw_background_none(void);
+void VP_view3d_draw_background_world(Scene *scene, View3D *v3d, RegionView3D *rv3d);
+void VP_view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar);
+
+/* temporary legacy calls, only when there is a switch between new/old draw calls */
+void VP_deprecated_gpu_update_lamps_shadows_world(Scene *scene, View3D *v3d);
+void VP_deprecated_view3d_draw_objects(
+ const struct bContext *C,
+ Scene *scene, View3D *v3d, ARegion *ar,
+ const char **grid_unit,
+ const bool do_bgpic, const bool draw_offscreen, struct GPUFX *fx);
+#endif /* __VIEW3D_INTERN_H__ */
diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c
index ce4b7f7deeb..ef7b01f7a21 100644
--- a/source/blender/editors/space_view3d/view3d_iterators.c
+++ b/source/blender/editors/space_view3d/view3d_iterators.c
@@ -119,7 +119,7 @@ void meshobject_foreachScreenVert(
data.clip_flag = clip_flag;
if (clip_flag & V3D_PROJ_TEST_CLIP_BB) {
- ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
+ ED_view3d_clipping_local(vc->rv3d, vc->obact->obmat);
}
dm->foreachMappedVert(dm, meshobject_foreachScreenVert__mapFunc, &data, DM_FOREACH_NOP);
diff --git a/source/blender/editors/space_view3d/view3d_manipulators.c b/source/blender/editors/space_view3d/view3d_manipulators.c
new file mode 100644
index 00000000000..3a12fc31ba2
--- /dev/null
+++ b/source/blender/editors/space_view3d/view3d_manipulators.c
@@ -0,0 +1,375 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/editors/space_view3d/view3d_manipulators.c
+ * \ingroup spview3d
+ */
+
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_armature.h"
+#include "BKE_camera.h"
+#include "BKE_context.h"
+#include "BKE_object.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+
+#include "ED_armature.h"
+#include "ED_screen.h"
+#include "ED_manipulator_library.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "view3d_intern.h" /* own include */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Lamp Manipulators
+ * \{ */
+
+static bool WIDGETGROUP_lamp_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt))
+{
+ 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_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup)
+{
+ const char *propname = "spot_size";
+
+ const float color[4] = {0.5f, 0.5f, 1.0f, 1.0f};
+ const float color_hi[4] = {0.8f, 0.8f, 0.45f, 1.0f};
+
+ wmManipulatorWrapper *wwrapper = MEM_mallocN(sizeof(wmManipulatorWrapper), __func__);
+
+ wwrapper->manipulator = WM_manipulator_new("MANIPULATOR_WT_arrow_3d", mgroup, propname, NULL);
+ RNA_enum_set(wwrapper->manipulator->ptr, "draw_options", ED_MANIPULATOR_ARROW_STYLE_INVERTED);
+
+ mgroup->customdata = wwrapper;
+
+ ED_manipulator_arrow3d_set_range_fac(wwrapper->manipulator, 4.0f);
+ WM_manipulator_set_color(wwrapper->manipulator, color);
+ WM_manipulator_set_color_highlight(wwrapper->manipulator, color_hi);
+}
+
+static void WIDGETGROUP_lamp_refresh(const bContext *C, wmManipulatorGroup *mgroup)
+{
+ wmManipulatorWrapper *wwrapper = mgroup->customdata;
+ Object *ob = CTX_data_active_object(C);
+ Lamp *la = ob->data;
+ float dir[3];
+
+ negate_v3_v3(dir, ob->obmat[2]);
+
+ WM_manipulator_set_matrix_rotation_from_z_axis(wwrapper->manipulator, dir);
+ WM_manipulator_set_matrix_location(wwrapper->manipulator, 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_Lamp, la, &lamp_ptr);
+ WM_manipulator_target_property_def_rna(wwrapper->manipulator, "offset", &lamp_ptr, propname, -1);
+}
+
+void VIEW3D_WGT_lamp(wmManipulatorGroupType *wgt)
+{
+ wgt->name = "Lamp Widgets";
+ wgt->idname = "VIEW3D_WGT_lamp";
+
+ wgt->flag |= (WM_MANIPULATORGROUPTYPE_PERSISTENT |
+ WM_MANIPULATORGROUPTYPE_3D |
+ WM_MANIPULATORGROUPTYPE_DEPTH_3D);
+
+ wgt->poll = WIDGETGROUP_lamp_poll;
+ wgt->setup = WIDGETGROUP_lamp_setup;
+ wgt->refresh = WIDGETGROUP_lamp_refresh;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Camera Manipulators
+ * \{ */
+
+struct CameraWidgetGroup {
+ wmManipulator *dop_dist;
+ wmManipulator *focal_len;
+ wmManipulator *ortho_scale;
+};
+
+static bool WIDGETGROUP_camera_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt))
+{
+ Object *ob = CTX_data_active_object(C);
+
+ return (ob && ob->type == OB_CAMERA);
+}
+
+static void cameragroup_property_setup(wmManipulator *widget, Object *ob, Camera *ca, const bool is_ortho)
+{
+ const float scale[3] = {1.0f / len_v3(ob->obmat[0]), 1.0f / len_v3(ob->obmat[1]), 1.0f / len_v3(ob->obmat[2])};
+ const float scale_fac = ca->drawsize;
+ const float drawsize = is_ortho ?
+ (0.5f * ca->ortho_scale) :
+ (scale_fac / ((scale[0] + scale[1] + scale[2]) / 3.0f));
+ const float half_sensor = 0.5f * ((ca->sensor_fit == CAMERA_SENSOR_FIT_VERT) ? ca->sensor_y : ca->sensor_x);
+ const char *propname = is_ortho ? "ortho_scale" : "lens";
+
+ PointerRNA camera_ptr;
+ float min, max, range;
+ float step, precision;
+
+ RNA_pointer_create(&ca->id, &RNA_Camera, ca, &camera_ptr);
+
+ /* get property range */
+ PropertyRNA *prop = RNA_struct_find_property(&camera_ptr, propname);
+ RNA_property_float_ui_range(&camera_ptr, prop, &min, &max, &step, &precision);
+ range = max - min;
+
+ ED_manipulator_arrow3d_set_range_fac(widget, is_ortho ? (scale_fac * range) : (drawsize * range / half_sensor));
+}
+
+static void WIDGETGROUP_camera_setup(const bContext *C, wmManipulatorGroup *mgroup)
+{
+ Object *ob = CTX_data_active_object(C);
+ Camera *ca = ob->data;
+ float dir[3];
+
+ const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_3d", true);
+
+ struct CameraWidgetGroup *camgroup = MEM_callocN(sizeof(struct CameraWidgetGroup), __func__);
+ mgroup->customdata = camgroup;
+
+ negate_v3_v3(dir, ob->obmat[2]);
+
+ /* dof distance */
+ {
+ const float color[4] = {1.0f, 0.3f, 0.0f, 1.0f};
+ const float color_hi[4] = {1.0f, 0.3f, 0.0f, 1.0f};
+
+ camgroup->dop_dist = WM_manipulator_new_ptr(wt_arrow, mgroup, "dof_distance", NULL);
+ RNA_enum_set(camgroup->dop_dist->ptr, "draw_style", ED_MANIPULATOR_ARROW_STYLE_CROSS);
+ WM_manipulator_set_flag(camgroup->dop_dist, WM_MANIPULATOR_DRAW_HOVER, true);
+ WM_manipulator_set_color(camgroup->dop_dist, color);
+ WM_manipulator_set_color_highlight(camgroup->dop_dist, color_hi);
+ }
+
+ /* focal length
+ * - logic/calculations are similar to BKE_camera_view_frame_ex, better keep in sync */
+ {
+ const float color[4] = {1.0f, 1.0, 0.27f, 0.5f};
+ const float color_hi[4] = {1.0f, 1.0, 0.27f, 1.0f};
+
+ camgroup->focal_len = WM_manipulator_new_ptr(wt_arrow, mgroup, "focal_len", NULL);
+ RNA_enum_set(camgroup->focal_len->ptr, "draw_style", ED_MANIPULATOR_ARROW_STYLE_CONE);
+ RNA_enum_set(camgroup->focal_len->ptr, "draw_options", ED_MANIPULATOR_ARROW_STYLE_CONSTRAINED);
+
+ WM_manipulator_set_color(camgroup->focal_len, color);
+ WM_manipulator_set_color_highlight(camgroup->focal_len, color_hi);
+ cameragroup_property_setup(camgroup->focal_len, ob, ca, false);
+
+ camgroup->ortho_scale = WM_manipulator_new_ptr(wt_arrow, mgroup, "ortho_scale", NULL);
+ RNA_enum_set(camgroup->ortho_scale->ptr, "draw_style", ED_MANIPULATOR_ARROW_STYLE_CONE);
+ RNA_enum_set(camgroup->ortho_scale->ptr, "draw_options", ED_MANIPULATOR_ARROW_STYLE_CONSTRAINED);
+
+ WM_manipulator_set_color(camgroup->ortho_scale, color);
+ WM_manipulator_set_color_highlight(camgroup->ortho_scale, color_hi);
+ cameragroup_property_setup(camgroup->ortho_scale, ob, ca, true);
+ }
+}
+
+static void WIDGETGROUP_camera_refresh(const bContext *C, wmManipulatorGroup *mgroup)
+{
+ if (!mgroup->customdata)
+ return;
+
+ struct CameraWidgetGroup *camgroup = mgroup->customdata;
+ Object *ob = CTX_data_active_object(C);
+ Camera *ca = ob->data;
+ PointerRNA camera_ptr;
+ float dir[3];
+
+ RNA_pointer_create(&ca->id, &RNA_Camera, ca, &camera_ptr);
+
+ negate_v3_v3(dir, ob->obmat[2]);
+
+ if (ca->flag & CAM_SHOWLIMITS) {
+ WM_manipulator_set_matrix_location(camgroup->dop_dist, ob->obmat[3]);
+ WM_manipulator_set_matrix_rotation_from_yz_axis(camgroup->dop_dist, ob->obmat[1], dir);
+ WM_manipulator_set_scale(camgroup->dop_dist, ca->drawsize);
+ WM_manipulator_set_flag(camgroup->dop_dist, WM_MANIPULATOR_HIDDEN, false);
+
+ /* need to set property here for undo. TODO would prefer to do this in _init */
+ WM_manipulator_target_property_def_rna(camgroup->dop_dist, "offset", &camera_ptr, "dof_distance", -1);
+ }
+ else {
+ WM_manipulator_set_flag(camgroup->dop_dist, WM_MANIPULATOR_HIDDEN, true);
+ }
+
+ /* TODO - make focal length/ortho scale widget optional */
+ if (true) {
+ const bool is_ortho = (ca->type == CAM_ORTHO);
+ const float scale[3] = {1.0f / len_v3(ob->obmat[0]), 1.0f / len_v3(ob->obmat[1]), 1.0f / len_v3(ob->obmat[2])};
+ const float scale_fac = ca->drawsize;
+ const float drawsize = is_ortho ?
+ (0.5f * ca->ortho_scale) :
+ (scale_fac / ((scale[0] + scale[1] + scale[2]) / 3.0f));
+ float offset[3];
+ float aspect[2];
+
+ wmManipulator *widget = is_ortho ? camgroup->ortho_scale : camgroup->focal_len;
+ WM_manipulator_set_flag(widget, WM_MANIPULATOR_HIDDEN, false);
+ WM_manipulator_set_flag(is_ortho ? camgroup->focal_len : camgroup->ortho_scale, WM_MANIPULATOR_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 */
+ 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 int sensor_fit = BKE_camera_sensor_fit(ca->sensor_fit, aspx, aspy);
+ aspect[0] = (sensor_fit == CAMERA_SENSOR_FIT_HOR) ? 1.0 : aspx / aspy;
+ aspect[1] = (sensor_fit == CAMERA_SENSOR_FIT_HOR) ? aspy / aspx : 1.0f;
+
+ WM_manipulator_set_matrix_location(widget, ob->obmat[3]);
+ WM_manipulator_set_matrix_rotation_from_yz_axis(widget, ob->obmat[1], dir);
+
+ RNA_float_set_array(widget->ptr, "aspect", aspect);
+
+ WM_manipulator_set_matrix_offset_location(widget, offset);
+ WM_manipulator_set_scale(widget, drawsize);
+
+ /* need to set property here for undo. TODO would prefer to do this in _init */
+ WM_manipulator_target_property_def_rna(camgroup->focal_len, "offset", &camera_ptr, "lens", -1);
+ WM_manipulator_target_property_def_rna(camgroup->ortho_scale, "offset", &camera_ptr, "ortho_scale", -1);
+ }
+}
+
+void VIEW3D_WGT_camera(wmManipulatorGroupType *wgt)
+{
+ wgt->name = "Camera Widgets";
+ wgt->idname = "VIEW3D_WGT_camera";
+
+ wgt->flag = (WM_MANIPULATORGROUPTYPE_PERSISTENT |
+ WM_MANIPULATORGROUPTYPE_3D |
+ WM_MANIPULATORGROUPTYPE_SCALE |
+ WM_MANIPULATORGROUPTYPE_DEPTH_3D);
+
+ wgt->poll = WIDGETGROUP_camera_poll;
+ wgt->setup = WIDGETGROUP_camera_setup;
+ wgt->refresh = WIDGETGROUP_camera_refresh;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Force Field Manipulators
+ * \{ */
+
+static bool WIDGETGROUP_forcefield_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt))
+{
+ Object *ob = CTX_data_active_object(C);
+
+ return (ob && ob->pd && ob->pd->forcefield);
+}
+
+static void WIDGETGROUP_forcefield_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup)
+{
+ const float col[4] = {0.8f, 0.8f, 0.45f, 0.5f};
+ const float col_hi[4] = {0.8f, 0.8f, 0.45f, 1.0f};
+
+ /* only wind effector for now */
+ wmManipulatorWrapper *wwrapper = MEM_mallocN(sizeof(wmManipulatorWrapper), __func__);
+ mgroup->customdata = wwrapper;
+
+ wwrapper->manipulator = WM_manipulator_new("MANIPULATOR_WT_arrow_3d", mgroup, "field_strength", NULL);
+ RNA_enum_set(wwrapper->manipulator->ptr, "draw_options", ED_MANIPULATOR_ARROW_STYLE_CONSTRAINED);
+ ED_manipulator_arrow3d_set_ui_range(wwrapper->manipulator, -200.0f, 200.0f);
+ ED_manipulator_arrow3d_set_range_fac(wwrapper->manipulator, 6.0f);
+ WM_manipulator_set_color(wwrapper->manipulator, col);
+ WM_manipulator_set_color_highlight(wwrapper->manipulator, col_hi);
+}
+
+static void WIDGETGROUP_forcefield_refresh(const bContext *C, wmManipulatorGroup *mgroup)
+{
+ wmManipulatorWrapper *wwrapper = mgroup->customdata;
+ 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_manipulator_set_matrix_location(wwrapper->manipulator, ob->obmat[3]);
+ WM_manipulator_set_matrix_rotation_from_z_axis(wwrapper->manipulator, ob->obmat[2]);
+ WM_manipulator_set_matrix_offset_location(wwrapper->manipulator, ofs);
+ WM_manipulator_set_flag(wwrapper->manipulator, WM_MANIPULATOR_HIDDEN, false);
+ WM_manipulator_target_property_def_rna(wwrapper->manipulator, "offset", &field_ptr, "strength", -1);
+ }
+ else {
+ WM_manipulator_set_flag(wwrapper->manipulator, WM_MANIPULATOR_HIDDEN, true);
+ }
+}
+
+void VIEW3D_WGT_force_field(wmManipulatorGroupType *wgt)
+{
+ wgt->name = "Force Field Widgets";
+ wgt->idname = "VIEW3D_WGT_force_field";
+
+ wgt->flag |= (WM_MANIPULATORGROUPTYPE_PERSISTENT |
+ WM_MANIPULATORGROUPTYPE_3D |
+ WM_MANIPULATORGROUPTYPE_SCALE |
+ WM_MANIPULATORGROUPTYPE_DEPTH_3D);
+
+ wgt->poll = WIDGETGROUP_forcefield_poll;
+ wgt->setup = WIDGETGROUP_forcefield_setup;
+ wgt->refresh = WIDGETGROUP_forcefield_refresh;
+}
+
+/** \} */
+
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index b273f46fca3..6f05dd353d7 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -119,8 +119,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 +152,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 **********************************/
@@ -164,10 +164,12 @@ void view3d_operatortypes(void)
WM_operatortype_append(VIEW3D_OT_zoom);
WM_operatortype_append(VIEW3D_OT_zoom_camera_1_to_1);
WM_operatortype_append(VIEW3D_OT_dolly);
+#ifdef WITH_INPUT_NDOF
WM_operatortype_append(VIEW3D_OT_ndof_orbit_zoom);
WM_operatortype_append(VIEW3D_OT_ndof_orbit);
WM_operatortype_append(VIEW3D_OT_ndof_pan);
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_orbit);
@@ -191,7 +193,6 @@ void view3d_operatortypes(void)
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);
@@ -199,7 +200,6 @@ void view3d_operatortypes(void)
WM_operatortype_append(VIEW3D_OT_camera_to_view);
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_fly);
WM_operatortype_append(VIEW3D_OT_walk);
@@ -238,13 +238,6 @@ void view3d_keymap(wmKeyConfig *keyconf)
/* only for region 3D window */
keymap = WM_keymap_find(keyconf, "3D View", SPACE_VIEW3D, 0);
- kmi = WM_keymap_verify_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_ANY, 0);
- RNA_boolean_set(kmi->ptr, "release_confirm", true);
- /*
- * Doesn't work with KM_SHIFT, have to use KM_ANY and filter in invoke
- * */
- // WM_keymap_verify_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0);
-
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);
@@ -360,10 +353,8 @@ void view3d_keymap(wmKeyConfig *keyconf)
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);
- /* NDOF: begin */
+#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);
@@ -392,8 +383,7 @@ void view3d_keymap(wmKeyConfig *keyconf)
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);
- /* NDOF: end */
-
+#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);
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index 7448d4c658e..f8b02f0b405 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -28,6 +28,7 @@
* \ingroup spview3d
*/
+#include "DNA_camera_types.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "DNA_scene_types.h"
@@ -35,13 +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
@@ -462,9 +463,12 @@ bool view3d_get_view_aligned_coordinate(ARegion *ar, float fp[3], const int mval
* \param ar The region (used for the window width and height).
* \param depth_pt The reference location used to calculate the Z depth.
* \param mval The area relative location (such as event->mval converted to floats).
- * \param out The resulting world-space location.
+ * \param r_out The resulting world-space location.
*/
-void ED_view3d_win_to_3d(const ARegion *ar, const float depth_pt[3], const float mval[2], float out[3])
+void ED_view3d_win_to_3d(
+ const View3D *v3d, const ARegion *ar,
+ const float depth_pt[3], const float mval[2],
+ float r_out[3])
{
RegionView3D *rv3d = ar->regiondata;
@@ -488,11 +492,19 @@ void ED_view3d_win_to_3d(const ARegion *ar, const float depth_pt[3], const float
else {
float dx = (2.0f * mval[0] / (float)ar->winx) - 1.0f;
float dy = (2.0f * mval[1] / (float)ar->winy) - 1.0f;
+
if (rv3d->persp == RV3D_CAMOB) {
/* ortho camera needs offset applied */
+ const Camera *cam = v3d->camera->data;
+ const int sensor_fit = BKE_camera_sensor_fit(cam->sensor_fit, ar->winx, ar->winy);
const float zoomfac = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom) * 4.0f;
- dx += rv3d->camdx * zoomfac;
- dy += rv3d->camdy * zoomfac;
+ const float aspx = ar->winx / (float)ar->winy;
+ const float aspy = ar->winy / (float)ar->winx;
+ const float shiftx = cam->shiftx * 0.5f * (sensor_fit == CAMERA_SENSOR_FIT_HOR ? 1.0f : aspy);
+ const float shifty = cam->shifty * 0.5f * (sensor_fit == CAMERA_SENSOR_FIT_HOR ? aspx : 1.0f);
+
+ dx += (rv3d->camdx + shiftx) * zoomfac;
+ dy += (rv3d->camdy + shifty) * zoomfac;
}
ray_origin[0] = (rv3d->persinv[0][0] * dx) + (rv3d->persinv[1][0] * dy) + rv3d->viewinv[3][0];
ray_origin[1] = (rv3d->persinv[0][1] * dx) + (rv3d->persinv[1][1] * dy) + rv3d->viewinv[3][1];
@@ -502,13 +514,16 @@ void ED_view3d_win_to_3d(const ARegion *ar, const float depth_pt[3], const float
lambda = ray_point_factor_v3(depth_pt, ray_origin, ray_direction);
}
- madd_v3_v3v3fl(out, ray_origin, ray_direction, lambda);
+ madd_v3_v3v3fl(r_out, ray_origin, ray_direction, lambda);
}
-void ED_view3d_win_to_3d_int(const ARegion *ar, const float depth_pt[3], const int mval[2], float out[3])
+void ED_view3d_win_to_3d_int(
+ const View3D *v3d, const ARegion *ar,
+ const float depth_pt[3], const int mval[2],
+ float r_out[3])
{
const float mval_fl[2] = {mval[0], mval[1]};
- ED_view3d_win_to_3d(ar, depth_pt, mval_fl, out);
+ ED_view3d_win_to_3d(v3d, ar, depth_pt, mval_fl, r_out);
}
/**
@@ -640,16 +655,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);
+ gpuProject(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 gpuUnProject(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 37b068e3e49..f62a12b071f 100644
--- a/source/blender/editors/space_view3d/view3d_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_ruler.c
@@ -43,6 +43,9 @@
#include "BIF_gl.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -280,7 +283,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), SNAP_OBJECT_USE_CACHE,
+ CTX_data_main(C), CTX_data_scene(C), CTX_data_scene_layer(C), 0,
ruler_info->ar, CTX_wm_view3d(C));
}
else {
@@ -297,6 +300,8 @@ static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info)
bGPDlayer *gpl;
bGPDframe *gpf;
bGPDstroke *gps;
+ bGPDpalette *palette;
+ bGPDpalettecolor *palcolor;
RulerItem *ruler_item;
const char *ruler_name = RULER_ID;
bool changed = false;
@@ -312,6 +317,17 @@ static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info)
gpl->flag |= GP_LAYER_HIDE;
}
+ /* try to get active palette or create a new one */
+ palette = BKE_gpencil_palette_getactive(scene->gpd);
+ if (palette == NULL) {
+ palette = BKE_gpencil_palette_addnew(scene->gpd, DATA_("GP_Palette"), true);
+ }
+ /* try to get color with the ruler name or create a new one */
+ palcolor = BKE_gpencil_palettecolor_getbyname(palette, (char *)ruler_name);
+ if (palcolor == NULL) {
+ palcolor = BKE_gpencil_palettecolor_addnew(palette, (char *)ruler_name, true);
+ }
+
gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true);
BKE_gpencil_free_strokes(gpf);
@@ -342,6 +358,10 @@ 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;
}
@@ -409,12 +429,11 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a
#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);
@@ -439,28 +458,37 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a
glEnable(GL_BLEND);
- cpack(is_act ? color_act : color_base);
+ const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("num_colors", 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(GWN_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];
@@ -484,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(GWN_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 */
@@ -544,75 +545,84 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a
glEnable(GL_BLEND);
- glColor3ubv(color_wire);
+ immUniformColor3ubv(color_wire);
- glBegin(GL_LINES);
+ immBegin(GWN_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);
+
+ immEnd();
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]);
- }
- glEnd();
- setlinestyle(0);
- sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[2]);
+ immUnbindProgram();
/* text */
{
char numstr[256];
float numstr_size[2];
- const int prec = 6; /* XXX, todo, make optional */
- float pos[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]);
- mid_v2_v2v2(pos, co_ss[0], co_ss[2]);
-
- /* center text */
- pos[0] -= numstr_size[0] / 2.0f;
- pos[1] -= numstr_size[1] / 2.0f;
+ posit[0] = co_ss[1][0] + (cap_size * 2.0f);
+ posit[1] = co_ss[1][1] - (numstr_size[1] / 2.0f);
/* 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);
+ UI_draw_roundbox_aa(true,
+ posit[0] - bg_margin, posit[1] - bg_margin,
+ posit[0] + bg_margin + numstr_size[0], posit[1] + bg_margin + numstr_size[1],
+ bg_radius, color_back);
/* 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];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("num_colors", 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(GWN_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 */
{
@@ -622,22 +632,56 @@ 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);
- glBegin(GL_LINES);
+ immUniformColor3ubv(color_wire);
+
+ immBegin(GWN_PRIM_LINES, 4);
+
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);
+
+ immEnd();
glDisable(GL_BLEND);
}
+
+ immUnbindProgram();
+
+ /* 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) */
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_aa(true,
+ posit[0] - bg_margin, posit[1] - bg_margin,
+ posit[0] + bg_margin + numstr_size[0], posit[1] + bg_margin + numstr_size[1],
+ bg_radius, color_back);
+ /* 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));
+ }
}
}
@@ -656,8 +700,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);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4fv(color_act);
+
+ imm_draw_circle_wire(pos, co_ss[0], co_ss[1], size * U.pixelsize, 32);
+
+ immUnbindProgram();
}
}
@@ -683,7 +733,7 @@ static void view3d_ruler_free(RulerInfo *ruler_info)
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->ar, r_co, xy, r_co);
+ ED_view3d_win_to_3d_int(ruler_info->sa->spacedata.first, ruler_info->ar, r_co, xy, r_co);
}
/* use for mousemove events */
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index e1c0a6be127..47ad86aede0 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -63,18 +63,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_utildefines.h"
-
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
+#include "DEG_depsgraph.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -97,9 +96,12 @@
#include "UI_interface.h"
#include "GPU_draw.h"
+#include "GPU_matrix.h"
#include "view3d_intern.h" /* own include */
+// #include "PIL_time_utildefines.h"
+
float ED_view3d_select_dist_px(void)
{
return 75.0f * U.pixelsize;
@@ -110,7 +112,9 @@ void view3d_set_viewcontext(bContext *C, ViewContext *vc)
{
memset(vc, 0, sizeof(ViewContext));
vc->ar = CTX_wm_region(C);
+ vc->depsgraph = CTX_data_depsgraph(C);
vc->scene = CTX_data_scene(C);
+ vc->scene_layer = CTX_data_scene_layer(C);
vc->v3d = CTX_wm_view3d(C);
vc->win = CTX_wm_window(C);
vc->rv3d = CTX_wm_region_view3d(C);
@@ -118,34 +122,6 @@ void view3d_set_viewcontext(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)
-{
- float cpy[4][4];
- int i, j;
-
- if (ob) {
- mul_m4_m4m4(cpy, rv3d->viewmat, ob->obmat);
- }
- else {
- copy_m4_m4(cpy, rv3d->viewmat);
- }
-
- 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];
- }
- }
-
- 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 */
@@ -396,18 +372,18 @@ static void do_lasso_select_pose(ViewContext *vc, Object *ob, const int mcords[]
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);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
}
}
-static void object_deselect_all_visible(Scene *scene, View3D *v3d)
+static void object_deselect_all_visible(SceneLayer *sl)
{
Base *base;
- for (base = scene->base.first; base; base = base->next) {
- if (BASE_SELECTABLE(v3d, base)) {
- ED_base_object_select(base, BA_DESELECT);
+ for (base = sl->object_bases.first; base; base = base->next) {
+ if (BASE_SELECTABLE_NEW(base)) {
+ ED_object_base_select(base, BA_DESELECT);
}
}
}
@@ -418,15 +394,14 @@ static void do_lasso_select_objects(ViewContext *vc, const int mcords[][2], cons
Base *base;
if (extend == false && select)
- object_deselect_all_visible(vc->scene, vc->v3d);
+ object_deselect_all_visible(vc->scene_layer);
- for (base = vc->scene->base.first; base; base = base->next) {
- if (BASE_SELECTABLE(vc->v3d, base)) { /* use this to avoid un-needed lasso lookups */
+ for (base = vc->scene_layer->object_bases.first; base; base = base->next) {
+ if (BASE_SELECTABLE_NEW(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)) {
- ED_base_object_select(base, select ? BA_SELECT : BA_DESELECT);
- base->object->flag = base->flag;
+ ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT);
}
}
if (vc->obact == base->object && (base->object->mode & OB_MODE_POSE)) {
@@ -503,7 +478,7 @@ static void do_lasso_select_mesh(ViewContext *vc, const int mcords[][2], short m
/* for non zbuf projections, don't change the GL state */
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- glLoadMatrixf(vc->rv3d->viewmat);
+ gpuLoadMatrix(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) {
@@ -935,7 +910,7 @@ static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
base = LASTBASE;
if (base == 0) return 0;
- maxob = base->selcol;
+ maxob = base->object->select_color;
len = (size - 1) / 2;
rc = 0;
@@ -1021,8 +996,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;
}
}
@@ -1033,8 +1008,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;
}
}
@@ -1078,25 +1053,26 @@ 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(SceneLayer *sl, Base *b) /* deselect all except b */
{
- Base *base;
-
- for (base = FIRSTBASE; base; base = base->next) {
- if (base->flag & SELECT) {
+ for (Base *base = sl->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);
}
}
}
}
-static Base *object_mouse_select_menu(bContext *C, ViewContext *vc, unsigned int *buffer, int hits, const int mval[2], short toggle)
+static Base *object_mouse_select_menu(
+ bContext *C, ViewContext *vc, unsigned int *buffer, int hits,
+ const int mval[2], bool toggle)
{
short baseCount = 0;
bool ok;
LinkNode *linklist = NULL;
-
+
+ /* handle base->object->select_color */
CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
{
ok = false;
@@ -1105,7 +1081,7 @@ static Base *object_mouse_select_menu(bContext *C, ViewContext *vc, unsigned int
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;
}
@@ -1182,19 +1158,19 @@ static bool selectbuffer_has_bones(const unsigned int *buffer, const unsigned in
}
/* utility function for mixed_bones_object_selectbuffer */
-static short selectbuffer_ret_hits_15(unsigned int *UNUSED(buffer), const short hits15)
+static int selectbuffer_ret_hits_15(unsigned int *UNUSED(buffer), const int hits15)
{
return hits15;
}
-static short selectbuffer_ret_hits_9(unsigned int *buffer, const short hits15, const short hits9)
+static int selectbuffer_ret_hits_9(unsigned int *buffer, const int hits15, const int hits9)
{
const int offs = 4 * hits15;
memcpy(buffer, buffer + offs, 4 * hits9 * sizeof(unsigned int));
return hits9;
}
-static short selectbuffer_ret_hits_5(unsigned int *buffer, const short hits15, const short hits9, const short hits5)
+static int selectbuffer_ret_hits_5(unsigned int *buffer, const int hits15, const int hits9, const int hits5)
{
const int offs = 4 * hits15 + 4 * hits9;
memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(unsigned int));
@@ -1203,14 +1179,13 @@ static short selectbuffer_ret_hits_5(unsigned int *buffer, const short hits15, c
/* we want a select buffer with bones, if there are... */
/* so check three selection levels and compare */
-static short mixed_bones_object_selectbuffer(
+static int mixed_bones_object_selectbuffer(
ViewContext *vc, unsigned int *buffer, const int mval[2],
bool use_cycle, bool enumerate,
bool *r_do_nearest)
{
rcti rect;
- int offs;
- short hits15, hits9 = 0, hits5 = 0;
+ int hits15, hits9 = 0, hits5 = 0;
bool has_bones15 = false, has_bones9 = false, has_bones5 = false;
static int last_mval[2] = {-100, -100};
bool do_nearest = false;
@@ -1238,52 +1213,64 @@ static short mixed_bones_object_selectbuffer(
do_nearest = do_nearest && !enumerate;
- BLI_rcti_init(&rect, mval[0] - 14, mval[0] + 14, mval[1] - 14, mval[1] + 14);
- hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, do_nearest);
+ 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 finally' */
+ view3d_opengl_select_cache_begin();
+
+ BLI_rcti_init_pt_radius(&rect, mval, 14);
+ hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode);
if (hits15 == 1) {
- return selectbuffer_ret_hits_15(buffer, hits15);
+ hits = selectbuffer_ret_hits_15(buffer, hits15);
+ goto finally;
}
else if (hits15 > 0) {
+ int offs;
has_bones15 = selectbuffer_has_bones(buffer, hits15);
offs = 4 * hits15;
- BLI_rcti_init(&rect, mval[0] - 9, mval[0] + 9, mval[1] - 9, mval[1] + 9);
- hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, do_nearest);
+ BLI_rcti_init_pt_radius(&rect, mval, 9);
+ hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode);
if (hits9 == 1) {
- return selectbuffer_ret_hits_9(buffer, hits15, hits9);
+ hits = selectbuffer_ret_hits_9(buffer, hits15, hits9);
+ goto finally;
}
else if (hits9 > 0) {
has_bones9 = selectbuffer_has_bones(buffer + offs, hits9);
offs += 4 * hits9;
- BLI_rcti_init(&rect, mval[0] - 5, mval[0] + 5, mval[1] - 5, mval[1] + 5);
- hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, do_nearest);
+ BLI_rcti_init_pt_radius(&rect, mval, 5);
+ hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode);
if (hits5 == 1) {
- return selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
+ hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
+ goto finally;
}
else if (hits5 > 0) {
has_bones5 = selectbuffer_has_bones(buffer + offs, hits5);
}
}
- if (has_bones5) return selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
- else if (has_bones9) return selectbuffer_ret_hits_9(buffer, hits15, hits9);
- else if (has_bones15) return selectbuffer_ret_hits_15(buffer, hits15);
-
- if (hits5 > 0) return selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
- else if (hits9 > 0) return selectbuffer_ret_hits_9(buffer, hits15, hits9);
- else return selectbuffer_ret_hits_15(buffer, hits15);
+ if (has_bones5) { hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5); goto finally; }
+ else if (has_bones9) { hits = selectbuffer_ret_hits_9(buffer, hits15, hits9); goto finally; }
+ else if (has_bones15) { hits = selectbuffer_ret_hits_15(buffer, hits15); goto finally; }
+
+ if (hits5 > 0) { hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5); goto finally; }
+ else if (hits9 > 0) { hits = selectbuffer_ret_hits_9(buffer, hits15, hits9); goto finally; }
+ else { hits = selectbuffer_ret_hits_15(buffer, hits15); goto finally; }
}
-
- return 0;
+
+finally:
+ view3d_opengl_select_cache_end();
+
+ return hits;
}
/* returns basact */
static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int hits,
Base *startbase, bool has_bones, bool do_nearest)
{
- Scene *scene = vc->scene;
- View3D *v3d = vc->v3d;
+ SceneLayer *sl = vc->scene_layer;
Base *base, *basact = NULL;
int a;
@@ -1303,7 +1290,9 @@ static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int
}
else {
/* only exclude active object when it is selected... */
- if (BASACT && (BASACT->flag & SELECT) && hits > 1) notcol = BASACT->selcol;
+ if (BASACT_NEW && (BASACT_NEW->flag & BASE_SELECTED) && hits > 1) {
+ notcol = BASACT_NEW->object->select_color;
+ }
for (a = 0; a < hits; a++) {
if (min > buffer[4 * a + 1] && notcol != (buffer[4 * a + 3] & 0xFFFF)) {
@@ -1313,10 +1302,10 @@ static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int
}
}
- base = FIRSTBASE;
+ base = FIRSTBASE_NEW;
while (base) {
- if (BASE_SELECTABLE(v3d, base)) {
- if (base->selcol == selcol) break;
+ if (BASE_SELECTABLE_NEW(base)) {
+ if (base->object->select_color == selcol) break;
}
base = base->next;
}
@@ -1328,23 +1317,23 @@ static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int
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_SELECTABLED) == 0) {
base = base->next;
- if (base == NULL) base = FIRSTBASE;
+ if (base == NULL) base = FIRSTBASE_NEW;
if (base == startbase) break;
}
- if (BASE_SELECTABLE(v3d, base)) {
+ if (BASE_SELECTABLE_NEW(base)) {
for (a = 0; a < hits; a++) {
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;
}
}
@@ -1353,7 +1342,7 @@ static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int
if (basact) break;
base = base->next;
- if (base == NULL) base = FIRSTBASE;
+ if (base == NULL) base = FIRSTBASE_NEW;
if (base == startbase) break;
}
}
@@ -1378,7 +1367,7 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
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.scene_layer->object_bases.first, has_bones, do_nearest);
}
return basact;
@@ -1410,13 +1399,13 @@ 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);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Base *base, *startbase = NULL, *basact = NULL, *oldbasact = NULL;
bool is_obedit;
float dist = ED_view3d_select_dist_px() * 1.3333f;
bool retval = false;
- short hits;
+ int hits;
const float mval_fl[2] = {(float)mval[0], (float)mval[1]};
@@ -1430,8 +1419,8 @@ static bool ed_object_select_pick(
}
/* always start list from basact in wire mode */
- startbase = FIRSTBASE;
- if (BASACT && BASACT->next) startbase = BASACT->next;
+ startbase = FIRSTBASE_NEW;
+ if (BASACT_NEW && BASACT_NEW->next) startbase = BASACT_NEW->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 */
@@ -1444,13 +1433,13 @@ static bool ed_object_select_pick(
else {
base = startbase;
while (base) {
- if (BASE_SELECTABLE(v3d, base)) {
+ if (BASE_SELECTABLE_NEW(base)) {
float screen_co[2];
if (ED_view3d_project_float_global(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)
{
float dist_temp = len_manhattan_v2v2(mval_fl, screen_co);
- if (base == BASACT) dist_temp += 10.0f;
+ if (base == BASACT_NEW) dist_temp += 10.0f;
if (dist_temp < dist) {
dist = dist_temp;
basact = base;
@@ -1459,7 +1448,7 @@ static bool ed_object_select_pick(
}
base = base->next;
- if (base == NULL) base = FIRSTBASE;
+ if (base == NULL) base = FIRSTBASE_NEW;
if (base == startbase) break;
}
}
@@ -1468,10 +1457,13 @@ static bool ed_object_select_pick(
unsigned int buffer[MAXPICKBUF];
bool do_nearest;
+ // 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);
-
+
+ // TIMEIT_END(select_time);
+
if (hits > 0) {
/* note: bundles are handling in the same way as bones */
const bool has_bones = selectbuffer_has_bones(buffer, hits);
@@ -1486,7 +1478,7 @@ static bool ed_object_select_pick(
if (has_bones && basact) {
if (basact->object->type == OB_CAMERA) {
- if (BASACT == basact) {
+ if (BASACT_NEW == basact) {
int i, hitresult;
bool changed = false;
@@ -1495,7 +1487,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;
}
@@ -1524,8 +1516,8 @@ 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;
@@ -1543,27 +1535,27 @@ static bool ed_object_select_pick(
}
}
}
- else if (ED_do_pose_selectbuffer(scene, basact, buffer, hits, extend, deselect, toggle, do_nearest)) {
+ else if (ED_do_pose_selectbuffer(scene, sl, 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_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_NEW && (BASACT_NEW->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_NEW)
basact = NULL;
}
}
@@ -1575,37 +1567,37 @@ 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(sl, basact);
+ ED_object_base_select(basact, BA_SELECT);
}
/* also prevent making it active on mouse selection */
- else if (BASE_SELECTABLE(v3d, basact)) {
+ else if (BASE_SELECTABLE_NEW(basact)) {
- oldbasact = BASACT;
+ oldbasact = BASACT_NEW;
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);
+ deselectall_except(sl, 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 */
}
}
@@ -1862,7 +1854,7 @@ static int do_mesh_box_select(ViewContext *vc, rcti *rect, bool select, bool ext
/* for non zbuf projections, don't change the GL state */
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- glLoadMatrixf(vc->rv3d->viewmat);
+ gpuLoadMatrix(vc->rv3d->viewmat);
bbsel = EDBM_backbuf_border_init(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
if (ts->selectmode & SCE_SELECT_VERTEX) {
@@ -1908,9 +1900,9 @@ static int do_meta_box_select(ViewContext *vc, rcti *rect, bool select, bool ext
int a;
unsigned int buffer[MAXPICKBUF];
- short hits;
+ int hits;
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, false);
+ hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, VIEW3D_SELECT_ALL);
if (extend == false && select)
BKE_mball_deselect_all(mb);
@@ -1942,9 +1934,9 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool
int a;
unsigned int buffer[MAXPICKBUF];
- short hits;
+ int hits;
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, false);
+ hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, VIEW3D_SELECT_ALL);
/* clear flag we use to detect point was affected */
for (ebone = arm->edbo->first; ebone; ebone = ebone->next)
@@ -1958,6 +1950,9 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool
int index = buffer[(4 * a) + 3];
if (index != -1) {
ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
+ if ((index & 0xFFFF0000) == 0) {
+ continue;
+ }
if ((select == false) || ((ebone->flag & BONE_UNSELECTABLE) == 0)) {
if (index & BONESEL_TIP) {
ebone->flag |= BONE_DONE;
@@ -2005,6 +2000,27 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool
return hits > 0 ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
+/**
+ * Compare result of 'GPU_select': 'uint[4]',
+ * needed for when we need to align with object draw-order.
+ */
+static int opengl_select_buffer_cmp(const void *sel_a_p, const void *sel_b_p)
+{
+ /* 4th element is select id */
+ const uint sel_a = ((uint *)sel_a_p)[3];
+ const uint sel_b = ((uint *)sel_b_p)[3];
+
+ if (sel_a < sel_b) {
+ return -1;
+ }
+ else if (sel_a > sel_b) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, bool select, bool extend)
{
Bone *bone;
@@ -2014,7 +2030,7 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b
int bone_only;
int bone_selected = 0;
int totobj = MAXPICKBUF; /* XXX solve later */
- short hits;
+ int hits;
if ((ob) && (ob->mode & OB_MODE_POSE))
bone_only = 1;
@@ -2032,13 +2048,13 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b
CTX_DATA_END;
}
else {
- object_deselect_all_visible(vc->scene, vc->v3d);
+ object_deselect_all_visible(vc->scene_layer);
}
}
/* 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, false);
+ hits = view3d_opengl_select(vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL);
/*
* LOGIC NOTES (theeth):
* The buffer and ListBase have the same relative order, which makes the selection
@@ -2046,18 +2062,22 @@ 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 */
+
+ /* The draw order doesn't always match the order we populate the engine, see: T51695. */
+ qsort(vbuffer, hits, sizeof(uint[4]), opengl_select_buffer_cmp);
+
+ /*
+ * Even though 'DRW_draw_select_loop' uses 'DEG_OBJECT_ITER',
+ * we can be sure the order remains the same between both.
+ */
+ for (base = vc->scene_layer->object_bases.first; base && hits; base = base->next) {
+ if (BASE_SELECTABLE_NEW(base)) {
+ while (base->object->select_color == (*col & 0xFFFF)) { /* we got an object */
if (*col & 0xFFFF0000) { /* we got a bone */
bone = get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
if (bone) {
@@ -2076,7 +2096,7 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b
}
}
else if (!bone_only) {
- ED_base_object_select(base, select ? BA_SELECT : BA_DESELECT);
+ ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT);
}
col += 4; /* next color */
@@ -2093,7 +2113,7 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b
if (arm && (arm->flag & ARM_HAS_VIZ_DEPS)) {
/* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
}
}
@@ -2583,7 +2603,7 @@ static void lattice_circle_select(ViewContext *vc, const bool select, const int
/* NOTE: pose-bone case is copied from editbone case... */
-static short pchan_circle_doSelectJoint(void *userData, bPoseChannel *pchan, const float screen_co[2])
+static bool pchan_circle_doSelectJoint(void *userData, bPoseChannel *pchan, const float screen_co[2])
{
CircleSelectUserData *data = userData;
@@ -2656,12 +2676,12 @@ static void pose_circle_select(ViewContext *vc, const bool select, const int mva
if (arm->flag & ARM_HAS_VIZ_DEPS) {
/* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&vc->obact->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&vc->obact->id, OB_RECALC_DATA);
}
}
}
-static short armature_circle_doSelectJoint(void *userData, EditBone *ebone, const float screen_co[2], short head)
+static bool armature_circle_doSelectJoint(void *userData, EditBone *ebone, const float screen_co[2], bool head)
{
CircleSelectUserData *data = userData;
@@ -2792,22 +2812,22 @@ 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;
+ SceneLayer *sl = vc->scene_layer;
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_NEW; base; base = base->next) {
+ if (BASE_SELECTABLE_NEW(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;
}
}
diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c
index 5dd69cc66eb..8e566b8da1a 100644
--- a/source/blender/editors/space_view3d/view3d_snap.c
+++ b/source/blender/editors/space_view3d/view3d_snap.c
@@ -40,13 +40,14 @@
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.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 "WM_api.h"
#include "WM_types.h"
@@ -153,7 +154,7 @@ 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);
@@ -177,7 +178,7 @@ static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op))
/* 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;
@@ -329,7 +330,7 @@ static int snap_selected_to_location(bContext *C, const float snap_target_global
obact->pose->flag |= (POSE_LOCKED | POSE_DO_UNLOCK);
- DAG_id_tag_update(&obact->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&obact->id, OB_RECALC_DATA);
}
else {
struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
@@ -385,7 +386,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);
}
}
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index bc7a9989c72..854f71b17b3 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -43,7 +43,6 @@
#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_main.h"
@@ -51,10 +50,12 @@
#include "BKE_scene.h"
#include "BKE_screen.h"
-#include "BIF_gl.h"
+#include "DEG_depsgraph.h"
+
#include "BIF_glutil.h"
#include "GPU_select.h"
+#include "GPU_matrix.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -62,6 +63,8 @@
#include "ED_screen.h"
#include "ED_armature.h"
+#include "DRW_engine.h"
+
#ifdef WITH_GAMEENGINE
# include "BLI_listbase.h"
@@ -96,10 +99,8 @@ void view3d_region_operator_needs_opengl(wmWindow *win, ARegion *ar)
RegionView3D *rv3d = ar->regiondata;
wmSubWindowSet(win, ar->swinid);
- glMatrixMode(GL_PROJECTION);
- glLoadMatrixf(rv3d->winmat);
- glMatrixMode(GL_MODELVIEW);
- glLoadMatrixf(rv3d->viewmat);
+ gpuLoadProjectionMatrix(rv3d->winmat);
+ gpuLoadMatrix(rv3d->viewmat);
}
}
@@ -449,7 +450,7 @@ void ED_view3d_smooth_view_force_finish(
/* force update of view matrix so tools that run immediately after
* can use them without redrawing first */
Scene *scene = CTX_data_scene(C);
- ED_view3d_update_viewmat(scene, v3d, ar, NULL, NULL);
+ ED_view3d_update_viewmat(scene, v3d, ar, NULL, NULL, NULL);
}
}
@@ -491,7 +492,7 @@ static int view3d_camera_to_view_exec(bContext *C, wmOperator *UNUSED(op))
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);
@@ -539,6 +540,7 @@ void VIEW3D_OT_camera_to_view(wmOperatorType *ot)
static int view3d_camera_to_view_selected_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
View3D *v3d = CTX_wm_view3d(C); /* can be NULL */
Object *camera_ob = v3d ? v3d->camera : scene->camera;
@@ -551,7 +553,7 @@ static int view3d_camera_to_view_selected_exec(bContext *C, wmOperator *op)
}
/* this function does all the important stuff */
- if (BKE_camera_view_frame_fit_to_scene(scene, v3d, camera_ob, r_co, &r_scale)) {
+ if (BKE_camera_view_frame_fit_to_scene(scene, sl, camera_ob, r_co, &r_scale)) {
ObjectTfmProtectedChannels obtfm;
float obmat_new[4][4];
@@ -568,7 +570,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;
}
@@ -592,6 +594,54 @@ void VIEW3D_OT_camera_to_view_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+static void sync_viewport_camera_smoothview(bContext *C, View3D *v3d, Object *ob, const int smooth_viewtx)
+{
+ Main *bmain = CTX_data_main(C);
+ for (bScreen *screen = bmain->screen.first; screen != NULL; screen = screen->id.next) {
+ for (ScrArea *area = screen->areabase.first; area != NULL; area = area->next) {
+ for (SpaceLink *space_link = area->spacedata.first; space_link != NULL; space_link = space_link->next) {
+ if (space_link->spacetype == SPACE_VIEW3D) {
+ View3D *other_v3d = (View3D *)space_link;
+ if (other_v3d == v3d) {
+ continue;
+ }
+ if (other_v3d->camera == ob) {
+ continue;
+ }
+ if (v3d->scenelock) {
+ ListBase *lb = (space_link == area->spacedata.first)
+ ? &area->regionbase
+ : &space_link->regionbase;
+ for (ARegion *other_ar = lb->first; other_ar != NULL; other_ar = other_ar->next) {
+ if (other_ar->regiontype == RGN_TYPE_WINDOW) {
+ if (other_ar->regiondata) {
+ RegionView3D *other_rv3d = other_ar->regiondata;
+ if (other_rv3d->persp == RV3D_CAMOB) {
+ Object *other_camera_old = other_v3d->camera;
+ other_v3d->camera = ob;
+ ED_view3d_lastview_store(other_rv3d);
+ ED_view3d_smooth_view(
+ C, other_v3d, other_ar, smooth_viewtx,
+ &(const V3D_SmoothParams) {
+ .camera_old = other_camera_old,
+ .camera = other_v3d->camera,
+ .ofs = other_rv3d->ofs,
+ .quat = other_rv3d->viewquat,
+ .dist = &other_rv3d->dist,
+ .lens = &other_v3d->lens});
+ }
+ else {
+ other_v3d->camera = ob;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
static int view3d_setobjectascamera_exec(bContext *C, wmOperator *op)
{
@@ -627,7 +677,11 @@ static int view3d_setobjectascamera_exec(bContext *C, wmOperator *op)
.dist = &rv3d->dist, .lens = &v3d->lens});
}
- WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS | NC_OBJECT | ND_DRAW, CTX_data_scene(C));
+ if (v3d->scenelock) {
+ sync_viewport_camera_smoothview(C, v3d, ob, smooth_viewtx);
+ WM_event_add_notifier(C, NC_SCENE, scene);
+ }
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, scene);
}
return OPERATOR_FINISHED;
@@ -673,40 +727,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;
- gluUnProject(xs, ys, 0.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
- copy_v3fl_v3db(bb->vec[val], p);
+ ED_view3d_unproject(ar, xs, ys, 0.0, bb->vec[val]);
+ ED_view3d_unproject(ar, xs, ys, 1.0, bb->vec[4 + val]);
+ }
+
+ /* 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);
}
@@ -856,7 +905,7 @@ void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist)
/**
* \param rect optional for picking (can be NULL).
*/
-void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rctf *rect)
+void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rcti *rect)
{
RegionView3D *rv3d = ar->regiondata;
rctf viewplane;
@@ -882,14 +931,14 @@ void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rctf *rect)
}
if (is_ortho) {
- wmOrtho(viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);
+ gpuOrtho(viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);
}
else {
- wmFrustum(viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);
+ gpuFrustum(viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);
}
/* update matrix in 3d view region */
- glGetFloatv(GL_PROJECTION_MATRIX, (float *)rv3d->winmat);
+ gpuGetProjectionMatrix(rv3d->winmat);
}
static void obmat_to_viewmat(RegionView3D *rv3d, Object *ob)
@@ -1039,76 +1088,19 @@ void view3d_viewmatrix_set(Scene *scene, const View3D *v3d, RegionView3D *rv3d)
}
}
-static void view3d_select_loop(ViewContext *vc, Scene *scene, View3D *v3d, ARegion *ar, bool use_obedit_skip)
+/**
+ * Optionally cache data for multiple calls to #view3d_opengl_select
+ *
+ * just avoid GPU_select headers outside this file
+ */
+void view3d_opengl_select_cache_begin(void)
{
- short code = 1;
- char dt;
- short dtx;
-
- if (vc->obedit && vc->obedit->type == OB_MBALL) {
- draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR);
- }
- else if ((vc->obedit && vc->obedit->type == OB_ARMATURE)) {
- /* if not drawing sketch, draw bones */
- if (!BDR_drawSketchNames(vc)) {
- draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR);
- }
- }
- else {
- Base *base;
-
- v3d->xray = true; /* otherwise it postpones drawing */
- 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;
-
- if (GPU_select_load_id(code)) {
- draw_object(scene, ar, v3d, base, DRAW_PICKING | DRAW_CONSTCOLOR);
-
- /* 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(G.main->eval_ctx, scene, base->object);
-
- for (dob = lb->first; dob; dob = dob->next) {
- float omat[4][4];
-
- 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(scene, ar, v3d, &tbase, DRAW_PICKING | DRAW_CONSTCOLOR);
-
- tbase.object->dt = dt;
- tbase.object->dtx = dtx;
+ GPU_select_cache_begin();
+}
- copy_m4_m4(dob->ob->obmat, omat);
- }
- free_object_duplilist(lb);
- }
- }
- code++;
- }
- }
- }
- v3d->xray = false; /* restore */
- }
+void view3d_opengl_select_cache_end(void)
+{
+ GPU_select_cache_end();
}
/**
@@ -1118,32 +1110,70 @@ static void view3d_select_loop(ViewContext *vc, Scene *scene, View3D *v3d, ARegi
*
* \note (vc->obedit == NULL) can be set to explicitly skip edit-object selection.
*/
-short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input, bool do_nearest)
+int view3d_opengl_select(
+ ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input,
+ eV3DSelectMode select_mode)
{
+ Depsgraph *graph = vc->depsgraph;
Scene *scene = vc->scene;
View3D *v3d = vc->v3d;
ARegion *ar = vc->ar;
- rctf rect;
- short hits;
+ rcti rect;
+ int hits;
const bool use_obedit_skip = (scene->obedit != NULL) && (vc->obedit == NULL);
- const bool do_passes = do_nearest && GPU_select_query_check_active();
+ 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);
+
+ char gpu_select_mode;
- G.f |= G_PICKSEL;
-
/* case not a border select */
if (input->xmin == input->xmax) {
- rect.xmin = input->xmin - 12; /* seems to be default value for bones only now */
- rect.xmax = input->xmin + 12;
- rect.ymin = input->ymin - 12;
- rect.ymax = input->ymin + 12;
+ /* seems to be default value for bones only now */
+ BLI_rcti_init_pt_radius(&rect, (const int[2]){input->xmin, input->ymin}, 12);
}
else {
- BLI_rctf_rcti_copy(&rect, input);
+ rect = *input;
}
-
- view3d_winmatrix_set(ar, v3d, &rect);
- mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat);
-
+
+ if (is_pick_select) {
+ if (is_pick_select && select_mode == VIEW3D_SELECT_PICK_NEAREST) {
+ gpu_select_mode = GPU_SELECT_PICK_NEAREST;
+ }
+ else if (is_pick_select && select_mode == VIEW3D_SELECT_PICK_ALL) {
+ gpu_select_mode = GPU_SELECT_PICK_ALL;
+ }
+ else {
+ gpu_select_mode = GPU_SELECT_ALL;
+ }
+ }
+ else {
+ if (do_passes) {
+ gpu_select_mode = GPU_SELECT_NEAREST_FIRST_PASS;
+ }
+ else {
+ gpu_select_mode = GPU_SELECT_ALL;
+ }
+ }
+
+ /* Re-use cache (rect must be smaller then the cached)
+ * other context is assumed to be unchanged */
+ if (GPU_select_is_cached()) {
+ GPU_select_begin(buffer, bufsize, &rect, gpu_select_mode, 0);
+ GPU_select_cache_load_id();
+ hits = GPU_select_end();
+ goto finally;
+ }
+
+ 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);
+
if (v3d->drawtype > OB_WIRE) {
v3d->zbuf = true;
glEnable(GL_DEPTH_TEST);
@@ -1152,27 +1182,41 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b
if (vc->rv3d->rflag & RV3D_CLIPPING)
ED_view3d_clipping_set(vc->rv3d);
- if (do_passes)
- GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
- else
- GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_ALL, 0);
+ GPU_select_begin(buffer, bufsize, &rect, gpu_select_mode, 0);
- view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip);
+#ifdef WITH_OPENGL_LEGACY
+ if (IS_VIEWPORT_LEGACY(vc->v3d)) {
+ ED_view3d_draw_select_loop(vc, scene, sl, v3d, ar, use_obedit_skip, use_nearest);
+ }
+ else
+#else
+ {
+ DRW_draw_select_loop(graph, ar, v3d, use_obedit_skip, use_nearest, &rect);
+ }
+#endif /* WITH_OPENGL_LEGACY */
hits = GPU_select_end();
/* second pass, to get the closest object to camera */
- if (do_passes) {
+ if (do_passes && (hits > 0)) {
GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
- view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip);
+#ifdef WITH_OPENGL_LEGACY
+ if (IS_VIEWPORT_LEGACY(vc->v3d)) {
+ ED_view3d_draw_select_loop(vc, scene, sl, v3d, ar, use_obedit_skip, use_nearest);
+ }
+ else
+#else
+ {
+ DRW_draw_select_loop(graph, ar, v3d, use_obedit_skip, use_nearest, &rect);
+ }
+#endif /* WITH_OPENGL_LEGACY */
GPU_select_end();
}
G.f &= ~G_PICKSEL;
- view3d_winmatrix_set(ar, v3d, NULL);
- mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat);
+ ED_view3d_draw_setup_view(vc->win, scene, ar, v3d, vc->rv3d->viewmat, NULL, NULL);
if (v3d->drawtype > OB_WIRE) {
v3d->zbuf = 0;
@@ -1181,48 +1225,13 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b
if (vc->rv3d->rflag & RV3D_CLIPPING)
ED_view3d_clipping_disable();
-
+
+finally:
if (hits < 0) printf("Too many objects in select buffer\n"); /* XXX make error message */
return hits;
}
-/* ********************** local view operator ******************** */
-
-static unsigned int free_localbit(Main *bmain)
-{
- unsigned int lay;
- ScrArea *sa;
- bScreen *sc;
-
- lay = 0;
-
- /* sometimes we loose a localview: when an area is closed */
- /* check all areas: which localviews are in use? */
- for (sc = bmain->screen.first; sc; sc = sc->id.next) {
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl = sa->spacedata.first;
- for (; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D *) sl;
- lay |= v3d->lay;
- }
- }
- }
- }
-
- 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 int *values, int *active)
{
int i, tot = 0;
@@ -1261,267 +1270,6 @@ int ED_view3d_scene_layer_set(int lay, const int *values, int *active)
return lay;
}
-static bool view3d_localview_init(
- wmWindowManager *wm, wmWindow *win,
- Main *bmain, Scene *scene, 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;
- bool ok = false;
-
- if (v3d->localvd) {
- return ok;
- }
-
- INIT_MINMAX(min, max);
-
- locallay = free_localbit(bmain);
-
- if (locallay == 0) {
- BKE_report(reports, RPT_ERROR, "No more than 8 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;
- }
- else {
- for (base = FIRSTBASE; base; base = base->next) {
- if (TESTBASE(v3d, base)) {
- BKE_object_minmax(base->object, min, max, false);
- base->lay |= locallay;
- base->object->lay = base->lay;
- ok = true;
- }
- }
- }
-
- sub_v3_v3v3(box, max, min);
- size = max_fff(box[0], box[1], box[2]);
- }
-
- if (ok == true) {
- ARegion *ar;
-
- v3d->localvd = MEM_mallocN(sizeof(View3D), "localview");
-
- memcpy(v3d->localvd, v3d, sizeof(View3D));
-
- 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 */
- Object *camera_old = NULL;
- float dist_new, ofs_new[3];
-
- rv3d->localvd = MEM_mallocN(sizeof(RegionView3D), "localview region");
- memcpy(rv3d->localvd, rv3d, sizeof(RegionView3D));
-
- negate_v3_v3(ofs_new, mid);
-
- if (rv3d->persp == RV3D_CAMOB) {
- rv3d->persp = RV3D_PERSP;
- camera_old = v3d->camera;
- }
-
- if (rv3d->persp == RV3D_ORTHO) {
- if (size < 0.0001f) {
- ok_dist = false;
- }
- }
-
- if (ok_dist) {
- dist_new = ED_view3d_radius_to_dist(v3d, ar, rv3d->persp, true, (size / 2) * VIEW3D_MARGIN);
- if (rv3d->persp == RV3D_PERSP) {
- /* don't zoom closer than the near clipping plane */
- dist_new = max_ff(dist_new, v3d->near * 1.5f);
- }
- }
-
- ED_view3d_smooth_view_ex(
- wm, win, sa, v3d, ar, smooth_viewtx,
- &(const V3D_SmoothParams) {
- .camera_old = camera_old,
- .ofs = ofs_new, .quat = rv3d->viewquat,
- .dist = ok_dist ? &dist_new : NULL, .lens = &v3d->lens});
- }
- }
-
- 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;
- }
- }
- }
-
- return ok;
-}
-
-static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmain, Scene *scene, ScrArea *sa, const int smooth_viewtx)
-{
- const bool free = true;
- ARegion *ar;
- View3D *v3d = sa->spacedata.first;
- Object *camera_old, *camera_new;
-
- if (v3d->localvd == NULL) return;
-
- camera_old = v3d->camera;
- camera_new = v3d->localvd->camera;
-
- v3d->near = v3d->localvd->near;
- v3d->far = v3d->localvd->far;
- v3d->lay = v3d->localvd->lay;
- v3d->layact = v3d->localvd->layact;
- v3d->drawtype = v3d->localvd->drawtype;
- v3d->camera = v3d->localvd->camera;
-
- if (free) {
- MEM_freeN(v3d->localvd);
- v3d->localvd = NULL;
- }
-
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->regiontype == RGN_TYPE_WINDOW) {
- RegionView3D *rv3d = ar->regiondata;
-
- if (rv3d->localvd) {
- Object *camera_old_rv3d, *camera_new_rv3d;
-
- camera_old_rv3d = (rv3d->persp == RV3D_CAMOB) ? camera_old : NULL;
- camera_new_rv3d = (rv3d->localvd->persp == RV3D_CAMOB) ? camera_new : NULL;
-
- rv3d->view = rv3d->localvd->view;
- rv3d->persp = rv3d->localvd->persp;
- rv3d->camzoom = rv3d->localvd->camzoom;
-
- ED_view3d_smooth_view_ex(
- wm, win, sa,
- v3d, ar, smooth_viewtx,
- &(const V3D_SmoothParams) {
- .camera_old = camera_old_rv3d, .camera = camera_new_rv3d,
- .ofs = rv3d->localvd->ofs, .quat = rv3d->localvd->viewquat,
- .dist = &rv3d->localvd->dist});
-
- if (free) {
- MEM_freeN(rv3d->localvd);
- rv3d->localvd = NULL;
- }
- }
-
- ED_view3d_shade_update(bmain, scene, v3d, sa);
- }
- }
-}
-
-static bool view3d_localview_exit(
- wmWindowManager *wm, wmWindow *win,
- Main *bmain, Scene *scene, ScrArea *sa, const int smooth_viewtx)
-{
- View3D *v3d = sa->spacedata.first;
- struct Base *base;
- unsigned int locallay;
-
- if (v3d->localvd) {
-
- locallay = v3d->lay & 0xFF000000;
-
- restore_localviewdata(wm, win, bmain, scene, sa, smooth_viewtx);
-
- /* for when in other window the layers have changed */
- if (v3d->scenelock) v3d->lay = scene->lay;
-
- 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;
- }
- base->object->lay = base->lay;
- }
- }
-
- DAG_on_visible_update(bmain, false);
-
- return true;
- }
- else {
- return false;
- }
-}
-
-static int localview_exec(bContext *C, wmOperator *op)
-{
- 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);
- 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);
- }
- else {
- changed = view3d_localview_init(wm, win, bmain, scene, sa, smooth_viewtx, op->reports);
- }
-
- if (changed) {
- DAG_id_type_tag(bmain, ID_OB);
- ED_area_tag_redraw(sa);
-
- /* unselected objects become selected when exiting */
- if (v3d->localvd == NULL) {
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
- }
-
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
-}
-
-void VIEW3D_OT_localview(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Local View";
- ot->description = "Toggle display of selected object(s) separately and centered in view";
- ot->idname = "VIEW3D_OT_localview";
-
- /* api callbacks */
- ot->exec = localview_exec;
- ot->flag = OPTYPE_UNDO; /* localview changes object layer bitflags */
-
- ot->poll = ED_operator_view3d_active;
-}
-
#ifdef WITH_GAMEENGINE
static ListBase queue_back;
@@ -1560,7 +1308,6 @@ static void RestoreState(bContext *C, wmWindow *win)
win->queue = queue_back;
GPU_state_init();
- GPU_set_tpage(NULL, 0, 0);
glPopAttrib();
}
@@ -1603,10 +1350,6 @@ static void game_set_commmandline_options(GameData *gm)
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);
-
-
}
}
@@ -1614,19 +1357,21 @@ static void game_set_commmandline_options(GameData *gm)
static int game_engine_poll(bContext *C)
{
- bScreen *screen;
+ const wmWindow *win = CTX_wm_window(C);
+ const Scene *scene = WM_window_get_active_scene(win);
+
/* 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 (win == NULL) return 0;
+ if (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))
+ if (!BKE_scene_uses_blender_game(scene))
return 0;
return 1;
@@ -1735,7 +1480,7 @@ static int game_engine_exec(bContext *C, wmOperator *op)
//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);
+ //XXX BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene);
BLI_callback_exec(bmain, &startscene->id, BLI_CB_EVT_GAME_POST);
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index c9e4bb301b8..71a4980d4a6 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -57,10 +57,14 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "GPU_immediate.h"
+
#include "view3d_intern.h" /* own include */
-//#define NDOF_WALK_DEBUG
-//#define NDOF_WALK_DRAW_TOOMUCH /* is this needed for ndof? - commented so redraw doesnt thrash - campbell */
+#ifdef WITH_INPUT_NDOF
+//# define NDOF_WALK_DEBUG
+//# define NDOF_WALK_DRAW_TOOMUCH /* is this needed for ndof? - commented so redraw doesnt thrash - campbell */
+#endif
#define USE_TABLET_SUPPORT
@@ -245,6 +249,7 @@ typedef struct WalkInfo {
View3D *v3d;
ARegion *ar;
Scene *scene;
+ SceneLayer *scene_layer;
wmTimer *timer; /* needed for redraws */
@@ -254,7 +259,10 @@ typedef struct WalkInfo {
int prev_mval[2]; /* previous 2D mouse values */
int center_mval[2]; /* center mouse values */
int moffset[2];
+
+#ifdef WITH_INPUT_NDOF
wmNDOFMotionData *ndof; /* latest 3D mouse values */
+#endif
/* walk state state */
float base_speed; /* the base speed without run/slow down modifications */
@@ -333,24 +341,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);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformThemeColor(TH_VIEW_OVERLAY);
+
+ immBegin(GWN_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)
@@ -495,6 +512,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->v3d = CTX_wm_view3d(C);
walk->ar = CTX_wm_region(C);
walk->scene = CTX_data_scene(C);
+ walk->scene_layer = CTX_data_scene_layer(C);
#ifdef NDOF_WALK_DEBUG
puts("\n-- walk begin --");
@@ -572,7 +590,9 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->timer = WM_event_add_timer(CTX_wm_manager(C), win, TIMER, 0.01f);
+#ifdef WITH_INPUT_NDOF
walk->ndof = NULL;
+#endif
walk->time_lastdraw = PIL_check_seconds_timer();
@@ -581,7 +601,7 @@ 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, SNAP_OBJECT_USE_CACHE,
+ CTX_data_main(C), walk->scene, walk->scene_layer, 0,
walk->ar, walk->v3d);
walk->v3d_camera_control = ED_view3d_cameracontrol_acquire(
@@ -639,8 +659,10 @@ static int walkEnd(bContext *C, WalkInfo *walk)
rv3d->rflag &= ~RV3D_NAVIGATING;
+#ifdef WITH_INPUT_NDOF
if (walk->ndof)
MEM_freeN(walk->ndof);
+#endif
/* restore the cursor */
WM_cursor_modal_restore(win);
@@ -743,6 +765,7 @@ static void walkEvent(bContext *C, wmOperator *op, WalkInfo *walk, const wmEvent
}
}
}
+#ifdef WITH_INPUT_NDOF
else if (event->type == NDOF_MOTION) {
/* do these automagically get delivered? yes. */
// puts("ndof motion detected in walk mode!");
@@ -752,15 +775,15 @@ static void walkEvent(bContext *C, wmOperator *op, WalkInfo *walk, const wmEvent
switch (incoming_ndof->progress) {
case P_STARTING:
/* start keeping track of 3D mouse position */
-#ifdef NDOF_WALK_DEBUG
+# ifdef NDOF_WALK_DEBUG
puts("start keeping track of 3D mouse position");
-#endif
+# endif
/* fall-through */
case P_IN_PROGRESS:
/* update 3D mouse position */
-#ifdef NDOF_WALK_DEBUG
+# ifdef NDOF_WALK_DEBUG
putchar('.'); fflush(stdout);
-#endif
+# endif
if (walk->ndof == NULL) {
// walk->ndof = MEM_mallocN(sizeof(wmNDOFMotionData), tag_name);
walk->ndof = MEM_dupallocN(incoming_ndof);
@@ -772,9 +795,9 @@ static void walkEvent(bContext *C, wmOperator *op, WalkInfo *walk, const wmEvent
break;
case P_FINISHING:
/* stop keeping track of 3D mouse position */
-#ifdef NDOF_WALK_DEBUG
+# ifdef NDOF_WALK_DEBUG
puts("stop keeping track of 3D mouse position");
-#endif
+# endif
if (walk->ndof) {
MEM_freeN(walk->ndof);
// free(walk->ndof);
@@ -789,6 +812,7 @@ static void walkEvent(bContext *C, wmOperator *op, WalkInfo *walk, const wmEvent
break; /* should always be one of the above 3 */
}
}
+#endif /* WITH_INPUT_NDOF */
/* handle modal keymap first */
else if (event->type == EVT_MODAL_MAP) {
switch (event->val) {
@@ -1323,6 +1347,7 @@ static int walkApply(bContext *C, wmOperator *op, WalkInfo *walk)
#undef WALK_BOOST_FACTOR
}
+#ifdef WITH_INPUT_NDOF
static void walkApply_ndof(bContext *C, WalkInfo *walk)
{
Object *lock_ob = ED_view3d_cameracontrol_object_get(walk->v3d_camera_control);
@@ -1341,6 +1366,7 @@ static void walkApply_ndof(bContext *C, WalkInfo *walk)
}
}
}
+#endif /* WITH_INPUT_NDOF */
/****** walk operator ******/
static int walk_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@@ -1388,12 +1414,15 @@ static int walk_modal(bContext *C, wmOperator *op, const wmEvent *event)
walkEvent(C, op, walk, event);
+#ifdef WITH_INPUT_NDOF
if (walk->ndof) { /* 3D mouse overrules [2D mouse + timer] */
if (event->type == NDOF_MOTION) {
walkApply_ndof(C, walk);
}
}
- else if (event->type == TIMER && event->customdata == walk->timer) {
+ else
+#endif /* WITH_INPUT_NDOF */
+ if (event->type == TIMER && event->customdata == walk->timer) {
walkApply(C, op, walk);
}
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt
index b7de49d8158..fda15545ead 100644
--- a/source/blender/editors/transform/CMakeLists.txt
+++ b/source/blender/editors/transform/CMakeLists.txt
@@ -46,6 +46,7 @@ set(SRC
transform_generics.c
transform_input.c
transform_manipulator.c
+ transform_manipulator2d.c
transform_ops.c
transform_orientations.c
transform_snap.c
@@ -58,10 +59,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 ef6cff19181..f6f4566f836 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -43,6 +43,7 @@
#include "DNA_mask_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_scene_types.h" /* PET modes */
+#include "DNA_workspace_types.h"
#include "BLI_alloca.h"
#include "BLI_utildefines.h"
@@ -63,10 +64,14 @@
#include "BKE_unit.h"
#include "BKE_mask.h"
#include "BKE_report.h"
+#include "BKE_workspace.h"
-#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+
#include "ED_image.h"
#include "ED_keyframing.h"
#include "ED_screen.h"
@@ -103,7 +108,7 @@ 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], short around);
+static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], const short around);
static void initSnapSpatial(TransInfo *t, float r_snap[3]);
@@ -1598,70 +1603,76 @@ typedef enum {
LEFT,
RIGHT
} ArrowDirection;
+
+#define POS_INDEX 0
+/* NOTE: this --^ is a bit hackish, but simplifies Gwn_VertFormat usage among functions
+ * private to this file - merwin
+ */
+
static void drawArrow(ArrowDirection d, short offset, short length, short size)
{
+ immBegin(GWN_PRIM_LINES, 6);
+
switch (d) {
case LEFT:
offset = -offset;
length = -length;
size = -size;
- /* fall-through */
+ 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:
offset = -offset;
length = -length;
size = -size;
- /* fall-through */
+ 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(GWN_PRIM_LINES, 4);
+
switch (d) {
case LEFT:
size = -size;
- /* fall-through */
+ 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;
- /* fall-through */
+ 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)
@@ -1670,14 +1681,14 @@ static void drawArc(float size, float angle_start, float angle_end, int segments
float angle;
int a;
- glBegin(GL_LINE_STRIP);
+ immBegin(GWN_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 int helpline_poll(bContext *C)
@@ -1693,12 +1704,9 @@ static void drawHelpline(bContext *UNUSED(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 vecrot[3], cent[2];
- int mval[2];
-
- mval[0] = x;
- mval[1] = y;
+ float mval[3] = { x, y, 0.0f };
copy_v3_v3(vecrot, t->center);
if (t->flag & T_EDIT) {
@@ -1712,42 +1720,67 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
projectFloatViewEx(t, vecrot, cent, V3D_PROJ_TEST_CLIP_ZERO);
- glPushMatrix();
+ gpuPushMatrix();
+
+ /* Dashed lines first. */
+ if (ELEM(t->helpline, HLP_SPRING, HLP_ANGLE)) {
+ const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ UNUSED_VARS_NDEBUG(shdr_pos); /* silence warning */
+ BLI_assert(shdr_pos == POS_INDEX);
+
+ glLineWidth(1.0f);
+
+ 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("num_colors", 0); /* "simple" mode */
+ immUniformThemeColor(TH_VIEW_OVERLAY);
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2fv(POS_INDEX, cent);
+ immVertex2f(POS_INDEX, (float)t->mval[0], (float)t->mval[1]);
+ immEnd();
+
+ immUnbindProgram();
+ }
+
+ /* And now, solid lines. */
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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);
-
- setlinestyle(3);
- glLineWidth(1);
- glBegin(GL_LINES);
- glVertex2iv(t->mval);
- glVertex2fv(cent);
- glEnd();
+ immUniformThemeColor(TH_VIEW_OVERLAY);
- glTranslate2iv(mval);
- glRotatef(-RAD2DEGF(atan2f(cent[0] - t->mval[0], cent[1] - t->mval[1])), 0, 0, 1);
+ gpuTranslate3fv(mval);
+ gpuRotateAxis(-RAD2DEGF(atan2f(cent[0] - t->mval[0], cent[1] - t->mval[1])), 'Z');
- setlinestyle(0);
- glLineWidth(3.0);
+ glLineWidth(3.0f);
drawArrow(UP, 5, 10, 5);
drawArrow(DOWN, 5, 10, 5);
break;
case HLP_HARROW:
- UI_ThemeColor(TH_VIEW_OVERLAY);
+ immUniformThemeColor(TH_VIEW_OVERLAY);
+ gpuTranslate3fv(mval);
- glTranslate2iv(mval);
-
- glLineWidth(3.0);
+ glLineWidth(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);
+ gpuTranslate3fv(mval);
- glLineWidth(3.0);
+ glLineWidth(3.0f);
drawArrow(UP, 5, 10, 5);
drawArrow(DOWN, 5, 10, 5);
break;
@@ -1758,33 +1791,26 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
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);
+ gpuTranslate3f(cent[0] - t->mval[0] + mval[0], cent[1] - t->mval[1] + mval[1], 0);
- setlinestyle(0);
- glLineWidth(3.0);
+ glLineWidth(3.0f);
drawArc(dist, angle - delta_angle, angle - spacing_angle, 10);
drawArc(dist, angle + spacing_angle, angle + delta_angle, 10);
- glPushMatrix();
+ gpuPushMatrix();
- glTranslatef(cosf(angle - delta_angle) * dist, sinf(angle - delta_angle) * dist, 0);
- glRotatef(RAD2DEGF(angle - delta_angle), 0, 0, 1);
+ gpuTranslate3f(cosf(angle - delta_angle) * dist, sinf(angle - delta_angle) * dist, 0);
+ gpuRotateAxis(RAD2DEGF(angle - delta_angle), 'Z');
drawArrowHead(DOWN, 5);
- glPopMatrix();
+ gpuPopMatrix();
- glTranslatef(cosf(angle + delta_angle) * dist, sinf(angle + delta_angle) * dist, 0);
- glRotatef(RAD2DEGF(angle + delta_angle), 0, 0, 1);
+ gpuTranslate3f(cosf(angle + delta_angle) * dist, sinf(angle + delta_angle) * dist, 0);
+ gpuRotateAxis(RAD2DEGF(angle + delta_angle), 'Z');
drawArrowHead(UP, 5);
break;
@@ -1794,18 +1820,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);
+ gpuTranslate3fv(mval);
- glLineWidth(3.0);
+ glLineWidth(3.0f);
UI_make_axis_color(col, col2, 'X');
- glColor3ubv((GLubyte *)col2);
+ immUniformColor3ubv((GLubyte *)col2);
drawArrow(RIGHT, 5, 10, 5);
drawArrow(LEFT, 5, 10, 5);
UI_make_axis_color(col, col2, 'Y');
- glColor3ubv((GLubyte *)col2);
+ immUniformColor3ubv((GLubyte *)col2);
drawArrow(UP, 5, 10, 5);
drawArrow(DOWN, 5, 10, 5);
@@ -1813,7 +1839,8 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
}
}
- glPopMatrix();
+ immUnbindProgram();
+ gpuPopMatrix();
}
}
@@ -1821,7 +1848,7 @@ static void drawTransformView(const struct bContext *C, ARegion *UNUSED(ar), voi
{
TransInfo *t = arg;
- glLineWidth(1.0);
+ glLineWidth(1.0f);
drawConstraint(t);
drawPropCircle(C, t);
@@ -1841,8 +1868,9 @@ static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar)
int xco, yco;
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);
@@ -1850,7 +1878,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
@@ -1873,7 +1903,8 @@ static void drawTransformPixel(const struct bContext *UNUSED(C), ARegion *ar, vo
{
TransInfo *t = arg;
Scene *scene = t->scene;
- Object *ob = OBACT;
+ SceneLayer *sl = t->scene_layer;
+ Object *ob = OBACT_NEW;
/* draw autokeyframing hint in the corner
* - only draw if enabled (advanced users may be distracted/annoyed),
@@ -1984,6 +2015,10 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
View3D *v3d = t->view;
v3d->twmode = t->current_orientation;
+
+ BLI_assert(((v3d->custom_orientation_index == -1) && (t->custom_orientation == NULL)) ||
+ (BKE_workspace_transform_orientation_get_index(
+ CTX_wm_workspace(C), t->custom_orientation) == v3d->custom_orientation_index));
}
}
}
@@ -2003,15 +2038,20 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
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);
- }
- else {
- RNA_enum_set(op->ptr, "constraint_orientation", t->current_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->current_orientation;
+
+ if (orientation == V3D_MANIP_CUSTOM) {
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ const int custom_orientation_index = BKE_workspace_transform_orientation_get_index(
+ workspace, t->custom_orientation);
+
+ /* Maybe we need a t->con.custom_orientation? Seems like it would always match t->custom_orientation. */
+ orientation = V3D_MANIP_CUSTOM + custom_orientation_index;
+ BLI_assert(orientation >= V3D_MANIP_CUSTOM);
}
+ RNA_enum_set(op->ptr, "constraint_orientation", orientation);
if (t->con.mode & CON_APPLY) {
if (t->con.mode & CON_AXIS0) {
@@ -2176,7 +2216,14 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
calculateCenter(t);
if (event) {
- initMouseInput(t, &t->mouse, t->center2d, event->mval);
+ /* Initialize accurate transform to settings requested by keymap. */
+ bool use_accurate = false;
+ if ((prop = RNA_struct_find_property(op->ptr, "use_accurate")) && RNA_property_is_set(op->ptr, prop)) {
+ if (RNA_property_boolean_get(op->ptr, prop)) {
+ use_accurate = true;
+ }
+ }
+ initMouseInput(t, &t->mouse, t->center2d, event->mval, use_accurate);
}
switch (mode) {
@@ -2880,7 +2927,7 @@ static void initBend(TransInfo *t)
curs = ED_view3d_cursor3d_get(t->scene, t->view);
copy_v3_v3(data->warp_sta, curs);
- ED_view3d_win_to_3d(t->ar, curs, mval_fl, data->warp_end);
+ 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) {
@@ -3044,19 +3091,13 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
/** \name Transform Shear
* \{ */
-static void postInputShear(TransInfo *UNUSED(t), float values[3])
-{
- mul_v3_fl(values, 0.05f);
-}
-
static void initShear(TransInfo *t)
{
t->mode = TFM_SHEAR;
t->transform = applyShear;
t->handleEvent = handleEventShear;
-
- setInputPostFct(&t->mouse, postInputShear);
- initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE);
+
+ initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO);
t->idx_max = 0;
t->num.idx_max = 0;
@@ -3078,24 +3119,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_ABSOLUTE);
+ initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_RATIO);
t->custom.mode.data = (void *)1;
}
else {
- initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE);
+ initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO);
t->custom.mode.data = NULL;
}
status = TREDRAW_HARD;
}
else if (event->type == XKEY && event->val == KM_PRESS) {
- initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE);
+ initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO);
t->custom.mode.data = NULL;
status = TREDRAW_HARD;
}
else if (event->type == YKEY && event->val == KM_PRESS) {
- initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE);
+ initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_RATIO);
t->custom.mode.data = (void *)1;
status = TREDRAW_HARD;
@@ -3392,12 +3433,14 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
}
protectedTransBits(td->protectflag, vec);
- add_v3_v3v3(td->loc, td->iloc, vec);
+ if (td->loc) {
+ add_v3_v3v3(td->loc, td->iloc, vec);
+ }
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];
@@ -3408,15 +3451,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);
@@ -3720,6 +3755,12 @@ static void initRotation(TransInfo *t)
copy_v3_v3(t->axis_orig, t->axis);
}
+/**
+ * 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)
{
float vec[3], totmat[3][3], smat[3][3];
@@ -4058,13 +4099,15 @@ 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], smat[3][3], totmat[3][3];
+ float mat[3][3];
+ float axis[3];
+ float angle;
int i;
- axis_angle_normalized_to_mat3(smat, axis1, angles[0]);
- axis_angle_normalized_to_mat3(totmat, axis2, angles[1]);
-
- mul_m3_m3m3(mat, smat, totmat);
+ mul_v3_v3fl(axis, axis1, angles[0]);
+ madd_v3_v3fl(axis, axis2, angles[1]);
+ 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)
@@ -4074,10 +4117,7 @@ static void applyTrackballValue(TransInfo *t, const float axis1[3], const float
continue;
if (t->flag & T_PROP_EDIT) {
- axis_angle_normalized_to_mat3(smat, axis1, td->factor * angles[0]);
- axis_angle_normalized_to_mat3(totmat, axis2, td->factor * angles[1]);
-
- mul_m3_m3m3(mat, smat, totmat);
+ axis_angle_normalized_to_mat3(mat, axis, td->factor * angle);
}
ElementRotation(t, td, mat, t->around);
@@ -4263,7 +4303,7 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
bUnit_AsString(distvec, sizeof(distvec), dist * t->scene->unit.scale_length, 4, t->scene->unit.system,
B_UNIT_LENGTH, do_split, false);
}
- else if (dist > 1e10f || dist < -1e10f) {
+ else if (dist > 1e10f || dist < -1e10f) {
/* prevent string buffer overflow */
BLI_snprintf(distvec, NUM_STR_REP_LEN, "%.4e", dist);
}
@@ -4337,9 +4377,22 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
{
TransData *td = t->data;
float tvec[3];
- int i;
- for (i = 0; i < t->total; i++, td++) {
+ /* 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);
+ }
+ }
+
+ for (int i = 0; i < t->total; i++, td++) {
if (td->flag & TD_NOACTION)
break;
@@ -4350,7 +4403,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
bool use_rotate_offset = false;
/* handle snapping rotation before doing the translation */
- if (usingSnappingNormal(t)) {
+ if (apply_snap_align_rotation) {
float mat[3][3];
if (validSnappingNormal(t)) {
@@ -4368,7 +4421,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
unit_m3(mat);
}
- ElementRotation_ex(t, td, mat, t->tsnap.snapTarget);
+ ElementRotation_ex(t, td, mat, pivot);
if (td->loc) {
use_rotate_offset = true;
@@ -4920,7 +4973,7 @@ static void initPushPull(TransInfo *t)
static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
{
- float vec[3], axis[3];
+ float vec[3], axis_global[3];
float distance;
int i;
char str[UI_MAX_DRAW_STR];
@@ -4948,7 +5001,7 @@ 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, NULL);
+ t->con.applyRot(t, NULL, axis_global, NULL);
}
for (i = 0; i < t->total; i++, td++) {
@@ -4960,7 +5013,11 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
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);
+
+ mul_m3_v3(td->smtx, axis);
if (isLockConstraint(t)) {
float dvec[3];
project_v3_v3v3(dvec, vec, axis);
@@ -5221,23 +5278,14 @@ 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);
@@ -5533,7 +5581,7 @@ static void slide_origdata_interp_data_vert(
float v_proj[3][3];
if (do_loop_weight || do_loop_mdisps) {
- project_plane_v3_v3v3(v_proj[1], sv->co_orig_3d, v_proj_axis);
+ project_plane_normalized_v3_v3v3(v_proj[1], sv->co_orig_3d, v_proj_axis);
}
// BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT) {
@@ -5567,19 +5615,19 @@ static void slide_origdata_interp_data_vert(
/* In the unlikely case that we're next to a zero length edge - walk around the to the next.
* Since we only need to check if the vertex is in this corner,
* its not important _which_ loop - as long as its not overlapping 'sv->co_orig_3d', see: T45096. */
- project_plane_v3_v3v3(v_proj[0], co_prev, v_proj_axis);
+ project_plane_normalized_v3_v3v3(v_proj[0], co_prev, v_proj_axis);
while (UNLIKELY(((co_prev_ok = (len_squared_v3v3(v_proj[1], v_proj[0]) > eps)) == false) &&
((l_prev = l_prev->prev) != l->next)))
{
co_prev = slide_origdata_orig_vert_co(sod, l_prev->v);
- project_plane_v3_v3v3(v_proj[0], co_prev, v_proj_axis);
+ project_plane_normalized_v3_v3v3(v_proj[0], co_prev, v_proj_axis);
}
- project_plane_v3_v3v3(v_proj[2], co_next, v_proj_axis);
+ project_plane_normalized_v3_v3v3(v_proj[2], co_next, v_proj_axis);
while (UNLIKELY(((co_next_ok = (len_squared_v3v3(v_proj[1], v_proj[2]) > eps)) == false) &&
((l_next = l_next->next) != l->prev)))
{
co_next = slide_origdata_orig_vert_co(sod, l_next->v);
- project_plane_v3_v3v3(v_proj[2], co_next, v_proj_axis);
+ project_plane_normalized_v3_v3v3(v_proj[2], co_next, v_proj_axis);
}
if (co_prev_ok && co_next_ok) {
@@ -6829,10 +6877,12 @@ static void drawEdgeSlide(TransInfo *t)
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glPushAttrib(GL_CURRENT_BIT | GL_LINE_BIT | GL_POINT_BIT);
- glPushMatrix();
+ gpuPushMatrix();
+ gpuMultMatrix(t->obedit->obmat);
- glMultMatrixf(t->obedit->obmat);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
if (sld->use_even == true) {
float co_a[3], co_b[3], co_mark[3];
@@ -6846,39 +6896,35 @@ static void drawEdgeSlide(TransInfo *t)
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);
+ immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
+ immBeginAtMost(GWN_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);
+ immUniformThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade);
glPointSize(ctrl_size);
- glBegin(GL_POINTS);
+ immBegin(GWN_PRIM_POINTS, 1);
if (sld->flipped) {
- if (curr_sv->v_side[1]) glVertex3fv(curr_sv->v_side[1]->co);
+ 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);
+ immUniformThemeColorShadeAlpha(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
+ immBegin(GWN_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) {
@@ -6888,8 +6934,8 @@ static void drawEdgeSlide(TransInfo *t)
const int alpha_shade = -160;
glLineWidth(line_size);
- UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
- glBegin(GL_LINES);
+ immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
+ immBegin(GWN_PRIM_LINES, sld->totsv * 2);
sv = sld->sv;
for (i = 0; i < sld->totsv; i++, sv++) {
@@ -6907,18 +6953,19 @@ 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();
+
+ gpuPopMatrix();
glDisable(GL_BLEND);
@@ -7442,19 +7489,22 @@ static void drawVertSlide(TransInfo *t)
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glPushAttrib(GL_CURRENT_BIT | GL_LINE_BIT | GL_POINT_BIT);
- glPushMatrix();
-
- glMultMatrixf(t->obedit->obmat);
+ gpuPushMatrix();
+ gpuMultMatrix(t->obedit->obmat);
glLineWidth(line_size);
- UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
- glBegin(GL_LINES);
+
+ const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
+
+ immBegin(GWN_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 {
@@ -7467,21 +7517,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);
- glBegin(GL_POINTS);
- glVertex3fv((sld->flipped && sld->use_even) ?
+ immBegin(GWN_PRIM_POINTS, 1);
+ immVertex3fv(shdr_pos, (sld->flipped && sld->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]) ||
@@ -7505,19 +7555,28 @@ static void drawVertSlide(TransInfo *t)
add_v3_v3(co_dest_3d, curr_sv->co_orig_3d);
- glLineWidth(1);
- setlinestyle(1);
+ glLineWidth(1.0f);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("num_colors", 0); /* "simple" mode */
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
- cpack(0xffffff);
- glBegin(GL_LINES);
- glVertex3fv(curr_sv->co_orig_3d);
- glVertex3fv(co_dest_3d);
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex3fv(shdr_pos, curr_sv->co_orig_3d);
+ immVertex3fv(shdr_pos, co_dest_3d);
+ immEnd();
- glEnd();
+ immUnbindProgram();
}
- glPopMatrix();
- glPopAttrib();
+ gpuPopMatrix();
if (v3d && v3d->zbuf)
glEnable(GL_DEPTH_TEST);
@@ -8493,7 +8552,7 @@ static void initTimeScale(TransInfo *t)
center[1] = t->mouse.imval[1];
/* force a reinit with the center2d used here */
- initMouseInput(t, &t->mouse, center, t->mouse.imval);
+ initMouseInput(t, &t->mouse, center, t->mouse.imval, false);
initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 10bf5b9df2e..58e61974df3 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -50,6 +50,7 @@ struct Object;
struct View3D;
struct ScrArea;
struct Scene;
+struct SceneLayer;
struct bConstraint;
struct wmKeyMap;
struct wmKeyConfig;
@@ -84,8 +85,8 @@ typedef struct TransSnap {
bool peel;
bool snap_spatial_grid;
short status;
- float snapPoint[3]; /* snapping from this point */
- float snapTarget[3]; /* to this point */
+ float snapPoint[3]; /* snapping from this point (in global-space)*/
+ float snapTarget[3]; /* to this point (in global-space)*/
float snapNormal[3];
char snapNodeBorder;
ListBase points;
@@ -446,6 +447,7 @@ typedef struct TransInfo {
short launch_event; /* event type used to launch transform */
short current_orientation;
+ TransformOrientation *custom_orientation; /* this gets used when current_orientation is V3D_MANIP_CUSTOM */
short twtype; /* backup from view3d, to restore on end */
short prop_mode;
@@ -464,6 +466,7 @@ typedef struct TransInfo {
struct ScrArea *sa;
struct ARegion *ar;
struct Scene *scene;
+ struct SceneLayer *scene_layer;
struct ToolSettings *settings;
struct wmTimer *animtimer;
struct wmKeyMap *keymap; /* so we can do lookups for header text */
@@ -496,8 +499,7 @@ typedef struct TransInfo {
#define T_CAMERA (1 << 4)
// 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)
+/* empty slot - (1 << 7) */
/* restrictions flags */
#define T_ALL_RESTRICTIONS ((1 << 8)|(1 << 9)|(1 << 10))
@@ -635,7 +637,10 @@ void flushTransMasking(TransInfo *t);
void flushTransPaintCurve(TransInfo *t);
void restoreBones(TransInfo *t);
-/*********************** exported from transform_manipulator.c ********** */
+/*********************** transform_manipulator.c ********** */
+
+#define MANIPULATOR_AXIS_LINE_WIDTH 2.0
+
bool gimbal_axis(struct Object *ob, float gmat[3][3]); /* return 0 when no gimbal for selection */
/*********************** TransData Creation and General Handling *********** */
@@ -650,7 +655,7 @@ bool transdata_check_local_islands(TransInfo *t, short around);
int count_set_pose_transflags(int *out_mode, short around, struct Object *ob);
/* 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_ob_cb_func(struct bContext *C, struct Scene *scene, struct SceneLayer *sl, 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);
/*********************** Constraints *****************************/
@@ -729,7 +734,7 @@ typedef enum {
INPUT_CUSTOM_RATIO_FLIP,
} MouseInputMode;
-void initMouseInput(TransInfo *t, MouseInput *mi, const float center[2], const int mval[2]);
+void initMouseInput(TransInfo *t, MouseInput *mi, const float center[2], const int mval[2], const bool precision);
void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode);
eRedrawFlag handleMouseInput(struct TransInfo *t, struct MouseInput *mi, const struct wmEvent *event);
void applyMouseInput(struct TransInfo *t, struct MouseInput *mi, const int mval[2], float output[3]);
@@ -785,7 +790,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
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index d7b670b6476..6132c4dda5f 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -40,9 +40,11 @@
#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 "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_string.h"
@@ -651,7 +653,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:
@@ -683,10 +685,15 @@ void setUserConstraint(TransInfo *t, short orientation, int mode, const char fte
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:
+ {
+ char orientation_str[128];
+ BLI_snprintf(orientation_str, sizeof(orientation_str), "%s \"%s\"",
+ IFACE_("custom orientation"), t->custom_orientation->name);
+ BLI_snprintf(text, sizeof(text), ftext, orientation_str);
setConstraint(t, t->spacemtx, mode, text);
break;
+ }
}
t->con.orientation = orientation;
@@ -704,8 +711,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;
@@ -715,7 +720,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]));
@@ -725,18 +729,29 @@ 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);
if (depth_test_enabled)
glDisable(GL_DEPTH_TEST);
- setlinestyle(1);
- glBegin(GL_LINES);
- glVertex3fv(t->center_global);
- glVertex3fv(vec);
- glEnd();
- setlinestyle(0);
+ const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("num_colors", 0); /* "simple" mode */
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ immUniform1f("dash_width", 2.0f);
+ immUniform1f("dash_factor", 0.5f);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex3fv(shdr_pos, t->center_global);
+ immVertex3fv(shdr_pos, vec);
+ immEnd();
+
+ immUnbindProgram();
if (depth_test_enabled)
glEnable(GL_DEPTH_TEST);
@@ -762,8 +777,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);
@@ -773,13 +786,13 @@ void drawPropCircle(const struct bContext *C, TransInfo *t)
unit_m4(imat);
}
- glPushMatrix();
+ gpuPushMatrix();
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);
+ gpuScale2f(1.0f / t->aspect[0], 1.0f / t->aspect[1]);
}
else if (ELEM(t->spacetype, SPACE_IPO, SPACE_ACTION)) {
/* only scale y */
@@ -789,21 +802,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);
+ gpuScale2f(1.0f, (ysize / xsize) * (xmask / ymask));
}
depth_test_enabled = glIsEnabled(GL_DEPTH_TEST);
if (depth_test_enabled)
glDisable(GL_DEPTH_TEST);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_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);
- glPopMatrix();
+ gpuPopMatrix();
}
}
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index eca5009595b..fc22f9c0088 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -68,11 +68,11 @@
#include "BKE_context.h"
#include "BKE_crazyspace.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_editstrands.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"
@@ -119,6 +119,7 @@
#include "RNA_access.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "transform.h"
#include "bmesh.h"
@@ -286,13 +287,13 @@ static void set_prop_dist(TransInfo *t, const bool with_dist)
static void createTransTexspace(TransInfo *t)
{
- Scene *scene = t->scene;
+ SceneLayer *sl = t->scene_layer;
TransData *td;
Object *ob;
ID *id;
short *texflag;
- ob = OBACT;
+ ob = OBACT_NEW;
if (ob == NULL) { // Shouldn't logically happen, but still...
t->total = 0;
@@ -772,34 +773,43 @@ int count_set_pose_transflags(int *out_mode, short around, Object *ob)
/* -------- Auto-IK ---------- */
/* adjust pose-channel's auto-ik chainlen */
-static void pchan_autoik_adjust(bPoseChannel *pchan, short chainlen)
+static bool pchan_autoik_adjust(bPoseChannel *pchan, short chainlen)
{
bConstraint *con;
+ bool changed = false;
/* don't bother to search if no valid constraints */
- if ((pchan->constflag & (PCHAN_HAS_IK | PCHAN_HAS_TARGET)) == 0)
- return;
+ if ((pchan->constflag & (PCHAN_HAS_IK | PCHAN_HAS_TARGET)) == 0) {
+ return changed;
+ }
/* check if pchan has ik-constraint */
for (con = pchan->constraints.first; con; con = con->next) {
if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->enforce != 0.0f)) {
bKinematicConstraint *data = con->data;
-
+
/* only accept if a temporary one (for auto-ik) */
if (data->flag & CONSTRAINT_IK_TEMP) {
/* chainlen is new chainlen, but is limited by maximum chainlen */
- if ((chainlen == 0) || (chainlen > data->max_rootbone))
+ const int old_rootbone = data->rootbone;
+ if ((chainlen == 0) || (chainlen > data->max_rootbone)) {
data->rootbone = data->max_rootbone;
- else
+ }
+ else {
data->rootbone = chainlen;
+ }
+ changed |= (data->rootbone != old_rootbone);
}
}
}
+
+ return changed;
}
/* change the chain-length of auto-ik */
void transform_autoik_update(TransInfo *t, short mode)
{
+ const short old_len = t->settings->autoik_chainlen;
short *chainlen = &t->settings->autoik_chainlen;
bPoseChannel *pchan;
@@ -813,13 +823,24 @@ void transform_autoik_update(TransInfo *t, short mode)
if (*chainlen > 0) (*chainlen)--;
}
+ /* IK length did not change, skip any updates. */
+ if (old_len == *chainlen) {
+ return;
+ }
+
/* 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) {
- pchan_autoik_adjust(pchan, *chainlen);
+ changed |= pchan_autoik_adjust(pchan, *chainlen);
+ }
+
+ if (changed) {
+ /* TODO(sergey): Consider doing partial update only. */
+ DEG_relations_tag_update(G.main);
}
}
@@ -829,7 +850,6 @@ static void pose_grab_with_ik_clear(Object *ob)
bKinematicConstraint *data;
bPoseChannel *pchan;
bConstraint *con, *next;
- bool need_dependency_update = false;
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
/* clear all temporary lock flags */
@@ -844,7 +864,6 @@ static void pose_grab_with_ik_clear(Object *ob)
data = con->data;
if (data->flag & CONSTRAINT_IK_TEMP) {
/* iTaSC needs clear for removed constraints */
- need_dependency_update = true;
BIK_clear_data(ob->pose);
BLI_remlink(&pchan->constraints, con);
@@ -859,13 +878,8 @@ static void pose_grab_with_ik_clear(Object *ob)
}
}
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (!DEG_depsgraph_use_legacy() && need_dependency_update)
-#endif
- {
- /* TODO(sergey): Consider doing partial update only. */
- DAG_relations_tag_update(G.main);
- }
+ /* TODO(sergey): Consider doing partial update only. */
+ DEG_relations_tag_update(G.main);
}
/* adds the IK to pchan - returns if added */
@@ -1018,13 +1032,8 @@ static short pose_grab_with_ik(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): Consuder doing partial update only. */
- DAG_relations_tag_update(G.main);
- }
+ /* TODO(sergey): Consuder doing partial update only. */
+ DEG_relations_tag_update(G.main);
}
return (tot_ik) ? 1 : 0;
@@ -1497,6 +1506,48 @@ static TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struc
return hdata;
}
+/**
+ * For the purpose of transform code we need to behave as if handles are selected,
+ * even when they aren't (see special case below).
+ */
+static int bezt_select_to_transform_triple_flag(
+ const BezTriple *bezt, const bool hide_handles)
+{
+ int flag = 0;
+
+ if (hide_handles) {
+ if (bezt->f2 & SELECT) {
+ flag = (1 << 0) | (1 << 1) | (1 << 2);
+ }
+ }
+ else {
+ flag = (
+ ((bezt->f1 & SELECT) ? (1 << 0) : 0) |
+ ((bezt->f2 & SELECT) ? (1 << 1) : 0) |
+ ((bezt->f3 & SELECT) ? (1 << 2) : 0)
+ );
+ }
+
+ /* Special case for auto & aligned handles:
+ * When a center point is being moved without the handles,
+ * leaving the handles stationary makes no sense and only causes strange behavior,
+ * where one handle is arbitrarily anchored, the other one is aligned and lengthened
+ * based on where the center point is moved. Also a bug when cancelling, see: T52007.
+ *
+ * A more 'correct' solution could be to store handle locations in 'TransDataCurveHandleFlags'.
+ * However that doesn't resolve odd behavior, so best transform the handles in this case.
+ */
+ if ((flag != ((1 << 0) | (1 << 1) | (1 << 2))) && (flag & (1 << 1))) {
+ if (ELEM(bezt->h1, HD_AUTO, HD_ALIGN) &&
+ ELEM(bezt->h2, HD_AUTO, HD_ALIGN))
+ {
+ flag = (1 << 0) | (1 << 1) | (1 << 2);
+ }
+ }
+
+ return flag;
+}
+
static void createTransCurveVerts(TransInfo *t)
{
Curve *cu = t->obedit->data;
@@ -1514,22 +1565,22 @@ static void createTransCurveVerts(TransInfo *t)
/* 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) {
- if (hide_handles) {
- if (bezt->f2 & SELECT) countsel += 3;
- if (is_prop_edit) count += 3;
- }
- else {
- if (bezt->f1 & SELECT) countsel++;
- if (bezt->f2 & SELECT) countsel++;
- if (bezt->f3 & SELECT) countsel++;
- if (is_prop_edit) count += 3;
- }
+ 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;
+
}
}
}
@@ -1580,10 +1631,10 @@ static void createTransCurveVerts(TransInfo *t)
}
}
- if (is_prop_edit ||
- ((bezt->f2 & SELECT) && hide_handles) ||
- ((bezt->f1 & SELECT) && hide_handles == 0))
- {
+ /* 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 ||
@@ -1614,7 +1665,7 @@ static void createTransCurveVerts(TransInfo *t)
}
/* This is the Curve Point, the other two are handles */
- if (is_prop_edit || (bezt->f2 & SELECT)) {
+ 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);
@@ -1640,7 +1691,7 @@ static void createTransCurveVerts(TransInfo *t)
copy_m3_m3(td->axismtx, axismtx);
}
- if ((bezt->f1 & SELECT) == 0 && (bezt->f3 & SELECT) == 0)
+ 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);
@@ -1650,10 +1701,7 @@ static void createTransCurveVerts(TransInfo *t)
count++;
tail++;
}
- if (is_prop_edit ||
- ((bezt->f2 & SELECT) && hide_handles) ||
- ((bezt->f3 & SELECT) && hide_handles == 0))
- {
+ 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 ||
@@ -1708,6 +1756,26 @@ static void createTransCurveVerts(TransInfo *t)
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);
@@ -1726,6 +1794,11 @@ static void createTransCurveVerts(TransInfo *t)
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++;
@@ -1741,6 +1814,10 @@ static void createTransCurveVerts(TransInfo *t)
calc_distanceCurveVerts(head, tail - 1);
}
}
+
+#undef SEL_F1
+#undef SEL_F2
+#undef SEL_F3
}
/* ********************* lattice *************** */
@@ -1812,7 +1889,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
Base *base = CTX_data_active_base(C);
Object *ob = CTX_data_active_object(C);
ParticleEditSettings *pset = PE_settings(t->scene);
- PTCacheEdit *edit = PE_get_current(t->scene, ob);
+ PTCacheEdit *edit = PE_get_current(t->scene, t->scene_layer, ob);
ParticleSystem *psys = NULL;
ParticleSystemModifierData *psmd = NULL;
PTCacheEditPoint *point;
@@ -1929,8 +2006,9 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
void flushTransParticles(TransInfo *t)
{
Scene *scene = t->scene;
- Object *ob = OBACT;
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ SceneLayer *sl = t->scene_layer;
+ Object *ob = OBACT_NEW;
+ PTCacheEdit *edit = PE_get_current(scene, sl, ob);
ParticleSystem *psys = edit->psys;
ParticleSystemModifierData *psmd = NULL;
PTCacheEditPoint *point;
@@ -1969,14 +2047,16 @@ void flushTransParticles(TransInfo *t)
point->flag |= PEP_EDIT_RECALC;
}
- PE_update_object(scene, OBACT, 1);
+ PE_update_object(scene, sl, OBACT_NEW, 1);
}
/* ******************* hair edit **************** */
-static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float *dists);
-static struct TransIslandData *bmesh_islands_info_calc(BMesh *bm, short selectmode, int *r_island_tot, int **r_island_vert_map);
+static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float *dists, int *index);
+static struct TransIslandData *bmesh_islands_info_calc(
+ BMesh *bm, short selectmode, int *r_island_tot, int **r_island_vert_map,
+ bool calc_single_islands);
static void StrandVertsToTransData(TransInfo *t, TransData *td,
BMEditStrands *UNUSED(edit), BMVert *eve, const float nor[3], const float tang[3],
@@ -2026,13 +2106,19 @@ static void createTransStrandVerts(TransInfo *t)
float mtx[3][3], smtx[3][3];
float *dists = NULL;
int a;
- int propmode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
+ int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
int mirror = 0;
struct TransIslandData *island_info = NULL;
int island_info_tot;
int *island_vert_map = NULL;
+ /* 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;
+
if (t->flag & T_MIRROR) {
#if 0 // TODO mirror relies on EDBM functions which don't have an equivalent for editstrands yet
EDBM_verts_mirror_cache_begin(em, 0, false, (t->flag & T_PROP_EDIT) == 0, false);
@@ -2046,7 +2132,7 @@ static void createTransStrandVerts(TransInfo *t)
goto cleanup;
}
- if (propmode) {
+ 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)) {
@@ -2057,8 +2143,12 @@ static void createTransStrandVerts(TransInfo *t)
t->total = count;
/* allocating scratch arrays */
- if (propmode & T_PROP_CONNECTED)
+ if (prop_mode & T_PROP_CONNECTED) {
dists = MEM_mallocN(bm->totvert * sizeof(float), "scratch nears");
+ if (is_island_center) {
+ dists_index = MEM_mallocN(bm->totvert * sizeof(int), __func__);
+ }
+ }
}
else {
t->total = bm->totvertsel;
@@ -2071,12 +2161,15 @@ static void createTransStrandVerts(TransInfo *t)
* matrix inversion still works and we can still moving along the other */
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
- if (propmode & T_PROP_CONNECTED) {
- editmesh_set_connectivity_distance(bm, mtx, dists);
+ if (prop_mode & T_PROP_CONNECTED) {
+ editmesh_set_connectivity_distance(bm, mtx, dists, dists_index);
}
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- island_info = bmesh_islands_info_calc(bm, SCE_SELECT_VERTEX, &island_info_tot, &island_vert_map);
+ 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);
+
+ island_info = bmesh_islands_info_calc(bm, SCE_SELECT_VERTEX, &island_info_tot, &island_vert_map, calc_single_islands);
}
/* find out which half we do */
@@ -2099,7 +2192,7 @@ static void createTransStrandVerts(TransInfo *t)
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- if (propmode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
struct TransIslandData *v_island = (island_info && island_vert_map[a] != -1) ?
&island_info[island_vert_map[a]] : NULL;
/* XXX TODO calculate normal and tangent along the strand */
@@ -2113,8 +2206,8 @@ static void createTransStrandVerts(TransInfo *t)
if (BM_elem_flag_test(eve, BM_ELEM_SELECT))
tob->flag |= TD_SELECTED;
- if (propmode) {
- if (propmode & T_PROP_CONNECTED) {
+ if (prop_mode) {
+ if (prop_mode & T_PROP_CONNECTED) {
tob->dist = dists[a];
}
else {
@@ -2179,9 +2272,12 @@ void flushTransStrands(TransInfo *t)
/* ********************* mesh ****************** */
-static bool bmesh_test_dist_add(BMVert *v, BMVert *v_other,
- float *dists, const float *dists_prev,
- float mtx[3][3])
+static bool bmesh_test_dist_add(
+ BMVert *v, BMVert *v_other,
+ float *dists, const float *dists_prev,
+ /* optionally track original index */
+ int *index, const int *index_prev,
+ float mtx[3][3])
{
if ((BM_elem_flag_test(v_other, BM_ELEM_SELECT) == 0) &&
(BM_elem_flag_test(v_other, BM_ELEM_HIDDEN) == 0))
@@ -2196,6 +2292,9 @@ static bool bmesh_test_dist_add(BMVert *v, BMVert *v_other,
dist_other = dists_prev[i] + len_v3(vec);
if (dist_other < dists[i_other]) {
dists[i_other] = dist_other;
+ if (index != NULL) {
+ index[i_other] = index_prev[i];
+ }
return true;
}
}
@@ -2203,11 +2302,13 @@ static bool bmesh_test_dist_add(BMVert *v, BMVert *v_other,
return false;
}
-static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float *dists)
+/**
+ * \param mtx: Measure disatnce in this space.
+ * \param dists: Store the closest connected distance to selected vertices.
+ * \param index: Optionally store the original index we're measuring the distance to (can be NULL).
+ */
+static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float *dists, int *index)
{
- /* need to be very careful of feedback loops here, store previous dist's to avoid feedback */
- float *dists_prev = MEM_mallocN(bm->totvert * sizeof(float), __func__);
-
BLI_LINKSTACK_DECLARE(queue, BMVert *);
/* any BM_ELEM_TAG'd vertex is in 'queue_next', so we don't add in twice */
@@ -2228,17 +2329,27 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float
if (BM_elem_flag_test(v, BM_ELEM_SELECT) == 0 || BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
dist = FLT_MAX;
+ if (index != NULL) {
+ index[i] = i;
+ }
}
else {
BLI_LINKSTACK_PUSH(queue, v);
dist = 0.0f;
+ if (index != NULL) {
+ index[i] = i;
+ }
}
- dists[i] = dists_prev[i] = dist;
+ dists[i] = dist;
}
bm->elem_index_dirty &= ~BM_VERT;
}
+ /* need to be very careful of feedback loops here, store previous dist's to avoid feedback */
+ float *dists_prev = MEM_dupallocN(dists);
+ int *index_prev = MEM_dupallocN(index); /* may be NULL */
+
do {
BMVert *v;
LinkNode *lnk;
@@ -2267,7 +2378,7 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float
/* edge distance */
{
BMVert *v_other = BM_edge_other_vert(e_iter, v);
- if (bmesh_test_dist_add(v, v_other, dists, dists_prev, mtx)) {
+ if (bmesh_test_dist_add(v, v_other, dists, dists_prev, index, index_prev, mtx)) {
if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
BM_elem_flag_enable(v_other, BM_ELEM_TAG);
BLI_LINKSTACK_PUSH(queue_next, v_other);
@@ -2292,7 +2403,7 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float
(BM_elem_flag_test(l_iter_radial->f, BM_ELEM_HIDDEN) == 0))
{
BMVert *v_other = l_iter_radial->next->next->v;
- if (bmesh_test_dist_add(v, v_other, dists, dists_prev, mtx)) {
+ if (bmesh_test_dist_add(v, v_other, dists, dists_prev, index, index_prev, mtx)) {
if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
BM_elem_flag_enable(v_other, BM_ELEM_TAG);
BLI_LINKSTACK_PUSH(queue_next, v_other);
@@ -2316,6 +2427,9 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float
/* keep in sync, avoid having to do full memcpy each iteration */
dists_prev[i] = dists[i];
+ if (index != NULL) {
+ index_prev[i] = index[i];
+ }
}
BLI_LINKSTACK_SWAP(queue, queue_next);
@@ -2329,9 +2443,14 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float
BLI_LINKSTACK_FREE(queue_next);
MEM_freeN(dists_prev);
+ if (index_prev != NULL) {
+ MEM_freeN(index_prev);
+ }
}
-static struct TransIslandData *bmesh_islands_info_calc(BMesh *bm, short selectmode, int *r_island_tot, int **r_island_vert_map)
+static struct TransIslandData *bmesh_islands_info_calc(
+ BMesh *bm, short selectmode, int *r_island_tot, int **r_island_vert_map,
+ bool calc_single_islands)
{
struct TransIslandData *trans_islands;
char htype;
@@ -2442,6 +2561,42 @@ static struct TransIslandData *bmesh_islands_info_calc(BMesh *bm, short selectmo
MEM_freeN(groups_array);
MEM_freeN(group_index);
+ /* for PET we need islands of 1 so connected vertices can use it with V3D_AROUND_LOCAL_ORIGINS */
+ if (calc_single_islands) {
+ BMIter viter;
+ BMVert *v;
+ int group_tot_single = 0;
+
+ BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) {
+ group_tot_single += 1;
+ }
+ }
+
+ if (group_tot_single != 0) {
+ trans_islands = MEM_reallocN(trans_islands, sizeof(*trans_islands) * (group_tot + group_tot_single));
+
+ BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) {
+ struct TransIslandData *v_island = &trans_islands[group_tot];
+ vert_map[i] = group_tot;
+
+ copy_v3_v3(v_island->co, v->co);
+
+ if (is_zero_v3(v->no) != 0.0f) {
+ axis_dominant_v3_to_m3(v_island->axismtx, v->no);
+ invert_m3(v_island->axismtx);
+ }
+ else {
+ unit_m3(v_island->axismtx);
+ }
+
+ group_tot += 1;
+ }
+ }
+ }
+ }
+
*r_island_tot = group_tot;
*r_island_vert_map = vert_map;
@@ -2541,6 +2696,12 @@ static void createTransEditVerts(TransInfo *t)
int island_info_tot;
int *island_vert_map = NULL;
+ /* 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;
+
if (t->flag & T_MIRROR) {
EDBM_verts_mirror_cache_begin(em, 0, false, (t->flag & T_PROP_EDIT) == 0, use_topology);
mirror = 1;
@@ -2572,8 +2733,12 @@ static void createTransEditVerts(TransInfo *t)
t->total = count;
/* allocating scratch arrays */
- if (prop_mode & T_PROP_CONNECTED)
- dists = MEM_mallocN(em->bm->totvert * sizeof(float), "scratch nears");
+ 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;
@@ -2595,11 +2760,16 @@ static void createTransEditVerts(TransInfo *t)
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
if (prop_mode & T_PROP_CONNECTED) {
- editmesh_set_connectivity_distance(em->bm, mtx, dists);
+ editmesh_set_connectivity_distance(em->bm, mtx, dists, dists_index);
}
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- island_info = bmesh_islands_info_calc(em->bm, em->selectmode, &island_info_tot, &island_vert_map);
+ 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) &&
+ (em->selectmode & SCE_SELECT_VERTEX));
+
+ island_info = bmesh_islands_info_calc(em->bm, em->selectmode, &island_info_tot, &island_vert_map, calc_single_islands);
}
/* detect CrazySpace [tm] */
@@ -2649,10 +2819,16 @@ static void createTransEditVerts(TransInfo *t)
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 = (island_info && island_vert_map[a] != -1) ?
- &island_info[island_vert_map[a]] : NULL;
+ 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;
+ }
+
+
VertsToTransData(t, tob, tx, em, eve, bweight, v_island);
if (tx)
tx++;
@@ -2731,6 +2907,8 @@ cleanup:
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);
@@ -2982,7 +3160,6 @@ static void createTransUVs(bContext *C, TransInfo *t)
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;
@@ -3006,10 +3183,9 @@ static void createTransUVs(bContext *C, TransInfo *t)
}
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 (!uvedit_face_visible_test(scene, ima, efa, tf)) {
+ if (!uvedit_face_visible_test(scene, ima, efa)) {
BM_elem_flag_disable(efa, BM_ELEM_TAG);
continue;
}
@@ -5464,7 +5640,8 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
}
/* update object's loc/rot to get current rigid body transform */
mat4_to_loc_rot_size(ob->loc, rot, scale, ob->obmat);
- BKE_object_mat3_to_rot(ob, rot, false);
+ sub_v3_v3(ob->loc, ob->dloc);
+ BKE_object_mat3_to_rot(ob, rot, false); /* drot is already corrected here */
}
}
@@ -5563,12 +5740,11 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
/* it deselects Bases, so we have to call the clear function always after */
static void set_trans_object_base_flags(TransInfo *t)
{
- Scene *scene = t->scene;
- View3D *v3d = t->view;
+ SceneLayer *sl = t->scene_layer;
/*
* if Base selected and has parent selected:
- * base->flag = BA_WAS_SEL
+ * base->flag_legacy = BA_WAS_SEL
*/
Base *base;
@@ -5577,32 +5753,32 @@ static void set_trans_object_base_flags(TransInfo *t)
return;
/* makes sure base flags and object flags are identical */
- BKE_scene_base_flag_to_objects(t->scene);
+ BKE_scene_base_flag_to_objects(t->scene_layer);
/* Make sure depsgraph is here. */
- DAG_scene_relations_update(G.main, t->scene);
+ DEG_scene_relations_update(G.main, t->scene);
/* handle pending update events, otherwise they got copied below */
- for (base = scene->base.first; base; base = base->next) {
+ for (base = sl->object_bases.first; base; base = base->next) {
if (base->object->recalc & OB_RECALC_ALL) {
/* TODO(sergey): Ideally, it's not needed. */
BKE_object_handle_update(G.main->eval_ctx, t->scene, base->object);
}
}
- for (base = scene->base.first; base; base = base->next) {
- base->flag &= ~BA_WAS_SEL;
+ for (base = sl->object_bases.first; base; base = base->next) {
+ base->flag_legacy &= ~BA_WAS_SEL;
- if (TESTBASELIB_BGMODE(v3d, scene, base)) {
+ if (TESTBASELIB_BGMODE_NEW(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 (parsel->base_flag & BASE_SELECTED) {
+ Base *parbase = BKE_scene_layer_base_find(sl, parsel);
if (parbase) { /* in rare cases this can fail */
- if (TESTBASELIB_BGMODE(v3d, scene, parbase)) {
+ if (TESTBASELIB_BGMODE_NEW(parbase)) {
break;
}
}
@@ -5615,29 +5791,24 @@ static void set_trans_object_base_flags(TransInfo *t)
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);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
}
}
- /* all recalc flags get flushed to all layers, so a layer flip later on works fine */
-#ifdef WITH_LEGACY_DEPSGRAPH
- DAG_scene_flush_update(G.main, t->scene, -1, 0);
-#endif
-
/* 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) {
+ for (base = sl->object_bases.first; base; base = base->next) {
if (base->object->recalc & OB_RECALC_OB)
- base->flag |= BA_HAS_RECALC_OB;
+ base->flag_legacy |= BA_HAS_RECALC_OB;
if (base->object->recalc & OB_RECALC_DATA)
- base->flag |= BA_HAS_RECALC_DATA;
+ base->flag_legacy |= BA_HAS_RECALC_DATA;
}
}
@@ -5659,8 +5830,7 @@ static bool mark_children(Object *ob)
static int count_proportional_objects(TransInfo *t)
{
int total = 0;
- Scene *scene = t->scene;
- View3D *v3d = t->view;
+ SceneLayer *sl = t->scene_layer;
Base *base;
/* rotations around local centers are allowed to propagate, so we take all objects */
@@ -5668,8 +5838,8 @@ static int count_proportional_objects(TransInfo *t)
(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)) {
+ for (base = sl->object_bases.first; base; base = base->next) {
+ if (TESTBASELIB_BGMODE_NEW(base)) {
Object *parent = base->object->parent;
/* flag all parents */
@@ -5681,25 +5851,27 @@ static int count_proportional_objects(TransInfo *t)
}
/* mark all children */
- for (base = scene->base.first; base; base = base->next) {
+ for (base = sl->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_NEW(base)))
{
mark_children(base->object);
}
}
}
- for (base = scene->base.first; base; base = base->next) {
+ for (base = sl->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_NEW(base)))
{
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
total += 1;
}
@@ -5707,18 +5879,15 @@ static int count_proportional_objects(TransInfo *t)
/* all recalc flags get flushed to all layers, so a layer flip later on works fine */
- DAG_scene_relations_update(G.main, t->scene);
-#ifdef WITH_LEGACY_DEPSGRAPH
- DAG_scene_flush_update(G.main, t->scene, -1, 0);
-#endif
+ DEG_scene_relations_update(G.main, t->scene);
/* 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) {
+ for (base = sl->object_bases.first; base; base = base->next) {
if (base->object->recalc & OB_RECALC_OB)
- base->flag |= BA_HAS_RECALC_OB;
+ base->flag_legacy |= BA_HAS_RECALC_OB;
if (base->object->recalc & OB_RECALC_DATA)
- base->flag |= BA_HAS_RECALC_DATA;
+ base->flag_legacy |= BA_HAS_RECALC_DATA;
}
return total;
@@ -5726,14 +5895,15 @@ static int count_proportional_objects(TransInfo *t)
static void clear_trans_object_base_flags(TransInfo *t)
{
- Scene *sce = t->scene;
+ SceneLayer *sl = t->scene_layer;
Base *base;
- for (base = sce->base.first; base; base = base->next) {
- if (base->flag & BA_WAS_SEL)
- base->flag |= SELECT;
+ for (base = sl->object_bases.first; base; base = base->next) {
+ if (base->flag_legacy & BA_WAS_SEL) {
+ base->flag |= BASE_SELECTED;
+ }
- base->flag &= ~(BA_WAS_SEL | BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA | BA_TEMP_TAG | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT);
+ base->flag_legacy &= ~(BA_WAS_SEL | BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA | BA_TEMP_TAG | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT);
}
}
@@ -5741,7 +5911,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_ob_cb_func(bContext *C, Scene *scene, SceneLayer *sl, View3D *v3d, Object *ob, int tmode)
{
ID *id = &ob->id;
FCurve *fcu;
@@ -5788,9 +5958,9 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob,
if (tmode == TFM_TRANSLATION) {
do_loc = true;
}
- else if (tmode == TFM_ROTATION) {
+ else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
if (v3d->around == V3D_AROUND_ACTIVE) {
- if (ob != OBACT)
+ if (ob != OBACT_NEW)
do_loc = true;
}
else if (v3d->around == V3D_AROUND_CURSOR)
@@ -5801,7 +5971,7 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob,
}
else if (tmode == TFM_RESIZE) {
if (v3d->around == V3D_AROUND_ACTIVE) {
- if (ob != OBACT)
+ if (ob != OBACT_NEW)
do_loc = true;
}
else if (v3d->around == V3D_AROUND_CURSOR)
@@ -5933,7 +6103,7 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o
else
do_loc = true;
}
- else if (tmode == TFM_ROTATION) {
+ else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
if (ELEM(v3d->around, V3D_AROUND_CURSOR, V3D_AROUND_ACTIVE))
do_loc = true;
@@ -6294,9 +6464,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:
@@ -6506,24 +6676,24 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
/* 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);
+ DEG_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);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
ob->recalc = 0; // is set on OK position already by recalcData()
}
else
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
else if (t->options & CTX_PAINT_CURVE) {
/* pass */
}
- else if ((t->scene->basact) &&
- (ob = t->scene->basact->object) &&
+ else if ((t->scene_layer->basact) &&
+ (ob = t->scene_layer->basact->object) &&
(ob->mode & OB_MODE_PARTICLE_EDIT) &&
- PE_get_current(t->scene, ob))
+ PE_get_current(t->scene, t->scene_layer, ob))
{
/* do nothing */
}
@@ -6561,17 +6731,17 @@ 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_ob_cb_func(C, t->scene, t->scene_layer, (View3D *)t->view, ob, t->mode);
}
/* restore rigid body transform */
@@ -6606,8 +6776,6 @@ 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;
@@ -6657,15 +6825,16 @@ static void createTransObject(bContext *C, TransInfo *t)
CTX_DATA_END;
if (is_prop_edit) {
- View3D *v3d = t->view;
+ SceneLayer *sl = t->scene_layer;
Base *base;
- for (base = scene->base.first; base; base = base->next) {
+ for (base = sl->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_NEW(base))
{
td->protectflag = ob->protectflag;
td->ext = tx;
@@ -8112,7 +8281,8 @@ static void createTransGPencil(bContext *C, TransInfo *t)
void createTransData(bContext *C, TransInfo *t)
{
Scene *scene = t->scene;
- Object *ob = OBACT;
+ SceneLayer *sl = t->scene_layer;
+ Object *ob = OBACT_NEW;
/* if tests must match recalcData for correct updates */
if (t->options & CTX_TEXTURE) {
@@ -8245,7 +8415,12 @@ void createTransData(bContext *C, TransInfo *t)
if (t->data && t->flag & T_PROP_EDIT) {
if (ELEM(t->obedit->type, OB_CURVE, OB_MESH)) {
sort_trans_data(t); // makes selected become first in array
- set_prop_dist(t, 0);
+ if ((t->obedit->type == OB_MESH) && (t->flag & T_PROP_CONNECTED)) {
+ /* already calculated by editmesh_set_connectivity_distance */
+ }
+ else {
+ set_prop_dist(t, 0);
+ }
sort_trans_data_dist(t);
}
else {
@@ -8272,17 +8447,16 @@ void createTransData(bContext *C, TransInfo *t)
* 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_scene_layer_base_find(t->scene_layer, ob_armature);
if (base_arm) {
- View3D *v3d = t->view;
- if (BASE_VISIBLE(v3d, base_arm)) {
+ if (BASE_VISIBLE_NEW(base_arm)) {
createTransPose(t, ob_armature);
}
}
}
}
- else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_start_edit(PE_get_current(scene, ob))) {
+ else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_start_edit(PE_get_current(scene, sl, ob))) {
createTransParticleVerts(C, t);
t->flag |= T_POINTS;
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 6bb26549c5d..b360a99f7fc 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -62,8 +62,8 @@
#include "RNA_access.h"
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
#include "BIK_api.h"
@@ -71,7 +71,6 @@
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_editstrands.h"
#include "BKE_fcurve.h"
#include "BKE_lattice.h"
@@ -84,6 +83,9 @@
#include "BKE_tracking.h"
#include "BKE_mask.h"
#include "BKE_utildefines.h"
+#include "BKE_workspace.h"
+
+#include "DEG_depsgraph.h"
#include "ED_anim_api.h"
#include "ED_armature.h"
@@ -316,7 +318,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;
+ SceneLayer *sl= t->scene_layer;
SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
bAnimContext ac = {NULL};
@@ -327,7 +329,8 @@ static void recalcData_actedit(TransInfo *t)
/* initialize relevant anim-context 'context' data from TransInfo data */
/* NOTE: sync this with the code in ANIM_animdata_get_context() */
ac.scene = t->scene;
- ac.obact = OBACT;
+ ac.scene_layer = t->scene_layer;
+ ac.obact = OBACT_NEW;
ac.sa = t->sa;
ac.ar = t->ar;
ac.sl = (t->sa) ? t->sa->spacedata.first : NULL;
@@ -364,7 +367,7 @@ static void recalcData_actedit(TransInfo *t)
static void recalcData_graphedit(TransInfo *t)
{
SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
- Scene *scene;
+ SceneLayer *sl = t->scene_layer;
ListBase anim_data = {NULL, NULL};
bAnimContext ac = {NULL};
@@ -375,8 +378,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() */
- scene = ac.scene = t->scene;
- ac.obact = OBACT;
+ ac.scene = t->scene;
+ ac.scene_layer = t->scene_layer;
+ ac.obact = OBACT_NEW;
ac.sa = t->sa;
ac.ar = t->ar;
ac.sl = (t->sa) ? t->sa->spacedata.first : NULL;
@@ -638,7 +642,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 */
@@ -657,7 +661,7 @@ static void recalcData_image(TransInfo *t)
if (sima->flag & SI_LIVE_UNWRAP)
ED_uvedit_live_unwrap_re_solve();
- DAG_id_tag_update(t->obedit->data, 0);
+ DEG_id_tag_update(t->obedit->data, 0);
}
}
@@ -700,7 +704,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);
@@ -710,7 +714,7 @@ static void recalcData_spaceclip(TransInfo *t)
/* helper for recalcData() - for object transforms, typically in the 3D view */
static void recalcData_objects(TransInfo *t)
{
- Base *base = t->scene->basact;
+ Base *base = t->scene_layer->basact;
if (t->obedit) {
if (ELEM(t->obedit->type, OB_CURVE, OB_SURF)) {
@@ -723,7 +727,7 @@ static void recalcData_objects(TransInfo *t)
applyProject(t);
}
- DAG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */
+ DEG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */
if (t->state == TRANS_CANCEL) {
while (nu) {
@@ -747,7 +751,7 @@ static void recalcData_objects(TransInfo *t)
applyProject(t);
}
- DAG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */
+ DEG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */
if (la->editlatt->latt->flag & LT_OUTSIDE) outside_lattice(la->editlatt->latt);
}
@@ -769,7 +773,7 @@ static void recalcData_objects(TransInfo *t)
projectVertSlideData(t, false);
}
- DAG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */
+ DEG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */
EDBM_mesh_normals_update(em);
BKE_editmesh_tessface_calc(em);
@@ -867,7 +871,7 @@ static void recalcData_objects(TransInfo *t)
if (t->state != TRANS_CANCEL) {
applyProject(t);
}
- DAG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */
+ DEG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */
}
}
else if ((t->flag & T_POSE) && t->poseobj) {
@@ -890,14 +894,14 @@ static void recalcData_objects(TransInfo *t)
/* 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 */
+ 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->scene, ob);
}
- else if (base && (base->object->mode & OB_MODE_PARTICLE_EDIT) && PE_get_current(t->scene, base->object)) {
+ else if (base && (base->object->mode & OB_MODE_PARTICLE_EDIT) && PE_get_current(t->scene, t->scene_layer, base->object)) {
if (t->state != TRANS_CANCEL) {
applyProject(t);
}
@@ -933,16 +937,16 @@ static void recalcData_objects(TransInfo *t)
// 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);
+ autokeyframe_ob_cb_func(t->context, t->scene, t->scene_layer, (View3D *)t->view, ob, t->mode);
}
/* sets recalc flags fully, instead of flushing existing ones
* otherwise proxies don't function correctly
*/
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
if (t->flag & T_TEXTURE)
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
}
}
@@ -978,7 +982,7 @@ 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++) {
bGPDstroke *gps = td->extra;
@@ -1039,11 +1043,10 @@ 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
-
-
+ gpuPushMatrix();
+
+ // if (t->obedit) gpuLoadMatrix(t->obedit->obmat); // sets opengl viewing
+
copy_v3_v3(v3, dir);
mul_v3_fl(v3, v3d->far);
@@ -1057,15 +1060,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();
-
- glPopMatrix();
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor3ubv(col2);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex3fv(pos, v1);
+ immVertex3fv(pos, v2);
+ immEnd();
+
+ immUnbindProgram();
+
+ gpuPopMatrix();
}
}
@@ -1111,6 +1119,7 @@ static int initTransInfo_edit_pet_to_flag(const int proportional)
void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event)
{
Scene *sce = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
ToolSettings *ts = CTX_data_tool_settings(C);
ARegion *ar = CTX_wm_region(C);
ScrArea *sa = CTX_wm_area(C);
@@ -1120,6 +1129,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
PropertyRNA *prop;
t->scene = sce;
+ t->scene_layer = sl;
t->sa = sa;
t->ar = ar;
t->obedit = obedit;
@@ -1227,7 +1237,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->animtimer = (animscreen) ? animscreen->animtimer : NULL;
/* turn manipulator off during transform */
- // FIXME: but don't do this when USING the manipulator...
if (t->flag & T_MODAL) {
t->twtype = v3d->twtype;
v3d->twtype = 0;
@@ -1242,6 +1251,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
t->current_orientation = v3d->twmode;
+ t->custom_orientation = BKE_workspace_transform_orientation_find(
+ CTX_wm_workspace(C), v3d->custom_orientation_index);
/* exceptional case */
if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
@@ -1332,13 +1343,24 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
if (op && ((prop = RNA_struct_find_property(op->ptr, "constraint_orientation")) &&
RNA_property_is_set(op->ptr, prop)))
{
- t->current_orientation = RNA_property_enum_get(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_workspace_transform_orientation_find(
+ CTX_wm_workspace(C), orientation - V3D_MANIP_CUSTOM);
+ orientation = V3D_MANIP_CUSTOM;
+ }
}
+
+ t->current_orientation = orientation;
+ t->custom_orientation = custom_orientation;
}
-
+
if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) &&
RNA_property_is_set(op->ptr, prop)))
{
@@ -1774,8 +1796,8 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
}
}
else if (t->flag & T_POSE) {
- Scene *scene = t->scene;
- Object *ob = OBACT;
+ SceneLayer *sl = t->scene_layer;
+ Object *ob = OBACT_NEW;
if (ob) {
bPoseChannel *pchan = BKE_pose_channel_active(ob);
if (pchan && (!select_only || (pchan->bone->flag & BONE_SELECTED))) {
@@ -1785,7 +1807,7 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
}
}
else if (t->options & CTX_PAINT_CURVE) {
- Paint *p = BKE_paint_get_active(t->scene);
+ Paint *p = BKE_paint_get_active(t->scene, t->scene_layer);
Brush *br = p->brush;
PaintCurve *pc = br->paint_curve;
copy_v3_v3(r_center, pc->points[pc->add_index - 1].bez.vec[1]);
@@ -1794,9 +1816,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))) {
+ SceneLayer *sl = t->scene_layer;
+ Object *ob = OBACT_NEW;
+ Base *base = BASACT_NEW;
+ if (ob && ((!select_only) || ((base->flag & BASE_SELECTED) != 0))) {
copy_v3_v3(r_center, ob->obmat[3]);
ok = true;
}
diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c
index 9b7d19eacd5..5f2e5a99090 100644
--- a/source/blender/editors/transform/transform_input.c
+++ b/source/blender/editors/transform/transform_input.c
@@ -86,12 +86,11 @@ static void InputTrackBall(TransInfo *UNUSED(t), MouseInput *mi, const double mv
output[1] *= mi->factor;
}
-static void InputHorizontalRatio(TransInfo *t, MouseInput *UNUSED(mi), const double mval[2], float output[3])
+static void InputHorizontalRatio(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
{
const int winx = t->ar ? t->ar->winx : 1;
- const double pad = winx / 10;
- output[0] = (mval[0] - pad) / (winx - 2 * pad);
+ output[0] = ((mval[0] - mi->imval[0]) / winx) * 2.0f;
}
static void InputHorizontalAbsolute(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
@@ -104,12 +103,11 @@ static void InputHorizontalAbsolute(TransInfo *t, MouseInput *mi, const double m
output[0] = dot_v3v3(t->viewinv[0], vec) * 2.0f;
}
-static void InputVerticalRatio(TransInfo *t, MouseInput *UNUSED(mi), const double mval[2], float output[3])
+static void InputVerticalRatio(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
{
const int winy = t->ar ? t->ar->winy : 1;
- const double pad = winy / 10;
- output[0] = (mval[1] - pad) / (winy - 2 * pad);
+ output[0] = ((mval[1] - mi->imval[1]) / winy) * 2.0f;
}
static void InputVerticalAbsolute(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
@@ -187,7 +185,7 @@ static void InputAngle(TransInfo *UNUSED(t), MouseInput *mi, const double mval[2
/* use doubles here, to make sure a "1.0" (no rotation) doesn't become 9.999999e-01, which gives 0.02 for acos */
double deler = (((dx1 * dx1 + dy1 * dy1) +
(dx2 * dx2 + dy2 * dy2) -
- (dx3 * dx3 + dy3 * dy3)) / (2.0 * ((A * B) ? (A * B) : 1.0)));
+ (dx3 * dx3 + dy3 * dy3)) / (2.0 * (((A * B) != 0.0) ? (A * B) : 1.0)));
/* ((A * B) ? (A * B) : 1.0) this takes care of potential divide by zero errors */
float dphi;
@@ -234,10 +232,10 @@ static void InputAngleSpring(TransInfo *t, MouseInput *mi, const double mval[2],
output[1] = toutput[0];
}
-void initMouseInput(TransInfo *UNUSED(t), MouseInput *mi, const float center[2], const int mval[2])
+void initMouseInput(TransInfo *UNUSED(t), MouseInput *mi, const float center[2], const int mval[2], const bool precision)
{
mi->factor = 0;
- mi->precision = 0;
+ mi->precision = precision;
mi->center[0] = center[0];
mi->center[1] = center[1];
@@ -314,7 +312,6 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode)
t->helpline = HLP_TRACKBALL;
break;
case INPUT_HORIZONTAL_RATIO:
- mi->factor = (float)(mi->center[0] - mi->imval[0]);
mi->apply = InputHorizontalRatio;
t->helpline = HLP_HARROW;
break;
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index 075f311db72..0f5f2f02e84 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -59,6 +59,7 @@
#include "BKE_editmesh.h"
#include "BKE_lattice.h"
#include "BKE_gpencil.h"
+#include "BKE_workspace.h"
#include "BIF_gl.h"
@@ -67,16 +68,23 @@
#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_manipulator_library.h"
#include "UI_resources.h"
/* local module include */
#include "transform.h"
+#include "MEM_guardedalloc.h"
+
#include "GPU_select.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
/* return codes for select, and drawing flags */
@@ -88,25 +96,350 @@
#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_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)
-/* 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
+/* axes as index */
+enum {
+ MAN_AXIS_TRANS_X = 0,
+ MAN_AXIS_TRANS_Y,
+ MAN_AXIS_TRANS_Z,
+ MAN_AXIS_TRANS_C,
+
+ MAN_AXIS_ROT_X,
+ MAN_AXIS_ROT_Y,
+ MAN_AXIS_ROT_Z,
+ MAN_AXIS_ROT_C,
+ MAN_AXIS_ROT_T, /* trackball rotation */
+
+ MAN_AXIS_SCALE_X,
+ MAN_AXIS_SCALE_Y,
+ MAN_AXIS_SCALE_Z,
+ MAN_AXIS_SCALE_C,
+
+ /* special */
+ MAN_AXIS_TRANS_XY,
+ MAN_AXIS_TRANS_YZ,
+ MAN_AXIS_TRANS_ZX,
+
+ MAN_AXIS_SCALE_XY,
+ MAN_AXIS_SCALE_YZ,
+ MAN_AXIS_SCALE_ZX,
+
+ MAN_AXIS_LAST,
+};
+
+/* axis types */
+enum {
+ MAN_AXES_ALL = 0,
+ MAN_AXES_TRANSLATE,
+ MAN_AXES_ROTATE,
+ MAN_AXES_SCALE,
+};
+
+typedef struct ManipulatorGroup {
+ bool all_hidden;
+
+ struct wmManipulator *translate_x,
+ *translate_y,
+ *translate_z,
+ *translate_xy,
+ *translate_yz,
+ *translate_zx,
+ *translate_c,
+
+ *rotate_x,
+ *rotate_y,
+ *rotate_z,
+ *rotate_c,
+ *rotate_t, /* trackball rotation */
+
+ *scale_x,
+ *scale_y,
+ *scale_z,
+ *scale_xy,
+ *scale_yz,
+ *scale_zx,
+ *scale_c;
+} ManipulatorGroup;
+
+
+/* **************** Utilities **************** */
+
+/* loop over axes */
+#define MAN_ITER_AXES_BEGIN(axis, axis_idx) \
+ { \
+ wmManipulator *axis; \
+ int axis_idx; \
+ for (axis_idx = 0; axis_idx < MAN_AXIS_LAST; axis_idx++) { \
+ axis = manipulator_get_axis_from_index(man, axis_idx);
+
+#define MAN_ITER_AXES_END \
+ } \
+ } ((void)0)
+
+static wmManipulator *manipulator_get_axis_from_index(const ManipulatorGroup *man, const short axis_idx)
+{
+ BLI_assert(IN_RANGE_INCL(axis_idx, (float)MAN_AXIS_TRANS_X, (float)MAN_AXIS_LAST));
+
+ switch (axis_idx) {
+ case MAN_AXIS_TRANS_X:
+ return man->translate_x;
+ case MAN_AXIS_TRANS_Y:
+ return man->translate_y;
+ case MAN_AXIS_TRANS_Z:
+ return man->translate_z;
+ case MAN_AXIS_TRANS_XY:
+ return man->translate_xy;
+ case MAN_AXIS_TRANS_YZ:
+ return man->translate_yz;
+ case MAN_AXIS_TRANS_ZX:
+ return man->translate_zx;
+ case MAN_AXIS_TRANS_C:
+ return man->translate_c;
+ case MAN_AXIS_ROT_X:
+ return man->rotate_x;
+ case MAN_AXIS_ROT_Y:
+ return man->rotate_y;
+ case MAN_AXIS_ROT_Z:
+ return man->rotate_z;
+ case MAN_AXIS_ROT_C:
+ return man->rotate_c;
+ case MAN_AXIS_ROT_T:
+ return man->rotate_t;
+ case MAN_AXIS_SCALE_X:
+ return man->scale_x;
+ case MAN_AXIS_SCALE_Y:
+ return man->scale_y;
+ case MAN_AXIS_SCALE_Z:
+ return man->scale_z;
+ case MAN_AXIS_SCALE_XY:
+ return man->scale_xy;
+ case MAN_AXIS_SCALE_YZ:
+ return man->scale_yz;
+ case MAN_AXIS_SCALE_ZX:
+ return man->scale_zx;
+ case MAN_AXIS_SCALE_C:
+ return man->scale_c;
+ }
+
+ return NULL;
+}
+
+static short manipulator_get_axis_type(const ManipulatorGroup *man, const wmManipulator *axis)
+{
+ if (ELEM(axis, man->translate_x, man->translate_y, man->translate_z, man->translate_c,
+ man->translate_xy, man->translate_yz, man->translate_zx))
+ {
+ return MAN_AXES_TRANSLATE;
+ }
+ else if (ELEM(axis, man->rotate_x, man->rotate_y, man->rotate_z, man->rotate_c, man->rotate_t)) {
+ return MAN_AXES_ROTATE;
+ }
+ else {
+ return MAN_AXES_SCALE;
+ }
+}
+
+/* get index within axis type, so that x == 0, y == 1 and z == 2, no matter which axis type */
+static uint manipulator_index_normalize(const int axis_idx)
+{
+ if (axis_idx > MAN_AXIS_TRANS_ZX) {
+ return axis_idx - 16;
+ }
+ else if (axis_idx > MAN_AXIS_SCALE_C) {
+ return axis_idx - 13;
+ }
+ else if (axis_idx > MAN_AXIS_ROT_T) {
+ return axis_idx - 9;
+ }
+ else if (axis_idx > MAN_AXIS_TRANS_C) {
+ return axis_idx - 4;
+ }
+
+ return axis_idx;
+}
+
+static bool manipulator_is_axis_visible(
+ const View3D *v3d, const RegionView3D *rv3d,
+ const float idot[3], const int axis_type, const int axis_idx)
+{
+ const uint aidx_norm = manipulator_index_normalize(axis_idx);
+ /* don't draw axis perpendicular to the view */
+ if (aidx_norm < 3 && idot[aidx_norm] < TW_AXIS_DOT_MIN) {
+ return false;
+ }
+
+ if ((axis_type == MAN_AXES_TRANSLATE && !(v3d->twtype & V3D_MANIP_TRANSLATE)) ||
+ (axis_type == MAN_AXES_ROTATE && !(v3d->twtype & V3D_MANIP_ROTATE)) ||
+ (axis_type == MAN_AXES_SCALE && !(v3d->twtype & V3D_MANIP_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 && (v3d->twtype & V3D_MANIP_TRANSLATE) == 0);
+ case MAN_AXIS_TRANS_XY:
+ return (rv3d->twdrawflag & MAN_TRANS_X &&
+ rv3d->twdrawflag & MAN_TRANS_Y &&
+ (v3d->twtype & V3D_MANIP_ROTATE) == 0);
+ case MAN_AXIS_TRANS_YZ:
+ return (rv3d->twdrawflag & MAN_TRANS_Y &&
+ rv3d->twdrawflag & MAN_TRANS_Z &&
+ (v3d->twtype & V3D_MANIP_ROTATE) == 0);
+ case MAN_AXIS_TRANS_ZX:
+ return (rv3d->twdrawflag & MAN_TRANS_Z &&
+ rv3d->twdrawflag & MAN_TRANS_X &&
+ (v3d->twtype & V3D_MANIP_ROTATE) == 0);
+ case MAN_AXIS_SCALE_XY:
+ return (rv3d->twdrawflag & MAN_SCALE_X &&
+ rv3d->twdrawflag & MAN_SCALE_Y &&
+ (v3d->twtype & V3D_MANIP_TRANSLATE) == 0 &&
+ (v3d->twtype & V3D_MANIP_ROTATE) == 0);
+ case MAN_AXIS_SCALE_YZ:
+ return (rv3d->twdrawflag & MAN_SCALE_Y &&
+ rv3d->twdrawflag & MAN_SCALE_Z &&
+ (v3d->twtype & V3D_MANIP_TRANSLATE) == 0 &&
+ (v3d->twtype & V3D_MANIP_ROTATE) == 0);
+ case MAN_AXIS_SCALE_ZX:
+ return (rv3d->twdrawflag & MAN_SCALE_Z &&
+ rv3d->twdrawflag & MAN_SCALE_X &&
+ (v3d->twtype & V3D_MANIP_TRANSLATE) == 0 &&
+ (v3d->twtype & V3D_MANIP_ROTATE) == 0);
+ }
+ return false;
+}
+
+static void manipulator_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;
+
+ const int axis_idx_norm = manipulator_index_normalize(axis_idx);
+ /* 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_axis = idot[axis_idx_norm];
+ alpha_fac = (idot_axis > TW_AXIS_DOT_MAX) ?
+ 1.0f : (idot_axis < TW_AXIS_DOT_MIN) ?
+ 0.0f : ((idot_axis - TW_AXIS_DOT_MIN) / (TW_AXIS_DOT_MAX - TW_AXIS_DOT_MIN));
+ }
+ else {
+ /* 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;
+ }
+
+ 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 manipulator_get_axis_constraint(const int axis_idx, int r_axis[3])
+{
+ zero_v3_int(r_axis);
+
+ 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(Scene *scene, const float co[3])
{
@@ -143,21 +476,17 @@ static void protectflag_to_drawflags(short protectflag, short *drawflags)
}
/* for pose mode */
-static void stats_pose(Scene *scene, RegionView3D *rv3d, bPoseChannel *pchan)
+static void protectflag_to_drawflags_pchan(RegionView3D *rv3d, const bPoseChannel *pchan)
{
- Bone *bone = pchan->bone;
-
- if (bone) {
- calc_tw_center(scene, pchan->pose_head);
- protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag);
- }
+ protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag);
}
/* for editmode*/
-static void stats_editbone(RegionView3D *rv3d, EditBone *ebo)
+static void protectflag_to_drawflags_ebone(RegionView3D *rv3d, const EditBone *ebo)
{
- if (ebo->flag & BONE_EDITMODE_LOCKED)
+ 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 */
@@ -192,73 +521,71 @@ static void axis_angle_to_gimbal_axis(float gmat[3][3], const float axis[3], con
}
-static int test_rotmode_euler(short rotmode)
+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) {
- 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];
+ if (ob->mode & OB_MODE_POSE) {
+ bPoseChannel *pchan = BKE_pose_channel_active(ob);
- 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);
+ 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 (ob->rotmode == ROT_MODE_AXISANGLE) {
- axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle);
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle);
}
else { /* quat */
return 0;
}
- if (ob->parent) {
+
+ /* 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, ob->parent->obmat);
- normalize_m3(parent_mat);
- mul_m3_m3m3(gmat, parent_mat, gmat);
+
+ 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;
}
@@ -271,11 +598,12 @@ static int calc_manipulator_stats(const bContext *C)
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *obedit = CTX_data_edit_object(C);
View3D *v3d = sa->spacedata.first;
RegionView3D *rv3d = ar->regiondata;
Base *base;
- Object *ob = OBACT;
+ Object *ob = OBACT_NEW;
bGPdata *gpd = CTX_data_gpencil_data(C);
const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE));
int a, totsel = 0;
@@ -340,8 +668,6 @@ static int calc_manipulator_stats(const bContext *C)
}
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;
@@ -385,7 +711,7 @@ static int calc_manipulator_stats(const bContext *C)
calc_tw_center(scene, ebo->head);
totsel++;
}
- stats_editbone(rv3d, ebo);
+ protectflag_to_drawflags_ebone(rv3d, ebo);
}
else {
for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
@@ -405,7 +731,7 @@ static int calc_manipulator_stats(const bContext *C)
totsel++;
}
if (ebo->flag & BONE_SELECTED) {
- stats_editbone(rv3d, ebo);
+ protectflag_to_drawflags_ebone(rv3d, ebo);
}
}
}
@@ -524,13 +850,12 @@ static int calc_manipulator_stats(const bContext *C)
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) {
- stats_pose(scene, rv3d, pchan);
+ calc_tw_center(scene, pchan->pose_head);
+ protectflag_to_drawflags_pchan(rv3d, pchan);
totsel = 1;
ok = true;
}
@@ -543,7 +868,8 @@ static int calc_manipulator_stats(const bContext *C)
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
Bone *bone = pchan->bone;
if (bone && (bone->flag & BONE_TRANSFORM)) {
- stats_pose(scene, rv3d, pchan);
+ calc_tw_center(scene, pchan->pose_head);
+ protectflag_to_drawflags_pchan(rv3d, pchan);
}
}
ok = true;
@@ -561,7 +887,7 @@ static int calc_manipulator_stats(const bContext *C)
/* pass */
}
else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) {
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(scene, sl, ob);
PTCacheEditPoint *point;
PTCacheEditKey *ek;
int k;
@@ -587,11 +913,12 @@ static int calc_manipulator_stats(const bContext *C)
else {
/* we need the one selected object, if its not active */
- ob = OBACT;
- if (ob && !(ob->flag & SELECT)) ob = NULL;
+ base = BASACT_NEW;
+ ob = OBACT_NEW;
+ if (base && ((base->flag & BASE_SELECTED) == 0)) ob = NULL;
- for (base = scene->base.first; base; base = base->next) {
- if (TESTBASELIB(v3d, base)) {
+ for (base = sl->object_bases.first; base; base = base->next) {
+ if (TESTBASELIB_NEW(base)) {
if (ob == NULL)
ob = base->object;
calc_tw_center(scene, base->object->obmat[3]);
@@ -623,7 +950,7 @@ static int calc_manipulator_stats(const bContext *C)
break;
}
/* if not gimbal, fall through to normal */
- /* fall-through */
+ ATTR_FALLTHROUGH;
}
case V3D_MANIP_NORMAL:
{
@@ -634,7 +961,7 @@ static int calc_manipulator_stats(const bContext *C)
break;
}
/* no break we define 'normal' as 'local' in Object mode */
- /* fall-through */
+ ATTR_FALLTHROUGH;
}
case V3D_MANIP_LOCAL:
{
@@ -660,10 +987,13 @@ static int calc_manipulator_stats(const bContext *C)
copy_m4_m3(rv3d->twmat, mat);
break;
}
- default: /* V3D_MANIP_CUSTOM */
+ case V3D_MANIP_CUSTOM:
{
+ TransformOrientation *custom_orientation = BKE_workspace_transform_orientation_find(
+ CTX_wm_workspace(C), v3d->custom_orientation_index);
float mat[3][3];
- if (applyTransformOrientation(C, mat, NULL, v3d->twmode - V3D_MANIP_CUSTOM)) {
+
+ if (applyTransformOrientation(custom_orientation, mat, NULL)) {
copy_m4_m3(rv3d->twmat, mat);
}
break;
@@ -675,1277 +1005,406 @@ static int calc_manipulator_stats(const bContext *C)
return totsel;
}
-/* don't draw axis perpendicular to the view */
-static void test_manipulator_axis(const bContext *C)
+static void manipulator_get_idot(RegionView3D *rv3d, float r_idot[3])
{
- 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++) {
+ for (int 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 */
-}
-
-
-/* radring = radius of doughnut rings
- * radhole = radius hole
- * start = starting segment (based on nrings)
- * end = end segment
- * nsides = amount of points in ring
- * nrigns = amount 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;
+ r_idot[i] = 1.0f - fabsf(dot_v3v3(view_vec, axis_vec));
}
}
-static char axisBlendAngle(float idot)
+static void manipulator_prepare_mat(const bContext *C, View3D *v3d, RegionView3D *rv3d)
{
- 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));
- }
-}
+ Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
-/* 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;
+ switch (v3d->around) {
+ case V3D_AROUND_CENTER_BOUNDS:
+ case V3D_AROUND_ACTIVE:
+ {
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ Object *ob = OBACT_NEW;
- 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;
+ if (((v3d->around == V3D_AROUND_ACTIVE) && (scene->obedit == NULL)) &&
+ ((gpd == NULL) || !(gpd->flag & GP_DATA_STROKE_EDITMODE)) &&
+ (!(ob->mode & OB_MODE_POSE)))
+ {
+ copy_v3_v3(rv3d->twmat[3], ob->obmat[3]);
}
- 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;
+ else {
+ mid_v3_v3v3(rv3d->twmat[3], scene->twmin, scene->twmax);
}
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;
}
+ case V3D_AROUND_LOCAL_ORIGINS:
+ case V3D_AROUND_CENTER_MEAN:
+ copy_v3_v3(rv3d->twmat[3], scene->twcent);
+ break;
+ case V3D_AROUND_CURSOR:
+ copy_v3_v3(rv3d->twmat[3], ED_view3d_cursor3d_get(scene, v3d));
+ break;
}
-
- glColor4ubv(col);
}
-static void manipulator_axis_order(RegionView3D *rv3d, int r_axis_order[3])
+/**
+ * Sets up \a r_start and \a r_len to define arrow line range.
+ * Needed to adjust line drawing for combined manipulator axis types.
+ */
+static void manipulator_line_range(const View3D *v3d, const short axis_type, float *r_start, float *r_len)
{
- float axis_values[3];
- float vec[3];
+ const float ofs = 0.2f;
- 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);
-}
+ *r_start = 0.2f;
+ *r_len = 1.0f;
-/* 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();
+ switch (axis_type) {
+ case MAN_AXES_TRANSLATE:
+ if (v3d->twtype & V3D_MANIP_SCALE) {
+ *r_start = *r_len - ofs + 0.075f;
}
- 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();
+ if (v3d->twtype & V3D_MANIP_ROTATE) {
+ *r_len += ofs;
}
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();
+ case MAN_AXES_SCALE:
+ if (v3d->twtype & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE)) {
+ *r_len -= ofs + 0.025f;
}
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();
- }
+ *r_len -= *r_start;
}
-BLI_INLINE bool manipulator_rotate_is_visible(const int drawflags)
-{
- return (drawflags & (MAN_ROT_X | MAN_ROT_Y | MAN_ROT_Z));
-}
+/* **************** Actual Widget Stuff **************** */
-static void draw_manipulator_rotate(
- View3D *v3d, RegionView3D *rv3d, const int drawflags, const int combo,
- const bool is_moving, const bool is_picksel)
+static ManipulatorGroup *manipulatorgroup_init(wmManipulatorGroup *mgroup)
{
- 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);
- }
+ ManipulatorGroup *man;
- glDisable(GL_CLIP_PLANE0);
- }
+ man = MEM_callocN(sizeof(ManipulatorGroup), "manipulator_data");
- if (arcs == 0) {
+ const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_3d", true);
+ const wmManipulatorType *wt_dial = WM_manipulatortype_find("MANIPULATOR_WT_dial_3d", true);
+ const wmManipulatorType *wt_prim = WM_manipulatortype_find("MANIPULATOR_WT_primitive_3d", true);
- /* 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);
+#define MANIPULATOR_NEW_ARROW(v, name, draw_style) { \
+ v = WM_manipulator_new_ptr(wt_arrow, mgroup, name, NULL); \
+ RNA_enum_set((v)->ptr, "draw_style", draw_style); \
+} ((void)0)
+#define MANIPULATOR_NEW_DIAL(v, name, draw_options) { \
+ v = WM_manipulator_new_ptr(wt_dial, mgroup, name, NULL); \
+ RNA_enum_set((v)->ptr, "draw_options", draw_options); \
+} ((void)0)
+#define MANIPULATOR_NEW_PRIM(v, name, draw_style) { \
+ v = WM_manipulator_new_ptr(wt_prim, mgroup, name, NULL); \
+ RNA_enum_set((v)->ptr, "draw_style", draw_style); \
+} ((void)0)
- partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64);
+ /* add/init widgets - order matters! */
+ MANIPULATOR_NEW_DIAL(man->rotate_t, "rotate_t", ED_MANIPULATOR_DIAL_DRAW_FLAG_FILL);
- 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);
+ MANIPULATOR_NEW_DIAL(man->scale_c, "scale_c", ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP);
- glPopMatrix();
- postOrtho(ortho);
- }
+ MANIPULATOR_NEW_ARROW(man->scale_x, "scale_x", ED_MANIPULATOR_ARROW_STYLE_BOX);
+ MANIPULATOR_NEW_ARROW(man->scale_y, "scale_y", ED_MANIPULATOR_ARROW_STYLE_BOX);
+ MANIPULATOR_NEW_ARROW(man->scale_z, "scale_z", ED_MANIPULATOR_ARROW_STYLE_BOX);
- /* 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);
+ MANIPULATOR_NEW_PRIM(man->scale_xy, "scale_xy", ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
+ MANIPULATOR_NEW_PRIM(man->scale_yz, "scale_yz", ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
+ MANIPULATOR_NEW_PRIM(man->scale_zx, "scale_zx", ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
- 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);
+ MANIPULATOR_NEW_DIAL(man->rotate_x, "rotate_x", ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP);
+ MANIPULATOR_NEW_DIAL(man->rotate_y, "rotate_y", ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP);
+ MANIPULATOR_NEW_DIAL(man->rotate_z, "rotate_z", ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP);
- glPopMatrix();
- postOrtho(ortho);
- }
+ /* init screen aligned widget last here, looks better, behaves better */
+ MANIPULATOR_NEW_DIAL(man->rotate_c, "rotate_c", ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP);
- }
+ MANIPULATOR_NEW_DIAL(man->translate_c, "translate_c", ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP);
- /* restore */
- glLoadMatrixf(rv3d->viewmat);
- if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
+ MANIPULATOR_NEW_ARROW(man->translate_x, "translate_x", ED_MANIPULATOR_ARROW_STYLE_NORMAL);
+ MANIPULATOR_NEW_ARROW(man->translate_y, "translate_y", ED_MANIPULATOR_ARROW_STYLE_NORMAL);
+ MANIPULATOR_NEW_ARROW(man->translate_z, "translate_z", ED_MANIPULATOR_ARROW_STYLE_NORMAL);
-}
+ MANIPULATOR_NEW_PRIM(man->translate_xy, "translate_xy", ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
+ MANIPULATOR_NEW_PRIM(man->translate_yz, "translate_yz", ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
+ MANIPULATOR_NEW_PRIM(man->translate_zx, "translate_zx", ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
-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();
+ return man;
}
-
-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)
+/**
+ * Custom handler for manipulator widgets
+ */
+static void manipulator_modal(
+ bContext *C, wmManipulator *widget, const wmEvent *UNUSED(event), const int UNUSED(flag))
{
- 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();
+ const ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ View3D *v3d = sa->spacedata.first;
+ RegionView3D *rv3d = ar->regiondata;
- dz = 1.0;
- }
- else {
- dz = 1.0f - 4.0f * cusize;
+ if (calc_manipulator_stats(C)) {
+ manipulator_prepare_mat(C, v3d, rv3d);
+ WM_manipulator_set_matrix_location(widget, rv3d->twmat[3]);
}
- 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);
- }
+ ED_region_tag_redraw(ar);
+}
- /* axis */
+static void WIDGETGROUP_manipulator_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup)
+{
+ ManipulatorGroup *man = manipulatorgroup_init(mgroup);
+ struct {
+ wmOperatorType *translate, *rotate, *trackball, *resize;
+ } ot_store = {NULL};
- /* 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);
+ mgroup->customdata = man;
+ /* *** set properties for axes *** */
- 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);
- }
+ MAN_ITER_AXES_BEGIN(axis, axis_idx)
+ {
+ const short axis_type = manipulator_get_axis_type(man, axis);
+ int constraint_axis[3] = {1, 0, 0};
+ PointerRNA *ptr;
+
+ manipulator_get_axis_constraint(axis_idx, constraint_axis);
+
+ /* custom handler! */
+ WM_manipulator_set_fn_custom_modal(axis, manipulator_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:
+ WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH);
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);
- }
+ case MAN_AXIS_ROT_X:
+ case MAN_AXIS_ROT_Y:
+ case MAN_AXIS_ROT_Z:
+ /* increased line width for better display */
+ WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH + 1.0f);
+ WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_VALUE, true);
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);
- }
+ 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 = 11.0f;
+ const float ofs[3] = {ofs_ax, ofs_ax, 0.0f};
+ WM_manipulator_set_scale(axis, 0.07f);
+ WM_manipulator_set_matrix_offset_location(axis, ofs);
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);
+ }
+ case MAN_AXIS_TRANS_C:
+ case MAN_AXIS_ROT_C:
+ case MAN_AXIS_SCALE_C:
+ case MAN_AXIS_ROT_T:
+ WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH);
+ if (axis_idx == MAN_AXIS_ROT_T) {
+ WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_HOVER, true);
}
- 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);
+ else if (axis_idx == MAN_AXIS_ROT_C) {
+ WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_VALUE, true);
}
- 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);
+ else {
+ WM_manipulator_set_scale(axis, 0.2f);
}
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);
+ switch (axis_type) {
+ case MAN_AXES_TRANSLATE:
+ if (ot_store.translate == NULL) {
+ ot_store.translate = WM_operatortype_find("TRANSFORM_OT_translate", true);
}
+ ptr = WM_manipulator_set_operator(axis, ot_store.translate, NULL);
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);
+ 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_manipulator_set_operator(axis, ot_rotate, NULL);
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);
+ }
+ case MAN_AXES_SCALE:
+ {
+ if (ot_store.resize == NULL) {
+ ot_store.resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
}
+ ptr = WM_manipulator_set_operator(axis, ot_store.resize, NULL);
break;
+ }
}
- }
- /* restore */
-
- gluDeleteQuadric(qobj);
- glLoadMatrixf(rv3d->viewmat);
-
- if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
+ {
+ PropertyRNA *prop;
+ 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;
}
-
-/* ********************************************* */
-
-/* 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)
+static void WIDGETGROUP_manipulator_refresh(const bContext *C, wmManipulatorGroup *mgroup)
{
+ ManipulatorGroup *man = mgroup->customdata;
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;
+ /* skip, we don't draw anything anyway */
+ if ((man->all_hidden = (calc_manipulator_stats(C) == 0)))
+ return;
- if (!(v3d->twflag & V3D_USE_MANIPULATOR)) return;
+ manipulator_prepare_mat(C, v3d, rv3d);
- if ((v3d->twtype & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE | V3D_MANIP_SCALE)) == 0) return;
+ /* *** set properties for axes *** */
+ MAN_ITER_AXES_BEGIN(axis, axis_idx)
{
- v3d->twflag &= ~V3D_DRAW_MANIPULATOR;
-
- totsel = calc_manipulator_stats(C);
- 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:
+ const short axis_type = manipulator_get_axis_type(man, axis);
+ const int aidx_norm = manipulator_index_normalize(axis_idx);
+
+ WM_manipulator_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:
{
- bGPdata *gpd = CTX_data_gpencil_data(C);
- Object *ob = OBACT;
+ float start_co[3] = {0.0f, 0.0f, 0.0f};
+ float len;
- 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], scene->twmin, scene->twmax);
- }
+ manipulator_line_range(v3d, axis_type, &start_co[2], &len);
+
+ WM_manipulator_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]);
+ RNA_float_set(axis->ptr, "length", len);
+ WM_manipulator_set_matrix_offset_location(axis, start_co);
break;
}
- case V3D_AROUND_LOCAL_ORIGINS:
- case V3D_AROUND_CENTER_MEAN:
- copy_v3_v3(rv3d->twmat[3], scene->twcent);
+ case MAN_AXIS_ROT_X:
+ case MAN_AXIS_ROT_Y:
+ case MAN_AXIS_ROT_Z:
+ WM_manipulator_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]);
break;
- case V3D_AROUND_CURSOR:
- copy_v3_v3(rv3d->twmat[3], ED_view3d_cursor3d_get(scene, v3d));
+ 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 > 2 ? 0 : aidx_norm + 1];
+ const float *z_axis = rv3d->twmat[aidx_norm - 1 < 0 ? 2 : aidx_norm - 1];
+ WM_manipulator_set_matrix_rotation_from_yz_axis(axis, y_axis, z_axis);
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);
}
+ MAN_ITER_AXES_END;
}
-static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], float hotspot)
+static void WIDGETGROUP_manipulator_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup)
{
+ ManipulatorGroup *man = mgroup->customdata;
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
View3D *v3d = sa->spacedata.first;
RegionView3D *rv3d = ar->regiondata;
- rctf rect, selrect;
- 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();
-
- /* XXX check a bit later on this... (ton) */
- extern void view3d_winmatrix_set(ARegion *ar, View3D *v3d, rctf *rect);
+ float idot[3];
/* 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;
-
- selrect = rect;
-
- view3d_winmatrix_set(ar, v3d, &rect);
- mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
-
- if (do_passes)
- GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
- else
- GPU_select_begin(buffer, 64, &selrect, 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) {
- GPU_select_begin(buffer, 64, &selrect, 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 (man->all_hidden || fabsf(ED_view3d_pixel_size(rv3d, rv3d->twmat[3])) < 1e-6f) {
+ MAN_ITER_AXES_BEGIN(axis, axis_idx)
+ {
+ WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, true);
}
- 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();
+ MAN_ITER_AXES_END;
+ return;
}
+ manipulator_get_idot(rv3d, idot);
- view3d_winmatrix_set(ar, v3d, NULL);
- mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
-
- 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];
+ /* *** set properties for axes *** */
- 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;
- }
- }
- }
+ MAN_ITER_AXES_BEGIN(axis, axis_idx)
+ {
+ const short axis_type = manipulator_get_axis_type(man, axis);
+ /* XXX maybe unset _HIDDEN flag on redraw? */
+ if (manipulator_is_axis_visible(v3d, rv3d, idot, axis_type, axis_idx)) {
+ WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, false);
+ }
+ else {
+ WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, true);
+ continue;
}
- if (minval)
- return minval;
- else
- return minvalrot;
+ float col[4], col_hi[4];
+ manipulator_get_axis_color(axis_idx, idot, col, col_hi);
+ WM_manipulator_set_color(axis, col);
+ WM_manipulator_set_color_highlight(axis, col_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_manipulator_set_matrix_rotation_from_z_axis(axis, rv3d->viewinv[2]);
+ break;
+ }
}
- return 0;
+ MAN_ITER_AXES_END;
}
-
-/* return 0; nothing happened */
-int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op)
+static bool WIDGETGROUP_manipulator_poll(const struct bContext *C, struct wmManipulatorGroupType *UNUSED(wgt))
{
- ScrArea *sa = CTX_wm_area(C);
- View3D *v3d = sa->spacedata.first;
- ARegion *ar = CTX_wm_region(C);
- int constraint_axis[3] = {0, 0, 0};
- int val;
- int shift = event->shift;
+ /* it's a given we only use this in 3D view */
+ const ScrArea *sa = CTX_wm_area(C);
+ const View3D *v3d = sa->spacedata.first;
- 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(sa, ar, event->mval, 0.5f * (float)U.tw_hotspot);
- if (val) {
+ return (((v3d->twflag & V3D_MANIPULATOR_DRAW) != 0) &&
+ ((v3d->twtype & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE | V3D_MANIP_SCALE)) != 0));
+}
- // drawflags still global, for drawing call above
- drawflags = manipulator_selectbuf(sa, ar, event->mval, 0.2f * (float)U.tw_hotspot);
- if (drawflags == 0) drawflags = val;
+void TRANSFORM_WGT_manipulator(wmManipulatorGroupType *wgt)
+{
+ wgt->name = "Transform Manipulator";
+ wgt->idname = "TRANSFORM_WGT_manipulator";
- if (drawflags & MAN_TRANS_C) {
- switch (drawflags) {
- case MAN_TRANS_C:
- break;
- case MAN_TRANS_X:
- if (shift) {
- constraint_axis[1] = 1;
- constraint_axis[2] = 1;
- }
- else
- constraint_axis[0] = 1;
- break;
- case MAN_TRANS_Y:
- if (shift) {
- constraint_axis[0] = 1;
- constraint_axis[2] = 1;
- }
- else
- constraint_axis[1] = 1;
- break;
- case MAN_TRANS_Z:
- if (shift) {
- constraint_axis[0] = 1;
- constraint_axis[1] = 1;
- }
- else
- constraint_axis[2] = 1;
- break;
- }
- RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
- WM_operator_name_call(C, "TRANSFORM_OT_translate", WM_OP_INVOKE_DEFAULT, op->ptr);
- }
- else if (drawflags & MAN_SCALE_C) {
- switch (drawflags) {
- case MAN_SCALE_X:
- if (shift) {
- constraint_axis[1] = 1;
- constraint_axis[2] = 1;
- }
- else
- constraint_axis[0] = 1;
- break;
- case MAN_SCALE_Y:
- if (shift) {
- constraint_axis[0] = 1;
- constraint_axis[2] = 1;
- }
- else
- constraint_axis[1] = 1;
- break;
- case MAN_SCALE_Z:
- if (shift) {
- constraint_axis[0] = 1;
- constraint_axis[1] = 1;
- }
- else
- constraint_axis[2] = 1;
- break;
- }
- RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
- WM_operator_name_call(C, "TRANSFORM_OT_resize", WM_OP_INVOKE_DEFAULT, op->ptr);
- }
- else if (drawflags == MAN_ROT_T) { /* trackball need special case, init is different */
- /* Do not pass op->ptr!!! trackball has no "constraint" properties!
- * See [#34621], it's a miracle it did not cause more problems!!! */
- /* However, we need to copy the "release_confirm" property, but only if defined, see T41112. */
- PointerRNA props_ptr;
- PropertyRNA *prop;
- wmOperatorType *ot = WM_operatortype_find("TRANSFORM_OT_trackball", true);
- WM_operator_properties_create_ptr(&props_ptr, ot);
- if ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) && RNA_property_is_set(op->ptr, prop)) {
- RNA_property_boolean_set(&props_ptr, prop, RNA_property_boolean_get(op->ptr, prop));
- }
- WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
- WM_operator_properties_free(&props_ptr);
- }
- 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(op->ptr, "constraint_axis", constraint_axis);
- WM_operator_name_call(C, "TRANSFORM_OT_rotate", WM_OP_INVOKE_DEFAULT, op->ptr);
- }
- }
- /* after transform, restore drawflags */
- drawflags = 0xFFFF;
+ wgt->flag |= (WM_MANIPULATORGROUPTYPE_PERSISTENT |
+ WM_MANIPULATORGROUPTYPE_3D);
- return val;
+ wgt->poll = WIDGETGROUP_manipulator_poll;
+ wgt->setup = WIDGETGROUP_manipulator_setup;
+ wgt->refresh = WIDGETGROUP_manipulator_refresh;
+ wgt->draw_prepare = WIDGETGROUP_manipulator_draw_prepare;
}
-
diff --git a/source/blender/editors/transform/transform_manipulator2d.c b/source/blender/editors/transform/transform_manipulator2d.c
new file mode 100644
index 00000000000..104675cb1a8
--- /dev/null
+++ b/source/blender/editors/transform/transform_manipulator2d.c
@@ -0,0 +1,274 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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/editors/transform/transform_manipulator2d.c
+ * \ingroup edtransform
+ *
+ * \name 2D Transform Manipulator
+ *
+ * Used for UV/Image Editor
+ */
+
+#include "BKE_context.h"
+#include "BKE_editmesh.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 "ED_image.h"
+#include "ED_screen.h"
+#include "ED_uvedit.h"
+#include "ED_manipulator_library.h"
+
+#include "MEM_guardedalloc.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 "transform.h" /* own include */
+
+/* axes as index */
+enum {
+ MAN2D_AXIS_TRANS_X = 0,
+ MAN2D_AXIS_TRANS_Y,
+
+ MAN2D_AXIS_LAST,
+};
+
+typedef struct ManipulatorGroup2D {
+ wmManipulator *translate_x,
+ *translate_y;
+
+ /* Current origin in view space, used to update widget origin for possible view changes */
+ float origin[2];
+} ManipulatorGroup2D;
+
+
+/* **************** Utilities **************** */
+
+/* loop over axes */
+#define MAN2D_ITER_AXES_BEGIN(axis, axis_idx) \
+ { \
+ wmManipulator *axis; \
+ int axis_idx; \
+ for (axis_idx = 0; axis_idx < MAN2D_AXIS_LAST; axis_idx++) { \
+ axis = manipulator2d_get_axis_from_index(man, axis_idx);
+
+#define MAN2D_ITER_AXES_END \
+ } \
+ } ((void)0)
+
+static wmManipulator *manipulator2d_get_axis_from_index(const ManipulatorGroup2D *man, 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 man->translate_x;
+ case MAN2D_AXIS_TRANS_Y:
+ return man->translate_y;
+ }
+
+ return NULL;
+}
+
+static void manipulator2d_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 ManipulatorGroup2D *manipulatorgroup2d_init(wmManipulatorGroup *mgroup)
+{
+ const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_2d", true);
+
+ ManipulatorGroup2D *man = MEM_callocN(sizeof(ManipulatorGroup2D), __func__);
+
+ man->translate_x = WM_manipulator_new_ptr(wt_arrow, mgroup, "translate_x", NULL);
+ man->translate_y = WM_manipulator_new_ptr(wt_arrow, mgroup, "translate_y", NULL);
+
+ return man;
+}
+
+/**
+ * Calculates origin in view space, use with #manipulator2d_origin_to_region.
+ */
+static void manipulator2d_calc_origin(const bContext *C, float *r_origin)
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = ED_space_image(sima);
+
+ if (sima->around == V3D_AROUND_CURSOR) {
+ copy_v2_v2(r_origin, sima->cursor);
+ }
+ else {
+ ED_uvedit_center(CTX_data_scene(C), ima, CTX_data_edit_object(C), r_origin, sima->around);
+ }
+}
+
+/**
+ * Convert origin (or any other point) from view to region space.
+ */
+BLI_INLINE void manipulator2d_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 manipulator widgets
+ */
+static void manipulator2d_modal(
+ bContext *C, wmManipulator *widget, const wmEvent *UNUSED(event), const int UNUSED(flag))
+{
+ ARegion *ar = CTX_wm_region(C);
+ float origin[3];
+
+ manipulator2d_calc_origin(C, origin);
+ manipulator2d_origin_to_region(ar, origin);
+ WM_manipulator_set_matrix_location(widget, origin);
+
+ ED_region_tag_redraw(ar);
+}
+
+void ED_widgetgroup_manipulator2d_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup)
+{
+ wmOperatorType *ot_translate = WM_operatortype_find("TRANSFORM_OT_translate", true);
+ ManipulatorGroup2D *man = manipulatorgroup2d_init(mgroup);
+ mgroup->customdata = man;
+
+ MAN2D_ITER_AXES_BEGIN(axis, axis_idx)
+ {
+ const float offset[3] = {0.0f, 0.2f};
+
+ float col[4], col_hi[4];
+ manipulator2d_get_axis_color(axis_idx, col, col_hi);
+
+ /* custom handler! */
+ WM_manipulator_set_fn_custom_modal(axis, manipulator2d_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_manipulator_set_matrix_offset_location(axis, offset);
+ WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH);
+ WM_manipulator_set_scale(axis, U.manipulator_size);
+ WM_manipulator_set_color(axis, col);
+ WM_manipulator_set_color_highlight(axis, col_hi);
+
+ /* assign operator */
+ PointerRNA *ptr = WM_manipulator_set_operator(axis, ot_translate, NULL);
+ int constraint[3] = {0.0f};
+ 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;
+}
+
+void ED_widgetgroup_manipulator2d_refresh(const bContext *C, wmManipulatorGroup *mgroup)
+{
+ ManipulatorGroup2D *man = mgroup->customdata;
+ float origin[3];
+
+ manipulator2d_calc_origin(C, origin);
+ copy_v2_v2(man->origin, origin);
+}
+
+void ED_widgetgroup_manipulator2d_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup)
+{
+ ManipulatorGroup2D *man = mgroup->customdata;
+ float origin[3] = {UNPACK2(man->origin), 0.0f};
+
+ manipulator2d_origin_to_region(CTX_wm_region(C), origin);
+
+ MAN2D_ITER_AXES_BEGIN(axis, axis_idx)
+ {
+ WM_manipulator_set_matrix_location(axis, origin);
+ }
+ MAN2D_ITER_AXES_END;
+}
+
+/* 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_manipulator2d_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt))
+{
+ 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, 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_ops.c b/source/blender/editors/transform/transform_ops.c
index 6e399d9fde3..dba442259d1 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -160,11 +160,12 @@ EnumPropertyItem rna_enum_transform_mode_types[] =
static int select_orientation_exec(bContext *C, wmOperator *op)
{
+ View3D *v3d = CTX_wm_view3d(C);
int orientation = RNA_enum_get(op->ptr, "orientation");
- BIF_selectTransformOrientationValue(C, orientation);
+ BIF_selectTransformOrientationValue(v3d, orientation);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C));
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
return OPERATOR_FINISHED;
}
@@ -206,10 +207,9 @@ 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);
-
+ BIF_removeTransformOrientationIndex(C, v3d->custom_orientation_index);
+
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
WM_event_add_notifier(C, NC_SCENE | NA_EDITED, CTX_data_scene(C));
@@ -223,18 +223,12 @@ static int delete_orientation_invoke(bContext *C, wmOperator *op, const wmEvent
static int delete_orientation_poll(bContext *C)
{
- int selected_index = -1;
View3D *v3d = CTX_wm_view3d(C);
-
+
if (ED_operator_areaactive(C) == 0)
return 0;
-
-
- if (v3d) {
- selected_index = (v3d->twmode - V3D_MANIP_CUSTOM);
- }
-
- return selected_index >= 0;
+
+ return (v3d->twmode >= V3D_MANIP_CUSTOM) && (v3d->custom_orientation_index != -1);
}
static void TRANSFORM_OT_delete_orientation(struct wmOperatorType *ot)
@@ -386,7 +380,7 @@ static int transform_modal(bContext *C, wmOperator *op, const wmEvent *event)
TransInfo *t = op->customdata;
const enum TfmMode mode_prev = t->mode;
-#if 0
+#if defined(WITH_INPUT_NDOF) && 0
// stable 2D mouse coords map to different 3D coords while the 3D mouse is active
// in other words, 2D deltas are no longer good enough!
// disable until individual 'transformers' behave better
@@ -569,6 +563,9 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
// Add confirm method all the time. At the end because it's not really that important and should be hidden only in log, not in keymap edit
/*prop =*/ RNA_def_boolean(ot->srna, "release_confirm", 0, "Confirm on Release", "Always confirm operation when releasing button");
//RNA_def_property_flag(prop, PROP_HIDDEN);
+
+ prop = RNA_def_boolean(ot->srna, "use_accurate", 0, "Accurate", "Use accurate transformation");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
}
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 7ac2daa5fa7..8db1c619b25 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -38,11 +38,12 @@
#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"
#include "BLI_string.h"
-#include "BLI_path_util.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BKE_action.h"
@@ -52,6 +53,7 @@
#include "BKE_report.h"
#include "BKE_main.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "BLT_translation.h"
@@ -63,14 +65,16 @@
void BIF_clearTransformOrientation(bContext *C)
{
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ ListBase *transform_orientations = BKE_workspace_transform_orientations_get(workspace);
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 && v3d->twmode == V3D_MANIP_CUSTOM) {
+ v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global */
+ v3d->custom_orientation_index = -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;
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ ListBase *transform_orientations = BKE_workspace_transform_orientations_get(workspace);
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,55 @@ 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_workspace_transform_orientation_remove(CTX_wm_workspace(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_workspace_transform_orientation_find(CTX_wm_workspace(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);
+ int index = BKE_workspace_transform_orientation_get_index(CTX_wm_workspace(C), target);
+ View3D *v3d = CTX_wm_view3d(C);
- if (i != -1) {
- View3D *v3d = CTX_wm_view3d(C);
- v3d->twmode = V3D_MANIP_CUSTOM + i;
- }
+ BLI_assert(index != -1);
+
+ v3d->twmode = V3D_MANIP_CUSTOM;
+ v3d->custom_orientation_index = 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(View3D *v3d, 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;
+
+ v3d->twmode = is_custom ? V3D_MANIP_CUSTOM : orientation;
+ v3d->custom_orientation_index = 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);
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ ListBase *transform_orientations = BKE_workspace_transform_orientations_get(workspace);
+ 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)
@@ -451,18 +441,18 @@ void initTransformOrientation(bContext *C, TransInfo *t)
case V3D_MANIP_GIMBAL:
unit_m3(t->spacemtx);
- if (gimbal_axis(ob, t->spacemtx)) {
+ if (ob && gimbal_axis(ob, t->spacemtx)) {
BLI_strncpy(t->spacename, IFACE_("gimbal"), sizeof(t->spacename));
break;
}
- /* fall-through */ /* no gimbal fallthrough to normal */
+ ATTR_FALLTHROUGH; /* no gimbal fallthrough to normal */
case V3D_MANIP_NORMAL:
if (obedit || (ob && ob->mode & OB_MODE_POSE)) {
BLI_strncpy(t->spacename, IFACE_("normal"), sizeof(t->spacename));
ED_getTransformOrientationMatrix(C, t->spacemtx, t->around);
break;
}
- /* fall-through */ /* we define 'normal' as 'local' in Object mode */
+ ATTR_FALLTHROUGH; /* we define 'normal' as 'local' in Object mode */
case V3D_MANIP_LOCAL:
BLI_strncpy(t->spacename, IFACE_("local"), sizeof(t->spacename));
@@ -492,8 +482,10 @@ 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_CUSTOM:
+ BLI_strncpy(t->spacename, t->custom_orientation->name, sizeof(t->spacename));
+
+ if (applyTransformOrientation(t->custom_orientation, t->spacemtx, t->spacename)) {
/* pass */
}
else {
@@ -586,10 +578,10 @@ 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);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *obedit = CTX_data_edit_object(C);
Base *base;
- Object *ob = OBACT;
+ Object *ob = OBACT_NEW;
int result = ORIENTATION_NONE;
const bool activeOnly = (around == V3D_AROUND_ACTIVE);
@@ -817,15 +809,21 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
Curve *cu = obedit->data;
Nurb *nu = NULL;
- BezTriple *bezt = NULL;
int a;
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- if (activeOnly && BKE_curve_nurb_vert_active_get(cu, &nu, (void *)&bezt)) {
+ void *vert_act = NULL;
+ if (activeOnly && BKE_curve_nurb_vert_active_get(cu, &nu, &vert_act)) {
if (nu->type == CU_BEZIER) {
+ BezTriple *bezt = vert_act;
BKE_nurb_bezt_calc_normal(nu, bezt, normal);
BKE_nurb_bezt_calc_plane(nu, bezt, plane);
}
+ else {
+ BPoint *bp = vert_act;
+ BKE_nurb_bpoint_calc_normal(nu, bp, normal);
+ BKE_nurb_bpoint_calc_plane(nu, bp, plane);
+ }
}
else {
const bool use_handle = (cu->drawflag & CU_HIDE_HANDLES) == 0;
@@ -833,7 +831,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
for (nu = nurbs->first; nu; nu = nu->next) {
/* only bezier has a normal */
if (nu->type == CU_BEZIER) {
- bezt = nu->bezt;
+ BezTriple *bezt = nu->bezt;
a = nu->pntsu;
while (a--) {
short flag = 0;
@@ -885,6 +883,36 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
bezt++;
}
}
+ else if (nu->bp && (nu->pntsv == 1)) {
+ BPoint *bp = nu->bp;
+ a = nu->pntsu;
+ while (a--) {
+ if (bp->f1 & SELECT) {
+ float tvec[3];
+
+ BPoint *bp_prev = BKE_nurb_bpoint_get_prev(nu, bp);
+ BPoint *bp_next = BKE_nurb_bpoint_get_next(nu, bp);
+
+ const bool is_prev_sel = bp_prev && (bp_prev->f1 & SELECT);
+ const bool is_next_sel = bp_next && (bp_next->f1 & SELECT);
+ if (is_prev_sel == false && is_next_sel == false) {
+ /* Isolated, add based on surrounding */
+ BKE_nurb_bpoint_calc_normal(nu, bp, tvec);
+ add_v3_v3(normal, tvec);
+ }
+ else if (is_next_sel) {
+ /* A segment, add the edge normal */
+ sub_v3_v3v3(tvec, bp->vec, bp_next->vec );
+ normalize_v3(tvec);
+ add_v3_v3(normal, tvec);
+ }
+
+ BKE_nurb_bpoint_calc_plane(nu, bp, tvec);
+ add_v3_v3(plane, tvec);
+ }
+ bp++;
+ }
+ }
}
}
@@ -1016,16 +1044,16 @@ 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_NEW;
+ ob = OBACT_NEW;
+ if (base && ((base->flag & BASE_SELECTED) != 0)) {
/* pass */
}
else {
/* first selected */
ob = NULL;
- for (base = scene->base.first; base; base = base->next) {
- if (TESTBASELIB(v3d, base)) {
+ for (base = sl->object_bases.first; base; base = base->next) {
+ if (TESTBASELIB_NEW(base)) {
ob = base->object;
break;
}
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index f8bb124e943..1181f584313 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -49,7 +49,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BIF_gl.h"
+#include "GPU_immediate.h"
#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
@@ -78,7 +78,7 @@
#include "transform.h"
/* this should be passed as an arg for use in snap functions */
-#undef BASACT
+#undef BASACT_NEW
/* use half of flt-max so we can scale up without an exception */
@@ -163,36 +163,42 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
invert_m4_m4(imat, rv3d->viewmat);
-
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_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);
+ immUniformColor4ubv(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();
+ immBegin(GWN_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();
}
-
+
+ immUnbindProgram();
+
if (v3d->zbuf)
glEnable(GL_DEPTH_TEST);
}
@@ -200,35 +206,7 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
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) {
@@ -241,23 +219,29 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
glEnable(GL_BLEND);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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);
}
-
+
+ immUnbindProgram();
+
glDisable(GL_BLEND);
}
}
@@ -519,8 +503,8 @@ static void initSnappingMode(TransInfo *t)
{
ToolSettings *ts = t->settings;
Object *obedit = t->obedit;
- Scene *scene = t->scene;
- Base *base_act = scene->basact;
+ SceneLayer *sl = t->scene_layer;
+ Base *base_act = sl->basact;
if (t->spacetype == SPACE_NODE) {
/* force project off when not supported */
@@ -569,7 +553,9 @@ static void initSnappingMode(TransInfo *t)
else if (t->tsnap.applySnap != NULL && // A snapping function actually exist
(obedit == NULL) ) // Object Mode
{
- t->tsnap.modeSelect = SNAP_NOT_SELECTED;
+ /* 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;
}
else {
/* Grid if snap is not possible */
@@ -599,7 +585,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(
- G.main, t->scene, SNAP_OBJECT_USE_CACHE,
+ G.main, t->scene, t->scene_layer, 0,
t->ar, t->view);
ED_transform_snap_object_context_set_editmesh_callbacks(
@@ -1214,7 +1200,7 @@ bool snapObjectsTransform(
t->tsnap.object_context,
t->scene->toolsettings->snap_mode,
&(const struct SnapObjectParams){
- .snap_select = ((t->options & CTX_GPENCIL_STROKES) != 0) ? SNAP_NOT_ACTIVE : t->tsnap.modeSelect,
+ .snap_select = t->tsnap.modeSelect,
.use_object_edit_cage = (t->flag & T_EDIT) != 0,
},
mval, dist_px, NULL,
@@ -1304,7 +1290,7 @@ bool peelObjectsTransform(
t->tsnap.object_context,
mval,
&(const struct SnapObjectParams){
- .snap_select = ((t->options & CTX_GPENCIL_STROKES) != 0) ? SNAP_NOT_ACTIVE : t->tsnap.modeSelect,
+ .snap_select = t->tsnap.modeSelect,
.use_object_edit_cage = (t->flag & T_EDIT) != 0,
},
use_peel_object,
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 1d4872cca7a..bdefd169f22 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -59,6 +59,24 @@
#include "transform.h"
+enum eViewProj {
+ VIEW_PROJ_NONE = -1,
+ VIEW_PROJ_ORTHO = 0,
+ VIEW_PROJ_PERSP = -1,
+};
+
+typedef struct SnapData {
+ short snap_to;
+ 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 */
+ enum eViewProj view_proj;
+ float depth_range[2];
+} SnapData;
+
typedef struct SnapObjectData {
enum {
SNAP_MESH = 1,
@@ -69,6 +87,8 @@ typedef struct SnapObjectData {
typedef struct SnapObjectData_Mesh {
SnapObjectData sd;
BVHTreeFromMesh *bvh_trees[3];
+ MPoly *mpoly;
+ bool poly_allocated;
} SnapObjectData_Mesh;
@@ -81,6 +101,7 @@ typedef struct SnapObjectData_EditMesh {
struct SnapObjectContext {
Main *bmain;
Scene *scene;
+ SceneLayer *scene_layer;
int flag;
/* Optional: when performing screen-space projection.
@@ -110,24 +131,149 @@ struct SnapObjectContext {
};
-enum eViewProj {
- VIEW_PROJ_NONE = -1,
- VIEW_PROJ_ORTHO = 0,
- VIEW_PROJ_PERSP = -1,
-};
-
-static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt);
+/** \} */
/* -------------------------------------------------------------------- */
-/** \name Support for storing all depths, not just the first (raycast 'all')
+/** Common utilities
+* \{ */
+
+
+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.
*
- * This uses a list of #SnapObjectHitDepth structs.
+ * \param sctx: Snap context to store data.
+ * \param snap_select : from enum SnapSelect.
+ * \param obedit : Object Edited to use its coordinates of BMesh(if any) to do the snapping.
+ */
+static void iter_snap_objects(
+ SnapObjectContext *sctx,
+ const SnapSelect snap_select,
+ Object *obedit,
+ IterSnapObjsCallback sob_callback,
+ void *data)
+{
+ Base *base_act = sctx->scene_layer->basact;
+ /* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA
+ * which makes the loop skip it, even the derived mesh will never change
+ *
+ * To solve that problem, we do it first as an exception.
+ * */
+ if (base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT) {
+ sob_callback(sctx, false, base_act->object, base_act->object->obmat, data);
+ }
+
+ for (Base *base = sctx->scene_layer->object_bases.first; base != NULL; base = base->next) {
+ if ((BASE_VISIBLE_NEW(base)) && (base->flag_legacy & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 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) {
+ DupliObject *dupli_ob;
+ ListBase *lb = object_duplilist(sctx->bmain->eval_ctx, sctx->scene, obj);
+ 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);
+ }
+ free_object_duplilist(lb);
+ }
+
+ use_obedit = obedit && obj->data == obedit->data;
+ sob_callback(sctx, use_obedit, use_obedit ? obedit : obj, obj->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);
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Ray Cast Funcs
+* \{ */
+
+/* Store all ray-hits
+ * Support for storing all depths, not just the first (raycast 'all') */
-/* Store all ray-hits */
struct RayCastAll_Data {
void *bvhdata;
@@ -148,6 +294,7 @@ struct RayCastAll_Data {
bool retval;
};
+
static struct SnapObjectHitDepth *hit_depth_create(
const float depth, const float co[3], const float no[3], int index,
Object *ob, const float obmat[4][4], unsigned int ob_uuid)
@@ -215,208 +362,565 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH
}
}
-/** \} */
+static bool raycastDerivedMesh(
+ SnapObjectContext *sctx,
+ const float ray_orig[3], const float ray_start[3], const float ray_dir[3], const float depth_range[2],
+ Object *ob, DerivedMesh *dm, float obmat[4][4], const unsigned int ob_index,
+ /* read/write args */
+ float *ray_depth,
+ /* return args */
+ float r_loc[3], float r_no[3], int *r_index,
+ ListBase *r_hit_list)
+{
+ bool retval = false;
+
+ if (dm->getNumPolys(dm) == 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;
-/** \Common utilities
- * \{ */
+ 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);
-/**
- * Struct that kepts basic information about a BVHTree build from a editmesh.
- */
-typedef struct BVHTreeFromMeshType {
- void *userdata;
- char type;
-} BVHTreeFromMeshType;
+ mul_m4_v3(imat, ray_start_local);
+ mul_mat3_m4_v3(imat, ray_normal_local);
-typedef struct PreDefProject {
- float pmat[4][4]; /* perspective matrix multiplied by object matrix */
- float win_half[2];
- float dist_px_sq;
-} PreDefProject;
+ /* 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;
+ }
-static void precalc_project(
- PreDefProject *projectdefs, const ARegion *ar,
- const float dist_px, float obmat[4][4])
-{
- float (*pmat)[4] = ((RegionView3D *)ar->regiondata)->persmat;
- if (obmat) {
- mul_m4_m4m4(projectdefs->pmat, pmat, obmat);
+ /* Test BoundBox */
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+ if (bb) {
+ /* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
+ if (!isect_ray_aabb_v3_simple(
+ ray_start_local, ray_normal_local, bb->vec[0], bb->vec[6], &len_diff, NULL))
+ {
+ 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;
}
else {
- copy_m4_m4(projectdefs->pmat, pmat);
+ sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
+ sod->sd.type = SNAP_MESH;
}
- projectdefs->win_half[0] = ar->winx / 2;
- projectdefs->win_half[1] = ar->winy / 2;
- projectdefs->dist_px_sq = SQUARE(dist_px);
-}
-/**
- * From a threshold (maximum distance to snap in pixels) returns:
- *
- * - The *real* distance (3D) if you are in orthographic-view.
- * - The *tangent* (view cone radius at distance 1.0) if you are in perspective-view.
- */
-static float dist_px_to_dist3d_or_tangent(const ARegion *ar, const float dist_px)
-{
- const RegionView3D *rv3d = ar->regiondata;
- if (ar->winx >= ar->winy)
- return 2 * (dist_px / ar->winx) / rv3d->winmat[0][0];
- else
- return 2 * (dist_px / ar->winy) / rv3d->winmat[1][1];
-}
+ if (sod->bvh_trees[2] == NULL) {
+ sod->bvh_trees[2] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata));
+ }
-static const float *get_vert_co(const BVHTreeFromMeshType *meshdata, const int index)
-{
- switch (meshdata->type) {
- case SNAP_MESH:
- {
- BVHTreeFromMesh *data = meshdata->userdata;
- const MVert *vert = data->vert;
- return vert[index].co;
+ treedata = sod->bvh_trees[2];
+
+ 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);
+ }
+ else {
+ if (!treedata->vert_allocated) {
+ treedata->vert = DM_get_vert_array(dm, &treedata->vert_allocated);
+ }
+ if (!treedata->loop_allocated) {
+ treedata->loop = DM_get_loop_array(dm, &treedata->loop_allocated);
+ }
+ if (!treedata->looptri_allocated) {
+ if (!sod->poly_allocated) {
+ sod->mpoly = DM_get_poly_array(dm, &sod->poly_allocated);
+ }
+ treedata->looptri = DM_get_looptri_array(
+ dm, treedata->vert,
+ sod->mpoly, dm->getNumPolys(dm),
+ treedata->loop, dm->getNumLoops(dm),
+ &treedata->looptri_allocated);
+ }
+ }
}
- case SNAP_EDIT_MESH:
- {
- BVHTreeFromEditMesh *data = meshdata->userdata;
- BMVert *eve = BM_vert_at_index(data->em->bm, index);
- return eve->co;
+
+ if (treedata->tree == NULL) {
+ bvhtree_from_mesh_looptri(treedata, dm, 0.0f, 4, 6);
+
+ if (treedata->tree == NULL) {
+ return retval;
+ }
}
}
- return NULL;
-}
+ else {
+ return retval;
+ }
-static void copy_vert_no(const BVHTreeFromMeshType *meshdata, const int index, float r_no[3])
-{
- switch (meshdata->type) {
- case SNAP_MESH:
+ /* 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))
{
- BVHTreeFromMesh *data = meshdata->userdata;
- const MVert *vert = data->vert;
- normal_short_to_float_v3(r_no, vert->no);
- break;
+ return retval;
}
- case SNAP_EDIT_MESH:
+ }
+ /* 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) {
+ float ray_org_local[3];
+
+ copy_v3_v3(ray_org_local, ray_orig);
+ mul_m4_v3(imat, ray_org_local);
+
+ /* 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_v3v3fl(
+ ray_start_local, ray_org_local, ray_normal_local,
+ len_diff + depth_range[0] * local_scale);
+ local_depth -= len_diff;
+ }
+ else {
+ len_diff = 0.0f;
+ }
+ if (r_hit_list) {
+ struct RayCastAll_Data data;
+
+ data.bvhdata = treedata;
+ data.raycast_callback = treedata->raycast_callback;
+ data.obmat = obmat;
+ data.timat = timat;
+ data.len_diff = len_diff;
+ data.local_scale = local_scale;
+ data.ob = ob;
+ data.ob_uuid = ob_index;
+ data.hit_list = r_hit_list;
+ data.retval = retval;
+
+ BLI_bvhtree_ray_cast_all(
+ treedata->tree, ray_start_local, ray_normal_local, 0.0f,
+ *ray_depth, raycast_all_cb, &data);
+
+ retval = data.retval;
+ }
+ else {
+ BVHTreeRayHit hit = {.index = -1, .dist = local_depth};
+
+ if (BLI_bvhtree_ray_cast(
+ treedata->tree, ray_start_local, ray_normal_local, 0.0f,
+ &hit, treedata->raycast_callback, treedata) != -1)
{
- BVHTreeFromEditMesh *data = meshdata->userdata;
- BMVert *eve = BM_vert_at_index(data->em->bm, index);
- copy_v3_v3(r_no, eve->no);
- break;
+ hit.dist += len_diff;
+ hit.dist /= local_scale;
+ if (hit.dist <= *ray_depth) {
+ *ray_depth = hit.dist;
+ copy_v3_v3(r_loc, hit.co);
+
+ /* back to worldspace */
+ mul_m4_v3(obmat, r_loc);
+
+ if (r_no) {
+ copy_v3_v3(r_no, hit.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+ }
+
+ retval = true;
+
+ if (r_index) {
+ *r_index = dm_looptri_to_poly_index(dm, &treedata->looptri[hit.index]);
+ }
+ }
}
}
+
+ return retval;
}
-static void get_edge_verts(
- const BVHTreeFromMeshType *meshdata, const int index,
- const float *v_pair[2])
+static bool raycastEditMesh(
+ SnapObjectContext *sctx,
+ const float ray_orig[3], const float ray_start[3], const float ray_dir[3], const float depth_range[2],
+ Object *ob, BMEditMesh *em, float obmat[4][4], const unsigned int ob_index,
+ /* read/write args */
+ float *ray_depth,
+ /* return args */
+ float r_loc[3], float r_no[3], int *r_index,
+ ListBase *r_hit_list)
{
- switch (meshdata->type) {
- case SNAP_MESH:
+ bool retval = false;
+ if (em->bm->totface == 0) {
+ return retval;
+ }
+
+ SnapObjectData_EditMesh *sod = NULL;
+
+ BVHTreeFromEditMesh *treedata;
+
+ 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;
+ }
+
+ if (sod->bvh_trees[2] == NULL) {
+ sod->bvh_trees[2] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata));
+ }
+ 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);
+
+ if (elem_mask) {
+ MEM_freeN(elem_mask);
+ }
+ }
+ if (treedata->tree == NULL) {
+ return retval;
+ }
+ }
+ 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;
+
+ 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);
+
+ copy_v3_v3(ray_start_local, ray_start);
+ mul_m4_v3(imat, ray_start_local);
+
+ /* 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;
+ }
+
+ /* 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))
{
- BVHTreeFromMesh *data = meshdata->userdata;
+ 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) {
+ float ray_org_local[3];
- const MVert *vert = data->vert;
- const MEdge *edge = data->edge + index;
+ copy_v3_v3(ray_org_local, ray_orig);
+ mul_m4_v3(imat, ray_org_local);
- v_pair[0] = vert[edge->v1].co;
- v_pair[1] = vert[edge->v2].co;
- break;
+ /* 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_v3v3fl(
+ ray_start_local, ray_org_local, ray_normal_local,
+ len_diff + depth_range[0] * local_scale);
+ local_depth -= len_diff;
}
- case SNAP_EDIT_MESH:
+ else len_diff = 0.0f;
+ }
+ if (r_hit_list) {
+ struct RayCastAll_Data data;
+
+ data.bvhdata = treedata;
+ data.raycast_callback = treedata->raycast_callback;
+ data.obmat = obmat;
+ data.timat = timat;
+ data.len_diff = len_diff;
+ data.local_scale = local_scale;
+ data.ob = ob;
+ data.ob_uuid = ob_index;
+ data.hit_list = r_hit_list;
+ data.retval = retval;
+
+ BLI_bvhtree_ray_cast_all(
+ treedata->tree, ray_start_local, ray_normal_local, 0.0f,
+ *ray_depth, raycast_all_cb, &data);
+
+ retval = data.retval;
+ }
+ else {
+ BVHTreeRayHit hit = {.index = -1, .dist = local_depth};
+
+ if (BLI_bvhtree_ray_cast(
+ treedata->tree, ray_start_local, ray_normal_local, 0.0f,
+ &hit, treedata->raycast_callback, treedata) != -1)
{
- BVHTreeFromEditMesh *data = meshdata->userdata;
- BMEdge *eed = BM_edge_at_index(data->em->bm, index);
+ hit.dist += len_diff;
+ hit.dist /= local_scale;
+ if (hit.dist <= *ray_depth) {
+ *ray_depth = hit.dist;
+ copy_v3_v3(r_loc, hit.co);
+
+ /* back to worldspace */
+ mul_m4_v3(obmat, r_loc);
+
+ if (r_no) {
+ copy_v3_v3(r_no, hit.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+ }
- v_pair[0] = eed->v1->co;
- v_pair[1] = eed->v2->co;
- break;
+ retval = true;
+
+ if (r_index) {
+ *r_index = hit.index;
+ }
+ }
}
}
+
+ return retval;
}
-#define V3_MUL_ELEM(a, b) \
- (a)[0] * (b)[0], \
- (a)[1] * (b)[1], \
- (a)[2] * (b)[2]
-static bool test_vert_dist(
- const float vco[3], const float ray_co[3], const float ray_dir[3],
- const float ray_depth_range[2], const float scale[3],
+/**
+ * \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping;
+ *
+ * \note Duplicate args here are documented at #snapObjectsRay
+ */
+static bool raycastObj(
+ SnapObjectContext *sctx,
+ const float ray_orig[3], const float ray_start[3], const float ray_dir[3], const float depth_range[2],
+ Object *ob, float obmat[4][4], const unsigned int ob_index,
+ bool use_obedit,
/* read/write args */
- float *ray_depth, float *dist_to_ray_sq,
+ float *ray_depth,
/* return args */
- float r_co[3])
+ float r_loc[3], float r_no[3], int *r_index,
+ Object **r_ob, float r_obmat[4][4],
+ ListBase *r_hit_list)
{
- const float vco_sc[3] = {V3_MUL_ELEM(vco, scale)};
- const float origin_sc[3] = {V3_MUL_ELEM(ray_co, scale)};
- const float dir_sc[3] = {V3_MUL_ELEM(ray_dir, scale)};
+ bool retval = false;
- float depth, dist_sq;
- dist_sq = dist_squared_to_ray_v3(origin_sc, dir_sc, vco_sc, &depth);
+ if (ob->type == OB_MESH) {
+ BMEditMesh *em;
- if (depth < ray_depth_range[0]) {
- return false;
+ if (use_obedit) {
+ em = BKE_editmesh_from_object(ob);
+ retval = raycastEditMesh(
+ sctx,
+ ray_orig, ray_start, ray_dir, depth_range,
+ ob, em, obmat, ob_index,
+ ray_depth, r_loc, r_no, r_index, r_hit_list);
+ }
+ 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);
+ }
+ retval = raycastDerivedMesh(
+ sctx,
+ ray_orig, ray_start, ray_dir, depth_range,
+ ob, dm, obmat, ob_index,
+ ray_depth, r_loc, r_no, r_index, r_hit_list);
+
+ dm->release(dm);
+ }
+ }
+
+ if (retval) {
+ if (r_ob) {
+ *r_ob = ob;
+ copy_m4_m4(r_obmat, obmat);
+ }
}
- if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) {
- *dist_to_ray_sq = dist_sq;
+ return retval;
+}
- copy_v3_v3(r_co, vco);
- *ray_depth = depth;
- return true;
- }
- return false;
+struct RaycastObjUserData {
+ const float *ray_orig;
+ const float *ray_start;
+ const float *ray_dir;
+ const float *depth_range;
+ unsigned int ob_index;
+ /* read/write args */
+ float *ray_depth;
+ /* return args */
+ float *r_loc;
+ float *r_no;
+ int *r_index;
+ Object **r_ob;
+ float (*r_obmat)[4];
+ ListBase *r_hit_list;
+ bool ret;
+};
+
+static void raycast_obj_cb(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data)
+{
+ struct RaycastObjUserData *dt = data;
+ dt->ret |= raycastObj(
+ sctx,
+ dt->ray_orig, dt->ray_start, dt->ray_dir, dt->depth_range,
+ ob, obmat, dt->ob_index++, is_obedit,
+ dt->ray_depth,
+ dt->r_loc, dt->r_no, dt->r_index,
+ dt->r_ob, dt->r_obmat,
+ dt->r_hit_list);
}
-static bool test_edge_dist(
- const float v1[3], const float v2[3], const float ray_co[3], const float ray_dir[3],
- const float ray_depth_range[2], const float scale[3],
+/**
+ * Main RayCast Function
+ * ======================
+ *
+ * Walks through all objects in the scene to find the `hit` on object surface.
+ *
+ * \param sctx: Snap context to store data.
+ * \param snapdata: struct generated in `set_snapdata`.
+ * \param snap_select : from enum SnapSelect.
+ * \param use_object_edit_cage : Uses the coordinates of BMesh(if any) to do the snapping.
+ * \param obj_list: List with objects to snap (created in `create_object_list`).
+ *
+ * Read/Write Args
+ * ---------------
+ *
+ * \param ray_depth: maximum depth allowed for r_co, elements deeper than this value will be ignored.
+ *
+ * Output Args
+ * -----------
+ *
+ * \param r_loc: Hit location.
+ * \param r_no: Hit normal (optional).
+ * \param r_index: Hit index or -1 when no valid index is found.
+ * (currently only set to the polygon index when when using ``snap_to == SCE_SNAP_MODE_FACE``).
+ * \param r_ob: Hit object.
+ * \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances).
+ * \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
+ *
+ */
+static bool raycastObjects(
+ SnapObjectContext *sctx,
+ const float ray_orig[3], const float ray_start[3], const float ray_dir[3], const float depth_range[2],
+ const SnapSelect snap_select, const bool use_object_edit_cage,
/* read/write args */
- float *ray_depth, float *dist_to_ray_sq,
+ float *ray_depth,
/* return args */
- float r_co[3])
+ float r_loc[3], float r_no[3], int *r_index,
+ Object **r_ob, float r_obmat[4][4],
+ ListBase *r_hit_list)
{
- const float v1_sc[3] = {V3_MUL_ELEM(v1, scale)};
- const float v2_sc[3] = {V3_MUL_ELEM(v2, scale)};
- const float co_sc[3] = {V3_MUL_ELEM(ray_co, scale)};
- const float dir_sc[3] = {V3_MUL_ELEM(ray_dir, scale)};
+ Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL;
- float tmp_co[3], depth, dist_sq;
- dist_sq = dist_squared_ray_to_seg_v3(co_sc, dir_sc, v1_sc, v2_sc, tmp_co, &depth);
+ struct RaycastObjUserData data = {
+ .ray_orig = ray_orig,
+ .ray_start = ray_start,
+ .ray_dir = ray_dir,
+ .depth_range = depth_range,
+ .ob_index = 0,
+ .ray_depth = ray_depth,
+ .r_loc = r_loc,
+ .r_no = r_no,
+ .r_index = r_index,
+ .r_ob = r_ob,
+ .r_obmat = r_obmat,
+ .r_hit_list = r_hit_list,
+ .ret = false,
+ };
- if (depth < ray_depth_range[0]) {
- return false;
- }
+ iter_snap_objects(sctx, snap_select, obedit, raycast_obj_cb, &data);
- if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) {
- *dist_to_ray_sq = dist_sq;
+ return data.ret;
+}
- tmp_co[0] /= scale[0];
- tmp_co[1] /= scale[1];
- tmp_co[2] /= scale[2];
- copy_v3_v3(r_co, tmp_co);
+/** \} */
- *ray_depth = depth;
- return true;
- }
- return false;
+
+/* -------------------------------------------------------------------- */
+
+/** Snap Nearest utilities
+ * \{ */
+
+static void copy_dm_vert_no(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);
}
-#undef V3_MUL_ELEM
+static void copy_bvert_no(const int index, float r_no[3], const BVHTreeFromEditMesh *data)
+{
+ BMVert *eve = BM_vert_at_index(data->em->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)
+{
+ const MVert *vert = data->vert;
+ const MEdge *edge = data->edge + index;
+
+ 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)
+{
+ BMEdge *eed = BM_edge_at_index(data->em->bm, index);
+
+ v_pair[0] = eed->v1->co;
+ v_pair[1] = eed->v2->co;
+}
static bool test_projected_vert_dist(
- PreDefProject *projectdefs,
- const float co[3], const enum eViewProj view_proj,
- const float mval[2], const float depth_range[2],
- float r_co[3])
+ 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,
+ float *dist_px_sq, float r_co[3])
{
float depth;
- float(*pmat)[4] = projectdefs->pmat;
- if (view_proj == VIEW_PROJ_PERSP) {
+ if (is_persp) {
depth = mul_project_m4_v3_zfac(pmat, co);
if (depth < depth_range[0] || depth > depth_range[1]) {
return false;
@@ -428,109 +932,106 @@ static bool test_projected_vert_dist(
(dot_m4_v3_row_y(pmat, co) + pmat[3][1]),
};
- if (view_proj == VIEW_PROJ_PERSP) {
+ if (is_persp) {
mul_v2_fl(co2d, 1 / depth);
}
co2d[0] += 1.0f;
co2d[1] += 1.0f;
- co2d[0] *= projectdefs->win_half[0];
- co2d[1] *= projectdefs->win_half[1];
+ co2d[0] *= win_half[0];
+ co2d[1] *= win_half[1];
const float dist_sq = len_squared_v2v2(mval, co2d);
- if (dist_sq < projectdefs->dist_px_sq) {
+ if (dist_sq < *dist_px_sq) {
copy_v3_v3(r_co, co);
- projectdefs->dist_px_sq = dist_sq;
+ *dist_px_sq = dist_sq;
return true;
}
return false;
}
static bool test_projected_edge_dist(
- PreDefProject *projectdefs,
- const float va[3], const float vb[3], const float ray_start[3], const float ray_normal[3],
- const enum eViewProj view_proj, const float mval[2], const float depth_range[2],
- float r_co[3])
+ 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],
+ float *dist_px_sq, float r_co[3])
{
float tmp_co[3], depth;
- dist_squared_ray_to_seg_v3(ray_start, ray_normal, va, vb, tmp_co, &depth);
- return test_projected_vert_dist(projectdefs, tmp_co, view_proj, mval, depth_range, r_co);
+ 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);
}
-
-/** \} */
-
-
-/* -------------------------------------------------------------------- */
-
-/** \Walk DFS
- * \{ */
-typedef struct Object_Nearest2dPrecalc {
+typedef struct Nearest2dPrecalc {
float ray_origin_local[3];
float ray_direction_local[3];
float ray_inv_dir[3];
- PreDefProject projectdefs;
+ float ray_min_dist;
+ float pmat[4][4]; /* perspective matrix multiplied by object matrix */
+ bool is_persp;
+ float win_half[2];
+
float mval[2];
bool sign[3];
- bool r_axis_closest[3];
- float depth_range[2];
-
- void *userdata;
- int index;
- float co[3];
- float no[3];
-} Object_Nearest2dPrecalc;
+} Nearest2dPrecalc;
-
-static void nearest2d_precalc(
- Object_Nearest2dPrecalc *neasrest_precalc, const ARegion *ar,
- const float dist_px, float obmat[4][4],
- const float ray_origin_local[3], const float ray_direction_local[3],
- const float mval[2], const float depth_range[2])
+/**
+ * \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])
{
- precalc_project(&neasrest_precalc->projectdefs, ar, dist_px, obmat);
+ 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;
+
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);
- copy_v2_v2(neasrest_precalc->depth_range, depth_range);
for (int i = 0; i < 3; i++) {
- neasrest_precalc->ray_inv_dir[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);
- neasrest_precalc->r_axis_closest[i] = true;
}
}
-static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *user_data)
+/* 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])
{
- Object_Nearest2dPrecalc *data = user_data;
float local_bvmin[3], local_bvmax[3];
if (data->sign[0]) {
- local_bvmin[0] = bounds[0].max;
- local_bvmax[0] = bounds[0].min;
+ local_bvmin[0] = bbmax[0];
+ local_bvmax[0] = bbmin[0];
}
else {
- local_bvmin[0] = bounds[0].min;
- local_bvmax[0] = bounds[0].max;
+ local_bvmin[0] = bbmin[0];
+ local_bvmax[0] = bbmax[0];
}
if (data->sign[1]) {
- local_bvmin[1] = bounds[1].max;
- local_bvmax[1] = bounds[1].min;
+ local_bvmin[1] = bbmax[1];
+ local_bvmax[1] = bbmin[1];
}
else {
- local_bvmin[1] = bounds[1].min;
- local_bvmax[1] = bounds[1].max;
+ local_bvmin[1] = bbmin[1];
+ local_bvmax[1] = bbmax[1];
}
if (data->sign[2]) {
- local_bvmin[2] = bounds[2].max;
- local_bvmax[2] = bounds[2].min;
+ local_bvmin[2] = bbmax[2];
+ local_bvmax[2] = bbmin[2];
}
else {
- local_bvmin[2] = bounds[2].min;
- local_bvmax[2] = bounds[2].max;
+ local_bvmin[2] = bbmin[2];
+ local_bvmax[2] = bbmax[2];
}
const float tmin[3] = {
@@ -543,7 +1044,9 @@ static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *us
(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;
@@ -551,38 +1054,38 @@ static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *us
rtmax = tmax[0];
va[0] = vb[0] = local_bvmax[0];
main_axis = 3;
- data->r_axis_closest[0] = data->sign[0];
+ 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;
- data->r_axis_closest[1] = data->sign[1];
+ r_axis_closest[1] = data->sign[1];
}
else {
rtmax = tmax[2];
va[2] = vb[2] = local_bvmax[2];
main_axis = 1;
- data->r_axis_closest[2] = data->sign[2];
+ r_axis_closest[2] = data->sign[2];
}
if ((tmin[0] >= tmin[1]) && (tmin[0] >= tmin[2])) {
rtmin = tmin[0];
va[0] = vb[0] = local_bvmin[0];
main_axis -= 3;
- data->r_axis_closest[0] = !data->sign[0];
+ 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;
- data->r_axis_closest[1] = !data->sign[1];
+ r_axis_closest[1] = !data->sign[1];
}
else {
rtmin = tmin[2];
va[2] = vb[2] = local_bvmin[2];
main_axis -= 2;
- data->r_axis_closest[2] = !data->sign[2];
+ r_axis_closest[2] = !data->sign[2];
}
if (main_axis < 0) {
main_axis += 3;
@@ -590,22 +1093,34 @@ static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *us
/* if rtmin < rtmax, ray intersect `AABB` */
if (rtmin <= rtmax) {
+#define IGNORE_BEHIND_RAY
#ifdef IGNORE_BEHIND_RAY
- /* `if rtmax < depth_min`, the whole `AABB` is behind us */
- if (rtmax < min_depth) {
- return fallback;
+ /* `if rtmax < depth_min`, the hit is behind us */
+ if (rtmax < data->ray_min_dist) {
+ /* Test if the entire AABB is behind us */
+ float depth = depth_get(
+ local_bvmax, data->ray_origin_local, data->ray_direction_local);
+ if (depth < (data->ray_min_dist)) {
+ return FLT_MAX;
+ }
}
#endif
const float proj = rtmin * data->ray_direction_local[main_axis];
- data->r_axis_closest[main_axis] = (proj - va[main_axis]) < (vb[main_axis] - proj);
- return true;
+ r_axis_closest[main_axis] = (proj - va[main_axis]) < (vb[main_axis] - proj);
+ return 0.0f;
}
#ifdef IGNORE_BEHIND_RAY
- /* `if rtmin < depth_min`, the whole `AABB` is behing us */
- else if (rtmin < min_depth) {
- return fallback;
+ /* `if rtmin < depth_min`, the hit is behing us */
+ else if (rtmin < data->ray_min_dist) {
+ /* Test if the entire AABB is behind us */
+ float depth = depth_get(
+ local_bvmax, data->ray_origin_local, data->ray_direction_local);
+ if (depth < (data->ray_min_dist)) {
+ return FLT_MAX;
+ }
}
#endif
+#undef IGNORE_BEHIND_RAY
if (data->sign[main_axis]) {
va[main_axis] = local_bvmax[main_axis];
vb[main_axis] = local_bvmin[main_axis];
@@ -616,110 +1131,172 @@ static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *us
}
float scale = fabsf(local_bvmax[main_axis] - local_bvmin[main_axis]);
- float (*pmat)[4] = data->projectdefs.pmat;
- float depth_a = mul_project_m4_v3_zfac(pmat, va);
- float depth_b = depth_a + pmat[main_axis][3] * scale;
+ float (*pmat)[4] = data->pmat;
float va2d[2] = {
(dot_m4_v3_row_x(pmat, va) + pmat[3][0]),
(dot_m4_v3_row_y(pmat, va) + pmat[3][1]),
};
float vb2d[2] = {
- (va2d[0] + pmat[main_axis][0] * scale) / depth_b,
- (va2d[1] + pmat[main_axis][1] * scale) / depth_b,
+ (va2d[0] + pmat[main_axis][0] * scale),
+ (va2d[1] + pmat[main_axis][1] * scale),
};
- va2d[0] /= depth_a;
- va2d[1] /= depth_a;
+ 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->projectdefs.win_half[0];
- va2d[1] *= data->projectdefs.win_half[1];
- vb2d[0] *= data->projectdefs.win_half[0];
- vb2d[1] *= data->projectdefs.win_half[1];
-
- //float dvec[2], edge[2], rdist;
- //sub_v2_v2v2(dvec, data->mval, va2d);
- //sub_v2_v2v2(edge, vb2d, va2d);
- float rdist;
- short dvec[2] = {data->mval[0] - va2d[0], data->mval[1] - va2d[1]};
- short edge[2] = {vb2d[0] - va2d[0], vb2d[1] - va2d[1]};
- float lambda = dvec[0] * edge[0] + dvec[1] * edge[1];
+ 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 /= edge[0] * edge[0] + edge[1] * edge[1];
+ lambda /= len_squared_v2(edge);
if (lambda <= 0.0f) {
rdist = len_squared_v2v2(data->mval, va2d);
- data->r_axis_closest[main_axis] = true;
+ r_axis_closest[main_axis] = true;
}
else if (lambda >= 1.0f) {
rdist = len_squared_v2v2(data->mval, vb2d);
- data->r_axis_closest[main_axis] = false;
+ r_axis_closest[main_axis] = false;
}
else {
va2d[0] += edge[0] * lambda;
va2d[1] += edge[1] * lambda;
rdist = len_squared_v2v2(data->mval, va2d);
- data->r_axis_closest[main_axis] = lambda < 0.5f;
+ r_axis_closest[main_axis] = lambda < 0.5f;
}
}
else {
rdist = len_squared_v2v2(data->mval, va2d);
}
- return rdist < data->projectdefs.dist_px_sq;
+ 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);
+
+ bool dummy[3] = {true, true, true};
+ return dist_squared_to_projected_aabb(&data, bbmin, bbmax, dummy);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** Walk DFS
+ * \{ */
+
+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);
+
+typedef struct Nearest2dUserData {
+ struct Nearest2dPrecalc data_precalc;
+
+ float dist_px_sq;
+
+ bool r_axis_closest[3];
+
+ float depth_range[2];
+
+ void *userdata;
+ Nearest2DGetEdgeVertsCallback get_edge_verts;
+ Nearest2DCopyVertNoCallback copy_vert_no;
+
+ int index;
+ float co[3];
+ float no[3];
+} Nearest2dUserData;
+
+
+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;
}
static bool cb_walk_leaf_snap_vert(const BVHTreeAxisRange *bounds, int index, void *userdata)
{
- struct Object_Nearest2dPrecalc *neasrest_precalc = 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,
};
- /* Currently the `BLI_bvhtree_walk_dfs` is being used only in the perspective view mode (VIEW_PROJ_PERSP)
- * It could be used in orthographic view mode too (VIEW_PROJ_ORTHO),
- * but in this case the `BLI_bvhtree_find_nearest_to_ray` is more efficient.*/
if (test_projected_vert_dist(
- &neasrest_precalc->projectdefs, co, VIEW_PROJ_PERSP,
- neasrest_precalc->mval, neasrest_precalc->depth_range,
- neasrest_precalc->co))
+ data->depth_range,
+ neasrest_precalc->mval, co,
+ neasrest_precalc->pmat,
+ neasrest_precalc->win_half,
+ neasrest_precalc->is_persp,
+ &data->dist_px_sq,
+ data->co))
{
- copy_vert_no(neasrest_precalc->userdata, index, neasrest_precalc->no);
- neasrest_precalc->index = index;
+ data->copy_vert_no(index, data->no, data->userdata);
+ data->index = index;
}
return true;
}
static bool cb_walk_leaf_snap_edge(const BVHTreeAxisRange *UNUSED(bounds), int index, void *userdata)
{
- struct Object_Nearest2dPrecalc *neasrest_precalc = userdata;
+ struct Nearest2dUserData *data = userdata;
+ struct Nearest2dPrecalc *neasrest_precalc = &data->data_precalc;
const float *v_pair[2];
- get_edge_verts(neasrest_precalc->userdata, index, v_pair);
+ data->get_edge_verts(index, v_pair, data->userdata);
- /* Currently the `BLI_bvhtree_walk_dfs` is being used only in the perspective view mode (VIEW_PROJ_PERSP)
- * It could be used in orthographic view mode too (VIEW_PROJ_ORTHO),
- * but in this case the `BLI_bvhtree_find_nearest_to_ray` is more efficient.*/
if (test_projected_edge_dist(
- &neasrest_precalc->projectdefs, v_pair[0], v_pair[1],
- neasrest_precalc->ray_origin_local, neasrest_precalc->ray_direction_local,
- VIEW_PROJ_PERSP, neasrest_precalc->mval, neasrest_precalc->depth_range,
- neasrest_precalc->co))
+ 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))
{
- sub_v3_v3v3(neasrest_precalc->no, v_pair[0], v_pair[1]);
- neasrest_precalc->index = index;
+ sub_v3_v3v3(data->no, v_pair[0], v_pair[1]);
+ data->index = index;
}
return true;
}
static bool cb_nearest_walk_order(const BVHTreeAxisRange *UNUSED(bounds), char axis, void *userdata)
{
- const bool *r_axis_closest = ((struct Object_Nearest2dPrecalc *)userdata)->r_axis_closest;
+ const bool *r_axis_closest = ((struct Nearest2dUserData *)userdata)->r_axis_closest;
return r_axis_closest[axis];
}
@@ -731,46 +1308,56 @@ static bool cb_nearest_walk_order(const BVHTreeAxisRange *UNUSED(bounds), char a
* \{ */
static bool snapArmature(
- const ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4],
- const short snap_to, const float origin[3], const float dir[3],
- const float mval[2], const enum eViewProj view_proj, const float depth_range[2],
+ SnapData *snapdata,
+ Object *ob, bArmature *arm, float obmat[4][4],
/* read/write args */
- float *dist_px,
+ float *ray_depth, float *dist_px,
/* return args */
float r_loc[3], float *UNUSED(r_no))
{
bool retval = false;
- float ray_start_local[3], ray_normal_local[3];
- if (snap_to != SCE_SNAP_MODE_VERTEX) {
+ 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);
- copy_v3_v3(ray_start_local, origin);
- copy_v3_v3(ray_normal_local, dir);
+ 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);
}
+ else if (snapdata->snap_to != SCE_SNAP_MODE_VERTEX) { /* Currently only edge and vert */
+ return retval;
+ }
- PreDefProject projectdefs;
- precalc_project(&projectdefs, ar, *dist_px, obmat);
+ 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);
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 (snap_to) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_VERTEX:
retval |= test_projected_vert_dist(
- &projectdefs, eBone->head, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, eBone->head,
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
retval |= test_projected_vert_dist(
- &projectdefs, eBone->tail, view_proj, mval, depth_range, r_loc);
+ 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(
- &projectdefs, eBone->head, eBone->tail, ray_start_local, ray_normal_local,
- view_proj, mval, depth_range, r_loc);
+ 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;
}
}
@@ -785,52 +1372,60 @@ static bool snapArmature(
const float *head_vec = pchan->pose_head;
const float *tail_vec = pchan->pose_tail;
- switch (snap_to) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_VERTEX:
retval |= test_projected_vert_dist(
- &projectdefs, head_vec, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, head_vec,
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
retval |= test_projected_vert_dist(
- &projectdefs, tail_vec, view_proj, mval, depth_range, r_loc);
+ 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(
- &projectdefs, head_vec, tail_vec, ray_start_local, ray_normal_local,
- view_proj, mval, depth_range, r_loc);
+ 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 (retval) {
- *dist_px = sqrtf(projectdefs.dist_px_sq);
+ *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;
}
return false;
}
static bool snapCurve(
- const ARegion *ar, Object *ob, Curve *cu, float obmat[4][4],
- const short snap_to, const float mval[2], const enum eViewProj view_proj,
- const float depth_range[2],
+ SnapData *snapdata,
+ Object *ob, Curve *cu, float obmat[4][4],
/* read/write args */
- float *dist_px,
+ float *ray_depth, float *dist_px,
/* return args */
float r_loc[3], float *UNUSED(r_no))
{
bool retval = false;
/* only vertex snapping mode (eg control points and handles) supported for now) */
- if (snap_to != SCE_SNAP_MODE_VERTEX) {
+ if (snapdata->snap_to != SCE_SNAP_MODE_VERTEX) {
return retval;
}
- PreDefProject projectdefs;
- precalc_project(&projectdefs, ar, *dist_px, obmat);
+ 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);
for (Nurb *nu = (ob->mode == OB_MODE_EDIT ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) {
for (int u = 0; u < nu->pntsu; u++) {
- switch (snap_to) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_VERTEX:
{
if (ob->mode == OB_MODE_EDIT) {
@@ -840,19 +1435,25 @@ static bool snapCurve(
break;
}
retval |= test_projected_vert_dist(
- &projectdefs, nu->bezt[u].vec[1], view_proj, mval, depth_range, r_loc);
+ 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(
- &projectdefs, nu->bezt[u].vec[0], view_proj, mval, depth_range, r_loc);
+ 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(
- &projectdefs, nu->bezt[u].vec[2], view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, nu->bezt[u].vec[2],
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
}
}
else {
@@ -861,7 +1462,9 @@ static bool snapCurve(
break;
}
retval |= test_projected_vert_dist(
- &projectdefs, nu->bp[u].vec, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, nu->bp[u].vec,
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
}
}
else {
@@ -869,11 +1472,15 @@ static bool snapCurve(
if (nu->pntsu > 1) {
if (nu->bezt) {
retval |= test_projected_vert_dist(
- &projectdefs, nu->bezt[u].vec[1], view_proj, mval, depth_range, r_loc);
+ 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(
- &projectdefs, nu->bp[u].vec, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, nu->bp[u].vec,
+ lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
}
}
}
@@ -885,8 +1492,9 @@ static bool snapCurve(
}
}
if (retval) {
- *dist_px = sqrtf(projectdefs.dist_px_sq);
+ *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;
}
return false;
@@ -894,11 +1502,10 @@ static bool snapCurve(
/* may extend later (for now just snaps to empty center) */
static bool snapEmpty(
- const ARegion *ar, Object *ob, float obmat[4][4],
- const short snap_to, const float mval[2], const enum eViewProj view_proj,
- const float depth_range[2],
+ SnapData *snapdata,
+ Object *ob, float obmat[4][4],
/* read/write args */
- float *dist_px,
+ float *ray_depth, float *dist_px,
/* return args */
float r_loc[3], float *UNUSED(r_no))
{
@@ -909,15 +1516,20 @@ static bool snapEmpty(
}
/* for now only vertex supported */
- switch (snap_to) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_VERTEX:
{
- PreDefProject projectdefs;
- precalc_project(&projectdefs, ar, *dist_px, NULL);
+ 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(&projectdefs, tmp_co, view_proj, mval, depth_range, r_loc)) {
- *dist_px = sqrtf(projectdefs.dist_px_sq);
+ 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;
@@ -930,18 +1542,17 @@ static bool snapEmpty(
}
static bool snapCamera(
- const SnapObjectContext *sctx, Object *object, float obmat[4][4],
- const short snap_to, const float mval[2], const enum eViewProj view_proj,
- const float depth_range[2],
+ const SnapObjectContext *sctx, SnapData *snapdata,
+ Object *object, float obmat[4][4],
/* read/write args */
- float *dist_px,
+ float *ray_depth, float *dist_px,
/* return args */
float r_loc[3], float *UNUSED(r_no))
{
Scene *scene = sctx->scene;
- PreDefProject projectdefs;
- precalc_project(&projectdefs, sctx->v3d_data.ar, *dist_px, NULL);
+ 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;
@@ -962,7 +1573,7 @@ static bool snapCamera(
invert_m4_m4(orig_camera_imat, orig_camera_mat);
invert_m4_m4(imat, obmat);
- switch (snap_to) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_VERTEX:
{
MovieTrackingObject *tracking_object;
@@ -1002,7 +1613,9 @@ static bool snapCamera(
mul_m4_v3(vertex_obmat, bundle_pos);
retval |= test_projected_vert_dist(
- &projectdefs, bundle_pos, view_proj, mval, depth_range, r_loc);
+ snapdata->depth_range, snapdata->mval, bundle_pos,
+ snapdata->pmat, snapdata->win_half, is_persp, &dist_px_sq,
+ r_loc);
}
}
@@ -1013,7 +1626,8 @@ static bool snapCamera(
}
if (retval) {
- *dist_px = sqrtf(projectdefs.dist_px_sq);
+ *dist_px = sqrtf(dist_px_sq);
+ *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
return true;
}
return false;
@@ -1025,71 +1639,17 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt)
return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly;
}
-struct NearestDM_Data {
- void *bvhdata;
- const float *depth_range;
- float *ray_depth;
-};
-
-static void test_vert_ray_dist_cb(
- void *userdata, const float origin[3], const float dir[3],
- const float scale[3], int index, BVHTreeNearest *nearest)
-{
- struct NearestDM_Data *ndata = userdata;
- const struct BVHTreeFromMeshType *data = ndata->bvhdata;
-
- const float *co = get_vert_co(data, index);
-
- if (test_vert_dist(
- co, origin, dir, ndata->depth_range,
- scale, ndata->ray_depth, &nearest->dist_sq,
- nearest->co))
- {
- copy_vert_no(data, index, nearest->no);
- nearest->index = index;
- }
-}
-
-static void test_edge_ray_dist_cb(
- void *userdata, const float origin[3], const float dir[3],
- const float scale[3], int index, BVHTreeNearest *nearest)
-{
- struct NearestDM_Data *ndata = userdata;
- BVHTreeFromMeshType *data = ndata->bvhdata;
-
- const float *v_pair[2];
- get_edge_verts(data, index, v_pair);
-
- if (test_edge_dist(
- v_pair[0], v_pair[1], origin, dir, ndata->depth_range,
- scale, ndata->ray_depth, &nearest->dist_sq,
- nearest->co))
- {
- sub_v3_v3v3(nearest->no, v_pair[0], v_pair[1]);
- nearest->index = index;
- }
-}
-
static bool snapDerivedMesh(
- SnapObjectContext *sctx,
- Object *ob, DerivedMesh *dm, float obmat[4][4], const unsigned int ob_index,
- const short snap_to, const float mval[2], const enum eViewProj view_proj, bool do_bb,
- const float ray_origin[3], const float ray_start[3], const float ray_normal[3],
- const float depth_range[2],
+ SnapObjectContext *sctx, SnapData *snapdata,
+ Object *ob, DerivedMesh *dm, float obmat[4][4],
/* read/write args */
float *ray_depth, float *dist_px,
/* return args */
- float r_loc[3], float r_no[3], int *r_index,
- ListBase *r_hit_list)
+ float r_loc[3], float r_no[3])
{
bool retval = false;
- if (snap_to == SCE_SNAP_MODE_FACE) {
- if (dm->getNumPolys(dm) == 0) {
- return retval;
- }
- }
- else if (snap_to == SCE_SNAP_MODE_EDGE) {
+ if (snapdata->snap_to == SCE_SNAP_MODE_EDGE) {
if (dm->getNumEdges(dm) == 0) {
return retval;
}
@@ -1100,106 +1660,89 @@ static bool snapDerivedMesh(
}
}
- {
- bool need_ray_start_correction_init = (snap_to == SCE_SNAP_MODE_FACE) && (view_proj == VIEW_PROJ_ORTHO);
+ float imat[4][4];
+ float timat[3][3]; /* transpose inverse matrix for normals */
+ float ray_normal_local[3];
+ float local_scale;
- 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;
+ invert_m4_m4(imat, obmat);
+ transpose_m3_m4(timat, imat);
- invert_m4_m4(imat, obmat);
- transpose_m3_m4(timat, imat);
+ copy_v3_v3(ray_normal_local, snapdata->ray_dir);
- copy_v3_v3(ray_start_local, ray_start);
- copy_v3_v3(ray_normal_local, ray_normal);
+ mul_mat3_m4_v3(imat, ray_normal_local);
- 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 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;
- }
+ float lpmat[4][4];
+ float ray_org_local[3];
+ float ray_min_dist;
- if (do_bb) {
- BoundBox *bb = BKE_object_boundbox_get(ob);
+ mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
+ ray_min_dist = snapdata->depth_range[0] * local_scale;
- if (bb) {
- BoundBox bb_temp;
+ copy_v3_v3(ray_org_local, snapdata->ray_origin);
+ mul_m4_v3(imat, ray_org_local);
- /* We cannot afford a bounding box with some null dimension, which may happen in some cases...
- * Threshold is rather high, but seems to be needed to get good behavior, see T46099. */
- bb = BKE_boundbox_ensure_minimum_dimensions(bb, &bb_temp, 1e-1f);
+ /* 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;
+ }
+ }
- /* Exact value here is arbitrary (ideally we would scale in pixel-space based on 'dist_px'),
- * scale up so we can snap against verts & edges on the boundbox, see T46816. */
- if (ELEM(snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) {
- BKE_boundbox_scale(&bb_temp, bb, 1.0f + 1e-1f);
- bb = &bb_temp;
- }
+ SnapObjectData_Mesh *sod = NULL;
+ BVHTreeFromMesh *treedata = NULL;
- /* was local_depth, see: T47838 */
- len_diff = BVH_RAYCAST_DIST_MAX;
+ 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_MESH;
+ }
- if (!BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, &len_diff)) {
- return retval;
- }
- need_ray_start_correction_init = 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;
+ }
+ 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));
}
+ treedata = sod->bvh_trees[tree_index];
- SnapObjectData_Mesh *sod = NULL;
- BVHTreeFromMesh *treedata = NULL, treedata_stack;
-
- if (sctx->flag & SNAP_OBJECT_USE_CACHE) {
- void **sod_p;
- if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
- sod = *sod_p;
+ /* 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 {
- sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
- sod->sd.type = SNAP_MESH;
- }
-
- int tree_index = -1;
- switch (snap_to) {
- case SCE_SNAP_MODE_FACE:
- tree_index = 2;
- break;
- 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));
+ if (!treedata->vert_allocated) {
+ treedata->vert = DM_get_vert_array(dm, &treedata->vert_allocated);
}
- 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);
- }
+ if ((tree_index == 1) && !treedata->edge_allocated) {
+ treedata->edge = DM_get_edge_array(dm, &treedata->edge_allocated);
}
}
}
- else {
- treedata = &treedata_stack;
- memset(treedata, 0, sizeof(*treedata));
- }
+ }
- if (treedata && treedata->tree == NULL) {
- switch (snap_to) {
- case SCE_SNAP_MODE_FACE:
- bvhtree_from_mesh_looptri(treedata, dm, 0.0f, 4, 6);
- break;
+ if (treedata) {
+ if (treedata->tree == NULL) {
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_EDGE:
bvhtree_from_mesh_edges(treedata, dm, 0.0f, 2, 6);
break;
@@ -1208,206 +1751,70 @@ static bool snapDerivedMesh(
break;
}
}
-
- if (!treedata || !treedata->tree) {
+ if (treedata->tree == NULL) {
return retval;
}
+ }
+ else {
+ return retval;
+ }
- if (snap_to == SCE_SNAP_MODE_FACE) {
- /* 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 (view_proj == VIEW_PROJ_ORTHO) { /* do_ray_start_correction */
- if (need_ray_start_correction_init) {
- /* We *need* a reasonably valid len_diff in this case.
- * Use BHVTree to find the closest face from ray_start_local.
- */
- BVHTreeNearest nearest;
- nearest.index = -1;
- nearest.dist_sq = FLT_MAX;
- /* Compute and store result. */
- BLI_bvhtree_find_nearest(
- treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata);
- if (nearest.index != -1) {
- float dvec[3];
- sub_v3_v3v3(dvec, nearest.co, ray_start_local);
- len_diff = dot_v3v3(dvec, ray_normal_local);
- }
- }
- float ray_org_local[3];
-
- copy_v3_v3(ray_org_local, ray_origin);
- mul_m4_v3(imat, ray_org_local);
-
- /* 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_v3v3fl(
- ray_start_local, ray_org_local, ray_normal_local, len_diff + depth_range[0] * local_scale);
- local_depth -= len_diff;
- }
- else {
- len_diff = 0.0f;
- }
- if (r_hit_list) {
- struct RayCastAll_Data data;
-
- data.bvhdata = treedata;
- data.raycast_callback = treedata->raycast_callback;
- data.obmat = obmat;
- data.timat = timat;
- data.len_diff = len_diff;
- data.local_scale = local_scale;
- data.ob = ob;
- data.ob_uuid = ob_index;
- data.hit_list = r_hit_list;
- data.retval = retval;
-
- BLI_bvhtree_ray_cast_all(
- treedata->tree, ray_start_local, ray_normal_local, 0.0f,
- *ray_depth, raycast_all_cb, &data);
-
- retval = data.retval;
- }
- else {
- BVHTreeRayHit hit = {.index = -1, .dist = local_depth};
-
- if (BLI_bvhtree_ray_cast(
- treedata->tree, ray_start_local, ray_normal_local, 0.0f,
- &hit, treedata->raycast_callback, treedata) != -1)
- {
- hit.dist += len_diff;
- hit.dist /= local_scale;
- if (hit.dist <= *ray_depth) {
- *ray_depth = hit.dist;
- copy_v3_v3(r_loc, hit.co);
-
- /* back to worldspace */
- mul_m4_v3(obmat, r_loc);
-
- if (r_no) {
- copy_v3_v3(r_no, hit.no);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
- }
-
- retval = true;
-
- if (r_index) {
- *r_index = dm_looptri_to_poly_index(dm, &treedata->looptri[hit.index]);
- }
- }
- }
- }
- }
- else {
- const ARegion *ar = sctx->v3d_data.ar;
-
- float ray_org_local[3];
- copy_v3_v3(ray_org_local, ray_origin);
- mul_m4_v3(imat, ray_org_local);
-
- BVHTreeFromMeshType treedata_type = {.userdata = treedata, .type = SNAP_MESH};
-
- if (view_proj == VIEW_PROJ_PERSP) {
- Object_Nearest2dPrecalc neasrest_precalc;
- neasrest_precalc.userdata = &treedata_type;
- neasrest_precalc.index = -1;
-
- nearest2d_precalc(&neasrest_precalc, ar, *dist_px, obmat,
- ray_org_local, ray_normal_local, mval, depth_range);
-
- BVHTree_WalkLeafCallback cb_walk_leaf =
- (snap_to == SCE_SNAP_MODE_VERTEX) ?
- cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge;
-
- BLI_bvhtree_walk_dfs(
- treedata->tree,
- cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest_precalc);
-
- if (neasrest_precalc.index != -1) {
- copy_v3_v3(r_loc, neasrest_precalc.co);
- mul_m4_v3(obmat, r_loc);
- if (r_no) {
- copy_v3_v3(r_no, neasrest_precalc.no);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
- }
- *dist_px = sqrtf(neasrest_precalc.projectdefs.dist_px_sq);
-
- retval = true;
- }
- }
- else {
- BVHTreeNearest nearest;
-
- nearest.index = -1;
- float dist_3d = dist_px_to_dist3d_or_tangent(ar, *dist_px);
- nearest.dist_sq = SQUARE(dist_3d);
-
-
- float ob_scale[3];
- mat4_to_size(ob_scale, obmat);
-
- struct NearestDM_Data userdata;
- userdata.bvhdata = &treedata_type;
- userdata.depth_range = depth_range;
- userdata.ray_depth = ray_depth;
-
- BVHTree_NearestToRayCallback cb_test_ray_dist =
- (snap_to == SCE_SNAP_MODE_VERTEX) ?
- test_vert_ray_dist_cb : test_edge_ray_dist_cb;
-
- if (BLI_bvhtree_find_nearest_to_ray(
- treedata->tree, ray_org_local, ray_normal_local,
- true, ob_scale, &nearest, cb_test_ray_dist, &userdata) != -1)
- {
- copy_v3_v3(r_loc, nearest.co);
- mul_m4_v3(obmat, r_loc);
- if (r_no) {
- copy_v3_v3(r_no, nearest.no);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
- }
- *dist_px *= sqrtf(nearest.dist_sq) / dist_3d;
-
- retval = true;
- }
- }
+ /* 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];
+
+ 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};
+
+ 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);
+
+ BVHTree_WalkLeafCallback cb_walk_leaf =
+ (snapdata->snap_to == SCE_SNAP_MODE_VERTEX) ?
+ cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge;
+
+ BLI_bvhtree_walk_dfs(
+ treedata->tree,
+ cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest2d);
+
+ if (neasrest2d.index != -1) {
+ copy_v3_v3(r_loc, neasrest2d.co);
+ mul_m4_v3(obmat, r_loc);
+ if (r_no) {
+ copy_v3_v3(r_no, neasrest2d.no);
+ mul_m3_v3(timat, 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 ((sctx->flag & SNAP_OBJECT_USE_CACHE) == 0) {
- if (treedata) {
- free_bvhtree_from_mesh(treedata);
- }
- }
+ retval = true;
}
return retval;
}
static bool snapEditMesh(
- SnapObjectContext *sctx,
- Object *ob, BMEditMesh *em, float obmat[4][4], const unsigned int ob_index,
- const short snap_to, const float mval[2], const enum eViewProj view_proj,
- const float ray_origin[3], const float ray_start[3], const float ray_normal[3],
- const float depth_range[2],
+ SnapObjectContext *sctx, SnapData *snapdata,
+ Object *ob, BMEditMesh *em, float obmat[4][4],
/* read/write args */
float *ray_depth, float *dist_px,
/* return args */
- float r_loc[3], float r_no[3], int *r_index,
- ListBase *r_hit_list)
+ float r_loc[3], float r_no[3])
{
bool retval = false;
- if (snap_to == SCE_SNAP_MODE_FACE) {
- if (em->bm->totface == 0) {
- return retval;
- }
- }
- if (snap_to == SCE_SNAP_MODE_EDGE) {
+ if (snapdata->snap_to == SCE_SNAP_MODE_EDGE) {
if (em->bm->totedge == 0) {
return retval;
}
@@ -1418,293 +1825,133 @@ static bool snapEditMesh(
}
}
- {
- float imat[4][4];
- float timat[3][3]; /* transpose inverse matrix for normals */
- float ray_normal_local[3];
+ float imat[4][4];
+ float timat[3][3]; /* transpose inverse matrix for normals */
+ float ray_normal_local[3];
- invert_m4_m4(imat, obmat);
- transpose_m3_m4(timat, imat);
+ invert_m4_m4(imat, obmat);
+ transpose_m3_m4(timat, imat);
- copy_v3_v3(ray_normal_local, ray_normal);
+ copy_v3_v3(ray_normal_local, snapdata->ray_dir);
- mul_mat3_m4_v3(imat, ray_normal_local);
+ mul_mat3_m4_v3(imat, ray_normal_local);
- SnapObjectData_EditMesh *sod = NULL;
+ /* local scale in normal direction */
+ float local_scale = normalize_v3(ray_normal_local);
- BVHTreeFromEditMesh *treedata = NULL, treedata_stack;
+ SnapObjectData_EditMesh *sod = NULL;
- if (sctx->flag & SNAP_OBJECT_USE_CACHE) {
- 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;
- }
+ BVHTreeFromEditMesh *treedata;
- int tree_index = -1;
- switch (snap_to) {
- case SCE_SNAP_MODE_FACE:
- tree_index = 2;
- break;
- 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));
- }
- treedata = sod->bvh_trees[tree_index];
- }
- }
- else {
- treedata = &treedata_stack;
- memset(treedata, 0, sizeof(*treedata));
+ 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;
+ }
+
+ 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));
}
+ treedata = sod->bvh_trees[tree_index];
+ }
- if (treedata && treedata->tree == NULL) {
- switch (snap_to) {
- case SCE_SNAP_MODE_FACE:
- {
- BLI_bitmap *looptri_mask = NULL;
- int looptri_num_active = -1;
- if (sctx->callbacks.edit_mesh.test_face_fn) {
- looptri_mask = BLI_BITMAP_NEW(em->tottri, __func__);
- looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface(
- em->bm, looptri_mask,
- sctx->callbacks.edit_mesh.test_face_fn, sctx->callbacks.edit_mesh.user_data);
- }
- bvhtree_from_editmesh_looptri_ex(treedata, em, looptri_mask, looptri_num_active, 0.0f, 4, 6, NULL);
- if (looptri_mask) {
- MEM_freeN(looptri_mask);
- }
- break;
- }
+ if (treedata) {
+ if (treedata->tree == NULL) {
+ BLI_bitmap *elem_mask = NULL;
+ switch (snapdata->snap_to) {
case SCE_SNAP_MODE_EDGE:
{
- 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__);
+ elem_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,
+ 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, edges_mask, edges_num_active, 0.0f, 2, 6);
- if (edges_mask) {
- MEM_freeN(edges_mask);
- }
+ bvhtree_from_editmesh_edges_ex(treedata, em, elem_mask, edges_num_active, 0.0f, 2, 6);
break;
}
case SCE_SNAP_MODE_VERTEX:
{
- 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__);
+ elem_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,
+ 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, verts_mask, verts_num_active, 0.0f, 2, 6);
- if (verts_mask) {
- MEM_freeN(verts_mask);
- }
+ bvhtree_from_editmesh_verts_ex(treedata, em, elem_mask, verts_num_active, 0.0f, 2, 6);
break;
}
}
+ if (elem_mask) {
+ MEM_freeN(elem_mask);
+ }
}
-
- if (!treedata || !treedata->tree) {
+ if (treedata->tree == NULL) {
return retval;
}
+ }
+ else {
+ return retval;
+ }
- if (snap_to == SCE_SNAP_MODE_FACE) {
- float ray_start_local[3];
- copy_v3_v3(ray_start_local, ray_start);
- mul_m4_v3(imat, ray_start_local);
-
- /* 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;
- }
-
- /* 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!
- */
- float len_diff = 0.0f;
- if (view_proj == VIEW_PROJ_ORTHO) { /* do_ray_start_correction */
- /* We *need* a reasonably valid len_diff in this case.
- * Use BHVTree to find the closest face from ray_start_local.
- */
- BVHTreeNearest nearest;
- nearest.index = -1;
- nearest.dist_sq = FLT_MAX;
- /* Compute and store result. */
- if (BLI_bvhtree_find_nearest(
- treedata->tree, ray_start_local, &nearest, NULL, NULL) != -1)
- {
- float dvec[3];
- sub_v3_v3v3(dvec, nearest.co, ray_start_local);
- len_diff = dot_v3v3(dvec, ray_normal_local);
- float ray_org_local[3];
-
- copy_v3_v3(ray_org_local, ray_origin);
- mul_m4_v3(imat, ray_org_local);
-
- /* 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_v3v3fl(
- ray_start_local, ray_org_local, ray_normal_local, len_diff + depth_range[0] * local_scale);
- local_depth -= len_diff;
- }
- }
- if (r_hit_list) {
- struct RayCastAll_Data data;
-
- data.bvhdata = treedata;
- data.raycast_callback = treedata->raycast_callback;
- data.obmat = obmat;
- data.timat = timat;
- data.len_diff = len_diff;
- data.local_scale = local_scale;
- data.ob = ob;
- data.ob_uuid = ob_index;
- data.hit_list = r_hit_list;
- data.retval = retval;
-
- BLI_bvhtree_ray_cast_all(
- treedata->tree, ray_start_local, ray_normal_local, 0.0f,
- *ray_depth, raycast_all_cb, &data);
-
- retval = data.retval;
- }
- else {
- BVHTreeRayHit hit = {.index = -1, .dist = local_depth};
-
- if (BLI_bvhtree_ray_cast(
- treedata->tree, ray_start_local, ray_normal_local, 0.0f,
- &hit, treedata->raycast_callback, treedata) != -1)
- {
- hit.dist += len_diff;
- hit.dist /= local_scale;
- if (hit.dist <= *ray_depth) {
- *ray_depth = hit.dist;
- copy_v3_v3(r_loc, hit.co);
-
- /* back to worldspace */
- mul_m4_v3(obmat, r_loc);
-
- if (r_no) {
- copy_v3_v3(r_no, hit.no);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
- }
-
- retval = true;
-
- if (r_index) {
- *r_index = hit.index;
- }
- }
- }
- }
- }
- else {
- const ARegion *ar = sctx->v3d_data.ar;
-
- float ray_org_local[3];
- copy_v3_v3(ray_org_local, ray_origin);
- mul_m4_v3(imat, ray_org_local);
-
- BVHTreeFromMeshType treedata_type = {.userdata = treedata, .type = SNAP_EDIT_MESH};
-
- if (view_proj == VIEW_PROJ_PERSP) {
- Object_Nearest2dPrecalc neasrest_precalc;
- neasrest_precalc.userdata = &treedata_type;
- neasrest_precalc.index = -1;
-
- nearest2d_precalc(&neasrest_precalc, ar, *dist_px, obmat,
- ray_org_local, ray_normal_local, mval, depth_range);
-
- BVHTree_WalkLeafCallback cb_walk_leaf =
- (snap_to == SCE_SNAP_MODE_VERTEX) ?
- cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge;
-
- BLI_bvhtree_walk_dfs(
- treedata->tree,
- cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest_precalc);
-
- if (neasrest_precalc.index != -1) {
- copy_v3_v3(r_loc, neasrest_precalc.co);
- mul_m4_v3(obmat, r_loc);
- if (r_no) {
- copy_v3_v3(r_no, neasrest_precalc.no);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
- }
- *dist_px = sqrtf(neasrest_precalc.projectdefs.dist_px_sq);
-
- retval = true;
- }
- }
- else {
- BVHTreeNearest nearest;
-
- nearest.index = -1;
- float dist_3d = dist_px_to_dist3d_or_tangent(ar, *dist_px);
- nearest.dist_sq = SQUARE(dist_3d);
-
-
- float ob_scale[3];
- mat4_to_size(ob_scale, obmat);
-
- struct NearestDM_Data userdata;
- userdata.bvhdata = &treedata_type;
- userdata.depth_range = depth_range;
- userdata.ray_depth = ray_depth;
-
- BVHTree_NearestToRayCallback cb_test_ray_dist =
- (snap_to == SCE_SNAP_MODE_VERTEX) ?
- test_vert_ray_dist_cb : test_edge_ray_dist_cb;
-
- if (BLI_bvhtree_find_nearest_to_ray(
- treedata->tree, ray_org_local, ray_normal_local,
- false, ob_scale, &nearest, cb_test_ray_dist, &userdata) != -1)
- {
- copy_v3_v3(r_loc, nearest.co);
- mul_m4_v3(obmat, r_loc);
- if (r_no) {
- copy_v3_v3(r_no, nearest.no);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
- }
- *dist_px *= sqrtf(nearest.dist_sq) / dist_3d;
-
- retval = true;
- }
- }
+ float ray_org_local[3];
+ copy_v3_v3(ray_org_local, snapdata->ray_origin);
+ mul_m4_v3(imat, ray_org_local);
+
+ 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};
+
+ 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);
+
+ BVHTree_WalkLeafCallback cb_walk_leaf =
+ (snapdata->snap_to == SCE_SNAP_MODE_VERTEX) ?
+ cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge;
+
+ BLI_bvhtree_walk_dfs(
+ treedata->tree,
+ cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest2d);
+
+ if (neasrest2d.index != -1) {
+ copy_v3_v3(r_loc, neasrest2d.co);
+ mul_m4_v3(obmat, r_loc);
+ if (r_no) {
+ copy_v3_v3(r_no, neasrest2d.no);
+ mul_m3_v3(timat, 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 ((sctx->flag & SNAP_OBJECT_USE_CACHE) == 0) {
- if (treedata) {
- free_bvhtree_from_editmesh(treedata);
- }
- }
+ retval = true;
}
return retval;
@@ -1716,24 +1963,15 @@ static bool snapEditMesh(
* \note Duplicate args here are documented at #snapObjectsRay
*/
static bool snapObject(
- SnapObjectContext *sctx,
- Object *ob, float obmat[4][4], const unsigned int ob_index,
- bool use_obedit, const short snap_to, const float mval[2],
- const float ray_origin[3], const float ray_start[3], const float ray_normal[3],
- const float depth_range[2],
+ SnapObjectContext *sctx, SnapData *snapdata,
+ Object *ob, float obmat[4][4],
+ bool use_obedit,
/* read/write args */
float *ray_depth, float *dist_px,
/* return args */
- float r_loc[3], float r_no[3], int *r_index,
- Object **r_ob, float r_obmat[4][4],
- ListBase *r_hit_list)
+ float r_loc[3], float r_no[3],
+ Object **r_ob, float r_obmat[4][4])
{
- const enum eViewProj view_proj =
- ((sctx->use_v3d == false) || (mval == NULL)) ? VIEW_PROJ_NONE :
- (((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO);
-
- const ARegion *ar = sctx->v3d_data.ar;
-
bool retval = false;
if (ob->type == OB_MESH) {
@@ -1742,12 +1980,9 @@ static bool snapObject(
if (use_obedit) {
em = BKE_editmesh_from_object(ob);
retval = snapEditMesh(
- sctx, ob, em, obmat, ob_index,
- snap_to, mval, view_proj,
- ray_origin, ray_start, ray_normal, depth_range,
+ sctx, snapdata, ob, em, obmat,
ray_depth, dist_px,
- r_loc, r_no, r_index,
- r_hit_list);
+ r_loc, r_no);
}
else {
/* in this case we want the mesh from the editmesh, avoids stale data. see: T45978.
@@ -1761,42 +1996,39 @@ static bool snapObject(
dm = mesh_get_derived_final(sctx->scene, ob, CD_MASK_BAREMESH);
}
retval = snapDerivedMesh(
- sctx, ob, dm, obmat, ob_index,
- snap_to, mval, view_proj, true,
- ray_origin, ray_start, ray_normal, depth_range,
+ sctx, snapdata, ob, dm, obmat,
ray_depth, dist_px,
- r_loc, r_no,
- r_index, r_hit_list);
+ r_loc, r_no);
dm->release(dm);
}
}
- else if (snap_to != SCE_SNAP_MODE_FACE) {
+ else if (snapdata->snap_to != SCE_SNAP_MODE_FACE) {
if (ob->type == OB_ARMATURE) {
retval = snapArmature(
- ar, ob, ob->data, obmat, snap_to, ray_origin, ray_normal,
- mval, view_proj, depth_range, dist_px,
+ snapdata,
+ ob, ob->data, obmat,
+ ray_depth, dist_px,
r_loc, r_no);
}
else if (ob->type == OB_CURVE) {
retval = snapCurve(
- ar, ob, ob->data, obmat, snap_to, mval, view_proj,
- depth_range,
- dist_px,
+ snapdata,
+ ob, ob->data, obmat,
+ ray_depth, dist_px,
r_loc, r_no);
}
else if (ob->type == OB_EMPTY) {
retval = snapEmpty(
- ar, ob, obmat, snap_to, mval, view_proj,
- depth_range,
- dist_px,
+ snapdata,
+ ob, obmat,
+ ray_depth, dist_px,
r_loc, r_no);
}
else if (ob->type == OB_CAMERA) {
retval = snapCamera(
- sctx, ob, obmat, snap_to, mval, view_proj,
- depth_range,
- dist_px,
+ sctx, snapdata, ob, obmat,
+ ray_depth, dist_px,
r_loc, r_no);
}
}
@@ -1811,6 +2043,34 @@ static bool snapObject(
return retval;
}
+
+struct SnapObjUserData {
+ SnapData *snapdata;
+ /* read/write args */
+ float *ray_depth;
+ float *dist_px;
+ /* return args */
+ float *r_loc;
+ float *r_no;
+ Object **r_ob;
+ float (*r_obmat)[4];
+ bool 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(
+ sctx, dt->snapdata,
+ ob, obmat, is_obedit,
+ /* read/write args */
+ dt->ray_depth, dt->dist_px,
+ /* return args */
+ dt->r_loc, dt->r_no,
+ dt->r_ob, dt->r_obmat);
+}
+
+
/**
* Main Snapping Function
* ======================
@@ -1818,18 +2078,9 @@ static bool snapObject(
* Walks through all objects in the scene to find the closest snap element ray.
*
* \param sctx: Snap context to store data.
- * \param snap_to: Element to snap, Vertice, Edge or Face.
- * Currently only works one at a time, but can eventually operate as flag.
- *
- * \param snap_select: from enum SnapSelect.
- *
- * \param use_object_edit_cage: Uses the coordinates of BMesh (if any) to do the snapping.
- * \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_normal: Unit length direction of the ray.
- * \param depth_range: distances of clipe plane min and clip plane max;
+ * \param snapdata: struct generated in `get_snapdata`.
+ * \param snap_select : from enum SnapSelect.
+ * \param use_object_edit_cage : Uses the coordinates of BMesh(if any) to do the snapping.
*
* Read/Write Args
* ---------------
@@ -1846,96 +2097,33 @@ static bool snapObject(
* (currently only set to the polygon index when when using ``snap_to == SCE_SNAP_MODE_FACE``).
* \param r_ob: Hit object.
* \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances).
- * \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
*
*/
static bool snapObjectsRay(
- SnapObjectContext *sctx,
- const unsigned short snap_to, const SnapSelect snap_select,
- const bool use_object_edit_cage, const float mval[2],
- const float ray_origin[3], const float ray_start[3], const float ray_normal[3],
- const float depth_range[2],
+ SnapObjectContext *sctx, SnapData *snapdata,
+ const SnapSelect snap_select, const bool use_object_edit_cage,
/* read/write args */
float *ray_depth, float *dist_px,
/* return args */
- float r_loc[3], float r_no[3], int *r_index,
- Object **r_ob, float r_obmat[4][4],
- ListBase *r_hit_list)
+ float r_loc[3], float r_no[3],
+ Object **r_ob, float r_obmat[4][4])
{
- bool retval = false;
-
- unsigned int ob_index = 0;
Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL;
- /* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA
- * which makes the loop skip it, even the derived mesh will never change
- *
- * To solve that problem, we do it first as an exception.
- * */
- Base *base_act = sctx->scene->basact;
- if (base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT) {
- Object *ob = base_act->object;
-
- retval |= snapObject(
- sctx, ob, ob->obmat, ob_index++,
- false, snap_to, mval,
- ray_origin, ray_start, ray_normal, depth_range,
- ray_depth, dist_px,
- r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
- }
-
- bool ignore_object_selected = false, ignore_object_active = false;
- switch (snap_select) {
- case SNAP_ALL:
- break;
- case SNAP_NOT_SELECTED:
- ignore_object_selected = true;
- break;
- case SNAP_NOT_ACTIVE:
- ignore_object_active = true;
- break;
- }
- 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_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 &&
-
- !((ignore_object_selected && (base->flag & (SELECT | BA_WAS_SEL))) ||
- (ignore_object_active && base == base_act)))
- {
- Object *ob = base->object;
-
- if (ob->transflag & OB_DUPLI) {
- DupliObject *dupli_ob;
- ListBase *lb = object_duplilist(sctx->bmain->eval_ctx, sctx->scene, ob);
-
- for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
- bool use_obedit_dupli = (obedit && dupli_ob->ob->data == obedit->data);
- Object *dupli_snap = (use_obedit_dupli) ? obedit : dupli_ob->ob;
-
- retval |= snapObject(
- sctx, dupli_snap, dupli_ob->mat, ob_index++,
- use_obedit_dupli, snap_to, mval,
- ray_origin, ray_start, ray_normal, depth_range,
- ray_depth, dist_px,
- r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
- }
-
- free_object_duplilist(lb);
- }
-
- bool use_obedit = (obedit != NULL) && (ob->data == obedit->data);
- Object *ob_snap = use_obedit ? obedit : ob;
+ 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_obmat = r_obmat,
+ .ret = false,
+ };
- retval |= snapObject(
- sctx, ob_snap, ob->obmat, ob_index++,
- use_obedit, snap_to, mval,
- ray_origin, ray_start, ray_normal, depth_range,
- ray_depth, dist_px,
- r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
- }
- }
+ iter_snap_objects(sctx, snap_select, obedit, sanp_obj_cb, &data);
- return retval;
+ return data.ret;
}
/** \} */
@@ -1947,7 +2135,7 @@ static bool snapObjectsRay(
* \{ */
SnapObjectContext *ED_transform_snap_object_context_create(
- Main *bmain, Scene *scene, int flag)
+ Main *bmain, Scene *scene, SceneLayer *sl, int flag)
{
SnapObjectContext *sctx = MEM_callocN(sizeof(*sctx), __func__);
@@ -1955,26 +2143,25 @@ SnapObjectContext *ED_transform_snap_object_context_create(
sctx->bmain = bmain;
sctx->scene = scene;
+ sctx->scene_layer = sl;
+
+ sctx->cache.object_map = BLI_ghash_ptr_new(__func__);
+ sctx->cache.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
return sctx;
}
SnapObjectContext *ED_transform_snap_object_context_create_view3d(
- Main *bmain, Scene *scene, int flag,
+ Main *bmain, Scene *scene, SceneLayer *sl, 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, sl, flag);
sctx->use_v3d = true;
sctx->v3d_data.ar = ar;
sctx->v3d_data.v3d = v3d;
- if (sctx->flag & SNAP_OBJECT_USE_CACHE) {
- sctx->cache.object_map = BLI_ghash_ptr_new(__func__);
- sctx->cache.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- }
-
return sctx;
}
@@ -1989,6 +2176,9 @@ static void snap_object_data_free(void *sod_v)
free_bvhtree_from_mesh(sod->bvh_trees[i]);
}
}
+ if (sod->poly_allocated) {
+ MEM_freeN(sod->mpoly);
+ }
break;
}
case SNAP_EDIT_MESH:
@@ -2006,10 +2196,8 @@ static void snap_object_data_free(void *sod_v)
void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx)
{
- if (sctx->flag & SNAP_OBJECT_USE_CACHE) {
- BLI_ghash_free(sctx->cache.object_map, NULL, snap_object_data_free);
- BLI_memarena_free(sctx->cache.mem_arena);
- }
+ BLI_ghash_free(sctx->cache.object_map, NULL, snap_object_data_free);
+ BLI_memarena_free(sctx->cache.mem_arena);
MEM_freeN(sctx);
}
@@ -2030,7 +2218,6 @@ void ED_transform_snap_object_context_set_editmesh_callbacks(
bool ED_transform_snap_object_project_ray_ex(
SnapObjectContext *sctx,
- const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3],
float *ray_depth,
@@ -2038,12 +2225,12 @@ bool ED_transform_snap_object_project_ray_ex(
Object **r_ob, float r_obmat[4][4])
{
const float depth_range[2] = {0.0f, FLT_MAX};
- return snapObjectsRay(
+
+ return raycastObjects(
sctx,
- snap_to, params->snap_select, params->use_object_edit_cage, NULL,
ray_start, ray_start, ray_normal, depth_range,
- ray_depth, NULL,
- r_loc, r_no, r_index, r_ob, r_obmat, NULL);
+ params->snap_select, params->use_object_edit_cage,
+ ray_depth, r_loc, r_no, r_index, r_ob, r_obmat, NULL);
}
/**
@@ -2055,7 +2242,6 @@ bool ED_transform_snap_object_project_ray_ex(
*/
bool ED_transform_snap_object_project_ray_all(
SnapObjectContext *sctx,
- const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3],
float ray_depth, bool sort,
@@ -2070,12 +2256,11 @@ bool ED_transform_snap_object_project_ray_all(
float ray_depth_prev = ray_depth;
#endif
- bool retval = snapObjectsRay(
+ bool retval = raycastObjects(
sctx,
- snap_to, params->snap_select, params->use_object_edit_cage, NULL,
ray_start, ray_start, ray_normal, depth_range,
- &ray_depth, NULL,
- NULL, NULL, NULL, NULL, NULL,
+ params->snap_select, params->use_object_edit_cage,
+ &ray_depth, NULL, NULL, NULL, NULL, NULL,
r_hit_list);
/* meant to be readonly for 'all' hits, ensure it is */
@@ -2108,7 +2293,6 @@ static bool transform_snap_context_project_ray_impl(
/* try snap edge, then face if it fails */
ret = ED_transform_snap_object_project_ray_ex(
sctx,
- SCE_SNAP_MODE_FACE,
params,
ray_start, ray_normal, ray_depth,
r_co, r_no, NULL,
@@ -2152,19 +2336,40 @@ static bool transform_snap_context_project_view3d_mixed_impl(
BLI_assert(snap_to_flag != 0);
BLI_assert((snap_to_flag & ~(1 | 2 | 4)) == 0);
- for (int i = 0; i < 3; i++) {
- if ((snap_to_flag & (1 << i)) && (is_hit == false || use_depth)) {
- if (use_depth == false) {
- ray_depth = BVH_RAYCAST_DIST_MAX;
+ 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;
+ }
}
-
- if (ED_transform_snap_object_project_view3d(
- sctx,
- elem_type[i], params,
- mval, dist_px, &ray_depth,
- r_co, r_no))
- {
- is_hit = true;
+ }
+ }
+ 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;
+ }
}
}
}
@@ -2233,12 +2438,24 @@ bool ED_transform_snap_object_project_view3d_ex(
ray_depth = &ray_depth_fallback;
}
- return snapObjectsRay(
- sctx,
- snap_to, params->snap_select, params->use_object_edit_cage,
- mval, ray_origin, ray_start, ray_normal, depth_range,
- ray_depth, dist_px,
- r_loc, r_no, r_index, NULL, NULL, NULL);
+ if (snap_to == SCE_SNAP_MODE_FACE) {
+ return raycastObjects(
+ sctx,
+ ray_origin, ray_start, ray_normal, depth_range,
+ params->snap_select, params->use_object_edit_cage,
+ ray_depth, r_loc, r_no, r_index, NULL, NULL, 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, NULL, NULL);
+ }
}
bool ED_transform_snap_object_project_view3d(
@@ -2279,7 +2496,6 @@ bool ED_transform_snap_object_project_all_view3d_ex(
return ED_transform_snap_object_project_ray_all(
sctx,
- SCE_SNAP_MODE_FACE,
params,
ray_start, ray_normal, ray_depth, sort,
r_hit_list);
diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt
index c0b30f93939..71a3322cb50 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
@@ -64,6 +65,7 @@ set(SRC
../include/ED_lattice.h
../include/ED_logic.h
../include/ED_markers.h
+ ../include/ED_manipulator_library.h
../include/ED_mask.h
../include/ED_mball.h
../include/ED_mesh.h
@@ -75,6 +77,7 @@ 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
diff --git a/source/blender/editors/util/ed_transverts.c b/source/blender/editors/util/ed_transverts.c
index b0970cdfd48..872810c5cf2 100644
--- a/source/blender/editors/util/ed_transverts.c
+++ b/source/blender/editors/util/ed_transverts.c
@@ -39,12 +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 "DEG_depsgraph.h"
+
#include "ED_armature.h"
#include "ED_transverts.h" /* own include */
@@ -56,7 +57,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);
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index baea74b9d1c..13822c658bf 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -71,6 +71,8 @@
#include "ED_space_api.h"
#include "ED_util.h"
+#include "GPU_immediate.h"
+
#include "UI_interface.h"
#include "UI_resources.h"
@@ -87,7 +89,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;
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *ob, *obact = (sl && sl->basact) ? sl->basact->object : NULL;
ID *data;
/* This is called during initialization, so we don't want to store any reports */
@@ -102,12 +105,15 @@ void ED_editors_init(bContext *C)
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;
+ if (mode == OB_MODE_OBJECT) {
+ /* pass */
+ }
+ else {
data = ob->data;
-
- if (ob == obact && !ID_IS_LINKED_DATABLOCK(ob) && !(data && ID_IS_LINKED_DATABLOCK(data)))
+ ob->mode = OB_MODE_OBJECT;
+ if ((ob == obact) && !ID_IS_LINKED_DATABLOCK(ob) && !(data && ID_IS_LINKED_DATABLOCK(data))) {
ED_object_toggle_modes(C, mode);
+ }
}
}
@@ -325,16 +331,28 @@ 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 = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniform1i("num_colors", 0); /* "simple" mode */
+ immUniformThemeColor(TH_VIEW_OVERLAY);
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2fv(shdr_pos, mval_src);
+ immVertex2fv(shdr_pos, mval_dst);
+ immEnd();
+
+ immUnbindProgram();
}
/**
diff --git a/source/blender/editors/util/editmode_undo.c b/source/blender/editors/util/editmode_undo.c
index d35cdf56413..7f3ac1cdcda 100644
--- a/source/blender/editors/util/editmode_undo.c
+++ b/source/blender/editors/util/editmode_undo.c
@@ -42,9 +42,10 @@
#include "BKE_blender_undo.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
+#include "DEG_depsgraph.h"
+
#include "ED_util.h"
#include "ED_mesh.h"
@@ -278,7 +279,7 @@ void undo_editmode_step(bContext *C, int step)
EDBM_selectmode_to_scene(C);
}
- DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
/* XXX notifiers */
}
diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c
index e07831358d6..61142fdc887 100644
--- a/source/blender/editors/util/numinput.c
+++ b/source/blender/editors/util/numinput.c
@@ -296,7 +296,7 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
}
/* Else, common behavior with DELKEY, only difference is remove char(s) before/after the cursor. */
dir = STRCUR_DIR_PREV;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case DELKEY:
if ((n->val_flag[idx] & NUM_EDITED) && n->str[0]) {
int t_cur = cur = n->str_cur;
@@ -322,7 +322,7 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
break;
case LEFTARROWKEY:
dir = STRCUR_DIR_PREV;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case RIGHTARROWKEY:
cur = n->str_cur;
if (event->ctrl) {
@@ -497,7 +497,7 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
n->unit_sys, n->unit_type[idx]);
/* Note: with angles, we always get values as radians here... */
- if (BPY_execute_string_as_number(C, str_unit_convert, &val, false)) {
+ if (BPY_execute_string_as_number(C, str_unit_convert, false, &val)) {
n->val[idx] = (float)val;
n->val_flag[idx] &= ~NUM_INVALID;
}
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
index cb87cd80fa2..bd180789cbe 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -102,7 +102,7 @@ void ED_undo_push(bContext *C, const char *str)
else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
if (U.undosteps == 0) return;
- PE_undo_push(CTX_data_scene(C), str);
+ PE_undo_push(CTX_data_scene(C), CTX_data_scene_layer(C), str);
}
else if (obact && obact->mode & OB_MODE_HAIR_EDIT) {
undo_push_strands(C, str);
@@ -124,6 +124,7 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
wmWindow *win = CTX_wm_window(C);
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Object *obedit = CTX_data_edit_object(C);
Object *obact = CTX_data_active_object(C);
ScrArea *sa = CTX_wm_area(C);
@@ -184,9 +185,9 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
}
else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
if (step == 1)
- PE_undo(scene);
+ PE_undo(scene, sl);
else
- PE_redo(scene);
+ PE_redo(scene, sl);
}
else if (obact && obact->mode & OB_MODE_HAIR_EDIT) {
if (undoname)
@@ -229,6 +230,19 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
return OPERATOR_FINISHED;
}
+void ED_undo_grouped_push(bContext *C, const char *str)
+{
+ /* do nothing if previous undo task is the same as this one (or from the same undo group) */
+ const char *last_undo = BKE_undo_get_name_last();
+
+ if (last_undo && STREQ(str, last_undo)) {
+ return;
+ }
+
+ /* push as usual */
+ ED_undo_push(C, str);
+}
+
void ED_undo_pop(bContext *C)
{
ed_undo_step(C, 1, NULL);
@@ -244,6 +258,16 @@ void ED_undo_push_op(bContext *C, wmOperator *op)
ED_undo_push(C, op->type->name);
}
+void ED_undo_grouped_push_op(bContext *C, wmOperator *op)
+{
+ if (op->type->undo_group[0] != '\0') {
+ ED_undo_grouped_push(C, op->type->undo_group);
+ }
+ else {
+ ED_undo_grouped_push(C, op->type->name);
+ }
+}
+
void ED_undo_pop_op(bContext *C, wmOperator *op)
{
/* search back a couple of undo's, in case something else added pushes */
@@ -286,7 +310,7 @@ bool ED_undo_is_valid(const bContext *C, const char *undoname)
return 1;
}
else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
- return PE_undo_is_valid(CTX_data_scene(C));
+ return PE_undo_is_valid(CTX_data_scene(C), CTX_data_scene_layer(C));
}
if (U.uiflag & USER_GLOBALUNDO) {
@@ -316,6 +340,19 @@ static int ed_redo_exec(bContext *C, wmOperator *UNUSED(op))
return ed_undo_step(C, -1, NULL);
}
+static int ed_undo_redo_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ wmOperator *last_op = WM_operator_last_redo(C);
+ const int ret = ED_undo_operator_repeat(C, last_op);
+ return ret ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
+
+static int ed_undo_redo_poll(bContext *C)
+{
+ wmOperator *last_op = WM_operator_last_redo(C);
+ return last_op && ED_operator_screenactive(C) &&
+ WM_operator_check_ui_enabled(C, last_op->type->name);
+}
/* ********************** */
@@ -358,6 +395,17 @@ void ED_OT_redo(wmOperatorType *ot)
ot->poll = ED_operator_screenactive;
}
+void ED_OT_undo_redo(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Undo and Redo";
+ ot->description = "Undo and redo previous action";
+ ot->idname = "ED_OT_undo_redo";
+
+ /* api callbacks */
+ ot->exec = ed_undo_redo_exec;
+ ot->poll = ed_undo_redo_poll;
+}
/* ui callbacks should call this rather than calling WM_operator_repeat() themselves */
int ED_undo_operator_repeat(bContext *C, struct wmOperator *op)
@@ -390,6 +438,9 @@ int ED_undo_operator_repeat(bContext *C, struct wmOperator *op)
if (G.debug & G_DEBUG)
printf("redo_cb: operator redo %s\n", op->type->name);
+
+ WM_operator_free_all_after(wm, op);
+
ED_undo_pop_op(C, op);
if (op->type->check) {
@@ -504,7 +555,7 @@ static EnumPropertyItem *rna_undo_itemf(bContext *C, int undosys, int *totitem)
const char *name = NULL;
if (undosys == UNDOSYSTEM_PARTICLE) {
- name = PE_undo_get_name(CTX_data_scene(C), i, &active);
+ name = PE_undo_get_name(CTX_data_scene(C), CTX_data_scene_layer(C), i, &active);
}
else if (undosys == UNDOSYSTEM_EDITMODE) {
name = undo_editmode_get_name(C, i, &active);
@@ -587,7 +638,7 @@ static int undo_history_exec(bContext *C, wmOperator *op)
int item = RNA_int_get(op->ptr, "item");
if (undosys == UNDOSYSTEM_PARTICLE) {
- PE_undo_number(CTX_data_scene(C), item);
+ PE_undo_number(CTX_data_scene(C), CTX_data_scene_layer(C), item);
}
else if (undosys == UNDOSYSTEM_EDITMODE) {
undo_editmode_number(C, item + 1);
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 ab415c0cb83..6b4dd0f0210 100644
--- a/source/blender/editors/uvedit/uvedit_buttons.c
+++ b/source/blender/editors/uvedit/uvedit_buttons.c
@@ -66,17 +66,14 @@ static int uvedit_center(Scene *scene, BMEditMesh *em, Image *ima, float center[
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, ima, f))
continue;
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
@@ -102,14 +99,11 @@ static void uvedit_translate(Scene *scene, BMEditMesh *em, Image *ima, float del
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, ima, f))
continue;
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index 94d69a0169f..1e557236bfd 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"
@@ -52,9 +54,15 @@
#include "BKE_scene.h"
-#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+
#include "ED_image.h"
#include "ED_mesh.h"
#include "ED_uvedit.h"
@@ -65,12 +73,7 @@
#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);
+static void draw_uvs_lineloop_bmface(BMFace *efa, const int cd_loop_uv_offset, const uint shdr_pos);
void ED_image_draw_cursor(ARegion *ar, const float cursor[2])
{
@@ -81,38 +84,59 @@ void ED_image_draw_cursor(ARegion *ar, const float cursor[2])
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);
+
+ gpuTranslate2fv(cursor);
+
+ const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniform1i("num_colors", 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);
+
+ immBegin(GWN_PRIM_LINES, 8);
+
+ immVertex2f(shdr_pos, -0.05f * x_fac, 0.0f);
+ immVertex2f(shdr_pos, 0.0f, 0.05f * y_fac);
+
+ immVertex2f(shdr_pos, 0.0f, 0.05f * y_fac);
+ immVertex2f(shdr_pos, 0.05f * x_fac, 0.0f);
+
+ immVertex2f(shdr_pos, 0.05f * x_fac, 0.0f);
+ immVertex2f(shdr_pos, 0.0f, -0.05f * y_fac);
+
+ immVertex2f(shdr_pos, 0.0f, -0.05f * y_fac);
+ immVertex2f(shdr_pos, -0.05f * x_fac, 0.0f);
+
+ immEnd();
+
+ 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);
+
+ immBegin(GWN_PRIM_LINES, 8);
+
+ immVertex2f(shdr_pos, -0.020f * x_fac, 0.0f);
+ immVertex2f(shdr_pos, -0.1f * x_fac, 0.0f);
+
+ immVertex2f(shdr_pos, 0.1f * x_fac, 0.0f);
+ immVertex2f(shdr_pos, 0.020f * x_fac, 0.0f);
+
+ immVertex2f(shdr_pos, 0.0f, -0.020f * y_fac);
+ immVertex2f(shdr_pos, 0.0f, -0.1f * y_fac);
+
+ immVertex2f(shdr_pos, 0.0f, 0.1f * y_fac);
+ immVertex2f(shdr_pos, 0.0f, 0.020f * y_fac);
+
+ immEnd();
+
+ immUnbindProgram();
+
+ gpuTranslate2f(-cursor[0], -cursor[1]);
}
static int draw_uvs_face_check(Scene *scene)
@@ -141,41 +165,32 @@ static void draw_uvs_shadow(Object *obedit)
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
- /* draws the mesh when painting */
- UI_ThemeColor(TH_UV_SHADOW);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset);
- }
-}
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-static int draw_uvs_dm_shadow(DerivedMesh *dm)
-{
- /* draw shadow mesh - this is the mesh with the modifier applied */
+ /* draws the mesh when painting */
+ immUniformThemeColor(TH_UV_SHADOW);
- if (dm && dm->drawUVEdges && CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) {
- UI_ThemeColor(TH_UV_SHADOW);
- dm->drawUVEdges(dm);
- return 1;
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, pos);
}
- return 0;
+ immUnbindProgram();
}
-static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTexPoly *activetf)
+static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, const BMFace *efa_act)
{
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);
@@ -191,7 +206,6 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
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);
@@ -203,28 +217,37 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
totarea += BM_face_calc_area(efa);
totuvarea += area_poly_v2((const float (*)[2])tf_uv, efa->len);
- if (uvedit_face_visible_test(scene, ima, efa, tf)) {
+ if (uvedit_face_visible_test(scene, ima, efa)) {
BM_elem_flag_enable(efa, BM_ELEM_TAG);
}
else {
- if (tf == activetf)
- activetf = NULL;
+ if (efa == efa_act) {
+ efa_act = NULL;
+ }
BM_elem_flag_disable(efa, BM_ELEM_TAG);
}
}
-
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
if (totarea < FLT_EPSILON || totuvarea < FLT_EPSILON) {
col[0] = 1.0;
col[1] = col[2] = 0.0;
- glColor3fv(col);
+
+ immUniformColor3fv(col);
+
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- glBegin(GL_POLYGON);
+ immBegin(GWN_PRIM_TRI_FAN, efa->len);
+
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);
+ immVertex2fv(pos, luv->uv);
}
- glEnd();
+
+ immEnd();
}
}
}
@@ -254,18 +277,23 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
areadiff = 1.0f - (area / uvarea);
weight_to_rgb(col, areadiff);
- glColor3fv(col);
+ immUniformColor3fv(col);
- /* TODO: USE_EDBM_LOOPTRIS */
- glBegin(GL_POLYGON);
+ /* TODO: use editmesh tessface */
+ immBegin(GWN_PRIM_TRI_FAN, efa->len);
+
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);
+ immVertex2fv(pos, luv->uv);
}
- glEnd();
+
+ immEnd();
}
}
}
+
+ immUnbindProgram();
+
break;
}
case SI_UVDT_STRETCH_ANGLE:
@@ -278,11 +306,15 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
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 */
-
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+
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)) {
+ if (uvedit_face_visible_test(scene, ima, efa)) {
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);
@@ -319,24 +351,26 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
ang[i] = angle_normalized_v3v3(av[i], av[(i + 1) % efa_len]);
}
- /* TODO: USE_EDBM_LOOPTRIS */
- glBegin(GL_POLYGON);
+ /* TODO: use editmesh tessface */
+ immBegin(GWN_PRIM_TRI_FAN, efa->len);
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);
+ immAttrib3fv(color, col);
+ immVertex2fv(pos, luv->uv);
}
- glEnd();
+ immEnd();
}
else {
- if (tf == activetf)
- activetf = NULL;
+ if (efa == efa_act)
+ efa_act = NULL;
BM_elem_flag_disable(efa, BM_ELEM_TAG);
}
}
+ immUnbindProgram();
+
BLI_buffer_free(&uvang_buf);
BLI_buffer_free(&ang_buf);
BLI_buffer_free(&av_buf);
@@ -350,53 +384,74 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
BLI_buffer_free(&tf_uvorig_buf);
}
-static void draw_uvs_lineloop_bmface(BMFace *efa, const int cd_loop_uv_offset)
+static void draw_uvs_lineloop_bmface(BMFace *efa, const int cd_loop_uv_offset, const uint shdr_pos)
{
BMIter liter;
BMLoop *l;
MLoopUV *luv;
- glBegin(GL_LINE_LOOP);
+ immBegin(GWN_PRIM_LINE_LOOP, efa->len);
+
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);
+ immVertex2fv(shdr_pos, luv->uv);
}
- glEnd();
+
+ immEnd();
}
-static void draw_uvs_lineloop_mpoly(Mesh *me, MPoly *mpoly)
+static void draw_uvs_lineloop_mpoly(Mesh *me, MPoly *mpoly, unsigned int pos)
{
MLoopUV *mloopuv;
int i;
- glBegin(GL_LINE_LOOP);
+ immBegin(GWN_PRIM_LINE_LOOP, mpoly->totloop);
+
mloopuv = &me->mloopuv[mpoly->loopstart];
for (i = mpoly->totloop; i != 0; i--, mloopuv++) {
- glVertex2fv(mloopuv->uv);
+ immVertex2fv(pos, mloopuv->uv);
}
- glEnd();
+
+ immEnd();
}
-static void draw_uvs_other_mesh_texface(Object *ob, const Image *curimage)
+static void draw_uvs_other_mesh_texface(Object *ob, const Image *curimage, const int other_uv_filter, unsigned int pos)
{
Mesh *me = ob->data;
MPoly *mpoly = me->mpoly;
- MTexPoly *mtpoly = me->mtpoly;
int a;
if (me->mloopuv == NULL) {
return;
}
- for (a = me->totpoly; a != 0; a--, mpoly++, mtpoly++) {
- if (mtpoly->tpage != curimage) {
- continue;
+ Image **image_array = NULL;
+
+ if (other_uv_filter == SI_FILTER_SAME_IMAGE) {
+ image_array = BKE_object_material_edit_image_get_array(ob);
+ }
+
+ 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) {
+ if (mpoly[a].mat_nr >= ob->totcol) {
+ continue;
+ }
+ if (image_array[mpoly[a].mat_nr] != curimage) {
+ continue;
+ }
}
- draw_uvs_lineloop_mpoly(me, mpoly);
+ draw_uvs_lineloop_mpoly(me, mpoly, pos);
+ }
+
+ if (image_array) {
+ MEM_freeN(image_array);
}
}
-static void draw_uvs_other_mesh_new_shading(Object *ob, const Image *curimage)
+static void draw_uvs_other_mesh_new_shading(Object *ob, const Image *curimage, const int other_uv_filter, unsigned int pos)
{
Mesh *me = ob->data;
MPoly *mpoly = me->mpoly;
@@ -436,46 +491,55 @@ static void draw_uvs_other_mesh_new_shading(Object *ob, const Image *curimage)
}
for (a = me->totpoly; a != 0; a--, mpoly++) {
- const int mat_nr = mpoly->mat_nr;
- if ((mat_nr >= totcol) ||
- (BLI_BITMAP_TEST(mat_test_array, mat_nr)) == 0)
- {
- continue;
+ 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;
+ }
}
- draw_uvs_lineloop_mpoly(me, mpoly);
+ draw_uvs_lineloop_mpoly(me, mpoly, pos);
}
}
-static void draw_uvs_other_mesh(Object *ob, const Image *curimage, const bool new_shading_nodes)
+static void draw_uvs_other_mesh(Object *ob, const Image *curimage, const bool new_shading_nodes,
+ const int other_uv_filter, unsigned int pos)
{
if (new_shading_nodes) {
- draw_uvs_other_mesh_new_shading(ob, curimage);
+ draw_uvs_other_mesh_new_shading(ob, curimage, other_uv_filter, pos);
}
else {
- draw_uvs_other_mesh_texface(ob, curimage);
+ draw_uvs_other_mesh_texface(ob, curimage, other_uv_filter, pos);
}
}
-static void draw_uvs_other(Scene *scene, Object *obedit, const Image *curimage, const bool new_shading_nodes)
+static void draw_uvs_other(SceneLayer *sl, Object *obedit, const Image *curimage, const bool new_shading_nodes,
+ const int other_uv_filter)
{
- Base *base;
-
- UI_ThemeColor(TH_UV_OTHERS);
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
- for (base = scene->base.first; base; base = base->next) {
- Object *ob = base->object;
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- if (!(base->flag & SELECT)) continue;
- if (!(base->lay & scene->lay)) continue;
- if (ob->restrictflag & OB_RESTRICT_VIEW) continue;
+ immUniformThemeColor(TH_UV_OTHERS);
- if ((ob->type == OB_MESH) && (ob != obedit) && ((Mesh *)ob->data)->mloopuv) {
- draw_uvs_other_mesh(ob, curimage, new_shading_nodes);
+ for (Base *base = sl->object_bases.first; base; base = base->next) {
+ if (((base->flag & BASE_SELECTED) != 0) &&
+ ((base->flag & BASE_VISIBLED) != 0))
+ {
+ Object *ob = base->object;
+ if ((ob->type == OB_MESH) && (ob != obedit) && ((Mesh *)ob->data)->mloopuv) {
+ draw_uvs_other_mesh(ob, curimage, new_shading_nodes, other_uv_filter, pos);
+ }
}
}
+ immUnbindProgram();
}
-static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, Object *ob)
+static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, SceneLayer *sl, Object *ob)
{
const bool new_shading_nodes = BKE_scene_use_new_shading_nodes(scene);
Image *curimage = ED_space_image(sima);
@@ -483,14 +547,12 @@ static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, Object *ob)
Material *ma;
if (sima->flag & SI_DRAW_OTHER) {
- draw_uvs_other(scene, ob, curimage, new_shading_nodes);
+ draw_uvs_other(sl, ob, curimage, new_shading_nodes, sima->other_uv_filter);
}
- UI_ThemeColor(TH_UV_SHADOW);
-
ma = give_current_material(ob, ob->actcol);
- if (me->mtpoly) {
+ if (me->mloopuv) {
MPoly *mpoly = me->mpoly;
MLoopUV *mloopuv, *mloopuv_base;
int a, b;
@@ -500,24 +562,33 @@ static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, Object *ob)
mloopuv = me->mloopuv;
}
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformThemeColor(TH_UV_SHADOW);
+
mloopuv_base = mloopuv;
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);
+
+ immBegin(GWN_PRIM_LINE_LOOP, mpoly->totloop);
mloopuv = mloopuv_base + mpoly->loopstart;
for (b = 0; b < mpoly->totloop; b++, mloopuv++) {
- glVertex2fv(mloopuv->uv);
+ immVertex2fv(pos, mloopuv->uv);
}
- glEnd();
+
+ immEnd();
}
+
+ immUnbindProgram();
}
}
-#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_looptri(BMEditMesh *em, unsigned int *r_loop_index, const int cd_loop_uv_offset, unsigned int pos)
{
unsigned int i = *r_loop_index;
BMFace *f = em->looptris[i][0]->f;
@@ -525,16 +596,15 @@ static void draw_uvs_looptri(BMEditMesh *em, unsigned int *r_loop_index, const i
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);
+ immVertex2fv(pos, luv->uv);
}
i++;
} while (i != em->tottri && (f == em->looptris[i][0]->f));
*r_loop_index = i - 1;
}
-#endif
/* draws uv's in the image space */
-static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
+static void draw_uvs(SpaceImage *sima, Scene *scene, SceneLayer *sl, Object *obedit, Depsgraph *depsgraph)
{
const bool new_shading_nodes = BKE_scene_use_new_shading_nodes(scene);
ToolSettings *ts;
@@ -542,26 +612,19 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
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);
- activetf = EDBM_mtexpoly_active_get(em, &efa_act, false, false); /* will be set to NULL if hidden */
-#ifndef USE_EDBM_LOOPTRIS
- activef = BM_mesh_active_face_get(bm, false, false);
-#endif
+ unsigned int pos;
+
+ efa_act = EDBM_uv_active_face_get(em, false, false); /* will be set to NULL if hidden */
ts = scene->toolsettings;
drawfaces = draw_uvs_face_check(scene);
@@ -583,38 +646,30 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
}
}
else {
- curimage = (activetf) ? activetf->tpage : ima;
+ curimage = (efa_act) ? BKE_object_material_edit_image_get(obedit, efa_act->mat_nr) : ima;
}
- draw_uvs_other(scene, obedit, curimage, new_shading_nodes);
+ draw_uvs_other(sl, obedit, curimage, new_shading_nodes, sima->other_uv_filter);
}
/* 1. draw shadow mesh */
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);
+ Object *ob_cage = DEG_get_evaluated_object(depsgraph, obedit);
+ /* XXX TODO: Need to check if shadow mesh is different than original mesh. */
+ bool is_cage_like_final_meshes = (ob_cage == obedit);
+
+ /* 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) == 0) || is_cage_like_final_meshes) {
+ draw_uvs_shadow(ob_cage);
}
}
-
+
/* 2. draw colored faces */
if (sima->flag & SI_DRAW_STRETCH) {
- draw_uvs_stretch(sima, scene, em, activetf);
+ draw_uvs_stretch(sima, scene, em, efa_act);
}
else if (!(sima->flag & SI_NO_DRAWFACES)) {
/* draw transparent faces */
@@ -623,79 +678,47 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
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);
+ pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
- 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));
- }
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- glBegin(GL_TRIANGLES);
- draw_uvs_looptri(em, &i, cd_loop_uv_offset);
- glEnd();
+ for (unsigned int i = 0; i < em->tottri; i++) {
+ efa = em->looptris[i][0]->f;
+ if (uvedit_face_visible_test(scene, ima, efa)) {
+ 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) {
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- }
+ if (efa == efa_act) {
+ /* only once */
+ immUniformThemeColor(TH_EDITMESH_ACTIVE);
}
else {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ immUniformColor4ubv(is_select ? col2 : col1);
}
- }
- }
-#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();
+ immBegin(GWN_PRIM_TRIS, (em->looptris[i][0]->f->len - 2) * 3);
+ draw_uvs_looptri(em, &i, cd_loop_uv_offset, pos);
+ immEnd();
}
else {
- if (tf == activetf)
- activetf = NULL;
BM_elem_flag_disable(efa, BM_ELEM_TAG);
}
}
-#endif
+
+ immUnbindProgram();
+
glDisable(GL_BLEND);
}
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)) {
+ if (uvedit_face_visible_test(scene, ima, efa)) {
BM_elem_flag_enable(efa, BM_ELEM_TAG);
}
else {
- if (tf == activetf)
- activetf = NULL;
+ if (efa == efa_act)
+ efa_act = NULL;
BM_elem_flag_disable(efa, BM_ELEM_TAG);
}
}
@@ -703,30 +726,8 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
}
/* 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();
+ /* (removed during OpenGL upgrade, reimplement if needed) */
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- glDisable(GL_BLEND);
- }
- }
-#endif
-
/* 4. draw edges */
if (sima->flag & SI_SMOOTH_UV) {
@@ -739,104 +740,150 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
switch (sima->dt_uv) {
case SI_UVDT_DASH:
+ {
+ const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniform1i("num_colors", 2); /* "advanced" mode */
+ immUniformArray4fv("colors", (float *)(float[][4]){{0.56f, 0.56f, 0.56f, 1.0f}, {0.07f, 0.07f, 0.07f, 1.0f}}, 2);
+ immUniform1f("dash_width", 4.0f);
+
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);
- if (tf) {
- cpack(0x111111);
+ draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, shdr_pos);
+ }
- draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset);
+ immUnbindProgram();
- setlinestyle(2);
- cpack(0x909090);
+ break;
+ }
+ case SI_UVDT_BLACK: /* black/white */
+ case SI_UVDT_WHITE:
+ pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
- draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- setlinestyle(0);
- }
+ if (sima->dt_uv == SI_UVDT_WHITE) {
+ immUniformColor3f(1.0f, 1.0f, 1.0f);
+ }
+ else {
+ immUniformColor3f(0.0f, 0.0f, 0.0f);
}
- 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);
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);
+ draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, pos);
}
+
+ immUnbindProgram();
+
break;
case SI_UVDT_OUTLINE:
+ pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
glLineWidth(3);
- cpack(0x0);
-
+ imm_cpack(0x0);
+
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);
+ draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, pos);
}
-
+
+ immUnbindProgram();
+
glLineWidth(1);
UI_GetThemeColor4ubv(TH_WIRE_EDIT, col2);
- glColor4ubv((unsigned char *)col2);
if (me->drawflag & ME_DRAWEDGES) {
- int sel, lastsel = -1;
+ int sel;
UI_GetThemeColor4ubv(TH_EDGE_SELECT, col1);
+ Gwn_VertFormat *format = immVertexFormat();
+ pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
if (interpedges) {
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_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);
+ immBegin(GWN_PRIM_LINE_LOOP, efa->len);
+
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);
+ immAttrib4ubv(color, sel ? (GLubyte *)col1 : (GLubyte *)col2);
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- glVertex2fv(luv->uv);
+ immVertex2fv(pos, luv->uv);
}
- glEnd();
+
+ immEnd();
}
+
+ immUnbindProgram();
}
else {
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ int lastsel = -1;
+
if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
continue;
- glBegin(GL_LINES);
+ immBegin(GWN_PRIM_LINES, efa->len * 2);
+
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);
+ immAttrib4ubv(color, sel ? (GLubyte *)col1 : (GLubyte *)col2);
lastsel = sel;
}
+
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- glVertex2fv(luv->uv);
+ immVertex2fv(pos, luv->uv);
luv = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
- glVertex2fv(luv->uv);
+ immVertex2fv(pos, luv->uv);
}
- glEnd();
+
+ immEnd();
}
+
+ immUnbindProgram();
}
}
else {
+ pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4ubv(col2);
+
/* 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);
+ draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, pos);
}
+
+ immUnbindProgram();
}
-
+
break;
}
@@ -849,50 +896,80 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
if (drawfaces) {
float cent[2];
-
+ bool col_set = false;
+
+ Gwn_VertFormat *format = immVertexFormat();
+ pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+
pointsize = UI_GetThemeValuef(TH_FACEDOT_SIZE);
glPointSize(pointsize);
- glBegin(GL_POINTS);
+ immBeginAtMost(GWN_PRIM_POINTS, bm->totface);
/* 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)) {
+ /* Only set color for the first face */
+ if (!col_set) {
+ UI_GetThemeColor3ubv(TH_WIRE, col1);
+ immAttrib3ubv(color, col1);
+
+ col_set = true;
+ }
+
uv_poly_center(efa, cent, cd_loop_uv_offset);
- glVertex2fv(cent);
+ immVertex2fv(pos, cent);
}
}
+ col_set = false;
+
/* 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)) {
+ /* Only set color for the first face */
+ if (!col_set) {
+ UI_GetThemeColor3ubv(TH_FACE_DOT, col1);
+ immAttrib3ubv(color, col1);
+
+ col_set = true;
+ }
+
uv_poly_center(efa, cent, cd_loop_uv_offset);
- glVertex2fv(cent);
+ immVertex2fv(pos, cent);
}
}
- glEnd();
+ immEnd();
+
+ immUnbindProgram();
}
/* 6. draw uv vertices */
if (drawfaces != 2) { /* 2 means Mesh Face Mode */
+ pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
/* unselected uvs */
- UI_ThemeColor(TH_VERTEX);
+ immUniformThemeColor(TH_VERTEX);
pointsize = UI_GetThemeValuef(TH_VERTEX_SIZE);
glPointSize(pointsize);
-
- glBegin(GL_POINTS);
+
+ immBeginAtMost(GWN_PRIM_POINTS, bm->totloop);
+
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
continue;
@@ -900,17 +977,19 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
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);
+ immVertex2fv(pos, luv->uv);
}
}
- glEnd();
+
+ immEnd();
/* pinned uvs */
/* give odd pointsizes odd pin pointsizes */
glPointSize(pointsize * 2 + (((int)pointsize % 2) ? (-1) : 0));
- cpack(0xFF);
+ imm_cpack(0xFF);
- glBegin(GL_POINTS);
+ immBeginAtMost(GWN_PRIM_POINTS, bm->totloop);
+
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
continue;
@@ -919,16 +998,18 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
if (luv->flag & MLOOPUV_PINNED)
- glVertex2fv(luv->uv);
+ immVertex2fv(pos, luv->uv);
}
}
- glEnd();
+
+ immEnd();
/* selected uvs */
- UI_ThemeColor(TH_VERTEX_SELECT);
+ immUniformThemeColor(TH_VERTEX_SELECT);
glPointSize(pointsize);
- glBegin(GL_POINTS);
+ immBeginAtMost(GWN_PRIM_POINTS, bm->totloop);
+
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
continue;
@@ -937,10 +1018,13 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
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);
+ immVertex2fv(pos, luv->uv);
}
}
- glEnd();
+
+ immEnd();
+
+ immUnbindProgram();
}
}
@@ -955,13 +1039,13 @@ static void draw_uv_shadows_get(SpaceImage *sima, Object *ob, Object *obedit, bo
if ((sima->mode == SI_MODE_PAINT) && obedit && obedit->type == OB_MESH) {
struct BMEditMesh *em = BKE_editmesh_from_object(obedit);
- *show_shadow = EDBM_mtexpoly_check(em);
+ *show_shadow = EDBM_uv_check(em);
}
*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, SceneLayer *sl, Object *obedit, Object *obact, Depsgraph *depsgraph)
{
ToolSettings *toolsettings = scene->toolsettings;
bool show_uvedit, show_uvshadow, show_texpaint_uvshadow;
@@ -973,9 +1057,9 @@ void ED_uvedit_draw_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *ob
if (show_uvshadow)
draw_uvs_shadow(obedit);
else if (show_uvedit)
- draw_uvs(sima, scene, obedit);
+ draw_uvs(sima, scene, sl, obedit, depsgraph);
else
- draw_uvs_texpaint(sima, scene, obact);
+ draw_uvs_texpaint(sima, scene, sl, obact);
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 e028c08091c..6ca46941404 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;
@@ -53,7 +52,6 @@ void uv_poly_center(struct BMFace *f, float r_cent[2], const int cd_loop_uv_off
typedef struct NearestHit {
struct BMFace *efa;
- struct MTexPoly *tf;
struct BMLoop *l;
struct MLoopUV *luv, *luv_next;
int lindex; /* index of loop within face */
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 193b006cf0d..5ee05273a5d 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -57,7 +57,6 @@
#include "BKE_context.h"
#include "BKE_customdata.h"
-#include "BKE_depsgraph.h"
#include "BKE_image.h"
#include "BKE_library.h"
#include "BKE_main.h"
@@ -68,6 +67,8 @@
#include "BKE_scene.h"
#include "BKE_editmesh.h"
+#include "DEG_depsgraph.h"
+
#include "ED_image.h"
#include "ED_mesh.h"
#include "ED_node.h"
@@ -106,7 +107,7 @@ bool ED_uvedit_test(Object *obedit)
return 0;
em = BKE_editmesh_from_object(obedit);
- ret = EDBM_mtexpoly_check(em);
+ ret = EDBM_uv_check(em);
return ret;
}
@@ -182,7 +183,6 @@ void ED_uvedit_assign_image(Main *UNUSED(bmain), Scene *scene, Object *obedit, I
{
BMEditMesh *em;
BMIter iter;
- MTexPoly *tf;
bool update = false;
const bool selected = !(scene->toolsettings->uv_flag & UV_SYNC_SELECTION);
@@ -206,8 +206,6 @@ void ED_uvedit_assign_image(Main *UNUSED(bmain), Scene *scene, Object *obedit, I
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;
@@ -221,31 +219,22 @@ void ED_uvedit_assign_image(Main *UNUSED(bmain), Scene *scene, Object *obedit, I
#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);
+ if (!CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV)) {
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_index(&em->bm->pdata, CD_MTEXPOLY));
+ ED_mesh_uv_loop_reset_ex(obedit->data, CustomData_get_active_layer_index(&em->bm->ldata, CD_MLOOPUV));
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) &&
+ if (uvedit_face_visible_test(scene, previma, efa) &&
(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
+ if (ima) {
/* we also need to correct the aspect of uvs */
if (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) {
/* do nothing */
@@ -261,11 +250,9 @@ void ED_uvedit_assign_image(Main *UNUSED(bmain), Scene *scene, Object *obedit, I
luv->uv[0] /= faspect;
}
}
-#endif
- }
- else {
- tf->tpage = NULL;
}
+#endif
+ BKE_object_material_edit_image_set(obedit, efa->mat_nr, ima);
update = true;
}
@@ -273,49 +260,12 @@ void ED_uvedit_assign_image(Main *UNUSED(bmain), Scene *scene, Object *obedit, I
/* and update depdency graph */
if (update) {
- DAG_id_tag_update(obedit->data, 0);
+ DEG_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;
-}
-
/*********************** space conversion *********************/
static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist)
@@ -346,14 +296,17 @@ 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, 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) {
+ const Image *face_image = BKE_object_material_edit_image_get(scene->obedit, efa->mat_nr);
+ return (face_image == ima) ? uvedit_face_visible_nolocal(scene, efa) : false;
+ }
+ else {
return uvedit_face_visible_nolocal(scene, efa);
+ }
}
bool uvedit_face_select_test(Scene *scene, BMFace *efa,
@@ -646,18 +599,15 @@ bool ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float r_min[2],
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- MTexPoly *tf;
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);
INIT_MINMAX2(r_min, r_max);
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, ima, efa))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -696,17 +646,14 @@ static bool ED_uvedit_median(Scene *scene, Image *ima, Object *obedit, float co[
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- MTexPoly *tf;
MLoopUV *luv;
unsigned int sel = 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(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))
+ if (!uvedit_face_visible_test(scene, ima, efa))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -723,7 +670,7 @@ 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)
+bool ED_uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2], char mode)
{
bool changed = false;
@@ -747,7 +694,6 @@ static bool uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2
void uv_find_nearest_edge(Scene *scene, Image *ima, BMEditMesh *em, const float co[2], NearestHit *hit)
{
- MTexPoly *tf;
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
@@ -756,7 +702,6 @@ void uv_find_nearest_edge(Scene *scene, Image *ima, BMEditMesh *em, const float
int i;
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_squared = 1e10f;
memset(hit, 0, sizeof(*hit));
@@ -764,8 +709,7 @@ void uv_find_nearest_edge(Scene *scene, Image *ima, BMEditMesh *em, const float
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, ima, efa))
continue;
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
@@ -775,7 +719,6 @@ void uv_find_nearest_edge(Scene *scene, Image *ima, BMEditMesh *em, const float
dist_squared = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv);
if (dist_squared < mindist_squared) {
- hit->tf = tf;
hit->efa = efa;
hit->l = l;
@@ -791,13 +734,11 @@ void uv_find_nearest_edge(Scene *scene, Image *ima, BMEditMesh *em, const float
static void uv_find_nearest_face(Scene *scene, Image *ima, BMEditMesh *em, const float co[2], NearestHit *hit)
{
- MTexPoly *tf;
BMFace *efa;
BMIter iter;
float mindist, dist, cent[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);
mindist = 1e10f;
memset(hit, 0, sizeof(*hit));
@@ -808,8 +749,7 @@ static void uv_find_nearest_face(Scene *scene, Image *ima, BMEditMesh *em, const
hit->luv = hit->luv_next = NULL;
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, ima, efa))
continue;
uv_poly_center(efa, cent, cd_loop_uv_offset);
@@ -817,7 +757,6 @@ static void uv_find_nearest_face(Scene *scene, Image *ima, BMEditMesh *em, const
dist = len_manhattan_v2v2(co, cent);
if (dist < mindist) {
- hit->tf = tf;
hit->efa = efa;
mindist = dist;
}
@@ -841,13 +780,11 @@ void uv_find_nearest_vert(Scene *scene, Image *ima, BMEditMesh *em,
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- MTexPoly *tf;
MLoopUV *luv;
float mindist, dist;
int i;
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*/
uv_find_nearest_edge(scene, ima, em, co, hit);
@@ -860,8 +797,7 @@ void uv_find_nearest_vert(Scene *scene, Image *ima, BMEditMesh *em,
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, ima, efa))
continue;
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
@@ -883,7 +819,6 @@ void uv_find_nearest_vert(Scene *scene, Image *ima, BMEditMesh *em,
hit->l = l;
hit->luv = luv;
hit->luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
- hit->tf = tf;
hit->efa = efa;
hit->lindex = i;
}
@@ -897,20 +832,17 @@ bool ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, const float
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- MTexPoly *tf;
MLoopUV *luv;
float mindist, dist;
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);
mindist = 1e10f;
copy_v2_v2(r_uv, 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))
+ if (!uvedit_face_visible_test(scene, ima, efa))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -1020,7 +952,6 @@ static int uv_select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestH
BMFace *efa;
BMIter iter, liter;
BMLoop *l;
- MTexPoly *tf;
UvVertMap *vmap;
UvMapVert *iterv_curr;
UvMapVert *iterv_next;
@@ -1028,7 +959,6 @@ static int uv_select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestH
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);
@@ -1061,9 +991,7 @@ static int uv_select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestH
/* 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, 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)))
@@ -1123,7 +1051,6 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- MTexPoly *tf;
MLoopUV *luv;
UvVertMap *vmap;
UvMapVert *vlist, *iterv, *startv;
@@ -1132,12 +1059,16 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
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);
BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */
- /* use winding so we don't consider overlapping islands as connected, see T44320 */
- vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, true);
+ /* 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 (vmap == NULL)
return;
@@ -1147,9 +1078,7 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
if (!hit) {
BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- 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, ima, efa)) {
if (select_faces) {
if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
stack[stacksize] = a;
@@ -1313,12 +1242,9 @@ static float *uv_sel_co_from_eve(Scene *scene, Image *ima, BMEditMesh *em, BMVer
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, ima, l->f))
continue;
if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
@@ -1344,7 +1270,6 @@ static int uv_select_more_less(bContext *C, const bool select)
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);
if (ts->uv_flag & UV_SYNC_SELECTION) {
if (select) {
@@ -1367,9 +1292,7 @@ static int uv_select_more_less(bContext *C, const bool select)
/* 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)) {
+ if (uvedit_face_visible_test(scene, ima, efa)) {
#define IS_SEL 1
#define IS_UNSEL 2
@@ -1412,9 +1335,7 @@ static int uv_select_more_less(bContext *C, const bool select)
/* 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)) {
+ if (uvedit_face_visible_test(scene, 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);
@@ -1481,11 +1402,9 @@ static void uv_weld_align(bContext *C, int tool)
SpaceImage *sima;
Scene *scene;
Image *ima;
- MTexPoly *tf;
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);
@@ -1499,9 +1418,7 @@ static void uv_weld_align(bContext *C, int tool)
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))
+ if (!uvedit_face_visible_test(scene, ima, efa))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -1515,7 +1432,7 @@ static void uv_weld_align(bContext *C, int tool)
tool = (max[0] - min[0] >= max[1] - min[1]) ? 'y' : 'x';
}
- uvedit_center(scene, ima, obedit, cent, 0);
+ ED_uvedit_center(scene, ima, obedit, cent, 0);
if (tool == 'x' || tool == 'w') {
BMIter iter, liter;
@@ -1523,8 +1440,7 @@ static void uv_weld_align(bContext *C, int tool)
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))
+ if (!uvedit_face_visible_test(scene, ima, efa))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -1543,8 +1459,7 @@ static void uv_weld_align(bContext *C, int tool)
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))
+ if (!uvedit_face_visible_test(scene, ima, efa))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -1572,9 +1487,7 @@ static void uv_weld_align(bContext *C, int tool)
/* 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 (!uvedit_face_visible_test(scene, ima, l->f, tf))
+ if (!uvedit_face_visible_test(scene, ima, l->f))
continue;
if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
@@ -1662,9 +1575,7 @@ static void uv_weld_align(bContext *C, int tool)
/* go over all verts except for endpoints */
for (i = 0; i < BLI_array_count(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))
+ if (!uvedit_face_visible_test(scene, ima, l->f))
continue;
if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
@@ -1698,7 +1609,7 @@ static void uv_weld_align(bContext *C, int tool)
uvedit_live_unwrap_update(sima, scene, 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);
}
@@ -1750,7 +1661,6 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op)
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;
@@ -1761,7 +1671,6 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op)
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);
sima = CTX_wm_space_image(C);
scene = CTX_data_scene(C);
@@ -1775,8 +1684,7 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op)
/* TODO, use qsort 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))
+ if (!uvedit_face_visible_test(scene, ima, efa))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -1838,8 +1746,7 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op)
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))
+ if (!uvedit_face_visible_test(scene, ima, efa))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -1876,7 +1783,7 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op)
}
uvedit_live_unwrap_update(sima, scene, 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);
return OPERATOR_FINISHED;
@@ -1929,11 +1836,9 @@ static void uv_select_all_perform(Scene *scene, Image *ima, BMEditMesh *em, int
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) {
@@ -1957,9 +1862,7 @@ static void uv_select_all_perform(Scene *scene, Image *ima, BMEditMesh *em, int
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))
+ if (!uvedit_face_visible_test(scene, ima, efa))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -1975,9 +1878,7 @@ static void uv_select_all_perform(Scene *scene, Image *ima, BMEditMesh *em, int
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, ima, efa))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -2066,7 +1967,6 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- MTexPoly *tf;
MLoopUV *luv;
NearestHit hit;
int i, selectmode, sticky, sync, *hitv = NULL;
@@ -2076,7 +1976,6 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
float penalty[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);
/* 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.
@@ -2228,8 +2127,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, ima, efa))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -2264,8 +2162,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, ima, efa))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -2308,7 +2205,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
#endif
}
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
@@ -2447,7 +2344,7 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
uv_select_linked(scene, ima, em, limit, hit_p, extend, select_faces);
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
@@ -2521,12 +2418,10 @@ static int uv_select_split_exec(bContext *C, wmOperator *op)
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");
@@ -2538,9 +2433,8 @@ static int uv_select_split_exec(bContext *C, wmOperator *op)
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);
- if (!uvedit_face_visible_test(scene, ima, efa, tf))
+ if (!uvedit_face_visible_test(scene, ima, efa))
continue;
/* are we all selected? */
@@ -2681,7 +2575,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) {
@@ -2770,7 +2663,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);
@@ -2854,7 +2746,6 @@ static int uv_border_select_exec(bContext *C, wmOperator *op)
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- MTexPoly *tf;
MLoopUV *luv;
rctf rectf;
bool changed, pinned, select, extend;
@@ -2863,7 +2754,6 @@ static int uv_border_select_exec(bContext *C, wmOperator *op)
(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);
@@ -2888,8 +2778,7 @@ static int uv_border_select_exec(bContext *C, wmOperator *op)
/* assume not touched */
BM_elem_flag_disable(efa, BM_ELEM_TAG);
- 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, 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);
@@ -2908,8 +2797,7 @@ static int uv_border_select_exec(bContext *C, wmOperator *op)
changed = true;
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, 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);
@@ -3110,13 +2998,11 @@ static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short mo
(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);
BMIter iter, liter;
BMFace *efa;
BMLoop *l;
- MTexPoly *tf;
int screen_uv[2];
bool changed = false;
rcti rect;
@@ -3152,8 +3038,7 @@ static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short mo
}
else { /* Vert Sel */
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, 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);
@@ -3244,7 +3129,7 @@ static void uv_snap_cursor_to_pixels(SpaceImage *sima)
static bool uv_snap_cursor_to_selection(Scene *scene, Image *ima, Object *obedit, SpaceImage *sima)
{
- return uvedit_center(scene, ima, obedit, sima->cursor, sima->around);
+ return ED_uvedit_center(scene, ima, obedit, sima->cursor, sima->around);
}
static int uv_snap_cursor_exec(bContext *C, wmOperator *op)
@@ -3302,16 +3187,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, ima, efa))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -3332,16 +3214,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, ima, efa))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -3363,17 +3242,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, 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));
@@ -3421,22 +3297,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, ima, efa))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -3470,7 +3343,7 @@ static int uv_snap_selection_exec(bContext *C, wmOperator *op)
case 2:
{
float center[2];
- if (uvedit_center(scene, ima, obedit, center, sima->around)) {
+ if (ED_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);
@@ -3486,7 +3359,7 @@ static int uv_snap_selection_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
uvedit_live_unwrap_update(sima, scene, 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);
return OPERATOR_FINISHED;
@@ -3526,16 +3399,13 @@ static int uv_pin_exec(bContext *C, wmOperator *op)
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- MTexPoly *tface;
MLoopUV *luv;
const bool clear = RNA_boolean_get(op->ptr, "clear");
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, ima, efa))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -3584,15 +3454,12 @@ static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op))
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);
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, ima, efa))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -3656,13 +3523,11 @@ 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);
@@ -3674,9 +3539,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, ima, efa)) {
continue;
}
@@ -3953,73 +3816,6 @@ static void UV_OT_cursor_set(wmOperatorType *ot)
"Cursor location in normalized (0.0-1.0) coordinates", -10.0f, 10.0f);
}
-/********************** set tile 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)
-{
- /* identifiers */
- ot->name = "Set Tile";
- ot->description = "Set UV image tile coordinates";
- ot->idname = "UV_OT_tile_set";
-
- /* api callbacks */
- ot->exec = set_tile_exec;
- ot->invoke = set_tile_invoke;
- ot->poll = ED_operator_image_active;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_int_vector(ot->srna, "tile", 2, NULL, 0, INT_MAX, "Tile", "Tile coordinate", 0, 10);
-}
-
-
static int uv_seams_from_islands_exec(bContext *C, wmOperator *op)
{
UvVertMap *vmap;
@@ -4037,7 +3833,7 @@ static int uv_seams_from_islands_exec(bContext *C, wmOperator *op)
em = me->edit_btmesh;
bm = em->bm;
- if (!EDBM_mtexpoly_check(em)) {
+ if (!EDBM_uv_check(em)) {
return OPERATOR_CANCELLED;
}
@@ -4129,7 +3925,7 @@ static int uv_seams_from_islands_exec(bContext *C, wmOperator *op)
BM_uv_vert_map_free(vmap);
- 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;
@@ -4184,7 +3980,7 @@ static int uv_mark_seam_exec(bContext *C, wmOperator *op)
if (scene->toolsettings->edge_mode_live_unwrap)
ED_unwrap_lscm(scene, ob, false);
- 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;
@@ -4274,7 +4070,6 @@ 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)
@@ -4354,7 +4149,6 @@ void ED_keymap_uvedit(wmKeyConfig *keyconf)
/* 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);
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index bdfff123aa4..8c76d03035a 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.c
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.c
@@ -2859,7 +2859,7 @@ static PBool p_chart_symmetry_pins(PChart *chart, PEdge *outer, PVert **pin1, PV
PEdge *cure = NULL, *firste1 = NULL, *firste2 = NULL, *nextbe;
float maxlen = 0.0f, curlen = 0.0f, totlen = 0.0f, firstlen = 0.0f;
float len1, len2;
-
+
/* find longest series of verts split in the chart itself, these are
* marked during construction */
be = outer;
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index 59442e89787..55c439924cd 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -52,10 +52,11 @@
#include "BKE_context.h"
#include "BKE_customdata.h"
-#include "BKE_depsgraph.h"
#include "BKE_mesh_mapping.h"
#include "BKE_editmesh.h"
+#include "DEG_depsgraph.h"
+
#include "UI_interface.h"
#include "ED_mesh.h"
@@ -63,6 +64,8 @@
#include "ED_screen.h"
#include "ED_space_api.h"
+#include "GPU_batch.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
@@ -459,7 +462,7 @@ static void stitch_calculate_island_snapping(
island_stitch_data[i].num_rot_elements_neg) / totelem;
}
- rotate_m2(rotation_mat, rotation);
+ angle_to_mat2(rotation_mat, rotation);
numOfIslandUVs = getNumOfIslandUvs(state->element_map, i);
element = &state->element_map->buf[state->element_map->islandIndices[i]];
for (j = 0; j < numOfIslandUVs; j++, element++) {
@@ -1538,63 +1541,118 @@ static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *no
normalize_v2(normal);
}
+static void stitch_draw_vbo(Gwn_VertBuf *vbo, Gwn_PrimType prim_type, const float col[4])
+{
+ Gwn_Batch *batch = GWN_batch_create(prim_type, vbo, NULL);
+ Batch_set_builtin_program(batch, GPU_SHADER_2D_UNIFORM_COLOR);
+ GWN_batch_uniform_4fv(batch, "color", col);
+ GWN_batch_draw(batch);
+ GWN_batch_discard_all(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;
+ int j, index = 0;
+ unsigned int num_line = 0, num_tri, tri_idx = 0, line_idx = 0;
StitchState *state = (StitchState *)arg;
StitchPreviewer *stitch_preview = state->stitch_preview;
+ Gwn_VertBuf *vbo, *vbo_line;
+ float col[4];
- glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
- glEnableClientState(GL_VERTEX_ARRAY);
+ static Gwn_VertFormat format = { 0 };
+ static unsigned int pos_id;
+ if (format.attrib_ct == 0) {
+ pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ }
glEnable(GL_BLEND);
- 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);
-
- 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
-
- index += stitch_preview->uvs_per_polygon[i];
+ /* Static Tris */
+ UI_GetThemeColor4fv(TH_STITCH_PREVIEW_ACTIVE, col);
+ vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, stitch_preview->num_static_tris * 3);
+ for (int i = 0; i < stitch_preview->num_static_tris * 3; i++)
+ GWN_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->static_tris[i*2]);
+ stitch_draw_vbo(vbo, GWN_PRIM_TRIS, col);
+
+
+ /* Preview Polys */
+ for (int i = 0; i < stitch_preview->num_polys; i++)
+ num_line += stitch_preview->uvs_per_polygon[i];
+
+ num_tri = num_line - 2 * stitch_preview->num_polys;
+
+ /* we need to convert the polys into triangles / lines */
+ vbo = GWN_vertbuf_create_with_format(&format);
+ vbo_line = GWN_vertbuf_create_with_format(&format);
+
+ GWN_vertbuf_data_alloc(vbo, num_tri * 3);
+ GWN_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 */
+ GWN_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index]);
+ GWN_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) {
+ GWN_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index]);
+ GWN_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j+0)*2]);
+ GWN_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j+1)*2]);
+
+ GWN_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + (j+0)*2]);
+ GWN_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + (j+1)*2]);
+ }
+
+ /* Closing line */
+ GWN_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index]);
+ GWN_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + j*2]); /* j = uvs_per_polygon[i] - 1*/
+
+ index += stitch_preview->uvs_per_polygon[i] * 2;
}
+ UI_GetThemeColor4fv(TH_STITCH_PREVIEW_FACE, col);
+ stitch_draw_vbo(vbo, GWN_PRIM_TRIS, col);
+ UI_GetThemeColor4fv(TH_STITCH_PREVIEW_EDGE, col);
+ stitch_draw_vbo(vbo_line, GWN_PRIM_LINES, col);
+
glDisable(GL_BLEND);
- /* draw vert preview */
+
+ /* draw stitch vert/lines preview */
if (state->mode == STITCH_VERT) {
glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) * 2.0f);
- UI_ThemeColor4(TH_STITCH_PREVIEW_STITCHABLE);
- glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_stitchable);
- glDrawArrays(GL_POINTS, 0, stitch_preview->num_stitchable);
+ UI_GetThemeColor4fv(TH_STITCH_PREVIEW_STITCHABLE, col);
+ vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, stitch_preview->num_stitchable);
+ for (int i = 0; i < stitch_preview->num_stitchable; i++)
+ GWN_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_stitchable[i*2]);
+ stitch_draw_vbo(vbo, GWN_PRIM_POINTS, col);
- UI_ThemeColor4(TH_STITCH_PREVIEW_UNSTITCHABLE);
- glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_unstitchable);
- glDrawArrays(GL_POINTS, 0, stitch_preview->num_unstitchable);
+ UI_GetThemeColor4fv(TH_STITCH_PREVIEW_UNSTITCHABLE, col);
+ vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, stitch_preview->num_unstitchable);
+ for (int i = 0; i < stitch_preview->num_unstitchable; i++)
+ GWN_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_unstitchable[i*2]);
+ stitch_draw_vbo(vbo, GWN_PRIM_POINTS, col);
}
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);
-
- UI_ThemeColor4(TH_STITCH_PREVIEW_UNSTITCHABLE);
- glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_unstitchable);
- glDrawArrays(GL_LINES, 0, 2 * stitch_preview->num_unstitchable);
+ UI_GetThemeColor4fv(TH_STITCH_PREVIEW_STITCHABLE, col);
+ vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, stitch_preview->num_stitchable * 2);
+ for (int i = 0; i < stitch_preview->num_stitchable * 2; i++)
+ GWN_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_stitchable[i*2]);
+ stitch_draw_vbo(vbo, GWN_PRIM_LINES, col);
+
+ UI_GetThemeColor4fv(TH_STITCH_PREVIEW_UNSTITCHABLE, col);
+ vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, stitch_preview->num_unstitchable * 2);
+ for (int i = 0; i < stitch_preview->num_unstitchable * 2; i++)
+ GWN_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_unstitchable[i*2]);
+ stitch_draw_vbo(vbo, GWN_PRIM_LINES, col);
}
-
- glPopClientAttrib();
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
static UvEdge *uv_edge_get(BMLoop *l, StitchState *state)
@@ -2024,7 +2082,7 @@ static void stitch_exit(bContext *C, wmOperator *op, int finished)
ED_region_draw_cb_exit(CTX_wm_region(C)->type, state->draw_handle);
- 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);
state_delete(state);
@@ -2116,6 +2174,7 @@ static int stitch_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
break;
}
+ ATTR_FALLTHROUGH;
case PADENTER:
case RETKEY:
if (event->val == KM_PRESS) {
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 8e4ba4c0afa..b700c992a01 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -55,13 +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 "DEG_depsgraph.h"
+
#include "PIL_time.h"
#include "UI_interface.h"
@@ -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))
@@ -214,8 +216,7 @@ void ED_uvedit_get_aspect(Scene *scene, Object *ob, BMesh *bm, float *aspx, floa
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;
+ ima = BKE_object_material_edit_image_get(ob, efa->mat_nr);
}
ED_image_get_uv_aspect(ima, NULL, aspx, aspy);
@@ -570,7 +571,7 @@ static void minimize_stretch_iteration(bContext *C, wmOperator *op, bool interac
ms->lasttime = PIL_check_seconds_timer();
- DAG_id_tag_update(ms->obedit->data, 0);
+ DEG_id_tag_update(ms->obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ms->obedit->data);
}
}
@@ -593,7 +594,7 @@ 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);
+ DEG_id_tag_update(ms->obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ms->obedit->data);
MEM_freeN(ms);
@@ -741,7 +742,7 @@ static int pack_islands_exec(bContext *C, wmOperator *op)
ED_uvedit_pack_islands(scene, obedit, em->bm, true, true, do_rotate);
- 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;
@@ -784,7 +785,7 @@ static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op))
param_flush(handle);
param_delete(handle);
- 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;
@@ -1222,12 +1223,12 @@ static int unwrap_exec(bContext *C, wmOperator *op)
* 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, "Subsurf modifier needs to be first to work with unwrap");
+ 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);
- 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;
@@ -1259,7 +1260,7 @@ void UV_OT_unwrap(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "correct_aspect", 1, "Correct Aspect",
"Map UVs taking image aspect ratio into account");
RNA_def_boolean(ot->srna, "use_subsurf_data", 0, "Use Subsurf Modifier",
- "Map UVs taking vertex position after subsurf into account");
+ "Map UVs taking vertex position after Subdivision Surface modifier has been applied");
RNA_def_float_factor(ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f);
}
@@ -1354,7 +1355,7 @@ static int uv_from_view_exec(bContext *C, wmOperator *op)
uv_map_clip_correct(scene, obedit, em, 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;
@@ -1407,7 +1408,7 @@ static int reset_exec(bContext *C, wmOperator *UNUSED(op))
ED_mesh_uv_loop_reset(C, me);
- 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;
@@ -1443,7 +1444,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;
@@ -1480,7 +1481,6 @@ static int sphere_project_exec(bContext *C, wmOperator *op)
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- MTexPoly *tf;
MLoopUV *luv;
float center[3], rotmat[4][4];
@@ -1505,13 +1505,12 @@ static int sphere_project_exec(bContext *C, wmOperator *op)
uv_sphere_project(luv->uv, l->v->co, center, rotmat);
}
- tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
- uv_map_mirror(em, efa, tf);
+ uv_map_mirror(em, efa);
}
uv_map_clip_correct(scene, obedit, em, 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;
@@ -1559,7 +1558,6 @@ static int cylinder_project_exec(bContext *C, wmOperator *op)
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- MTexPoly *tf;
MLoopUV *luv;
float center[3], rotmat[4][4];
@@ -1584,13 +1582,12 @@ static int cylinder_project_exec(bContext *C, wmOperator *op)
uv_cylinder_project(luv->uv, l->v->co, center, rotmat);
}
- tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
- uv_map_mirror(em, efa, tf);
+ uv_map_mirror(em, efa);
}
uv_map_clip_correct(scene, obedit, em, 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;
@@ -1621,7 +1618,6 @@ void ED_uvedit_unwrap_cube_project(Object *ob, BMesh *bm, float cube_size, bool
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- /* MTexPoly *tf; */ /* UNUSED */
MLoopUV *luv;
float *loc, dx, dy;
int cox, coy;
@@ -1637,8 +1633,6 @@ void ED_uvedit_unwrap_cube_project(Object *ob, BMesh *bm, float cube_size, bool
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
int first = 1;
-
- /* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
if (use_select && !BM_elem_flag_test(efa, BM_ELEM_SELECT))
continue;
@@ -1680,7 +1674,7 @@ static int cube_project_exec(bContext *C, wmOperator *op)
ED_uvedit_unwrap_cube_project(obedit, em->bm, cube_size, true);
uv_map_clip_correct(scene, obedit, em, 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;
diff --git a/source/blender/freestyle/CMakeLists.txt b/source/blender/freestyle/CMakeLists.txt
index f6b7efe978c..1ae4211aa23 100644
--- a/source/blender/freestyle/CMakeLists.txt
+++ b/source/blender/freestyle/CMakeLists.txt
@@ -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 039a75a2f0f..a6382010ca7 100644
--- a/source/blender/freestyle/FRS_freestyle.h
+++ b/source/blender/freestyle/FRS_freestyle.h
@@ -63,8 +63,7 @@ void FRS_exit(void);
void FRS_copy_active_lineset(struct FreestyleConfig *config);
void FRS_paste_active_lineset(struct FreestyleConfig *config);
void FRS_delete_active_lineset(struct FreestyleConfig *config);
-void FRS_move_active_lineset_up(struct FreestyleConfig *config);
-void FRS_move_active_lineset_down(struct FreestyleConfig *config);
+bool FRS_move_active_lineset(struct FreestyleConfig *config, int direction);
/* Testing */
struct Material *FRS_create_stroke_material(struct Main *bmain, struct FreestyleLineStyle *linestyle);
diff --git a/source/blender/freestyle/intern/application/AppView.cpp b/source/blender/freestyle/intern/application/AppView.cpp
index c331d1de9c9..9b1b02c8ee2 100644
--- a/source/blender/freestyle/intern/application/AppView.cpp
+++ b/source/blender/freestyle/intern/application/AppView.cpp
@@ -22,12 +22,6 @@
* \ingroup freestyle
*/
-/* This header file needs to be included first, in order to avoid a
- compilation with MinGW (see the commit log of revision 28253) */
-extern "C" {
-#include "BLI_jitter.h"
-}
-
#include <iostream>
#include "Controller.h"
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
index 1f5e2b63bfa..35ac3171987 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
@@ -105,8 +105,6 @@ NodeGroup *BlenderFileLoader::Load()
cnt++;
}
- 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);
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index f63cf771120..50fe2162bda 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -43,8 +43,8 @@ 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_global.h"
#include "BKE_library.h" /* free_libblock */
#include "BKE_material.h"
@@ -59,6 +59,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"
@@ -127,8 +130,8 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : Str
BKE_scene_set_background(freestyle_bmain, freestyle_scene);
// 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, (SceneLayer *)freestyle_scene->render_layers.first, OB_CAMERA, NULL);
+ DEG_relations_tag_update(freestyle_bmain);
Camera *camera = (Camera *)object_camera->data;
camera->type = CAM_ORTHO;
@@ -166,7 +169,7 @@ BlenderStrokeRenderer::~BlenderStrokeRenderer()
// compositor has finished.
// release objects and data blocks
- for (Base *b = (Base *)freestyle_scene->base.first; b; b = b->next) {
+ for (Base *b = (Base *)((SceneLayer *)(freestyle_scene->render_layers.first))->object_bases.first; b; b = b->next) {
Object *ob = b->object;
void *data = ob->data;
char *name = ob->id.name;
@@ -189,7 +192,6 @@ BlenderStrokeRenderer::~BlenderStrokeRenderer()
cerr << "Warning: unexpected object in the scene: " << name[0] << name[1] << ":" << (name + 2) << endl;
}
}
- BLI_freelistN(&freestyle_scene->base);
// release materials
Link *lnk = (Link *)freestyle_bmain->mat.first;
@@ -510,7 +512,7 @@ void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
// If still no material, create one
if (!has_mat) {
Material *ma = BKE_material_add(freestyle_bmain, "stroke_material");
- DAG_relations_tag_update(freestyle_bmain);
+ DEG_relations_tag_update(freestyle_bmain);
ma->mode |= MA_VERTEXCOLP;
ma->mode |= MA_TRANSP;
ma->mode |= MA_SHLESS;
@@ -524,7 +526,7 @@ void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
// We'll generate both with tips and without tips
// coordinates, on two different UV layers.
- if (ma->mtex[a]->texflag & MTEX_TIPS) {
+ if (ma->mtex[a]->texflag & MTEX_TIPS) {
BLI_strncpy(ma->mtex[a]->uvname, uvNames[1], sizeof(ma->mtex[a]->uvname));
}
else {
@@ -674,8 +676,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, (SceneLayer *)freestyle_scene->render_layers.first, OB_MESH);
+ DEG_relations_tag_update(freestyle_bmain);
#else
Object *object_mesh = NewMesh();
#endif
@@ -700,17 +702,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;
@@ -922,7 +920,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();
@@ -932,16 +929,13 @@ Object *BlenderStrokeRenderer::NewMesh() const
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
+ SceneCollection *sc_master = BKE_collection_master(freestyle_scene);
+ BKE_collection_object_add(freestyle_scene, sc_master, ob);
+
+ BKE_scene_base_add(freestyle_scene, ob);
+ DEG_relations_tag_update(freestyle_bmain);
- DAG_id_tag_update_ex(freestyle_bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update_ex(freestyle_bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
return ob;
}
@@ -958,6 +952,8 @@ Render *BlenderStrokeRenderer::RenderScene(Render * /*re*/, bool render)
#endif
Render *freestyle_render = RE_NewRender(freestyle_scene->id.name);
+ DEG_scene_relations_update(freestyle_bmain, freestyle_scene);
+ freestyle_render->depsgraph = freestyle_scene->depsgraph_legacy;
RE_RenderFreestyleStrokes(freestyle_render, freestyle_bmain, freestyle_scene,
render && get_stroke_count() > 0);
diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
index 4d8c6a66d42..ea22633c50e 100644
--- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
+++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
@@ -433,8 +433,8 @@ static void prepare(Render *re, SceneRenderLayer *srl)
cout << "Crease angle : " << controller->getCreaseAngle() << endl;
cout << "Sphere radius : " << controller->getSphereRadius() << endl;
cout << "Face smoothness : " << (controller->getFaceSmoothness() ? "enabled" : "disabled") << endl;
- cout << "Redges and valleys : " << (controller->getComputeRidgesAndValleysFlag() ? "enabled" : "disabled") <<
- endl;
+ cout << "Ridges and valleys : " <<
+ (controller->getComputeRidgesAndValleysFlag() ? "enabled" : "disabled") << endl;
cout << "Suggestive contours : " <<
(controller->getComputeSuggestiveContoursFlag() ? "enabled" : "disabled") << endl;
cout << "Suggestive contour Kr derivative epsilon : " <<
@@ -448,15 +448,13 @@ static void prepare(Render *re, SceneRenderLayer *srl)
RenderLayer *rl = RE_GetRenderLayer(re->result, srl->name);
bool diffuse = false, z = false;
for (RenderPass *rpass = (RenderPass *)rl->passes.first; rpass; rpass = rpass->next) {
- switch (rpass->passtype) {
- case SCE_PASS_DIFFUSE:
+ if (STREQ(rpass->name, RE_PASSNAME_DIFFUSE)) {
controller->setPassDiffuse(rpass->rect, rpass->rectx, rpass->recty);
diffuse = true;
- break;
- case SCE_PASS_Z:
+ }
+ if (STREQ(rpass->name, RE_PASSNAME_Z)) {
controller->setPassZ(rpass->rect, rpass->rectx, rpass->recty);
z = true;
- break;
}
}
if (G.debug & G_DEBUG_FREESTYLE) {
@@ -492,7 +490,7 @@ void FRS_composite_result(Render *re, SceneRenderLayer *srl, Render *freestyle_r
return;
}
- src = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, freestyle_render->viewname);
+ src = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, freestyle_render->viewname);
if (!src) {
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "No source result image to composite" << endl;
@@ -512,7 +510,7 @@ void FRS_composite_result(Render *re, SceneRenderLayer *srl, Render *freestyle_r
}
return;
}
- dest = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, re->viewname);
+ dest = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, re->viewname);
if (!dest) {
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "No destination result image to composite to" << endl;
@@ -730,24 +728,14 @@ void FRS_delete_active_lineset(FreestyleConfig *config)
}
}
-void FRS_move_active_lineset_up(FreestyleConfig *config)
-{
- FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
-
- if (lineset) {
- BLI_remlink(&config->linesets, lineset);
- BLI_insertlinkbefore(&config->linesets, lineset->prev, lineset);
- }
-}
-
-void FRS_move_active_lineset_down(FreestyleConfig *config)
+/**
+ * Reinsert the active lineset at an offset \a direction from current position.
+ * \return if position of active lineset has changed.
+ */
+bool FRS_move_active_lineset(FreestyleConfig *config, int direction)
{
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
-
- if (lineset) {
- BLI_remlink(&config->linesets, lineset);
- BLI_insertlinkafter(&config->linesets, lineset->next, lineset);
- }
+ return (lineset != NULL) && BLI_listbase_link_move(&config->linesets, lineset, direction);
}
// Testing
diff --git a/source/blender/freestyle/intern/geometry/GeomUtils.cpp b/source/blender/freestyle/intern/geometry/GeomUtils.cpp
index 3eb92c559fe..cd7c1b83a4e 100644
--- a/source/blender/freestyle/intern/geometry/GeomUtils.cpp
+++ b/source/blender/freestyle/intern/geometry/GeomUtils.cpp
@@ -470,6 +470,8 @@ bool intersectRayTriangle(const Vec3r& orig, const Vec3r& dir, const Vec3r& v0,
}
// Intersection between plane and ray, adapted from Graphics Gems, Didier Badouel
+// The plane is represented by a set of points P implicitly defined as dot(norm, P) + d = 0.
+// The ray is represented as r(t) = orig + dir * t.
intersection_test intersectRayPlane(const Vec3r& orig, const Vec3r& dir, const Vec3r& norm, const real d,
real& t, const real epsilon)
{
diff --git a/source/blender/freestyle/intern/geometry/matrix_util.h b/source/blender/freestyle/intern/geometry/matrix_util.h
index d65b0ea803b..444fd7c4785 100644
--- a/source/blender/freestyle/intern/geometry/matrix_util.h
+++ b/source/blender/freestyle/intern/geometry/matrix_util.h
@@ -50,15 +50,15 @@ namespace MatrixUtil {
/**
* computes the eigen values and eigen vectors of a semi definite symmetric matrix
*
- * @param matrix is stored in column symmetric storage, i.e.
+ * \param mat: The matrix stored in column symmetric storage, i.e.
* matrix = { m11, m12, m22, m13, m23, m33, m14, m24, m34, m44 ... }
* size = n(n+1)/2
*
- * @param eigen_vectors (return) = { v1, v2, v3, ..., vn }
+ * \param eigen_vec: (return) = { v1, v2, v3, ..., vn }
* where vk = vk0, vk1, ..., vkn
* size = n^2, must be allocated by caller
*
- * @param eigen_values (return) are in decreasing order
+ * \param eigen_val: (return) are in decreasing order
* size = n, must be allocated by caller
*/
void semi_definite_symmetric_eigen(const double *mat, int n, double *eigen_vec, double *eigen_val);
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 8d7bf986bde..16dea6f907e 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/stroke/StrokeRep.cpp b/source/blender/freestyle/intern/stroke/StrokeRep.cpp
index ab06e207331..028127897ff 100644
--- a/source/blender/freestyle/intern/stroke/StrokeRep.cpp
+++ b/source/blender/freestyle/intern/stroke/StrokeRep.cpp
@@ -135,11 +135,11 @@ void Strip::createStrip (const vector<StrokeVertex*>& iStrokeVertices)
int orientationErrors = 0;
//special case of first vertex
- v = iStrokeVertices.begin();
+ v2 = v = iStrokeVertices.begin();
+ ++v2;
sv = *v;
vPrev = v; //in case the stroke has only 2 vertices;
- ++v;
- sv2 = *v;
+ sv2 = *v2;
Vec2r dir(sv2->getPoint() - sv->getPoint());
Vec2r orthDir(-dir[1], dir[0]);
if (orthDir.norm() > ZERO)
@@ -189,11 +189,7 @@ void Strip::createStrip (const vector<StrokeVertex*>& iStrokeVertices)
int i = 2; // 2 because we have already processed the first vertex
- for (vend = iStrokeVertices.end(); v != vend; ++v) {
- v2 = v;
- ++v2;
- if (v2 == vend)
- break;
+ for (vend = iStrokeVertices.end(), ++v, ++v2; v2 != vend; vPrev = v++, ++v2) {
sv = (*v);
sv2 = (*v2);
svPrev = (*vPrev);
@@ -289,8 +285,6 @@ void Strip::createStrip (const vector<StrokeVertex*>& iStrokeVertices)
{
_vertices[i - 1]->setPoint2d(p - thickness[0] * stripDir);
}
-
- vPrev = v;
} // end of for
//special case of last vertex
diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
index 77beb1d97d9..794c782bb73 100644
--- a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
+++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
@@ -57,7 +57,7 @@ using namespace std;
template <typename G, typename I>
static void findOccludee(FEdge *fe, G& /*grid*/, I& occluders, real epsilon, WFace **oaWFace,
- Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edge, vector<WVertex*>& faceVertices)
+ Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edgeDir, vector<WVertex*>& faceVertices)
{
WFace *face = NULL;
if (fe->isSmooth()) {
@@ -125,7 +125,7 @@ static void findOccludee(FEdge *fe, G& /*grid*/, I& occluders, real epsilon, WFa
// check whether the edge and the polygon plane are coincident:
//-------------------------------------------------------------
//first let us compute the plane equation.
- if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edge, p->getNormal(), d, t, epsilon))
+ if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edgeDir, p->getNormal(), d, t, epsilon))
{
#if LOGGING
if (_global.debug & G_DEBUG_FREESTYLE) {
@@ -172,10 +172,11 @@ template <typename G, typename I>
static void findOccludee(FEdge *fe, G& grid, real epsilon, ViewEdge * /*ve*/, WFace **oaFace)
{
Vec3r A;
- Vec3r edge;
+ Vec3r edgeDir;
Vec3r origin;
A = Vec3r(((fe)->vertexA()->point3D() + (fe)->vertexB()->point3D()) / 2.0);
- edge = Vec3r((fe)->vertexB()->point3D() - (fe)->vertexA()->point3D());
+ edgeDir = Vec3r((fe)->vertexB()->point3D() - (fe)->vertexA()->point3D());
+ edgeDir.normalize();
origin = Vec3r((fe)->vertexA()->point3D());
Vec3r u;
if (grid.orthographicProjection()) {
@@ -199,7 +200,7 @@ static void findOccludee(FEdge *fe, G& grid, real epsilon, ViewEdge * /*ve*/, WF
}
I occluders(grid, A, epsilon);
- findOccludee<G, I>(fe, grid, occluders, epsilon, oaFace, u, A, origin, edge, faceVertices);
+ findOccludee<G, I>(fe, grid, occluders, epsilon, oaFace, u, A, origin, edgeDir, faceVertices);
}
// computeVisibility takes a pointer to foundOccluders, instead of using a reference,
@@ -211,11 +212,12 @@ static int computeVisibility(ViewMap *viewMap, FEdge *fe, G& grid, real epsilon,
int qi = 0;
Vec3r center;
- Vec3r edge;
+ Vec3r edgeDir;
Vec3r origin;
center = fe->center3d();
- edge = Vec3r(fe->vertexB()->point3D() - fe->vertexA()->point3D());
+ edgeDir = Vec3r(fe->vertexB()->point3D() - fe->vertexA()->point3D());
+ edgeDir.normalize();
origin = Vec3r(fe->vertexA()->point3D());
Vec3r vp;
@@ -337,7 +339,7 @@ static int computeVisibility(ViewMap *viewMap, FEdge *fe, G& grid, real epsilon,
// check whether the edge and the polygon plane are coincident:
//-------------------------------------------------------------
//first let us compute the plane equation.
- if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edge, p->getNormal(), d, t, epsilon)) {
+ if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edgeDir, p->getNormal(), d, t, epsilon)) {
#if LOGGING
if (_global.debug & G_DEBUG_FREESTYLE) {
cout << "\t\tRejecting occluder for target coincidence." << endl;
@@ -391,7 +393,7 @@ static int computeVisibility(ViewMap *viewMap, FEdge *fe, G& grid, real epsilon,
}
// Find occludee
- findOccludee<G, I>(fe, grid, occluders, epsilon, oaWFace, u, center, origin, edge, faceVertices);
+ findOccludee<G, I>(fe, grid, occluders, epsilon, oaWFace, u, center, origin, edgeDir, faceVertices);
return qi;
}
@@ -1788,7 +1790,7 @@ void ViewMapBuilder::ComputeVeryFastRayCastingVisibility(ViewMap *ioViewMap, rea
}
void ViewMapBuilder::FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3r **oaPolygon, unsigned timestamp,
- Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edge, vector<WVertex*>& faceVertices)
+ Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edgeDir, vector<WVertex*>& faceVertices)
{
WFace *face = NULL;
if (fe->isSmooth()) {
@@ -1856,7 +1858,7 @@ void ViewMapBuilder::FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3
continue;
}
else {
- if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edge, normal, d, t, epsilon))
+ if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edgeDir, normal, d, t, epsilon))
continue;
}
if ((*p)->rayIntersect(A, v, t, t_u, t_v)) {
@@ -1883,10 +1885,11 @@ void ViewMapBuilder::FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3
OccludersSet occluders;
Vec3r A;
- Vec3r edge;
+ Vec3r edgeDir;
Vec3r origin;
A = Vec3r(((fe)->vertexA()->point3D() + (fe)->vertexB()->point3D()) / 2.0);
- edge = Vec3r((fe)->vertexB()->point3D() - (fe)->vertexA()->point3D());
+ edgeDir = Vec3r((fe)->vertexB()->point3D() - (fe)->vertexA()->point3D());
+ edgeDir.normalize();
origin = Vec3r((fe)->vertexA()->point3D());
Vec3r u;
if (_orthographicProjection) {
@@ -1910,7 +1913,7 @@ void ViewMapBuilder::FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3
if (face)
face->RetrieveVertexList(faceVertices);
- return FindOccludee(fe, iGrid, epsilon, oaPolygon, timestamp, u, A, origin, edge, faceVertices);
+ return FindOccludee(fe, iGrid, epsilon, oaPolygon, timestamp, u, A, origin, edgeDir, faceVertices);
}
int ViewMapBuilder::ComputeRayCastingVisibility(FEdge *fe, Grid *iGrid, real epsilon, set<ViewShape*>& oOccluders,
@@ -1920,11 +1923,12 @@ int ViewMapBuilder::ComputeRayCastingVisibility(FEdge *fe, Grid *iGrid, real eps
int qi = 0;
Vec3r center;
- Vec3r edge;
+ Vec3r edgeDir;
Vec3r origin;
center = fe->center3d();
- edge = Vec3r(fe->vertexB()->point3D() - fe->vertexA()->point3D());
+ edgeDir = Vec3r(fe->vertexB()->point3D() - fe->vertexA()->point3D());
+ edgeDir.normalize();
origin = Vec3r(fe->vertexA()->point3D());
// Is the edge outside the view frustum ?
Vec3r gridOrigin(iGrid->getOrigin());
@@ -2062,7 +2066,7 @@ int ViewMapBuilder::ComputeRayCastingVisibility(FEdge *fe, Grid *iGrid, real eps
//-------------------------------------------------------------
//first let us compute the plane equation.
- if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edge, normal, d, t, epsilon)) {
+ if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edgeDir, normal, d, t, epsilon)) {
#if LOGGING
if (_global.debug & G_DEBUG_FREESTYLE) {
cout << "\t\tRejecting occluder for target coincidence." << endl;
@@ -2099,7 +2103,7 @@ int ViewMapBuilder::ComputeRayCastingVisibility(FEdge *fe, Grid *iGrid, real eps
}
// Find occludee
- FindOccludee(fe, iGrid, epsilon, oaPolygon, timestamp, u, center, edge, origin, faceVertices);
+ FindOccludee(fe, iGrid, epsilon, oaPolygon, timestamp, u, center, origin, edgeDir, faceVertices);
return qi;
}
diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.h b/source/blender/freestyle/intern/view_map/ViewMapBuilder.h
index 36497bf8d22..440ae93c7df 100644
--- a/source/blender/freestyle/intern/view_map/ViewMapBuilder.h
+++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.h
@@ -250,7 +250,7 @@ protected:
// FIXME
void FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3r **oaPolygon, unsigned timestamp);
void FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3r **oaPolygon, unsigned timestamp,
- Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edge, vector<WVertex*>& faceVertices);
+ Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edgeDir, vector<WVertex*>& faceVertices);
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:ViewMapBuilder")
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index cfa083116f2..ec623554567 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -31,6 +31,9 @@ set(INC
../imbuf
../makesdna
../makesrna
+ ../draw
+
+ ../editors/include
# For node muting stuff...
../nodes
@@ -39,6 +42,7 @@ set(INC
../../../intern/glew-mx
../../../intern/guardedalloc
../../../intern/smoke/extern
+ ../../../intern/gawain
)
set(INC_SYS
@@ -47,6 +51,7 @@ set(INC_SYS
set(SRC
intern/gpu_basic_shader.c
+ intern/gpu_batch.c
intern/gpu_buffers.c
intern/gpu_codegen.c
intern/gpu_compositing.c
@@ -54,11 +59,19 @@ set(SRC
intern/gpu_draw.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_lamp.c
intern/gpu_material.c
+ intern/gpu_matrix.c
intern/gpu_select.c
+ intern/gpu_select_pick.c
+ intern/gpu_select_sample_query.c
intern/gpu_shader.c
intern/gpu_texture.c
+ intern/gpu_uniformbuffer.c
+ intern/gpu_viewport.c
shaders/gpu_shader_fx_lib.glsl
shaders/gpu_shader_fx_ssao_frag.glsl
@@ -67,7 +80,7 @@ set(SRC
shaders/gpu_shader_fx_dof_hq_frag.glsl
shaders/gpu_shader_fx_dof_hq_vert.glsl
shaders/gpu_shader_fx_dof_hq_geo.glsl
- shaders/gpu_shader_fx_vert.glsl
+ shaders/gpu_shader_fullscreen_vert.glsl
shaders/gpu_shader_material.glsl
shaders/gpu_shader_sep_gaussian_blur_frag.glsl
shaders/gpu_shader_sep_gaussian_blur_vert.glsl
@@ -78,10 +91,12 @@ set(SRC
shaders/gpu_shader_vsm_store_frag.glsl
shaders/gpu_shader_vsm_store_vert.glsl
shaders/gpu_shader_fx_depth_resolve.glsl
+ shaders/gpu_shader_fire_frag.glsl
shaders/gpu_shader_smoke_frag.glsl
shaders/gpu_shader_smoke_vert.glsl
GPU_basic_shader.h
+ GPU_batch.h
GPU_buffers.h
GPU_compositing.h
GPU_debug.h
@@ -89,16 +104,109 @@ set(SRC
GPU_extensions.h
GPU_framebuffer.h
GPU_glew.h
+ GPU_immediate.h
+ GPU_immediate_util.h
GPU_init_exit.h
+ GPU_lamp.h
+ GPU_legacy_stubs.h
GPU_material.h
+ GPU_matrix.h
GPU_select.h
GPU_shader.h
GPU_texture.h
+ GPU_uniformbuffer.h
+ GPU_viewport.h
+
intern/gpu_codegen.h
intern/gpu_private.h
+ intern/gpu_lamp_private.h
+ intern/gpu_select_private.h
+ intern/gpu_shader_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_2D_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_image_vert.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_rect_modulate_alpha_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_image_depth_linear_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_image_interlace_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_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_instance_bone_envelope_solid_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_instance_bone_envelope_wire_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_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_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_vert.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)
@@ -111,7 +219,7 @@ 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_fullscreen_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)
diff --git a/source/blender/gpu/GPU_basic_shader.h b/source/blender/gpu/GPU_basic_shader.h
index d9bf3d1ced3..dc378927e79 100644
--- a/source/blender/gpu/GPU_basic_shader.h
+++ b/source/blender/gpu/GPU_basic_shader.h
@@ -64,12 +64,6 @@ typedef enum GPUBasicShaderStipple {
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);
@@ -132,9 +126,6 @@ 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
diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h
new file mode 100644
index 00000000000..d052a2d831f
--- /dev/null
+++ b/source/blender/gpu/GPU_batch.h
@@ -0,0 +1,51 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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 *****
+ */
+
+/* Batched geometry rendering is powered by the Gawain library.
+ * This file contains any additions or modifications specific to Blender.
+ */
+
+#ifndef __GPU_BATCH_H__
+#define __GPU_BATCH_H__
+
+#include "../../../intern/gawain/gawain/batch.h"
+
+// TODO: CMake magic to do this:
+// #include "gawain/batch.h"
+
+#include "GPU_shader.h"
+
+/* Extend GWN_batch_program_set to use Blender’s library of built-in shader programs. */
+void Batch_set_builtin_program(Gwn_Batch*, GPUBuiltinShader);
+
+/* Replacement for gluSphere */
+Gwn_Batch *Batch_get_sphere(int lod);
+Gwn_Batch *Batch_get_sphere_wire(int lod);
+
+void gpu_batch_init(void);
+void gpu_batch_exit(void);
+
+#endif /* __GPU_BATCH_H__ */
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index b693d473bd8..30fd4bd30b8 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -51,6 +51,7 @@ struct GPUVertPointLink;
struct GPUDrawObject;
struct GridCommonGPUBuffer;
struct PBVH;
+struct Gwn_Batch;
struct MVert;
typedef struct GPUBuffer {
@@ -222,50 +223,52 @@ void GPU_interleaved_attrib_unbind(void);
typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers;
/* build */
-GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(
+GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(
const int (*face_vert_indices)[3],
const struct MPoly *mpoly, const struct MLoop *mloop, const struct MLoopTri *looptri,
const struct MVert *verts,
const int *face_indices,
const int face_indices_len);
-GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(
+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);
-GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(bool smooth_shading);
+GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading);
/* update */
-void GPU_update_mesh_pbvh_buffers(
+void GPU_pbvh_mesh_buffers_update(
GPU_PBVH_Buffers *buffers, const struct MVert *mvert,
const int *vert_indices, int totvert, const float *vmask,
const int (*face_vert_indices)[3], bool show_diffuse_color);
-void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
- struct BMesh *bm,
- struct GSet *bm_faces,
- struct GSet *bm_unique_verts,
- struct GSet *bm_other_verts,
- bool show_diffuse_color);
+void GPU_pbvh_bmesh_buffers_update(
+ GPU_PBVH_Buffers *buffers,
+ struct BMesh *bm,
+ struct GSet *bm_faces,
+ struct GSet *bm_unique_verts,
+ struct GSet *bm_other_verts,
+ bool show_diffuse_color);
-void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, struct CCGElem **grids,
- const struct DMFlagMat *grid_flag_mats,
- int *grid_indices, int totgrid, const struct CCGKey *key,
- bool show_diffuse_color);
+void GPU_pbvh_grid_buffers_update(
+ GPU_PBVH_Buffers *buffers, struct CCGElem **grids,
+ const struct DMFlagMat *grid_flag_mats,
+ int *grid_indices, int totgrid, const struct CCGKey *key,
+ bool show_diffuse_color);
/* draw */
-void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
- bool wireframe, bool fast);
+void GPU_pbvh_buffers_draw(
+ GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
+ bool wireframe, bool fast);
+struct Gwn_Batch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast);
-/* debug PBVH draw*/
-void GPU_draw_pbvh_BB(float min[3], float max[3], bool leaf);
-void GPU_end_draw_pbvh_BB(void);
-void GPU_init_draw_pbvh_BB(void);
+/* debug PBVH draw */
+void GPU_pbvh_BB_draw(float min[3], float max[3], bool leaf, unsigned int pos);
bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, struct GSet *bm_faces, bool show_diffuse_color);
-void GPU_free_pbvh_buffers(GPU_PBVH_Buffers *buffers);
-void GPU_free_pbvh_buffer_multires(struct GridCommonGPUBuffer **grid_common_gpu_buffer);
+void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers);
+void GPU_pbvh_multires_buffers_free(struct GridCommonGPUBuffer **grid_common_gpu_buffer);
#endif
diff --git a/source/blender/gpu/GPU_debug.h b/source/blender/gpu/GPU_debug.h
index 2c1728bfff1..c7a99d33654 100644
--- a/source/blender/gpu/GPU_debug.h
+++ b/source/blender/gpu/GPU_debug.h
@@ -34,8 +34,6 @@
#include "GPU_glew.h"
-#include "BLI_utildefines.h"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -43,26 +41,8 @@ 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(size_t size, const char *str);
+void GPU_string_marker(const char *str);
#ifdef __cplusplus
}
diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h
index 90b65af87c8..ad7eb0339e0 100644
--- a/source/blender/gpu/GPU_draw.h
+++ b/source/blender/gpu/GPU_draw.h
@@ -39,9 +39,9 @@ extern "C" {
struct ImBuf;
struct Image;
struct ImageUser;
-struct MTexPoly;
struct Object;
struct Scene;
+struct SceneLayer;
struct View3D;
struct RegionView3D;
struct SmokeModifierData;
@@ -59,6 +59,13 @@ struct DupliObject;
void GPU_state_init(void);
+/* Programmable point size
+ * - shaders set their own point size when enabled
+ * - use glPointSize when disabled */
+
+void GPU_enable_program_point_size(void);
+void GPU_disable_program_point_size(void);
+
/* Material drawing
* - first the state is initialized by a particular object and
* it's materials
@@ -66,8 +73,9 @@ void GPU_state_init(void);
* 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_begin_object_materials(struct View3D *v3d, struct RegionView3D *rv3d,
+ struct Scene *scene, struct SceneLayer *sl,
+ struct Object *ob, bool glsl, bool *do_alpha_after);
void GPU_end_object_materials(void);
bool GPU_object_materials_check(void);
@@ -84,29 +92,19 @@ 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);
-
/* 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);
+ struct SceneLayer *sl, 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,
+ int mode, const char *textstr, int textlen, unsigned int *col,
const float *v_quad[4], const float *uv_quad[4],
int glattrib);
@@ -166,6 +164,17 @@ 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_extensions.h b/source/blender/gpu/GPU_extensions.h
index 4a728c881b6..d36b0ea15be 100644
--- a/source/blender/gpu/GPU_extensions.h
+++ b/source/blender/gpu/GPU_extensions.h
@@ -38,22 +38,16 @@ extern "C" {
/* GPU extensions support */
-void GPU_extensions_disable(void);
-
-bool GPU_legacy_support(void);
-bool GPU_glsl_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_textures(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);
int GPU_color_depth(void);
void GPU_get_dfdy_factors(float fac[2]);
diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h
index 2719b8fa6a8..a079d12b469 100644
--- a/source/blender/gpu/GPU_framebuffer.h
+++ b/source/blender/gpu/GPU_framebuffer.h
@@ -50,8 +50,13 @@ struct GPUTexture;
void GPU_texture_bind_as_framebuffer(struct GPUTexture *tex);
GPUFrameBuffer *GPU_framebuffer_create(void);
-int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, char err_out[256]);
+bool GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int mip);
+bool GPU_framebuffer_texture_layer_attach(
+ GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int layer, int mip);
+bool GPU_framebuffer_texture_cubeface_attach(
+ GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int face, int mip);
void GPU_framebuffer_texture_detach(struct GPUTexture *tex);
+void GPU_framebuffer_bind(GPUFrameBuffer *fb);
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);
@@ -66,6 +71,14 @@ void GPU_framebuffer_blur(
GPUFrameBuffer *fb, struct GPUTexture *tex,
GPUFrameBuffer *blurfb, struct GPUTexture *blurtex);
+void GPU_framebuffer_blit(
+ GPUFrameBuffer *fb_read, int read_slot,
+ GPUFrameBuffer *fb_write, int write_slot, bool use_depth);
+
+void GPU_framebuffer_recursive_downsample(
+ GPUFrameBuffer *fb, struct GPUTexture *tex, int num_iter,
+ 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 */
@@ -79,6 +92,10 @@ int GPU_offscreen_width(const GPUOffScreen *ofs);
int GPU_offscreen_height(const GPUOffScreen *ofs);
int 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);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_glew.h b/source/blender/gpu/GPU_glew.h
index 94217863fd6..afe1c9763ad 100644
--- a/source/blender/gpu/GPU_glew.h
+++ b/source/blender/gpu/GPU_glew.h
@@ -34,4 +34,8 @@
#include "glew-mx.h"
+#ifndef WITH_LEGACY_OPENGL
+#include "GPU_legacy_stubs.h"
+#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..2eb4eb94f48
--- /dev/null
+++ b/source/blender/gpu/GPU_immediate.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) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Mike Erwin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/* Immediate mode rendering is powered by the Gawain library.
+ * This file contains any additions or modifications specific to Blender.
+ */
+
+#ifndef __GPU_IMMEDIATE_H__
+#define __GPU_IMMEDIATE_H__
+
+#include "../../../intern/gawain/gawain/immediate.h"
+#include "../../../intern/gawain/gawain/imm_util.h"
+
+// TODO: CMake magic to do this:
+// #include "gawain/immediate.h"
+// #include "gawain/imm_util.h"
+
+#include "GPU_shader.h"
+
+/* 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);
+
+#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..f91dd6147a0
--- /dev/null
+++ b/source/blender/gpu/GPU_immediate_util.h
@@ -0,0 +1,59 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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__
+
+void imm_cpack(unsigned int x);
+
+void imm_draw_circle_wire(uint shdr_pos, float x, float y, float radius, int nsegments);
+void imm_draw_circle_fill(uint shdr_pos, float x, float y, float radius, int nsegments);
+
+/* use this version when Gwn_VertFormat has a vec3 position */
+void imm_draw_circle_wire_3d(unsigned pos, float x, float y, float radius, int nsegments);
+void imm_draw_circle_fill_3d(unsigned pos, float x, float y, float radius, int nsegments);
+
+void imm_draw_disk_partial_fill(
+ unsigned pos, float x, float y,
+ float radius_inner, float radius_outer, int nsegments, float start, float sweep);
+
+void imm_draw_line_box(unsigned pos, float x1, float y1, float x2, float y2);
+
+void imm_draw_line_box_3d(unsigned pos, float x1, float y1, float x2, float y2);
+
+void imm_draw_checker_box(float x1, float y1, float x2, float y2);
+
+void imm_draw_cylinder_fill_normal_3d(
+ unsigned int pos, unsigned int nor, float base, float top, float height,
+ int slices, int stacks);
+void imm_draw_cylinder_wire_3d(
+ unsigned int pos, float base, float top, float height,
+ int slices, int stacks);
+void imm_draw_cylinder_fill_3d(
+ unsigned int pos, float base, float top, float height,
+ int slices, int stacks);
+
+#endif /* __GPU_IMMEDIATE_UTIL_H__ */
diff --git a/source/blender/gpu/GPU_lamp.h b/source/blender/gpu/GPU_lamp.h
new file mode 100644
index 00000000000..e08fbede80a
--- /dev/null
+++ b/source/blender/gpu/GPU_lamp.h
@@ -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) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Brecht Van Lommel, Clément Foucault.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file GPU_lamp.h
+ * \ingroup gpu
+ */
+
+#ifndef __GPU_LAMP_H__
+#define __GPU_LAMP_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Scene;
+struct Object;
+struct RenderEngineType;
+
+typedef struct GPULamp GPULamp;
+
+#define MAX_LAMP_DATA 2
+
+typedef struct LampEngineData {
+ void *storage[MAX_LAMP_DATA];
+} LampEngineData;
+
+LampEngineData *GPU_lamp_engine_data_get(struct Scene *scene, struct Object *ob, struct Object *par, struct RenderEngineType *re);
+
+GPULamp *GPU_lamp_from_blender(struct Scene *scene, struct Object *ob, struct Object *par);
+void GPU_lamp_free(struct Object *ob);
+void GPU_lamp_engine_data_free(LampEngineData *led);
+
+bool GPU_lamp_override_visible(GPULamp *lamp, struct SceneRenderLayer *srl, struct Material *ma);
+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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GPU_LAMP_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..a195eac9eec
--- /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 0d92d22a173..47035c8c64e 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -43,9 +43,9 @@ extern "C" {
struct Image;
struct ImageUser;
+struct ListBase;
struct Material;
struct Object;
-struct Image;
struct Scene;
struct SceneRenderLayer;
struct GPUVertexAttribs;
@@ -54,14 +54,17 @@ struct GPUNodeLink;
struct GPUNodeStack;
struct GPUMaterial;
struct GPUTexture;
+struct GPUUniformBuffer;
struct GPULamp;
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 */
@@ -76,6 +79,8 @@ typedef enum GPUType {
GPU_MAT3 = 9,
GPU_MAT4 = 16,
+ GPU_CLOSURE = 17,
+
GPU_TEX2D = 1002,
GPU_SHADOW2D = 1003,
GPU_TEXCUBE = 1004,
@@ -98,6 +103,7 @@ typedef enum GPUBuiltin {
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)
} GPUBuiltin;
typedef enum GPUOpenGLBuiltin {
@@ -140,6 +146,7 @@ typedef struct GPUNodeStack {
#define GPU_DYNAMIC_GROUP_MIST 0x00050000
#define GPU_DYNAMIC_GROUP_WORLD 0x00060000
#define GPU_DYNAMIC_GROUP_MAT 0x00070000
+#define GPU_DYNAMIC_UBO 0x00080000
typedef enum GPUDynamicType {
@@ -199,6 +206,7 @@ typedef enum GPUDynamicType {
GPUNodeLink *GPU_attribute(CustomDataType type, const char *name);
GPUNodeLink *GPU_uniform(float *num);
GPUNodeLink *GPU_dynamic_uniform(float *num, GPUDynamicType dynamictype, void *data);
+GPUNodeLink *GPU_uniform_buffer(float *num, GPUType gputype);
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);
@@ -209,32 +217,44 @@ 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);
-
+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);
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);
void GPU_material_free(struct ListBase *gpumaterial);
void GPU_materials_free(void);
-bool GPU_lamp_override_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 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 GPUUniformBuffer *GPU_material_get_uniform_buffer(GPUMaterial *material);
+void GPU_material_create_uniform_buffer(GPUMaterial *material, struct ListBase *inputs);
+void GPU_material_uniform_buffer_tag_dirty(struct ListBase *gpumaterials);
void GPU_material_vertex_attributes(GPUMaterial *material,
struct GPUVertexAttribs *attrib);
@@ -310,26 +330,8 @@ 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,
+ GPUMaterial *mat, struct GPULamp *lamp,
GPUNodeLink **r_col, GPUNodeLink **r_lv, GPUNodeLink **r_dist, GPUNodeLink **r_shadow, GPUNodeLink **r_energy);
/* World */
@@ -345,6 +347,7 @@ struct GPUParticleInfo
float location[3];
float velocity[3];
float angular_velocity[3];
+ int random_id;
};
#ifdef WITH_OPENSUBDIV
diff --git a/source/blender/gpu/GPU_matrix.h b/source/blender/gpu/GPU_matrix.h
new file mode 100644
index 00000000000..a3fd75b662b
--- /dev/null
+++ b/source/blender/gpu/GPU_matrix.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 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"
+#include "GPU_glew.h"
+#include "../../../intern/gawain/gawain/shader_interface.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void gpuMatrixReset(void); /* to Identity transform & empty stack */
+
+/* ModelView Matrix (2D or 3D) */
+
+void gpuPushMatrix(void); /* TODO: PushCopy vs PushIdentity? */
+void gpuPopMatrix(void);
+
+void gpuLoadIdentity(void);
+
+void gpuScaleUniform(float factor);
+
+
+/* 3D ModelView Matrix */
+
+void gpuLoadMatrix(const float m[4][4]);
+void gpuMultMatrix(const float m[4][4]);
+
+void gpuTranslate3f(float x, float y, float z);
+void gpuTranslate3fv(const float vec[3]);
+void gpuScale3f(float x, float y, float z);
+void gpuScale3fv(const float vec[3]);
+void gpuRotate3f(float deg, float x, float y, float z); /* axis of rotation should be a unit vector */
+void gpuRotate3fv(float deg, const float axis[3]); /* axis of rotation should be a unit vector */
+void gpuRotateAxis(float deg, char axis); /* TODO: enum for axis? */
+
+void gpuLookAt(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 gpuTranslate2f(float x, float y);
+void gpuTranslate2fv(const float vec[2]);
+void gpuScale2f(float x, float y);
+void gpuScale2fv(const float vec[2]);
+void gpuRotate2D(float deg);
+
+/* Projection Matrix (2D or 3D) */
+
+void gpuPushProjectionMatrix(void);
+void gpuPopProjectionMatrix(void);
+
+/* 3D Projection Matrix */
+
+void gpuLoadIdentityProjectionMatrix(void);
+void gpuLoadProjectionMatrix(const float m[4][4]);
+
+void gpuOrtho(float left, float right, float bottom, float top, float near, float far);
+void gpuFrustum(float left, float right, float bottom, float top, float near, float far);
+void gpuPerspective(float fovy, float aspect, float near, float far);
+
+/* 3D Projection between Window and World Space */
+
+void gpuProject(const float world[3], const float model[4][4], const float proj[4][4], const int view[4], float win[3]);
+bool gpuUnProject(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 gpuOrtho2D(float left, float right, float bottom, float top);
+
+
+/* functions to get matrix values */
+const float (*gpuGetModelViewMatrix(float m[4][4]))[4];
+const float (*gpuGetProjectionMatrix(float m[4][4]))[4];
+const float (*gpuGetModelViewProjectionMatrix(float m[4][4]))[4];
+
+const float (*gpuGetNormalMatrix(float m[3][3]))[3];
+const float (*gpuGetNormalMatrixInverse(float m[3][3]))[3];
+
+
+/* set uniform values for currently bound shader */
+void gpuBindMatrices(const Gwn_ShaderInterface*);
+bool gpuMatricesDirty(void); /* since last bind */
+
+#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 gpuMultMatrix(x) gpuMultMatrix(_GPU_MAT4_CONST_CAST(x))
+# define gpuLoadMatrix(x) gpuLoadMatrix(_GPU_MAT4_CONST_CAST(x))
+# define gpuLoadProjectionMatrix(x) gpuLoadProjectionMatrix(_GPU_MAT4_CONST_CAST(x))
+# define gpuGetModelViewMatrix(x) gpuGetModelViewMatrix(_GPU_MAT4_CAST(x))
+# define gpuGetProjectionMatrix(x) gpuGetProjectionMatrix(_GPU_MAT4_CAST(x))
+# define gpuGetModelViewProjectionMatrix(x) gpuGetModelViewProjectionMatrix(_GPU_MAT4_CAST(x))
+# define gpuGetNormalMatrix(x) gpuGetNormalMatrix(_GPU_MAT3_CAST(x))
+# define gpuGetNormalMatrixInverse(x) gpuGetNormalMatrixInverse(_GPU_MAT3_CAST(x))
+#endif /* SUPPRESS_GENERIC_MATRIX_API */
+
+#endif /* __GPU_MATRIX_H__ */
diff --git a/source/blender/gpu/GPU_select.h b/source/blender/gpu/GPU_select.h
index 6a16b5b7456..cf5b8bf7d8f 100644
--- a/source/blender/gpu/GPU_select.h
+++ b/source/blender/gpu/GPU_select.h
@@ -30,19 +30,30 @@
#ifndef __GPU_SELECT_H__
#define __GPU_SELECT_H__
-#include "DNA_vec_types.h" /* rcft */
#include "BLI_sys_types.h"
+struct rcti;
+
/* flags for mode of operation */
enum {
GPU_SELECT_ALL = 1,
+ /* gpu_select_query */
GPU_SELECT_NEAREST_FIRST_PASS = 2,
GPU_SELECT_NEAREST_SECOND_PASS = 3,
+ /* gpu_select_pick */
+ GPU_SELECT_PICK_ALL = 4,
+ GPU_SELECT_PICK_NEAREST = 5,
};
-void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, char mode, int oldhits);
+void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, const struct rcti *input, char mode, int oldhits);
bool GPU_select_load_id(unsigned int id);
unsigned int GPU_select_end(void);
bool GPU_select_query_check_active(void);
+/* cache selection region */
+bool GPU_select_is_cached(void);
+void GPU_select_cache_begin(void);
+void GPU_select_cache_load_id(void);
+void GPU_select_cache_end(void);
+
#endif
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index 762329ee077..7c8ee07eb88 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -38,6 +38,7 @@ extern "C" {
typedef struct GPUShader GPUShader;
struct GPUTexture;
+struct GPUUniformBuffer;
/* GPU Shader
* - only for fragment shaders now
@@ -54,29 +55,34 @@ GPUShader *GPU_shader_create(
const char *fragcode,
const char *geocode,
const char *libcode,
- const char *defines,
- int input, int output, int number);
+ const char *defines);
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);
void GPU_shader_free(GPUShader *shader);
void GPU_shader_bind(GPUShader *shader);
void GPU_shader_unbind(void);
+int GPU_shader_get_program(GPUShader *shader);
+
void *GPU_shader_get_interface(GPUShader *shader);
-void GPU_shader_set_interface(GPUShader *shader, void *interface);
+
+void *GPU_fx_shader_get_interface(GPUShader *shader);
+void GPU_fx_shader_set_interface(GPUShader *shader, void *interface);
+
int GPU_shader_get_uniform(GPUShader *shader, const char *name);
+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_int(GPUShader *shader, int location, int value);
void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number);
@@ -85,12 +91,99 @@ 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_VSM_STORE,
+ GPU_SHADER_SEP_GAUSSIAN_BLUR,
+ GPU_SHADER_SMOKE,
+ GPU_SHADER_SMOKE_FIRE,
+ GPU_SHADER_SMOKE_COBA,
+
+ /* specialized drawing */
+ GPU_SHADER_TEXT,
+ 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 */
+ GPU_SHADER_2D_UNIFORM_COLOR,
+ GPU_SHADER_2D_FLAT_COLOR,
+ GPU_SHADER_2D_SMOOTH_COLOR,
+ GPU_SHADER_2D_IMAGE_COLOR,
+ GPU_SHADER_2D_IMAGE_ALPHA_COLOR,
+ GPU_SHADER_2D_CHECKER,
+ GPU_SHADER_2D_DIAG_STRIPES,
+ /* for simple 3D drawing */
+ GPU_SHADER_3D_UNIFORM_COLOR,
+ GPU_SHADER_3D_UNIFORM_COLOR_INSTANCE,
+ GPU_SHADER_3D_FLAT_COLOR,
+ GPU_SHADER_3D_FLAT_COLOR_U32, /* use for select-id's */
+ GPU_SHADER_3D_SMOOTH_COLOR,
+ 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,
+ GPU_SHADER_3D_IMAGE_MODULATE_ALPHA,
+ GPU_SHADER_3D_IMAGE_RECT_MODULATE_ALPHA,
+ GPU_SHADER_3D_IMAGE_DEPTH,
+ /* stereo 3d */
+ GPU_SHADER_2D_IMAGE_INTERLACE,
+ /* points */
+ GPU_SHADER_2D_POINT_FIXED_SIZE_UNIFORM_COLOR,
+ GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA,
+ GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA,
+ GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_AA,
+ GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR,
+ GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR,
+ GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR,
+ GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA,
+ GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA,
+ GPU_SHADER_3D_POINT_VARYING_SIZE_UNIFORM_COLOR,
+ 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_COLOR_VARIYING_SIZE, /* Uniformly scaled */
+ GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SCALE,
+ GPU_SHADER_INSTANCE_EDGES_VARIYING_COLOR,
+
+ GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_SOLID,
+ GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_WIRE,
+
+ 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);
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index 756fe79151b..6d6c195c175 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -55,25 +55,118 @@ 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;
+/* 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_RGBA32F,
+ GPU_RGBA16F,
+ GPU_RGBA8,
+ GPU_RG32F,
+ GPU_RG16F,
+ GPU_R32F,
+ GPU_R16F,
+ GPU_R8,
+#if 0
+ GPU_RGBA32I,
+ GPU_RGBA32UI,
+ GPU_RGBA16,
+ GPU_RGBA16I,
+ GPU_RGBA16UI,
+ GPU_RGBA8I,
+ GPU_RGBA8UI,
+ GPU_RG32I,
+ GPU_RG32UI,
+ GPU_RG16,
+ GPU_RG16I,
+ GPU_RG16UI,
+ GPU_RG8,
+ GPU_RG8I,
+ GPU_RG8UI,
+ GPU_R32I,
+ GPU_R32UI,
+ GPU_R16I,
+ GPU_R16UI,
+ GPU_R16,
+ GPU_R8I,
+ GPU_R8UI,
+#endif
+
+ /* Special formats texture & renderbuffer */
+#if 0
+ GPU_RGB10_A2,
+ GPU_RGB10_A2UI,
+ GPU_DEPTH32F_STENCIL8,
+#endif
+ GPU_R11F_G11F_B10F,
+ 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;
+
+unsigned int GPU_texture_memory_usage_get(void);
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_1D_custom(
+ int w, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]);
+GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, char err_out[256]);
+GPUTexture *GPU_texture_create_2D_custom(
+ int w, int h, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]);
+GPUTexture *GPU_texture_create_2D_multisample(int w, int h, const float *pixels, int samples, char err_out[256]);
+GPUTexture *GPU_texture_create_2D_array_custom(
+ int w, int h, int d, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]);
+GPUTexture *GPU_texture_create_3D(int w, int h, int d, const float *pixels, char err_out[256]);
+GPUTexture *GPU_texture_create_3D_custom(
+ int w, int h, int d, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]);
+GPUTexture *GPU_texture_create_cube_custom(
+ int w, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]);
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]);
-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_with_stencil(int w, int h, char err_out[256]);
GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256]);
+
GPUTexture *GPU_texture_from_blender(
struct Image *ima, struct ImageUser *iuser, int textarget, bool is_data, double time, int mipmap);
GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap);
+
void GPU_invalid_tex_init(void);
void GPU_invalid_tex_bind(int mode);
void GPU_invalid_tex_free(void);
@@ -81,12 +174,15 @@ 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);
struct GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex);
int GPU_texture_framebuffer_attachment(GPUTexture *tex);
@@ -95,7 +191,9 @@ void GPU_texture_framebuffer_set(GPUTexture *tex, struct GPUFrameBuffer *fb, int
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_format(const GPUTexture *tex);
+bool GPU_texture_depth(const GPUTexture *tex);
+bool GPU_texture_stencil(const GPUTexture *tex);
int GPU_texture_opengl_bindcode(const GPUTexture *tex);
#ifdef __cplusplus
diff --git a/source/blender/gpu/GPU_uniformbuffer.h b/source/blender/gpu/GPU_uniformbuffer.h
new file mode 100644
index 00000000000..e342078d8fd
--- /dev/null
+++ b/source/blender/gpu/GPU_uniformbuffer.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.
+ *
+ * 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__
+
+typedef enum GPUType GPUType;
+struct ListBase;
+
+typedef struct GPUUniformBuffer GPUUniformBuffer;
+typedef struct GPUUniformBufferDynamicItem GPUUniformBufferDynamicItem;
+
+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);
+#if 0
+void GPU_uniformbuffer_unbind(GPUUniformBuffer *ubo);
+#endif
+
+int GPU_uniformbuffer_bindpoint(GPUUniformBuffer *ubo);
+
+bool GPU_uniformbuffer_is_empty(GPUUniformBuffer *ubo);
+bool GPU_uniformbuffer_is_dirty(GPUUniformBuffer *ubo);
+void GPU_uniformbuffer_tag_dirty(GPUUniformBuffer *ubo);
+
+#define GPU_UBO_BLOCK_NAME "nodeTree"
+
+#endif /* __GPU_UNIFORMBUFFER_H__ */
diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h
new file mode 100644
index 00000000000..2b2a07f50b7
--- /dev/null
+++ b/source/blender/gpu/GPU_viewport.h
@@ -0,0 +1,118 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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;
+
+/* 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 cache_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_free(GPUViewport *viewport);
+
+GPUViewport *GPU_viewport_create_from_offscreen(struct GPUOffScreen *ofs);
+void GPU_viewport_clear_from_offscreen(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]);
+
+/* Texture pool */
+GPUTexture *GPU_viewport_texture_pool_query(GPUViewport *viewport, void *engine, int width, int height, int channels, int format);
+
+bool GPU_viewport_cache_validate(GPUViewport *viewport, unsigned int hash);
+
+/* debug */
+bool GPU_viewport_debug_depth_create(GPUViewport *viewport, int width, int height, char err_out[256]);
+void GPU_viewport_debug_depth_free(GPUViewport *viewport);
+void GPU_viewport_debug_depth_store(GPUViewport *viewport, const int x, const int y);
+void GPU_viewport_debug_depth_draw(GPUViewport *viewport, const float znear, const float zfar);
+bool GPU_viewport_debug_depth_is_valid(GPUViewport *viewport);
+int GPU_viewport_debug_depth_width(const GPUViewport *viewport);
+int GPU_viewport_debug_depth_height(const GPUViewport *viewport);
+
+#endif // __GPU_VIEWPORT_H__
diff --git a/source/blender/gpu/intern/gpu_basic_shader.c b/source/blender/gpu/intern/gpu_basic_shader.c
index a2b89239344..620a06ae606 100644
--- a/source/blender/gpu/intern/gpu_basic_shader.c
+++ b/source/blender/gpu/intern/gpu_basic_shader.c
@@ -140,114 +140,6 @@ const GLubyte stipple_checker_8px[128] = {
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,
@@ -267,24 +159,6 @@ const GLubyte stipple_hexagon[128] = {
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)
@@ -316,31 +190,6 @@ static bool solid_compatible_lighting(void)
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 */
@@ -388,7 +237,7 @@ static GPUShader *gpu_basic_shader(int options)
datatoc_gpu_shader_basic_frag_glsl,
geom_glsl,
NULL,
- defines, 0, 0, 0);
+ defines);
if (shader) {
/* set texture map to first texture unit */
@@ -407,7 +256,7 @@ static GPUShader *gpu_basic_shader(int options)
return shader;
}
-static void GPU_basic_shader_uniform_autoset(GPUShader *shader, int options)
+static void gpu_basic_shader_uniform_autoset(GPUShader *shader, int options)
{
if (options & GPU_SHADER_LINE) {
glGetIntegerv(GL_VIEWPORT, &GPU_MATERIAL_STATE.viewport[0]);
@@ -420,102 +269,16 @@ static void GPU_basic_shader_uniform_autoset(GPUShader *shader, int options)
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 (options) {
+ GPUShader *shader = gpu_basic_shader(options);
- if (shader) {
- GPU_shader_bind(shader);
- GPU_basic_shader_uniform_autoset(shader, options);
- }
- }
- else {
- GPU_shader_unbind();
+ if (shader) {
+ GPU_shader_bind(shader);
+ gpu_basic_shader_uniform_autoset(shader, options);
}
}
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_shader_unbind();
}
GPU_MATERIAL_STATE.bound_options = options;
@@ -544,175 +307,37 @@ 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));
+ UNUSED_VARS(diffuse, specular, shininess, alpha);
+ return;
}
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);
- }
+ UNUSED_VARS(light_num, light);
+ return;
}
void GPU_basic_shader_light_set_viewer(bool local)
{
- glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, (local) ? GL_TRUE: GL_FALSE);
+ UNUSED_VARS(local);
+ return;
}
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;
- }
- }
+ glUniform1i(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "stipple_id"), stipple_id);
}
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);
+ 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);
}
}
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);
- }
+ 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);
}
diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c
new file mode 100644
index 00000000000..92bab13dcb5
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_batch.c
@@ -0,0 +1,171 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Mike Erwin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "GPU_batch.h"
+#include "gpu_shader_private.h"
+
+void Batch_set_builtin_program(Gwn_Batch *batch, GPUBuiltinShader shader_id)
+{
+ GPUShader *shader = GPU_shader_get_builtin_shader(shader_id);
+ GWN_batch_program_set(batch, shader->program, shader->interface);
+}
+
+static Gwn_Batch *sphere_high = NULL;
+static Gwn_Batch *sphere_med = NULL;
+static Gwn_Batch *sphere_low = NULL;
+static Gwn_Batch *sphere_wire_low = NULL;
+static Gwn_Batch *sphere_wire_med = NULL;
+
+static Gwn_VertBuf *vbo;
+static Gwn_VertFormat format = {0};
+static unsigned int pos_id, nor_id;
+static unsigned int vert;
+
+static void batch_sphere_lat_lon_vert(float lat, float lon)
+{
+ float pos[3];
+ pos[0] = sinf(lat) * cosf(lon);
+ pos[1] = cosf(lat);
+ pos[2] = sinf(lat) * sinf(lon);
+
+ GWN_vertbuf_attr_set(vbo, nor_id, vert, pos);
+ GWN_vertbuf_attr_set(vbo, pos_id, vert++, pos);
+}
+
+/* Replacement for gluSphere */
+static Gwn_Batch *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;
+
+ if (format.attrib_ct == 0) {
+ pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ nor_id = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, (lat_res - 1) * lon_res * 6);
+ vert = 0;
+
+ 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(lat + lat_inc, lon + lon_inc);
+ batch_sphere_lat_lon_vert(lat + lat_inc, lon);
+ batch_sphere_lat_lon_vert(lat, lon);
+ }
+
+ if (j != 0) { /* Pole */
+ batch_sphere_lat_lon_vert(lat, lon + lon_inc);
+ batch_sphere_lat_lon_vert(lat + lat_inc, lon + lon_inc);
+ batch_sphere_lat_lon_vert(lat, lon);
+ }
+ }
+ }
+
+ return GWN_batch_create(GWN_PRIM_TRIS, vbo, NULL);
+}
+
+static Gwn_Batch *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;
+
+ if (format.attrib_ct == 0) {
+ pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ nor_id = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, (lat_res * lon_res * 2) + ((lat_res - 1) * lon_res * 2));
+ vert = 0;
+
+ 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(lat + lat_inc, lon);
+ batch_sphere_lat_lon_vert(lat, lon);
+
+ if (j != lat_res - 1) { /* Pole */
+ batch_sphere_lat_lon_vert(lat + lat_inc, lon + lon_inc);
+ batch_sphere_lat_lon_vert(lat + lat_inc, lon);
+ }
+ }
+ }
+
+ return GWN_batch_create(GWN_PRIM_LINES, vbo, NULL);
+}
+
+Gwn_Batch *Batch_get_sphere(int lod)
+{
+ BLI_assert(lod >= 0 && lod <= 2);
+
+ if (lod == 0)
+ return sphere_low;
+ else if (lod == 1)
+ return sphere_med;
+ else
+ return sphere_high;
+}
+
+Gwn_Batch *Batch_get_sphere_wire(int lod)
+{
+ BLI_assert(lod >= 0 && lod <= 1);
+
+ if (lod == 0)
+ return sphere_wire_low;
+ else
+ return sphere_wire_med;
+}
+
+void gpu_batch_init(void)
+{
+ /* Hard coded resolution */
+ sphere_low = batch_sphere(8, 16);
+ sphere_med = batch_sphere(16, 10);
+ sphere_high = batch_sphere(32, 24);
+
+ sphere_wire_low = batch_sphere_wire(6, 8);
+ sphere_wire_med = batch_sphere_wire(8, 16);
+}
+
+void gpu_batch_exit(void)
+{
+ GWN_batch_discard_all(sphere_low);
+ GWN_batch_discard_all(sphere_med);
+ GWN_batch_discard_all(sphere_high);
+ GWN_batch_discard_all(sphere_wire_low);
+ GWN_batch_discard_all(sphere_wire_med);
+}
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 370841327aa..fb2e271f9a2 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,10 +53,14 @@
#include "GPU_buffers.h"
#include "GPU_draw.h"
-#include "GPU_basic_shader.h"
+#include "GPU_immediate.h"
+#include "GPU_batch.h"
#include "bmesh.h"
+/* TODO: gawain support for baseelemarray */
+// #define USE_BASE_ELEM
+
typedef enum {
GPU_BUFFER_VERTEX_STATE = (1 << 0),
GPU_BUFFER_NORMAL_STATE = (1 << 1),
@@ -106,9 +108,8 @@ 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;
+ Gwn_IndexBuf *mres_buffer;
int mres_prev_gridsize;
- GLenum mres_prev_index_type;
unsigned mres_prev_totquad;
} GridCommonGPUBuffer;
@@ -743,7 +744,7 @@ void GPU_triangle_setup(struct DerivedMesh *dm)
GLStates |= GPU_BUFFER_ELEMENT_STATE;
}
-static int GPU_typesize(int type)
+static int gpu_typesize(int type)
{
switch (type) {
case GL_FLOAT:
@@ -766,7 +767,7 @@ 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);
+ int typesize = gpu_typesize(data[i].type);
if (typesize != 0)
elementsize += typesize * data[i].size;
}
@@ -803,7 +804,7 @@ void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numda
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);
+ offset += data[i].size * gpu_typesize(data[i].type);
attribData[i].index = data[i].index;
attribData[i].size = data[i].size;
@@ -943,26 +944,12 @@ void GPU_buffer_draw_elements(GPUBuffer *UNUSED(elements), unsigned int mode, in
/* 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;
+ Gwn_IndexBuf *index_buf, *index_buf_fast;
+ Gwn_VertBuf *vert_buf;
- int *baseelemarray;
- void **baseindex;
+ Gwn_Batch *triangles;
+ Gwn_Batch *triangles_fast;
/* mesh pointers in case buffer allocation fails */
const MPoly *mpoly;
@@ -997,6 +984,39 @@ struct GPU_PBVH_Buffers {
float diffuse_color[4];
};
+typedef struct {
+ uint pos, nor, col;
+} VertexBufferAttrID;
+
+static void gpu_pbvh_vert_format_init__gwn(Gwn_VertFormat *format, VertexBufferAttrID *vbo_id)
+{
+ vbo_id->pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ vbo_id->nor = GWN_vertformat_attr_add(format, "nor", GWN_COMP_I16, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+ vbo_id->col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
+}
+
+static void gpu_pbvh_batch_init(GPU_PBVH_Buffers *buffers)
+{
+ /* force flushing to the GPU */
+ if (buffers->vert_buf->data) {
+ GWN_vertbuf_use(buffers->vert_buf);
+ }
+
+ GWN_BATCH_DISCARD_SAFE(buffers->triangles);
+ buffers->triangles = GWN_batch_create(
+ GWN_PRIM_TRIS, buffers->vert_buf,
+ /* can be NULL */
+ buffers->index_buf);
+
+ GWN_BATCH_DISCARD_SAFE(buffers->triangles_fast);
+ if (buffers->index_buf_fast) {
+ buffers->triangles_fast = GWN_batch_create(
+ GWN_PRIM_TRIS, buffers->vert_buf,
+ /* can be NULL */
+ buffers->index_buf_fast);
+ }
+}
+
static float gpu_color_from_mask(float mask)
{
return 1.0f - mask * 0.75f;
@@ -1030,14 +1050,11 @@ static void gpu_color_from_mask_quad_copy(const CCGKey *key,
out[2] = diffuse_color[2] * mask_color;
}
-void GPU_update_mesh_pbvh_buffers(
+void GPU_pbvh_mesh_buffers_update(
GPU_PBVH_Buffers *buffers, const MVert *mvert,
const int *vert_indices, int totvert, const float *vmask,
const int (*face_vert_indices)[3], bool show_diffuse_color)
{
- VertexBufferFormat *vert_data;
- int i, j;
-
buffers->vmask = vmask;
buffers->show_diffuse_color = show_diffuse_color;
buffers->use_matcaps = GPU_material_use_matcaps_get();
@@ -1057,54 +1074,54 @@ void GPU_update_mesh_pbvh_buffers(
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);
+ GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf);
+
+ /* match 'VertexBufferFormat' */
+ Gwn_VertFormat format = {0};
+ VertexBufferAttrID vbo_id;
+ gpu_pbvh_vert_format_init__gwn(&format, &vbo_id);
- if (vert_data) {
+ buffers->vert_buf = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(buffers->vert_buf, totelem);
+
+ if (buffers->vert_buf->data) {
/* 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);
+ GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.pos, i, v->co);
+ GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.nor, i, v->no);
}
-#define UPDATE_VERTEX(face, vertex, index, diffuse_color) \
- { \
- VertexBufferFormat *out = vert_data + face_vert_indices[face][index]; \
- if (vmask) \
- gpu_color_from_mask_copy(vmask[vertex], diffuse_color, out->color); \
- else \
- rgb_float_to_uchar(out->color, diffuse_color); \
- } (void)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] = {
- buffers->mloop[lt->tri[0]].v,
- buffers->mloop[lt->tri[1]].v,
- buffers->mloop[lt->tri[2]].v,
- };
-
- UPDATE_VERTEX(i, vtri[0], 0, diffuse_color);
- UPDATE_VERTEX(i, vtri[1], 1, diffuse_color);
- UPDATE_VERTEX(i, vtri[2], 2, diffuse_color);
+ for (uint j = 0; j < 3; j++) {
+ int vidx = face_vert_indices[i][j];
+ if (vmask) {
+ int v_index = buffers->mloop[lt->tri[j]].v;
+ uchar color_ub[3];
+ gpu_color_from_mask_copy(vmask[v_index], diffuse_color, color_ub);
+ GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.col, vidx, color_ub);
+ }
+ else {
+ GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.col, vidx, diffuse_color_ub);
+ }
+ }
}
-#undef UPDATE_VERTEX
}
else {
/* calculate normal for each polygon only once */
unsigned int 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] = {
buffers->mloop[lt->tri[0]].v,
@@ -1112,8 +1129,6 @@ void GPU_update_mesh_pbvh_buffers(
buffers->mloop[lt->tri[2]].v,
};
- float fmask;
-
if (paint_is_face_hidden(lt, mvert, buffers->mloop))
continue;
@@ -1126,41 +1141,38 @@ void GPU_update_mesh_pbvh_buffers(
mpoly_prev = lt->poly;
}
+ uchar color_ub[3];
if (vmask) {
- fmask = (vmask[vtri[0]] +
- vmask[vtri[1]] +
- vmask[vtri[2]]) / 3.0f;
+ 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);
}
- for (j = 0; j < 3; j++) {
+ 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);
- if (vmask)
- gpu_color_from_mask_copy(fmask, diffuse_color, out->color);
- else
- rgb_float_to_uchar(out->color, diffuse_color);
+ GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.pos, vbo_index, v->co);
+ GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.nor, vbo_index, no);
+ GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.col, vbo_index, color_ub);
- vert_data++;
+ vbo_index++;
}
}
}
- GPU_buffer_unlock(buffers->vert_buf, GPU_BINDING_ARRAY);
+ gpu_pbvh_batch_init(buffers);
}
else {
- GPU_buffer_free(buffers->vert_buf);
- buffers->vert_buf = NULL;
+ GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf);
}
}
buffers->mvert = mvert;
}
-GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(
+GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(
const int (*face_vert_indices)[3],
const MPoly *mpoly, const MLoop *mloop, const MLoopTri *looptri,
const MVert *mvert,
@@ -1168,12 +1180,17 @@ GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(
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->use_matcaps = false;
@@ -1201,35 +1218,28 @@ GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(
* 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;
+ Gwn_IndexBufBuilder elb;
+ GWN_indexbuf_init(&elb, GWN_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;
+
+ GWN_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 = GWN_indexbuf_build(&elb);
+ }
+ else {
+ if (!buffers->is_index_buf_global) {
+ GWN_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
}
+ buffers->index_buf = NULL;
+ buffers->is_index_buf_global = false;
}
buffers->tot_tri = tottri;
@@ -1244,11 +1254,11 @@ GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(
return buffers;
}
-void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids,
- const DMFlagMat *grid_flag_mats, int *grid_indices,
- int totgrid, const CCGKey *key, bool show_diffuse_color)
+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, bool show_diffuse_color)
{
- VertexBufferFormat *vert_data;
int i, j, k, x, y;
buffers->show_diffuse_color = show_diffuse_color;
@@ -1256,12 +1266,13 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids,
buffers->smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH;
/* Build VBO */
- if (buffers->vert_buf) {
+ if (buffers->index_buf) {
const int has_mask = key->has_mask;
float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 1.0f};
- if (buffers->use_matcaps)
+ 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]];
@@ -1270,33 +1281,43 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids,
copy_v4_v4(buffers->diffuse_color, diffuse_color);
- vert_data = GPU_buffer_lock_stream(buffers->vert_buf, GPU_BINDING_ARRAY);
- if (vert_data) {
+ Gwn_VertFormat format = {0};
+ VertexBufferAttrID vbo_id;
+ gpu_pbvh_vert_format_init__gwn(&format, &vbo_id);
+
+ /* Build coord/normal VBO */
+ GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf);
+ buffers->vert_buf = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(buffers->vert_buf, totgrid * key->grid_area);
+
+ uint vbo_index_offset = 0;
+ if (buffers->vert_buf->data) {
for (i = 0; i < totgrid; ++i) {
- VertexBufferFormat *vd = vert_data;
CCGElem *grid = grids[grid_indices[i]];
+ int vbo_index = vbo_index_offset;
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);
-
- copy_v3_v3(vd->co, CCG_elem_co(key, elem));
+ GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.pos, vbo_index, CCG_elem_co(key, elem));
+
if (buffers->smooth) {
- normal_float_to_short_v3(vd->no, CCG_elem_no(key, elem));
+ short no_short[3];
+ normal_float_to_short_v3(no_short, CCG_elem_no(key, elem));
+ GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.nor, vbo_index, no_short);
if (has_mask) {
+ uchar color_ub[3];
gpu_color_from_mask_copy(*CCG_elem_mask(key, elem),
- diffuse_color, vd->color);
+ diffuse_color, color_ub);
+ GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.col, vbo_index, color_ub);
}
}
- vd++;
+ vbo_index += 1;
}
}
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] = {
@@ -1313,30 +1334,33 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids,
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);
+ vbo_index = vbo_index_offset + ((j + 1) * key->grid_size + k);
+ short no_short[3];
+ normal_float_to_short_v3(no_short, fno);
+ GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.nor, vbo_index, no_short);
if (has_mask) {
+ uchar color_ub[3];
gpu_color_from_mask_quad_copy(key,
elems[0],
elems[1],
elems[2],
elems[3],
diffuse_color,
- vd->color);
+ color_ub);
+ GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.col, vbo_index, color_ub);
}
}
}
}
- vert_data += key->grid_area;
+ vbo_index_offset += key->grid_area;
}
- GPU_buffer_unlock(buffers->vert_buf, GPU_BINDING_ARRAY);
+ gpu_pbvh_batch_init(buffers);
}
else {
- GPU_buffer_free(buffers->vert_buf);
- buffers->vert_buf = NULL;
+ GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf);
}
}
@@ -1351,57 +1375,54 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids,
/* Build the element array buffer of grid indices using either
* unsigned shorts or unsigned ints. */
-#define FILL_QUAD_BUFFER(type_, tot_quad_, buffer_) \
+#define FILL_QUAD_BUFFER(max_vert_, tot_quad_, buffer_) \
{ \
- type_ *tri_data; \
int offset = 0; \
int i, j, k; \
- buffer_ = GPU_buffer_alloc(sizeof(type_) * (tot_quad_) * 6); \
+ \
+ Gwn_IndexBufBuilder elb; \
+ GWN_indexbuf_init( \
+ &elb, GWN_PRIM_TRIS, tot_quad_ * 2, max_vert_); \
\
/* 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]]; \
+ 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; \
- \
- *(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; \
+ 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; \
+ } \
+ GWN_indexbuf_add_generic_vert(&elb, offset + j * gridsize + k + 1); \
+ GWN_indexbuf_add_generic_vert(&elb, offset + j * gridsize + k); \
+ GWN_indexbuf_add_generic_vert(&elb, offset + (j + 1) * gridsize + k); \
+ \
+ GWN_indexbuf_add_generic_vert(&elb, offset + (j + 1) * gridsize + k + 1); \
+ GWN_indexbuf_add_generic_vert(&elb, offset + j * gridsize + k + 1); \
+ GWN_indexbuf_add_generic_vert(&elb, offset + (j + 1) * gridsize + k); \
+ } \
} \
- GPU_buffer_unlock(buffer_, GPU_BINDING_INDEX); \
- } \
- else { \
- GPU_buffer_free(buffer_); \
- (buffer_) = NULL; \
+ \
+ offset += gridsize * gridsize; \
} \
+ buffer_ = GWN_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 Gwn_IndexBuf *gpu_get_grid_buffer(
+ int gridsize, unsigned *totquad, GridCommonGPUBuffer **grid_common_gpu_buffer,
+ /* remove this arg when gawain 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;
+ // int totgrid = 1;
GridCommonGPUBuffer *gridbuff = *grid_common_gpu_buffer;
@@ -1409,65 +1430,48 @@ static GPUBuffer *gpu_get_grid_buffer(
*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);
+ GWN_indexbuf_discard(gridbuff->mres_buffer);
+ gridbuff->mres_buffer = NULL;
}
/* 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);
- }
+ FILL_QUAD_BUFFER(max_vert, *totquad, gridbuff->mres_buffer);
gridbuff->mres_prev_gridsize = gridsize;
- gridbuff->mres_prev_index_type = *index_type;
gridbuff->mres_prev_totquad = *totquad;
return gridbuff->mres_buffer;
}
-#define FILL_FAST_BUFFER(type_) \
+#define FILL_FAST_BUFFER() \
{ \
- 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; \
+ Gwn_IndexBufBuilder elb; \
+ GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, 6 * totgrid, INT_MAX); \
+ for (int i = 0; i < totgrid; i++) { \
+ GWN_indexbuf_add_generic_vert(&elb, i * gridsize * gridsize + gridsize - 1); \
+ GWN_indexbuf_add_generic_vert(&elb, i * gridsize * gridsize); \
+ GWN_indexbuf_add_generic_vert(&elb, (i + 1) * gridsize * gridsize - gridsize); \
+ GWN_indexbuf_add_generic_vert(&elb, (i + 1) * gridsize * gridsize - 1); \
+ GWN_indexbuf_add_generic_vert(&elb, i * gridsize * gridsize + gridsize - 1); \
+ GWN_indexbuf_add_generic_vert(&elb, (i + 1) * gridsize * gridsize - gridsize); \
} \
+ buffers->index_buf_fast = GWN_indexbuf_build(&elb); \
} (void)0
-GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(
- int *grid_indices, int totgrid, BLI_bitmap **grid_hidden, int gridsize, const CCGKey *key,
+GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(
+ int *grid_indices, int totgrid, BLI_bitmap **grid_hidden, int gridsize, const CCGKey *UNUSED(key),
GridCommonGPUBuffer **grid_common_gpu_buffer)
{
GPU_PBVH_Buffers *buffers;
@@ -1489,39 +1493,26 @@ GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(
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);
- }
+ FILL_FAST_BUFFER();
if (totquad == fully_visible_totquad) {
buffers->index_buf = gpu_get_grid_buffer(
- gridsize, &buffers->index_type, &buffers->tot_quad, grid_common_gpu_buffer);
+ gridsize, &buffers->tot_quad, grid_common_gpu_buffer, totgrid);
buffers->has_hidden = false;
buffers->is_index_buf_global = true;
}
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;
}
+#ifdef USE_BASE_ELEM
/* 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");
@@ -1532,6 +1523,7 @@ GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(
buffers->baseindex[i] = NULL;
}
}
+#endif
return buffers;
}
@@ -1544,26 +1536,36 @@ GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(
* 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])
+static void gpu_bmesh_vert_to_buffer_copy__gwn(
+ BMVert *v,
+ Gwn_VertBuf *vert_buf,
+ const VertexBufferAttrID *vbo_id,
+ int *v_index,
+ const float fno[3],
+ const float *fmask,
+ const int cd_vert_mask_offset,
+ const float diffuse_color[4])
{
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);
+ GWN_vertbuf_attr_set(vert_buf, vbo_id->pos, *v_index, v->co);
+
+ {
+ short no_short[3];
+ normal_float_to_short_v3(no_short, fno ? fno : v->no);
+ GWN_vertbuf_attr_set(vert_buf, vbo_id->nor, *v_index, no_short);
+ }
- gpu_color_from_mask_copy(
- fmask ? *fmask :
- BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset),
- diffuse_color,
- vd->color);
+ {
+ uchar color_ub[3];
+ gpu_color_from_mask_copy(
+ fmask ? *fmask :
+ BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset),
+ diffuse_color,
+ color_ub);
+ GWN_vertbuf_attr_set(vert_buf, vbo_id->col, *v_index, color_ub);
+ }
/* Assign index for use in the triangle index buffer */
/* note: caller must set: bm->elem_index_dirty |= BM_VERT; */
@@ -1612,15 +1614,14 @@ static int gpu_bmesh_face_visible_count(GSet *bm_faces)
/* Creates a vertex buffer (coordinate, normal, color) and, if smooth
* shading, an element index buffer. */
-void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
- BMesh *bm,
- GSet *bm_faces,
- GSet *bm_unique_verts,
- GSet *bm_other_verts,
- bool show_diffuse_color)
+void GPU_pbvh_bmesh_buffers_update(
+ GPU_PBVH_Buffers *buffers,
+ BMesh *bm,
+ GSet *bm_faces,
+ GSet *bm_unique_verts,
+ GSet *bm_other_verts,
+ bool show_diffuse_color)
{
- VertexBufferFormat *vert_data;
- void *tri_data;
int tottri, totvert, maxvert = 0;
float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 1.0f};
@@ -1659,13 +1660,17 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
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);
+ GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf);
+ /* match 'VertexBufferFormat' */
+ Gwn_VertFormat format = {0};
+ VertexBufferAttrID vbo_id;
+ gpu_pbvh_vert_format_init__gwn(&format, &vbo_id);
+
+ buffers->vert_buf = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(buffers->vert_buf, totvert);
/* Fill vertex buffer */
- vert_data = GPU_buffer_lock(buffers->vert_buf, GPU_BINDING_ARRAY);
- if (vert_data) {
+ if (buffers->vert_buf->data) {
int v_index = 0;
if (buffers->smooth) {
@@ -1676,15 +1681,17 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
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);
+ gpu_bmesh_vert_to_buffer_copy__gwn(
+ BLI_gsetIterator_getKey(&gs_iter),
+ buffers->vert_buf, &vbo_id, &v_index, NULL, NULL,
+ cd_vert_mask_offset, diffuse_color);
}
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);
+ gpu_bmesh_vert_to_buffer_copy__gwn(
+ BLI_gsetIterator_getKey(&gs_iter),
+ buffers->vert_buf, &vbo_id, &v_index, NULL, NULL,
+ cd_vert_mask_offset, diffuse_color);
}
maxvert = v_index;
@@ -1714,9 +1721,10 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
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);
+ gpu_bmesh_vert_to_buffer_copy__gwn(
+ v[i], buffers->vert_buf, &vbo_id,
+ &v_index, f->no, &fmask,
+ cd_vert_mask_offset, diffuse_color);
}
}
}
@@ -1724,32 +1732,30 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
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 {
+ GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf);
/* 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;
+ Gwn_IndexBufBuilder elb;
+ GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, tottri, maxvert);
/* Initialize triangle index buffer */
- if (buffers->index_buf && !buffers->is_index_buf_global)
- GPU_buffer_free(buffers->index_buf);
+ if (buffers->triangles && !buffers->is_index_buf_global) {
+ GWN_BATCH_DISCARD_SAFE(buffers->triangles);
+ }
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) {
@@ -1761,49 +1767,28 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
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;
- }
+ GWN_indexbuf_add_generic_vert(&elb, BM_elem_index_get(l_iter->v));
} while ((l_iter = l_iter->next) != l_first);
}
}
- 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);
- }
- buffers->index_buf = NULL;
- buffers->is_index_buf_global = false;
+
+ buffers->index_buf = GWN_indexbuf_build(&elb);
}
}
else if (buffers->index_buf) {
if (!buffers->is_index_buf_global) {
- GPU_buffer_free(buffers->index_buf);
+ GWN_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
}
buffers->index_buf = NULL;
buffers->is_index_buf_global = false;
}
+
+ gpu_pbvh_batch_init(buffers);
}
-GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(bool smooth_shading)
+GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading)
{
GPU_PBVH_Buffers *buffers;
@@ -1816,146 +1801,45 @@ GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(bool smooth_shading)
return buffers;
}
-void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
- bool wireframe, bool fast)
+void GPU_pbvh_buffers_draw(
+ GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
+ bool wireframe, 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;
- }
- }
+ UNUSED_VARS(wireframe, fast, setMaterial);
+ bool do_fast = fast && buffers->triangles_fast;
+ Gwn_Batch *triangles = do_fast ? buffers->triangles_fast : buffers->triangles;
- 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;
- }
+ if (triangles) {
- GPU_buffer_bind(buffers->vert_buf, GPU_BINDING_ARRAY);
+ /* Simple Shader: use when drawing without the draw-manager (old 2.7x viewport) */
+ if (triangles->interface == NULL) {
+ GPUBuiltinShader shader_id =
+ buffers->smooth ? GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR : GPU_SHADER_SIMPLE_LIGHTING_FLAT_COLOR;
+ GPUShader *shader = GPU_shader_get_builtin_shader(shader_id);
- 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);
- }
+ GWN_batch_program_set(
+ triangles,
+ GPU_shader_get_program(shader), GPU_shader_get_interface(shader));
- 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);
- }
+ static float light[3] = {-0.3f, 0.5f, 1.0f};
+ static float alpha = 1.0f;
+ static float world_light = 1.0f;
- if (buffers->tot_quad) {
- const char *offset = base;
- const bool drawall = !(buffers->has_hidden || do_fast);
+ GPU_shader_uniform_vector(shader, GPU_shader_get_uniform(shader, "light"), 3, 1, light);
+ GPU_shader_uniform_vector(shader, GPU_shader_get_uniform(shader, "alpha"), 1, 1, &alpha);
+ GPU_shader_uniform_vector(shader, GPU_shader_get_uniform(shader, "global"), 1, 1, &world_light);
- 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);
-
- 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);
-
- glDisableClientState(GL_VERTEX_ARRAY);
- if (!wireframe) {
- glDisableClientState(GL_NORMAL_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
- }
-
- if (bound_options_new & ~bound_options_old) {
- GPU_basic_shader_bind(bound_options_old);
}
+ GWN_batch_draw(triangles);
}
}
+Gwn_Batch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast)
+{
+ return (fast && buffers->triangles_fast) ?
+ buffers->triangles_fast : buffers->triangles;
+}
+
bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, GSet *bm_faces, bool show_diffuse_color)
{
float diffuse_color[4];
@@ -1999,32 +1883,36 @@ bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, GSet *bm_faces,
return !equals_v3v3(diffuse_color, buffers->diffuse_color);
}
-void GPU_free_pbvh_buffers(GPU_PBVH_Buffers *buffers)
+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);
+ GWN_BATCH_DISCARD_SAFE(buffers->triangles);
+ GWN_BATCH_DISCARD_SAFE(buffers->triangles_fast);
+ if (!buffers->is_index_buf_global) {
+ GWN_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
+ }
+ GWN_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast);
+ GWN_vertbuf_discard(buffers->vert_buf);
+
+#ifdef USE_BASE_ELEM
if (buffers->baseelemarray)
MEM_freeN(buffers->baseelemarray);
if (buffers->baseindex)
MEM_freeN(buffers->baseindex);
+#endif
MEM_freeN(buffers);
}
}
-void GPU_free_pbvh_buffer_multires(GridCommonGPUBuffer **grid_common_gpu_buffer)
+void GPU_pbvh_multires_buffers_free(GridCommonGPUBuffer **grid_common_gpu_buffer)
{
GridCommonGPUBuffer *gridbuff = *grid_common_gpu_buffer;
if (gridbuff) {
if (gridbuff->mres_buffer) {
BLI_mutex_lock(&buffer_mutex);
- gpu_buffer_free_intern(gridbuff->mres_buffer);
+ GWN_INDEXBUF_DISCARD_SAFE(gridbuff->mres_buffer);
BLI_mutex_unlock(&buffer_mutex);
}
MEM_freeN(gridbuff);
@@ -2033,59 +1921,57 @@ void GPU_free_pbvh_buffer_multires(GridCommonGPUBuffer **grid_common_gpu_buffer)
}
/* debug function, draws the pbvh BB */
-void GPU_draw_pbvh_BB(float min[3], float max[3], bool leaf)
+void GPU_pbvh_BB_draw(float min[3], float max[3], bool leaf, unsigned int pos)
{
- 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]}
- },
+ if (leaf)
+ immUniformColor4f(0.0, 1.0, 0.0, 0.5);
+ else
+ immUniformColor4f(1.0, 0.0, 0.0, 0.5);
- {
- {min[0], min[1], min[2]},
- {min[0], max[1], min[2]},
- {min[0], max[1], max[2]},
- {min[0], min[1], max[2]}
- },
+ /* TODO(merwin): revisit this after we have mutable VertexBuffers
+ * could keep a static batch & index buffer, change the VBO contents per draw
+ */
- {
- {max[0], max[1], min[2]},
- {max[0], min[1], min[2]},
- {max[0], min[1], max[2]},
- {max[0], max[1], max[2]}
- },
+ immBegin(GWN_PRIM_LINES, 24);
- {
- {max[0], max[1], min[2]},
- {min[0], max[1], min[2]},
- {min[0], max[1], max[2]},
- {max[0], max[1], max[2]}
- },
- };
+ /* top */
+ immVertex3f(pos, min[0], min[1], max[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, min[0], max[1], max[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], max[1], max[2]);
+ immVertex3f(pos, max[0], min[1], max[2]);
-void GPU_init_draw_pbvh_BB(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);
-}
+ immVertex3f(pos, max[0], min[1], max[2]);
+ immVertex3f(pos, min[0], min[1], max[2]);
-void GPU_end_draw_pbvh_BB(void)
-{
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- glPopAttrib();
+ /* bottom */
+ immVertex3f(pos, min[0], min[1], min[2]);
+ immVertex3f(pos, min[0], max[1], min[2]);
+
+ immVertex3f(pos, min[0], max[1], min[2]);
+ immVertex3f(pos, max[0], max[1], min[2]);
+
+ immVertex3f(pos, max[0], max[1], min[2]);
+ immVertex3f(pos, max[0], min[1], min[2]);
+
+ immVertex3f(pos, max[0], min[1], min[2]);
+ immVertex3f(pos, min[0], min[1], min[2]);
+
+ /* sides */
+ immVertex3f(pos, min[0], min[1], min[2]);
+ immVertex3f(pos, min[0], min[1], max[2]);
+
+ immVertex3f(pos, min[0], max[1], min[2]);
+ immVertex3f(pos, min[0], max[1], max[2]);
+
+ immVertex3f(pos, max[0], max[1], min[2]);
+ immVertex3f(pos, max[0], max[1], max[2]);
+
+ immVertex3f(pos, max[0], min[1], min[2]);
+ immVertex3f(pos, max[0], min[1], max[2]);
+
+ immEnd();
}
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index c40bc8eaf27..9fa78bfe5b9 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -36,6 +36,7 @@
#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_utildefines.h"
@@ -47,6 +48,7 @@
#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 */
@@ -86,9 +88,10 @@ typedef struct GPUFunction {
} GPUFunction;
/* Indices match the GPUType enum */
-static const char *GPU_DATATYPE_STR[17] = {
+static const char *GPU_DATATYPE_STR[18] = {
"", "float", "vec2", "vec3", "vec4",
NULL, NULL, NULL, NULL, "mat3", NULL, NULL, NULL, NULL, NULL, NULL, "mat4",
+ "Closure"
};
/* GLSL code parsing for finding function definitions.
@@ -172,7 +175,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 <= 17; i++) {
if (GPU_DATATYPE_STR[i] && gpu_str_prefix(code, GPU_DATATYPE_STR[i])) {
type = i;
break;
@@ -350,6 +353,8 @@ static void codegen_convert_datatype(DynStr *ds, int from, int to, const char *t
BLI_dynstr_appendf(ds, "vec4(%s.r, %s.r, %s.r, %s.g)", name, name, name, name);
else if (from == GPU_FLOAT)
BLI_dynstr_appendf(ds, "vec4(%s, %s, %s, 1.0)", name, name, name);
+ else /* can happen with closure */
+ BLI_dynstr_append(ds, name);
}
}
@@ -357,10 +362,15 @@ static void codegen_print_datatype(DynStr *ds, const GPUType type, float *data)
{
int i;
+ if (type == GPU_CLOSURE) {
+ BLI_dynstr_append(ds, "CLOSURE_DEFAULT");
+ return;
+ }
+
BLI_dynstr_appendf(ds, "%s(", GPU_DATATYPE_STR[type]);
for (i = 0; i < type; i++) {
- BLI_dynstr_appendf(ds, "%f", data[i]);
+ BLI_dynstr_appendf(ds, "%.12f", data[i]);
if (i == type - 1)
BLI_dynstr_append(ds, ")");
else
@@ -410,6 +420,8 @@ const char *GPU_builtin_name(GPUBuiltin builtin)
return "unfparticlevel";
else if (builtin == GPU_PARTICLE_ANG_VELOCITY)
return "unfparticleangvel";
+ else if (builtin == GPU_OBJECT_INFO)
+ return "unfobjectinfo";
else
return "";
}
@@ -498,12 +510,16 @@ static void codegen_set_unique_ids(ListBase *nodes)
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) {
@@ -535,15 +551,28 @@ static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes)
}
}
else if (input->source == GPU_SOURCE_VEC_UNIFORM) {
- if (input->dynamicvec) {
+ if (input->dynamictype == GPU_DYNAMIC_UBO) {
+ if (!input->link) {
+ /* We handle the UBOuniforms separately. */
+ BLI_addtail(&ubo_inputs, BLI_genericNodeN(input));
+ }
+ }
+ else 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);
+ if (input->type != GPU_CLOSURE) {
+ /* 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);
+ }
+ else {
+ /* const keyword does not work with struct */
+ BLI_dynstr_appendf(ds, "%s cons%d = ",
+ GPU_DATATYPE_STR[input->type], input->id);
+ }
codegen_print_datatype(ds, input->type, input->vec);
BLI_dynstr_append(ds, ";\n");
}
@@ -567,6 +596,22 @@ static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes)
}
}
+ /* Handle the UBO block separately. */
+ if ((material != NULL) && !BLI_listbase_is_empty(&ubo_inputs)) {
+ GPU_material_create_uniform_buffer(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;
@@ -620,7 +665,19 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final
"tmp", input->link->output->id);
}
else if (input->source == GPU_SOURCE_BUILTIN) {
- if (input->builtin == GPU_VIEW_NORMAL)
+ 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_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));
@@ -653,12 +710,11 @@ 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, bool use_new_shading)
{
DynStr *ds = BLI_dynstr_new();
char *code;
@@ -675,17 +731,47 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output)
#endif
codegen_set_unique_ids(nodes);
- builtins = codegen_print_uniforms_functions(ds, nodes);
+ builtins = codegen_process_uniforms_functions(material, ds, nodes);
#if 0
if (G.debug & G_DEBUG)
BLI_dynstr_appendf(ds, "/* %s */\n", name);
#endif
- BLI_dynstr_append(ds, "void main()\n{\n");
+ BLI_dynstr_append(ds, "Closure nodetree_exec(void)\n{\n");
- if (builtins & GPU_VIEW_NORMAL)
- BLI_dynstr_append(ds, "\tvec3 facingnormal = gl_FrontFacing? varnormal: -varnormal;\n");
+ if (use_new_shading) {
+ if (builtins & GPU_VIEW_MATRIX)
+ BLI_dynstr_append(ds, "\tmat4 viewmat = ViewMatrix;\n");
+ if (builtins & GPU_CAMERA_TEXCO_FACTORS)
+ BLI_dynstr_append(ds, "\tvec4 camtexfac = CameraTexCoFactors;\n");
+ if (builtins & GPU_OBJECT_MATRIX)
+ BLI_dynstr_append(ds, "\tmat4 objmat = ModelMatrix;\n");
+ if (builtins & GPU_INVERSE_OBJECT_MATRIX)
+ BLI_dynstr_append(ds, "\tmat4 objinv = ModelMatrixInverse;\n");
+ if (builtins & GPU_INVERSE_VIEW_MATRIX)
+ BLI_dynstr_append(ds, "\tmat4 viewinv = ViewMatrixInverse;\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, "\tvec3 viewposition = viewPosition;\n");
+ }
+ else {
+ if (builtins & GPU_VIEW_MATRIX)
+ BLI_dynstr_append(ds, "\tmat4 viewmat = unfviewmat;\n");
+ if (builtins & GPU_CAMERA_TEXCO_FACTORS)
+ BLI_dynstr_append(ds, "\tvec4 camtexfac = unfcameratexfactors;\n");
+ if (builtins & GPU_OBJECT_MATRIX)
+ BLI_dynstr_append(ds, "\tmat4 objmat = unfobmat;\n");
+ if (builtins & GPU_INVERSE_OBJECT_MATRIX)
+ BLI_dynstr_append(ds, "\tmat4 objinv = unfinvobmat;\n");
+ if (builtins & GPU_INVERSE_VIEW_MATRIX)
+ BLI_dynstr_append(ds, "\tmat4 viewinv = unfinvviewmat;\n");
+ if (builtins & GPU_VIEW_NORMAL)
+ BLI_dynstr_append(ds, "\tvec3 facingnormal = gl_FrontFacing? varnormal: -varnormal;\n");
+ if (builtins & GPU_VIEW_POSITION)
+ BLI_dynstr_append(ds, "\tvec3 viewposition = varposition;\n");
+ }
/* Calculate tangent space. */
#ifdef WITH_OPENSUBDIV
@@ -720,6 +806,17 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *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);
@@ -731,6 +828,95 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output)
return code;
}
+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 && "Gwn_VertAttr Prefix type not found : This should not happen!"); return "";
+ }
+}
+
+static char *code_generate_vertex_new(ListBase *nodes, const char *vert_code, bool use_geom)
+{
+ DynStr *ds = BLI_dynstr_new();
+ GPUNode *node;
+ GPUInput *input;
+ char *code;
+
+ 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) {
+ /* 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 bellow */
+ BLI_dynstr_appendf(ds, "uniform vec3 OrcoTexCoFactors[2];\n");
+ }
+ else if (input->attribname[0] == '\0') {
+ BLI_dynstr_appendf(ds, "in %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));
+ }
+ else {
+ unsigned int hash = BLI_ghashutil_strhash_p(input->attribname);
+ BLI_dynstr_appendf(ds, "in %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);
+ }
+ BLI_dynstr_appendf(ds, "out %s var%d%s;\n",
+ GPU_DATATYPE_STR[input->type], input->attribid, use_geom ? "g" : "");
+ }
+ }
+ }
+
+ BLI_dynstr_append(ds, "\n");
+
+ BLI_dynstr_append(ds, "#define ATTRIB\n");
+ BLI_dynstr_append(ds, "uniform mat3 NormalMatrix;\n");
+ BLI_dynstr_append(ds, "void pass_attrib(in vec3 position) {\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->attribtype == CD_ORCO) {
+ BLI_dynstr_appendf(ds, "\tvar%d%s = OrcoTexCoFactors[0] + position * OrcoTexCoFactors[1];\n",
+ input->attribid, use_geom ? "g" : "");
+ }
+ else {
+ BLI_dynstr_appendf(ds, "\tvar%d%s = att%d;\n",
+ input->attribid, use_geom ? "g" : "", input->attribid);
+ }
+ }
+ }
+ }
+
+ BLI_dynstr_append(ds, "}\n");
+
+ BLI_dynstr_append(ds, vert_code);
+
+ code = BLI_dynstr_get_cstring(ds);
+
+ BLI_dynstr_free(ds);
+
+#if 0
+ if (G.debug & G_DEBUG) printf("%s\n", code);
+#endif
+
+ return code;
+}
+
static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
{
DynStr *ds = BLI_dynstr_new();
@@ -788,7 +974,7 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n");
#endif
BLI_dynstr_appendf(
- ds, "\tvar%d.xyz = normalize(gl_NormalMatrix * att%d.xyz);\n",
+ ds, "\tvar%d.xyz = normalize(NormalMatrix * att%d.xyz);\n",
input->attribid, input->attribid);
BLI_dynstr_appendf(
ds, "\tvar%d.w = att%d.w;\n",
@@ -839,6 +1025,51 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
return code;
}
+static char *code_generate_geometry_new(ListBase *nodes, const char *geom_code)
+{
+ DynStr *ds = BLI_dynstr_new();
+ GPUNode *node;
+ GPUInput *input;
+ char *code;
+
+ /* Create prototype because attributes cannot be declared before layout. */
+ BLI_dynstr_appendf(ds, "void pass_attrib(in int vert);\n");
+ BLI_dynstr_append(ds, "#define ATTRIB\n");
+
+ BLI_dynstr_append(ds, geom_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) {
+ 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);
+ }
+ }
+ }
+
+ /* Generate varying assignments. */
+ BLI_dynstr_appendf(ds, "void pass_attrib(in int 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;
+}
+
static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv)
{
#ifdef WITH_OPENSUBDIV
@@ -877,7 +1108,7 @@ static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv)
if (input->attribtype == CD_MTFACE) {
BLI_dynstr_appendf(
ds,
- "\tINTERP_FACE_VARYING_2(var%d, "
+ "\tINTERP_FACE_VARYING_ATT_2(var%d, "
"int(texelFetch(FVarDataOffsetBuffer, fvar%d_offset).r), st);\n",
input->attribid,
input->attribid);
@@ -926,6 +1157,67 @@ GPUShader *GPU_pass_shader(GPUPass *pass)
return pass->shader;
}
+static void gpu_nodes_extract_dynamic_inputs_new(GPUPass *pass, ListBase *nodes)
+{
+ GPUShader *shader = pass->shader;
+ GPUNode *node;
+ GPUInput *next, *input;
+ ListBase *inputs = &pass->inputs;
+ int extract, z;
+
+ memset(inputs, 0, sizeof(*inputs));
+
+ if (!shader)
+ return;
+
+ GPU_shader_bind(shader);
+
+ for (node = nodes->first; node; node = node->next) {
+ 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) {
+ continue;
+ }
+
+ if (input->source == GPU_SOURCE_BUILTIN ||
+ input->source == GPU_SOURCE_OPENGL_BUILTIN)
+ {
+ continue;
+ }
+
+ if (input->ima || input->tex || input->prv)
+ BLI_snprintf(input->shadername, sizeof(input->shadername), "samp%d", input->texid);
+ 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);
+
+ /* extract nodes */
+ if (extract) {
+ BLI_remlink(&node->inputs, input);
+ BLI_addtail(inputs, input);
+ }
+ }
+ }
+
+ GPU_shader_unbind();
+}
+
static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes)
{
GPUShader *shader = pass->shader;
@@ -1133,7 +1425,7 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType
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);
@@ -1192,7 +1484,7 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType
#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->tex = GPU_texture_create_2D(link->texturesize, 1, link->ptr1, NULL);
input->textarget = GL_TEXTURE_2D;
MEM_freeN(link->ptr1);
@@ -1250,15 +1542,84 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType
BLI_addtail(&node->inputs, input);
}
-static void gpu_node_input_socket(GPUNode *node, GPUNodeStack *sock)
+
+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;
+ }
+}
+
+/**
+ * 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)
{
- GPUNodeLink *link;
+ bNodeSocket *socket;
+ if (in_out == SOCK_IN) {
+ socket = BLI_findlink(&node->original->inputs, index);
+ }
+ else {
+ socket = BLI_findlink(&node->original->outputs, index);
+ }
+
+ 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_buffer(&socket_data->value, GPU_FLOAT);
+ break;
+ }
+ case SOCK_VECTOR:
+ {
+ bNodeSocketValueRGBA *socket_data = socket->default_value;
+ link = GPU_uniform_buffer(socket_data->value, GPU_VEC3);
+ break;
+ }
+ case SOCK_RGBA:
+ {
+ bNodeSocketValueRGBA *socket_data = socket->default_value;
+ link = GPU_uniform_buffer(socket_data->value, GPU_VEC4);
+ 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(GPUMaterial *material, bNode *bnode, GPUNode *node, GPUNodeStack *sock, const int index)
+{
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();
+ GPUNodeLink *link = GPU_node_link_create();
link->ptr1 = sock->vec;
gpu_node_input_link(node, link, sock->type);
}
@@ -1385,7 +1746,14 @@ GPUNodeLink *GPU_attribute(const CustomDataType type, const char *name)
{
GPUNodeLink *link = GPU_node_link_create();
- link->attribtype = type;
+ /* 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;
+ }
+
link->attribname = name;
return link;
@@ -1414,6 +1782,21 @@ GPUNodeLink *GPU_dynamic_uniform(float *num, GPUDynamicType dynamictype, void *d
return link;
}
+/**
+ * Add uniform to UBO struct of GPUMaterial.
+ */
+GPUNodeLink *GPU_uniform_buffer(float *num, GPUType gputype)
+{
+ GPUNodeLink *link = GPU_node_link_create();
+ link->ptr1 = num;
+ link->ptr2 = NULL;
+ link->dynamic = true;
+ link->dynamictype = GPU_DYNAMIC_UBO;
+ link->type = gputype;
+
+ return link;
+}
+
GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser, bool is_data)
{
GPUNodeLink *link = GPU_node_link_create();
@@ -1524,7 +1907,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;
@@ -1544,11 +1927,11 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod
if (in) {
for (i = 0; in[i].type != GPU_NONE; i++) {
- gpu_node_input_socket(node, &in[i]);
+ 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);
@@ -1570,7 +1953,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]);
}
@@ -1580,8 +1963,8 @@ 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;
}
@@ -1606,6 +1989,11 @@ int GPU_link_changed(GPUNodeLink *link)
return 0;
}
+GPUNodeLink *GPU_uniformbuffer_link_out(GPUMaterial *mat, bNode *node, GPUNodeStack *stack, const int index)
+{
+ return gpu_uniformbuffer_link(mat, node, stack, index, SOCK_OUT);
+}
+
/* Pass create/free */
static void gpu_nodes_tag(GPUNodeLink *link)
@@ -1645,6 +2033,78 @@ static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink)
}
}
+GPUPass *GPU_generate_pass_new(
+ struct GPUMaterial *material,
+ ListBase *nodes, struct GPUNodeLink *frag_outlink,
+ GPUVertexAttribs *attribs,
+ const char *vert_code, const char *geom_code,
+ const char *frag_lib, const char *defines)
+{
+ GPUShader *shader;
+ GPUPass *pass;
+ char *vertexgen, *fragmentgen, *tmp;
+ char *vertexcode, *geometrycode, *fragmentcode;
+
+ /* prune unused nodes */
+ gpu_nodes_prune(nodes, frag_outlink);
+
+ gpu_nodes_get_vertex_attributes(nodes, attribs);
+
+ /* generate code and compile with opengl */
+ fragmentgen = code_generate_fragment(material, nodes, frag_outlink->output, true);
+ vertexgen = code_generate_vertex_new(nodes, vert_code, (geom_code != NULL));
+
+ tmp = BLI_strdupcat(frag_lib, glsl_material_library);
+ fragmentcode = BLI_strdupcat(tmp, fragmentgen);
+ vertexcode = BLI_strdup(vertexgen);
+
+ if (geom_code) {
+ geometrycode = code_generate_geometry_new(nodes, geom_code);
+ }
+ else {
+ geometrycode = NULL;
+ }
+
+ shader = GPU_shader_create(vertexcode,
+ fragmentcode,
+ geometrycode,
+ NULL,
+ defines);
+
+ MEM_freeN(tmp);
+
+ /* failed? */
+ if (!shader) {
+ if (fragmentcode)
+ MEM_freeN(fragmentcode);
+ if (vertexcode)
+ MEM_freeN(vertexcode);
+ if (geometrycode)
+ MEM_freeN(geometrycode);
+ MEM_freeN(fragmentgen);
+ MEM_freeN(vertexgen);
+ gpu_nodes_free(nodes);
+ return NULL;
+ }
+
+ /* create pass */
+ pass = MEM_callocN(sizeof(GPUPass), "GPUPass");
+ 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_new(pass, nodes);
+ gpu_nodes_free(nodes);
+
+ MEM_freeN(fragmentgen);
+ MEM_freeN(vertexgen);
+
+ return pass;
+}
+
GPUPass *GPU_generate_pass(
ListBase *nodes, GPUNodeLink *outlink,
GPUVertexAttribs *attribs, int *builtins,
@@ -1670,7 +2130,7 @@ GPUPass *GPU_generate_pass(
gpu_nodes_get_builtin_flag(nodes, builtins);
/* generate code and compile with opengl */
- fragmentcode = code_generate_fragment(nodes, outlink->output);
+ fragmentcode = code_generate_fragment(NULL, nodes, outlink->output, false);
vertexcode = code_generate_vertex(nodes, type);
geometrycode = code_generate_geometry(nodes, use_opensubdiv);
@@ -1686,9 +2146,6 @@ GPUPass *GPU_generate_pass(
geometrycode,
glsl_material_library,
NULL,
- 0,
- 0,
- 0,
flags);
/* failed? */
@@ -1706,7 +2163,6 @@ GPUPass *GPU_generate_pass(
/* create pass */
pass = MEM_callocN(sizeof(GPUPass), "GPUPass");
- pass->output = outlink->output;
pass->shader = shader;
pass->fragmentcode = fragmentcode;
pass->geometrycode = geometrycode;
diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h
index 7af17f9122d..28eb55968bb 100644
--- a/source/blender/gpu/intern/gpu_codegen.h
+++ b/source/blender/gpu/intern/gpu_codegen.h
@@ -156,10 +156,7 @@ typedef struct GPUInput {
} GPUInput;
struct GPUPass {
- struct GPUPass *next, *prev;
-
ListBase inputs;
- struct GPUOutput *output;
struct GPUShader *shader;
char *fragmentcode;
char *geometrycode;
@@ -170,11 +167,18 @@ struct GPUPass {
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_new(
+ struct GPUMaterial *material,
+ ListBase *nodes, struct GPUNodeLink *frag_outlink,
+ struct GPUVertexAttribs *attribs,
+ const char *vert_code, const char *geom_code,
+ const char *frag_lib, const char *defines);
+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);
struct GPUShader *GPU_pass_shader(GPUPass *pass);
diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c
index 964c2b5051e..afd28aece12 100644
--- a/source/blender/gpu/intern/gpu_compositing.c
+++ b/source/blender/gpu/intern/gpu_compositing.c
@@ -42,11 +42,13 @@
#include "DNA_gpu_types.h"
#include "GPU_compositing.h"
+#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_framebuffer.h"
#include "GPU_glew.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
+#include "GPU_batch.h"
#include "MEM_guardedalloc.h"
@@ -193,7 +195,8 @@ struct GPUFX {
/* we have a stencil, restore the previous state */
bool restore_stencil;
- unsigned int vbuffer;
+ Gwn_Batch *quad_batch;
+ Gwn_Batch *point_batch;
};
#if 0
@@ -225,7 +228,13 @@ static GPUTexture * create_concentric_sample_texture(int side)
}
}
- tex = GPU_texture_create_1D_procedural(side * side, texels, NULL);
+ tex = GPU_texture_create_1D_custom(side * side, 2, GPU_RG16F, (float *)texels, NULL);
+
+ /* Set parameters */
+ GPU_texture_bind(tex, 0);
+ GPU_texture_filter_mode(tex, false);
+ GPU_texture_unbind(tex);
+
MEM_freeN(texels);
return tex;
}
@@ -247,7 +256,13 @@ static GPUTexture *create_spiral_sample_texture(int numsaples)
texels[i][1] = r * sinf(phi);
}
- tex = GPU_texture_create_1D_procedural(numsaples, (float *)texels, NULL);
+ tex = GPU_texture_create_1D_custom(numsaples, 2, GPU_RG16F, (float *)texels, NULL);
+
+ /* Set parameters */
+ GPU_texture_bind(tex, 0);
+ GPU_texture_filter_mode(tex, false);
+ GPU_texture_unbind(tex);
+
MEM_freeN(texels);
return tex;
}
@@ -257,12 +272,32 @@ 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);
+ /* Quad buffer */
+ static Gwn_VertFormat format = {0};
+ static unsigned int pos, uvs;
+ if (format.attrib_ct == 0) {
+ pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ uvs = GWN_vertformat_attr_add(&format, "uvs", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ }
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 4);
+ for (int i = 0; i < 4; ++i) {
+ GWN_vertbuf_attr_set(vbo, pos, i, fullscreencos[i]);
+ GWN_vertbuf_attr_set(vbo, uvs, i, fullscreenuvs[i]);
+ }
+ fx->quad_batch = GWN_batch_create(GWN_PRIM_TRI_STRIP, vbo, NULL);
+
+ /* Point Buffer */
+ static Gwn_VertFormat format_point = {0};
+ static unsigned int dummy_attrib;
+ if (format_point.attrib_ct == 0) {
+ dummy_attrib = GWN_vertformat_attr_add(&format_point, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ }
+ float dummy[2] = {0.0f, 0.0f};
+ Gwn_VertBuf *vbo_point = GWN_vertbuf_create_with_format(&format_point);
+ GWN_vertbuf_data_alloc(vbo_point, 1);
+ GWN_vertbuf_attr_set(vbo_point, dummy_attrib, 0, &dummy);
+ fx->point_batch = GWN_batch_create(GWN_PRIM_POINTS, vbo_point, NULL);
return fx;
}
@@ -352,12 +387,14 @@ static void cleanup_fx_gl_data(GPUFX *fx, bool do_fbo)
void GPU_fx_compositor_destroy(GPUFX *fx)
{
cleanup_fx_gl_data(fx, true);
- glDeleteBuffers(1, &fx->vbuffer);
+ GWN_batch_discard_all(fx->quad_batch);
+ GWN_batch_discard_all(fx->point_batch);
MEM_freeN(fx);
}
static GPUTexture * create_jitter_texture(void)
{
+ GPUTexture *tex;
float jitter[64 * 64][2];
int i;
@@ -367,7 +404,15 @@ static GPUTexture * create_jitter_texture(void)
normalize_v2(jitter[i]);
}
- return GPU_texture_create_2D_procedural(64, 64, &jitter[0][0], true, NULL);
+ tex = GPU_texture_create_2D_custom(64, 64, 2, GPU_RG16F, &jitter[0][0], NULL);
+
+ /* Set parameters */
+ GPU_texture_bind(tex, 0);
+ GPU_texture_filter_mode(tex, false);
+ GPU_texture_wrap_mode(tex, true);
+ GPU_texture_unbind(tex);
+
+ return tex;
}
@@ -382,9 +427,6 @@ bool GPU_fx_compositor_initialize_passes(
fx->effects = 0;
- if (!GLEW_EXT_framebuffer_object)
- return false;
-
if (!fx_settings) {
cleanup_fx_gl_data(fx, true);
return false;
@@ -436,7 +478,7 @@ bool GPU_fx_compositor_initialize_passes(
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))) {
+ if (!(fx->color_buffer = GPU_texture_create_2D(w, h, NULL, err_out))) {
printf(".256%s\n", err_out);
cleanup_fx_gl_data(fx, true);
return false;
@@ -472,8 +514,7 @@ bool GPU_fx_compositor_initialize_passes(
/* 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();
+ bool dof_high_quality = (fx_settings->dof->high_quality != 0);
/* cleanup buffers if quality setting has changed (no need to keep more buffers around than necessary ) */
if (dof_high_quality != fx->dof_high_quality)
@@ -488,38 +529,42 @@ bool GPU_fx_compositor_initialize_passes(
{
if (!(fx->dof_half_downsampled_near = GPU_texture_create_2D(
- fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, 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)))
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, 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)))
+
+ if (!(fx->dof_nearfar_coc = GPU_texture_create_2D_custom(
+ fx->dof_downsampled_w, fx->dof_downsampled_h, 2, GPU_RG16F, NULL, err_out)))
{
printf("%.256s\n", err_out);
cleanup_fx_gl_data(fx, true);
return false;
}
+ GPU_texture_bind(fx->dof_nearfar_coc, 0);
+ GPU_texture_filter_mode(fx->dof_nearfar_coc, false);
+ GPU_texture_wrap_mode(fx->dof_nearfar_coc, false);
+ GPU_texture_unbind(fx->dof_nearfar_coc);
-
- if (!(fx->dof_near_blur = GPU_texture_create_2D(
- fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_HALF_FLOAT, err_out)))
+ if (!(fx->dof_near_blur = GPU_texture_create_2D_custom(
+ fx->dof_downsampled_w, fx->dof_downsampled_h, 4, GPU_RGBA16F, NULL, 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)))
+ if (!(fx->dof_far_blur = GPU_texture_create_2D_custom(
+ fx->dof_downsampled_w, fx->dof_downsampled_h, 4, GPU_RGBA16F, NULL, err_out)))
{
printf("%.256s\n", err_out);
cleanup_fx_gl_data(fx, true);
@@ -534,21 +579,21 @@ bool GPU_fx_compositor_initialize_passes(
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)))
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, 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)))
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, 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)))
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out)))
{
printf("%.256s\n", err_out);
cleanup_fx_gl_data(fx, true);
@@ -567,7 +612,7 @@ bool GPU_fx_compositor_initialize_passes(
/* 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))) {
+ if (!(fx->color_buffer_sec = GPU_texture_create_2D(w, h, NULL, err_out))) {
printf(".256%s\n", err_out);
cleanup_fx_gl_data(fx, true);
return false;
@@ -585,11 +630,8 @@ bool GPU_fx_compositor_initialize_passes(
/* 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);
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, 0);
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->color_buffer, 0, 0);
if (!GPU_framebuffer_check_valid(fx->gbuffer, err_out))
printf("%.256s\n", err_out);
@@ -600,7 +642,7 @@ bool GPU_fx_compositor_initialize_passes(
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);
+ gpuPushAttrib(GPU_SCISSOR_BIT);
glEnable(GL_SCISSOR_TEST);
glScissor(scissor_rect->xmin - rect->xmin, scissor_rect->ymin - rect->ymin,
w_sc, h_sc);
@@ -634,7 +676,7 @@ static void gpu_fx_bind_render_target(int *passes_left, GPUFX *fx, struct GPUOff
}
else {
/* bind the ping buffer to the color buffer */
- GPU_framebuffer_texture_attach(fx->gbuffer, target, 0, NULL);
+ GPU_framebuffer_texture_attach(fx->gbuffer, target, 0, 0);
}
}
@@ -663,8 +705,7 @@ void GPU_fx_compositor_setup_XRay_pass(GPUFX *fx, bool do_xray)
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);
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer_xray, 0, 0);
}
@@ -674,39 +715,35 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx)
GPU_framebuffer_texture_detach(fx->depth_buffer_xray);
/* attach regular framebuffer */
- GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, NULL);
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, 0);
/* full screen quad where we will always write to depth buffer */
- glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_SCISSOR_BIT);
+ gpuPushAttrib(GPU_DEPTH_BUFFER_BIT | GPU_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);
+ GPUDepthResolveInterface *interface = GPU_fx_shader_get_interface(depth_resolve_shader);
- GPU_shader_bind(depth_resolve_shader);
+ /* set up quad buffer */
+ GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(depth_resolve_shader), GPU_shader_get_interface(depth_resolve_shader));
GPU_texture_bind(fx->depth_buffer_xray, 0);
- GPU_texture_filter_mode(fx->depth_buffer_xray, false, true);
+ GPU_texture_compare_mode(fx->depth_buffer_xray, false);
+ GPU_texture_filter_mode(fx->depth_buffer_xray, true);
GPU_shader_uniform_texture(depth_resolve_shader, interface->depth_uniform, fx->depth_buffer_xray);
/* draw */
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ GWN_batch_draw(fx->quad_batch);
/* disable bindings */
- GPU_texture_filter_mode(fx->depth_buffer_xray, true, false);
+ GPU_texture_compare_mode(fx->depth_buffer_xray, true);
+ GPU_texture_filter_mode(fx->depth_buffer_xray, false);
GPU_texture_unbind(fx->depth_buffer_xray);
GPU_shader_unbind();
@@ -714,11 +751,7 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx)
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-
- glPopAttrib();
+ gpuPopAttrib();
}
@@ -748,19 +781,13 @@ bool GPU_fx_do_composite_pass(
GPU_framebuffer_texture_detach(fx->color_buffer);
GPU_framebuffer_texture_detach(fx->depth_buffer);
- if (fx->restore_stencil)
- glPopAttrib();
+ if (fx->restore_stencil) {
+ gpuPopAttrib();
+ }
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 */
@@ -788,8 +815,6 @@ bool GPU_fx_do_composite_pass(
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 */
@@ -798,7 +823,9 @@ bool GPU_fx_do_composite_pass(
ssao_shader = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_SSAO, is_persp);
if (ssao_shader) {
const GPUSSAOSettings *fx_ssao = fx->settings.ssao;
- float ssao_params[4] = {fx_ssao->distance_max, fx_ssao->factor, fx_ssao->attenuation, 0.0f};
+ /* 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;
@@ -808,9 +835,9 @@ bool GPU_fx_do_composite_pass(
ssao_params[3] = (passes_left == 1 && !ofs) ? dfdyfac[0] : dfdyfac[1];
- GPUSSAOShaderInterface *interface = GPU_shader_get_interface(ssao_shader);
+ GPUSSAOShaderInterface *interface = GPU_fx_shader_get_interface(ssao_shader);
- GPU_shader_bind(ssao_shader);
+ GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(ssao_shader), GPU_shader_get_interface(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);
@@ -821,7 +848,8 @@ bool GPU_fx_do_composite_pass(
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_texture_compare_mode(fx->depth_buffer, false);
+ GPU_texture_filter_mode(fx->depth_buffer, true);
GPU_shader_uniform_texture(ssao_shader, interface->depth_uniform, fx->depth_buffer);
GPU_texture_bind(fx->jitter_buffer, numslots++);
@@ -833,11 +861,12 @@ bool GPU_fx_do_composite_pass(
/* draw */
gpu_fx_bind_render_target(&passes_left, fx, ofs, target);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ GWN_batch_draw(fx->quad_batch);
/* disable bindings */
GPU_texture_unbind(src);
- GPU_texture_filter_mode(fx->depth_buffer, true, false);
+ GPU_texture_compare_mode(fx->depth_buffer, true);
+ GPU_texture_filter_mode(fx->depth_buffer, false);
GPU_texture_unbind(fx->depth_buffer);
GPU_texture_unbind(fx->jitter_buffer);
GPU_texture_unbind(fx->ssao_spiral_samples_tex);
@@ -890,11 +919,8 @@ bool GPU_fx_do_composite_pass(
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;
}
@@ -902,9 +928,9 @@ bool GPU_fx_do_composite_pass(
{
float invrendertargetdim[2] = {1.0f / fx->dof_downsampled_w, 1.0f / fx->dof_downsampled_h};
- GPUDOFHQPassOneInterface *interface = GPU_shader_get_interface(dof_shader_pass1);
+ GPUDOFHQPassOneInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass1);
- GPU_shader_bind(dof_shader_pass1);
+ GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass1), GPU_shader_get_interface(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);
@@ -913,28 +939,31 @@ bool GPU_fx_do_composite_pass(
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_texture_compare_mode(fx->depth_buffer, false);
+ GPU_texture_filter_mode(fx->depth_buffer, 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_texture_filter_mode(src, 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);
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_near, 0, 0);
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_far, 1, 0);
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_nearfar_coc, 2, 0);
/* 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);
+ GWN_batch_draw(fx->quad_batch);
+
/* disable bindings */
- GPU_texture_filter_mode(src, false, true);
+ GPU_texture_filter_mode(src, true);
GPU_texture_unbind(src);
- GPU_texture_filter_mode(fx->depth_buffer, true, false);
+ GPU_texture_compare_mode(fx->depth_buffer, true);
+ GPU_texture_filter_mode(fx->depth_buffer, false);
GPU_texture_unbind(fx->depth_buffer);
GPU_framebuffer_texture_detach(fx->dof_half_downsampled_near);
@@ -951,24 +980,23 @@ bool GPU_fx_do_composite_pass(
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);
+ GPUDOFHQPassTwoInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass2);
- GPU_shader_bind(dof_shader_pass2);
+ GWN_batch_program_set(fx->point_batch, GPU_shader_get_program(dof_shader_pass2), GPU_shader_get_interface(dof_shader_pass2));
+
+ GPU_texture_bind(fx->dof_nearfar_coc, numslots++);
+ GPU_texture_bind(fx->dof_half_downsampled_far, numslots++);
+ GPU_texture_bind(fx->dof_half_downsampled_near, numslots++);
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);
+ GPU_texture_filter_mode(fx->dof_half_downsampled_far, false);
/* target is the downsampled coc buffer */
- GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_far_blur, 0, NULL);
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_far_blur, 0, 0);
GPU_texture_bind_as_framebuffer(fx->dof_far_blur);
glDisable(GL_DEPTH_TEST);
@@ -979,24 +1007,24 @@ bool GPU_fx_do_composite_pass(
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);
+ GWN_batch_draw_stupid_instanced(fx->point_batch, 0, fx->dof_downsampled_w * fx->dof_downsampled_h, 0, 0, NULL, NULL);
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_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_half_downsampled_near);
+ GPU_texture_filter_mode(fx->dof_half_downsampled_near, false);
- GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_blur, 0, NULL);
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_blur, 0, 0);
/* 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);
+ GWN_batch_draw_stupid_instanced(fx->point_batch, 0, fx->dof_downsampled_w * fx->dof_downsampled_h, 0, 0, NULL, NULL);
+ GWN_batch_program_use_end(fx->point_batch);
/* disable bindings */
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -1008,15 +1036,16 @@ bool GPU_fx_do_composite_pass(
GPU_texture_unbind(fx->dof_nearfar_coc);
GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_far_blur);
+ numslots = 0;
}
/* 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);
+ GPUDOFHQPassThreeInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass3);
- GPU_shader_bind(dof_shader_pass3);
+ GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass3), GPU_shader_get_interface(dof_shader_pass3));
GPU_shader_uniform_vector(dof_shader_pass3, interface->dof_uniform, 4, 1, dof_params);
@@ -1025,14 +1054,15 @@ bool GPU_fx_do_composite_pass(
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_filter_mode(fx->dof_near_blur, 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_filter_mode(fx->dof_far_blur, true);
GPU_texture_bind(fx->depth_buffer, numslots++);
- GPU_texture_filter_mode(fx->depth_buffer, false, false);
+ GPU_texture_compare_mode(fx->depth_buffer, false);
+ GPU_texture_filter_mode(fx->depth_buffer, false);
GPU_shader_uniform_texture(dof_shader_pass3, interface->depth_uniform, fx->depth_buffer);
GPU_texture_bind(src, numslots++);
@@ -1041,13 +1071,13 @@ bool GPU_fx_do_composite_pass(
/* 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);
+ GWN_batch_draw(fx->quad_batch);
/* 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_compare_mode(fx->depth_buffer, true);
GPU_texture_unbind(fx->depth_buffer);
/* may not be attached, in that case this just returns */
@@ -1083,11 +1113,8 @@ bool GPU_fx_do_composite_pass(
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;
}
@@ -1095,9 +1122,9 @@ bool GPU_fx_do_composite_pass(
{
float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]};
- GPUDOFPassOneInterface *interface = GPU_shader_get_interface(dof_shader_pass1);
+ GPUDOFPassOneInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass1);
- GPU_shader_bind(dof_shader_pass1);
+ GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass1), GPU_shader_get_interface(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);
@@ -1107,18 +1134,20 @@ bool GPU_fx_do_composite_pass(
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_texture_compare_mode(fx->depth_buffer, false);
+ GPU_texture_filter_mode(fx->depth_buffer, 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);
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, 0);
/* 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);
+ GWN_batch_draw(fx->quad_batch);
/* disable bindings */
GPU_texture_unbind(src);
- GPU_texture_filter_mode(fx->depth_buffer, true, false);
+ GPU_texture_compare_mode(fx->depth_buffer, true);
+ GPU_texture_filter_mode(fx->depth_buffer, false);
GPU_texture_unbind(fx->depth_buffer);
GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer);
@@ -1132,32 +1161,37 @@ bool GPU_fx_do_composite_pass(
float tmp = invrendertargetdim[0];
invrendertargetdim[0] = 0.0f;
- GPUDOFPassTwoInterface *interface = GPU_shader_get_interface(dof_shader_pass2);
+ GPUDOFPassTwoInterface *interface = GPU_fx_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);
+ GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass2), GPU_shader_get_interface(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_texture_compare_mode(fx->depth_buffer, false);
+ GPU_texture_filter_mode(fx->depth_buffer, 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);
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, 0);
/* Drawing quad */
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ GWN_batch_draw(fx->quad_batch);
+
+ /* Rebind Shader */
+ GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass2), GPU_shader_get_interface(dof_shader_pass2));
/* *unbind/detach */
GPU_texture_unbind(fx->dof_near_coc_buffer);
+
GPU_framebuffer_texture_detach(fx->dof_near_coc_final_buffer);
/* Blurring horizontally */
@@ -1168,11 +1202,13 @@ bool GPU_fx_do_composite_pass(
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);
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_blurred_buffer, 0, 0);
+
+ GWN_batch_draw(fx->quad_batch);
/* *unbind/detach */
- GPU_texture_filter_mode(fx->depth_buffer, true, false);
+ GPU_texture_compare_mode(fx->depth_buffer, true);
+ GPU_texture_filter_mode(fx->depth_buffer, false);
GPU_texture_unbind(fx->depth_buffer);
GPU_texture_unbind(fx->dof_near_coc_final_buffer);
@@ -1185,9 +1221,9 @@ bool GPU_fx_do_composite_pass(
/* third pass, calculate near coc */
{
- GPUDOFPassThreeInterface *interface = GPU_shader_get_interface(dof_shader_pass3);
+ GPUDOFPassThreeInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass3);
- GPU_shader_bind(dof_shader_pass3);
+ GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass3), GPU_shader_get_interface(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);
@@ -1195,9 +1231,9 @@ bool GPU_fx_do_composite_pass(
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);
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, 0);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ GWN_batch_draw(fx->quad_batch);
/* disable bindings */
GPU_texture_unbind(fx->dof_near_coc_buffer);
GPU_texture_unbind(fx->dof_near_coc_blurred_buffer);
@@ -1213,17 +1249,17 @@ bool GPU_fx_do_composite_pass(
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);
+ GPUDOFPassFourInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass4);
- GPU_shader_bind(dof_shader_pass4);
+ GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass4), GPU_shader_get_interface(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);
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, 0);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ GWN_batch_draw(fx->quad_batch);
/* disable bindings */
GPU_texture_unbind(fx->dof_near_coc_final_buffer);
@@ -1238,9 +1274,9 @@ bool GPU_fx_do_composite_pass(
{
float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]};
- GPUDOFPassFiveInterface *interface = GPU_shader_get_interface(dof_shader_pass5);
+ GPUDOFPassFiveInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass5);
- GPU_shader_bind(dof_shader_pass5);
+ GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass5), GPU_shader_get_interface(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);
@@ -1256,18 +1292,20 @@ bool GPU_fx_do_composite_pass(
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_texture_compare_mode(fx->depth_buffer, false);
+ GPU_texture_filter_mode(fx->depth_buffer, 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);
+ GWN_batch_draw(fx->quad_batch);
/* 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_compare_mode(fx->depth_buffer, true);
+ GPU_texture_filter_mode(fx->depth_buffer, false);
GPU_texture_unbind(fx->depth_buffer);
/* may not be attached, in that case this just returns */
@@ -1287,10 +1325,6 @@ bool GPU_fx_do_composite_pass(
}
}
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
-
GPU_shader_unbind();
return true;
@@ -1303,6 +1337,7 @@ void GPU_fx_compositor_init_dof_settings(GPUDOFSettings *fx_dof)
fx_dof->focus_distance = 1.0f;
fx_dof->sensor = 1.0f;
fx_dof->num_blades = 6;
+ fx_dof->ratio = 1.0f;
}
void GPU_fx_compositor_init_ssao_settings(GPUSSAOSettings *fx_ssao)
@@ -1313,7 +1348,7 @@ void GPU_fx_compositor_init_ssao_settings(GPUSSAOSettings *fx_ssao)
fx_ssao->samples = 20;
}
-void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect effect)
+void GPU_fx_shader_init_interface(GPUShader *shader, GPUFXShaderEffect effect)
{
if (!shader)
return;
@@ -1332,7 +1367,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef
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);
+ GPU_fx_shader_set_interface(shader, interface);
break;
}
@@ -1346,7 +1381,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef
interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer");
interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs");
- GPU_shader_set_interface(shader, interface);
+ GPU_fx_shader_set_interface(shader, interface);
break;
}
@@ -1360,7 +1395,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef
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);
+ GPU_fx_shader_set_interface(shader, interface);
break;
}
@@ -1376,7 +1411,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef
interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs");
interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer");
- GPU_shader_set_interface(shader, interface);
+ GPU_fx_shader_set_interface(shader, interface);
break;
}
@@ -1390,7 +1425,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef
interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer");
interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs");
- GPU_shader_set_interface(shader, interface);
+ GPU_fx_shader_set_interface(shader, interface);
break;
}
case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO:
@@ -1403,7 +1438,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef
interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer");
interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs");
- GPU_shader_set_interface(shader, interface);
+ GPU_fx_shader_set_interface(shader, interface);
break;
}
case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE:
@@ -1413,7 +1448,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef
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);
+ GPU_fx_shader_set_interface(shader, interface);
break;
}
case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR:
@@ -1423,7 +1458,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef
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);
+ GPU_fx_shader_set_interface(shader, interface);
break;
}
case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE:
@@ -1438,7 +1473,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef
interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer");
interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs");
- GPU_shader_set_interface(shader, interface);
+ GPU_fx_shader_set_interface(shader, interface);
break;
}
@@ -1448,7 +1483,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef
interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer");
- GPU_shader_set_interface(shader, interface);
+ GPU_fx_shader_set_interface(shader, interface);
break;
}
diff --git a/source/blender/gpu/intern/gpu_debug.c b/source/blender/gpu/intern/gpu_debug.c
index be9285727fe..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 *****
*/
@@ -29,7 +29,10 @@
* \ingroup gpu
*/
+#include "BLI_compiler_attrs.h"
+#include "BLI_utildefines.h"
#include "BLI_sys_types.h"
+#include "BLI_system.h"
#include "BKE_global.h"
@@ -41,284 +44,190 @@
#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
-
- default:
- return "<unknown error>";
- }
-}
+/* control whether we use older AMD_debug_output extension
+ * some supported GPU + OS combos do not have the newer extensions */
+# define LEGACY_DEBUG 1
-#undef CASE_CODE_RETURN_STR
+/* Debug callbacks need the same calling convention as OpenGL functions. */
+# if defined(_WIN32)
+# define APIENTRY __stdcall
+# else
+# define APIENTRY
+# endif
-static bool gpu_report_gl_errors(const char *file, int line, const char *str)
+static const char *source_name(GLenum source)
{
- 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;
+ switch (source) {
+ case GL_DEBUG_SOURCE_API: return "API";
+ case GL_DEBUG_SOURCE_WINDOW_SYSTEM: return "window system";
+ case GL_DEBUG_SOURCE_SHADER_COMPILER: return "shader compiler";
+ case GL_DEBUG_SOURCE_THIRD_PARTY: return "3rd party";
+ case GL_DEBUG_SOURCE_APPLICATION: return "application";
+ case GL_DEBUG_SOURCE_OTHER: return "other";
+ default: return "???";
}
}
-
-const char *gpuErrorString(GLenum err)
+static const char *message_type_name(GLenum message)
{
- 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>";
+ switch (message) {
+ case GL_DEBUG_TYPE_ERROR: return "error";
+ case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: return "deprecated behavior";
+ case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: return "undefined behavior";
+ case GL_DEBUG_TYPE_PORTABILITY: return "portability";
+ case GL_DEBUG_TYPE_PERFORMANCE: return "performance";
+ case GL_DEBUG_TYPE_OTHER: return "other";
+ case GL_DEBUG_TYPE_MARKER: return "marker"; /* KHR has this, ARB does not */
+ default: return "???";
}
}
-
-/* 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
-
-
static void APIENTRY gpu_debug_proc(
GLenum source, GLenum type, GLuint UNUSED(id),
- GLenum UNUSED(severity), GLsizei UNUSED(length),
+ GLenum severity, GLsizei UNUSED(length),
const GLchar *message, const GLvoid *UNUSED(userParm))
{
- if (source == GL_DEBUG_SOURCE_API && type == GL_DEBUG_TYPE_ERROR) {
- fprintf(stderr, "GL: %s\n", message);
- fflush(stderr);
+ bool backtrace = false;
+
+ switch (severity) {
+ case GL_DEBUG_SEVERITY_HIGH:
+ backtrace = true;
+ ATTR_FALLTHROUGH;
+ case GL_DEBUG_SEVERITY_MEDIUM:
+ case GL_DEBUG_SEVERITY_LOW:
+ case GL_DEBUG_SEVERITY_NOTIFICATION: /* KHR has this, ARB does not */
+ fprintf(stderr, "GL %s %s: %s\n", source_name(source), message_type_name(type), message);
}
- else if (G.debug_value == 20) {
- fprintf(stderr, "GL: %s\n", message);
+
+ if (backtrace) {
+ BLI_system_backtrace(stderr);
fflush(stderr);
}
}
+# 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 UNUSED(category),
- GLenum UNUSED(severity), GLsizei UNUSED(length),
+ GLuint UNUSED(id), GLenum category,
+ GLenum severity, GLsizei UNUSED(length),
const GLchar *message, GLvoid *UNUSED(userParm))
{
- fprintf(stderr, "GL: %s\n", message);
-}
-#endif
+ bool backtrace = false;
+ switch (severity) {
+ case GL_DEBUG_SEVERITY_HIGH:
+ backtrace = true;
+ ATTR_FALLTHROUGH;
+ case GL_DEBUG_SEVERITY_MEDIUM:
+ case GL_DEBUG_SEVERITY_LOW:
+ fprintf(stderr, "GL %s: %s\n", category_name_amd(category), message);
+ }
-#undef APIENTRY
+ if (backtrace) {
+ BLI_system_backtrace(stderr);
+ fflush(stderr);
+ }
+}
+# endif /* LEGACY_DEBUG */
+
+# 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) {
+ 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);
- glDebugMessageCallback((GLDEBUGPROC)gpu_debug_proc, mxGetCurrentContext());
+ glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
+ glDebugMessageCallback((GLDEBUGPROC)gpu_debug_proc, NULL);
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
- GPU_string_marker(sizeof(success), success);
- return;
+ GPU_string_marker(success);
}
-#endif
-
- if (GLEW_KHR_debug) {
-#ifndef GLEW_ES_ONLY
- glDebugMessageCallback((GLDEBUGPROC)gpu_debug_proc, mxGetCurrentContext());
- glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
- GPU_string_marker(sizeof(success), success);
-#endif
- return;
- }
-
-#ifndef GLEW_ES_ONLY
- if (GLEW_ARB_debug_output) {
- glDebugMessageCallbackARB((GLDEBUGPROCARB)gpu_debug_proc, mxGetCurrentContext());
+ else if (GLEW_ARB_debug_output) {
+ fprintf(stderr, "Using ARB_debug_output extension\n");
+ glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
+ glDebugMessageCallbackARB((GLDEBUGPROCARB)gpu_debug_proc, NULL);
glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
- GPU_string_marker(sizeof(success), success);
-
- return;
+ GPU_string_marker(success);
}
-
- if (GLEW_AMD_debug_output) {
- glDebugMessageCallbackAMD(gpu_debug_proc_amd, mxGetCurrentContext());
+# if LEGACY_DEBUG
+ else if (GLEW_AMD_debug_output) {
+ fprintf(stderr, "Using AMD_debug_output extension\n");
+ glDebugMessageCallbackAMD(gpu_debug_proc_amd, NULL);
glDebugMessageEnableAMD(GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
- GPU_string_marker(sizeof(success), success);
-
- return;
+ GPU_string_marker(success);
}
-#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(size_t length, const char *buf)
+void GPU_string_marker(const char *buf)
{
-#ifndef WITH_GLEW_ES
-#ifndef GLEW_ES_ONLY
- if (GLEW_VERSION_4_3) {
+#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, length, buf);
-
- return;
+ GL_DEBUG_SEVERITY_NOTIFICATION, -1, buf);
}
-#endif
-#endif
-
- if (GLEW_KHR_debug) {
-#ifndef GLEW_ES_ONLY
- glDebugMessageInsert(
- GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 0,
- GL_DEBUG_SEVERITY_NOTIFICATION, length, 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, length, buf);
-
- return;
+ GL_DEBUG_SEVERITY_LOW_ARB, -1, buf);
}
-
- 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,
- length, buf);
-
- return;
+ 0, buf);
}
-
- if (GLEW_GREMEDY_string_marker) {
- glStringMarkerGREMEDY(length, buf);
-
- return;
- }
-#endif
-
- return;
+# endif
+#endif /* not Apple */
}
void GPU_print_error_debug(const char *str)
@@ -326,401 +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)
-{
- const unsigned char err_mark[4] = {0xff, 0xff, 0xff, 0xff};
-
- float value[32];
- int a;
-
- memset(value, 0xff, sizeof(value));
- glGetFloatv(type, value);
-
- if (glGetError() == GL_NO_ERROR) {
- printf("%s: ", name);
- for (a = 0; a < 32; a++) {
- if (memcmp(&value[a], err_mark, sizeof(value[a])) == 0) {
- break;
- }
- printf("%.2f ", value[a]);
- }
- printf("\n");
- }
-}
-
-#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_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 7936811ab4d..e6c37425828 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -38,13 +38,12 @@
#include <string.h>
-#include "GPU_glew.h"
-
#include "BLI_blenlib.h"
#include "BLI_linklist.h"
#include "BLI_math.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#include "BLI_hash.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
@@ -80,6 +79,7 @@
#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_material.h"
+#include "GPU_matrix.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
@@ -108,23 +108,27 @@ static void gpu_mcol(unsigned int ucol)
}
void GPU_render_text(
- MTexPoly *mtexpoly, int mode,
- const char *textstr, int textlen, unsigned int *col,
+ 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) {
+ /* XXX, 2.8 removes texface */
+#if 0
+ Image *ima = mtexpoly->tpage;
+#else
+ Image *ima = NULL;
+#endif
+ if ((mode & GEMAT_TEXT) && (textlen > 0) && ima) {
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
@@ -132,50 +136,48 @@ void GPU_render_text(
line_height *= 1.2f; /* could be an option? */
/* end multiline */
-
+
/* color has been set */
- if (mtexpoly->mode & TF_OBCOL)
- col = NULL;
- else if (!col)
+ if (!col)
glColor3f(1.0f, 1.0f, 1.0f);
- glPushMatrix();
-
+ gpuPushMatrix();
+
/* 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);
-
+ &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);
+ gpuTranslate2f(line_start, -line_height);
line_start = 0.0f;
continue;
}
else if (character == '\t') {
- glTranslatef(advance_tab, 0.0f, 0.0f);
+ gpuTranslate2f(advance_tab, 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);
+ &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;
@@ -183,13 +185,13 @@ void GPU_render_text(
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]);
@@ -211,28 +213,29 @@ void GPU_render_text(
}
glEnd();
- glTranslatef(advance, 0.0f, 0.0f);
+ gpuTranslate2f(advance, 0.0f);
line_start -= advance; /* so we can go back to the start of the line */
}
- glPopMatrix();
+ gpuPopMatrix();
BKE_image_release_ibuf(ima, first_ibuf, NULL);
}
}
/* 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);
}
@@ -268,8 +271,7 @@ static struct GPUTextureState {
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 = {0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 1, 0, 0, -1, 1.0f, 0};
/* Mipmap settings */
@@ -278,36 +280,13 @@ void GPU_set_gpu_mipmapping(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();
}
}
-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(bool mipmap)
{
if (GTS.domipmap != mipmap) {
@@ -414,43 +393,16 @@ static unsigned int *gpu_get_image_bindcode(Image *ima, GLenum textarget)
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)) {
@@ -459,59 +411,20 @@ static void gpu_set_alpha_blend(GPUBlendMode alphablend)
/* 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;
-
- 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);
- }
-}
-
typedef struct VerifyThreadData {
ImBuf *ibuf;
float *srgb_frect;
@@ -533,8 +446,6 @@ static void gpu_verify_high_bit_srgb_buffer_slice(float *srgb_frect,
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,
@@ -603,19 +514,6 @@ int GPU_verify_image(
return (ima != NULL);
}
- /* 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 (ima == NULL || ima->ok == 0)
return 0;
@@ -651,29 +549,29 @@ int GPU_verify_image(
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;
@@ -747,7 +645,7 @@ int GPU_verify_image(
memcpy(tilerectrow, rectrow, tpx * sizeof(*rectrow));
}
-
+
rect = tilerect;
}
}
@@ -758,13 +656,13 @@ int GPU_verify_image(
else
#endif
GPU_create_gl_tex(bind, rect, frect, rectw, recth, textarget, mipmap, use_high_bit_depth, ima);
-
+
/* mark as non-color data texture */
if (*bind) {
if (is_data)
- ima->tpageflag |= IMA_GLBIND_IS_DATA;
+ ima->tpageflag |= IMA_GLBIND_IS_DATA;
else
- ima->tpageflag &= ~IMA_GLBIND_IS_DATA;
+ ima->tpageflag &= ~IMA_GLBIND_IS_DATA;
}
/* clean up */
@@ -857,30 +755,6 @@ 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);
@@ -899,7 +773,7 @@ void GPU_create_gl_tex(
if (GPU_get_mipmap() && mipmap) {
if (GTS.gpu_mipmap) {
- gpu_generate_mipmap(GL_TEXTURE_2D);
+ glGenerateMipmap(GL_TEXTURE_2D);
}
else {
int i;
@@ -950,7 +824,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,7 +848,7 @@ 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]);
+ informat, mipw, miph, 0, GL_RGBA, type, mip_cube_map[j]);
}
}
gpu_del_cube_map(mip_cube_map);
@@ -1055,7 +929,7 @@ 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);
+ 0, size, ibuf->dds_data.data + offset);
offset += size;
width >>= 1;
@@ -1090,62 +964,6 @@ void GPU_create_gl_tex_compressed(
}
#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;
-}
/* these two functions are called on entering and exiting texture paint mode,
* temporary disabling/enabling mipmapping on all images for quick texture
@@ -1203,11 +1021,9 @@ void GPU_paint_set_mipmap(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)
+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);
@@ -1260,7 +1076,7 @@ static bool GPU_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x,
}
if (GPU_get_mipmap()) {
- gpu_generate_mipmap(GL_TEXTURE_2D);
+ glGenerateMipmap(GL_TEXTURE_2D);
}
else {
ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
@@ -1295,8 +1111,8 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
float *buffer = MEM_mallocN(w * h * sizeof(float) * 4, "temp_texpaint_float_buf");
bool is_data = (ima->tpageflag & IMA_GLBIND_IS_DATA) != 0;
IMB_partial_rect_from_float(ibuf, buffer, x, y, w, h, is_data);
-
- if (GPU_check_scaled_image(ibuf, ima, buffer, x, y, w, h)) {
+
+ if (gpu_check_scaled_image(ibuf, ima, buffer, x, y, w, h)) {
MEM_freeN(buffer);
BKE_image_release_ibuf(ima, ibuf, NULL);
return;
@@ -1310,7 +1126,7 @@ 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;
@@ -1320,7 +1136,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
return;
}
- if (GPU_check_scaled_image(ibuf, ima, NULL, x, y, w, h)) {
+ if (gpu_check_scaled_image(ibuf, ima, NULL, x, y, w, h)) {
BKE_image_release_ibuf(ima, ibuf, NULL);
return;
}
@@ -1336,7 +1152,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA,
- GL_UNSIGNED_BYTE, ibuf->rect);
+ GL_UNSIGNED_BYTE, ibuf->rect);
glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels);
@@ -1344,7 +1160,7 @@ 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;
@@ -1360,9 +1176,9 @@ void GPU_update_images_framechange(void)
if (ima->tpageflag & IMA_TWINANIM) {
if (ima->twend >= ima->xrep * ima->yrep)
ima->twend = ima->xrep * ima->yrep - 1;
-
+
/* check: is bindcode not in the array? free. (to do) */
-
+
ima->lastframe++;
if (ima->lastframe > ima->twend)
ima->lastframe = ima->twsta;
@@ -1385,9 +1201,9 @@ int GPU_update_image_time(Image *ima, double time)
if (ima->tpageflag & IMA_TWINANIM) {
if (ima->twend >= ima->xrep * ima->yrep) ima->twend = ima->xrep * ima->yrep - 1;
-
+
/* check: is the bindcode not in the array? Then free. (still to do) */
-
+
float diff = (float)((float)time - ima->lastupdate);
inc = (int)(diff * (float)ima->animspeed);
@@ -1436,31 +1252,40 @@ void GPU_create_smoke(SmokeModifierData *smd, int highres)
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);
+ sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], data, NULL);
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 = GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1,
+ GPU_R8, smoke_get_density(sds->fluid), NULL);
}
- 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;
+ sds->tex_flame = (smoke_has_fuel(sds->fluid)) ?
+ GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1,
+ GPU_R8, smoke_get_flame(sds->fluid), NULL) :
+ NULL;
}
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);
+ sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], data, NULL);
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 = GPU_texture_create_3D_custom(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1,
+ GPU_R8, smoke_turbulence_get_density(sds->wt), NULL);
}
- 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;
+ sds->tex_flame = (smoke_turbulence_has_fuel(sds->wt)) ?
+ GPU_texture_create_3D_custom(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1,
+ GPU_R8, smoke_turbulence_get_flame(sds->wt), NULL):
+ NULL;
}
- sds->tex_shadow = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, sds->shadow);
+ sds->tex_shadow = GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1,
+ GPU_R8, sds->shadow, NULL);
}
#else // WITH_SMOKE
(void)highres;
@@ -1527,7 +1352,7 @@ 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;
}
@@ -1600,7 +1425,7 @@ typedef struct GPUMaterialFixed {
float spec[3];
int hard;
float alpha;
-} GPUMaterialFixed;
+} GPUMaterialFixed;
static struct GPUMaterialState {
GPUMaterialFixed (*matbuf);
@@ -1656,12 +1481,12 @@ static void gpu_material_to_fixed(
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);
@@ -1672,7 +1497,7 @@ static void gpu_material_to_fixed(
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;
@@ -1709,7 +1534,7 @@ void GPU_end_dupli_object(void)
}
void GPU_begin_object_materials(
- View3D *v3d, RegionView3D *rv3d, Scene *scene, Object *ob,
+ View3D *v3d, RegionView3D *rv3d, Scene *scene, SceneLayer *sl, Object *ob,
bool glsl, bool *do_alpha_after)
{
Material *ma;
@@ -1748,8 +1573,10 @@ void GPU_begin_object_materials(
#ifdef WITH_GAMEENGINE
if (rv3d->rflag & RV3D_IS_GAME_ENGINE) {
- ob = BKE_object_lod_matob_get(ob, scene);
+ ob = BKE_object_lod_matob_get(ob, sl);
}
+#else
+ UNUSED_VARS(sl);
#endif
/* initialize state */
@@ -1788,7 +1615,7 @@ void GPU_begin_object_materials(
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");
@@ -1807,11 +1634,11 @@ void GPU_begin_object_materials(
/* 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);
@@ -1826,7 +1653,7 @@ void GPU_begin_object_materials(
GMS.alphablend[0] = GPU_BLEND_SOLID;
}
-
+
/* setup materials */
for (a = 1; a <= ob->totcol; a++) {
/* find a suitable material */
@@ -1870,7 +1697,7 @@ void GPU_begin_object_materials(
GPU_object_material_unbind();
}
-static int GPU_get_particle_info(GPUParticleInfo *pi)
+static int gpu_get_particle_info(GPUParticleInfo *pi)
{
DupliObject *dob = GMS.dob;
if (dob->particle_system) {
@@ -1899,6 +1726,21 @@ static int GPU_get_particle_info(GPUParticleInfo *pi)
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;
@@ -1958,21 +1800,27 @@ int GPU_object_material_bind(int nr, void *attribs)
/* 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 (GMS.dob) {
+ gpu_get_particle_info(&partile_info);
+ }
+
+ if ((GPU_get_material_builtins(gpumat) & GPU_OBJECT_INFO) != 0) {
+ 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);
+ 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
@@ -2040,7 +1888,7 @@ void GPU_set_material_alpha_blend(int alphablend)
{
if (GMS.lastalphablend == alphablend)
return;
-
+
gpu_set_alpha_blend(alphablend);
GMS.lastalphablend = alphablend;
}
@@ -2111,13 +1959,6 @@ void GPU_end_object_materials(void)
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 */
@@ -2131,13 +1972,13 @@ int GPU_default_lights(void)
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;
@@ -2170,31 +2011,28 @@ int GPU_default_lights(void)
return count;
}
-int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][4], int ortho)
+int GPU_scene_object_lights(SceneLayer *sl, 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 ourselfs */
GPU_basic_shader_light_set_viewer(!ortho);
int count = 0;
- for (Base *base = scene->base.first; base; base = base->next) {
+ for (Base *base = FIRSTBASE_NEW; 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);
-
+ gpuPushMatrix();
+ gpuLoadMatrix(viewmat);
+
/* setup light */
GPULightData light = {0};
@@ -2213,7 +2051,7 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][
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]);
@@ -2224,11 +2062,11 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][
else
light.type = GPU_LIGHT_POINT;
}
-
+
GPU_basic_shader_light_set(count, &light);
-
- glPopMatrix();
-
+
+ gpuPopMatrix();
+
count++;
if (count == 8)
break;
@@ -2275,64 +2113,36 @@ static void gpu_multisample(bool enable)
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_default_lights();
-
+
+ GPU_disable_program_point_size();
+
+ 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);
+void GPU_enable_program_point_size(void)
+{
+ glEnable(GL_PROGRAM_POINT_SIZE);
+}
+
+void GPU_disable_program_point_size(void)
+{
+ glDisable(GL_PROGRAM_POINT_SIZE);
}
#ifdef WITH_OPENSUBDIV
@@ -2478,10 +2288,10 @@ void GPU_select_to_index_array(unsigned int *col, const unsigned int size)
{
#define INDEX_BUF_ARRAY(INDEX_FROM_BUF_BITS) \
for (i = size; i--; col++) { \
- if ((c = *col)) { \
- *col = INDEX_FROM_BUF_BITS(c); \
- } \
- } ((void)0)
+ if ((c = *col)) { \
+ *col = INDEX_FROM_BUF_BITS(c); \
+ } \
+ } ((void)0)
if (size > 0) {
unsigned int i, c;
@@ -2509,4 +2319,172 @@ 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 */
+ unsigned int is_blend : 1;
+ unsigned int is_cull_face : 1;
+ unsigned int is_depth_test : 1;
+ unsigned int is_dither : 1;
+ unsigned int is_lighting : 1;
+ unsigned int is_line_smooth : 1;
+ unsigned int is_color_logic_op : 1;
+ unsigned int is_multisample : 1;
+ unsigned int is_polygon_offset_line : 1;
+ unsigned int is_polygon_offset_fill : 1;
+ unsigned int is_polygon_smooth : 1;
+ unsigned int is_sample_alpha_to_coverage : 1;
+ unsigned int is_scissor_test : 1;
+ unsigned int is_stencil_test : 1;
+
+ bool is_clip_plane[6];
+
+ /* GL_DEPTH_BUFFER_BIT */
+ /* unsigned int is_depth_test : 1; */
+ int depth_func;
+ double depth_clear_value;
+ bool depth_write_mask;
+
+ /* GL_SCISSOR_BIT */
+ int scissor_box[4];
+ /* unsigned int is_scissor_test : 1; */
+
+ /* GL_VIEWPORT_BIT */
+ int viewport[4];
+ double near_far[2];
+} GPUAttribValues;
+
+typedef struct {
+ GPUAttribValues attrib_stack[STATE_STACK_DEPTH];
+ unsigned int top;
+} GPUAttribStack;
+
+static GPUAttribStack state = {
+ .top = 0
+};
+
+#define AttribStack state
+#define Gwn_VertAttr 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)
+{
+ Gwn_VertAttr.mask = mask;
+
+ if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) {
+ Gwn_VertAttr.is_depth_test = glIsEnabled(GL_DEPTH_TEST);
+ glGetIntegerv(GL_DEPTH_FUNC, &Gwn_VertAttr.depth_func);
+ glGetDoublev(GL_DEPTH_CLEAR_VALUE, &Gwn_VertAttr.depth_clear_value);
+ glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&Gwn_VertAttr.depth_write_mask);
+ }
+
+ if ((mask & GPU_ENABLE_BIT) != 0) {
+ Gwn_VertAttr.is_blend = glIsEnabled(GL_BLEND);
+
+ for (int i = 0; i < 6; i++) {
+ Gwn_VertAttr.is_clip_plane[i] = glIsEnabled(GL_CLIP_PLANE0 + i);
+ }
+
+ Gwn_VertAttr.is_cull_face = glIsEnabled(GL_CULL_FACE);
+ Gwn_VertAttr.is_depth_test = glIsEnabled(GL_DEPTH_TEST);
+ Gwn_VertAttr.is_dither = glIsEnabled(GL_DITHER);
+ Gwn_VertAttr.is_line_smooth = glIsEnabled(GL_LINE_SMOOTH);
+ Gwn_VertAttr.is_color_logic_op = glIsEnabled(GL_COLOR_LOGIC_OP);
+ Gwn_VertAttr.is_multisample = glIsEnabled(GL_MULTISAMPLE);
+ Gwn_VertAttr.is_polygon_offset_line = glIsEnabled(GL_POLYGON_OFFSET_LINE);
+ Gwn_VertAttr.is_polygon_offset_fill = glIsEnabled(GL_POLYGON_OFFSET_FILL);
+ Gwn_VertAttr.is_polygon_smooth = glIsEnabled(GL_POLYGON_SMOOTH);
+ Gwn_VertAttr.is_sample_alpha_to_coverage = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE);
+ Gwn_VertAttr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
+ Gwn_VertAttr.is_stencil_test = glIsEnabled(GL_STENCIL_TEST);
+ }
+
+ if ((mask & GPU_SCISSOR_BIT) != 0) {
+ Gwn_VertAttr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
+ glGetIntegerv(GL_SCISSOR_BOX, (GLint *)&Gwn_VertAttr.scissor_box);
+ }
+
+ if ((mask & GPU_VIEWPORT_BIT) != 0) {
+ glGetDoublev(GL_DEPTH_RANGE, (GLdouble *)&Gwn_VertAttr.near_far);
+ glGetIntegerv(GL_VIEWPORT, (GLint *)&Gwn_VertAttr.viewport);
+ }
+
+ if ((mask & GPU_BLEND_BIT) != 0) {
+ Gwn_VertAttr.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 = Gwn_VertAttr.mask;
+
+ if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) {
+ restore_mask(GL_DEPTH_TEST, Gwn_VertAttr.is_depth_test);
+ glDepthFunc(Gwn_VertAttr.depth_func);
+ glClearDepth(Gwn_VertAttr.depth_clear_value);
+ glDepthMask(Gwn_VertAttr.depth_write_mask);
+ }
+
+ if ((mask & GPU_ENABLE_BIT) != 0) {
+ restore_mask(GL_BLEND, Gwn_VertAttr.is_blend);
+
+ for (int i = 0; i < 6; i++) {
+ restore_mask(GL_CLIP_PLANE0 + i, Gwn_VertAttr.is_clip_plane[i]);
+ }
+
+ restore_mask(GL_CULL_FACE, Gwn_VertAttr.is_cull_face);
+ restore_mask(GL_DEPTH_TEST, Gwn_VertAttr.is_depth_test);
+ restore_mask(GL_DITHER, Gwn_VertAttr.is_dither);
+ restore_mask(GL_LINE_SMOOTH, Gwn_VertAttr.is_line_smooth);
+ restore_mask(GL_COLOR_LOGIC_OP, Gwn_VertAttr.is_color_logic_op);
+ restore_mask(GL_MULTISAMPLE, Gwn_VertAttr.is_multisample);
+ restore_mask(GL_POLYGON_OFFSET_LINE, Gwn_VertAttr.is_polygon_offset_line);
+ restore_mask(GL_POLYGON_OFFSET_FILL, Gwn_VertAttr.is_polygon_offset_fill);
+ restore_mask(GL_POLYGON_SMOOTH, Gwn_VertAttr.is_polygon_smooth);
+ restore_mask(GL_SAMPLE_ALPHA_TO_COVERAGE, Gwn_VertAttr.is_sample_alpha_to_coverage);
+ restore_mask(GL_SCISSOR_TEST, Gwn_VertAttr.is_scissor_test);
+ restore_mask(GL_STENCIL_TEST, Gwn_VertAttr.is_stencil_test);
+ }
+
+ if ((mask & GPU_VIEWPORT_BIT) != 0) {
+ glViewport(Gwn_VertAttr.viewport[0], Gwn_VertAttr.viewport[1], Gwn_VertAttr.viewport[2], Gwn_VertAttr.viewport[3]);
+ glDepthRange(Gwn_VertAttr.near_far[0], Gwn_VertAttr.near_far[1]);
+ }
+
+ if ((mask & GPU_SCISSOR_BIT) != 0) {
+ restore_mask(GL_SCISSOR_TEST, Gwn_VertAttr.is_scissor_test);
+ glScissor(Gwn_VertAttr.scissor_box[0], Gwn_VertAttr.scissor_box[1], Gwn_VertAttr.scissor_box[2], Gwn_VertAttr.scissor_box[3]);
+ }
+
+ if ((mask & GPU_BLEND_BIT) != 0) {
+ restore_mask(GL_BLEND, Gwn_VertAttr.is_blend);
+ }
+}
+
+#undef Gwn_VertAttr
+#undef AttribStack
+
/** \} */
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index d41573b681b..6bf330179d3 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -56,14 +56,11 @@
/* 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
*/
@@ -71,7 +68,8 @@ static struct GPUGlobal {
GLint maxtexsize;
GLint maxcubemapsize;
GLint maxtextures;
- bool extdisabled;
+ GLint maxubosize;
+ GLint maxubobinds;
int colordepth;
int samples_color_texture_max;
GPUDeviceType device;
@@ -93,11 +91,6 @@ bool GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver)
/* GPU Extensions */
-void GPU_extensions_disable(void)
-{
- GG.extdisabled = true;
-}
-
int GPU_max_texture_size(void)
{
return GG.maxtexsize;
@@ -123,6 +116,16 @@ 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;
+}
+
void GPU_get_dfdy_factors(float fac[2])
{
copy_v2_v2(fac, GG.dfdyfactors);
@@ -130,8 +133,11 @@ void GPU_get_dfdy_factors(float fac[2])
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);
@@ -143,11 +149,22 @@ void gpu_extensions_init(void)
else
GG.max_anisotropy = 1.0f;
+ glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &GG.maxubobinds);
+ glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &GG.maxubosize);
+
+#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);
@@ -173,7 +190,10 @@ void gpu_extensions_init(void)
GG.device = GPU_DEVICE_INTEL;
GG.driver = GPU_DRIVER_OFFICIAL;
}
- else if (strstr(renderer, "Mesa DRI R") || (strstr(renderer, "Gallium ") && strstr(renderer, " on ATI "))) {
+ else if ((strstr(renderer, "Mesa DRI R")) ||
+ (strstr(renderer, "Gallium ") && strstr(renderer, " on ATI ")) ||
+ (strstr(renderer, "Gallium ") && strstr(renderer, " on AMD ")))
+ {
GG.device = GPU_DEVICE_ATI;
GG.driver = GPU_DRIVER_OPENSOURCE;
}
@@ -198,10 +218,6 @@ void gpu_extensions_init(void)
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__)
@@ -243,49 +259,6 @@ void gpu_extensions_exit(void)
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_glsl_support(void)
-{
- /* always supported, still queried by game engine */
- return true;
-}
-
bool GPU_full_non_power_of_two_support(void)
{
/* always supported on full GL but still relevant for OpenGL ES 2.0 where
@@ -293,39 +266,11 @@ bool GPU_full_non_power_of_two_support(void)
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;
@@ -333,12 +278,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 c0400cdb04c..cb782358f91 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.c
+++ b/source/blender/gpu/intern/gpu_framebuffer.c
@@ -32,9 +32,10 @@
#include "BKE_global.h"
-#include "GPU_debug.h"
-#include "GPU_glew.h"
+#include "GPU_batch.h"
+#include "GPU_draw.h"
#include "GPU_framebuffer.h"
+#include "GPU_matrix.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
@@ -52,46 +53,39 @@ struct GPUFrameBuffer {
GPUTexture *depthtex;
};
-static void GPU_print_framebuffer_error(GLenum status, char err_out[256])
+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);
}
}
@@ -101,41 +95,33 @@ GPUFrameBuffer *GPU_framebuffer_create(void)
{
GPUFrameBuffer *fb;
- if (!(GLEW_VERSION_3_0 || GLEW_ARB_framebuffer_object ||
- (GLEW_EXT_framebuffer_object && GLEW_EXT_framebuffer_blit)))
- {
- return NULL;
- }
-
fb = MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");
- glGenFramebuffersEXT(1, &fb->object);
+ glGenFramebuffers(1, &fb->object);
if (!fb->object) {
- fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed. %d\n",
- (int)glGetError());
+ fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed.\n");
GPU_framebuffer_free(fb);
return NULL;
}
/* 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);
+ glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
glReadBuffer(GL_NONE);
glDrawBuffer(GL_NONE);
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
return fb;
}
-int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, char err_out[256])
+bool GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int mip)
{
GLenum attachment;
- GLenum error;
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;
+ return false;
}
if ((G.debug & G_DEBUG)) {
@@ -146,26 +132,64 @@ int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot
}
}
+ glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
+ GG.currentfb = fb->object;
+
+ if (GPU_texture_stencil(tex) && GPU_texture_depth(tex))
+ attachment = GL_DEPTH_STENCIL_ATTACHMENT;
+ else if (GPU_texture_depth(tex))
+ attachment = GL_DEPTH_ATTACHMENT;
+ else
+ attachment = GL_COLOR_ATTACHMENT0 + slot;
+
+ glFramebufferTexture(GL_FRAMEBUFFER, attachment, GPU_texture_opengl_bindcode(tex), mip);
+
if (GPU_texture_depth(tex))
- attachment = GL_DEPTH_ATTACHMENT_EXT;
+ fb->depthtex = tex;
else
- attachment = GL_COLOR_ATTACHMENT0_EXT + slot;
+ fb->colortex[slot] = tex;
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
- GG.currentfb = fb->object;
+ GPU_texture_framebuffer_set(tex, fb, slot);
- /* Clean glError buffer. */
- while (glGetError() != GL_NO_ERROR) {}
+ return true;
+}
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment,
- GPU_texture_target(tex), GPU_texture_opengl_bindcode(tex), 0);
+static bool gpu_framebuffer_texture_layer_attach_ex(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip, bool cubemap)
+{
+ GLenum attachment;
+ GLenum facetarget;
- error = glGetError();
+ 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 false;
+ }
- if (error == GL_INVALID_OPERATION) {
- GPU_framebuffer_restore();
- GPU_print_framebuffer_error(error, err_out);
- return 0;
+ 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");
+ }
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
+ GG.currentfb = fb->object;
+
+ if (GPU_texture_stencil(tex) && GPU_texture_depth(tex))
+ attachment = GL_DEPTH_STENCIL_ATTACHMENT;
+ else if (GPU_texture_depth(tex))
+ attachment = GL_DEPTH_ATTACHMENT;
+ else
+ attachment = GL_COLOR_ATTACHMENT0 + slot;
+
+ if (cubemap) {
+ facetarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;
+ glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, facetarget, GPU_texture_opengl_bindcode(tex), mip);
+ }
+ else {
+ glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment, GPU_texture_opengl_bindcode(tex), mip, layer);
}
if (GPU_texture_depth(tex))
@@ -175,7 +199,18 @@ int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot
GPU_texture_framebuffer_set(tex, fb, slot);
- return 1;
+ return true;
+}
+
+bool GPU_framebuffer_texture_layer_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip)
+{
+ return gpu_framebuffer_texture_layer_attach_ex(fb, tex, slot, layer, mip, false);
+}
+
+bool GPU_framebuffer_texture_cubeface_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int face, int mip)
+{
+ BLI_assert(GPU_texture_target(tex) == GL_TEXTURE_CUBE_MAP);
+ return gpu_framebuffer_texture_layer_attach_ex(fb, tex, slot, face, mip, true);
}
void GPU_framebuffer_texture_detach(GPUTexture *tex)
@@ -188,21 +223,25 @@ void GPU_framebuffer_texture_detach(GPUTexture *tex)
return;
if (GG.currentfb != fb->object) {
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
+ glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
GG.currentfb = fb->object;
}
- if (GPU_texture_depth(tex)) {
+ if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) {
fb->depthtex = NULL;
- attachment = GL_DEPTH_ATTACHMENT_EXT;
+ attachment = GL_DEPTH_STENCIL_ATTACHMENT;
+ }
+ else if (GPU_texture_depth(tex)) {
+ fb->depthtex = NULL;
+ attachment = GL_DEPTH_ATTACHMENT;
}
else {
BLI_assert(fb->colortex[fb_attachment] == tex);
fb->colortex[fb_attachment] = NULL;
- attachment = GL_COLOR_ATTACHMENT0_EXT + fb_attachment;
+ attachment = GL_COLOR_ATTACHMENT0 + fb_attachment;
}
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, GPU_texture_target(tex), 0, 0);
+ glFramebufferTexture(GL_FRAMEBUFFER, attachment, 0, 0);
GPU_texture_framebuffer_set(tex, NULL, -1);
}
@@ -218,11 +257,11 @@ void GPU_texture_bind_as_framebuffer(GPUTexture *tex)
}
/* push attributes */
- glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT);
+ gpuPushAttrib(GPU_ENABLE_BIT | GPU_VIEWPORT_BIT);
glDisable(GL_SCISSOR_TEST);
/* bind framebuffer */
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
+ glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
if (GPU_texture_depth(tex)) {
glDrawBuffer(GL_NONE);
@@ -230,22 +269,17 @@ void GPU_texture_bind_as_framebuffer(GPUTexture *tex)
}
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);
+ glDrawBuffer(GL_COLOR_ATTACHMENT0 + fb_attachment);
+ glReadBuffer(GL_COLOR_ATTACHMENT0 + fb_attachment);
}
if (GPU_texture_target(tex) == GL_TEXTURE_2D_MULTISAMPLE) {
glEnable(GL_MULTISAMPLE);
}
- /* push matrices and set default viewport and matrix */
+ /* set default viewport */
glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex));
GG.currentfb = fb->object;
-
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
}
void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot)
@@ -260,56 +294,80 @@ void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot)
for (i = 0; i < 4; i++) {
if (fb->colortex[i]) {
- attachments[numslots] = GL_COLOR_ATTACHMENT0_EXT + i;
+ attachments[numslots] = GL_COLOR_ATTACHMENT0 + i;
numslots++;
}
}
/* push attributes */
- glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT);
+ gpuPushAttrib(GPU_ENABLE_BIT | GPU_VIEWPORT_BIT);
glDisable(GL_SCISSOR_TEST);
/* bind framebuffer */
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
+ glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
/* last bound prevails here, better allow explicit control here too */
glDrawBuffers(numslots, attachments);
- glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot);
+ glReadBuffer(GL_COLOR_ATTACHMENT0 + slot);
- /* push matrices and set default viewport and matrix */
+ /* set default viewport */
glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot]));
GG.currentfb = fb->object;
-
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
}
+void GPU_framebuffer_bind(GPUFrameBuffer *fb)
+{
+ int numslots = 0, i;
+ GLenum attachments[4];
+ GLenum readattachement = 0;
+ GPUTexture *tex;
+
+ for (i = 0; i < 4; i++) {
+ if (fb->colortex[i]) {
+ attachments[numslots] = GL_COLOR_ATTACHMENT0 + i;
+ tex = fb->colortex[i];
+
+ if (!readattachement)
+ readattachement = GL_COLOR_ATTACHMENT0 + i;
+
+ numslots++;
+ }
+ }
+
+ /* bind framebuffer */
+ glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
+
+ if (numslots == 0) {
+ glDrawBuffer(GL_NONE);
+ glReadBuffer(GL_NONE);
+ tex = fb->depthtex;
+ }
+ else {
+ /* last bound prevails here, better allow explicit control here too */
+ glDrawBuffers(numslots, attachments);
+ glReadBuffer(readattachement);
+ }
+
+ glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex));
+ GG.currentfb = fb->object;
+}
void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUSED(tex))
{
- /* restore matrix */
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
-
- /* restore attributes */
- glPopAttrib();
+ /* Restore attributes. */
+ gpuPopAttrib();
}
void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot)
{
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
+ glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
/* last bound prevails here, better allow explicit control here too */
- glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + slot);
- glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot);
+ glDrawBuffer(GL_COLOR_ATTACHMENT0 + slot);
+ glReadBuffer(GL_COLOR_ATTACHMENT0 + 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;
}
bool GPU_framebuffer_bound(GPUFrameBuffer *fb)
@@ -319,22 +377,17 @@ bool GPU_framebuffer_bound(GPUFrameBuffer *fb)
bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256])
{
- GLenum status;
-
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
+ glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
GG.currentfb = fb->object;
-
- /* Clean glError buffer. */
- while (glGetError() != GL_NO_ERROR) {}
-
- status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
-
- if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
GPU_framebuffer_restore();
- GPU_print_framebuffer_error(status, err_out);
+ gpu_print_framebuffer_error(status, err_out);
return false;
}
-
+
return true;
}
@@ -351,10 +404,10 @@ void GPU_framebuffer_free(GPUFrameBuffer *fb)
}
if (fb->object) {
- glDeleteFramebuffersEXT(1, &fb->object);
+ glDeleteFramebuffers(1, &fb->object);
if (GG.currentfb == fb->object) {
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
GG.currentfb = 0;
}
}
@@ -365,7 +418,7 @@ void GPU_framebuffer_free(GPUFrameBuffer *fb)
void GPU_framebuffer_restore(void)
{
if (GG.currentfb != 0) {
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
GG.currentfb = 0;
}
}
@@ -374,73 +427,170 @@ void GPU_framebuffer_blur(
GPUFrameBuffer *fb, GPUTexture *tex,
GPUFrameBuffer *blurfb, GPUTexture *blurtex)
{
+ const float fullscreencos[4][2] = {{-1.0f, -1.0f}, {1.0f, -1.0f}, {-1.0f, 1.0f}, {1.0f, 1.0f}};
+ const float fullscreenuvs[4][2] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}};
+
+ static Gwn_VertFormat format = {0};
+ static Gwn_VertBuf vbo = {{0}};
+ static Gwn_Batch batch = {{0}};
+
const float scaleh[2] = {1.0f / GPU_texture_width(blurtex), 0.0f};
const float scalev[2] = {0.0f, 1.0f / GPU_texture_height(tex)};
GPUShader *blur_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SEP_GAUSSIAN_BLUR);
- int scale_uniform, texture_source_uniform;
if (!blur_shader)
return;
- scale_uniform = GPU_shader_get_uniform(blur_shader, "ScaleU");
- texture_source_uniform = GPU_shader_get_uniform(blur_shader, "textureSource");
+ /* Preparing to draw quad */
+ if (format.attrib_ct == 0) {
+ unsigned int i = 0;
+ /* Vertex format */
+ unsigned int pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int uvs = GWN_vertformat_attr_add(&format, "uvs", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ /* Vertices */
+ GWN_vertbuf_init_with_format(&vbo, &format);
+ GWN_vertbuf_data_alloc(&vbo, 36);
+
+ for (int j = 0; j < 3; ++j) {
+ GWN_vertbuf_attr_set(&vbo, uvs, i, fullscreenuvs[j]);
+ GWN_vertbuf_attr_set(&vbo, pos, i++, fullscreencos[j]);
+ }
+ for (int j = 1; j < 4; ++j) {
+ GWN_vertbuf_attr_set(&vbo, uvs, i, fullscreenuvs[j]);
+ GWN_vertbuf_attr_set(&vbo, pos, i++, fullscreencos[j]);
+ }
+
+ GWN_batch_init(&batch, GL_TRIANGLES, &vbo, NULL);
+ }
+ glDisable(GL_DEPTH_TEST);
+
/* Blurring horizontally */
-
/* 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_FRAMEBUFFER, blurfb->object);
+ glDrawBuffer(GL_COLOR_ATTACHMENT0);
/* avoid warnings from texture binding */
GG.currentfb = blurfb->object;
- 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));
- /* Peparing to draw quad */
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
-
- glDisable(GL_DEPTH_TEST);
-
GPU_texture_bind(tex, 0);
- /* 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();
+ Batch_set_builtin_program(&batch, GPU_SHADER_SEP_GAUSSIAN_BLUR);
+ GWN_batch_uniform_2f(&batch, "ScaleU", scaleh[0], scaleh[1]);
+ GWN_batch_uniform_1i(&batch, "textureSource", GL_TEXTURE0);
+ GWN_batch_draw(&batch);
/* Blurring vertically */
-
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
- glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+ glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
+ glDrawBuffer(GL_COLOR_ATTACHMENT0);
GG.currentfb = fb->object;
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);
- 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();
+ /* Hack to make the following uniform stick */
+ Batch_set_builtin_program(&batch, GPU_SHADER_SEP_GAUSSIAN_BLUR);
+ GWN_batch_uniform_2f(&batch, "ScaleU", scalev[0], scalev[1]);
+ GWN_batch_uniform_1i(&batch, "textureSource", GL_TEXTURE0);
+ GWN_batch_draw(&batch);
+}
+
+void GPU_framebuffer_blit(GPUFrameBuffer *fb_read, int read_slot, GPUFrameBuffer *fb_write, int write_slot, bool use_depth)
+{
+ GPUTexture *read_tex = (use_depth) ? fb_read->depthtex : fb_read->colortex[read_slot];
+ GPUTexture *write_tex = (use_depth) ? fb_write->depthtex : fb_write->colortex[write_slot];
+ int read_attach = (use_depth) ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0 + GPU_texture_framebuffer_attachment(read_tex);
+ int write_attach = (use_depth) ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0 + GPU_texture_framebuffer_attachment(write_tex);
+ int read_bind = GPU_texture_opengl_bindcode(read_tex);
+ int write_bind = GPU_texture_opengl_bindcode(write_tex);
+ const int read_w = GPU_texture_width(read_tex);
+ const int read_h = GPU_texture_height(read_tex);
+ const int write_w = GPU_texture_width(write_tex);
+ const int write_h = GPU_texture_height(write_tex);
+
+ /* read from multi-sample buffer */
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_read->object);
+ glFramebufferTexture2D(
+ GL_READ_FRAMEBUFFER, read_attach,
+ GL_TEXTURE_2D, read_bind, 0);
+ BLI_assert(glCheckFramebufferStatus(GL_READ_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
+
+ /* write into new single-sample buffer */
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_write->object);
+ glFramebufferTexture2D(
+ GL_DRAW_FRAMEBUFFER, write_attach,
+ GL_TEXTURE_2D, write_bind, 0);
+ BLI_assert(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
+
+ glBlitFramebuffer(0, 0, read_w, read_h, 0, 0, write_w, write_h, (use_depth) ? GL_DEPTH_BUFFER_BIT : GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+ /* Restore previous framebuffer */
+ glBindFramebuffer(GL_FRAMEBUFFER, GG.currentfb);
+ glDrawBuffer(GL_COLOR_ATTACHMENT0);
+}
+
+/**
+ * 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, GPUTexture *tex, int num_iter, void (*callback)(void *userData, int level), void *userData)
+{
+ int current_dim[2] = {GPU_texture_width(tex), GPU_texture_height(tex)};
+ GLenum attachment;
+
+ /* Manually setup framebuffer to not use GPU_texture_framebuffer_set() */
+ glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
+ GG.currentfb = fb->object;
+
+ if (GPU_texture_stencil(tex) && GPU_texture_depth(tex))
+ attachment = GL_DEPTH_STENCIL_ATTACHMENT;
+ else if (GPU_texture_depth(tex))
+ attachment = GL_DEPTH_ATTACHMENT;
+ else
+ attachment = GL_COLOR_ATTACHMENT0;
+
+ /* last bound prevails here, better allow explicit control here too */
+ glDrawBuffer(GL_COLOR_ATTACHMENT0);
+ glReadBuffer(GL_COLOR_ATTACHMENT0);
+
+ for (int i=1; i < num_iter+1 && (current_dim[0] > 1 && current_dim[1] > 1); i++) {
+
+ /* calculate next viewport size */
+ current_dim[0] /= 2;
+ current_dim[1] /= 2;
+
+ /* ensure that the viewport size is always at least 1x1 */
+ CLAMP_MIN(current_dim[0], 1);
+ CLAMP_MIN(current_dim[1], 1);
+
+ glViewport(0, 0, current_dim[0], current_dim[1]);
+
+ /* bind next level for rendering but first restrict fetches only to previous level */
+ 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, i-1);
+ GPU_texture_unbind(tex);
- GPU_shader_unbind();
+ glFramebufferTexture(GL_FRAMEBUFFER, attachment, GPU_texture_opengl_bindcode(tex), i);
+
+ callback(userData, i);
+ }
+
+ glFramebufferTexture(GL_FRAMEBUFFER, attachment, 0, 0);
+
+ /* reset mipmap level range for the depth image */
+ GPU_texture_bind(tex, 0);
+ glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, num_iter);
+ GPU_texture_unbind(tex);
}
/* GPUOffScreen */
@@ -464,12 +614,7 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_
}
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 ||
+ if (!GLEW_ARB_texture_multisample ||
/* This is required when blitting from a multi-sampled buffers,
* even though we're not scaling. */
!GLEW_EXT_framebuffer_multisample_blit_scaled)
@@ -484,18 +629,18 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_
return NULL;
}
- if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0, err_out)) {
+ if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0, 0)) {
GPU_offscreen_free(ofs);
return NULL;
}
- ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, GPU_HDR_NONE, samples, err_out);
+ ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, samples, err_out);
if (!ofs->color) {
GPU_offscreen_free(ofs);
return NULL;
}
- if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0, err_out)) {
+ if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0, 0)) {
GPU_offscreen_free(ofs);
return NULL;
}
@@ -569,37 +714,37 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels)
#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,
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, ofs->color->fb->object);
+ glFramebufferTexture2D(
+ GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + ofs->color->fb_attachment,
GL_TEXTURE_2D_MULTISAMPLE, ofs->color->bindcode, 0);
- status = glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT);
- if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+ status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
goto finally;
}
#endif
/* 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) {
+ 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);
+ glBindFramebuffer(GL_FRAMEBUFFER, ofs->color->fb->object);
#undef USE_FBO_CTX_SWITCH
#endif
@@ -610,10 +755,8 @@ finally:
glDeleteTextures(1, &tex_blit);
}
if (fbo_blit) {
- glDeleteFramebuffersEXT(1, &fbo_blit);
+ glDeleteFramebuffers(1, &fbo_blit);
}
-
- GPU_ASSERT_NO_GL_ERRORS("Read Multi-Sample Pixels");
}
else {
glReadPixels(0, 0, w, h, GL_RGBA, type, pixels);
@@ -635,3 +778,12 @@ int GPU_offscreen_color_texture(const GPUOffScreen *ofs)
return GPU_texture_opengl_bindcode(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;
+}
diff --git a/source/blender/gpu/intern/gpu_immediate.c b/source/blender/gpu/intern/gpu_immediate.c
new file mode 100644
index 00000000000..5f22b7f9279
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_immediate.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) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Mike Erwin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "UI_resources.h"
+#include "BLI_utildefines.h"
+
+#include "gpu_shader_private.h"
+
+void immBindBuiltinProgram(GPUBuiltinShader shader_id)
+{
+ GPUShader *shader = GPU_shader_get_builtin_shader(shader_id);
+ immBindProgram(shader->program, shader->interface);
+}
+
+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)
+{
+ unsigned char 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..a4e54d15034
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_immediate_util.c
@@ -0,0 +1,344 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 source/blender/gpu/intern/gpu_immediate_util.c
+ * \ingroup gpu
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "GPU_basic_shader.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+
+/**
+ * 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(unsigned int x)
+{
+ immUniformColor3ub(((x) & 0xFF),
+ (((x) >> 8) & 0xFF),
+ (((x) >> 16) & 0xFF));
+}
+
+static void imm_draw_circle(Gwn_PrimType prim_type, const uint shdr_pos, float x, float y, float rad, int nsegments)
+{
+ immBegin(prim_type, nsegments);
+ for (int i = 0; i < nsegments; ++i) {
+ const float angle = 2 * M_PI * ((float)i / (float)nsegments);
+ immVertex2f(shdr_pos, x + rad * cosf(angle), y + rad * 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(uint shdr_pos, float x, float y, float rad, int nsegments)
+{
+ imm_draw_circle(GWN_PRIM_LINE_LOOP, shdr_pos, x, y, 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(uint shdr_pos, float x, float y, float rad, int nsegments)
+{
+ imm_draw_circle(GWN_PRIM_TRI_FAN, shdr_pos, x, y, rad, nsegments);
+}
+
+/**
+ * \note We could have `imm_draw_lined_disk_partial` but currently there is no need.
+ */
+static void imm_draw_disk_partial(
+ Gwn_PrimType prim_type, unsigned pos, float x, float y,
+ float rad_inner, float rad_outer, int nsegments, float start, float sweep)
+{
+ /* shift & reverse angle, increase 'nsegments' to match gluPartialDisk */
+ const float angle_start = -(DEG2RADF(start)) + (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(
+ unsigned pos, float x, float y,
+ float rad_inner, float rad_outer, int nsegments, float start, float sweep)
+{
+ imm_draw_disk_partial(GWN_PRIM_TRI_STRIP, pos, x, y, rad_inner, rad_outer, nsegments, start, sweep);
+}
+
+static void imm_draw_circle_3D(
+ Gwn_PrimType prim_type, unsigned pos, float x, float y,
+ float rad, int nsegments)
+{
+ immBegin(prim_type, nsegments);
+ for (int i = 0; i < nsegments; ++i) {
+ float angle = 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(unsigned pos, float x, float y, float rad, int nsegments)
+{
+ imm_draw_circle_3D(GWN_PRIM_LINE_LOOP, pos, x, y, rad, nsegments);
+}
+
+void imm_draw_circle_fill_3d(unsigned pos, float x, float y, float rad, int nsegments)
+{
+ imm_draw_circle_3D(GWN_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_line_box(unsigned pos, float x1, float y1, float x2, float y2)
+{
+ immBegin(GWN_PRIM_LINE_LOOP, 4);
+ immVertex2f(pos, x1, y1);
+ immVertex2f(pos, x1, y2);
+ immVertex2f(pos, x2, y2);
+ immVertex2f(pos, x2, y1);
+ immEnd();
+}
+
+void imm_draw_line_box_3d(unsigned pos, float x1, float y1, float x2, float y2)
+{
+ /* use this version when Gwn_VertFormat has a vec3 position */
+ immBegin(GWN_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_checker_box(float x1, float y1, float x2, float y2)
+{
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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();
+}
+
+/**
+* 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(
+ unsigned int pos, unsigned int nor, float base, float top, float height, int slices, int stacks)
+{
+ immBegin(GWN_PRIM_TRIS, 6 * slices * stacks);
+ for (int i = 0; i < slices; ++i) {
+ const float angle1 = 2 * M_PI * ((float)i / (float)slices);
+ const float angle2 = 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 */
+ immAttrib3fv(nor, n2);
+ immVertex3fv(pos, v1);
+ immVertex3fv(pos, v2);
+ immAttrib3fv(nor, n1);
+ immVertex3fv(pos, v3);
+
+ /* second tri */
+ immVertex3fv(pos, v3);
+ immVertex3fv(pos, v4);
+ immAttrib3fv(nor, n2);
+ immVertex3fv(pos, v1);
+ }
+ }
+ immEnd();
+}
+
+void imm_draw_cylinder_wire_3d(unsigned int pos, float base, float top, float height, int slices, int stacks)
+{
+ immBegin(GWN_PRIM_LINES, 6 * slices * stacks);
+ for (int i = 0; i < slices; ++i) {
+ const float angle1 = 2 * M_PI * ((float)i / (float)slices);
+ const float angle2 = 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(unsigned int pos, float base, float top, float height, int slices, int stacks)
+{
+ immBegin(GWN_PRIM_TRIS, 6 * slices * stacks);
+ for (int i = 0; i < slices; ++i) {
+ const float angle1 = 2 * M_PI * ((float)i / (float)slices);
+ const float angle2 = 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..7a6b1ff6c70 100644
--- a/source/blender/gpu/intern/gpu_init_exit.c
+++ b/source/blender/gpu/intern/gpu_init_exit.c
@@ -31,7 +31,8 @@
#include "BLI_sys_types.h"
#include "GPU_init_exit.h" /* interface */
-
+#include "GPU_immediate.h"
+#include "GPU_batch.h"
#include "BKE_global.h"
#include "intern/gpu_codegen.h"
@@ -59,14 +60,22 @@ void GPU_init(void)
if (G.debug & G_DEBUG_GPU)
gpu_debug_init();
+ gpu_batch_init();
+
+ immInit();
}
void GPU_exit(void)
{
+ immDestroy();
+
+ gpu_batch_exit();
+
if (G.debug & G_DEBUG_GPU)
gpu_debug_exit();
+
gpu_codegen_exit();
gpu_extensions_exit(); /* must come last */
diff --git a/source/blender/gpu/intern/gpu_lamp.c b/source/blender/gpu/intern/gpu_lamp.c
new file mode 100644
index 00000000000..8bf343568b1
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_lamp.c
@@ -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.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Brecht Van Lommel, Clément Foucault.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_lamp.c
+ * \ingroup gpu
+ *
+ * Manages Opengl lights.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_lamp_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_group.h"
+
+#include "GPU_framebuffer.h"
+#include "GPU_glew.h"
+#include "GPU_lamp.h"
+#include "GPU_material.h"
+#include "GPU_shader.h"
+#include "GPU_texture.h"
+
+#include "gpu_lamp_private.h"
+
+bool GPU_lamp_override_visible(GPULamp *lamp, SceneRenderLayer *srl, Material *ma)
+{
+ 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;
+}
+
+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;
+ }
+}
+
+static GPUTexture *gpu_lamp_create_vsm_shadow_map(int size)
+{
+ return GPU_texture_create_2D_custom(size, size, 2, GPU_RG32F, NULL, NULL);
+}
+
+LampEngineData *GPU_lamp_engine_data_get(Scene *scene, Object *ob, Object *par, struct RenderEngineType *re)
+{
+ GPULamp *lamp;
+ LinkData *link;
+
+ for (link = ob->gpulamp.first; link; link = link->next) {
+ lamp = (GPULamp *)link->data;
+
+ if ((lamp->par == par) && (lamp->scene == scene) && (lamp->re == re))
+ return &lamp->data;
+ }
+
+ lamp = MEM_callocN(sizeof(GPULamp), "GPULamp");
+
+ link = MEM_callocN(sizeof(LinkData), "GPULampLink");
+ link->data = lamp;
+ BLI_addtail(&ob->gpulamp, link);
+
+ lamp->scene = scene;
+ lamp->ob = ob;
+ lamp->par = par;
+ lamp->la = ob->data;
+ lamp->re = re;
+
+ return &lamp->data;
+}
+
+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;
+ }
+
+ GPU_texture_bind(lamp->depthtex, 0);
+ GPU_texture_compare_mode(lamp->depthtex, true);
+ GPU_texture_unbind(lamp->depthtex);
+
+ if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->depthtex, 0, 0)) {
+ gpu_lamp_shadow_free(lamp);
+ return lamp;
+ }
+
+ /* Shadow color map */
+ lamp->tex = gpu_lamp_create_vsm_shadow_map(lamp->size);
+ if (!lamp->tex) {
+ gpu_lamp_shadow_free(lamp);
+ return lamp;
+ }
+
+ if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, 0)) {
+ 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_lamp_create_vsm_shadow_map(lamp->size * 0.5);
+ if (!lamp->blurtex) {
+ gpu_lamp_shadow_free(lamp);
+ return lamp;
+ }
+
+ if (!GPU_framebuffer_texture_attach(lamp->blurfb, lamp->blurtex, 0, 0)) {
+ 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;
+ }
+
+ GPU_texture_bind(lamp->tex, 0);
+ GPU_texture_compare_mode(lamp->tex, true);
+ GPU_texture_unbind(lamp->tex);
+
+ if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, 0)) {
+ 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_engine_data_free(LampEngineData *led)
+{
+ for (int i = 0; i < MAX_LAMP_DATA; ++i) {
+ if (led->storage[i]) {
+ MEM_freeN(led->storage[i]);
+ led->storage[i] = NULL;
+ }
+ }
+}
+
+void GPU_lamp_free(Object *ob)
+{
+ GPULamp *lamp;
+ LinkData *link;
+
+ for (link = ob->gpulamp.first; link; link = link->next) {
+ lamp = link->data;
+
+ gpu_lamp_shadow_free(lamp);
+ GPU_lamp_engine_data_free(&lamp->data);
+
+ 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;
+}
diff --git a/source/blender/gpu/intern/gpu_lamp_private.h b/source/blender/gpu/intern/gpu_lamp_private.h
new file mode 100644
index 00000000000..f227ce74e7e
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_lamp_private.h
@@ -0,0 +1,84 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Brecht Van Lommel, Clément Foucault.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file gpu_lamp_private.h
+ * \ingroup gpu
+ */
+
+#ifndef __GPU_LAMP_PRIVATE_H__
+#define __GPU_LAMP_PRIVATE_H__
+
+#include "BLI_sys_types.h" /* for bool */
+
+struct GPULamp {
+ Scene *scene;
+ Object *ob;
+ Object *par;
+ Lamp *la;
+ struct RenderEngineType *re;
+
+ /* Old Viewport (pre-2.8) */
+ int type, mode, lay, hide;
+
+ float dynenergy, dyncol[3];
+ float energy, col[3];
+
+ float co[3], vec[3];
+ float dynco[3], dynvec[3];
+ float obmat[4][4];
+ float imat[4][4];
+ float dynimat[4][4];
+
+ 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];
+
+ float bias, d, clipend;
+ int size;
+
+ 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;
+
+ /* New viewport */
+ struct LampEngineData data;
+};
+
+#endif /* __GPU_LAMP_PRIVATE_H__ */
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index ed9718f1a17..f62c599a9b6 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -60,11 +60,14 @@
#include "GPU_extensions.h"
#include "GPU_framebuffer.h"
+#include "GPU_lamp.h"
#include "GPU_material.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
+#include "GPU_uniformbuffer.h"
#include "gpu_codegen.h"
+#include "gpu_lamp_private.h"
#ifdef WITH_OPENSUBDIV
# include "BKE_DerivedMesh.h"
@@ -92,12 +95,15 @@ static struct GPUWorld {
} GPUWorld;
struct GPUMaterial {
- Scene *scene;
+ Scene *scene; /* DEPRECATED was only usefull 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;
+ int type; /* DEPRECATED */
+
+ const void *engine_type; /* attached engine type */
+ int options; /* to identify shader variations (shadow, probe, world background...) */
/* for creating the material */
ListBase nodes;
@@ -122,54 +128,13 @@ struct GPUMaterial {
int partvel;
int partangvel;
+ int objectinfoloc;
+
ListBase lamps;
bool bound;
bool is_opensubdiv;
-};
-
-struct GPULamp {
- Scene *scene;
- Object *ob;
- Object *par;
- Lamp *la;
-
- int type, mode, lay, hide;
-
- float dynenergy, dyncol[3];
- float energy, col[3];
-
- float co[3], vec[3];
- float dynco[3], dynvec[3];
- float obmat[4][4];
- float imat[4][4];
- float dynimat[4][4];
-
- 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];
-
- float bias, d, clipend;
- int size;
-
- 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;
+ GPUUniformBuffer *ubo; /* UBOs for shader uniforms. */
};
/* Forward declaration so shade_light_textures() can use this, while still keeping the code somewhat organized */
@@ -225,7 +190,7 @@ static void gpu_material_set_attrib_id(GPUMaterial *material)
attribs->totlayer = b;
}
-static int GPU_material_construct_end(GPUMaterial *material, const char *passname)
+static int gpu_material_construct_end(GPUMaterial *material, const char *passname)
{
if (material->outlink) {
GPUNodeLink *outlink = material->outlink;
@@ -268,6 +233,8 @@ static int GPU_material_construct_end(GPUMaterial *material, const char *passnam
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;
}
else {
@@ -285,21 +252,10 @@ void GPU_material_free(ListBase *gpumaterial)
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);
- }
- }
+ if (material->ubo != NULL) {
+ GPU_uniformbuffer_free(material->ubo);
}
-
+
BLI_freelistN(&material->lamps);
MEM_freeN(material);
@@ -308,16 +264,6 @@ void GPU_material_free(ListBase *gpumaterial)
BLI_freelistN(gpumaterial);
}
-bool GPU_lamp_override_visible(GPULamp *lamp, SceneRenderLayer *srl, Material *ma)
-{
- 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)
@@ -398,9 +344,14 @@ void GPU_material_bind(
}
}
+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 autobumpscale, GPUParticleInfo *pi, float object_info[3])
{
if (material->pass) {
GPUShader *shader = GPU_pass_shader(material->pass);
@@ -449,6 +400,9 @@ void GPU_material_bind_uniforms(
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);
+ }
}
}
@@ -476,6 +430,34 @@ GPUMatType GPU_Material_get_type(GPUMaterial *material)
return material->type;
}
+GPUPass *GPU_material_get_pass(GPUMaterial *material)
+{
+ return material->pass;
+}
+
+GPUUniformBuffer *GPU_material_get_uniform_buffer(GPUMaterial *material)
+{
+ return material->ubo;
+}
+
+/**
+ * Create dynamic UBO from parameters
+ * \param ListBase of BLI_genericNodeN(GPUInput)
+ */
+void GPU_material_create_uniform_buffer(GPUMaterial *material, ListBase *inputs)
+{
+ material->ubo = GPU_uniformbuffer_dynamic_create(inputs, NULL);
+}
+
+void GPU_material_uniform_buffer_tag_dirty(ListBase *gpumaterials)
+{
+ for (LinkData *link = gpumaterials->first; link; link = link->next) {
+ GPUMaterial *material = link->data;
+ if (material->ubo != NULL) {
+ GPU_uniformbuffer_tag_dirty(material->ubo);
+ }
+ }
+}
void GPU_material_vertex_attributes(GPUMaterial *material, GPUVertexAttribs *attribs)
{
@@ -609,7 +591,7 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode
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_SPOTSIZE, lamp->ob),
+ GPU_dynamic_uniform(&lamp->spotbl, GPU_DYNAMIC_LAMP_SPOTBLEND, lamp->ob),
inpr, visifac, &visifac);
}
@@ -804,7 +786,7 @@ static void shade_light_textures(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **
for (int i = 0; i < MAX_MTEX; ++i) {
MTex *mtex = lamp->la->mtex[i];
- if (mtex && mtex->tex->type & TEX_IMAGE && mtex->tex->ima) {
+ if (mtex && mtex->tex && (mtex->tex->type & TEX_IMAGE) && mtex->tex->ima) {
mat->dynproperty |= DYN_LAMP_PERSMAT;
float one = 1.0f;
@@ -937,14 +919,12 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la
}
add_user_list(&mat->lamps, lamp);
- add_user_list(&lamp->materials, shi->gpumat->ma);
return;
}
}
}
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
@@ -1011,7 +991,6 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la
}
add_user_list(&mat->lamps, lamp);
- add_user_list(&lamp->materials, shi->gpumat->ma);
}
static void material_lights(GPUShadeInput *shi, GPUShadeResult *shr)
@@ -1891,7 +1870,7 @@ GPUMaterial *GPU_material_matcap(Scene *scene, Material *ma, bool use_opensubdiv
GPU_material_output_link(mat, outlink);
- GPU_material_construct_end(mat, "matcap_pass");
+ gpu_material_construct_end(mat, "matcap_pass");
/* 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
@@ -2044,7 +2023,7 @@ static void do_world_tex(GPUShadeInput *shi, struct World *wo, GPUNodeLink **hor
}
}
-static void GPU_material_old_world(struct GPUMaterial *mat, struct World *wo)
+static void gpu_material_old_world(struct GPUMaterial *mat, struct World *wo)
{
GPUShadeInput shi;
GPUShadeResult shr;
@@ -2112,17 +2091,18 @@ GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo)
mat->type = GPU_MATERIAL_TYPE_WORLD;
/* create nodes */
- if (BKE_scene_use_new_shading_nodes(scene) && wo->nodetree && wo->use_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);
+ gpu_material_old_world(mat, wo);
}
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);
+ gpu_material_construct_end(mat, wo->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
@@ -2135,6 +2115,64 @@ GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo)
return mat;
}
+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->engine_type == engine_type &&
+ current_material->options == options)
+ {
+ return current_material;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * TODO: This is supposed to replace GPU_material_from_blender/_world in the future
+ *
+ * \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)
+{
+ GPUMaterial *mat;
+ GPUNodeLink *outlink;
+ LinkData *link;
+
+ /* Caller must re-use materials. */
+ BLI_assert(GPU_material_from_nodetree_find(gpumaterials, engine_type, options) == NULL);
+
+ /* allocate material */
+ mat = GPU_material_construct_begin(NULL); /* TODO remove GPU_material_construct_begin */
+ mat->scene = scene;
+ mat->engine_type = engine_type;
+ mat->options = options;
+
+ ntreeGPUMaterialNodes(ntree, mat, NODE_NEWER_SHADING);
+
+ /* Let Draw manager finish the construction. */
+ if (mat->outlink) {
+ outlink = mat->outlink;
+ mat->pass = GPU_generate_pass_new(
+ mat, &mat->nodes, outlink, &mat->attribs, vert_code, geom_code, frag_lib, defines);
+ }
+
+ /* 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(gpumaterials, link);
+
+ return mat;
+}
GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, bool use_opensubdiv)
{
@@ -2188,7 +2226,7 @@ GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, bool use_open
if (mat->outlink)
GPU_link(mat, "linearrgb_to_srgb", mat->outlink, &mat->outlink);
- GPU_material_construct_end(mat, ma->id.name);
+ 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
@@ -2222,386 +2260,6 @@ void GPU_materials_free(void)
/* 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)
@@ -2643,7 +2301,6 @@ GPUNodeLink *GPU_lamp_get_data(
/* ensure shadow buffer and lamp textures will be updated */
add_user_list(&mat->lamps, lamp);
- add_user_list(&lamp->materials, mat->ma);
return visifac;
}
@@ -2720,6 +2377,7 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)
case GPU_VEC4:
case GPU_MAT3:
case GPU_MAT4:
+ case GPU_CLOSURE:
case GPU_ATTRIB:
break;
}
@@ -2748,6 +2406,7 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)
break;
case GPU_NONE:
+ case GPU_CLOSURE:
case GPU_TEX2D:
case GPU_TEXCUBE:
case GPU_SHADOW2D:
diff --git a/source/blender/gpu/intern/gpu_matrix.c b/source/blender/gpu/intern/gpu_matrix.c
new file mode 100644
index 00000000000..f03a076a9fd
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_matrix.c
@@ -0,0 +1,624 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at 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
+ */
+
+#define SUPPRESS_GENERIC_MATRIX_API
+#include "GPU_matrix.h"
+
+#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];
+ unsigned int 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 gpuMatrixReset(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 gpuPushMatrix(void)
+{
+ BLI_assert(ModelViewStack.top < MATRIX_STACK_DEPTH);
+ ModelViewStack.top++;
+ copy_m4_m4(ModelView, ModelViewStack.stack[ModelViewStack.top - 1]);
+}
+
+void gpuPopMatrix(void)
+{
+ BLI_assert(ModelViewStack.top > 0);
+ ModelViewStack.top--;
+ state.dirty = true;
+}
+
+void gpuPushProjectionMatrix(void)
+{
+ BLI_assert(ProjectionStack.top < MATRIX_STACK_DEPTH);
+ ProjectionStack.top++;
+ copy_m4_m4(Projection, ProjectionStack.stack[ProjectionStack.top - 1]);
+}
+
+void gpuPopProjectionMatrix(void)
+{
+ BLI_assert(ProjectionStack.top > 0);
+ ProjectionStack.top--;
+ state.dirty = true;
+}
+
+void gpuLoadMatrix(const float m[4][4])
+{
+ copy_m4_m4(ModelView, m);
+ CHECKMAT(ModelView3D);
+ state.dirty = true;
+}
+
+void gpuLoadIdentityProjectionMatrix(void)
+{
+ unit_m4(Projection);
+ CHECKMAT(Projection3D);
+ state.dirty = true;
+}
+
+void gpuLoadProjectionMatrix(const float m[4][4])
+{
+ copy_m4_m4(Projection, m);
+ CHECKMAT(Projection3D);
+ state.dirty = true;
+}
+
+void gpuLoadIdentity(void)
+{
+ unit_m4(ModelView);
+ state.dirty = true;
+}
+
+void gpuTranslate2f(float x, float y)
+{
+ Mat4 m;
+ unit_m4(m);
+ m[3][0] = x;
+ m[3][1] = y;
+ gpuMultMatrix(m);
+}
+
+void gpuTranslate2fv(const float vec[2])
+{
+ gpuTranslate2f(vec[0], vec[1]);
+}
+
+void gpuTranslate3f(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;
+ gpuMultMatrix(m);
+#endif
+ state.dirty = true;
+}
+
+void gpuTranslate3fv(const float vec[3])
+{
+ gpuTranslate3f(vec[0], vec[1], vec[2]);
+}
+
+void gpuScaleUniform(float factor)
+{
+ Mat4 m;
+ scale_m4_fl(m, factor);
+ gpuMultMatrix(m);
+}
+
+void gpuScale2f(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;
+ gpuMultMatrix(m);
+}
+
+void gpuScale2fv(const float vec[2])
+{
+ gpuScale2f(vec[0], vec[1]);
+}
+
+void gpuScale3f(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;
+ gpuMultMatrix(m);
+}
+
+void gpuScale3fv(const float vec[3])
+{
+ gpuScale3f(vec[0], vec[1], vec[2]);
+}
+
+void gpuMultMatrix(const float m[4][4])
+{
+ mul_m4_m4_post(ModelView, m);
+ CHECKMAT(ModelView);
+ state.dirty = true;
+}
+
+void gpuRotate2D(float deg)
+{
+ /* essentially RotateAxis('Z')
+ * TODO: simpler math for 2D case
+ */
+ rotate_m4(ModelView, 'Z', DEG2RADF(deg));
+}
+
+void gpuRotate3f(float deg, float x, float y, float z)
+{
+ const float axis[3] = {x, y, z};
+ gpuRotate3fv(deg, axis);
+}
+
+void gpuRotate3fv(float deg, const float axis[3])
+{
+ Mat4 m;
+ axis_angle_to_mat4(m, axis, DEG2RADF(deg));
+ gpuMultMatrix(m);
+}
+
+void gpuRotateAxis(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 gpuOrtho(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 gpuOrtho2D(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 gpuFrustum(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 gpuPerspective(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;
+ gpuFrustum(-half_width, +half_width, -half_height, +half_height, near, far);
+}
+
+void gpuLookAt(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);
+
+ gpuMultMatrix(cm);
+ gpuTranslate3f(-eyeX, -eyeY, -eyeZ);
+}
+
+void gpuProject(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 gpuUnProject(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 (*gpuGetModelViewMatrix(float m[4][4]))[4]
+{
+ if (m) {
+ copy_m4_m4(m, ModelView);
+ return m;
+ }
+ else {
+ return ModelView;
+ }
+}
+
+const float (*gpuGetProjectionMatrix(float m[4][4]))[4]
+{
+ if (m) {
+ copy_m4_m4(m, Projection);
+ return m;
+ }
+ else {
+ return Projection;
+ }
+}
+
+const float (*gpuGetModelViewProjectionMatrix(float m[4][4]))[4]
+{
+ if (m == NULL) {
+ static Mat4 temp;
+ m = temp;
+ }
+
+ mul_m4_m4m4(m, Projection, ModelView);
+ return m;
+}
+
+const float (*gpuGetNormalMatrix(float m[3][3]))[3]
+{
+ if (m == NULL) {
+ static Mat3 temp3;
+ m = temp3;
+ }
+
+ copy_m3_m4(m, (const float (*)[4])gpuGetModelViewMatrix(NULL));
+
+ invert_m3(m);
+ transpose_m3(m);
+
+ return m;
+}
+
+const float (*gpuGetNormalMatrixInverse(float m[3][3]))[3]
+{
+ if (m == NULL) {
+ static Mat3 temp3;
+ m = temp3;
+ }
+
+ gpuGetNormalMatrix(m);
+ invert_m3(m);
+
+ return m;
+}
+
+void gpuBindMatrices(const Gwn_ShaderInterface* 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 Gwn_ShaderInput *MV = GWN_shaderinterface_uniform_builtin(shaderface, GWN_UNIFORM_MODELVIEW);
+ const Gwn_ShaderInput *P = GWN_shaderinterface_uniform_builtin(shaderface, GWN_UNIFORM_PROJECTION);
+ const Gwn_ShaderInput *MVP = GWN_shaderinterface_uniform_builtin(shaderface, GWN_UNIFORM_MVP);
+
+ const Gwn_ShaderInput *N = GWN_shaderinterface_uniform_builtin(shaderface, GWN_UNIFORM_NORMAL);
+ const Gwn_ShaderInput *MV_inv = GWN_shaderinterface_uniform_builtin(shaderface, GWN_UNIFORM_MODELVIEW_INV);
+ const Gwn_ShaderInput *P_inv = GWN_shaderinterface_uniform_builtin(shaderface, GWN_UNIFORM_PROJECTION_INV);
+
+ if (MV) {
+ #if DEBUG_MATRIX_BIND
+ puts("setting MV matrix");
+ #endif
+
+ glUniformMatrix4fv(MV->location, 1, GL_FALSE, (const float *)gpuGetModelViewMatrix(NULL));
+ }
+
+ if (P) {
+ #if DEBUG_MATRIX_BIND
+ puts("setting P matrix");
+ #endif
+
+ glUniformMatrix4fv(P->location, 1, GL_FALSE, (const float *)gpuGetProjectionMatrix(NULL));
+ }
+
+ if (MVP) {
+ #if DEBUG_MATRIX_BIND
+ puts("setting MVP matrix");
+ #endif
+
+ glUniformMatrix4fv(MVP->location, 1, GL_FALSE, (const float *)gpuGetModelViewProjectionMatrix(NULL));
+ }
+
+ if (N) {
+ #if DEBUG_MATRIX_BIND
+ puts("setting normal matrix");
+ #endif
+
+ glUniformMatrix3fv(N->location, 1, GL_FALSE, (const float *)gpuGetNormalMatrix(NULL));
+ }
+
+ if (MV_inv) {
+ Mat4 m;
+ gpuGetModelViewMatrix(m);
+ invert_m4(m);
+ glUniformMatrix4fv(MV_inv->location, 1, GL_FALSE, (const float*) m);
+ }
+
+ if (P_inv) {
+ Mat4 m;
+ gpuGetProjectionMatrix(m);
+ invert_m4(m);
+ glUniformMatrix4fv(P_inv->location, 1, GL_FALSE, (const float*) m);
+ }
+
+ state.dirty = false;
+}
+
+bool gpuMatricesDirty(void)
+{
+ return state.dirty;
+}
diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c
index 58582232cd5..162a605ef3d 100644
--- a/source/blender/gpu/intern/gpu_select.c
+++ b/source/blender/gpu/intern/gpu_select.c
@@ -29,109 +29,92 @@
* Interface for accessing gpu-related methods for selection. The semantics will be
* similar to glRenderMode(GL_SELECT) since the goal is to maintain compatibility.
*/
+#include <stdlib.h>
+
#include "GPU_select.h"
#include "GPU_extensions.h"
#include "GPU_glew.h"
-
+
#include "MEM_guardedalloc.h"
#include "DNA_userdef_types.h"
#include "BLI_utildefines.h"
-/* Ad hoc number of queries to allocate to skip doing many glGenQueries */
-#define ALLOC_QUERIES 200
-
-typedef struct GPUQueryState {
+#include "gpu_select_private.h"
+
+/* Internal algorithm used */
+enum {
+ /** GL_SELECT, legacy OpenGL selection */
+ ALGO_GL_LEGACY = 1,
+ /** glBegin/EndQuery(GL_SAMPLES_PASSED... ), `gpu_select_query.c`
+ * Only sets 4th component (ID) correctly. */
+ ALGO_GL_QUERY = 2,
+ /** Read depth buffer for every drawing pass and extract depths, `gpu_select_pick.c`
+ * Only sets 4th component (ID) correctly. */
+ ALGO_GL_PICK = 3,
+};
+
+typedef struct GPUSelectState {
/* To ignore selection id calls when not initialized */
bool select_is_active;
- /* Tracks whether a query has been issued so that gpu_load_id can end the previous one */
- bool query_issued;
- /* array holding the OpenGL query identifiers */
- unsigned int *queries;
- /* array holding the id corresponding to each query */
- unsigned int *id;
- /* number of queries in *queries and *id */
- unsigned int num_of_queries;
- /* index to the next query to start */
- unsigned int active_query;
/* flag to cache user preference for occlusion based selection */
bool use_gpu_select;
- /* cache on initialization */
- unsigned int *buffer;
- /* buffer size (stores number of integers, for actual size multiply by sizeof integer)*/
- unsigned int bufsize;
/* mode of operation */
char mode;
- unsigned int index;
- int oldhits;
-} GPUQueryState;
+ /* internal algorithm for selection */
+ char algorithm;
+ /* allow GPU_select_begin/end without drawing */
+ bool use_cache;
+} GPUSelectState;
-static GPUQueryState g_query_state = {0};
+static GPUSelectState g_select_state = {0};
/**
* initialize and provide buffer for results
*/
-void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, char mode, int oldhits)
+void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, const rcti *input, char mode, int oldhits)
{
- g_query_state.select_is_active = true;
- g_query_state.query_issued = false;
- g_query_state.active_query = 0;
- g_query_state.use_gpu_select = GPU_select_query_check_active();
- g_query_state.num_of_queries = 0;
- g_query_state.bufsize = bufsize;
- g_query_state.buffer = buffer;
- g_query_state.mode = mode;
- g_query_state.index = 0;
- g_query_state.oldhits = oldhits;
-
- if (!g_query_state.use_gpu_select) {
- glSelectBuffer(bufsize, (GLuint *)buffer);
- glRenderMode(GL_SELECT);
- glInitNames();
- glPushName(-1);
+ if (mode == GPU_SELECT_NEAREST_SECOND_PASS) {
+ /* In the case hits was '-1', don't start the second pass since it's not going to give useful results.
+ * As well as buffer overflow in 'gpu_select_query_load_id'. */
+ BLI_assert(oldhits != -1);
}
- else {
- float viewport[4];
-
- g_query_state.num_of_queries = ALLOC_QUERIES;
- g_query_state.queries = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.queries), "gpu selection queries");
- 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);
+ g_select_state.select_is_active = true;
+ g_select_state.use_gpu_select = GPU_select_query_check_active();
+ g_select_state.mode = mode;
- glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_VIEWPORT_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
- * 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);
- if (!input || input->xmin == input->xmax) {
- glViewport(viewport[0], viewport[1], 24, 24);
- }
- else {
- glViewport(viewport[0], viewport[1], (int)(input->xmax - input->xmin), (int)(input->ymax - input->ymin));
- }
+ if (ELEM(g_select_state.mode, GPU_SELECT_PICK_ALL, GPU_SELECT_PICK_NEAREST)) {
+ g_select_state.algorithm = ALGO_GL_PICK;
+ }
+ else if (!g_select_state.use_gpu_select) {
+ g_select_state.algorithm = ALGO_GL_LEGACY;
+ }
+ else {
+ g_select_state.algorithm = ALGO_GL_QUERY;
+ }
- /* occlusion queries operates on fragments that pass tests and since we are interested on all
- * objects in the view frustum independently of their order, we need to disable the depth test */
- if (mode == GPU_SELECT_ALL) {
- glDisable(GL_DEPTH_TEST);
- glDepthMask(GL_FALSE);
+ switch (g_select_state.algorithm) {
+ case ALGO_GL_LEGACY:
+ {
+ g_select_state.use_cache = false;
+ glSelectBuffer(bufsize, (GLuint *)buffer);
+ glRenderMode(GL_SELECT);
+ glInitNames();
+ glPushName(-1);
+ break;
}
- else if (mode == GPU_SELECT_NEAREST_FIRST_PASS) {
- glClear(GL_DEPTH_BUFFER_BIT);
- glEnable(GL_DEPTH_TEST);
- glDepthMask(GL_TRUE);
- glDepthFunc(GL_LEQUAL);
+ case ALGO_GL_QUERY:
+ {
+ g_select_state.use_cache = false;
+ gpu_select_query_begin((unsigned int (*)[4])buffer, bufsize / 4, input, mode, oldhits);
+ break;
}
- else if (mode == GPU_SELECT_NEAREST_SECOND_PASS) {
- glEnable(GL_DEPTH_TEST);
- glDepthMask(GL_FALSE);
- glDepthFunc(GL_EQUAL);
+ default: /* ALGO_GL_PICK */
+ {
+ gpu_select_pick_begin((unsigned int (*)[4])buffer, bufsize / 4, input, mode);
+ break;
}
}
}
@@ -146,41 +129,24 @@ void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, c
bool GPU_select_load_id(unsigned int id)
{
/* if no selection mode active, ignore */
- if (!g_query_state.select_is_active)
+ if (!g_select_state.select_is_active)
return true;
- if (!g_query_state.use_gpu_select) {
- glLoadName(id);
- }
- else {
- if (g_query_state.query_issued) {
- glEndQuery(GL_SAMPLES_PASSED);
+ switch (g_select_state.algorithm) {
+ case ALGO_GL_LEGACY:
+ {
+ glLoadName(id);
+ return true;
}
- /* if required, allocate extra queries */
- if (g_query_state.active_query == g_query_state.num_of_queries) {
- g_query_state.num_of_queries += ALLOC_QUERIES;
- g_query_state.queries = MEM_reallocN(g_query_state.queries, g_query_state.num_of_queries * sizeof(*g_query_state.queries));
- g_query_state.id = MEM_reallocN(g_query_state.id, g_query_state.num_of_queries * sizeof(*g_query_state.id));
- glGenQueries(ALLOC_QUERIES, &g_query_state.queries[g_query_state.active_query]);
+ case ALGO_GL_QUERY:
+ {
+ return gpu_select_query_load_id(id);
}
-
- glBeginQuery(GL_SAMPLES_PASSED, g_query_state.queries[g_query_state.active_query]);
- g_query_state.id[g_query_state.active_query] = id;
- g_query_state.active_query++;
- g_query_state.query_issued = true;
-
- if (g_query_state.mode == GPU_SELECT_NEAREST_SECOND_PASS && g_query_state.index < g_query_state.oldhits) {
- if (g_query_state.buffer[g_query_state.index * 4 + 3] == id) {
- g_query_state.index++;
- return true;
- }
- else {
- return false;
- }
+ default: /* ALGO_GL_PICK */
+ {
+ return gpu_select_pick_load_id(id);
}
}
-
- return true;
}
/**
@@ -191,59 +157,27 @@ bool GPU_select_load_id(unsigned int id)
unsigned int GPU_select_end(void)
{
unsigned int hits = 0;
- if (!g_query_state.use_gpu_select) {
- glPopName();
- hits = glRenderMode(GL_RENDER);
- }
- else {
- int i;
- if (g_query_state.query_issued) {
- glEndQuery(GL_SAMPLES_PASSED);
+ switch (g_select_state.algorithm) {
+ case ALGO_GL_LEGACY:
+ {
+ glPopName();
+ hits = glRenderMode(GL_RENDER);
+ break;
}
-
- for (i = 0; i < g_query_state.active_query; i++) {
- unsigned int result;
- glGetQueryObjectuiv(g_query_state.queries[i], GL_QUERY_RESULT, &result);
- if (result > 0) {
- if (g_query_state.mode != GPU_SELECT_NEAREST_SECOND_PASS) {
- int maxhits = g_query_state.bufsize / 4;
-
- if (hits < maxhits) {
- g_query_state.buffer[hits * 4] = 1;
- g_query_state.buffer[hits * 4 + 1] = 0xFFFF;
- g_query_state.buffer[hits * 4 + 2] = 0xFFFF;
- g_query_state.buffer[hits * 4 + 3] = g_query_state.id[i];
-
- hits++;
- }
- else {
- hits = -1;
- break;
- }
- }
- else {
- int j;
- /* search in buffer and make selected object first */
- for (j = 0; j < g_query_state.oldhits; j++) {
- if (g_query_state.buffer[j * 4 + 3] == g_query_state.id[i]) {
- g_query_state.buffer[j * 4 + 1] = 0;
- g_query_state.buffer[j * 4 + 2] = 0;
- }
- }
- break;
- }
- }
+ case ALGO_GL_QUERY:
+ {
+ hits = gpu_select_query_end();
+ break;
+ }
+ default: /* ALGO_GL_PICK */
+ {
+ hits = gpu_select_pick_end();
+ break;
}
-
- glDeleteQueries(g_query_state.num_of_queries, g_query_state.queries);
- MEM_freeN(g_query_state.queries);
- MEM_freeN(g_query_state.id);
- glPopAttrib();
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
- g_query_state.select_is_active = false;
+ g_select_state.select_is_active = false;
return hits;
}
@@ -253,10 +187,43 @@ unsigned int 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);
+}
+/* ----------------------------------------------------------------------------
+ * Caching
+ *
+ * Support multiple begin/end's as long as they are within the initial region.
+ * Currently only used by ALGO_GL_PICK.
+ */
+
+void GPU_select_cache_begin(void)
+{
+ /* validate on GPU_select_begin, clear if not supported */
+ BLI_assert(g_select_state.use_cache == false);
+ g_select_state.use_cache = true;
+ if (g_select_state.algorithm == ALGO_GL_PICK) {
+ gpu_select_pick_cache_begin();
+ }
+}
+
+void GPU_select_cache_load_id(void)
+{
+ BLI_assert(g_select_state.use_cache == true);
+ if (g_select_state.algorithm == ALGO_GL_PICK) {
+ gpu_select_pick_cache_load_id();
+ }
+}
+
+void GPU_select_cache_end(void)
+{
+ if (g_select_state.algorithm == ALGO_GL_PICK) {
+ gpu_select_pick_cache_end();
+ }
+ g_select_state.use_cache = false;
+}
+
+bool GPU_select_is_cached(void)
+{
+ return g_select_state.use_cache && gpu_select_pick_is_cached();
}
diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c
new file mode 100644
index 00000000000..f1d311890e6
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_select_pick.c
@@ -0,0 +1,742 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_select_pick.c
+ * \ingroup gpu
+ *
+ * Custom select code for picking small regions (not efficient for large regions).
+ * `gpu_select_pick_*` API.
+ */
+#include <string.h>
+#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"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_rect.h"
+#include "BLI_listbase.h"
+#include "BLI_math_vector.h"
+#include "BLI_utildefines.h"
+
+#include "gpu_select_private.h"
+
+#include "BLI_strict_flags.h"
+
+/* #define DEBUG_PRINT */
+
+/* Alloc number for depths */
+#define ALLOC_DEPTHS 200
+
+/* Z-depth of cleared depth buffer */
+#define DEPTH_MAX 0xffffffff
+
+/* ----------------------------------------------------------------------------
+ * SubRectStride
+ */
+
+/* For looping over a sub-region of a rect, could be moved into 'rct.c'*/
+typedef struct SubRectStride {
+ unsigned int start; /* start here */
+ unsigned int span; /* read these */
+ unsigned int span_len; /* len times (read span 'len' times). */
+ unsigned int skip; /* skip those */
+} SubRectStride;
+
+/* we may want to change back to float if uint isn't well supported */
+typedef unsigned int depth_t;
+
+/**
+ * Calculate values needed for looping over a sub-region (smaller buffer within a larger buffer).
+ *
+ * 'src' must be bigger than 'dst'.
+ */
+static void rect_subregion_stride_calc(const rcti *src, const rcti *dst, SubRectStride *r_sub)
+{
+ const int src_x = BLI_rcti_size_x(src);
+ // const int src_y = BLI_rcti_size_y(src);
+ const int dst_x = BLI_rcti_size_x(dst);
+ const int dst_y = BLI_rcti_size_y(dst);
+ const int x = dst->xmin - src->xmin;
+ 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);
+ BLI_assert(x >= 0 && y >= 0);
+
+ r_sub->start = (unsigned int)((src_x * y) + x);
+ r_sub->span = (unsigned int)dst_x;
+ r_sub->span_len = (unsigned int)dst_y;
+ r_sub->skip = (unsigned int)(src_x - dst_x);
+}
+
+/**
+ * Ignore depth clearing as a change,
+ * only check if its been changed _and_ filled in (ignore clearing since XRAY does this).
+ */
+BLI_INLINE bool depth_is_filled(const depth_t *prev, const depth_t *curr)
+{
+ return (*prev != *curr) && (*curr != DEPTH_MAX);
+}
+
+/* ----------------------------------------------------------------------------
+ * DepthBufCache
+ *
+ * Result of reading glReadPixels,
+ * use for both cache and non-cached storage.
+ */
+
+/* store result of glReadPixels */
+typedef struct DepthBufCache {
+ struct DepthBufCache *next, *prev;
+ unsigned int id;
+ depth_t buf[0];
+} DepthBufCache;
+
+static DepthBufCache *depth_buf_malloc(unsigned int rect_len)
+{
+ DepthBufCache *rect = MEM_mallocN(sizeof(DepthBufCache) + sizeof(depth_t) * rect_len, __func__);
+ rect->id = SELECT_ID_NONE;
+ return rect;
+}
+
+static bool depth_buf_rect_depth_any(
+ const DepthBufCache *rect_depth,
+ unsigned int rect_len)
+{
+ const depth_t *curr = rect_depth->buf;
+ for (unsigned int i = 0; i < rect_len; i++, curr++) {
+ if (*curr != DEPTH_MAX) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool depth_buf_subrect_depth_any(
+ const DepthBufCache *rect_depth,
+ const SubRectStride *sub_rect)
+{
+ const depth_t *curr = rect_depth->buf + sub_rect->start;
+ for (unsigned int i = 0; i < sub_rect->span_len; i++) {
+ const depth_t *curr_end = curr + sub_rect->span;
+ for (; curr < curr_end; curr++, curr++) {
+ if (*curr != DEPTH_MAX) {
+ return true;
+ }
+ }
+ curr += sub_rect->skip;
+ }
+ return false;
+}
+
+static bool depth_buf_rect_depth_any_filled(
+ const DepthBufCache *rect_prev, const DepthBufCache *rect_curr,
+ unsigned int rect_len)
+{
+#if 0
+ return memcmp(rect_depth_a->buf, rect_depth_b->buf, rect_len * sizeof(depth_t)) != 0;
+#else
+ const depth_t *prev = rect_prev->buf;
+ const depth_t *curr = rect_curr->buf;
+ for (unsigned int i = 0; i < rect_len; i++, curr++, prev++) {
+ if (depth_is_filled(prev, curr)) {
+ return true;
+ }
+ }
+ return false;
+#endif
+}
+
+/**
+ * Both buffers are the same size, just check if the sub-rect contains any differences.
+ */
+static bool depth_buf_subrect_depth_any_filled(
+ const DepthBufCache *rect_src, const DepthBufCache *rect_dst,
+ const SubRectStride *sub_rect)
+{
+ /* same as above but different rect sizes */
+ const depth_t *prev = rect_src->buf + sub_rect->start;
+ const depth_t *curr = rect_dst->buf + sub_rect->start;
+ for (unsigned int i = 0; i < sub_rect->span_len; i++) {
+ const depth_t *curr_end = curr + sub_rect->span;
+ for (; curr < curr_end; prev++, curr++) {
+ if (depth_is_filled(prev, curr)) {
+ return true;
+ }
+ }
+ prev += sub_rect->skip;
+ curr += sub_rect->skip;
+ }
+ return false;
+}
+
+/* ----------------------------------------------------------------------------
+ * DepthID
+ *
+ * Internal structure for storing hits.
+ */
+
+typedef struct DepthID {
+ unsigned int id;
+ depth_t depth;
+} DepthID;
+
+static int depth_id_cmp(const void *v1, const void *v2)
+{
+ const DepthID *d1 = v1, *d2 = v2;
+ if (d1->id < d2->id) {
+ return -1;
+ }
+ else if (d1->id > d2->id) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+static int depth_cmp(const void *v1, const void *v2)
+{
+ const DepthID *d1 = v1, *d2 = v2;
+ if (d1->depth < d2->depth) {
+ return -1;
+ }
+ else if (d1->depth > d2->depth) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+/* depth sorting */
+typedef struct GPUPickState {
+ /* cache on initialization */
+ unsigned int (*buffer)[4];
+
+ /* buffer size (stores number of integers, for actual size multiply by sizeof integer)*/
+ unsigned int bufsize;
+ /* mode of operation */
+ char mode;
+
+ /* OpenGL drawing, never use when (is_cached == true). */
+ struct {
+ /* The current depth, accumulated as we draw */
+ DepthBufCache *rect_depth;
+ /* Scratch buffer, avoid allocs every time (when not caching) */
+ DepthBufCache *rect_depth_test;
+
+ /* Pass to glReadPixels (x, y, w, h) */
+ int clip_readpixels[4];
+
+ /* Set after first draw */
+ bool is_init;
+ unsigned int prev_id;
+ } gl;
+
+ /* src: data stored in 'cache' and 'gl',
+ * dst: use when cached region is smaller (where src -> dst isn't 1:1) */
+ struct {
+ rcti clip_rect;
+ unsigned int rect_len;
+ } src, dst;
+
+ /* Store cache between `GPU_select_cache_begin/end` */
+ bool use_cache;
+ bool is_cached;
+ struct {
+ /* Cleanup used for iterating over both source and destination buffers:
+ * src.clip_rect -> dst.clip_rect */
+ SubRectStride sub_rect;
+
+ /* List of DepthBufCache, sized of 'src.clip_rect' */
+ ListBase bufs;
+ } cache;
+
+ /* Pickign methods */
+ union {
+ /* GPU_SELECT_PICK_ALL */
+ struct {
+ DepthID *hits;
+ unsigned int hits_len;
+ unsigned int hits_len_alloc;
+ } all;
+
+ /* GPU_SELECT_PICK_NEAREST */
+ struct {
+ unsigned int *rect_id;
+ } nearest;
+ };
+} GPUPickState;
+
+
+static GPUPickState g_pick_state = {0};
+
+void gpu_select_pick_begin(
+ unsigned int (*buffer)[4], unsigned int bufsize,
+ const rcti *input, char mode)
+{
+ GPUPickState *ps = &g_pick_state;
+
+#ifdef DEBUG_PRINT
+ printf("%s: mode=%d, use_cache=%d, is_cache=%d\n", __func__, mode, ps->use_cache, ps->is_cached);
+#endif
+
+ ps->bufsize = bufsize;
+ ps->buffer = buffer;
+ ps->mode = mode;
+
+ const unsigned int rect_len = (unsigned int)(BLI_rcti_size_x(input) * BLI_rcti_size_y(input));
+ ps->dst.clip_rect = *input;
+ ps->dst.rect_len = rect_len;
+
+ /* Restrict OpenGL operations for when we don't have cache */
+ if (ps->is_cached == false) {
+ gpuPushAttrib(GPU_DEPTH_BUFFER_BIT | GPU_VIEWPORT_BIT);
+
+ /* disable writing to the framebuffer */
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+
+ glEnable(GL_DEPTH_TEST);
+ glDepthMask(GL_TRUE);
+
+ if (mode == GPU_SELECT_PICK_ALL) {
+ glDepthFunc(GL_ALWAYS);
+ }
+ else {
+ glDepthFunc(GL_LEQUAL);
+ }
+
+ float viewport[4];
+ glGetFloatv(GL_SCISSOR_BOX, viewport);
+
+ ps->src.clip_rect = *input;
+ ps->src.rect_len = rect_len;
+
+ ps->gl.clip_readpixels[0] = (int)viewport[0];
+ ps->gl.clip_readpixels[1] = (int)viewport[1];
+ ps->gl.clip_readpixels[2] = BLI_rcti_size_x(&ps->src.clip_rect);
+ ps->gl.clip_readpixels[3] = BLI_rcti_size_y(&ps->src.clip_rect);
+
+ glViewport(UNPACK4(ps->gl.clip_readpixels));
+
+ /* It's possible we don't want to clear depth buffer,
+ * so existing elements are masked by current z-buffer. */
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ /* scratch buffer (read new values here) */
+ ps->gl.rect_depth_test = depth_buf_malloc(rect_len);
+ ps->gl.rect_depth = depth_buf_malloc(rect_len);
+
+ /* set initial 'far' value */
+#if 0
+ glReadPixels(UNPACK4(ps->gl.clip_readpixels), GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, ps->gl.rect_depth->buf);
+#else
+ for (unsigned int i = 0; i < rect_len; i++) {
+ ps->gl.rect_depth->buf[i] = DEPTH_MAX;
+ }
+#endif
+
+ ps->gl.is_init = false;
+ ps->gl.prev_id = 0;
+ }
+ else {
+ /* Using cache (ps->is_cached == true) */
+ /* src.clip_rect -> dst.clip_rect */
+ rect_subregion_stride_calc(&ps->src.clip_rect, &ps->dst.clip_rect, &ps->cache.sub_rect);
+ BLI_assert(ps->gl.rect_depth == NULL);
+ BLI_assert(ps->gl.rect_depth_test == NULL);
+ }
+
+ if (mode == GPU_SELECT_PICK_ALL) {
+ ps->all.hits = MEM_mallocN(sizeof(*ps->all.hits) * ALLOC_DEPTHS, __func__);
+ ps->all.hits_len = 0;
+ ps->all.hits_len_alloc = ALLOC_DEPTHS;
+ }
+ else {
+ /* Set to 0xff for SELECT_ID_NONE */
+ ps->nearest.rect_id = MEM_mallocN(sizeof(unsigned int) * ps->dst.rect_len, __func__);
+ memset(ps->nearest.rect_id, 0xff, sizeof(unsigned int) * ps->dst.rect_len);
+ }
+}
+
+/**
+ * Given 2x depths, we know are different - update the depth information
+ * use for both cached/uncached depth buffers.
+ */
+static void gpu_select_load_id_pass_all(const DepthBufCache *rect_curr)
+{
+ GPUPickState *ps = &g_pick_state;
+ const unsigned int id = rect_curr->id;
+ /* find the best depth for this pass and store in 'all.hits' */
+ depth_t depth_best = DEPTH_MAX;
+
+#define EVAL_TEST() \
+ if (depth_best > *curr) { \
+ depth_best = *curr; \
+ } ((void)0)
+
+ if (ps->is_cached == false) {
+ const depth_t *curr = rect_curr->buf;
+ BLI_assert(ps->src.rect_len == ps->dst.rect_len);
+ const unsigned int rect_len = ps->src.rect_len;
+ for (unsigned int i = 0; i < rect_len; i++, curr++) {
+ EVAL_TEST();
+ }
+ }
+ else {
+ /* same as above but different rect sizes */
+ const depth_t *curr = rect_curr->buf + ps->cache.sub_rect.start;
+ for (unsigned int i = 0; i < ps->cache.sub_rect.span_len; i++) {
+ const depth_t *curr_end = curr + ps->cache.sub_rect.span;
+ for (; curr < curr_end; curr++) {
+ EVAL_TEST();
+ }
+ curr += ps->cache.sub_rect.skip;
+ }
+ }
+
+#undef EVAL_TEST
+
+ /* ensure enough space */
+ if (UNLIKELY(ps->all.hits_len == ps->all.hits_len_alloc)) {
+ ps->all.hits_len_alloc += ALLOC_DEPTHS;
+ ps->all.hits = MEM_reallocN(ps->all.hits, ps->all.hits_len_alloc * sizeof(*ps->all.hits));
+ }
+ DepthID *d = &ps->all.hits[ps->all.hits_len++];
+ d->id = id;
+ d->depth = depth_best;
+}
+
+static void gpu_select_load_id_pass_nearest(const DepthBufCache *rect_prev, const DepthBufCache *rect_curr)
+{
+ GPUPickState *ps = &g_pick_state;
+ const unsigned int id = rect_curr->id;
+ /* keep track each pixels ID in 'nearest.rect_id' */
+ if (id != SELECT_ID_NONE) {
+ unsigned int *id_ptr = ps->nearest.rect_id;
+
+ /* Check against DEPTH_MAX because XRAY will clear the buffer,
+ * so previously set values will become unset.
+ * In this case just leave those id's left as-is. */
+#define EVAL_TEST() \
+ if (depth_is_filled(prev, curr)) { \
+ *id_ptr = id; \
+ } ((void)0)
+
+ if (ps->is_cached == false) {
+ const depth_t *prev = rect_prev->buf;
+ const depth_t *curr = rect_curr->buf;
+ BLI_assert(ps->src.rect_len == ps->dst.rect_len);
+ const unsigned int rect_len = ps->src.rect_len;
+ for (unsigned int i = 0; i < rect_len; i++, curr++, prev++, id_ptr++) {
+ EVAL_TEST();
+ }
+ }
+ else {
+ /* same as above but different rect sizes */
+ const depth_t *prev = rect_prev->buf + ps->cache.sub_rect.start;
+ const depth_t *curr = rect_curr->buf + ps->cache.sub_rect.start;
+ for (unsigned int i = 0; i < ps->cache.sub_rect.span_len; i++) {
+ const depth_t *curr_end = curr + ps->cache.sub_rect.span;
+ for (; curr < curr_end; prev++, curr++, id_ptr++) {
+ EVAL_TEST();
+ }
+ prev += ps->cache.sub_rect.skip;
+ curr += ps->cache.sub_rect.skip;
+ }
+ }
+
+#undef EVAL_TEST
+ }
+}
+
+
+bool gpu_select_pick_load_id(unsigned int id)
+{
+ GPUPickState *ps = &g_pick_state;
+ if (ps->gl.is_init) {
+ const unsigned int rect_len = ps->src.rect_len;
+ glReadPixels(UNPACK4(ps->gl.clip_readpixels), GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, ps->gl.rect_depth_test->buf);
+ /* perform initial check since most cases the array remains unchanged */
+
+ bool do_pass = false;
+ if (g_pick_state.mode == GPU_SELECT_PICK_ALL) {
+ if (depth_buf_rect_depth_any(ps->gl.rect_depth_test, rect_len)) {
+ ps->gl.rect_depth_test->id = ps->gl.prev_id;
+ gpu_select_load_id_pass_all(ps->gl.rect_depth_test);
+ do_pass = true;
+ }
+ }
+ else {
+ if (depth_buf_rect_depth_any_filled(ps->gl.rect_depth, ps->gl.rect_depth_test, rect_len)) {
+ ps->gl.rect_depth_test->id = ps->gl.prev_id;
+ gpu_select_load_id_pass_nearest(ps->gl.rect_depth, ps->gl.rect_depth_test);
+ do_pass = true;
+ }
+ }
+
+ if (do_pass) {
+ /* Store depth in cache */
+ if (ps->use_cache) {
+ BLI_addtail(&ps->cache.bufs, ps->gl.rect_depth);
+ ps->gl.rect_depth = depth_buf_malloc(ps->src.rect_len);
+ }
+
+ SWAP(DepthBufCache *, ps->gl.rect_depth, ps->gl.rect_depth_test);
+
+ if (g_pick_state.mode == GPU_SELECT_PICK_ALL) {
+ /* we want new depths every time */
+ glClear(GL_DEPTH_BUFFER_BIT);
+ }
+ }
+ }
+
+ ps->gl.is_init = true;
+ ps->gl.prev_id = id;
+
+ return true;
+}
+
+unsigned int gpu_select_pick_end(void)
+{
+ GPUPickState *ps = &g_pick_state;
+
+#ifdef DEBUG_PRINT
+ printf("%s\n", __func__);
+#endif
+
+ if (ps->is_cached == false) {
+ if (ps->gl.is_init) {
+ /* force finishing last pass */
+ gpu_select_pick_load_id(ps->gl.prev_id);
+ }
+
+ gpuPopAttrib();
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ }
+
+ /* assign but never free directly since it may be in cache */
+ DepthBufCache *rect_depth_final;
+
+ /* Store depth in cache */
+ if (ps->use_cache && !ps->is_cached) {
+ BLI_addtail(&ps->cache.bufs, ps->gl.rect_depth);
+ ps->gl.rect_depth = NULL;
+ rect_depth_final = ps->cache.bufs.last;
+ }
+ else if (ps->is_cached) {
+ rect_depth_final = ps->cache.bufs.last;
+ }
+ else {
+ /* common case, no cache */
+ rect_depth_final = ps->gl.rect_depth;
+ }
+
+ unsigned int maxhits = g_pick_state.bufsize;
+ DepthID *depth_data;
+ unsigned int depth_data_len = 0;
+
+ if (g_pick_state.mode == GPU_SELECT_PICK_ALL) {
+ depth_data = ps->all.hits;
+ depth_data_len = ps->all.hits_len;
+ /* move ownership */
+ ps->all.hits = NULL;
+ ps->all.hits_len = 0;
+ ps->all.hits_len_alloc = 0;
+ }
+ else {
+ /* GPU_SELECT_PICK_NEAREST */
+
+ /* Over alloc (unlikely we have as many depths as pixels) */
+ unsigned int depth_data_len_first_pass = 0;
+ depth_data = MEM_mallocN(ps->dst.rect_len * sizeof(*depth_data), __func__);
+
+ /* Partially de-duplicating copy,
+ * when contiguous ID's are found - update their closest depth.
+ * This isn't essential but means there is less data to sort. */
+
+#define EVAL_TEST(i_src, i_dst) \
+ { \
+ const unsigned int id = ps->nearest.rect_id[i_dst]; \
+ if (id != SELECT_ID_NONE) { \
+ const depth_t depth = rect_depth_final->buf[i_src]; \
+ if (depth_last == NULL || depth_last->id != id) { \
+ DepthID *d = &depth_data[depth_data_len_first_pass++]; \
+ d->id = id; \
+ d->depth = depth; \
+ } \
+ else if (depth_last->depth > depth) { \
+ depth_last->depth = depth; \
+ } \
+ } \
+ } ((void)0)
+
+ {
+ DepthID *depth_last = NULL;
+ if (ps->is_cached == false) {
+ for (unsigned int i = 0; i < ps->src.rect_len; i++) {
+ EVAL_TEST(i, i);
+ }
+ }
+ else {
+ /* same as above but different rect sizes */
+ unsigned int i_src = ps->cache.sub_rect.start, i_dst = 0;
+ for (unsigned int j = 0; j < ps->cache.sub_rect.span_len; j++) {
+ const unsigned int i_src_end = i_src + ps->cache.sub_rect.span;
+ for (; i_src < i_src_end; i_src++, i_dst++) {
+ EVAL_TEST(i_src, i_dst);
+ }
+ i_src += ps->cache.sub_rect.skip;
+ }
+ }
+ }
+
+#undef EVAL_TEST
+
+ qsort(depth_data, depth_data_len_first_pass, sizeof(DepthID), depth_id_cmp);
+
+ /* Sort by ID's then keep the best depth for each ID */
+ depth_data_len = 0;
+ {
+ DepthID *depth_last = NULL;
+ for (unsigned int i = 0; i < depth_data_len_first_pass; i++) {
+ if (depth_last == NULL || depth_last->id != depth_data[i].id) {
+ depth_last = &depth_data[depth_data_len++];
+ *depth_last = depth_data[i];
+ }
+ else if (depth_last->depth > depth_data[i].depth) {
+ depth_last->depth = depth_data[i].depth;
+ }
+ }
+ }
+ }
+
+ /* Finally sort each unique (id, depth) pair by depth
+ * so the final hit-list is sorted by depth (nearest first) */
+ unsigned int hits = 0;
+
+ if (depth_data_len > maxhits) {
+ hits = (unsigned int)-1;
+ }
+ else {
+ /* leave sorting up to the caller */
+ qsort(depth_data, depth_data_len, sizeof(DepthID), depth_cmp);
+
+ for (unsigned int i = 0; i < depth_data_len; i++) {
+#ifdef DEBUG_PRINT
+ printf(" hit: %u: depth %u\n", depth_data[i].id, depth_data[i].depth);
+#endif
+ /* first 3 are dummy values */
+ g_pick_state.buffer[hits][0] = 1;
+ g_pick_state.buffer[hits][1] = 0x0; /* depth_data[i].depth; */ /* unused */
+ g_pick_state.buffer[hits][2] = 0x0; /* z-far is currently never used. */
+ g_pick_state.buffer[hits][3] = depth_data[i].id;
+ hits++;
+ }
+ BLI_assert(hits < maxhits);
+ }
+
+ MEM_freeN(depth_data);
+
+ MEM_SAFE_FREE(ps->gl.rect_depth);
+ MEM_SAFE_FREE(ps->gl.rect_depth_test);
+
+ if (g_pick_state.mode == GPU_SELECT_PICK_ALL) {
+ /* 'hits' already freed as 'depth_data' */
+ }
+ else {
+ MEM_freeN(ps->nearest.rect_id);
+ ps->nearest.rect_id = NULL;
+ }
+
+ if (ps->use_cache) {
+ ps->is_cached = true;
+ }
+
+ return hits;
+}
+
+/* ----------------------------------------------------------------------------
+ * Caching
+ *
+ * Support multiple begin/end's reusing depth buffers.
+ */
+
+void gpu_select_pick_cache_begin(void)
+{
+ BLI_assert(g_pick_state.use_cache == false);
+#ifdef DEBUG_PRINT
+ printf("%s\n", __func__);
+#endif
+ g_pick_state.use_cache = true;
+ g_pick_state.is_cached = false;
+}
+
+void gpu_select_pick_cache_end(void)
+{
+#ifdef DEBUG_PRINT
+ printf("%s: with %d buffers\n", __func__, BLI_listbase_count(&g_pick_state.cache.bufs));
+#endif
+ g_pick_state.use_cache = false;
+ g_pick_state.is_cached = false;
+
+ BLI_freelistN(&g_pick_state.cache.bufs);
+}
+
+/* is drawing needed? */
+bool gpu_select_pick_is_cached(void)
+{
+ return g_pick_state.is_cached;
+}
+
+void gpu_select_pick_cache_load_id(void)
+{
+ BLI_assert(g_pick_state.is_cached == true);
+ GPUPickState *ps = &g_pick_state;
+#ifdef DEBUG_PRINT
+ printf("%s (building depth from cache)\n", __func__);
+#endif
+ for (DepthBufCache *rect_depth = ps->cache.bufs.first; rect_depth; rect_depth = rect_depth->next) {
+ if (rect_depth->next != NULL) {
+ /* we know the buffers differ, but this sub-region may not.
+ * double check before adding an id-pass */
+ if (g_pick_state.mode == GPU_SELECT_PICK_ALL) {
+ if (depth_buf_subrect_depth_any(rect_depth->next, &ps->cache.sub_rect)) {
+ gpu_select_load_id_pass_all(rect_depth->next);
+ }
+ }
+ else {
+ if (depth_buf_subrect_depth_any_filled(rect_depth, rect_depth->next, &ps->cache.sub_rect)) {
+ gpu_select_load_id_pass_nearest(rect_depth, rect_depth->next);
+ }
+ }
+ }
+ }
+}
diff --git a/source/blender/gpu/intern/gpu_select_private.h b/source/blender/gpu/intern/gpu_select_private.h
new file mode 100644
index 00000000000..8935bd7b253
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_select_private.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.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Antony Riakiotakis.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_select_private.h
+ * \ingroup gpu
+ *
+ * Selection implementations.
+ */
+
+#ifndef __GPU_SELECT_PRIVATE_H__
+#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_cache_begin(void);
+void gpu_select_pick_cache_end(void);
+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);
+
+
+#define SELECT_ID_NONE ((unsigned int)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
new file mode 100644
index 00000000000..e3bd20f3776
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_select_sample_query.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) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Antony Riakiotakis.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_select_sample_query.c
+ * \ingroup gpu
+ *
+ * Interface for accessing gpu-related methods for selection. The semantics will be
+ * similar to glRenderMode(GL_SELECT) since the goal is to maintain compatibility.
+ */
+
+#include <stdlib.h>
+
+#include "GPU_immediate.h"
+#include "GPU_draw.h"
+#include "GPU_select.h"
+#include "GPU_extensions.h"
+#include "GPU_glew.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_rect.h"
+
+#include "BLI_utildefines.h"
+
+#include "gpu_select_private.h"
+
+
+/* Ad hoc number of queries to allocate to skip doing many glGenQueries */
+#define ALLOC_QUERIES 200
+
+typedef struct GPUQueryState {
+ /* Tracks whether a query has been issued so that gpu_load_id can end the previous one */
+ bool query_issued;
+ /* array holding the OpenGL query identifiers */
+ unsigned int *queries;
+ /* array holding the id corresponding to each query */
+ unsigned int *id;
+ /* number of queries in *queries and *id */
+ unsigned int num_of_queries;
+ /* index to the next query to start */
+ unsigned int active_query;
+ /* cache on initialization */
+ unsigned int (*buffer)[4];
+ /* buffer size (stores number of integers, for actual size multiply by sizeof integer)*/
+ unsigned int bufsize;
+ /* mode of operation */
+ char mode;
+ unsigned int index;
+ int oldhits;
+} GPUQueryState;
+
+static GPUQueryState g_query_state = {0};
+
+
+void gpu_select_query_begin(
+ unsigned int (*buffer)[4], unsigned int bufsize,
+ const rcti *input, char mode,
+ int oldhits)
+{
+ float viewport[4];
+
+ g_query_state.query_issued = false;
+ g_query_state.active_query = 0;
+ g_query_state.num_of_queries = 0;
+ g_query_state.bufsize = bufsize;
+ g_query_state.buffer = buffer;
+ g_query_state.mode = mode;
+ g_query_state.index = 0;
+ g_query_state.oldhits = oldhits;
+
+ g_query_state.num_of_queries = ALLOC_QUERIES;
+
+ g_query_state.queries = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.queries), "gpu selection queries");
+ 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);
+
+ gpuPushAttrib(GPU_DEPTH_BUFFER_BIT | GPU_VIEWPORT_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
+ * 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);
+ 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
+ * objects in the view frustum independently of their order, we need to disable the depth test */
+ if (mode == GPU_SELECT_ALL) {
+ glDisable(GL_DEPTH_TEST);
+ glDepthMask(GL_FALSE);
+ }
+ else if (mode == GPU_SELECT_NEAREST_FIRST_PASS) {
+ glClear(GL_DEPTH_BUFFER_BIT);
+ glEnable(GL_DEPTH_TEST);
+ glDepthMask(GL_TRUE);
+ glDepthFunc(GL_LEQUAL);
+ }
+ else if (mode == GPU_SELECT_NEAREST_SECOND_PASS) {
+ glEnable(GL_DEPTH_TEST);
+ glDepthMask(GL_FALSE);
+ glDepthFunc(GL_EQUAL);
+ }
+}
+
+bool gpu_select_query_load_id(unsigned int id)
+{
+ if (g_query_state.query_issued) {
+ glEndQuery(GL_SAMPLES_PASSED);
+ }
+ /* if required, allocate extra queries */
+ if (g_query_state.active_query == g_query_state.num_of_queries) {
+ g_query_state.num_of_queries += ALLOC_QUERIES;
+ g_query_state.queries = MEM_reallocN(g_query_state.queries, g_query_state.num_of_queries * sizeof(*g_query_state.queries));
+ g_query_state.id = MEM_reallocN(g_query_state.id, g_query_state.num_of_queries * sizeof(*g_query_state.id));
+ glGenQueries(ALLOC_QUERIES, &g_query_state.queries[g_query_state.active_query]);
+ }
+
+ glBeginQuery(GL_SAMPLES_PASSED, g_query_state.queries[g_query_state.active_query]);
+ g_query_state.id[g_query_state.active_query] = id;
+ g_query_state.active_query++;
+ g_query_state.query_issued = true;
+
+ if (g_query_state.mode == GPU_SELECT_NEAREST_SECOND_PASS) {
+ /* Second pass should never run if first pass fails, can read past 'bufsize' in this case. */
+ BLI_assert(g_query_state.oldhits != -1);
+ if (g_query_state.index < g_query_state.oldhits) {
+ if (g_query_state.buffer[g_query_state.index][3] == id) {
+ g_query_state.index++;
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+unsigned int gpu_select_query_end(void)
+{
+ int i;
+
+ unsigned int hits = 0;
+ const unsigned int maxhits = g_query_state.bufsize;
+
+ if (g_query_state.query_issued) {
+ glEndQuery(GL_SAMPLES_PASSED);
+ }
+
+ for (i = 0; i < g_query_state.active_query; i++) {
+ unsigned int result;
+ glGetQueryObjectuiv(g_query_state.queries[i], GL_QUERY_RESULT, &result);
+ if (result > 0) {
+ if (g_query_state.mode != GPU_SELECT_NEAREST_SECOND_PASS) {
+
+ if (hits < maxhits) {
+ g_query_state.buffer[hits][0] = 1;
+ g_query_state.buffer[hits][1] = 0xFFFF;
+ g_query_state.buffer[hits][2] = 0xFFFF;
+ g_query_state.buffer[hits][3] = g_query_state.id[i];
+
+ hits++;
+ }
+ else {
+ hits = -1;
+ break;
+ }
+ }
+ else {
+ int j;
+ /* search in buffer and make selected object first */
+ for (j = 0; j < g_query_state.oldhits; j++) {
+ if (g_query_state.buffer[j][3] == g_query_state.id[i]) {
+ g_query_state.buffer[j][1] = 0;
+ g_query_state.buffer[j][2] = 0;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ glDeleteQueries(g_query_state.num_of_queries, g_query_state.queries);
+ MEM_freeN(g_query_state.queries);
+ MEM_freeN(g_query_state.id);
+ 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 df1213b01e2..e67e5bc933d 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -34,24 +34,112 @@
#include "BKE_global.h"
#include "GPU_compositing.h"
-#include "GPU_debug.h"
#include "GPU_extensions.h"
-#include "GPU_glew.h"
+#include "GPU_matrix.h"
#include "GPU_shader.h"
#include "GPU_texture.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_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_2D_vert_glsl[];
+extern char datatoc_gpu_shader_2D_flat_color_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_image_vert_glsl[];
+
+extern char datatoc_gpu_shader_3D_image_vert_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_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_rect_modulate_alpha_frag_glsl[];
+extern char datatoc_gpu_shader_image_depth_linear_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_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_bone_envelope_solid_vert_glsl[];
+extern char datatoc_gpu_shader_instance_bone_envelope_wire_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_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_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_frag_glsl[];
+extern char datatoc_gpu_shader_keyframe_diamond_vert_glsl[];
+extern char datatoc_gpu_shader_keyframe_diamond_frag_glsl[];
+
+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_fullscreen_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[];
@@ -61,40 +149,25 @@ 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;
- /* 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) */
+/* cache of built-in shaders (each is created on first use) */
+static GPUShader *builtin_shaders[GPU_NUM_BUILTIN_SHADERS] = { NULL };
- GLuint vertex; /* handle for vertex shader */
- GLuint geometry; /* handle for geometry shader */
- GLuint fragment; /* handle for fragment shader */
+/* cache for shader fx. Those can exist in combinations so store them here */
+static GPUShader *fx_shaders[MAX_FX_SHADERS * 2] = { NULL };
- int totattrib; /* total number of attributes */
- int uniforms; /* required uniforms */
-
- void *uniform_interface; /* cached uniform interface for shader. Data depends on shader */
-};
+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) {
@@ -117,71 +190,19 @@ 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_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],
@@ -204,10 +225,6 @@ static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH],
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.
@@ -240,19 +257,13 @@ 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)
+ const char *defines)
{
return GPU_shader_create_ex(vertexcode,
fragcode,
geocode,
libcode,
defines,
- input,
- output,
- number,
GPU_SHADER_FLAGS_NONE);
}
@@ -261,16 +272,9 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode,
const char *geocode,
const char *libcode,
const char *defines,
- int input,
- int output,
- int number,
const int flags)
{
#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);
@@ -283,9 +287,6 @@ 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");
if (vertexcode)
@@ -310,7 +311,7 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode,
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_extensions(standard_extensions);
if (vertexcode) {
const char *source[5];
@@ -402,20 +403,12 @@ 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);
}
#endif
@@ -433,16 +426,26 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode,
return NULL;
}
+ shader->interface = GWN_shaderinterface_create(shader->program);
+
#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 */
+ if (use_opensubdiv) {
+ if (GLEW_VERSION_4_1) {
+ glProgramUniform1i(shader->program,
+ GWN_shaderinterface_uniform(shader->interface, "FVarDataOffsetBuffer")->location,
+ 30); /* GL_TEXTURE30 */
+
+ glProgramUniform1i(shader->program,
+ GWN_shaderinterface_uniform(shader->interface, "FVarDataBuffer")->location,
+ 31); /* GL_TEXTURE31 */
+ }
+ else {
+ glUseProgram(shader->program);
+ glUniform1i(GWN_shaderinterface_uniform(shader->interface, "FVarDataOffsetBuffer")->location, 30);
+ glUniform1i(GWN_shaderinterface_uniform(shader->interface, "FVarDataBuffer")->location, 31);
+ glUseProgram(0);
+ }
}
#endif
@@ -451,20 +454,21 @@ 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");
+ gpuBindMatrices(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");
}
void GPU_shader_free(GPUShader *shader)
{
+ BLI_assert(shader);
+
if (shader->vertex)
glDeleteShader(shader->vertex);
if (shader->geometry)
@@ -477,20 +481,43 @@ void GPU_shader_free(GPUShader *shader)
if (shader->uniform_interface)
MEM_freeN(shader->uniform_interface);
+ if (shader->interface)
+ GWN_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 Gwn_ShaderInput *uniform = GWN_shaderinterface_uniform(shader->interface, name);
+ return uniform ? uniform->location : -1;
}
-void *GPU_shader_get_interface(GPUShader *shader)
+int GPU_shader_get_uniform_block(GPUShader *shader, const char *name)
+{
+ BLI_assert(shader && shader->program);
+
+ return glGetUniformBlockIndex(shader->program, name);
+}
+
+void *GPU_fx_shader_get_interface(GPUShader *shader)
{
return shader->uniform_interface;
}
-void GPU_shader_set_interface(GPUShader *shader, void *interface)
+void *GPU_shader_get_interface(GPUShader *shader)
+{
+ return shader->interface;
+}
+
+/* Clement : Temp */
+int GPU_shader_get_program(GPUShader *shader)
+{
+ return (int)shader->program;
+}
+
+void GPU_fx_shader_set_interface(GPUShader *shader, void *interface)
{
shader->uniform_interface = interface;
}
@@ -500,16 +527,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)
@@ -517,14 +540,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)
@@ -532,22 +551,22 @@ 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);
@@ -563,71 +582,223 @@ void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUText
if (location == -1)
return;
- GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Texture");
-
- arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + number);
+ if (number != 0)
+ glActiveTexture(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");
+ if (number != 0)
+ glActiveTexture(GL_TEXTURE0);
}
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 Gwn_ShaderInput *attrib = GWN_shaderinterface_attr(shader->interface, name);
+ return attrib ? attrib->location : -1;
}
GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
{
- GPUShader *retval = NULL;
-
- 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_smoke_frag_glsl,
- NULL, NULL, "#define USE_FIRE;\n", 0, 0, 0);
- retval = GG.shaders.smoke_fire;
- break;
- }
+ BLI_assert(shader != GPU_NUM_BUILTIN_SHADERS); /* don't be a troll */
+
+ static const GPUShaderStages builtin_shader_stages[GPU_NUM_BUILTIN_SHADERS] = {
+ [GPU_SHADER_VSM_STORE] = { datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl },
+ [GPU_SHADER_SEP_GAUSSIAN_BLUR] = { datatoc_gpu_shader_sep_gaussian_blur_vert_glsl,
+ datatoc_gpu_shader_sep_gaussian_blur_frag_glsl },
+ [GPU_SHADER_SMOKE] = { datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl },
+ [GPU_SHADER_SMOKE_FIRE] = { datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl },
+ [GPU_SHADER_SMOKE_COBA] = { datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl },
+
+ [GPU_SHADER_TEXT] = { datatoc_gpu_shader_text_vert_glsl, datatoc_gpu_shader_text_frag_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,
+ /* this version is */ datatoc_gpu_shader_flat_color_frag_glsl,
+ /* magical but slooow */ datatoc_gpu_shader_edges_front_back_persp_geom_glsl },
+ [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_RECT_MODULATE_ALPHA] = { datatoc_gpu_shader_3D_image_vert_glsl,
+ datatoc_gpu_shader_image_rect_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_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_IMAGE_LINEAR_TO_SRGB] = { datatoc_gpu_shader_2D_image_vert_glsl,
+ datatoc_gpu_shader_image_linear_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_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_3D_UNIFORM_COLOR] = { 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_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_3D_INSTANCE_BONE_ENVELOPE_SOLID] = { datatoc_gpu_shader_instance_bone_envelope_solid_vert_glsl,
+ datatoc_gpu_shader_simple_lighting_frag_glsl },
+ [GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_WIRE] = { datatoc_gpu_shader_instance_bone_envelope_wire_vert_glsl,
+ datatoc_gpu_shader_flat_color_frag_glsl },
+ };
+
+ if (builtin_shaders[shader] == NULL) {
+ /* just a few special cases */
+ const char *defines = NULL;
+ switch (shader) {
+ case GPU_SHADER_SMOKE_COBA:
+ defines = "#define USE_COBA;\n";
+ break;
+ case GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE:
+ defines = "#define UNIFORM_SCALE;\n";
+ break;
+ case GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED_AXIS:
+ defines = "#define AXIS_NAME;\n";
+ break;
+ case GPU_SHADER_3D_OBJECTSPACE_SIMPLE_LIGHTING_VARIYING_COLOR:
+ case GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_SOLID:
+ defines = "#define USE_INSTANCE_COLOR;\n";
+ break;
+ case GPU_SHADER_3D_FLAT_COLOR_U32:
+ defines = "#define USE_COLOR_U32;\n";
+ break;
+ case GPU_SHADER_SIMPLE_LIGHTING_FLAT_COLOR:
+ defines = "#define USE_FLAT_NORMAL;\n";
+ break;
+ default:
+ break;
+ }
+
+ 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;
+ }
- if (retval == NULL)
- printf("Unable to create a GPUShader for builtin shader: %u\n", shader);
+ /* common case */
+ builtin_shaders[shader] = GPU_shader_create(stages->vert, stages->frag, stages->geom, NULL, defines);
+ }
- return retval;
+ return builtin_shaders[shader];
}
#define MAX_DEFINES 100
@@ -647,98 +818,80 @@ GPUShader *GPU_shader_get_builtin_fx_shader(int effect, bool persp)
strcat(defines, "#define PERSP_MATRIX\n");
}
- if (!GG.shaders.fx_shaders[offset]) {
+ if (!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);
+ shader = GPU_shader_create(datatoc_gpu_shader_fullscreen_vert_glsl, datatoc_gpu_shader_fx_ssao_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines);
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);
+ 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);
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);
+ 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);
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);
+ 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);
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);
+ 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);
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);
+ 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);
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);
+ 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);
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);
+ 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);
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);
+ 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);
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);
+ shader = GPU_shader_create(datatoc_gpu_shader_fullscreen_vert_glsl, datatoc_gpu_shader_fx_depth_resolve_glsl, NULL, NULL, defines);
break;
}
- GG.shaders.fx_shaders[offset] = shader;
+ fx_shaders[offset] = shader;
GPU_fx_shader_init_interface(shader, effect);
}
- return GG.shaders.fx_shaders[offset];
+ return fx_shaders[offset];
}
void GPU_shader_free_builtin_shaders(void)
{
- int i;
-
- if (GG.shaders.vsm_store) {
- GPU_shader_free(GG.shaders.vsm_store);
- GG.shaders.vsm_store = NULL;
- }
-
- if (GG.shaders.sep_gaussian_blur) {
- GPU_shader_free(GG.shaders.sep_gaussian_blur);
- GG.shaders.sep_gaussian_blur = NULL;
- }
-
- if (GG.shaders.smoke) {
- GPU_shader_free(GG.shaders.smoke);
- GG.shaders.smoke = NULL;
- }
-
- if (GG.shaders.smoke_fire) {
- GPU_shader_free(GG.shaders.smoke_fire);
- GG.shaders.smoke_fire = NULL;
+ for (int i = 0; i < GPU_NUM_BUILTIN_SHADERS; ++i) {
+ if (builtin_shaders[i]) {
+ GPU_shader_free(builtin_shaders[i]);
+ builtin_shaders[i] = NULL;
+ }
}
- 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;
+ for (int i = 0; i < 2 * MAX_FX_SHADERS; ++i) {
+ if (fx_shaders[i]) {
+ GPU_shader_free(fx_shaders[i]);
+ fx_shaders[i] = NULL;
}
}
}
-
-
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..2de05b5746b
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader_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.
+ *
+ * ***** 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 "gawain/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 */
+
+ void *uniform_interface; /* cached uniform interface for shader. Data depends on shader */
+ /* NOTE: ^-- only FX compositing shaders use this */
+
+ Gwn_ShaderInterface *interface; /* cached uniform & attrib interface for shader */
+};
+
+#endif /* __GPU_SHADER_PRIVATE_H__ */
+
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c
index 54f0003c086..48ed3fc1de1 100644
--- a/source/blender/gpu/intern/gpu_texture.c
+++ b/source/blender/gpu/intern/gpu_texture.c
@@ -49,9 +49,8 @@ static struct GPUTextureGlobal {
} GG = {NULL, NULL, NULL};
/* 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_* */
@@ -62,43 +61,257 @@ struct GPUTexture {
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? */
+ bool depth; /* is a depth texture? */
+ bool stencil; /* is a stencil texture? */
+
+ unsigned int bytesize; /* number of byte for one pixel */
+ int format; /* GPUTextureFormat */
};
-static unsigned char *GPU_texture_convert_pixels(int length, const float *fpixels)
+/* ------ Memory Management ------- */
+/* Records every texture allocation / free
+ * to estimate the Texture Pool Memory consumption */
+static unsigned int memory_usage;
+
+static unsigned int gpu_texture_memory_footprint_compute(GPUTexture *tex)
{
- unsigned char *pixels, *p;
- const float *fp = fpixels;
- const int len = 4 * length;
+ switch (tex->target) {
+ case GL_TEXTURE_1D:
+ return tex->bytesize * tex->w;
+ case GL_TEXTURE_1D_ARRAY:
+ case GL_TEXTURE_2D:
+ return tex->bytesize * tex->w * tex->h;
+ case GL_TEXTURE_2D_ARRAY:
+ case GL_TEXTURE_3D:
+ return tex->bytesize * tex->w * tex->h * tex->d;
+ case GL_TEXTURE_CUBE_MAP:
+ return tex->bytesize * 6 * tex->w * tex->h;
+ case GL_TEXTURE_CUBE_MAP_ARRAY:
+ return tex->bytesize * 6 * tex->w * tex->h * tex->d;
+ default:
+ return 0;
+ }
+}
- p = pixels = MEM_callocN(sizeof(unsigned char) * len, "GPUTexturePixels");
+static void gpu_texture_memory_footprint_add(GPUTexture *tex)
+{
+ memory_usage += gpu_texture_memory_footprint_compute(tex);
+}
- for (int a = 0; a < len; a++, p++, fp++)
- *p = FTOCHAR((*fp));
+static void gpu_texture_memory_footprint_remove(GPUTexture *tex)
+{
+ memory_usage -= gpu_texture_memory_footprint_compute(tex);
+}
- return pixels;
+unsigned int GPU_texture_memory_usage_get(void)
+{
+ return memory_usage;
}
-static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h)
+/* -------------------------------- */
+
+static GLenum gpu_texture_get_format(
+ int components, GPUTextureFormat data_type,
+ GLenum *format, GLenum *data_format, bool *is_depth, bool *is_stencil, unsigned int *bytesize)
{
- void *pixels = MEM_callocN(sizeof(char) * 4 * w * h, "GPUTextureEmptyPixels");
+ if (data_type == GPU_DEPTH_COMPONENT24 ||
+ data_type == GPU_DEPTH_COMPONENT16 ||
+ data_type == GPU_DEPTH_COMPONENT32F)
+ {
+ *is_depth = true;
+ *is_stencil = false;
+ *data_format = GL_FLOAT;
+ *format = GL_DEPTH_COMPONENT;
+ }
+ else if (data_type == GPU_DEPTH24_STENCIL8) {
+ *is_depth = true;
+ *is_stencil = true;
+ *data_format = GL_UNSIGNED_INT_24_8;
+ *format = GL_DEPTH_STENCIL;
+ }
+ else {
+ *is_depth = false;
+ *is_stencil = false;
+ *data_format = GL_FLOAT;
+
+ switch (components) {
+ case 1: *format = GL_RED; break;
+ case 2: *format = GL_RG; break;
+ case 3: *format = GL_RGB; break;
+ case 4: *format = GL_RGBA; break;
+ default: break;
+ }
+ }
- 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);
-
- MEM_freeN(pixels);
+ switch (data_type) {
+ case GPU_RGBA32F:
+ *bytesize = 32;
+ break;
+ case GPU_RG32F:
+ case GPU_RGBA16F:
+ *bytesize = 16;
+ break;
+ case GPU_RGB16F:
+ *bytesize = 12;
+ break;
+ case GPU_RG16F:
+ case GPU_DEPTH24_STENCIL8:
+ case GPU_DEPTH_COMPONENT32F:
+ case GPU_RGBA8:
+ case GPU_R11F_G11F_B10F:
+ case GPU_R32F:
+ *bytesize = 4;
+ break;
+ case GPU_DEPTH_COMPONENT24:
+ *bytesize = 3;
+ break;
+ case GPU_DEPTH_COMPONENT16:
+ case GPU_R16F:
+ *bytesize = 2;
+ break;
+ case GPU_R8:
+ *bytesize = 1;
+ break;
+ default:
+ *bytesize = 0;
+ break;
+ }
+
+ /* You can add any of the available type to this list
+ * For available types see GPU_texture.h */
+ switch (data_type) {
+ /* Formats texture & renderbuffer */
+ case GPU_RGBA32F: return GL_RGBA32F;
+ case GPU_RGBA16F: return GL_RGBA16F;
+ case GPU_RG32F: return GL_RG32F;
+ case GPU_RGB16F: return GL_RGB16F;
+ case GPU_RG16F: return GL_RG16F;
+ case GPU_RGBA8: return GL_RGBA8;
+ case GPU_R32F: return GL_R32F;
+ case GPU_R16F: return GL_R16F;
+ 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;
+ /* 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:
+ fprintf(stderr, "Texture format incorrect or unsupported\n");
+ return 0;
+ }
}
-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])
+static float *GPU_texture_3D_rescale(GPUTexture *tex, int w, int h, int d, int channels, const float *fpixels)
{
- GLenum type, format, internalformat;
- void *pixels = NULL;
+ const unsigned int 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 (unsigned k = 0; k < tex->d; 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);
+
+ 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 format, GLenum data_format,
+ int channels, bool try_rescale, const float *fpixels, float **rescaled_fpixels)
+{
+ int r_width;
+
+ switch (proxy) {
+ case GL_PROXY_TEXTURE_1D:
+ glTexImage1D(proxy, 0, internalformat, tex->w, 0, format, data_format, NULL);
+ break;
+ case GL_PROXY_TEXTURE_1D_ARRAY:
+ case GL_PROXY_TEXTURE_2D:
+ glTexImage2D(proxy, 0, internalformat, tex->w, tex->h, 0, format, data_format, NULL);
+ break;
+ case GL_PROXY_TEXTURE_2D_ARRAY:
+ case GL_PROXY_TEXTURE_3D:
+ glTexImage3D(proxy, 0, internalformat, tex->w, tex->h, tex->d, 0, format, data_format, 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, format, data_format, NULL);
+ else if (proxy == GL_PROXY_TEXTURE_2D)
+ glTexImage2D(proxy, 0, internalformat, tex->w, tex->h, 0, format, data_format, NULL);
+ else if (proxy == GL_PROXY_TEXTURE_3D)
+ glTexImage3D(proxy, 0, internalformat, tex->w, tex->h, tex->d, 0, format, data_format, 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:
+ *rescaled_fpixels = GPU_texture_3D_rescale(tex, w, h, d, channels, fpixels);
+ return (bool)*rescaled_fpixels;
+ }
+ }
+ }
+
+ return (r_width > 0);
+}
+
+static GPUTexture *GPU_texture_create_nD(
+ int w, int h, int d, int n, const float *fpixels,
+ GPUTextureFormat data_type, int components, int samples,
+ const bool can_rescale, char err_out[256])
+{
if (samples) {
CLAMP_MAX(samples, GPU_max_color_texture_samples());
}
@@ -106,262 +319,204 @@ static GPUTexture *GPU_texture_create_nD(
GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
tex->w = w;
tex->h = h;
+ tex->d = d;
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;
+ tex->format = data_type;
+ 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;
+ }
+
+ if (samples && n == 2 && d == 0)
+ tex->target = GL_TEXTURE_2D_MULTISAMPLE;
+
+ GLenum format, internalformat, data_format;
+ internalformat = gpu_texture_get_format(components, data_type, &format, &data_format, &tex->depth, &tex->stencil, &tex->bytesize);
+
+ gpu_texture_memory_footprint_add(tex);
+
+ /* Generate Texture object */
glGenTextures(1, &tex->bindcode);
if (!tex->bindcode) {
- if (err_out) {
- BLI_snprintf(err_out, 256, "GPUTexture: texture create failed: %d",
- (int)glGetError());
- }
- else {
- fprintf(stderr, "GPUTexture: texture create failed: %d\n",
- (int)glGetError());
- }
+ if (err_out)
+ BLI_snprintf(err_out, 256, "GPUTexture: texture create failed");
+ else
+ fprintf(stderr, "GPUTexture: texture create failed");
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);
- }
-
tex->number = 0;
glBindTexture(tex->target, tex->bindcode);
- if (depth) {
- type = GL_UNSIGNED_BYTE;
- format = GL_DEPTH_COMPONENT;
- internalformat = GL_DEPTH_COMPONENT;
- }
- 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;
- }
- }
- 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;
- }
- }
+ /* Check if texture fit in VRAM */
+ GLenum proxy = GL_PROXY_TEXTURE_2D;
- if (fpixels && hdr_type == GPU_HDR_NONE) {
- type = GL_UNSIGNED_BYTE;
- pixels = GPU_texture_convert_pixels(w * h, fpixels);
- }
+ 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;
}
- if (tex->target == GL_TEXTURE_1D) {
- glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, type, NULL);
+ float *rescaled_fpixels = NULL;
+ bool valid = gpu_texture_try_alloc(tex, proxy, internalformat, format, data_format, components, can_rescale,
+ fpixels, &rescaled_fpixels);
+ 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;
+ }
- if (fpixels) {
- glTexSubImage1D(tex->target, 0, 0, w, format, type,
- pixels ? pixels : fpixels);
+ /* Upload Texture */
+ const float *pix = (rescaled_fpixels) ? rescaled_fpixels : fpixels;
- if (tex->w > w) {
- GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, 1);
- }
- }
- }
- else {
+ 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, format, data_format, pix);
}
else {
- glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0,
- format, type, NULL);
- }
-
- 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);
+ glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0, format, data_format, pix);
}
}
+ else if (tex->target == GL_TEXTURE_1D) {
+ glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, data_format, pix);
+ }
+ else {
+ glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->d, 0, format, data_format, pix);
+ }
- if (pixels)
- MEM_freeN(pixels);
+ if (rescaled_fpixels)
+ MEM_freeN(rescaled_fpixels);
- if (depth) {
+ /* Texture Parameters */
+ if (tex->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_MODE, GL_NONE);
glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
- glTexParameteri(tex->target_base, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
}
else {
glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
- 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_S, GL_CLAMP_TO_EDGE);
+ if (n > 1) {
glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
- else
- glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ if (n > 2) {
+ glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+ }
+
+ GPU_texture_unbind(tex);
return tex;
}
-
-GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels)
+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 data_type, int components,
+ char err_out[256])
{
- GLenum type, format, internalformat;
- void *pixels = NULL;
+ GLenum format, internalformat, data_format;
GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
tex->w = w;
- tex->h = h;
- tex->depth = depth;
+ tex->h = w;
+ tex->d = d;
tex->number = -1;
tex->refcount = 1;
- tex->target = GL_TEXTURE_3D;
- tex->target_base = GL_TEXTURE_3D;
-
- glGenTextures(1, &tex->bindcode);
-
- if (!tex->bindcode) {
- fprintf(stderr, "GPUTexture: texture create failed: %d\n",
- (int)glGetError());
- GPU_texture_free(tex);
- return NULL;
- }
-
- tex->number = 0;
- glBindTexture(tex->target, tex->bindcode);
-
- GPU_ASSERT_NO_GL_ERRORS("3D glBindTexture");
+ tex->fb_attachment = -1;
+ tex->format = data_type;
- type = GL_FLOAT;
- if (channels == 4) {
- format = GL_RGBA;
- internalformat = GL_RGBA8;
+ if (d == 0) {
+ tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP;
}
else {
- format = GL_RED;
- internalformat = GL_INTENSITY8;
+ BLI_assert(false && "Cubemap array Not implemented yet");
+ // tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP_ARRAY;
}
- /* 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);
+ internalformat = gpu_texture_get_format(components, data_type, &format, &data_format, &tex->depth, &tex->stencil, &tex->bytesize);
- bool rescale = false;
- int r_width;
+ gpu_texture_memory_footprint_add(tex);
- glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width);
+ /* Generate Texture object */
+ glGenTextures(1, &tex->bindcode);
- 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);
+ if (!tex->bindcode) {
+ if (err_out)
+ BLI_snprintf(err_out, 256, "GPUTexture: texture create failed");
+ else
+ fprintf(stderr, "GPUTexture: texture create failed");
+ GPU_texture_free(tex);
+ return NULL;
}
- /* 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);
-
-#if 0
- if (fpixels)
- pixels = GPU_texture_convert_pixels(w*h*depth, fpixels);
-#endif
-
- GPU_ASSERT_NO_GL_ERRORS("3D glTexImage3D");
-
- /* 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");
-
- GPU_print_error_debug("You need to scale a 3D texture, feel the pain!");
-
- 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);
-
- 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];
- }
- }
- }
+ tex->number = 0;
+ glBindTexture(tex->target, tex->bindcode);
- glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, tex3d);
+ /* Upload Texture */
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_px);
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_py);
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_pz);
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_nx);
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_ny);
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_nz);
- MEM_freeN(tex3d);
+ /* Texture Parameters */
+ if (tex->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_NONE);
+ glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
}
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);
}
-
- 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);
@@ -378,6 +533,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget
/* 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?) */
if (textarget == GL_TEXTURE_2D)
gputt = TEXTARGET_TEXTURE_2D;
else
@@ -396,14 +552,15 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget
tex->target = textarget;
tex->target_base = textarget;
tex->fromblender = 1;
+ tex->format = -1;
ima->gputexture[gputt] = 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, border;
+ GLint w, h;
GLenum gettarget;
@@ -415,10 +572,8 @@ 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);
@@ -450,11 +605,12 @@ 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;
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;
@@ -473,114 +629,88 @@ 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, 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;
+ return GPU_texture_create_nD(w, 0, 0, 1, pixels, GPU_RGBA8, 4, 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_custom(
+ int w, int channels, GPUTextureFormat data_type, 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);
-
- return tex;
+ return GPU_texture_create_nD(w, 0, 0, 1, pixels, data_type, channels, 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])
-{
- GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, samples, err_out);
-
- if (tex)
- GPU_texture_unbind(tex);
- return tex;
+GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, char err_out[256])
+{
+ return GPU_texture_create_nD(w, h, 0, 2, pixels, GPU_RGBA8, 4, 0, false, err_out);
}
-GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256])
+GPUTexture *GPU_texture_create_2D_custom(
+ int w, int h, int channels, GPUTextureFormat data_type, 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);
-
- if (tex)
- GPU_texture_unbind(tex);
-
- return tex;
+ return GPU_texture_create_nD(w, h, 0, 2, pixels, data_type, channels, 0, false, err_out);
}
-GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256])
-{
- GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, samples, err_out);
-
- if (tex)
- GPU_texture_unbind(tex);
- return tex;
+GPUTexture *GPU_texture_create_2D_multisample(int w, int h, const float *pixels, int samples, char err_out[256])
+{
+ return GPU_texture_create_nD(w, h, 0, 2, pixels, GPU_RGBA8, 4, samples, false, err_out);
}
-/**
- * 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])
+GPUTexture *GPU_texture_create_2D_array_custom(int w, int h, int d, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256])
{
- GPUTexture *tex = GPU_texture_create_nD(size, size, 2, NULL, 0, GPU_HDR_FULL_FLOAT, 2, 0, err_out);
-
- 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_texture_unbind(tex);
- }
-
- return tex;
+ return GPU_texture_create_nD(w, h, d, 2, pixels, data_type, channels, 0, false, err_out);
}
-GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256])
+GPUTexture *GPU_texture_create_3D(int w, int h, int d, const float *pixels, char err_out[256])
{
- GPUTexture *tex = GPU_texture_create_nD(w, h, 2, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out);
+ return GPU_texture_create_nD(w, h, d, 3, pixels, GPU_RGBA8, 4, 0, true, err_out);
+}
- 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);
+GPUTexture *GPU_texture_create_3D_custom(int w, int h, int d, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256])
+{
+ return GPU_texture_create_nD(w, h, d, 3, pixels, data_type, channels, 0, true, err_out);
+}
+GPUTexture *GPU_texture_create_cube_custom(int w, int channels, GPUTextureFormat data_type, const float *fpixels, char err_out[256])
+{
+ const float *fpixels_px, *fpixels_py, *fpixels_pz, *fpixels_nx, *fpixels_ny, *fpixels_nz;
- GPU_texture_unbind(tex);
+ if (fpixels) {
+ fpixels_px = fpixels + 0 * w * w * channels;
+ fpixels_nx = fpixels + 1 * w * w * channels;
+ fpixels_py = fpixels + 2 * w * w * channels;
+ fpixels_ny = fpixels + 3 * w * w * channels;
+ fpixels_pz = fpixels + 4 * w * w * channels;
+ fpixels_nz = fpixels + 5 * w * w * channels;
+ }
+ 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, data_type, channels, err_out);
}
-GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256])
+GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256])
{
- GPUTexture *tex = GPU_texture_create_nD(w, 0, 1, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out);
-
- 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);
+ return GPU_texture_create_nD(w, h, 0, 2, NULL, GPU_DEPTH_COMPONENT24, 1, 0, false, err_out);
+}
- GPU_texture_unbind(tex);
- }
+GPUTexture *GPU_texture_create_depth_with_stencil(int w, int h, char err_out[256])
+{
+ return GPU_texture_create_nD(w, h, 0, 2, NULL, GPU_DEPTH24_STENCIL8, 1, 0, false, err_out);
+}
- return tex;
+GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256])
+{
+ return GPU_texture_create_nD(w, h, 0, 2, NULL, GPU_DEPTH_COMPONENT24, 1, samples, false, err_out);
}
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_2D = GPU_texture_create_2D(1, 1, color, NULL);
+ GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, color, NULL);
}
void GPU_invalid_tex_bind(int mode)
@@ -625,21 +755,18 @@ void GPU_texture_bind(GPUTexture *tex, int number)
if (number < 0)
return;
- GPU_ASSERT_NO_GL_ERRORS("Pre Texture Bind");
+ if (number != 0)
+ glActiveTexture(GL_TEXTURE0 + number);
- GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + number);
- if (number != 0) glActiveTexture(arbnumber);
- if (tex->bindcode != 0) {
+ if (tex->bindcode != 0)
glBindTexture(tex->target_base, tex->bindcode);
- }
else
GPU_invalid_tex_bind(tex->target_base);
- glEnable(tex->target_base);
- if (number != 0) glActiveTexture(GL_TEXTURE0);
- tex->number = number;
+ if (number != 0)
+ glActiveTexture(GL_TEXTURE0);
- GPU_ASSERT_NO_GL_ERRORS("Post Texture Bind");
+ tex->number = number;
}
void GPU_texture_unbind(GPUTexture *tex)
@@ -651,18 +778,16 @@ void GPU_texture_unbind(GPUTexture *tex)
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);
+ if (tex->number != 0)
+ glActiveTexture(GL_TEXTURE0 + tex->number);
+
glBindTexture(tex->target_base, 0);
- glDisable(tex->target_base);
- if (tex->number != 0) glActiveTexture(GL_TEXTURE0);
- tex->number = -1;
+ if (tex->number != 0)
+ glActiveTexture(GL_TEXTURE0);
- GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind");
+ tex->number = -1;
}
int GPU_texture_bound_number(GPUTexture *tex)
@@ -670,7 +795,7 @@ int GPU_texture_bound_number(GPUTexture *tex)
return tex->number;
}
-void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter)
+void GPU_texture_generate_mipmap(GPUTexture *tex)
{
if (tex->number >= GPU_max_textures()) {
fprintf(stderr, "Not enough texture slots.\n");
@@ -680,29 +805,101 @@ void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter)
if (tex->number == -1)
return;
- GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind");
+ if (tex->number != 0)
+ glActiveTexture(GL_TEXTURE0 + tex->number);
- GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number);
- if (tex->number != 0) glActiveTexture(arbnumber);
+ glGenerateMipmap(tex->target_base);
- 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);
+ if (tex->number != 0)
+ glActiveTexture(GL_TEXTURE0);
+}
+
+void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare)
+{
+ if (tex->number >= GPU_max_textures()) {
+ fprintf(stderr, "Not enough texture slots.\n");
+ return;
}
- if (use_filter) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ if (tex->number == -1)
+ return;
+
+ if (tex->number != 0)
+ glActiveTexture(GL_TEXTURE0 + tex->number);
+
+ /* TODO viewport: use GL_COMPARE_REF_TO_TEXTURE after we switch to core profile */
+ if (tex->depth)
+ glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, use_compare ? GL_COMPARE_R_TO_TEXTURE : GL_NONE);
+
+ if (tex->number != 0)
+ glActiveTexture(GL_TEXTURE0);
+}
+
+void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter)
+{
+ if (tex->number >= GPU_max_textures()) {
+ fprintf(stderr, "Not enough texture slots.\n");
+ return;
}
- else {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ if (tex->number == -1)
+ return;
+
+ if (tex->number != 0)
+ glActiveTexture(GL_TEXTURE0 + tex->number);
+
+ GLenum filter = use_filter ? GL_LINEAR : GL_NEAREST;
+ glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, filter);
+ glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, filter);
+
+ if (tex->number != 0)
+ glActiveTexture(GL_TEXTURE0);
+}
+
+void GPU_texture_mipmap_mode(GPUTexture *tex, bool use_mipmap, bool use_filter)
+{
+ if (tex->number >= GPU_max_textures()) {
+ fprintf(stderr, "Not enough texture slots.\n");
+ return;
}
- if (tex->number != 0) glActiveTexture(GL_TEXTURE0);
- GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind");
+ if (tex->number == -1)
+ return;
+
+ if (tex->number != 0)
+ glActiveTexture(GL_TEXTURE0 + tex->number);
+
+ GLenum mipmap = (use_filter)
+ ? use_mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR
+ : use_mipmap ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST;
+ glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, mipmap);
+
+ if (tex->number != 0)
+ glActiveTexture(GL_TEXTURE0);
+}
+
+void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat)
+{
+ if (tex->number >= GPU_max_textures()) {
+ fprintf(stderr, "Not enough texture slots.\n");
+ return;
+ }
+
+ if (tex->number == -1)
+ return;
+
+ if (tex->number != 0)
+ glActiveTexture(GL_TEXTURE0 + tex->number);
+
+ GLenum repeat = use_repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE;
+ 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);
+
+ if (tex->number != 0)
+ glActiveTexture(GL_TEXTURE0);
}
void GPU_texture_free(GPUTexture *tex)
@@ -718,6 +915,8 @@ void GPU_texture_free(GPUTexture *tex)
if (tex->bindcode && !tex->fromblender)
glDeleteTextures(1, &tex->bindcode);
+ gpu_texture_memory_footprint_remove(tex);
+
MEM_freeN(tex);
}
}
@@ -742,11 +941,21 @@ int GPU_texture_height(const GPUTexture *tex)
return tex->h;
}
-int GPU_texture_depth(const GPUTexture *tex)
+int GPU_texture_format(const GPUTexture *tex)
+{
+ return tex->format;
+}
+
+bool GPU_texture_depth(const GPUTexture *tex)
{
return tex->depth;
}
+bool GPU_texture_stencil(const GPUTexture *tex)
+{
+ return tex->stencil;
+}
+
int GPU_texture_opengl_bindcode(const GPUTexture *tex)
{
return tex->bindcode;
diff --git a/source/blender/gpu/intern/gpu_uniformbuffer.c b/source/blender/gpu/intern/gpu_uniformbuffer.c
new file mode 100644
index 00000000000..e3072d729c3
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_uniformbuffer.c
@@ -0,0 +1,301 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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_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;
+
+typedef struct GPUUniformBuffer {
+ int size; /* in bytes */
+ GLuint bindcode; /* opengl identifier for UBO */
+ int bindpoint; /* current binding point */
+ GPUUniformBufferType type;
+} GPUUniformBuffer;
+
+#define GPUUniformBufferStatic GPUUniformBuffer
+
+typedef struct GPUUniformBufferDynamic {
+ GPUUniformBuffer buffer;
+ ListBase items; /* GPUUniformBufferDynamicItem */
+ void *data;
+ char flag;
+} GPUUniformBufferDynamic;
+
+typedef struct GPUUniformBufferDynamicItem {
+ struct GPUUniformBufferDynamicItem *next, *prev;
+ GPUType gputype;
+ float *data;
+ int size;
+} GPUUniformBufferDynamicItem;
+
+
+/* Prototypes */
+static void gpu_uniformbuffer_inputs_sort(struct ListBase *inputs);
+
+static GPUUniformBufferDynamicItem *gpu_uniformbuffer_populate(
+ GPUUniformBufferDynamic *ubo, const GPUType gputype, float *num);
+
+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;
+
+ /* Generate Buffer object */
+ glGenBuffers(1, &ubo->bindcode);
+
+ 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->flag = GPU_UBO_FLAG_DIRTY;
+
+ /* Generate Buffer object. */
+ glGenBuffers(1, &ubo->buffer.bindcode);
+
+ 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) {
+ GPUInput *input = link->data;
+ gpu_uniformbuffer_populate(ubo, input->type, input->dynamicvec);
+ }
+
+ ubo->data = MEM_mallocN(ubo->buffer.size, __func__);
+
+ /* Initialize buffer data. */
+ GPU_uniformbuffer_dynamic_update(&ubo->buffer);
+ return &ubo->buffer;
+}
+
+/**
+ * Free the data, and clean the items list.
+ */
+static void gpu_uniformbuffer_dynamic_reset(GPUUniformBufferDynamic *ubo)
+{
+ ubo->buffer.size = 0;
+ if (ubo->data) {
+ MEM_freeN(ubo->data);
+ }
+ BLI_freelistN(&ubo->items);
+}
+
+void GPU_uniformbuffer_free(GPUUniformBuffer *ubo)
+{
+ if (ubo->type == GPU_UBO_DYNAMIC) {
+ gpu_uniformbuffer_dynamic_reset((GPUUniformBufferDynamic *)ubo);
+ }
+
+ glDeleteBuffers(1, &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_;
+
+ float *offset = ubo->data;
+ for (GPUUniformBufferDynamicItem *item = ubo->items.first; item; item = item->next) {
+ memcpy(offset, item->data, item->size);
+ offset += item->gputype;
+ }
+
+ 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;
+}
+
+/**
+ * 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)
+{
+ BLI_listbase_sort(inputs, inputs_cmp);
+}
+
+/**
+ * This may now happen from the main thread, so we can't update the UBO
+ * We simply flag it as dirty
+ */
+static GPUUniformBufferDynamicItem *gpu_uniformbuffer_populate(
+ GPUUniformBufferDynamic *ubo, const GPUType gputype, float *num)
+{
+ BLI_assert(gputype <= GPU_VEC4);
+ GPUUniformBufferDynamicItem *item = MEM_callocN(sizeof(GPUUniformBufferDynamicItem), __func__);
+
+ /* Treat VEC3 as VEC4 because of UBO struct alignment requirements. */
+ GPUType type = gputype == GPU_VEC3 ? GPU_VEC4 : gputype;
+
+ item->gputype = type;
+ item->data = num;
+ item->size = type * sizeof(float);
+ ubo->buffer.size += item->size;
+
+ ubo->flag |= GPU_UBO_FLAG_DIRTY;
+ BLI_addtail(&ubo->items, item);
+
+ return item;
+}
+
+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;
+}
+
+int GPU_uniformbuffer_bindpoint(GPUUniformBuffer *ubo)
+{
+ return ubo->bindpoint;
+}
+
+void GPU_uniformbuffer_tag_dirty(GPUUniformBuffer *ubo_) {
+ BLI_assert(ubo_->type == GPU_UBO_DYNAMIC);
+ GPUUniformBufferDynamic *ubo = (GPUUniformBufferDynamic *)ubo_;
+ ubo->flag |= GPU_UBO_FLAG_DIRTY;
+}
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
new file mode 100644
index 00000000000..9bd990e9796
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -0,0 +1,584 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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 "DNA_vec_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 "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 {
+ float pad[4];
+
+ /* debug */
+ GPUTexture *debug_depth;
+ int size[2];
+
+ ListBase data; /* ViewportEngineData wrapped in LinkData */
+ unsigned int data_hash; /* If hash mismatch we free all ViewportEngineData in this viewport */
+
+ DefaultFramebufferList *fbl;
+ DefaultTextureList *txl;
+
+ ListBase tex_pool; /* ViewportTempTexture list : Temporary textures shared across draw engines */
+};
+
+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);
+
+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->size[0] = viewport->size[1] = -1;
+
+ return viewport;
+}
+
+GPUViewport *GPU_viewport_create_from_offscreen(struct GPUOffScreen *ofs)
+{
+ GPUViewport *viewport = GPU_viewport_create();
+ GPU_offscreen_viewport_data_get(ofs, &viewport->fbl->default_fb, &viewport->txl->color, &viewport->txl->depth);
+ viewport->size[0] = GPU_offscreen_width(ofs);
+ viewport->size[1] = GPU_offscreen_height(ofs);
+ return viewport;
+}
+/**
+ * Clear vars assigned from offscreen, so we don't free data owned by `GPUOffScreen`.
+ */
+void GPU_viewport_clear_from_offscreen(GPUViewport *viewport)
+{
+ viewport->fbl->default_fb = NULL;
+ viewport->txl->color = NULL;
+ viewport->txl->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;
+}
+
+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];
+}
+
+/**
+ * Try to find a texture coresponding 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 channels, int format)
+{
+ GPUTexture *tex;
+
+ for (ViewportTempTexture *tmp_tex = viewport->tex_pool.first; tmp_tex; tmp_tex = tmp_tex->next) {
+ if ((GPU_texture_width(tmp_tex->texture) == width) &&
+ (GPU_texture_height(tmp_tex->texture) == height) &&
+ (GPU_texture_format(tmp_tex->texture) == format))
+ {
+ /* 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_custom(width, height, channels, format, NULL, NULL);
+
+ 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_cache_validate(GPUViewport *viewport, unsigned int hash)
+{
+ bool dirty = false;
+
+ /* TODO for testing only, we need proper cache invalidation */
+ if (ELEM(G.debug_value, 666, 667) == false) {
+ 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);
+ }
+ dirty = true;
+ }
+
+ if (viewport->data_hash != hash) {
+ gpu_viewport_engines_data_free(viewport);
+ dirty = true;
+ }
+
+ viewport->data_hash = hash;
+
+ return dirty;
+}
+
+void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect)
+{
+ DefaultFramebufferList *dfbl = viewport->fbl;
+ DefaultTextureList *dtxl = viewport->txl;
+ 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;
+
+ if (dfbl->default_fb) {
+ if (rect_w != viewport->size[0] || rect_h != viewport->size[1]) {
+ 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);
+ }
+ }
+
+ gpu_viewport_texture_pool_clear_users(viewport);
+
+ if (!dfbl->default_fb) {
+ bool ok = true;
+ viewport->size[0] = rect_w;
+ viewport->size[1] = rect_h;
+
+ dfbl->default_fb = GPU_framebuffer_create();
+ if (!dfbl->default_fb) {
+ ok = false;
+ goto cleanup;
+ }
+
+ /* Color */
+ /* No multi samples for now */
+ dtxl->color = GPU_texture_create_2D(rect_w, rect_h, NULL, NULL);
+ if (!dtxl->color) {
+ ok = false;
+ goto cleanup;
+ }
+
+ if (!GPU_framebuffer_texture_attach(dfbl->default_fb, dtxl->color, 0, 0)) {
+ ok = false;
+ goto cleanup;
+ }
+
+ /* Depth */
+ dtxl->depth = GPU_texture_create_depth(rect_w, rect_h, NULL);
+
+ if (dtxl->depth) {
+ /* Define texture parameters */
+ GPU_texture_bind(dtxl->depth, 0);
+ GPU_texture_compare_mode(dtxl->depth, false);
+ GPU_texture_filter_mode(dtxl->depth, true);
+ GPU_texture_unbind(dtxl->depth);
+ }
+ else {
+ ok = false;
+ goto cleanup;
+ }
+
+ if (!GPU_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0)) {
+ ok = false;
+ goto cleanup;
+ }
+ else if (!GPU_framebuffer_check_valid(dfbl->default_fb, NULL)) {
+ ok = false;
+ goto cleanup;
+ }
+
+cleanup:
+ if (!ok) {
+ GPU_viewport_free(viewport);
+ MEM_freeN(viewport);
+ return;
+ }
+
+ GPU_framebuffer_restore();
+ }
+
+ GPU_framebuffer_slots_bind(dfbl->default_fb, 0);
+}
+
+static void draw_ofs_to_screen(GPUViewport *viewport)
+{
+ DefaultTextureList *dtxl = viewport->txl;
+
+ GPUTexture *color = dtxl->color;
+
+ const float w = (float)GPU_texture_width(color);
+ const float h = (float)GPU_texture_height(color);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int texcoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_MODULATE_ALPHA);
+ GPU_texture_bind(color, 0);
+
+ immUniform1i("image", 0); /* default GL_TEXTURE0 unit */
+
+ immBegin(GWN_PRIM_TRI_STRIP, 4);
+
+ immAttrib2f(texcoord, 0.0f, 0.0f);
+ immVertex2f(pos, 0.0f, 0.0f);
+
+ immAttrib2f(texcoord, 1.0f, 0.0f);
+ immVertex2f(pos, w, 0.0f);
+
+ immAttrib2f(texcoord, 0.0f, 1.0f);
+ immVertex2f(pos, 0.0f, h);
+
+ immAttrib2f(texcoord, 1.0f, 1.0f);
+ immVertex2f(pos, w, h);
+
+ immEnd();
+
+ GPU_texture_unbind(color);
+
+ immUnbindProgram();
+}
+
+void GPU_viewport_unbind(GPUViewport *viewport)
+{
+ DefaultFramebufferList *dfbl = viewport->fbl;
+
+ if (dfbl->default_fb) {
+ GPU_framebuffer_texture_unbind(NULL, NULL);
+ GPU_framebuffer_restore();
+
+ glEnable(GL_SCISSOR_TEST);
+ glDisable(GL_DEPTH_TEST);
+
+ /* This might be bandwidth limiting */
+ draw_ofs_to_screen(viewport);
+ }
+}
+
+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);
+ MEM_freeN(pass);
+ psl->passes[i] = NULL;
+ }
+ }
+}
+
+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);
+
+ GPU_viewport_debug_depth_free(viewport);
+}
+
+/****************** debug ********************/
+
+bool GPU_viewport_debug_depth_create(GPUViewport *viewport, int width, int height, char err_out[256])
+{
+ viewport->debug_depth = GPU_texture_create_2D_custom(width, height, 4, GPU_RGBA16F, NULL, err_out);
+ return (viewport->debug_depth != NULL);
+}
+
+void GPU_viewport_debug_depth_free(GPUViewport *viewport)
+{
+ if (viewport->debug_depth != NULL) {
+ MEM_freeN(viewport->debug_depth);
+ viewport->debug_depth = NULL;
+ }
+}
+
+void GPU_viewport_debug_depth_store(GPUViewport *viewport, const int x, const int y)
+{
+ const int w = GPU_texture_width(viewport->debug_depth);
+ const int h = GPU_texture_height(viewport->debug_depth);
+
+ GPU_texture_bind(viewport->debug_depth, 0);
+ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, x, y, w, h, 0);
+ GPU_texture_unbind(viewport->debug_depth);
+}
+
+void GPU_viewport_debug_depth_draw(GPUViewport *viewport, const float znear, const float zfar)
+{
+ const float w = (float)GPU_texture_width(viewport->debug_depth);
+ const float h = (float)GPU_texture_height(viewport->debug_depth);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int texcoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_DEPTH);
+
+ GPU_texture_bind(viewport->debug_depth, 0);
+
+ immUniform1f("znear", znear);
+ immUniform1f("zfar", zfar);
+ immUniform1i("image", 0); /* default GL_TEXTURE0 unit */
+
+ immBegin(GWN_PRIM_TRI_STRIP, 4);
+
+ immAttrib2f(texcoord, 0.0f, 0.0f);
+ immVertex2f(pos, 0.0f, 0.0f);
+
+ immAttrib2f(texcoord, 1.0f, 0.0f);
+ immVertex2f(pos, w, 0.0f);
+
+ immAttrib2f(texcoord, 0.0f, 1.0f);
+ immVertex2f(pos, 0.0f, h);
+
+ immAttrib2f(texcoord, 1.0f, 1.0f);
+ immVertex2f(pos, w, h);
+
+ immEnd();
+
+ GPU_texture_unbind(viewport->debug_depth);
+
+ immUnbindProgram();
+}
+
+int GPU_viewport_debug_depth_width(const GPUViewport *viewport)
+{
+ return GPU_texture_width(viewport->debug_depth);
+}
+
+int GPU_viewport_debug_depth_height(const GPUViewport *viewport)
+{
+ return GPU_texture_height(viewport->debug_depth);
+}
+
+bool GPU_viewport_debug_depth_is_valid(GPUViewport *viewport)
+{
+ return viewport->debug_depth != NULL;
+}
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_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl
new file mode 100644
index 00000000000..228f3f1da19
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl
@@ -0,0 +1,13 @@
+
+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);
+ 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..7caf00f58fd
--- /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 num_colors > 0. */
+/* Note: max number of steps/colors in pattern is 32! */
+uniform int num_colors; /* 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 (num_colors > 0) {
+ /* Solid line case, simple. */
+ if (num_colors == 1) {
+ fragColor = colors[0];
+ }
+ /* Actually dashed line... */
+ else {
+ float normalized_distance = fract(distance_along_line / dash_width);
+ fragColor = colors[int(normalized_distance * num_colors)];
+ }
+ }
+ /* 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..db4bdf0a9f0
--- /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 num_colors; /* 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 ((num_colors == 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..20c72f4407d
--- /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 num_colors; /* 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 ((num_colors == 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_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_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_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
index 01a335af048..5f7455582cd 100644
--- a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl
@@ -20,12 +20,10 @@
#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
+
+#ifndef NO_SPECULAR
+uniform mat4 ProjectionMatrix;
+#endif
#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
#if defined(USE_FLAT_NORMAL)
@@ -58,7 +56,7 @@ uniform sampler2D_default texture_map;
#ifdef USE_STIPPLE
uniform int stipple_id;
#if defined(DRAW_LINE)
-varying in float t;
+varying float t;
uniform int stipple_pattern;
#endif
#endif
@@ -74,14 +72,9 @@ void main()
/* 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)
- {
+ if (stipple_id == STIPPLE_HALFTONE) {
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;
}
@@ -116,22 +109,6 @@ void main()
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));
@@ -190,7 +167,7 @@ void main()
#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);
+ vec3 V = (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++) {
diff --git a/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl b/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl
index a88681a5fd3..13f05b340bf 100644
--- a/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl
@@ -14,9 +14,9 @@ layout(line_strip, max_vertices = 10) out;
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;
+out float t;
+in vec4 varying_vertex_color_line[];
+out vec4 varying_vertex_color;
uniform ivec4 viewport;
uniform float line_width;
diff --git a/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl b/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl
index 42fbdadf1d1..dbf6c267f14 100644
--- a/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl
@@ -1,4 +1,8 @@
+uniform mat4 ModelViewMatrix;
+uniform mat4 ProjectionMatrix;
+uniform mat3 NormalMatrix;
+
#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
#if defined(USE_FLAT_NORMAL)
varying vec3 eyespace_vert_pos;
@@ -29,15 +33,15 @@ varying float gl_ClipDistance[6];
void main()
{
- vec4 co = gl_ModelViewMatrix * gl_Vertex;
+ vec4 co = ModelViewMatrix * gl_Vertex;
#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
#if !defined(USE_FLAT_NORMAL)
- varying_normal = normalize(gl_NormalMatrix * gl_Normal);
+ varying_normal = normalize(NormalMatrix * gl_Normal);
#endif
#if defined(USE_FLAT_NORMAL)
/* transform vertex into eyespace */
- eyespace_vert_pos = (gl_ModelViewMatrix * gl_Vertex).xyz;
+ eyespace_vert_pos = (ModelViewMatrix * gl_Vertex).xyz;
#endif
#ifndef USE_SOLID_LIGHTING
@@ -45,7 +49,7 @@ void main()
#endif
#endif
- gl_Position = gl_ProjectionMatrix * co;
+ gl_Position = ProjectionMatrix * co;
#ifdef CLIP_WORKAROUND
int i;
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..10b5fad7972
--- /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
new file mode 100644
index 00000000000..fc9cafb6b02
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_fire_frag.glsl
@@ -0,0 +1,15 @@
+
+in vec3 coords;
+out vec4 fragColor;
+
+uniform sampler3D flame_texture;
+uniform sampler1D spectrum_texture;
+
+void main()
+{
+ float flame = texture(flame_texture, coords).r;
+ vec4 emission = texture(spectrum_texture, flame);
+
+ fragColor.rgb = emission.a * emission.rgb;
+ fragColor.a = emission.a;
+}
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_fullscreen_vert.glsl b/source/blender/gpu/shaders/gpu_shader_fullscreen_vert.glsl
new file mode 100644
index 00000000000..fc5cc1cdcc3
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_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/gpu/shaders/gpu_shader_fx_depth_resolve.glsl b/source/blender/gpu/shaders/gpu_shader_fx_depth_resolve.glsl
index e04cd7d3306..c4e7cff2b0b 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_depth_resolve.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_depth_resolve.glsl
@@ -1,9 +1,10 @@
uniform sampler2D depthbuffer;
-varying vec4 uvcoordsvar;
+
+in vec4 uvcoordsvar;
void main(void)
{
- float depth = texture2D(depthbuffer, uvcoordsvar.xy).r;
+ float depth = texture(depthbuffer, uvcoordsvar.xy).r;
/* XRay background, discard */
if (depth >= 1.0) {
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl
index 338ef6d51a7..15d30e75969 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl
@@ -17,17 +17,18 @@ uniform vec4 dof_params;
uniform vec4 viewvecs[3];
// coordinates on framebuffer in normalized (0.0-1.0) uv space
-varying vec4 uvcoordsvar;
+in vec4 uvcoordsvar;
/* color texture coordinates, offset by a small amount */
-varying vec2 color_uv1;
-varying vec2 color_uv2;
+in vec2 color_uv1;
+in vec2 color_uv2;
-varying vec2 depth_uv1;
-varying vec2 depth_uv2;
-varying vec2 depth_uv3;
-varying vec2 depth_uv4;
+in vec2 depth_uv1;
+in vec2 depth_uv2;
+in vec2 depth_uv3;
+in vec2 depth_uv4;
+out vec4 FragColor;
float calculate_far_coc(in float zdepth)
{
@@ -63,85 +64,85 @@ void first_pass()
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]);
+ vec4 color = texture(colorbuffer, color_uv1);
+ color += texture(colorbuffer, color_uv1 + offset_row[1]);
+ color += texture(colorbuffer, color_uv2);
+ color += texture(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;
+ depth.r = texture(depthbuffer, depth_uv1).r;
+ depth.g = texture(depthbuffer, depth_uv2).r;
+ depth.b = texture(depthbuffer, depth_uv3).r;
+ depth.a = texture(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;
+ depth.r = texture(depthbuffer, depth_uv1 + offset_row[0]).r;
+ depth.g = texture(depthbuffer, depth_uv2 + offset_row[0]).r;
+ depth.b = texture(depthbuffer, depth_uv3 + offset_row[0]).r;
+ depth.a = texture(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;
+ depth.r = texture(depthbuffer, depth_uv1 + offset_row[1]).r;
+ depth.g = texture(depthbuffer, depth_uv2 + offset_row[1]).r;
+ depth.b = texture(depthbuffer, depth_uv3 + offset_row[1]).r;
+ depth.a = texture(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;
+ depth.r = texture(depthbuffer, depth_uv1 + offset_row[2]).r;
+ depth.g = texture(depthbuffer, depth_uv2 + offset_row[2]).r;
+ depth.b = texture(depthbuffer, depth_uv3 + offset_row[2]).r;
+ depth.a = texture(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);
+ FragColor = vec4(color.rgb, final_coc);
}
/* second pass, gaussian blur the downsampled image */
void second_pass()
{
- vec4 depth = vec4(texture2D(depthbuffer, uvcoordsvar.xy).r);
+ vec4 depth = vec4(texture(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;
+ vec4 color = texture(colorbuffer, uvcoordsvar.xy) * 0.3125;
+ color += texture(colorbuffer, uvcoordsvar.xy + invrendertargetdim) * 0.234375;
+ color += texture(colorbuffer, uvcoordsvar.xy + 2.5 * invrendertargetdim) * 0.09375;
+ color += texture(colorbuffer, uvcoordsvar.xy + 4.5 * invrendertargetdim) * 0.015625;
+ color += texture(colorbuffer, uvcoordsvar.xy - invrendertargetdim) * 0.234375;
+ color += texture(colorbuffer, uvcoordsvar.xy - 2.5 * invrendertargetdim) * 0.09375;
+ color += texture(colorbuffer, uvcoordsvar.xy - 4.5 * invrendertargetdim) * 0.015625;
+
+ 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);
+ vec4 color = texture(colorbuffer, uvcoordsvar.xy);
+ vec4 color_blurred = texture(blurredcolorbuffer, uvcoordsvar.xy);
float coc = 2.0 * max(color_blurred.a, color.a); -color.a;
- gl_FragColor = vec4(color.rgb, coc);
+ 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);
+ vec4 color = texture(colorbuffer, uvcoordsvar.xz);
+ color += texture(colorbuffer, uvcoordsvar.yz);
+ color += texture(colorbuffer, uvcoordsvar.xw);
+ color += texture(colorbuffer, uvcoordsvar.yw);
- gl_FragColor = color / 4.0;
+ FragColor = color / 4.0;
}
vec4 small_sample_blur(in sampler2D colorbuffer, in vec2 uv, in vec4 color)
@@ -150,10 +151,10 @@ vec4 small_sample_blur(in sampler2D colorbuffer, in vec2 uv, in vec4 color)
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);
+ result += weight * texture(colorbuffer, uv + color_uv1.xy);
+ result += weight * texture(colorbuffer, uv - color_uv1.xy);
+ result += weight * texture(colorbuffer, uv + color_uv1.yx);
+ result += weight * texture(colorbuffer, uv - color_uv1.yx);
return result;
}
@@ -163,11 +164,11 @@ vec4 small_sample_blur(in sampler2D colorbuffer, in vec2 uv, in vec4 color)
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 color_orig = texture(colorbuffer, uvcoordsvar.xy);
+ vec4 highblurred = texture(blurredcolorbuffer, uvcoordsvar.xy);
+ vec4 mediumblurred = texture(mblurredcolorbuffer, uvcoordsvar.xy);
vec4 smallblurred = small_sample_blur(colorbuffer, uvcoordsvar.xy, color_orig);
- float depth = texture2D(depthbuffer, uvcoordsvar.xy).r;
+ float depth = texture(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);
@@ -188,7 +189,7 @@ void fifth_pass()
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);
+ FragColor = vec4(color.rgb, color_orig.a);
}
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
index 182113367d3..c41c1d0820b 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl
@@ -14,24 +14,28 @@ uniform sampler2D depthbuffer;
uniform sampler2D cocbuffer;
-/* this includes focal distance in x and aperture size in y */
+/* this includes aperture size in x and focal distance in y */
uniform vec4 dof_params;
/* viewvectors for reconstruction of world space */
uniform vec4 viewvecs[3];
/* initial uv coordinate */
-varying vec2 uvcoord;
+in vec2 uvcoord;
/* coordinate used for calculating radius et al set in geometry shader */
-varying vec2 particlecoord;
-varying vec4 color;
+in vec2 particlecoord;
+flat in vec4 color;
/* downsampling coordinates */
-varying vec2 downsample1;
-varying vec2 downsample2;
-varying vec2 downsample3;
-varying vec2 downsample4;
+in vec2 downsample1;
+in vec2 downsample2;
+in vec2 downsample3;
+in vec2 downsample4;
+
+layout(location = 0) out vec4 fragData0;
+layout(location = 1) out vec4 fragData1;
+layout(location = 2) out vec4 fragData2;
#define M_PI 3.1415926535897932384626433832795
@@ -55,15 +59,15 @@ void downsample_pass()
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);
+ vec4 color1 = texture(colorbuffer, downsample1);
+ vec4 color2 = texture(colorbuffer, downsample2);
+ vec4 color3 = texture(colorbuffer, downsample3);
+ vec4 color4 = texture(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;
+ depth.r = texture(depthbuffer, downsample1).r;
+ depth.g = texture(depthbuffer, downsample2).r;
+ depth.b = texture(depthbuffer, downsample3).r;
+ depth.a = texture(depthbuffer, downsample4).r;
zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), depth);
coc = calculate_coc(zdepth);
@@ -82,16 +86,16 @@ void downsample_pass()
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 +
+ fragData0 = 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 +
+ fragData1 = 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;
+ fragData0 /= norm_near;
if (norm_far > 0.0)
- gl_FragData[1] /= norm_far;
- gl_FragData[2] = vec4(near_coc, far_coc, 0.0, 1.0);
+ fragData1 /= norm_far;
+ fragData2 = vec4(near_coc, far_coc, 0.0, 1.0);
}
/* accumulate color in the near/far blur buffers */
@@ -102,36 +106,36 @@ void accumulate_pass(void) {
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))));
+ 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;
+ fragData0 = color;
}
-#define MERGE_THRESHOLD 4.0
+#define MERGE_THRESHOLD 4.0
/* combine the passes, */
void final_pass(void) {
vec4 finalcolor;
float totalweight;
- float depth = texture2D(depthbuffer, uvcoord).r;
+ float depth = texture(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);
+ vec4 farcolor = texture(farbuffer, uvcoord);
float farweight = farcolor.a;
if (farweight > 0.0)
farcolor /= farweight;
- vec4 nearcolor = texture2D(nearbuffer, uvcoord);
+ vec4 nearcolor = texture(nearbuffer, uvcoord);
- vec4 srccolor = texture2D(colorbuffer, uvcoord);
+ vec4 srccolor = texture(colorbuffer, uvcoord);
- vec4 coc = texture2D(cocbuffer, uvcoord);
+ vec4 coc = texture(cocbuffer, uvcoord);
float mixfac = smoothstep(1.0, MERGE_THRESHOLD, coc_far);
finalcolor = mix(srccolor, farcolor, mixfac);
@@ -152,7 +156,9 @@ void final_pass(void) {
finalcolor = mix(finalcolor, nearcolor, nearweight / totalweight);
}
- gl_FragData[0] = finalcolor;
+ fragData0 = finalcolor;
+ // fragData0 = vec4(nearweight, farweight, 0.0, 1.0);
+ // fragData0 = vec4(nearcolor.rgb, 1.0);
}
void main()
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
index 4c650e7695f..52d0a9be499 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl
@@ -5,27 +5,14 @@ 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
+layout(points) in;
+layout(triangle_strip, max_vertices = 4) out;
+
+#define POS gl_in[0].gl_Position
+
+in vec2 uvcoord[];
+out vec2 particlecoord;
+flat out vec4 color;
#define M_PI 3.1415926535897932384626433832795
@@ -46,21 +33,23 @@ void main()
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;
+
+ gl_Position = POS + vec4(-offset_far.x, -offset_far.y, 0.0, 0.0);
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
index 09a0c75facc..1dd5bf42b25 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl
@@ -1,27 +1,31 @@
-uniform vec2 invrendertargetdim;
-uniform ivec2 rendertargetdim;
+
+in vec2 pos;
+in vec2 uvs;
/* initial uv coordinate */
-varying vec2 uvcoord;
+out vec2 uvcoord;
/* coordinate used for calculating radius et al set in geometry shader */
-varying vec2 particlecoord;
+out vec2 particlecoord;
/* downsampling coordinates */
-varying vec2 downsample1;
-varying vec2 downsample2;
-varying vec2 downsample3;
-varying vec2 downsample4;
+out vec2 downsample1;
+out vec2 downsample2;
+out vec2 downsample3;
+out vec2 downsample4;
+
+uniform vec2 invrendertargetdim;
+uniform ivec2 rendertargetdim;
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;
+ downsample1 = uvs.xy + vec2(-0.5, -0.5) * invrendertargetdim;
+ downsample2 = uvs.xy + vec2(-0.5, 0.5) * invrendertargetdim;
+ downsample3 = uvs.xy + vec2(0.5, 0.5) * invrendertargetdim;
+ downsample4 = uvs.xy + vec2(0.5, -0.5) * invrendertargetdim;
- gl_Position = gl_Vertex;
+ gl_Position = vec4(pos, 0.0, 1.0);
}
/* geometry shading pass, calculate a texture coordinate based on the indexed id */
@@ -42,8 +46,8 @@ void vert_dof_coc_scatter_pass()
void vert_dof_final()
{
- uvcoord = gl_MultiTexCoord0.xy;
- gl_Position = gl_Vertex;
+ uvcoord = uvs;
+ gl_Position = vec4(pos, 0.0, 1.0);
}
void main()
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl
index 63b57d5775c..0fcab6302e4 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl
@@ -1,51 +1,54 @@
uniform vec2 invrendertargetdim;
-//texture coordinates for framebuffer read
-varying vec4 uvcoordsvar;
+in vec2 pos;
+in vec2 uvs;
+
+/* texture coordinates for framebuffer read */
+out vec4 uvcoordsvar;
/* color texture coordinates, offset by a small amount */
-varying vec2 color_uv1;
-varying vec2 color_uv2;
+out vec2 color_uv1;
+out vec2 color_uv2;
-varying vec2 depth_uv1;
-varying vec2 depth_uv2;
-varying vec2 depth_uv3;
-varying vec2 depth_uv4;
+out vec2 depth_uv1;
+out vec2 depth_uv2;
+out vec2 depth_uv3;
+out vec2 depth_uv4;
//very simple shader for gull screen FX, just pass values on
void vert_generic()
{
- uvcoordsvar = gl_MultiTexCoord0;
- gl_Position = gl_Vertex;
+ uvcoordsvar = vec4(uvs, 0.0, 0.0);
+ gl_Position = vec4(pos, 0.0, 1.0);
}
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;
+ color_uv1 = uvs.xy + vec2(-1.5, -1.5) * invrendertargetdim;
+ color_uv2 = uvs.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;
+ depth_uv1 = uvs.xy + vec2(-1.5, -1.5) * invrendertargetdim;
+ depth_uv2 = uvs.xy + vec2(-0.5, -1.5) * invrendertargetdim;
+ depth_uv3 = uvs.xy + vec2(0.5, -1.5) * invrendertargetdim;
+ depth_uv4 = uvs.xy + vec2(1.5, -1.5) * invrendertargetdim;
- gl_Position = gl_Vertex;
+ gl_Position = vec4(pos, 0.0, 1.0);
}
void vert_dof_fourth_pass()
{
vec4 halfpixel = vec4(-0.5, 0.5, -0.5, 0.5);
- uvcoordsvar = gl_MultiTexCoord0.xxyy +
+ uvcoordsvar = uvs.xxyy +
halfpixel *
vec4(invrendertargetdim.x,
invrendertargetdim.x,
invrendertargetdim.y,
invrendertargetdim.y);
- gl_Position = gl_Vertex;
+ gl_Position = vec4(pos, 0.0, 1.0);
}
void vert_dof_fifth_pass()
@@ -53,8 +56,8 @@ 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;
+ uvcoordsvar = vec4(uvs, 0.0, 0.0);
+ gl_Position = vec4(pos, 0.0, 1.0);
}
void main()
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl b/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl
index 1dc49b52be1..7aa6786d292 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl
@@ -1,14 +1,17 @@
+uniform mat4 ProjectionMatrix;
+
/* 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]);
+ float zview = -ProjectionMatrix[3][2] / (d + ProjectionMatrix[2][2]);
return zview * (viewvec_origin + vec3(uvcoords, 0.0) * viewvec_diff);
}
@@ -18,7 +21,7 @@ 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]));
+ return vec4(ProjectionMatrix[3][2]) / (d + vec4(ProjectionMatrix[2][2]));
}
#else
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
index 054a2f795ee..4904010c841 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
@@ -1,3 +1,4 @@
+
// color buffer
uniform sampler2D colorbuffer;
@@ -9,8 +10,10 @@ uniform sampler1D ssao_concentric_tex;
// depth buffer
uniform sampler2D depthbuffer;
+
// coordinates on framebuffer in normalized (0.0-1.0) uv space
-varying vec4 uvcoordsvar;
+in vec4 uvcoordsvar;
+out vec4 FragColor;
/* ssao_params.x : pixel scale for the ssao radious */
/* ssao_params.y : factor for the ssao darkening */
@@ -27,14 +30,13 @@ vec3 calculate_view_space_normal(in vec3 viewposition)
{
vec3 normal = cross(normalize(dFdx(viewposition)),
ssao_params.w * normalize(dFdy(viewposition)));
- normalize(normal);
- return normal;
+ 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 rotX = texture(jitter_tex, uvcoordsvar.xy * ssao_sample_params.yz).rg;
vec2 rotY = vec2(-rotX.y, rotX.x);
/* occlusion is zero in full depth */
@@ -47,9 +49,9 @@ float calculate_ssao_factor(float depth)
/* 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;
+ float homcoord = ProjectionMatrix[2][3] * position.z + ProjectionMatrix[3][3];
+ offset.x = ProjectionMatrix[0][0] * ssao_params.x / homcoord;
+ offset.y = 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;
@@ -58,7 +60,7 @@ float calculate_ssao_factor(float depth)
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;
+ vec2 dir_sample = texture(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));
@@ -68,7 +70,7 @@ float calculate_ssao_factor(float depth)
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;
+ float depth_new = texture(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;
@@ -76,7 +78,7 @@ float calculate_ssao_factor(float depth)
float f = dot(dir, normal);
/* use minor bias here to avoid self shadowing */
- if (f > 0.05 * len + 0.0001)
+ if (f > 0.05 * len)
factor += f * 1.0 / (len * (1.0 + len * len * ssao_params.z));
}
}
@@ -88,8 +90,8 @@ float calculate_ssao_factor(float depth)
void main()
{
- float depth = texture2D(depthbuffer, uvcoordsvar.xy).r;
- vec4 scene_col = texture2D(colorbuffer, uvcoordsvar.xy);
+ float depth = texture(depthbuffer, uvcoordsvar.xy).r;
+ vec4 scene_col = texture(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);
+ 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 6f063883e37..7586050b258 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,6 +32,18 @@ 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;
@@ -57,7 +70,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();
}
@@ -78,7 +91,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_image_alpha_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_alpha_color_frag.glsl
new file mode 100644
index 00000000000..727c3c0a832
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_image_alpha_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).r * color;
+}
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_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_interlace_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_interlace_frag.glsl
new file mode 100644
index 00000000000..7f3e7df40ac
--- /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 sampler2DRect image_a;
+uniform sampler2DRect 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..c2b25cc8011
--- /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);
+} \ No newline at end of file
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_rect_modulate_alpha_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_rect_modulate_alpha_frag.glsl
new file mode 100644
index 00000000000..7d9ce9d2003
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_image_rect_modulate_alpha_frag.glsl
@@ -0,0 +1,12 @@
+
+in vec2 texCoord_interp;
+out vec4 fragColor;
+
+uniform float alpha;
+uniform sampler2DRect image;
+
+void main()
+{
+ fragColor = texture(image, texCoord_interp);
+ fragColor.a *= alpha;
+}
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_instance_bone_envelope_solid_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_solid_vert.glsl
new file mode 100644
index 00000000000..74c8f6f3103
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_solid_vert.glsl
@@ -0,0 +1,122 @@
+
+
+/* This shader essentially operates in Object space, where it aligns given geometry with bone, scales it accordingly
+ * to given radii, and then does usual basic solid operations.
+ * Note that if one of head/tail radius is negative, it assumes it only works on the other end of the bone
+ * (used to draw head/tail spheres). */
+
+
+uniform mat4 ViewMatrix;
+uniform mat4 ObjectModelMatrix;
+uniform mat4 ViewProjectionMatrix;
+
+
+/* ---- Instanciated Attribs ---- */
+in vec4 pos; /* w encodes head (== 0.0f), tail (== 1.0f) or in-between. */
+
+/* ---- Per instance Attribs ---- */
+in mat4 InstanceModelMatrix;
+in vec4 color;
+
+in float radius_head;
+in float radius_tail;
+
+
+out vec3 normal;
+flat out vec4 finalColor;
+
+
+void main()
+{
+ /* We get head/tail in object space. */
+ vec4 head = InstanceModelMatrix * vec4(0.0f, 0.0f, 0.0f, 1.0f);
+ vec4 tail = InstanceModelMatrix * vec4(0.0f, 1.0f, 0.0f, 1.0f);
+
+ /* We need rotation from bone mat, but not scaling. */
+ mat3 bone_mat = mat3(InstanceModelMatrix);
+ bone_mat[0] = normalize(bone_mat[0]);
+ bone_mat[1] = normalize(bone_mat[1]);
+ bone_mat[2] = normalize(bone_mat[2]);
+
+ mat3 nor_mat = transpose(inverse(mat3(ViewMatrix * ObjectModelMatrix) * bone_mat));
+
+ /* Where does this comes from???? Don't know why, but is mandatory anyway... :/ */
+ const float size = 2.0f;
+
+ head.xyz *= size;
+ tail.xyz *= size;
+
+ bool head_only = (radius_tail < 0.0f);
+ bool tail_only = (radius_head < 0.0f);
+ /* == 0: head; == 1: tail; in-between: along bone. */
+ float head_fac = head_only ? 0.0f : (tail_only ? 1.0f : pos.w);
+
+ vec4 ob_pos;
+ vec4 ob_bone_origin;
+ float radius;
+
+ /* head */
+ if (head_fac <= 0.0f) {
+ if (!head_only) {
+ /* We are drawing the body itself, need to adjust start/end positions and radius! */
+ vec3 bone_vec = tail.xyz - head.xyz;
+ float len = length(bone_vec);
+
+ if (len > (radius_head + radius_tail)) {
+ float fac = (len - radius_head) / len;
+ radius = fac * radius_head + (1.0f - fac) * radius_tail;
+ bone_vec /= len;
+ ob_bone_origin = vec4(head.xyz + bone_vec * radius_head * size, 1.0f);
+ }
+ else {
+ radius = (radius_head + radius_tail) / 2.0f;
+ ob_bone_origin = (head + tail) / 2.0f;
+ }
+ }
+ else {
+ radius = radius_head;
+ ob_bone_origin = head;
+ }
+ }
+ /* tail */
+ else if (head_fac >= 1.0f) {
+ if (!tail_only) {
+ /* We are drawing the body itself, need to adjust start/end positions and radius! */
+ vec3 bone_vec = tail.xyz - head.xyz;
+ float len = length(bone_vec);
+
+ if (len > (radius_head + radius_tail)) {
+ float fac = (len - radius_tail) / len;
+ radius = fac * radius_tail + (1.0f - fac) * radius_head;
+ bone_vec /= len;
+ ob_bone_origin = vec4(tail.xyz - bone_vec * radius_tail * size, 1.0f);
+ }
+ else {
+ radius = (radius_head + radius_tail) / 2.0f;
+ ob_bone_origin = (head + tail) / 2.0f;
+ }
+ }
+ else {
+ radius = radius_tail;
+ ob_bone_origin = tail;
+ }
+ }
+ /* Body of the bone */
+#if 0 /* Note: not used currently! */
+ else {
+ float tail_fac = 1.0f - head_fac;
+ radius = radius_head * head_fac + radius_tail * tail_fac;
+ ob_bone_origin = head * head_fac + tail * tail_fac;
+ }
+#endif
+
+ /* Yep, since input pos is unit sphere coordinates, it's also our normal. */
+ vec3 nor = pos.xyz;
+ ob_pos = pos * radius * size;
+ ob_pos.xyz = bone_mat * ob_pos.xyz;
+ ob_pos.w = 1.0f;
+
+ gl_Position = ViewProjectionMatrix * ObjectModelMatrix * (ob_pos + ob_bone_origin);
+ normal = normalize(nor_mat * nor);
+ finalColor = color;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_wire_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_wire_vert.glsl
new file mode 100644
index 00000000000..a36eb1dec77
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_wire_vert.glsl
@@ -0,0 +1,103 @@
+
+
+/* This shader takes a 2D shape, puts it in 3D Object space such that is stays aligned with view and bone,
+ * and scales head/tail/distance according to per-instance attributes
+ * (and 'role' of current vertex, encoded in zw input, head or tail, and inner or outer for distance outline).
+ * It is used for both the distance outline drawing, and the wire version of envelope bone.
+ * Note that if one of head/tail radius is negative, it assumes it only works on the other end of the bone
+ * (used to draw head/tail spheres). */
+
+
+uniform mat4 ViewMatrix;
+uniform mat4 ProjectionMatrix;
+uniform mat4 ObjectModelMatrix;
+
+
+/* ---- Instanciated Attribs ---- */
+in vec4 pos; /* z encodes head (== 0.0f), tail (== 1.0f) or in-between; w encodes inner (0.0f) or outer border. */
+
+/* ---- Per instance Attribs ---- */
+in mat4 InstanceModelMatrix;
+in vec4 color;
+
+in float radius_head;
+in float radius_tail;
+in float distance;
+
+
+flat out vec4 finalColor;
+
+
+void main()
+{
+ /* We get head/tail in object space. */
+ mat4 bone_mat = InstanceModelMatrix;
+ vec4 head = bone_mat * vec4(0.0f, 0.0f, 0.0f, 1.0f);
+ vec4 tail = bone_mat * vec4(0.0f, 1.0f, 0.0f, 1.0f);
+
+ /* We generate our XY axes in object space, Y axis being aligned with bone in view space. */
+ mat4 obview_mat = ViewMatrix * ObjectModelMatrix;
+ mat4 iobview_mat = inverse(obview_mat);
+
+ vec4 view_bone_vec = obview_mat * normalize(tail - head);
+ view_bone_vec.z = 0.0f;
+ if (length(view_bone_vec.xy) <= 1e-5f) {
+ /* A bit weak, but will do the job for now.
+ * Ideally we could compute head/tail radius in view space, and take larger one... */
+ if (view_bone_vec.x > view_bone_vec.y) {
+ view_bone_vec.x = 1e-5f;
+ }
+ else {
+ view_bone_vec.y = 1e-5f;
+ }
+ }
+ vec3 bone_axis_y = normalize((iobview_mat * view_bone_vec).xyz);
+ vec3 bone_axis_x = normalize(cross(bone_axis_y, iobview_mat[2].xyz));
+
+ /* Where does this comes from???? Don't know why, but is mandatory anyway... :/ */
+ float size = 2.0f;
+
+ head.xyz *= size;
+ tail.xyz *= size;
+
+ bool head_only = (radius_tail < 0.0f);
+ bool tail_only = (radius_head < 0.0f);
+ /* == 0: head; == 1: tail; in-between: along bone. */
+ float head_fac = head_only ? 0.0f : (tail_only ? 1.0f : pos.z);
+ bool do_distance_offset = (pos.w != 0.0f) && (distance >= 0.0f);
+
+ vec2 xy_pos = pos.xy;
+ vec4 ob_pos;
+
+ vec4 ob_bone_origin;
+ float radius;
+
+ /* head */
+ if (head_fac <= 0.0f) {
+ radius = radius_head;
+ ob_bone_origin = head;
+ }
+ /* tail */
+ else if (head_fac >= 1.0f) {
+ radius = radius_tail;
+ ob_bone_origin = tail;
+ }
+ /* Body of the bone */
+#if 0 /* Note: not used currently! */
+ else {
+ float tail_fac = 1.0f - head_fac;
+ radius = radius_head * head_fac + radius_tail * tail_fac;
+ ob_bone_origin = head * head_fac + tail * tail_fac;
+ }
+#endif
+
+ if (do_distance_offset) {
+ radius += distance;
+ }
+
+ xy_pos = xy_pos * radius * size;
+
+ ob_pos = ob_bone_origin + vec4(bone_axis_x * xy_pos.x + bone_axis_y * xy_pos.y, 1.0f);
+ gl_Position = ProjectionMatrix * obview_mat * ob_pos;
+ finalColor = color;
+}
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..aec8fd9b0a1
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl
@@ -0,0 +1,50 @@
+
+uniform mat4 ViewProjectionMatrix;
+
+/* ---- Instanciated 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..142df70e68a
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl
@@ -0,0 +1,25 @@
+
+uniform mat4 ViewProjectionMatrix;
+
+/* ---- Instanciated 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);
+} \ No newline at end of file
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..6f580ef3ff6
--- /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..195d4849d99
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl
@@ -0,0 +1,29 @@
+
+uniform mat4 ViewMatrix;
+uniform mat4 ViewProjectionMatrix;
+uniform mat4 ObjectModelMatrix;
+
+/* ---- Instanciated 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 FinalModelMatrix = ObjectModelMatrix * InstanceModelMatrix;
+ mat4 ModelViewProjectionMatrix = ViewProjectionMatrix * FinalModelMatrix;
+ /* 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 * FinalModelMatrix)));
+
+ 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..2ee74b3eae0
--- /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];
+
+/* ---- Instanciated 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..ba0ac29fb79
--- /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;
+
+/* ---- Instanciated 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..10a2ba61a2c
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl
@@ -0,0 +1,22 @@
+
+uniform mat4 ViewProjectionMatrix;
+
+/* ---- Instanciated 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, 1.0);
+}
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..eac167e8045
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl
@@ -0,0 +1,13 @@
+
+uniform mat4 ViewProjectionMatrix;
+
+/* ---- Instanciated 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..7f445369833
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_frag.glsl
@@ -0,0 +1,31 @@
+
+in vec4 radii;
+in vec4 finalColor;
+in vec4 finalOutlineColor;
+out vec4 fragColor;
+
+void main() {
+ vec2 quad = abs(gl_PointCoord - vec2(0.5));
+ float dist = quad.x + quad.y;
+
+// 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 mid_stroke = 0.5 * (radii[1] + radii[2]);
+
+ vec4 backgroundColor = vec4(finalOutlineColor.rgb, 0.0);
+
+ if (dist > mid_stroke)
+ fragColor = mix(finalOutlineColor, backgroundColor, smoothstep(radii[1], radii[0], dist));
+ else
+ fragColor = mix(finalColor, finalOutlineColor, smoothstep(radii[3], radii[2], dist));
+}
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..b86d6fd70fe
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_vert.glsl
@@ -0,0 +1,34 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+const float pixel_fudge = sqrt(2.0);
+const float outline_width = 1.25 * pixel_fudge;
+
+in vec2 pos;
+in float size;
+in vec4 color;
+in vec4 outlineColor;
+out vec4 finalColor;
+out vec4 finalOutlineColor;
+out vec4 radii;
+
+void main() {
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
+
+ // pass through unchanged
+ gl_PointSize = size + pixel_fudge; // 0.5 pixel_fudge on either side
+ finalColor = color;
+ finalOutlineColor = outlineColor;
+
+ // calculate concentric radii in pixels
+ float radius = 0.5 * gl_PointSize;
+
+ // start at the outside and progress toward the center
+ radii[0] = radius;
+ radii[1] = radius - pixel_fudge;
+ radii[2] = radius - outline_width;
+ radii[3] = radius - outline_width - pixel_fudge;
+
+ // convert to PointCoord units
+ radii /= size;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index 845a78720ba..81f70332876 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -1,11 +1,57 @@
+
+uniform mat4 ModelViewMatrix;
+#ifndef EEVEE_ENGINE
+uniform mat4 ProjectionMatrix;
+uniform mat4 ViewMatrixInverse;
+uniform mat4 ViewMatrix;
+#endif
+uniform mat4 ModelMatrix;
+uniform mat4 ModelMatrixInverse;
+uniform mat4 ModelViewMatrixInverse;
+uniform mat4 ProjectionMatrixInverse;
+uniform mat3 NormalMatrix;
+uniform vec4 CameraTexCoFactors;
+
+/* Old glsl mode compat. */
+
+#ifndef CLOSURE_DEFAULT
+
+struct Closure {
+ vec3 radiance;
+ float opacity;
+};
+
+#define CLOSURE_DEFAULT Closure(vec3(0.0), 1.0)
+
+Closure closure_mix(Closure cl1, Closure cl2, float fac)
+{
+ Closure cl;
+ cl.radiance = mix(cl1.radiance, cl2.radiance, fac);
+ cl.opacity = mix(cl1.opacity, cl2.opacity, fac);
+ return cl;
+}
+
+Closure closure_add(Closure cl1, Closure cl2)
+{
+ Closure cl;
+ cl.radiance = cl1.radiance + cl2.radiance;
+ cl.opacity = cl1.opacity + cl2.opacity;
+ return cl;
+}
+
+Closure nodetree_exec(void); /* Prototype */
+
+#endif /* CLOSURE_DEFAULT */
+
+
/* 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;
+ return dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
#else
- return (color.r + color.g + color.b) / 3.0;
+ return (color.r + color.g + color.b) * 0.333333;
#endif
}
@@ -53,7 +99,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];
@@ -155,15 +201,18 @@ void color_to_blender_normal_new_shading(vec3 color, out vec3 normal)
normal.y = -2.0 * ((color.g) - 0.5);
normal.z = -2.0 * ((color.b) - 0.5);
}
-
+#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);
+ vcol = vec4(attvcol.xyz, 1.0);
}
void uv_attribute(vec2 attuv, out vec3 uv)
@@ -177,7 +226,7 @@ void geom(
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);
+ view = (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);
@@ -403,7 +452,7 @@ void math_modulo(float val1, float val2, out float outval)
/* change sign to match C convention, mod in GLSL will take absolute for negative numbers,
* see https://www.opengl.org/sdk/docs/man/html/mod.xhtml */
- outval = (val1 > 0.0) ? outval : -outval;
+ outval = (val1 > 0.0) ? outval : outval - val2;
}
void math_abs(float val1, out float outval)
@@ -419,13 +468,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)
@@ -441,7 +490,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);
}
@@ -483,9 +532,9 @@ void normal_new_shading(vec3 dir, vec3 nor, out vec3 outnor, out float outdot)
void curves_vec(float fac, vec3 vec, sampler2D curvemap, 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;
+ outvec.x = texture(curvemap, vec2((vec.x + 1.0) * 0.5, 0.0)).x;
+ outvec.y = texture(curvemap, vec2((vec.y + 1.0) * 0.5, 0.0)).y;
+ outvec.z = texture(curvemap, vec2((vec.z + 1.0) * 0.5, 0.0)).z;
if (fac != 1.0)
outvec = (outvec * fac) + (vec * (1.0 - fac));
@@ -494,9 +543,9 @@ void curves_vec(float fac, vec3 vec, sampler2D curvemap, out vec3 outvec)
void curves_rgb(float fac, vec4 col, sampler2D curvemap, 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;
+ outcol.r = texture(curvemap, vec2(texture(curvemap, vec2(col.r, 0.0)).a, 0.0)).r;
+ outcol.g = texture(curvemap, vec2(texture(curvemap, vec2(col.g, 0.0)).a, 0.0)).g;
+ outcol.b = texture(curvemap, vec2(texture(curvemap, vec2(col.b, 0.0)).a, 0.0)).b;
if (fac != 1.0)
outcol = (outcol * fac) + (col * (1.0 - fac));
@@ -816,22 +865,23 @@ void mix_linear(float fac, vec4 col1, vec4 col2, out vec4 outcol)
void valtorgb(float fac, sampler2D colormap, out vec4 outcol, out float outalpha)
{
- outcol = texture2D(colormap, vec2(fac, 0.0));
+ outcol = texture(colormap, vec2(fac, 0.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;
+ vec3 factors = vec3(0.2126, 0.7152, 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 */
+ vec3 factors = vec3(0.35, 0.45, 0.2); /* keep these factors in sync with texture.h:RGBTOBW */
#endif
+ 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;
}
@@ -916,12 +966,12 @@ void texture_flip_blend(vec3 vec, out vec3 outvec)
void texture_blend_lin(vec3 vec, out float outval)
{
- outval = (1.0 + vec.x) / 2.0;
+ outval = (1.0 + vec.x) * 0.5;
}
void texture_blend_quad(vec3 vec, out float outval)
{
- outval = max((1.0 + vec.x) / 2.0, 0.0);
+ outval = max((1.0 + vec.x) * 0.5, 0.0);
outval *= outval;
}
@@ -932,12 +982,12 @@ void texture_wood_sin(vec3 vec, out float value, out vec4 color, out vec3 normal
value = wi;
color = vec4(wi, wi, wi, 1.0);
- normal = vec3(0.0, 0.0, 0.0);
+ normal = vec3(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);
+ color = texture(ima, (vec.xy + vec2(1.0)) * 0.5);
value = color.a;
normal.x = 2.0 * (color.r - 0.5);
@@ -955,7 +1005,7 @@ void texco_orco(vec3 attorco, out vec3 orco)
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 * 2.0 - vec2(1.0), 0.0); */
uv = vec3(attuv, 0.0);
}
@@ -1277,11 +1327,7 @@ void mtex_har_divide(float har, out float outhar)
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;
+ outhar = clamp(har * 128.0, 1.0, 511.0);
}
void mtex_alpha_from_col(vec4 col, out float alpha)
@@ -1350,15 +1396,15 @@ vec3 mtex_2d_mapping(vec3 vec)
void mtex_cube_map(vec3 co, samplerCube ima, out float value, out vec4 color)
{
- color = textureCube(ima, co);
+ color = texture(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 = 1.0;
+ color = texture(ima, reflecteddirection);
+ value = color.a;
}
void mtex_cube_map_refl(
@@ -1368,13 +1414,13 @@ void mtex_cube_map_refl(
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);
+ color = texture(ima, reflecteddirection);
value = 1.0;
}
void mtex_image(vec3 texco, sampler2D ima, out float value, out vec4 color)
{
- color = texture2D(ima, texco.xy);
+ color = texture(ima, texco.xy);
value = 1.0;
}
@@ -1385,7 +1431,7 @@ void mtex_normal(vec3 texco, sampler2D ima, out vec3 normal)
// 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);
+ vec4 color = texture(ima, texco.xy);
normal = 2.0 * (vec3(-color.r, color.g, color.b) - vec3(-0.5, 0.5, 0.5));
}
@@ -1413,8 +1459,8 @@ void mtex_bump_init_objspace(
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);
+ mat3 obj2view = to_mat3(ModelViewMatrix);
+ mat3 view2obj = to_mat3(ModelViewMatrixInverse);
vec3 vSigmaS = view2obj * dFdx(surf_pos);
vec3 vSigmaT = view2obj * dFdy(surf_pos);
@@ -1481,9 +1527,9 @@ void mtex_bump_tap3(
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);
+ rgbtobw(texture(ima, STll), Hll);
+ rgbtobw(texture(ima, STlr), Hlr);
+ rgbtobw(texture(ima, STul), Hul);
dBs = hScale * (Hlr - Hll);
dBt = hScale * (Hul - Hll);
@@ -1508,10 +1554,10 @@ void mtex_bump_bicubic(
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);
+ rgbtobw(texture(ima, STl), Hl);
+ rgbtobw(texture(ima, STr), Hr);
+ rgbtobw(texture(ima, STd), Hd);
+ rgbtobw(texture(ima, STu), Hu);
vec2 dHdxy = vec2(Hr - Hl, Hu - Hd);
float fBlend = clamp(1.0 - textureQueryLOD(ima, texco.xy).x, 0.0, 1.0);
@@ -1597,11 +1643,11 @@ void mtex_bump_tap5(
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);
+ rgbtobw(texture(ima, STc), Hc);
+ rgbtobw(texture(ima, STl), Hl);
+ rgbtobw(texture(ima, STr), Hr);
+ rgbtobw(texture(ima, STd), Hd);
+ rgbtobw(texture(ima, STu), Hu);
dBs = hScale * (Hr - Hl);
dBt = hScale * (Hu - Hd);
@@ -1618,7 +1664,7 @@ void mtex_bump_deriv(
// 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);
+ vec2 dBduv = hScale * dim * (2.0 * texture(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;
@@ -1670,7 +1716,7 @@ void mtex_nspace_world(mat4 viewmat, vec3 texnormal, out vec3 outnormal)
void mtex_nspace_object(vec3 texnormal, out vec3 outnormal)
{
- outnormal = normalize(gl_NormalMatrix * texnormal);
+ outnormal = normalize(NormalMatrix * texnormal);
}
void mtex_blend_normal(float norfac, vec3 normal, vec3 newnormal, out vec3 outnormal)
@@ -1727,7 +1773,7 @@ void lamp_falloff_invcoefficients(float coeff_const, float coeff_lin, float coef
void lamp_falloff_curve(float lampdist, sampler2D curvemap, float dist, out float visifac)
{
- visifac = texture2D(curvemap, vec2(dist / lampdist, 0.0)).x;
+ visifac = texture(curvemap, vec2(dist / lampdist, 0.0)).x;
}
void lamp_visibility_sphere(float lampdist, float dist, float visifac, out float outvisifac)
@@ -1794,7 +1840,7 @@ void lamp_visibility_clamp(float visifac, out float outvisifac)
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);
+ outvec = (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)
@@ -1828,7 +1874,7 @@ void world_blend(vec3 vec, out float blend)
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);
+ view = (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)
@@ -2020,7 +2066,7 @@ 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);
+ outcol = vec3(0.0);
}
void shade_hemi_spec(vec3 vn, vec3 lv, vec3 view, float spec, float hard, float visifac, out float t)
@@ -2177,19 +2223,19 @@ void shade_madd(vec4 col, vec4 col1, vec4 col2, out vec4 outcol)
void shade_add_clamped(vec4 col1, vec4 col2, out vec4 outcol)
{
- outcol = col1 + max(col2, vec4(0.0, 0.0, 0.0, 0.0));
+ outcol = col1 + max(col2, vec4(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));
+ outcol = col + max(col1 * col2, vec4(0.0));
}
-void env_apply(vec4 col, vec4 hor, vec4 zen, vec4 f, mat4 vm, vec3 vn, out vec4 outcol)
+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 * mix(hor, zen, skyfac);
+ outcol = col + f * vec4(mix(hor, zen, skyfac), 0);
}
void shade_maddf(vec4 col, float f, vec4 col1, out vec4 outcol)
@@ -2219,7 +2265,7 @@ void shade_obcolor(vec4 col, vec4 obcol, out vec4 outcol)
void ramp_rgbtobw(vec3 color, out float outval)
{
- outval = color.r * 0.3 + color.g * 0.58 + color.b * 0.12;
+ outval = dot(color, vec3(0.3, 0.58, 0.12));
}
void shade_only_shadow(float i, float shadfac, float energy, vec3 shadcol, out vec3 outshadrgb)
@@ -2255,10 +2301,12 @@ void test_shadowbuf(
//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
+ 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 = textureProj(shadowmap, co);
+ }
+ else {
result = 1.0;
+ }
}
}
@@ -2272,7 +2320,7 @@ void test_shadowbuf_vsm(
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;
+ vec2 moments = textureProj(shadowmap, co).rg;
float dist = co.z / co.w;
float p = 0.0;
@@ -2331,7 +2379,7 @@ void shade_light_texture(vec3 rco, sampler2D cookie, mat4 shadowpersmat, out vec
vec4 co = shadowpersmat * vec4(rco, 1.0);
- result = texture2DProj(cookie, co);
+ result = textureProj(cookie, co);
}
void shade_exposure_correct(vec3 col, float linfac, float logfac, out vec3 outcol)
@@ -2346,7 +2394,7 @@ void shade_mist_factor(
if (enable == 1.0) {
float fac, zcor;
- zcor = (gl_ProjectionMatrix[3][3] == 0.0) ? length(co) : -co[2];
+ zcor = (ProjectionMatrix[3][3] == 0.0) ? length(co) : -co[2];
fac = clamp((zcor - miststa) / mistdist, 0.0, 1.0);
if (misttype == 0.0) fac *= fac;
@@ -2378,11 +2426,19 @@ void shade_alpha_obcolor(vec4 col, vec4 obcol, out vec4 outcol)
/*********** NEW SHADER UTILITIES **************/
-float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
+float fresnel_dielectric_0(float eta)
+{
+ /* compute fresnel reflactance at normal incidence => cosi = 1.0 */
+ float A = (eta - 1.0) / (eta + 1.0);
+
+ return A * A;
+}
+
+float fresnel_dielectric_cos(float cosi, float eta)
{
/* compute fresnel reflectance without explicitly computing
* the refracted direction */
- float c = abs(dot(Incoming, Normal));
+ float c = abs(cosi);
float g = eta * eta - 1.0 + c * c;
float result;
@@ -2399,6 +2455,13 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
return result;
}
+float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
+{
+ /* compute fresnel reflectance without explicitly computing
+ * the refracted direction */
+ return fresnel_dielectric_cos(dot(Incoming, Normal), eta);
+}
+
float hypot(float x, float y)
{
return sqrt(x * x + y * y);
@@ -2406,7 +2469,11 @@ float hypot(float x, float y)
void generated_from_orco(vec3 orco, out vec3 generated)
{
- generated = orco * 0.5 + vec3(0.5);
+#ifdef VOLUMETRICS
+ generated = worldPosition;
+#else
+ generated = orco;
+#endif
}
int floor_to_int(float x)
@@ -2419,7 +2486,6 @@ int quick_floor(float x)
return int(x) - ((x < 0) ? 1 : 0);
}
-#ifdef BIT_OPERATIONS
float integer_noise(int n)
{
int nn;
@@ -2484,7 +2550,6 @@ vec3 cellnoise_color(vec3 p)
return vec3(r, g, b);
}
-#endif // BIT_OPERATIONS
float floorfrac(float x, out int i)
{
@@ -2492,141 +2557,437 @@ float floorfrac(float x, out int i)
return x - i;
}
+
+/* Principled BSDF operations */
+
+float sqr(float a)
+{
+ return a*a;
+}
+
+float schlick_fresnel(float u)
+{
+ float m = clamp(1.0 - u, 0.0, 1.0);
+ float m2 = m * m;
+ return m2 * m2 * m; // pow(m,5)
+}
+
+float GTR1(float NdotH, float a)
+{
+ if (a >= 1.0) return M_1_PI;
+ float a2 = a*a;
+ float t = 1.0 + (a2 - 1.0) * NdotH*NdotH;
+ return (a2 - 1.0) / (M_PI * log(a2) * t);
+}
+
+float GTR2(float NdotH, float a)
+{
+ float a2 = a*a;
+ float t = 1.0 + (a2 - 1.0) * NdotH*NdotH;
+ return a2 / (M_PI * t*t);
+}
+
+float GTR2_aniso(float NdotH, float HdotX, float HdotY, float ax, float ay)
+{
+ return 1.0 / (M_PI * ax*ay * sqr(sqr(HdotX / ax) + sqr(HdotY / ay) + NdotH*NdotH));
+}
+
+float smithG_GGX(float NdotV, float alphaG)
+{
+ float a = alphaG*alphaG;
+ float b = NdotV*NdotV;
+ return 1.0 / (NdotV + sqrt(a + b - a * b));
+}
+
+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 prepare_tangent(
+ float anisotropic, float anisotropic_rotation, float roughness, vec3 N, vec3 T,
+ out vec3 X, out vec3 Y, out float ax, out float ay)
+{
+ /* rotate tangent */
+ if (anisotropic_rotation != 0.0) {
+ T = rotate_vector(T, N, anisotropic_rotation * 2.0 * M_PI);
+ }
+
+ Y = normalize(cross(T, N));
+
+ float aspect = sqrt(1.0 - anisotropic * 0.9);
+ float a = sqr(roughness);
+ ax = max(0.001, a / aspect);
+ ay = max(0.001, a * aspect);
+}
+
+void convert_metallic_to_specular(vec3 basecol, float metallic, float specular_fac, out vec3 diffuse, out vec3 f0)
+{
+ vec3 dielectric = vec3(0.034) * specular_fac * 2.0;
+ diffuse = mix(basecol, vec3(0.0), metallic);
+ f0 = mix(dielectric, basecol, metallic);
+}
+
+void convert_metallic_to_specular_tinted(
+ vec3 basecol, float metallic, float specular_fac, float specular_tint,
+ out vec3 diffuse, out vec3 f0)
+{
+ vec3 dielectric = vec3(0.034) * specular_fac * 2.0;
+ float lum = dot(basecol, vec3(0.3, 0.6, 0.1)); /* luminance approx. */
+ vec3 tint = lum > 0 ? basecol / lum : vec3(1.0); /* normalize lum. to isolate hue+sat */
+ f0 = mix(dielectric * mix(vec3(1.0), tint, specular_tint), basecol, metallic);
+ diffuse = mix(basecol, vec3(0.0), metallic);
+}
+
/*********** NEW SHADER NODES ***************/
#define NUM_LIGHTS 3
-/* bsdfs */
+struct glLight {
+ vec4 position;
+ vec4 diffuse;
+ vec4 specular;
+ vec4 halfVector;
+};
+
+layout(std140) uniform lightSource {
+ glLight glLightSource[NUM_LIGHTS];
+};
-void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out vec4 result)
+#ifndef VOLUMETRICS
+/* bsdfs */
+void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result)
{
+#ifdef EEVEE_ENGINE
+ vec3 L = eevee_surface_diffuse_lit(N, vec3(1.0), 1.0);
+#else
/* 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 light_diffuse = gl_LightSource[i].diffuse.rgb;
+ vec3 light_position = glLightSource[i].position.xyz;
+ vec3 light_diffuse = glLightSource[i].diffuse.rgb;
float bsdf = max(dot(N, light_position), 0.0);
L += light_diffuse * bsdf;
}
+#endif
- result = vec4(L * color.rgb, 1.0);
+ result = Closure(L * color.rgb, 1.0);
}
-void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out vec4 result)
+void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out Closure result)
{
+#ifdef EEVEE_ENGINE
+ vec3 L = eevee_surface_glossy_lit(N, vec3(1.0), roughness, 1.0);
+#else
/* ambient light */
vec3 L = vec3(0.2);
+ direction_transform_m4v3(N, ViewMatrix, N);
+
/* 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;
+ vec3 light_position = glLightSource[i].position.xyz;
+ vec3 H = glLightSource[i].halfVector.xyz;
+ vec3 light_diffuse = glLightSource[i].diffuse.rgb;
+ vec3 light_specular = glLightSource[i].specular.rgb;
/* we mix in some diffuse so low roughness still shows up */
float bsdf = 0.5 * pow(max(dot(N, H), 0.0), 1.0 / roughness);
bsdf += 0.5 * max(dot(N, light_position), 0.0);
L += light_specular * bsdf;
}
+#endif
- result = vec4(L * color.rgb, 1.0);
+ result = Closure(L * color.rgb, 1.0);
}
void node_bsdf_anisotropic(
vec4 color, float roughness, float anisotropy, float rotation, vec3 N, vec3 T,
- out vec4 result)
+ out Closure result)
{
node_bsdf_diffuse(color, 0.0, N, result);
}
-void node_bsdf_glass(vec4 color, float roughness, float ior, vec3 N, out vec4 result)
+void node_bsdf_glass(vec4 color, float roughness, float ior, 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_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out Closure result)
{
node_bsdf_diffuse(color, 0.0, N, result);
}
-void node_bsdf_translucent(vec4 color, vec3 N, out vec4 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, out Closure result)
+{
+ vec3 X, Y;
+ float ax, ay;
+ prepare_tangent(anisotropic, anisotropic_rotation, roughness, N, T, X, Y, ax, ay);
+
+ /* 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 = (ProjectionMatrix[3][3] == 0.0) ? -normalize(I) : vec3(0.0, 0.0, 1.0);
+
+ /* 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 = glLightSource[i].position.xyz;
+ vec3 light_position = normalize(light_position_world);
+
+ vec3 H = normalize(light_position + V);
+
+ vec3 light_diffuse = glLightSource[i].diffuse.rgb;
+ vec3 light_specular = glLightSource[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);
+
+ float Cdlum = dot(base_color.rgb, vec3(0.3, 0.6, 0.1)); // luminance approx.
+
+ 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);
+
+ // Diffuse fresnel - go from 1 at normal incidence to .5 at grazing
+ // and mix in diffuse retro-reflection based on roughness
+
+ 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);
+
+ // 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);
+
+ // specular
+ 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);
+
+ // sheen
+ vec3 Fsheen = schlick_fresnel(LdotH) * sheen * Csheen;
+
+ 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);
+
+ float CNdotL = dot(CN, light_position);
+ float CNdotV = dot(CN, V);
+
+ 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);
+
+ // 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);
+
+ clearcoat_bsdf = clearcoat * Gr * Fr * Dr * vec3(0.25) * light_specular;
+ }
+ clearcoat_bsdf *= max(CNdotL, 0.0);
+
+ L += diffuse_and_specular_bsdf + clearcoat_bsdf;
+ }
+
+ result = Closure(L, 1.0);
+}
+
+void node_bsdf_principled_simple(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 Closure result)
+{
+#ifdef EEVEE_ENGINE
+ vec3 diffuse, f0;
+ convert_metallic_to_specular_tinted(base_color.rgb, metallic, specular, specular_tint, diffuse, f0);
+
+ result = Closure(eevee_surface_lit(N, diffuse, f0, roughness, 1.0), 1.0);
+#else
+ node_bsdf_principled(base_color, subsurface, subsurface_radius, subsurface_color, metallic, specular,
+ specular_tint, roughness, anisotropic, anisotropic_rotation, sheen, sheen_tint, clearcoat,
+ clearcoat_roughness, ior, transmission, transmission_roughness, N, CN, T, I, result);
+#endif
+}
+
+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, out Closure result)
+{
+#ifdef EEVEE_ENGINE
+ vec3 diffuse, f0;
+ convert_metallic_to_specular_tinted(base_color.rgb, metallic, specular, specular_tint, diffuse, f0);
+
+ clearcoat *= 0.25;
+#if 0 /* Wait until temporal AA (aka. denoising) */
+
+ vec3 X, Y;
+ float ax, ay;
+ prepare_tangent(anisotropic, anisotropic_rotation, roughness, N, T, X, Y, ax, ay);
+
+ /* Distribute N in anisotropy direction. */
+ vec4 surface_color = vec4(0.0);
+ for (float i = 0.0; i < 5.0; ++i) {
+ vec4 rand = texture(utilTex, vec3((gl_FragCoord.xy + i) / LUT_SIZE, 2.0));
+
+ float tmp = sqrt( rand.x / (1.0 - rand.x) );
+ float x = (ax > ay ? ax : 0.0) * tmp * rand.z;
+ float y = (ay > ax ? ay : 0.0) * tmp * rand.w;
+ vec3 Ht = normalize(vec3(x, y, 1.0));
+ N = tangent_to_world(Ht, N, Y, X);
+
+ if (dot(N, cameraVec) > 0) {
+ surface_color.rgb += eevee_surface_clearcoat_lit(N, diffuse, f0, sqrt(min(ax, ay)), CN, clearcoat, clearcoat_roughness, 1.0);
+ surface_color.a += 1.0;
+ }
+ }
+ result = Closure(surface_color.rgb / surface_color.a, 1.0);
+#else
+ result = Closure(eevee_surface_clearcoat_lit(N, diffuse, f0, roughness, CN, clearcoat, clearcoat_roughness, 1.0), 1.0);
+#endif
+
+#else
+ node_bsdf_principled(base_color, subsurface, subsurface_radius, subsurface_color, metallic, specular,
+ specular_tint, roughness, anisotropic, anisotropic_rotation, sheen, sheen_tint, clearcoat,
+ clearcoat_roughness, ior, transmission, transmission_roughness, N, CN, T, I, result);
+#endif
+}
+
+void node_bsdf_translucent(vec4 color, vec3 N, out Closure result)
{
node_bsdf_diffuse(color, 0.0, N, result);
}
-void node_bsdf_transparent(vec4 color, out vec4 result)
+void node_bsdf_transparent(vec4 color, out Closure result)
{
/* this isn't right */
- result.r = color.r;
- result.g = color.g;
- result.b = color.b;
- result.a = 0.0;
+ result.radiance = color.rgb;
+ result.opacity = color.a;
}
-void node_bsdf_velvet(vec4 color, float sigma, 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_subsurface_scattering(
vec4 color, float scale, vec3 radius, float sharpen, float texture_blur, vec3 N,
- out vec4 result)
+ out Closure result)
{
node_bsdf_diffuse(color, 0.0, N, result);
}
-void node_bsdf_hair(vec4 color, float offset, float roughnessu, float roughnessv, vec3 tangent, out vec4 result)
+void node_bsdf_hair(vec4 color, float offset, float roughnessu, float roughnessv, vec3 tangent, out Closure result)
{
- result = color;
+ result = Closure(color.rgb, color.a);
}
-void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out vec4 result)
+void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Closure result)
{
node_bsdf_diffuse(color, 0.0, N, result);
}
-void node_ambient_occlusion(vec4 color, out vec4 result)
+void node_ambient_occlusion(vec4 color, out Closure result)
{
- result = color;
+ result = Closure(color.rgb, color.a);
}
+#endif /* VOLUMETRICS */
/* emission */
-void node_emission(vec4 color, float strength, vec3 N, out vec4 result)
+void node_emission(vec4 color, float strength, vec3 N, out Closure result)
{
- result = color * strength;
+#ifndef VOLUMETRICS
+ color *= strength;
+ result = Closure(color.rgb, color.a);
+#else
+ result = Closure(vec3(0.0), vec3(0.0), color.rgb * strength, 0.0);
+#endif
}
/* background */
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);
+ 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);
- worldvec = (gl_ModelViewMatrixInverse * co).xyz;
+#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
+ worldvec = (ViewMatrixInverse * co).xyz;
+#else
+ worldvec = (ModelViewMatrixInverse * co).xyz;
+#endif
+}
+
+void node_background(vec4 color, float strength, out Closure result)
+{
+#ifndef VOLUMETRICS
+ color *= strength;
+ result = Closure(color.rgb, color.a);
+#else
+ result = CLOSURE_DEFAULT;
+#endif
+}
+
+/* volumes */
+
+void node_volume_scatter(vec4 color, float density, float anisotropy, out Closure result)
+{
+#ifdef VOLUMETRICS
+ result = Closure(vec3(0.0), color.rgb * density, vec3(0.0), anisotropy);
+#else
+ result = CLOSURE_DEFAULT;
+#endif
}
-void node_background(vec4 color, float strength, vec3 N, out vec4 result)
+void node_volume_absorption(vec4 color, float density, out Closure result)
{
- result = color * strength;
+#ifdef VOLUMETRICS
+ result = Closure((1.0 - color.rgb) * density, vec3(0.0), vec3(0.0), 0.0);
+#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 */
@@ -2634,7 +2995,7 @@ void node_add_shader(vec4 shader1, vec4 shader2, out vec4 shader)
void node_fresnel(float ior, vec3 N, vec3 I, out float result)
{
/* 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);
@@ -2646,7 +3007,7 @@ void node_layer_weight(float blend, vec3 N, vec3 I, out float fresnel, out float
{
/* 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);
@@ -2688,24 +3049,56 @@ 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.25, 0.25);
+}
+
+void tangent_orco_y(vec3 orco_in, out vec3 orco_out)
+{
+ orco_out = orco_in.zyx * 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.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)
+{
+ N = (toworld * vec4(N, 0.0)).xyz;
+ 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,
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)
{
+#ifdef EEVEE_ENGINE
+ position = worldPosition;
+#else
position = (toworld * vec4(I, 1.0)).xyz;
+#endif
normal = (toworld * vec4(N, 0.0)).xyz;
- tangent = vec3(0.0);
+ tangent_orco_z(orco, orco);
+ node_tangent(N, orco, objmat, toworld, tangent);
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);
backfacing = (gl_FrontFacing) ? 0.0 : 1.0;
- pointiness = 0.0;
+ pointiness = 0.5;
}
void node_tex_coord(
@@ -2714,12 +3107,12 @@ 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 * 0.5 + 0.5;
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;
@@ -2734,13 +3127,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;
@@ -2748,13 +3146,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)
@@ -2821,8 +3223,7 @@ 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 bias,
+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,
float squash_amount, int squash_frequency)
@@ -2843,25 +3244,32 @@ vec2 calc_brick_texture(vec3 p, float mortar_size, float bias,
x = (p.x + offset) - brick_width * bricknum;
y = p.y - row_height * rownum;
- return vec2(clamp((integer_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias), 0.0, 1.0),
- (x < mortar_size || y < mortar_size ||
- x > (brick_width - mortar_size) ||
- y > (row_height - mortar_size)) ? 1.0 : 0.0);
+ float tint = clamp((integer_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias), 0.0, 1.0);
+
+ float min_dist = min(min(x, y), min(brick_width - x, row_height - y));
+ if (min_dist >= mortar_size) {
+ return vec2(tint, 0.0);
+ }
+ else if (mortar_smooth == 0.0) {
+ return vec2(tint, 1.0);
+ }
+ else {
+ min_dist = 1.0 - min_dist/mortar_size;
+ return vec2(tint, smoothstep(0.0, mortar_smooth, min_dist));
+ }
}
-#endif
void node_tex_brick(vec3 co,
vec4 color1, vec4 color2,
vec4 mortar, float scale,
- float mortar_size, float bias,
+ float mortar_size, float mortar_smooth, float bias,
float brick_width, float row_height,
float offset_amount, float offset_frequency,
float squash_amount, float squash_frequency,
out vec4 color, out float fac)
{
-#ifdef BIT_OPERATIONS
vec2 f2 = calc_brick_texture(co * scale,
- mortar_size, bias,
+ mortar_size, mortar_smooth, bias,
brick_width, row_height,
offset_amount, int(offset_frequency),
squash_amount, int(squash_frequency));
@@ -2871,12 +3279,8 @@ void node_tex_brick(vec3 co,
float facm = 1.0 - tint;
color1 = facm * color1 + tint * color2;
}
- color = (f == 1.0) ? mortar : color1;
+ 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)
@@ -2891,7 +3295,15 @@ void node_tex_environment_equirectangular(vec3 co, sampler2D ima, out vec4 color
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;
- color = texture2D(ima, vec2(u, v));
+ /* Fix pole bleeding */
+ float half_width = 0.5 / float(textureSize(ima, 0).x);
+ v = clamp(v, half_width, 1.0 - half_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. */
+ color = textureLod(ima, vec2(u, v), 0.0);
}
void node_tex_environment_mirror_ball(vec3 co, sampler2D ima, out vec4 color)
@@ -2907,7 +3319,7 @@ void node_tex_environment_mirror_ball(vec3 co, sampler2D ima, out vec4 color)
float u = 0.5 * (nco.x + 1.0);
float v = 0.5 * (nco.z + 1.0);
- color = texture2D(ima, vec2(u, v));
+ color = texture(ima, vec2(u, v));
}
void node_tex_environment_empty(vec3 co, out vec4 color)
@@ -2917,7 +3329,7 @@ void node_tex_environment_empty(vec3 co, out vec4 color)
void node_tex_image(vec3 co, sampler2D ima, out vec4 color, out float alpha)
{
- color = texture2D(ima, co.xy);
+ color = texture(ima, co.xy);
alpha = color.a;
}
@@ -2985,13 +3397,13 @@ void node_tex_image_box(vec3 texco,
}
color = vec4(0);
if (weight.x > 0.0) {
- color += weight.x * texture2D(ima, texco.yz);
+ color += weight.x * texture(ima, texco.yz);
}
if (weight.y > 0.0) {
- color += weight.y * texture2D(ima, texco.xz);
+ color += weight.y * texture(ima, texco.xz);
}
if (weight.z > 0.0) {
- color += weight.z * texture2D(ima, texco.yx);
+ color += weight.z * texture(ima, texco.yx);
}
alpha = color.a;
@@ -3064,7 +3476,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);
@@ -3127,10 +3538,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);
@@ -3140,7 +3550,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);
@@ -3155,11 +3565,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) {
@@ -3175,15 +3583,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
@@ -3199,9 +3600,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;
@@ -3227,9 +3627,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;
@@ -3255,13 +3654,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;
@@ -3290,13 +3688,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;
@@ -3327,14 +3724,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));
@@ -3356,19 +3752,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,
@@ -3381,7 +3776,6 @@ void node_tex_musgrave(vec3 co,
out vec4 color,
out float fac)
{
-#ifdef BIT_OPERATIONS
fac = svm_musgrave(int(type),
dimension,
lacunarity,
@@ -3390,9 +3784,6 @@ void node_tex_musgrave(vec3 co,
1.0,
gain,
co * scale);
-#else
- fac = 1.0;
-#endif
color = vec4(fac, fac, fac, 1.0);
}
@@ -3404,7 +3795,6 @@ void node_tex_sky(vec3 co, out vec4 color)
void node_tex_voronoi(vec3 co, float scale, float coloring, out vec4 color, out float fac)
{
-#ifdef BIT_OPERATIONS
vec3 p = co * scale;
int xx, yy, zz, xi, yi, zi;
float da[4];
@@ -3469,13 +3859,8 @@ void node_tex_voronoi(vec3 co, float scale, float coloring, out vec4 color, out
color = vec4(cellnoise_color(pa[0]), 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;
@@ -3497,22 +3882,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 */
@@ -3527,18 +3906,30 @@ void node_light_path(
out float is_transmission_ray,
out float ray_length,
out float ray_depth,
+ out float diffuse_depth,
+ out float glossy_depth,
out float transparent_depth,
out float transmission_depth)
{
+#ifndef PROBE_CAPTURE
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_diffuse_ray = 0.0;
is_reflection_ray = 0.0;
is_transmission_ray = 0.0;
+#else
+ is_camera_ray = 0.0;
+ is_glossy_ray = 1.0;
+ is_diffuse_ray = 1.0;
+ is_reflection_ray = 1.0;
+ is_transmission_ray = 1.0;
+#endif
+ is_shadow_ray = 0.0;
+ is_singular_ray = 0.0;
ray_length = 1.0;
ray_depth = 1.0;
+ diffuse_depth = 1.0;
+ glossy_depth = 1.0;
transparent_depth = 1.0;
transmission_depth = 1.0;
}
@@ -3550,12 +3941,12 @@ void node_light_falloff(float strength, float tsmooth, out float quadratic, out
constant = strength;
}
-void node_object_info(out vec3 location, out float object_index, out float material_index, out float random)
+void node_object_info(mat4 obmat, vec3 info, out vec3 location, out float object_index, out float material_index, out float random)
{
- location = vec3(0.0);
- object_index = 0.0;
- material_index = 0.0;
- random = 0.0;
+ location = obmat[3].xyz;
+ object_index = info.x;
+ material_index = info.y;
+ random = info.z;
}
void node_normal_map(vec4 tangent, vec3 normal, vec3 texnormal, out vec3 outnormal)
@@ -3594,37 +3985,80 @@ void node_bump(float strength, float dist, float height, vec3 N, vec3 surf_pos,
/* output */
-void node_output_material(vec4 surface, vec4 volume, float displacement, out vec4 result)
+void node_output_material(Closure surface, Closure volume, float displacement, out Closure result)
{
result = surface;
}
-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)
{
+#ifndef VOLUMETRICS
+ result = Closure(surface.radiance, backgroundAlpha);
+#else
+ result = volume;
+#endif /* VOLUMETRICS */
+}
+
+#ifndef VOLUMETRICS
+/* TODO : clean this ifdef mess */
+/* EEVEE output */
+#ifdef EEVEE_ENGINE
+void world_normals_get(out vec3 N)
+{
+ N = gl_FrontFacing ? worldNormal : -worldNormal;
+}
+
+void node_eevee_metallic(
+ vec4 basecol, float metallic, float specular, float roughness, vec4 emissive, float transp, vec3 normal,
+ float clearcoat, float clearcoat_roughness, vec3 clearcoat_normal,
+ float occlusion, out Closure result)
+{
+ vec3 diffuse, f0;
+ convert_metallic_to_specular(basecol.rgb, metallic, specular, diffuse, f0);
+
+ result = Closure(eevee_surface_lit(normal, diffuse, f0, roughness, occlusion) + emissive.rgb, 1.0 - transp);
+}
+
+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, out Closure result)
+{
+ result = Closure(eevee_surface_lit(normal, diffuse.rgb, specular.rgb, roughness, occlusion) + emissive.rgb, 1.0 - transp);
+}
+
+void node_output_eevee_material(Closure surface, out Closure result)
+{
+#if defined(USE_ALPHA_HASH) || defined(USE_ALPHA_CLIP) || defined(USE_ALPHA_BLEND)
result = surface;
+#else
+ result = Closure(surface.radiance, length(viewPosition));
+#endif
}
+#endif /* EEVEE_ENGINE */
+#endif /* VOLUMETRICS */
+
/* ********************** matcap style render ******************** */
void material_preview_matcap(vec4 color, sampler2D ima, vec4 N, vec4 mask, out vec4 result)
{
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;
- }
+ normal = 2.0 * N.xyz - vec3(1.0);
+ normal.z = max(normal.z, 0.0);
normal = normalize(normal);
#else
normal = inpt.v.normal;
- mask = vec4(1.0, 1.0, 1.0, 1.0);
+ mask = vec4(1.0);
#endif
- tex.x = 0.5 + 0.49 * normal.x;
- tex.y = 0.5 + 0.49 * normal.y;
- result = texture2D(ima, tex) * mask;
+ vec2 tex = 0.49 * normal.xy + vec2(0.5);
+
+ result = texture(ima, tex) * mask;
}
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_sep_gaussian_blur_frag.glsl b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl
index b485d2cce86..78241a798a2 100644
--- a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl
@@ -1,16 +1,19 @@
uniform vec2 ScaleU;
uniform sampler2D textureSource;
+in vec2 texCoord_interp;
+out vec4 fragColor;
+
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;
+ color += texture(textureSource, texCoord_interp.st + vec2(-3.0 * ScaleU.x, -3.0 * ScaleU.y)) * 0.015625;
+ color += texture(textureSource, texCoord_interp.st + vec2(-2.0 * ScaleU.x, -2.0 * ScaleU.y)) * 0.09375;
+ color += texture(textureSource, texCoord_interp.st + vec2(-1.0 * ScaleU.x, -1.0 * ScaleU.y)) * 0.234375;
+ color += texture(textureSource, texCoord_interp.st + vec2(0.0, 0.0)) * 0.3125;
+ color += texture(textureSource, texCoord_interp.st + vec2(1.0 * ScaleU.x, 1.0 * ScaleU.y)) * 0.234375;
+ color += texture(textureSource, texCoord_interp.st + vec2(2.0 * ScaleU.x, 2.0 * ScaleU.y)) * 0.09375;
+ color += texture(textureSource, texCoord_interp.st + vec2(3.0 * ScaleU.x, 3.0 * ScaleU.y)) * 0.015625;
- gl_FragColor = color;
+ 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
index 5d00108b052..1319e386c65 100644
--- a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl
@@ -1,6 +1,12 @@
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec2 pos;
+in vec2 uvs;
+out vec2 texCoord_interp;
+
void main()
{
- gl_Position = ftransform();
- gl_TexCoord[0] = gl_MultiTexCoord0;
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
+ texCoord_interp = uvs;
}
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..4d7131c4eb1
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl
@@ -0,0 +1,17 @@
+
+#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 * max(0.0, dot(normalize(normal), light));
+}
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
index 4d1feb5c83e..b57bd5b6a37 100644
--- a/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl
@@ -1,5 +1,6 @@
-varying vec3 coords;
+in vec3 coords;
+out vec4 fragColor;
uniform vec3 active_color;
uniform float step_size;
@@ -8,21 +9,23 @@ uniform float density_scale;
uniform sampler3D soot_texture;
uniform sampler3D shadow_texture;
-#ifdef USE_FIRE
-uniform sampler3D flame_texture;
-uniform sampler1D spectrum_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);
+ vec4 soot = texture(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);
+ soot_color = vec3(0);
}
float soot_density = density_scale * soot.a;
@@ -31,18 +34,14 @@ void main()
float soot_alpha = 1.0 - soot_transmittance;
/* shade */
- float shadow = texture3D(shadow_texture, coords).r;
+ float shadow = texture(shadow_texture, coords).r;
soot_color *= soot_transmittance * shadow;
/* premultiply alpha */
- vec4 color = vec4(soot_alpha * soot_color, soot_alpha);
-
-#ifdef USE_FIRE
- /* fire */
- float flame = texture3D(flame_texture, coords).r;
- vec4 emission = texture1D(spectrum_texture, flame);
- color.rgb += (1 - color.a) * emission.a * emission.rgb;
+ fragColor = vec4(soot_alpha * soot_color, soot_alpha);
+#else
+ float color_band = texture(color_band_texture, coords).r;
+ vec4 transfer_function = texture(transfer_texture, color_band);
+ fragColor = 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
index 297486ae26a..8c30e9baf9e 100644
--- a/source/blender/gpu/shaders/gpu_shader_smoke_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_smoke_vert.glsl
@@ -1,5 +1,7 @@
-varying vec3 coords;
+uniform mat4 ModelViewProjectionMatrix;
+
+out vec3 coords;
uniform vec3 min_location;
uniform vec3 invsize;
@@ -7,6 +9,7 @@ uniform vec3 ob_sizei;
void main()
{
- gl_Position = gl_ModelViewProjectionMatrix * vec4(gl_Vertex.xyz * ob_sizei, 1.0);
+ // TODO: swap gl_Vertex for vec3 pos, update smoke setup code
+ gl_Position = 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..7ff90ad4f21
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl
@@ -0,0 +1,15 @@
+
+flat in vec4 color_flat;
+noperspective in vec2 texCoord_interp;
+out vec4 fragColor;
+
+uniform sampler2D glyph;
+
+void main()
+{
+ // input color replaces texture color
+ fragColor.rgb = color_flat.rgb;
+
+ // modulate input alpha & texture alpha
+ fragColor.a = color_flat.a * texture(glyph, texCoord_interp).r;
+}
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..6129f49ce22
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl
@@ -0,0 +1,16 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec2 pos;
+in vec2 texCoord;
+in vec4 color;
+flat out vec4 color_flat;
+noperspective out vec2 texCoord_interp;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
+
+ color_flat = color;
+ texCoord_interp = texCoord;
+}
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..5dd1352adc5
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl
@@ -0,0 +1,9 @@
+
+uniform vec4 color;
+
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = color;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_vertex.glsl b/source/blender/gpu/shaders/gpu_shader_vertex.glsl
index db0068d2f3d..4ebd10d514f 100644
--- a/source/blender/gpu/shaders/gpu_shader_vertex.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_vertex.glsl
@@ -1,3 +1,8 @@
+
+uniform mat4 ModelViewMatrix;
+uniform mat4 ProjectionMatrix;
+uniform mat3 NormalMatrix;
+
#ifdef USE_OPENSUBDIV
in vec3 normal;
in vec4 position;
@@ -7,8 +12,8 @@ out block {
} outpt;
#endif
-varying vec3 varposition;
-varying vec3 varnormal;
+out vec3 varposition;
+out vec3 varnormal;
#ifdef CLIP_WORKAROUND
varying float gl_ClipDistance[6];
@@ -89,11 +94,11 @@ void main()
vec3 normal = gl_Normal;
#endif
- vec4 co = gl_ModelViewMatrix * position;
+ vec4 co = ModelViewMatrix * position;
varposition = co.xyz;
- varnormal = normalize(gl_NormalMatrix * normal);
- gl_Position = gl_ProjectionMatrix * co;
+ varnormal = normalize(NormalMatrix * normal);
+ gl_Position = ProjectionMatrix * co;
#ifdef CLIP_WORKAROUND
int i;
diff --git a/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl
index d45a4b316a8..89a2f391a12 100644
--- a/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl
@@ -1,7 +1,6 @@
-varying vec3 varposition;
-varying vec3 varnormal;
-
+out vec3 varposition;
+out vec3 varnormal;
/* Color, keep in sync with: gpu_shader_vertex.glsl */
diff --git a/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl b/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl
index 3761bf350eb..6aad94bbf59 100644
--- a/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl
@@ -2,7 +2,8 @@
* This fragment shader was initially found at http://fabiensanglard.net/shadowmappingVSM/index.php
*/
-varying vec4 v_position;
+in vec4 v_position;
+out vec4 fragColor;
void main()
{
@@ -17,5 +18,6 @@ void main()
float dy = dFdy(depth);
moment2 += 0.25 * (dx * dx + dy * dy);
- gl_FragColor = vec4(moment1, moment2, 0.0, 0.0);
+ fragColor = vec4(moment1, moment2, 0.0, 0.0);
+ // TODO: write to a 2-component target --^
}
diff --git a/source/blender/gpu/shaders/gpu_shader_vsm_store_vert.glsl b/source/blender/gpu/shaders/gpu_shader_vsm_store_vert.glsl
index 224c3e78adc..def835156f7 100644
--- a/source/blender/gpu/shaders/gpu_shader_vsm_store_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_vsm_store_vert.glsl
@@ -1,7 +1,10 @@
-varying vec4 v_position;
+
+uniform mat4 ModelViewProjectionMatrix;
+
+out vec4 v_position;
void main()
{
- gl_Position = ftransform();
+ gl_Position = ModelViewProjectionMatrix * gl_Vertex;
v_position = gl_Position;
}
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index b8ed780397f..d58340965a7 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -1763,20 +1763,15 @@ 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);
- //itasc_update_param(ob->pose);
+ if (count)
+ create_scene(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)
{
- if (!ob->pose->ikdata) {
- // IK tree not yet created, no it now
- create_scene(scene, ob, ctime);
- itasc_update_param(ob->pose);
- }
if (ob->pose->ikdata) {
IK_Data *ikdata = (IK_Data *)ob->pose->ikdata;
bItasc *ikparam = (bItasc *) ob->pose->ikparam;
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h
index 52febe642a0..ff1784c54dd 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -77,6 +77,16 @@ void IMB_colormanagement_transform(float *buffer, int width, int height, int cha
const char *from_colorspace, const char *to_colorspace, bool predivide);
void IMB_colormanagement_transform_threaded(float *buffer, int width, int height, int channels,
const char *from_colorspace, const char *to_colorspace, bool predivide);
+void IMB_colormanagement_transform_byte(unsigned char *buffer, int width, int height, int channels,
+ const char *from_colorspace, const char *to_colorspace);
+void IMB_colormanagement_transform_byte_threaded(unsigned char *buffer, int width, int height, int channels,
+ const char *from_colorspace, const char *to_colorspace);
+void IMB_colormanagement_transform_from_byte(float *float_buffer, unsigned char *byte_buffer,
+ int width, int height, int channels,
+ const char *from_colorspace, const char *to_colorspace);
+void IMB_colormanagement_transform_from_byte_threaded(float *float_buffer, unsigned char *byte_buffer,
+ int width, int height, int channels,
+ const char *from_colorspace, const char *to_colorspace);
void IMB_colormanagement_transform_v4(float pixel[4], const char *from_colorspace, const char *to_colorspace);
void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], struct ColorSpace *colorspace);
@@ -152,7 +162,7 @@ void IMB_colormanagment_colorspace_from_ibuf_ftype(struct ColorManagedColorspace
/* ** RNA helper functions ** */
void IMB_colormanagement_display_items_add(struct EnumPropertyItem **items, int *totitem);
void IMB_colormanagement_view_items_add(struct EnumPropertyItem **items, int *totitem, const char *display_name);
-void IMB_colormanagement_look_items_add(struct EnumPropertyItem **items, int *totitem);
+void IMB_colormanagement_look_items_add(struct EnumPropertyItem **items, int *totitem, const char *view_name);
void IMB_colormanagement_colorspace_items_add(struct EnumPropertyItem **items, int *totitem);
/* ** Tile-based buffer management ** */
@@ -185,6 +195,8 @@ void IMB_colormanagement_processor_apply_v3(struct ColormanageProcessor *cm_proc
void IMB_colormanagement_processor_apply_pixel(struct ColormanageProcessor *cm_processor, float *pixel, int channels);
void IMB_colormanagement_processor_apply(struct ColormanageProcessor *cm_processor, float *buffer, int width, int height,
int channels, bool predivide);
+void IMB_colormanagement_processor_apply_byte(struct ColormanageProcessor *cm_processor,
+ unsigned char *buffer, int width, int height, int channels);
void IMB_colormanagement_processor_free(struct ColormanageProcessor *cm_processor);
/* ** OpenGL drawing routines using GLSL for color space transform ** */
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 93d2b3e0cd0..e7abfdc7d67 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -166,7 +166,7 @@ struct ImBuf *IMB_makeSingleUser(struct ImBuf *ibuf);
*
* \attention Defined in allocimbuf.c
*/
-struct ImBuf *IMB_dupImBuf(struct ImBuf *ibuf1);
+struct ImBuf *IMB_dupImBuf(const struct ImBuf *ibuf1);
/**
*
diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h
index f4b2539d7d7..1701c2ba307 100644
--- a/source/blender/imbuf/IMB_imbuf_types.h
+++ b/source/blender/imbuf/IMB_imbuf_types.h
@@ -237,9 +237,8 @@ typedef struct ImBuf {
/**
* \name Imbuf Component flags
* \brief These flags determine the components of an ImBuf struct.
- */
-/**@{*/
-/** \brief Flag defining the components of the ImBuf struct. */
+ *
+ * \{ */
#define IB_rect (1 << 0)
#define IB_test (1 << 1)
@@ -259,15 +258,20 @@ typedef struct ImBuf {
#define IB_thumbnail (1 << 15)
#define IB_multiview (1 << 16)
+/** \} */
+
/**
* \name Imbuf preset profile tags
* \brief Some predefined color space profiles that 8 bit imbufs can represent
- */
+ *
+ * \{ */
#define IB_PROFILE_NONE 0
#define IB_PROFILE_LINEAR_RGB 1
#define IB_PROFILE_SRGB 2
#define IB_PROFILE_CUSTOM 3
+/** \} */
+
/* dds */
#ifdef WITH_DDS
#ifndef DDS_MAKEFOURCC
@@ -298,8 +302,16 @@ extern const char *imb_ext_audio[];
/* image formats that can only be loaded via filepath */
extern const char *imb_ext_image_filepath_only[];
+/**
+ * \name Imbuf Color Management Flag
+ * \brief Used with #ImBuf.colormanage_flag
+ *
+ * \{ */
+
enum {
IMB_COLORMANAGE_IS_DATA = (1 << 0)
};
-#endif
+/** \} */
+
+#endif /* __IMB_IMBUF_TYPES_H__ */
diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h
index d89393b9903..6d7ad7985f9 100644
--- a/source/blender/imbuf/intern/IMB_anim.h
+++ b/source/blender/imbuf/intern/IMB_anim.h
@@ -40,10 +40,7 @@
# include <mmsystem.h>
# include <memory.h>
# include <commdlg.h>
-
-# ifndef FREE_WINDOWS
-# include <vfw.h>
-# endif
+# include <vfw.h>
# undef AVIIF_KEYFRAME // redefined in AVI_avi.h
# undef AVIIF_LIST // redefined in AVI_avi.h
@@ -130,7 +127,7 @@ struct anim {
/* avi */
struct _AviMovie *avi;
-#if defined(_WIN32) && !defined(FREE_WINDOWS)
+#if defined(_WIN32)
/* windows avi */
int avistreams;
int firstvideo;
diff --git a/source/blender/imbuf/intern/IMB_colormanagement_intern.h b/source/blender/imbuf/intern/IMB_colormanagement_intern.h
index b75f12b239d..0b4557e7bef 100644
--- a/source/blender/imbuf/intern/IMB_colormanagement_intern.h
+++ b/source/blender/imbuf/intern/IMB_colormanagement_intern.h
@@ -79,6 +79,8 @@ typedef struct ColorManagedLook {
struct ColorManagedLook *next, *prev;
int index;
char name[MAX_COLORSPACE_NAME];
+ char ui_name[MAX_COLORSPACE_NAME];
+ char view[MAX_COLORSPACE_NAME];
char process_space[MAX_COLORSPACE_NAME];
bool is_noop;
} ColorManagedLook;
diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c
index ef3743d9c8a..6e9bfa1fc4e 100644
--- a/source/blender/imbuf/intern/allocimbuf.c
+++ b/source/blender/imbuf/intern/allocimbuf.c
@@ -89,11 +89,14 @@ void imb_mmap_unlock(void)
void imb_freemipmapImBuf(ImBuf *ibuf)
{
int a;
-
- for (a = 1; a < ibuf->miptot; a++) {
- if (ibuf->mipmap[a - 1])
- IMB_freeImBuf(ibuf->mipmap[a - 1]);
- ibuf->mipmap[a - 1] = NULL;
+
+ /* Do not trust ibuf->miptot, in some cases IMB_remakemipmap can leave unfreed unused levels,
+ * leading to memory leaks... */
+ for (a = 0; a < IMB_MIPMAP_LEVELS; a++) {
+ if (ibuf->mipmap[a] != NULL) {
+ IMB_freeImBuf(ibuf->mipmap[a]);
+ ibuf->mipmap[a] = NULL;
+ }
}
ibuf->miptot = 0;
@@ -503,7 +506,7 @@ bool IMB_initImBuf(struct ImBuf *ibuf,
}
/* does no zbuffers? */
-ImBuf *IMB_dupImBuf(ImBuf *ibuf1)
+ImBuf *IMB_dupImBuf(const ImBuf *ibuf1)
{
ImBuf *ibuf2, tbuf;
int flags = 0;
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index d378ca9a78c..9806ff006d7 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -37,10 +37,7 @@
#include <mmsystem.h>
#include <memory.h>
#include <commdlg.h>
-
-#ifndef FREE_WINDOWS
#include <vfw.h>
-#endif
#undef AVIIF_KEYFRAME /* redefined in AVI_avi.h */
#undef AVIIF_LIST /* redefined in AVI_avi.h */
@@ -173,7 +170,7 @@ static void an_stringenc(char *string, const char *head, const char *tail, unsig
#ifdef WITH_AVI
static void free_anim_avi(struct anim *anim)
{
-#if defined(_WIN32) && !defined(FREE_WINDOWS)
+#if defined(_WIN32)
int i;
#endif
@@ -184,7 +181,7 @@ static void free_anim_avi(struct anim *anim)
MEM_freeN(anim->avi);
anim->avi = NULL;
-#if defined(_WIN32) && !defined(FREE_WINDOWS)
+#if defined(_WIN32)
if (anim->pgf) {
AVIStreamGetFrameClose(anim->pgf);
@@ -283,7 +280,7 @@ static int startavi(struct anim *anim)
{
AviError avierror;
-#if defined(_WIN32) && !defined(FREE_WINDOWS)
+#if defined(_WIN32)
HRESULT hr;
int i, firstvideo = -1;
int streamcount;
@@ -304,7 +301,7 @@ static int startavi(struct anim *anim)
avierror = AVI_open_movie(anim->name, anim->avi);
-#if defined(_WIN32) && !defined(FREE_WINDOWS)
+#if defined(_WIN32)
if (avierror == AVI_ERROR_COMPRESSION) {
AVIFileInit();
hr = AVIFileOpen(&anim->pfile, anim->name, OF_READ, 0L);
@@ -401,7 +398,7 @@ static ImBuf *avi_fetchibuf(struct anim *anim, int position)
return NULL;
}
-#if defined(_WIN32) && !defined(FREE_WINDOWS)
+#if defined(_WIN32)
if (anim->avistreams) {
LPBITMAPINFOHEADER lpbi;
@@ -522,9 +519,9 @@ static int startffmpeg(struct anim *anim)
anim->duration = pFormatCtx->streams[videoStream]->nb_frames;
}
else {
- anim->duration = ceil(pFormatCtx->duration *
- av_q2d(frame_rate) /
- AV_TIME_BASE);
+ anim->duration = (int)(pFormatCtx->duration *
+ av_q2d(frame_rate) /
+ AV_TIME_BASE + 0.5f);
}
frs_num = frame_rate.num;
diff --git a/source/blender/imbuf/intern/cineon/dpxlib.c b/source/blender/imbuf/intern/cineon/dpxlib.c
index 8b4e95ac452..429a19936a5 100644
--- a/source/blender/imbuf/intern/cineon/dpxlib.c
+++ b/source/blender/imbuf/intern/cineon/dpxlib.c
@@ -183,7 +183,7 @@ LogImageFile *dpxOpen(const unsigned char *byteStuff, int fromMemory, size_t buf
if (verbose) printf("DPX: File is LSB.\n");
}
else {
- if (verbose) {
+ if (verbose) {
printf("DPX: Bad magic number %u in \"%s\".\n",
header.fileHeader.magic_num, byteStuff);
}
diff --git a/source/blender/imbuf/intern/cineon/logImageCore.c b/source/blender/imbuf/intern/cineon/logImageCore.c
index 6fb1bccf491..600642f5e44 100644
--- a/source/blender/imbuf/intern/cineon/logImageCore.c
+++ b/source/blender/imbuf/intern/cineon/logImageCore.c
@@ -177,19 +177,18 @@ unsigned int getRowLength(int width, LogImageElement logElement)
return ((width * logElement.depth * 10 - 1) / 32 + 1) * 4;
else if (logElement.packing == 1 || logElement.packing == 2)
return ((width * logElement.depth - 1) / 3 + 1) * 4;
-
+ break;
case 12:
if (logElement.packing == 0)
return ((width * logElement.depth * 12 - 1) / 32 + 1) * 4;
else if (logElement.packing == 1 || logElement.packing == 2)
return width * logElement.depth * 2;
-
+ break;
case 16:
return width * logElement.depth * 2;
- default:
- return 0;
}
+ return 0;
}
@@ -572,20 +571,20 @@ static int logImageElementGetData(LogImageFile *logImage, LogImageElement logEle
return logImageElementGetData10Packed(logImage, logElement, data);
else if (logElement.packing == 1 || logElement.packing == 2)
return logImageElementGetData10(logImage, logElement, data);
+ break;
case 12:
if (logElement.packing == 0)
return logImageElementGetData12Packed(logImage, logElement, data);
else if (logElement.packing == 1 || logElement.packing == 2)
return logImageElementGetData12(logImage, logElement, data);
+ break;
case 16:
return logImageElementGetData16(logImage, logElement, data);
-
- default:
- /* format not supported */
- return 1;
}
+ /* format not supported */
+ return 1;
}
static int logImageElementGetData1(LogImageFile *logImage, LogImageElement logElement, float *data)
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index 41812872f11..03f71b5878c 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -63,6 +63,7 @@
#include "BKE_context.h"
#include "BKE_image.h"
#include "BKE_main.h"
+#include "BKE_sequencer.h"
#include "RNA_define.h"
@@ -214,7 +215,7 @@ typedef struct ColormanageCacheKey {
int display; /* display device name */
} ColormanageCacheKey;
-typedef struct ColormnaageCacheData {
+typedef struct ColormanageCacheData {
int flag; /* view flags of cached buffer */
int look; /* Additional artistics transform */
float exposure; /* exposure value cached buffer is calculated with */
@@ -222,12 +223,12 @@ typedef struct ColormnaageCacheData {
float dither; /* dither value cached buffer is calculated with */
CurveMapping *curve_mapping; /* curve mapping used for cached buffer */
int curve_mapping_timestamp; /* time stamp of curve mapping used for cached buffer */
-} ColormnaageCacheData;
+} ColormanageCacheData;
typedef struct ColormanageCache {
struct MovieCache *moviecache;
- ColormnaageCacheData *data;
+ ColormanageCacheData *data;
} ColormanageCache;
static struct MovieCache *colormanage_moviecache_get(const ImBuf *ibuf)
@@ -238,7 +239,7 @@ static struct MovieCache *colormanage_moviecache_get(const ImBuf *ibuf)
return ibuf->colormanage_cache->moviecache;
}
-static ColormnaageCacheData *colormanage_cachedata_get(const ImBuf *ibuf)
+static ColormanageCacheData *colormanage_cachedata_get(const ImBuf *ibuf)
{
if (!ibuf->colormanage_cache)
return NULL;
@@ -281,7 +282,7 @@ static struct MovieCache *colormanage_moviecache_ensure(ImBuf *ibuf)
return ibuf->colormanage_cache->moviecache;
}
-static void colormanage_cachedata_set(ImBuf *ibuf, ColormnaageCacheData *data)
+static void colormanage_cachedata_set(ImBuf *ibuf, ColormanageCacheData *data)
{
if (!ibuf->colormanage_cache)
ibuf->colormanage_cache = MEM_callocN(sizeof(ColormanageCache), "imbuf colormanage cache");
@@ -361,7 +362,7 @@ static unsigned char *colormanage_cache_get(ImBuf *ibuf, const ColormanageCacheV
cache_ibuf = colormanage_cache_get_ibuf(ibuf, &key, cache_handle);
if (cache_ibuf) {
- ColormnaageCacheData *cache_data;
+ ColormanageCacheData *cache_data;
BLI_assert(cache_ibuf->x == ibuf->x &&
cache_ibuf->y == ibuf->y);
@@ -402,7 +403,7 @@ static void colormanage_cache_put(ImBuf *ibuf, const ColormanageCacheViewSetting
{
ColormanageCacheKey key;
ImBuf *cache_ibuf;
- ColormnaageCacheData *cache_data;
+ ColormanageCacheData *cache_data;
int view_flag = 1 << (view_settings->view - 1);
struct MovieCache *moviecache = colormanage_moviecache_ensure(ibuf);
CurveMapping *curve_mapping = view_settings->curve_mapping;
@@ -421,7 +422,7 @@ static void colormanage_cache_put(ImBuf *ibuf, const ColormanageCacheViewSetting
cache_ibuf->flags |= IB_rect;
/* store data which is needed to check whether cached buffer could be used for color managed display settings */
- cache_data = MEM_callocN(sizeof(ColormnaageCacheData), "color manage cache imbuf data");
+ cache_data = MEM_callocN(sizeof(ColormanageCacheData), "color manage cache imbuf data");
cache_data->look = view_settings->look;
cache_data->exposure = view_settings->exposure;
cache_data->gamma = view_settings->gamma;
@@ -710,7 +711,7 @@ void colormanage_cache_free(ImBuf *ibuf)
}
if (ibuf->colormanage_cache) {
- ColormnaageCacheData *cache_data = colormanage_cachedata_get(ibuf);
+ ColormanageCacheData *cache_data = colormanage_cachedata_get(ibuf);
struct MovieCache *moviecache = colormanage_moviecache_get(ibuf);
if (cache_data) {
@@ -1112,6 +1113,7 @@ void IMB_colormanagement_check_file_config(Main *bmain)
for (scene = bmain->scene.first; scene; scene = scene->id.next) {
ColorManagedColorspaceSettings *sequencer_colorspace_settings;
+ /* check scene color management settings */
colormanage_check_display_settings(&scene->display_settings, "scene", default_display);
colormanage_check_view_settings(&scene->display_settings, &scene->view_settings, "scene");
@@ -1122,6 +1124,15 @@ void IMB_colormanagement_check_file_config(Main *bmain)
if (sequencer_colorspace_settings->name[0] == '\0') {
BLI_strncpy(sequencer_colorspace_settings->name, global_role_default_sequencer, MAX_COLORSPACE_NAME);
}
+
+ /* check sequencer strip input color space settings */
+ Sequence *seq;
+ SEQ_BEGIN (scene->ed, seq) {
+ if (seq->strip) {
+ colormanage_check_colorspace_settings(&seq->strip->colorspace_settings, "sequencer strip");
+ }
+ }
+ SEQ_END
}
/* ** check input color space settings ** */
@@ -1227,7 +1238,12 @@ const char *IMB_colormanagement_get_float_colorspace(ImBuf *ibuf)
const char *IMB_colormanagement_get_rect_colorspace(ImBuf *ibuf)
{
- return ibuf->rect_colorspace->name;
+ if (ibuf->rect_colorspace) {
+ return ibuf->rect_colorspace->name;
+ }
+ else {
+ return IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_BYTE);
+ }
}
/*********************** Threaded display buffer transform routines *************************/
@@ -1401,7 +1417,7 @@ static void *do_display_buffer_apply_thread(void *handle_v)
bool is_data = handle->is_data;
if (cm_processor == NULL) {
- if (display_buffer_byte) {
+ if (display_buffer_byte && display_buffer_byte != handle->byte_buffer) {
IMB_buffer_byte_from_byte(display_buffer_byte, handle->byte_buffer, IB_PROFILE_SRGB, IB_PROFILE_SRGB,
false, width, height, width, width);
}
@@ -1550,21 +1566,25 @@ static void colormanage_display_buffer_process(ImBuf *ibuf, unsigned char *displ
typedef struct ProcessorTransformThread {
ColormanageProcessor *cm_processor;
- float *buffer;
+ unsigned char *byte_buffer;
+ float *float_buffer;
int width;
int start_line;
int tot_line;
int channels;
bool predivide;
+ bool float_from_byte;
} ProcessorTransformThread;
typedef struct ProcessorTransformInit {
ColormanageProcessor *cm_processor;
- float *buffer;
+ unsigned char *byte_buffer;
+ float *float_buffer;
int width;
int height;
int channels;
bool predivide;
+ bool float_from_byte;
} ProcessorTransformInitData;
static void processor_transform_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
@@ -1572,17 +1592,24 @@ static void processor_transform_init_handle(void *handle_v, int start_line, int
ProcessorTransformThread *handle = (ProcessorTransformThread *) handle_v;
ProcessorTransformInitData *init_data = (ProcessorTransformInitData *) init_data_v;
- int channels = init_data->channels;
- int width = init_data->width;
- bool predivide = init_data->predivide;
+ const int channels = init_data->channels;
+ const int width = init_data->width;
+ const bool predivide = init_data->predivide;
+ const bool float_from_byte = init_data->float_from_byte;
- size_t offset = ((size_t)channels) * start_line * width;
+ const size_t offset = ((size_t)channels) * start_line * width;
memset(handle, 0, sizeof(ProcessorTransformThread));
handle->cm_processor = init_data->cm_processor;
- handle->buffer = init_data->buffer + offset;
+ if (init_data->byte_buffer != NULL) {
+ /* TODO(serge): Offset might be different for byte and float buffers. */
+ handle->byte_buffer = init_data->byte_buffer + offset;
+ }
+ if (init_data->float_buffer != NULL) {
+ handle->float_buffer = init_data->float_buffer + offset;
+ }
handle->width = width;
@@ -1591,33 +1618,62 @@ static void processor_transform_init_handle(void *handle_v, int start_line, int
handle->channels = channels;
handle->predivide = predivide;
+ handle->float_from_byte = float_from_byte;
}
static void *do_processor_transform_thread(void *handle_v)
{
ProcessorTransformThread *handle = (ProcessorTransformThread *) handle_v;
- float *buffer = handle->buffer;
- int channels = handle->channels;
- int width = handle->width;
- int height = handle->tot_line;
- bool predivide = handle->predivide;
-
- IMB_colormanagement_processor_apply(handle->cm_processor, buffer, width, height, channels, predivide);
+ unsigned char *byte_buffer = handle->byte_buffer;
+ float *float_buffer = handle->float_buffer;
+ const int channels = handle->channels;
+ const int width = handle->width;
+ const int height = handle->tot_line;
+ const bool predivide = handle->predivide;
+ const bool float_from_byte = handle->float_from_byte;
+
+ if (float_from_byte) {
+ IMB_buffer_float_from_byte(float_buffer, byte_buffer,
+ IB_PROFILE_SRGB, IB_PROFILE_SRGB,
+ true,
+ width, height, width, width);
+ IMB_colormanagement_processor_apply(handle->cm_processor,
+ float_buffer,
+ width, height, channels,
+ predivide);
+ }
+ else {
+ if (byte_buffer != NULL) {
+ IMB_colormanagement_processor_apply_byte(handle->cm_processor,
+ byte_buffer,
+ width, height, channels);
+ }
+ if (float_buffer != NULL) {
+ IMB_colormanagement_processor_apply(handle->cm_processor,
+ float_buffer,
+ width, height, channels,
+ predivide);
+ }
+ }
return NULL;
}
-static void processor_transform_apply_threaded(float *buffer, int width, int height, int channels,
- ColormanageProcessor *cm_processor, bool predivide)
+static void processor_transform_apply_threaded(unsigned char *byte_buffer, float *float_buffer,
+ const int width, const int height, const int channels,
+ ColormanageProcessor *cm_processor,
+ const bool predivide, const bool float_from_byte)
{
ProcessorTransformInitData init_data;
init_data.cm_processor = cm_processor;
- init_data.buffer = buffer;
+ init_data.byte_buffer = byte_buffer;
+ init_data.float_buffer = float_buffer;
init_data.width = width;
init_data.height = height;
init_data.channels = channels;
init_data.predivide = predivide;
+ init_data.float_from_byte = float_from_byte;
IMB_processor_apply_threaded(height, sizeof(ProcessorTransformThread), &init_data,
processor_transform_init_handle, do_processor_transform_thread);
@@ -1626,8 +1682,10 @@ static void processor_transform_apply_threaded(float *buffer, int width, int hei
/*********************** Color space transformation functions *************************/
/* convert the whole buffer from specified by name color space to another - internal implementation */
-static void colormanagement_transform_ex(float *buffer, int width, int height, int channels, const char *from_colorspace,
- const char *to_colorspace, bool predivide, bool do_threaded)
+static void colormanagement_transform_ex(unsigned char *byte_buffer, float *float_buffer,
+ int width, int height, int channels,
+ const char *from_colorspace, const char *to_colorspace,
+ bool predivide, bool do_threaded)
{
ColormanageProcessor *cm_processor;
@@ -1644,10 +1702,19 @@ static void colormanagement_transform_ex(float *buffer, int width, int height, i
cm_processor = IMB_colormanagement_colorspace_processor_new(from_colorspace, to_colorspace);
- if (do_threaded)
- processor_transform_apply_threaded(buffer, width, height, channels, cm_processor, predivide);
- else
- IMB_colormanagement_processor_apply(cm_processor, buffer, width, height, channels, predivide);
+ if (do_threaded) {
+ processor_transform_apply_threaded(byte_buffer, float_buffer,
+ width, height, channels,
+ cm_processor, predivide, false);
+ }
+ else {
+ if (byte_buffer != NULL) {
+ IMB_colormanagement_processor_apply_byte(cm_processor, byte_buffer, width, height, channels);
+ }
+ if (float_buffer != NULL) {
+ IMB_colormanagement_processor_apply(cm_processor, float_buffer, width, height, channels, predivide);
+ }
+ }
IMB_colormanagement_processor_free(cm_processor);
}
@@ -1656,7 +1723,7 @@ static void colormanagement_transform_ex(float *buffer, int width, int height, i
void IMB_colormanagement_transform(float *buffer, int width, int height, int channels,
const char *from_colorspace, const char *to_colorspace, bool predivide)
{
- colormanagement_transform_ex(buffer, width, height, channels, from_colorspace, to_colorspace, predivide, false);
+ colormanagement_transform_ex(NULL, buffer, width, height, channels, from_colorspace, to_colorspace, predivide, false);
}
/* convert the whole buffer from specified by name color space to another
@@ -1665,7 +1732,59 @@ void IMB_colormanagement_transform(float *buffer, int width, int height, int cha
void IMB_colormanagement_transform_threaded(float *buffer, int width, int height, int channels,
const char *from_colorspace, const char *to_colorspace, bool predivide)
{
- colormanagement_transform_ex(buffer, width, height, channels, from_colorspace, to_colorspace, predivide, true);
+ colormanagement_transform_ex(NULL, buffer, width, height, channels, from_colorspace, to_colorspace, predivide, true);
+}
+
+/* Similar to functions above, but operates on byte buffer. */
+void IMB_colormanagement_transform_byte(unsigned char *buffer, int width, int height, int channels,
+ const char *from_colorspace, const char *to_colorspace)
+{
+ colormanagement_transform_ex(buffer, NULL, width, height, channels, from_colorspace, to_colorspace, false, false);
+}
+void IMB_colormanagement_transform_byte_threaded(unsigned char *buffer, int width, int height, int channels,
+ const char *from_colorspace, const char *to_colorspace)
+{
+ colormanagement_transform_ex(buffer, NULL, width, height, channels, from_colorspace, to_colorspace, false, true);
+}
+
+/* Similar to above, but gets float buffer from display one. */
+void IMB_colormanagement_transform_from_byte(float *float_buffer, unsigned char *byte_buffer,
+ int width, int height, int channels,
+ const char *from_colorspace, const char *to_colorspace)
+{
+ IMB_buffer_float_from_byte(float_buffer, byte_buffer,
+ IB_PROFILE_SRGB, IB_PROFILE_SRGB,
+ true,
+ width, height, width, width);
+ IMB_colormanagement_transform(float_buffer,
+ width, height, channels,
+ from_colorspace, to_colorspace,
+ true);
+}
+void IMB_colormanagement_transform_from_byte_threaded(float *float_buffer, unsigned char *byte_buffer,
+ int width, int height, int channels,
+ const char *from_colorspace, const char *to_colorspace)
+{
+ ColormanageProcessor *cm_processor;
+ if (from_colorspace == NULL || from_colorspace[0] == '\0') {
+ return;
+ }
+ if (STREQ(from_colorspace, to_colorspace)) {
+ /* Because this function always takes a byte buffer and returns a float buffer, it must
+ * always do byte-to-float conversion of some kind. To avoid threading overhead
+ * IMB_buffer_float_from_byte is used when color spaces are identical. See T51002.
+ */
+ IMB_buffer_float_from_byte(float_buffer, byte_buffer,
+ IB_PROFILE_SRGB, IB_PROFILE_SRGB,
+ true,
+ width, height, width, width);
+ return;
+ }
+ cm_processor = IMB_colormanagement_colorspace_processor_new(from_colorspace, to_colorspace);
+ processor_transform_apply_threaded(byte_buffer, float_buffer,
+ width, height, channels,
+ cm_processor, true, true);
+ IMB_colormanagement_processor_free(cm_processor);
}
void IMB_colormanagement_transform_v4(float pixel[4], const char *from_colorspace, const char *to_colorspace)
@@ -1957,6 +2076,10 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, bool save_as_render, boo
}
}
+ if (colormanaged_ibuf != ibuf) {
+ IMB_metadata_copy(colormanaged_ibuf, ibuf);
+ }
+
return colormanaged_ibuf;
}
@@ -1969,12 +2092,14 @@ void IMB_colormanagement_buffer_make_display_space(float *buffer, unsigned char
size_t float_buffer_size = ((size_t)width) * height * channels * sizeof(float);
float *display_buffer_float = MEM_mallocN(float_buffer_size, "byte_buffer_make_display_space");
+ /* TODO(sergey): Convert float directly to byte buffer. */
+
memcpy(display_buffer_float, buffer, float_buffer_size);
cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
- processor_transform_apply_threaded(display_buffer_float, width, height, channels,
- cm_processor, true);
+ processor_transform_apply_threaded(NULL, display_buffer_float, width, height, channels,
+ cm_processor, true, false);
IMB_buffer_byte_from_float(display_buffer, display_buffer_float,
channels, dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB,
@@ -2463,9 +2588,17 @@ ColorManagedLook *colormanage_look_add(const char *name, const char *process_spa
look = MEM_callocN(sizeof(ColorManagedLook), "ColorManagedLook");
look->index = index + 1;
BLI_strncpy(look->name, name, sizeof(look->name));
+ BLI_strncpy(look->ui_name, name, sizeof(look->ui_name));
BLI_strncpy(look->process_space, process_space, sizeof(look->process_space));
look->is_noop = is_noop;
+ /* Detect view specific looks. */
+ const char *separator_offset = strstr(look->name, " - ");
+ if (separator_offset) {
+ BLI_strncpy(look->view, look->name, separator_offset - look->name + 1);
+ BLI_strncpy(look->ui_name, separator_offset + strlen(" - "), sizeof(look->ui_name));
+ }
+
BLI_addtail(&global_looks, look);
global_tot_looks++;
@@ -2566,15 +2699,27 @@ void IMB_colormanagement_view_items_add(EnumPropertyItem **items, int *totitem,
}
}
-void IMB_colormanagement_look_items_add(struct EnumPropertyItem **items, int *totitem)
+void IMB_colormanagement_look_items_add(struct EnumPropertyItem **items, int *totitem, const char *view_name)
{
ColorManagedLook *look;
+ const char *view_filter = NULL;
+
+ /* Test if this view transform is limited to specific looks. */
+ for (look = global_looks.first; look; look = look->next) {
+ if (STREQ(look->view, view_name)) {
+ view_filter = view_name;
+ }
+ }
for (look = global_looks.first; look; look = look->next) {
+ if (!look->is_noop && view_filter && !STREQ(look->view, view_filter)) {
+ continue;
+ }
+
EnumPropertyItem item;
item.value = look->index;
- item.name = look->name;
+ item.name = look->ui_name;
item.identifier = look->name;
item.icon = 0;
item.description = "";
@@ -3095,6 +3240,25 @@ void IMB_colormanagement_processor_apply(ColormanageProcessor *cm_processor, flo
}
}
+void IMB_colormanagement_processor_apply_byte(ColormanageProcessor *cm_processor,
+ unsigned char *buffer,
+ int width, int height, int channels)
+{
+ /* TODO(sergey): Would be nice to support arbitrary channels configurations,
+ * but for now it's not so important.
+ */
+ BLI_assert(channels == 4);
+ float pixel[4];
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ size_t offset = channels * (((size_t)y) * width + x);
+ rgba_uchar_to_float(pixel, buffer + offset);
+ IMB_colormanagement_processor_apply_v4(cm_processor, pixel);
+ rgba_float_to_uchar(buffer + offset, pixel);
+ }
+ }
+}
+
void IMB_colormanagement_processor_free(ColormanageProcessor *cm_processor)
{
if (cm_processor->curve_mapping)
@@ -3268,6 +3432,13 @@ bool IMB_colormanagement_setup_glsl_draw_from_space(const ColorManagedViewSettin
update_glsl_display_processor(applied_view_settings, display_settings,
from_colorspace ? from_colorspace->name : global_role_scene_linear);
+ if (global_glsl_state.processor == NULL) {
+ /* Happens when requesting non-existing color space or LUT in the
+ * configuration file does not exist.
+ */
+ return false;
+ }
+
return OCIO_setupGLSLDraw(&global_glsl_state.ocio_glsl_state, global_glsl_state.processor,
global_glsl_state.use_curve_mapping ? &global_glsl_state.curve_mapping_settings : NULL,
dither, predivide);
@@ -3304,5 +3475,7 @@ bool IMB_colormanagement_setup_glsl_draw_ctx(const bContext *C, float dither, bo
/* Finish GLSL-based display space conversion */
void IMB_colormanagement_finish_glsl_draw(void)
{
- OCIO_finishGLSLDraw(global_glsl_state.ocio_glsl_state);
+ if (global_glsl_state.ocio_glsl_state != NULL) {
+ OCIO_finishGLSLDraw(global_glsl_state.ocio_glsl_state);
+ }
}
diff --git a/source/blender/imbuf/intern/dds/dds_api.cpp b/source/blender/imbuf/intern/dds/dds_api.cpp
index 12e03f55450..67a0b0ffd00 100644
--- a/source/blender/imbuf/intern/dds/dds_api.cpp
+++ b/source/blender/imbuf/intern/dds/dds_api.cpp
@@ -37,7 +37,7 @@ extern "C" {
#include <stdio.h> // printf
#include <fstream>
-#if defined (WIN32) && !defined(FREE_WINDOWS)
+#if defined (WIN32)
#include "utfconv.h"
#endif
@@ -62,7 +62,7 @@ int imb_save_dds(struct ImBuf *ibuf, const char *name, int /*flags*/)
/* open file for writing */
std::ofstream fildes;
-#if defined (WIN32) && !defined(FREE_WINDOWS)
+#if defined (WIN32)
wchar_t *wname = alloc_utf16_from_8(name, 0);
fildes.open(wname);
free(wname);
diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c
index 1987c6d2a9a..38609d0a342 100644
--- a/source/blender/imbuf/intern/filter.c
+++ b/source/blender/imbuf/intern/filter.c
@@ -406,7 +406,7 @@ void IMB_filter_extend(struct ImBuf *ibuf, char *mask, int filter)
const int height = ibuf->y;
const int depth = 4; /* always 4 channels */
const int chsize = ibuf->rect_float ? sizeof(float) : sizeof(unsigned char);
- const int bsize = width * height * depth * chsize;
+ const size_t bsize = ((size_t)width) * height * depth * chsize;
const bool is_float = (ibuf->rect_float != NULL);
void *dstbuf = (void *) MEM_dupallocN(ibuf->rect_float ? (void *) ibuf->rect_float : (void *) ibuf->rect);
char *dstmask = mask == NULL ? NULL : (char *) MEM_dupallocN(mask);
@@ -499,7 +499,9 @@ void IMB_filter_extend(struct ImBuf *ibuf, char *mask, int filter)
/* keep the original buffer up to date. */
memcpy(srcbuf, dstbuf, bsize);
- if (dstmask != NULL) memcpy(srcmask, dstmask, width * height);
+ if (dstmask != NULL) {
+ memcpy(srcmask, dstmask, ((size_t)width) * height);
+ }
}
/* free memory */
diff --git a/source/blender/imbuf/intern/imbuf.h b/source/blender/imbuf/intern/imbuf.h
index 897a149a45c..90dad70fa61 100644
--- a/source/blender/imbuf/intern/imbuf.h
+++ b/source/blender/imbuf/intern/imbuf.h
@@ -67,8 +67,6 @@
# define BIG_LONG SWAP_LONG
#endif
-typedef unsigned char uchar;
-
#define IMB_DPI_DEFAULT 72.0f
#endif /* __IMBUF_H__ */
diff --git a/source/blender/imbuf/intern/metadata.c b/source/blender/imbuf/intern/metadata.c
index 134bbe88f15..da39967a4fe 100644
--- a/source/blender/imbuf/intern/metadata.c
+++ b/source/blender/imbuf/intern/metadata.c
@@ -81,7 +81,9 @@ bool IMB_metadata_get_field(struct ImBuf *img, const char *key, char *field, con
void IMB_metadata_copy(struct ImBuf *dimb, struct ImBuf *simb)
{
+ BLI_assert(dimb != simb);
if (simb->metadata) {
+ IMB_metadata_free(dimb);
dimb->metadata = IDP_CopyProperty(simb->metadata);
}
}
diff --git a/source/blender/imbuf/intern/oiio/CMakeLists.txt b/source/blender/imbuf/intern/oiio/CMakeLists.txt
index c873fa3f32d..a4fb9c5aee1 100644
--- a/source/blender/imbuf/intern/oiio/CMakeLists.txt
+++ b/source/blender/imbuf/intern/oiio/CMakeLists.txt
@@ -49,6 +49,11 @@ if(WITH_OPENIMAGEIO)
${OPENIMAGEIO_INCLUDE_DIRS}
${BOOST_INCLUDE_DIR}
)
+ if(WITH_IMAGE_OPENEXR)
+ list(APPEND INC_SYS
+ ${OPENEXR_INCLUDE_DIRS}
+ )
+ endif()
add_definitions(-DWITH_OPENIMAGEIO)
endif()
diff --git a/source/blender/imbuf/intern/oiio/openimageio_api.cpp b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
index 11bf45418d6..b123d508f99 100644
--- a/source/blender/imbuf/intern/oiio/openimageio_api.cpp
+++ b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
@@ -31,7 +31,7 @@
#include <set>
-#if defined(WIN32) && !defined(FREE_WINDOWS)
+#if defined(WIN32)
#include "utfconv.h"
#endif
@@ -213,7 +213,7 @@ struct ImBuf *imb_load_photoshop(const char *filename, int flags, char colorspac
in = ImageInput::create(filename);
if (!in) {
std::cerr << __func__ << ": ImageInput::create() failed:" << std::endl
- << OpenImageIO::geterror() << std::endl;
+ << OIIO_NAMESPACE::geterror() << std::endl;
return NULL;
}
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index 89e796fb7ee..ec544e65355 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -69,7 +69,7 @@
#include <openexr_api.h>
-#if defined (WIN32) && !defined(FREE_WINDOWS)
+#if defined (WIN32)
#include "utfconv.h"
#endif
@@ -77,7 +77,7 @@ extern "C"
{
// The following prevents a linking error in debug mode for MSVC using the libs in CVS
-#if defined(WITH_OPENEXR) && defined(_WIN32) && defined(DEBUG) && !defined(__MINGW32__) && _MSC_VER < 1900
+#if defined(WITH_OPENEXR) && defined(_WIN32) && defined(DEBUG) && _MSC_VER < 1900
_CRTIMP void __cdecl _invalid_parameter_noinfo(void)
{
}
@@ -180,7 +180,7 @@ public:
: IStream(filename)
{
/* utf-8 file path support on windows */
-#if defined (WIN32) && !defined(FREE_WINDOWS)
+#if defined (WIN32)
wchar_t *wfilename = alloc_utf16_from_8(filename, 0);
ifs.open(wfilename, std::ios_base::binary);
free(wfilename);
@@ -243,7 +243,7 @@ public:
: OStream(filename)
{
/* utf-8 file path support on windows */
-#if defined (WIN32) && !defined(FREE_WINDOWS)
+#if defined (WIN32)
wchar_t *wfilename = alloc_utf16_from_8(filename, 0);
ofs.open(wfilename, std::ios_base::binary);
free(wfilename);
@@ -1026,15 +1026,16 @@ void IMB_exr_set_channel(void *handle, const char *layname, const char *passname
ExrChannel *echan;
char name[EXR_TOT_MAXNAME + 1];
- if (layname) {
+ if (layname && layname[0] != '\0') {
char lay[EXR_LAY_MAXNAME + 1], pass[EXR_PASS_MAXNAME + 1];
BLI_strncpy(lay, layname, EXR_LAY_MAXNAME);
BLI_strncpy(pass, passname, EXR_PASS_MAXNAME);
BLI_snprintf(name, sizeof(name), "%s.%s", lay, pass);
}
- else
+ else {
BLI_strncpy(name, passname, EXR_TOT_MAXNAME - 1);
+ }
echan = (ExrChannel *)BLI_findstring(&data->channels, name, offsetof(ExrChannel, name));
@@ -1043,8 +1044,9 @@ void IMB_exr_set_channel(void *handle, const char *layname, const char *passname
echan->ystride = ystride;
echan->rect = rect;
}
- else
+ else {
printf("IMB_exr_set_channel error %s\n", name);
+ }
}
float *IMB_exr_channel_rect(void *handle, const char *layname, const char *passname, const char *viewname)
diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c
index 5192e3f2d26..503e63a3fb1 100644
--- a/source/blender/imbuf/intern/png.c
+++ b/source/blender/imbuf/intern/png.c
@@ -613,11 +613,12 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors
int unit_type;
png_uint_32 xres, yres;
- if (png_get_pHYs(png_ptr, info_ptr, &xres, &yres, &unit_type))
+ if (png_get_pHYs(png_ptr, info_ptr, &xres, &yres, &unit_type)) {
if (unit_type == PNG_RESOLUTION_METER) {
ibuf->ppm[0] = xres;
ibuf->ppm[1] = yres;
}
+ }
}
}
else {
diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c
index 71e74928e20..a21468e474c 100644
--- a/source/blender/imbuf/intern/radiance_hdr.c
+++ b/source/blender/imbuf/intern/radiance_hdr.c
@@ -340,13 +340,14 @@ static int fwritecolrs(FILE *file, int width, int channels, unsigned char *ibufs
}
if (((beg - j) > 1) && ((beg - j) < MINRUN)) {
c2 = j + 1;
- while (rgbe_scan[c2++][i] == rgbe_scan[j][i])
+ while (rgbe_scan[c2++][i] == rgbe_scan[j][i]) {
if (c2 == beg) { /* short run */
putc((unsigned char)(128 + beg - j), file);
putc((unsigned char)(rgbe_scan[j][i]), file);
j = beg;
break;
}
+ }
}
while (j < beg) { /* write out non-run */
if ((c2 = beg - j) > 128) c2 = 128;
diff --git a/source/blender/imbuf/intern/thumbs_blend.c b/source/blender/imbuf/intern/thumbs_blend.c
index b5c6deb6b01..00fb1a44dff 100644
--- a/source/blender/imbuf/intern/thumbs_blend.c
+++ b/source/blender/imbuf/intern/thumbs_blend.c
@@ -32,6 +32,7 @@
#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"
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 5c1bfc229da..ed29f2336de 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -82,8 +82,6 @@ enum {
IDP_FLOAT = 2,
IDP_ARRAY = 5,
IDP_GROUP = 6,
- /* the ID link property type hasn't been implemented yet, this will require
- * some cleanup of blenkernel, most likely. */
IDP_ID = 7,
IDP_DOUBLE = 8,
IDP_IDPARRAY = 9,
@@ -98,6 +96,17 @@ 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 {
IDP_FLAG_GHOST = 1 << 7, /* this means the property is set but RNA will return false when checking
@@ -155,8 +164,9 @@ typedef struct Library {
struct PackedFile *packedfile;
+ /* Temp data needed by read/write code. */
int temp_index;
- int _pad;
+ short versionfile, subversionfile; /* see BLENDER_VERSION, BLENDER_SUBVERSION, needed for do_versions */
} Library;
enum eIconSizes {
@@ -172,6 +182,13 @@ enum ePreviewImage_Flag {
PRV_USER_EDITED = (1 << 1), /* if user-edited, do not auto-update this anymore! */
};
+/* for PreviewImage->tag */
+enum {
+ PRV_TAG_DEFFERED = (1 << 0), /* Actual loading of preview is deffered. */
+ PRV_TAG_DEFFERED_RENDERING = (1 << 1), /* Deffered preview is being loaded. */
+ PRV_TAG_DEFFERED_DELETE = (1 << 2), /* Deffered preview should be deleted asap. */
+};
+
typedef struct PreviewImage {
/* All values of 2 are really NUM_ICON_SIZES */
unsigned int w[2];
@@ -184,12 +201,12 @@ typedef struct PreviewImage {
struct GPUTexture *gputexture[2];
int icon_id; /* Used by previews outside of ID context. */
- char pad[3];
- char use_deferred; /* for now a mere bool, if we add more deferred loading methods we can switch to bitflag. */
+ short tag; /* Runtime data. */
+ char pad[2];
} PreviewImage;
#define PRV_DEFERRED_DATA(prv) \
- (CHECK_TYPE_INLINE(prv, PreviewImage *), BLI_assert((prv)->use_deferred), (void *)((prv) + 1))
+ (CHECK_TYPE_INLINE(prv, PreviewImage *), BLI_assert((prv)->tag & PRV_TAG_DEFFERED), (void *)((prv) + 1))
/**
* Defines for working with IDs.
@@ -248,6 +265,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. */
@@ -269,8 +288,9 @@ typedef enum ID_Type {
#define ID_FAKE_USERS(id) ((((ID *)id)->flag & LIB_FAKEUSER) ? 1 : 0)
#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 : (_bmain)->name)
@@ -283,9 +303,9 @@ typedef enum ID_Type {
#endif
#define GS(a) (CHECK_TYPE_ANY(a, char *, const char *, char [66], const char[66]), (*((const short *)(a))))
-#define ID_NEW(a) if ( (a) && (a)->id.newid ) (a) = (void *)(a)->id.newid
-#define ID_NEW_US(a) if ( (a)->id.newid) { (a) = (void *)(a)->id.newid; (a)->id.us++; }
-#define ID_NEW_US2(a) if (((ID *)a)->newid) { (a) = ((ID *)a)->newid; ((ID *)a)->us++; }
+#define ID_NEW_SET(_id, _idn) \
+ (((ID *)(_id))->newid = (ID *)(_idn), ((ID *)(_id))->newid->tag |= LIB_TAG_NEW, (void *)((ID *)(_id))->newid)
+#define ID_NEW_REMAP(a) if ((a) && (a)->id.newid) (a) = (void *)(a)->id.newid
/* id->flag (persitent). */
enum {
@@ -329,7 +349,8 @@ enum {
/* tag datablock has having actually increased usercount for the extra virtual user. */
LIB_TAG_EXTRAUSER_SET = 1 << 7,
- /* RESET_AFTER_USE tag newly duplicated/copied IDs. */
+ /* RESET_AFTER_USE tag newly duplicated/copied IDs.
+ * Also used internally in readfile.c to mark datablocks needing do_versions. */
LIB_TAG_NEW = 1 << 8,
/* RESET_BEFORE_USE free test flag.
* TODO make it a RESET_AFTER_USE too. */
@@ -379,9 +400,11 @@ enum {
FILTER_ID_WO = (1 << 26),
FILTER_ID_PA = (1 << 27),
FILTER_ID_CF = (1 << 28),
+ FILTER_ID_WS = (1 << 29),
+ FILTER_ID_LP = (1 << 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,
@@ -410,12 +433,14 @@ enum {
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,
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index f3df9090d41..90d6bbb4f1e 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -76,6 +76,8 @@ typedef struct bMotionPath {
int start_frame; /* for drawing paths, the start frame number */
int end_frame; /* for drawing paths, the end frame number */
+ float color[3]; /* optional custom color */
+ int line_thickness; /* line thickness */
int flag; /* baking settings - eMotionPath_Flag */
} bMotionPath;
@@ -84,7 +86,11 @@ typedef enum eMotionPath_Flag {
/* (for bones) path represents the head of the bone */
MOTIONPATH_FLAG_BHEAD = (1 << 0),
/* motion path is being edited */
- MOTIONPATH_FLAG_EDIT = (1 << 1)
+ MOTIONPATH_FLAG_EDIT = (1 << 1),
+ /* Custom colors */
+ MOTIONPATH_FLAG_CUSTOM = (1 << 2),
+ /* Draw lines or only points */
+ MOTIONPATH_FLAG_LINES = (1 << 3)
} eMotionPath_Flag;
/* Visualization General --------------------------- */
@@ -174,6 +180,18 @@ 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;
+
/* ************************************************ */
/* Poses */
@@ -232,6 +250,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*/
@@ -252,8 +272,10 @@ typedef struct bPoseChannel {
struct bPoseChannel *bbone_prev; /* next/prev bones to use as handle references when calculating bbones (optional) */
struct bPoseChannel *bbone_next;
-
+
void *temp; /* use for outliner */
+ /* Runtime data for color and bbone segment matrix. */
+ bPoseChannelDrawData *draw_data;
} bPoseChannel;
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index 31fe8fe563e..e50a2637fff 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -939,7 +939,10 @@ typedef enum eAnimData_Flag {
ADT_UI_ACTIVE = (1<<15),
/* F-Curves from this AnimData block are not visible in the Graph Editor */
- ADT_CURVES_NOT_VISIBLE = (1<<16)
+ ADT_CURVES_NOT_VISIBLE = (1<<16),
+
+ /* F-Curves from this AnimData block are always visible */
+ ADT_CURVES_ALWAYS_VISIBLE = (1<<17),
} eAnimData_Flag;
/* Animation Data recalculation settings (to be set by depsgraph) */
diff --git a/source/blender/makesdna/DNA_cachefile_types.h b/source/blender/makesdna/DNA_cachefile_types.h
index 1cda0233aa8..a353c94ae64 100644
--- a/source/blender/makesdna/DNA_cachefile_types.h
+++ b/source/blender/makesdna/DNA_cachefile_types.h
@@ -36,10 +36,10 @@
extern "C" {
#endif
-
/* CacheFile::flag */
enum {
CACHEFILE_DS_EXPAND = (1 << 0),
+ CACHEFILE_DIRTY = (1 << 1),
};
/* CacheFile::draw_flag */
@@ -47,10 +47,12 @@ enum {
CACHEFILE_KEYFRAME_DRAWN = (1 << 0),
};
+/* Representation of an object's path inside the Alembic file.
+ * Note that this is not a file path. */
typedef struct AlembicObjectPath {
struct AlembicObjectPath *next, *prev;
- char path[1024]; /* 1024 = FILE_MAX, might use PATH_MAX in the future. */
+ char path[4096];
} AlembicObjectPath;
typedef struct CacheFile {
@@ -58,6 +60,7 @@ typedef struct CacheFile {
struct AnimData *adt;
struct AbcArchiveHandle *handle;
+ void *handle_mutex;
/* Paths of the objects inside of the Alembic archive referenced by this
* CacheFile. */
diff --git a/source/blender/makesdna/DNA_camera_types.h b/source/blender/makesdna/DNA_camera_types.h
index 52e40cbc098..4aa3edcc788 100644
--- a/source/blender/makesdna/DNA_camera_types.h
+++ b/source/blender/makesdna/DNA_camera_types.h
@@ -85,6 +85,13 @@ typedef struct Camera {
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;
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index fc4e7de73f5..ca774864e95 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -461,6 +461,7 @@ typedef struct bObjectSolverConstraint {
/* Transform matrix cache constraint */
typedef struct bTransformCacheConstraint {
struct CacheFile *cache_file;
+ struct CacheReader *reader;
char object_path[1024]; /* FILE_MAX */
} bTransformCacheConstraint;
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index 902fa4ce987..e598c32173c 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -266,6 +266,7 @@ typedef struct Curve {
char pad2[2];
+ void *batch_cache;
} Curve;
#define CURVE_VFONT_ANY(cu) \
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index f0dc52c211b..5b1eeb798d7 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -91,13 +91,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,
@@ -144,13 +144,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_fileglobal_types.h b/source/blender/makesdna/DNA_fileglobal_types.h
index b2ab0d2a08d..6a01878a9ef 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 SceneLayer *cur_render_layer;
+ void *pad1;
+
int fileflags;
int globalf;
uint64_t build_commit_timestamp; /* commit timestamp from buildinfo */
diff --git a/source/blender/makesdna/DNA_genfile.h b/source/blender/makesdna/DNA_genfile.h
index a2981c0aa76..9e9ab974b01 100644
--- a/source/blender/makesdna/DNA_genfile.h
+++ b/source/blender/makesdna/DNA_genfile.h
@@ -100,6 +100,7 @@ void *DNA_struct_reconstruct(
int DNA_elem_array_size(const char *str);
int DNA_elem_offset(struct SDNA *sdna, const char *stype, const char *vartype, const char *name);
+bool DNA_struct_find(const struct SDNA *sdna, const char *stype);
bool DNA_struct_elem_find(const struct SDNA *sdna, const char *stype, const char *vartype, const char *name);
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index f1546053c5c..ba1bf1520ce 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -126,7 +126,7 @@ 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) */
+ /* "volumetric" strokes */
PC_COLOR_VOLUMETRIC = (1 << 4),
/* Use High quality fill */
PC_COLOR_HQ_FILL = (1 << 5)
@@ -244,6 +244,7 @@ typedef struct bGPDlayer {
float inverse[4][4]; /* inverse matrix (only used if parented) */
char parsubstr[64]; /* String describing subobject info, MAX_ID_NAME-2 */
short partype, pad;
+
float tintcolor[4]; /* Color used to tint layer, alpha value is used as factor */
float opacity; /* Opacity of the layer */
} bGPDlayer;
@@ -270,12 +271,14 @@ typedef enum eGPDlayer_Flag {
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)
+ GP_LAYER_UNLOCK_COLOR = (1 << 12),
+ /* always show onion skins (i.e. even during renders/animation playback) */
+ GP_LAYER_GHOST_ALWAYS = (1 << 13),
} eGPDlayer_Flag;
/* Grease-Pencil Annotations - 'DataBlock' */
@@ -295,12 +298,12 @@ typedef struct bGPdata {
short sbuffer_sflag; /* flags for stroke that cache represents */
void *sbuffer; /* stroke buffer (can hold GP_STROKE_BUFFER_MAX) */
float scolor[4]; /* buffer color using palettes */
+ float sfill[4]; /* buffer fill color */
char pad[6]; /* padding for compiler alignment error */
short sflag; /* settings for palette color */
- /* saved paletes and brushes */
+ /* saved palettes */
ListBase palettes;
- //ListBase brushes;
} bGPdata;
/* bGPdata->flag */
@@ -337,7 +340,7 @@ typedef enum eGPdata_Flag {
/* Convenience/cache flag to make it easier to quickly toggle 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)
} eGPdata_Flag;
#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_lamp_types.h b/source/blender/makesdna/DNA_lamp_types.h
index a2e39f93875..cb5b44f3268 100644
--- a/source/blender/makesdna/DNA_lamp_types.h
+++ b/source/blender/makesdna/DNA_lamp_types.h
@@ -67,7 +67,7 @@ typedef struct Lamp {
short pad2;
float clipsta, clipend;
- float bias, soft, compressthresh, bleedbias, pad5;
+ float bias, soft, compressthresh, bleedbias, bleedexp;
short bufsize, samp, buffers, filtertype;
char bufflag, buftype;
diff --git a/source/blender/makesdna/DNA_lattice_types.h b/source/blender/makesdna/DNA_lattice_types.h
index 242d6f0feeb..28a401676fc 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..03ca6cd8c5c
--- /dev/null
+++ b/source/blender/makesdna/DNA_layer_types.h
@@ -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.
+ *
+ * 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_listBase.h"
+
+typedef struct Base {
+ struct Base *next, *prev;
+ short flag;
+ short refcount;
+ short sx, sy;
+ struct Object *object;
+ unsigned int lay;
+ int flag_legacy;
+ struct IDProperty *collection_properties; /* used by depsgraph, flushed from collection-tree */
+} Base;
+
+typedef struct CollectionOverride {
+ struct CollectionOverride *next, *prev;
+ char name[64]; /* MAX_NAME */
+ /* TODO proper data */
+} CollectionOverride;
+
+typedef struct SceneLayerEngineData {
+ struct SceneLayerEngineData *next, *prev;
+ struct DrawEngineType *engine_type;
+ void *storage;
+ void (*free)(void *storage);
+} SceneLayerEngineData;
+
+typedef struct LayerCollection {
+ struct LayerCollection *next, *prev;
+ struct SceneCollection *scene_collection;
+ short flag;
+ /* TODO(sergey): Get rid of this once we've got CoW in DEG, */
+ short flag_evaluated;
+ short pad[2];
+ ListBase object_bases; /* (ObjectBase *)LinkData->data - synced with collection->objects and collection->filter_objects */
+ ListBase overrides;
+ ListBase layer_collections; /* synced with collection->collections */
+ struct IDProperty *properties; /* overrides */
+ struct IDProperty *properties_evaluated;
+} LayerCollection;
+
+typedef struct SceneLayer {
+ struct SceneLayer *next, *prev;
+ char name[64]; /* MAX_NAME */
+ char engine[32]; /* render engine */
+ short active_collection;
+ short flag;
+ short pad[2];
+ ListBase object_bases; /* ObjectBase */
+ struct SceneStats *stats; /* default allocated now */
+ struct Base *basact;
+ ListBase layer_collections; /* LayerCollection */
+ struct IDProperty *properties; /* overrides */
+ struct IDProperty *properties_evaluated;
+
+ /* Runtime data */
+ ListBase drawdata; /* SceneLayerEngineData */
+} SceneLayer;
+
+typedef struct SceneCollection {
+ struct SceneCollection *next, *prev;
+ char name[64]; /* MAX_NAME */
+ char filter[64]; /* MAX_NAME */
+ int active_object_index; /* for UI */
+ int pad;
+ ListBase objects; /* (Object *)LinkData->data */
+ ListBase filter_objects; /* (Object *)LinkData->data */
+ ListBase scene_collections; /* nested collections */
+} SceneCollection;
+
+/* Base->flag */
+enum {
+ BASE_SELECTED = (1 << 0),
+ BASE_VISIBLED = (1 << 1),
+ BASE_SELECTABLED = (1 << 2),
+ BASE_FROMDUPLI = (1 << 3),
+ BASE_DIRTY_ENGINE_SETTINGS = (1 << 4),
+ BASE_FROM_SET = (1 << 5), /* To be set only by the depsgraph */
+};
+
+/* LayerCollection->flag */
+enum {
+ COLLECTION_VISIBLE = (1 << 0),
+ COLLECTION_SELECTABLE = (1 << 1),
+};
+
+/* SceneLayer->flag */
+enum {
+ SCENE_LAYER_RENDER = (1 << 0),
+ SCENE_LAYER_ENGINE_DIRTY = (1 << 1),
+};
+
+
+/* *************************************************************** */
+/* Engine Settings */
+
+/* CollectionEngineSettings->type */
+typedef enum CollectionEngineSettingsType {
+ COLLECTION_MODE_NONE = 0,
+ COLLECTION_MODE_OBJECT = 1,
+ COLLECTION_MODE_EDIT = 2,
+ COLLECTION_MODE_PAINT_WEIGHT = 5,
+ COLLECTION_MODE_PAINT_VERTEX = 6,
+} CollectionModeSettingsType;
+
+/* *************************************************************** */
+
+
+#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..e65c36672b5
--- /dev/null
+++ b/source/blender/makesdna/DNA_lightprobe_types.h
@@ -0,0 +1,106 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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;
+
+ 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 */
+
+ float data_draw_size;
+
+ /* Runtime display data */
+ float distfalloff, distgridinf;
+ float pad;
+} 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),
+};
+
+/* 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,
+};
+
+#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 0c500e366a7..41ad12e63f2 100644
--- a/source/blender/makesdna/DNA_material_types.h
+++ b/source/blender/makesdna/DNA_material_types.h
@@ -90,6 +90,16 @@ typedef struct TexPaintSlot {
int pad;
} TexPaintSlot;
+/* Clay engine */
+
+/* MaterialRuntimeClay.flag */
+#define CLAY_OUTDATED 1
+
+/* MaterialEngineSettingsClay.type */
+#define CLAY_MATCAP_NONE 0
+#define CLAY_MATCAP_SIMPLE 1
+#define CLAY_MATCAP_COMPLETE 2
+
typedef struct Material {
ID id;
struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */
@@ -201,6 +211,17 @@ typedef struct Material {
char nmap_tangent_names[9][64]; /* [MAX_MTFACE+1][MAX_NAME]; +1 for empty name */
int nmap_tangent_names_count, pad5;
+ /* Transparency */
+ float alpha_threshold;
+ char blend_method;
+ char blend_shadow;
+ char blend_flag;
+ char pad6;
+
+ /* image to use for image/uv space, also bake target
+ * (not to be used shading/rendering pipeline, this is editor featyure only!). */
+ struct Image *edit_image;
+
struct TexPaintSlot *texpaintslot; /* cached slot for painting. Make sure to recalculate before use
* with refresh_texpaint_image_cache */
ListBase gpumaterial; /* runtime */
@@ -275,7 +296,7 @@ typedef struct Material {
#define MA_ONLYSHADOW 1024
#define MA_HALO_XALPHA 1024
#define MA_STAR 0x800
-#define MA_FACETEXTURE 0x800
+// #define MA_FACETEXTURE 0x800 /* deprecated */
#define MA_HALOTEX 0x1000
#define MA_HALOPUNO 0x2000
#define MA_ONLYCAST 0x2000
@@ -297,7 +318,7 @@ typedef struct Material {
/* 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_FACETEXTURE_ALPHA 0x20000000 /* deprecated */
#define MA_STR_B_UNITS 0x40000000
#define MA_STR_SURFDIFF 0x80000000
@@ -477,5 +498,28 @@ typedef struct Material {
#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),
+};
+
+/* blend_shadow */
+enum {
+ MA_BS_NONE = 0,
+ MA_BS_SOLID,
+ MA_BS_CLIP,
+ MA_BS_HASHED,
+};
+
#endif
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 64367789432..9794f37e997 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -66,7 +66,6 @@ typedef struct Mesh {
/* BMESH ONLY */
/*new face structures*/
struct MPoly *mpoly;
- struct MTexPoly *mtpoly;
struct MLoop *mloop;
struct MLoopUV *mloopuv;
struct MLoopCol *mloopcol;
@@ -128,6 +127,7 @@ typedef struct Mesh {
short totcol;
struct Multires *mr DNA_DEPRECATED; /* deprecated multiresolution modeling data, only keep for loading old files */
+ void *batch_cache;
} Mesh;
/* deprecated by MTFace, only here for file reading */
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index ca9c5020e0b..d8077c7bc36 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -164,8 +164,8 @@ 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 (ELEM(ed->v1, tri_edge[0], tri_edge[1]) &&
- * ELEM(ed->v2, tri_edge[0], tri_edge[1]))
+ * if (((ed->v1 == tri_edge[0]) && (ed->v1 == tri_edge[1])) ||
+ * ((ed->v1 == tri_edge[1]) && (ed->v1 == tri_edge[0])))
* {
* printf("real edge found %u %u\n", tri_edge[0], tri_edge[1]);
* }
@@ -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*/
@@ -470,58 +454,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_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 0424dc98a25..4959055ed10 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -86,6 +86,7 @@ typedef enum ModifierType {
eModifierType_NormalEdit = 50,
eModifierType_CorrectiveSmooth = 51,
eModifierType_MeshSequenceCache = 52,
+ eModifierType_SurfaceDeform = 53,
NUM_MODIFIER_TYPES
} ModifierType;
@@ -276,6 +277,7 @@ typedef struct MirrorModifierData {
short axis DNA_DEPRECATED; /* deprecated, use flag instead */
short flag;
float tolerance;
+ float uv_offset[2];
struct Object *mirror_ob;
} MirrorModifierData;
@@ -383,7 +385,7 @@ typedef struct DisplaceModifierData {
int direction;
char defgrp_name[64]; /* MAX_VGROUP_NAME */
float midlevel;
- int pad;
+ int space;
} DisplaceModifierData;
/* DisplaceModifierData->direction */
@@ -404,13 +406,19 @@ enum {
MOD_DISP_MAP_UV = 3,
};
+/* DisplaceModifierData->space */
+enum {
+ MOD_DISP_SPACE_LOCAL = 0,
+ MOD_DISP_SPACE_GLOBAL = 1,
+};
+
typedef struct UVProjectModifierData {
ModifierData modifier;
/* 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;
@@ -621,6 +629,9 @@ typedef struct CollisionModifierData {
unsigned int mvert_num;
unsigned int tri_num;
float time_x, time_xnew; /* cfra time of modifier */
+ char is_static; /* collider doesn't move this frame, i.e. x[].co==xnew[].co */
+ char pad[7];
+
struct BVHTree *bvhtree; /* bounding volume hierarchy for this cloth object */
} CollisionModifierData;
@@ -1546,6 +1557,7 @@ typedef struct MeshSeqCacheModifierData {
ModifierData modifier;
struct CacheFile *cache_file;
+ struct CacheReader *reader;
char object_path[1024]; /* 1024 = FILE_MAX */
char read_flag;
@@ -1560,6 +1572,46 @@ enum {
MOD_MESHSEQ_READ_COLOR = (1 << 3),
};
+typedef struct SDefBind {
+ unsigned int *vert_inds;
+ unsigned int numverts;
+ int mode;
+ float *vert_weights;
+ float normal_dist;
+ float influence;
+} SDefBind;
+
+typedef struct SDefVert {
+ SDefBind *binds;
+ unsigned int numbinds;
+ char pad[4];
+} SDefVert;
+
+typedef struct SurfaceDeformModifierData {
+ ModifierData modifier;
+
+ struct Object *target; /* bind target object */
+ SDefVert *verts; /* vertex bind data */
+ float falloff;
+ unsigned int numverts, numpoly;
+ int flags;
+ float mat[4][4];
+} SurfaceDeformModifierData;
+
+/* Surface Deform modifier flags */
+enum {
+ MOD_SDEF_BIND = (1 << 0),
+ MOD_SDEF_USES_LOOPTRI = (1 << 1),
+ MOD_SDEF_HAS_CONCAVE = (1 << 2),
+};
+
+/* Surface Deform vertex bind modes */
+enum {
+ MOD_SDEF_MODE_LOOPTRI = 0,
+ MOD_SDEF_MODE_NGON = 1,
+ MOD_SDEF_MODE_CENTROID = 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_movieclip_types.h b/source/blender/makesdna/DNA_movieclip_types.h
index 499f1c50155..56b99475909 100644
--- a/source/blender/makesdna/DNA_movieclip_types.h
+++ b/source/blender/makesdna/DNA_movieclip_types.h
@@ -146,6 +146,7 @@ enum {
MCLIP_USE_PROXY = (1 << 0),
MCLIP_USE_PROXY_CUSTOM_DIR = (1 << 1),
/* MCLIP_CUSTOM_START_FRAME = (1<<2), */ /* UNUSED */
+ MCLIP_DATA_EXPAND = (1 << 3),
MCLIP_TIMECODE_FLAGS = (MCLIP_USE_PROXY | MCLIP_USE_PROXY_CUSTOM_DIR)
};
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 46b30f41f5b..b922ac072b0 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -569,9 +569,9 @@ typedef struct NodeEllipseMask {
/* layer info for image node outputs */
typedef struct NodeImageLayer {
/* index in the Image->layers->passes lists */
- int pass_index;
- /* render pass flag, in case this is an original render pass */
- int pass_flag;
+ int pass_index DNA_DEPRECATED;
+ /* render pass name */
+ char pass_name[64]; /* amount defined in openexr_multi.h */
} NodeImageLayer;
typedef struct NodeBlurData {
@@ -595,6 +595,7 @@ typedef struct NodeBilateralBlurData {
short iter, pad;
} NodeBilateralBlurData;
+/* NOTE: Only for do-version code. */
typedef struct NodeHueSat {
float hue, sat, val;
} NodeHueSat;
@@ -667,7 +668,8 @@ typedef struct NodeScriptDict {
/* qdn: glare node */
typedef struct NodeGlare {
char quality, type, iter;
- char angle, pad_c1, size, pad[2];
+ /* XXX angle is only kept for backward/forward compatibility, was used for two different things, see T50736. */
+ char angle DNA_DEPRECATED, pad_c1, size, star_45, streaks;
float colmod, mix, threshold, fade;
float angle_ofs, pad_f1;
} NodeGlare;
@@ -811,7 +813,10 @@ typedef struct NodeShaderTexPointDensity {
short color_source;
short ob_color_source;
char vertex_attribute_name[64]; /* vertex attribute layer for color source, MAX_CUSTOMDATA_LAYER_NAME */
+ /* Used at runtime only by sampling RNA API. */
PointDensity pd;
+ int cached_resolution;
+ int pad2;
} NodeShaderTexPointDensity;
/* TEX_output */
diff --git a/source/blender/makesdna/DNA_object_fluidsim.h b/source/blender/makesdna/DNA_object_fluidsim.h
index a714195dd5d..846d5788d63 100644
--- a/source/blender/makesdna/DNA_object_fluidsim.h
+++ b/source/blender/makesdna/DNA_object_fluidsim.h
@@ -179,6 +179,7 @@ typedef struct FluidsimSettings {
#define OB_FLUIDSIM_ACTIVE (1 << 1)
#define OB_FLUIDSIM_OVERRIDE_TIME (1 << 2)
+#define OB_FLUIDSIM_SURF_DIR_DEFAULT "cache_fluid"
#define OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME "fluidsurface_preview_####.bobj.gz"
#define OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME "fluidsurface_final_####.bobj.gz"
#define OB_FLUIDSIM_SURF_FINAL_VEL_FNAME "fluidsurface_final_####.bvel.gz"
diff --git a/source/blender/makesdna/DNA_object_force.h b/source/blender/makesdna/DNA_object_force.h
index 59acefeffe4..9413a21633b 100644
--- a/source/blender/makesdna/DNA_object_force.h
+++ b/source/blender/makesdna/DNA_object_force.h
@@ -112,6 +112,12 @@ 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 */
} PartDeflect;
@@ -372,6 +378,7 @@ typedef struct SoftBody {
#define PFIELD_DO_ROTATION (1<<15)
#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 */
/* pd->falloff */
#define PFIELD_FALL_SPHERE 0
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 8566ec2368c..4eb44531767 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -65,6 +65,21 @@ 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 */
+} bFaceMap;
+
+/* Object Runtime display data */
+typedef struct ObjectEngineData {
+ struct ObjectEngineData *next, *prev;
+ struct DrawEngineType *engine_type;
+ void *storage;
+ void (*free)(void *storage);
+} ObjectEngineData;
+
#define MAX_VGROUP_NAME 64
/* bDeformGroup->flag */
@@ -142,7 +157,8 @@ 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 fmaps; /* list of facemaps */
+
int mode; /* Local object mode */
int restore_mode; /* Keep track of what mode to return to after toggling a mode */
@@ -223,7 +239,10 @@ typedef struct Object {
float jump_speed;
float fall_speed;
unsigned char max_jumps;
- char pad2[3];
+ char pad2;
+
+ /* Depsgraph */
+ short base_flag; /* used by depsgraph, flushed from base */
/** Collision mask settings */
unsigned short col_group, col_mask;
@@ -248,6 +267,8 @@ typedef struct Object {
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;
@@ -299,6 +320,17 @@ typedef struct Object {
LodLevel *currentlod;
struct PreviewImage *preview;
+
+ struct IDProperty *base_collection_properties; /* used by depsgraph, flushed from base */
+
+ ListBase drawdata; /* runtime, ObjectEngineData */
+ int deg_update_flag; /* what has been updated in this object */
+ int select_color;
+
+ /* Mesh structure createrd during object evaluaiton.
+ * It has all modifiers applied.
+ */
+ struct Mesh *mesh_evaluated;
} Object;
/* Warning, this is not used anymore because hooks are now modifiers */
@@ -331,10 +363,12 @@ typedef struct DupliObject {
/* persistent identifier for a dupli object, for inter-frame matching of
* objects with motion blur, or inter-update matching for syncing */
- int persistent_id[8]; /* MAX_DUPLI_RECUR */
+ 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 ********************* */
@@ -355,6 +389,7 @@ enum {
OB_CAMERA = 11,
OB_SPEAKER = 12,
+ OB_LIGHTPROBE = 13,
/* OB_WAVE = 21, */
OB_LATTICE = 22,
@@ -375,10 +410,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_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_AR
/* partype: first 4 bits: type */
enum {
@@ -597,6 +632,11 @@ enum {
OB_DEPS_EXTRA_DATA_RECALC = 1 << 1,
};
+/* ob->deg_update_flag */
+enum {
+ DEG_RUNTIME_DATA_UPDATE = 1 << 0,
+};
+
/* ob->scavisflag */
enum {
OB_VIS_SENS = 1 << 0,
diff --git a/source/blender/makesdna/DNA_outliner_types.h b/source/blender/makesdna/DNA_outliner_types.h
index 984e3334414..81575beaac8 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,14 @@ 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),
+};
/* TreeStoreElem->types */
#define TSE_NLA 1 /* NO ID */
@@ -96,6 +102,8 @@ 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 /* NO ID */
+#define TSE_SCENE_COLLECTION 39 /* NO ID */
/* Check whether given TreeStoreElem should have a real ID in its ->id member. */
@@ -103,7 +111,8 @@ typedef struct TreeStore {
(!ELEM((_tse)->type, TSE_NLA, TSE_NLA_TRACK, TSE_DRIVER_BASE, \
TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP, \
TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, \
- TSE_KEYMAP, TSE_KEYMAP_ITEM, TSE_ID_BASE, TSE_GP_LAYER))
+ TSE_KEYMAP, TSE_KEYMAP_ITEM, TSE_ID_BASE, TSE_GP_LAYER, \
+ TSE_SCENE_COLLECTION, TSE_LAYER_COLLECTION))
#endif
diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h
index ade53328bc2..f01da3a57fd 100644
--- a/source/blender/makesdna/DNA_particle_types.h
+++ b/source/blender/makesdna/DNA_particle_types.h
@@ -166,8 +166,9 @@ typedef struct ParticleSettings {
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;
@@ -324,7 +325,9 @@ typedef struct ParticleSystem {
struct ParticleDrawData *pdd;
float dt_frac; /* current time step, as a fraction of a frame */
- float _pad; /* spare capacity */
+ float lattice_strength; /* influence of the lattice modifier */
+
+ void *batch_cache;
} ParticleSystem;
typedef enum eParticleDrawFlag {
diff --git a/source/blender/makesdna/DNA_rigidbody_types.h b/source/blender/makesdna/DNA_rigidbody_types.h
index 5d76ffe57b5..381ee5d40e5 100644
--- a/source/blender/makesdna/DNA_rigidbody_types.h
+++ b/source/blender/makesdna/DNA_rigidbody_types.h
@@ -226,10 +226,16 @@ typedef struct RigidBodyCon {
float spring_stiffness_x;
float spring_stiffness_y;
float spring_stiffness_z;
+ float spring_stiffness_ang_x;
+ float spring_stiffness_ang_y;
+ float spring_stiffness_ang_z;
/* amount of velocity lost over time */
float spring_damping_x;
float spring_damping_y;
float spring_damping_z;
+ float spring_damping_ang_x;
+ float spring_damping_ang_y;
+ float spring_damping_ang_z;
/* motor settings */
float motor_lin_target_velocity; /* linear velocity the motor tries to hold */
@@ -295,7 +301,11 @@ typedef enum eRigidBodyCon_Flag {
RBC_FLAG_USE_SPRING_Z = (1 << 13),
/* motors */
RBC_FLAG_USE_MOTOR_LIN = (1 << 14),
- RBC_FLAG_USE_MOTOR_ANG = (1 << 15)
+ RBC_FLAG_USE_MOTOR_ANG = (1 << 15),
+ /* angular springs */
+ RBC_FLAG_USE_SPRING_ANG_X = (1 << 16),
+ RBC_FLAG_USE_SPRING_ANG_Y = (1 << 17),
+ RBC_FLAG_USE_SPRING_ANG_Z = (1 << 18)
} eRigidBodyCon_Flag;
/* ******************************** */
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 9dbe95ff440..d9fbbc39ba7 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -47,6 +47,8 @@ extern "C" {
#include "DNA_ID.h"
#include "DNA_freestyle_types.h"
#include "DNA_gpu_types.h"
+#include "DNA_layer_types.h"
+#include "DNA_material_types.h"
#include "DNA_userdef_types.h"
struct CurveMapping;
@@ -65,18 +67,13 @@ 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;
+#define BaseLegacy Base
/* ************************************************************* */
/* Output Format Data */
@@ -135,6 +132,37 @@ typedef struct QuicktimeCodecSettings {
int pad1;
} QuicktimeCodecSettings;
+typedef enum FFMpegPreset {
+ FFM_PRESET_NONE,
+ FFM_PRESET_ULTRAFAST,
+ FFM_PRESET_SUPERFAST,
+ FFM_PRESET_VERYFAST,
+ FFM_PRESET_FASTER,
+ FFM_PRESET_FAST,
+ FFM_PRESET_MEDIUM,
+ FFM_PRESET_SLOW,
+ FFM_PRESET_SLOWER,
+ FFM_PRESET_VERYSLOW,
+} FFMpegPreset;
+
+
+/* Mapping from easily-understandable descriptions to CRF values.
+ * Assumes we output 8-bit video. Needs to be remapped if 10-bit
+ * is output.
+ * We use a slightly wider than "subjectively sane range" according
+ * to https://trac.ffmpeg.org/wiki/Encode/H.264#a1.ChooseaCRFvalue
+ */
+typedef enum FFMpegCrf {
+ FFM_CRF_NONE = -1,
+ FFM_CRF_LOSSLESS = 0,
+ FFM_CRF_PERC_LOSSLESS = 17,
+ FFM_CRF_HIGH = 20,
+ FFM_CRF_MEDIUM = 23,
+ FFM_CRF_LOW = 26,
+ FFM_CRF_VERYLOW = 29,
+ FFM_CRF_LOWEST = 32,
+} FFMpegCrf;
+
typedef struct FFMpegCodecData {
int type;
int codec;
@@ -146,13 +174,18 @@ typedef struct FFMpegCodecData {
int audio_pad;
float audio_volume;
int gop_size;
+ int max_b_frames; /* only used if FFMPEG_USE_MAX_B_FRAMES flag is set. */
int flags;
+ int constant_rate_factor;
+ int ffmpeg_preset; /* see FFMpegPreset */
int rc_min_rate;
int rc_max_rate;
int rc_buffer_size;
int mux_packet_size;
int mux_rate;
+ int pad1;
+
IDProperty *properties;
} FFMpegCodecData;
@@ -193,7 +226,9 @@ typedef struct SceneRenderLayer {
int samples;
float pass_alpha_threshold;
-
+
+ IDProperty *prop;
+
struct FreestyleConfig freestyleConfig;
} SceneRenderLayer;
@@ -247,9 +282,43 @@ typedef enum ScenePassType {
SCE_PASS_SUBSURFACE_DIRECT = (1 << 28),
SCE_PASS_SUBSURFACE_INDIRECT = (1 << 29),
SCE_PASS_SUBSURFACE_COLOR = (1 << 30),
- SCE_PASS_DEBUG = (1 << 31), /* This is a virtual pass. */
} ScenePassType;
+#define RE_PASSNAME_COMBINED "Combined"
+#define RE_PASSNAME_Z "Depth"
+#define RE_PASSNAME_VECTOR "Vector"
+#define RE_PASSNAME_NORMAL "Normal"
+#define RE_PASSNAME_UV "UV"
+#define RE_PASSNAME_RGBA "Color"
+#define RE_PASSNAME_EMIT "Emit"
+#define RE_PASSNAME_DIFFUSE "Diffuse"
+#define RE_PASSNAME_SPEC "Spec"
+#define RE_PASSNAME_SHADOW "Shadow"
+
+#define RE_PASSNAME_AO "AO"
+#define RE_PASSNAME_ENVIRONMENT "Env"
+#define RE_PASSNAME_INDIRECT "Indirect"
+#define RE_PASSNAME_REFLECT "Reflect"
+#define RE_PASSNAME_REFRACT "Refract"
+#define RE_PASSNAME_INDEXOB "IndexOB"
+#define RE_PASSNAME_INDEXMA "IndexMA"
+#define RE_PASSNAME_MIST "Mist"
+
+#define RE_PASSNAME_RAYHITS "RayHits"
+#define RE_PASSNAME_DIFFUSE_DIRECT "DiffDir"
+#define RE_PASSNAME_DIFFUSE_INDIRECT "DiffInd"
+#define RE_PASSNAME_DIFFUSE_COLOR "DiffCol"
+#define RE_PASSNAME_GLOSSY_DIRECT "GlossDir"
+#define RE_PASSNAME_GLOSSY_INDIRECT "GlossInd"
+#define RE_PASSNAME_GLOSSY_COLOR "GlossCol"
+#define RE_PASSNAME_TRANSM_DIRECT "TransDir"
+#define RE_PASSNAME_TRANSM_INDIRECT "TransInd"
+#define RE_PASSNAME_TRANSM_COLOR "TransCol"
+
+#define RE_PASSNAME_SUBSURFACE_DIRECT "SubsurfaceDir"
+#define RE_PASSNAME_SUBSURFACE_INDIRECT "SubsurfaceInd"
+#define RE_PASSNAME_SUBSURFACE_COLOR "SubsurfaceCol"
+
/* note, srl->passflag is treestore element 'nr' in outliner, short still... */
/* View - MultiView */
@@ -506,6 +575,12 @@ typedef enum BakePassFilter {
#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 */
@@ -890,7 +965,7 @@ typedef struct GameData {
#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_DISPLAY_LISTS (1 << 5) /* deprecated */
#define GAME_GLSL_NO_LIGHTS (1 << 6)
#define GAME_GLSL_NO_SHADERS (1 << 7)
#define GAME_GLSL_NO_SHADOWS (1 << 8)
@@ -1038,6 +1113,7 @@ typedef struct ParticleEditSettings {
int draw_step, fade_frames;
struct Scene *scene;
+ struct SceneLayer *scene_layer;
struct Object *object;
struct Object *shape_object;
} ParticleEditSettings;
@@ -1094,7 +1170,7 @@ typedef struct Sculpt {
float gravity_factor;
/* scale for constant detail size */
- float constant_detail;
+ float constant_detail; /* Constant detail resolution (Blender unit / constant_detail) */
float detail_percent;
float pad;
@@ -1151,6 +1227,14 @@ typedef enum eGP_EditBrush_Types {
TOT_GP_EDITBRUSH_TYPES
} eGP_EditBrush_Types;
+/* Lock axis options */
+typedef enum eGP_Lockaxis_Types {
+ GP_LOCKAXIS_NONE = 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 {
short size; /* radius of brush */
@@ -1181,7 +1265,7 @@ typedef struct GP_BrushEdit_Settings {
int brushtype; /* eGP_EditBrush_Types */
int flag; /* eGP_BrushEdit_SettingsFlag */
- char pad[4];
+ int lock_axis; /* lock drawing to one axis */
float alpha; /* alpha factor for selection color */
} GP_BrushEdit_Settings;
@@ -1194,19 +1278,51 @@ typedef enum eGP_BrushEdit_SettingsFlag {
/* apply brush to strength */
GP_BRUSHEDIT_FLAG_APPLY_STRENGTH = (1 << 2),
/* apply brush to thickness */
- GP_BRUSHEDIT_FLAG_APPLY_THICKNESS = (1 << 3)
-
+ GP_BRUSHEDIT_FLAG_APPLY_THICKNESS = (1 << 3),
} eGP_BrushEdit_SettingsFlag;
-/* *************************************************************** */
-/* Transform Orientations */
-typedef struct TransformOrientation {
- struct TransformOrientation *next, *prev;
- char name[64]; /* MAX_NAME */
- float mat[3][3];
- int pad;
-} TransformOrientation;
+/* Settings for GP Interpolation Operators */
+typedef struct GP_Interpolate_Settings {
+ short flag; /* eGP_Interpolate_SettingsFlag */
+
+ char type; /* eGP_Interpolate_Type - Interpolation Mode */
+ char easing; /* eBezTriple_Easing - Easing mode (if easing equation used) */
+
+ float back; /* BEZT_IPO_BACK */
+ float amplitude, period; /* BEZT_IPO_ELASTIC */
+
+ struct CurveMapping *custom_ipo; /* custom interpolation curve (for use with GP_IPO_CURVEMAP) */
+} GP_Interpolate_Settings;
+
+/* GP_Interpolate_Settings.flag */
+typedef enum eGP_Interpolate_SettingsFlag {
+ /* apply interpolation to all layers */
+ GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS = (1 << 0),
+ /* apply interpolation to only selected */
+ GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED = (1 << 1),
+} eGP_Interpolate_SettingsFlag;
+
+/* GP_Interpolate_Settings.type */
+typedef enum eGP_Interpolate_Type {
+ /* Traditional Linear Interpolation */
+ GP_IPO_LINEAR = 0,
+
+ /* CurveMap Defined Interpolation */
+ GP_IPO_CURVEMAP = 1,
+
+ /* Easing Equations */
+ GP_IPO_BACK = 3,
+ GP_IPO_BOUNCE = 4,
+ GP_IPO_CIRC = 5,
+ GP_IPO_CUBIC = 6,
+ GP_IPO_ELASTIC = 7,
+ GP_IPO_EXPO = 8,
+ GP_IPO_QUAD = 9,
+ GP_IPO_QUART = 10,
+ GP_IPO_QUINT = 11,
+ GP_IPO_SINE = 12,
+} eGP_Interpolate_Type;
/* *************************************************************** */
/* Unified Paint Settings
@@ -1414,7 +1530,10 @@ typedef struct ToolSettings {
/* Grease Pencil Sculpt */
struct GP_BrushEdit_Settings gp_sculpt;
-
+
+ /* Grease Pencil Interpolation Tool(s) */
+ struct GP_Interpolate_Settings gp_interpolate;
+
/* Grease Pencil Drawing Brushes (bGPDbrush) */
ListBase gp_brushes;
@@ -1568,7 +1687,7 @@ typedef struct Scene {
struct Scene *set;
ListBase base;
- struct Base *basact; /* active base */
+ struct BaseLegacy *basact; /* active base */
struct Object *obedit; /* name replaces old G.obedit */
float cursor[3]; /* 3d cursor location */
@@ -1589,17 +1708,17 @@ 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... */
/* no, is on the right place (ton) */
struct RenderData r;
struct AudioData audio;
-
+
ListBase markers;
- ListBase transform_spaces;
-
+ ListBase transform_spaces DNA_DEPRECATED;
+
void *sound_scene;
void *playback_handle;
void *sound_scrub_handle;
@@ -1608,7 +1727,7 @@ 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;
+ struct Depsgraph *depsgraph_legacy;
void *pad1;
struct DagForest *theDag;
short dagflags;
@@ -1646,6 +1765,16 @@ typedef struct Scene {
struct RigidBodyWorld *rigidbody_world;
struct PreviewImage *preview;
+
+ ListBase render_layers;
+ struct SceneCollection *collection;
+ int active_layer;
+ int pad4;
+
+ IDProperty *collection_properties; /* settings to be overriden by layer collections */
+ IDProperty *layer_properties; /* settings to be override by workspaces */
+
+ int pad5[2];
} Scene;
/* **************** RENDERDATA ********************* */
@@ -1656,6 +1785,7 @@ typedef struct Scene {
#define SCER_LOCK_FRAME_SELECTION (1<<1)
/* timeline/keyframe jumping - only selected items (on by default) */
#define SCE_KEYS_NO_SELONLY (1<<2)
+#define SCER_SHOW_SUBFRAME (1<<3)
/* mode (int now) */
#define R_OSA 0x0001
@@ -1768,9 +1898,11 @@ typedef struct Scene {
#define R_STAMP_CAMERALENS 0x0800
#define R_STAMP_STRIPMETA 0x1000
#define R_STAMP_MEMORY 0x2000
+#define R_STAMP_HIDE_LABELS 0x4000
#define R_STAMP_ALL (R_STAMP_TIME|R_STAMP_FRAME|R_STAMP_DATE|R_STAMP_CAMERA|R_STAMP_SCENE| \
R_STAMP_NOTE|R_STAMP_MARKER|R_STAMP_FILENAME|R_STAMP_SEQSTRIP| \
- R_STAMP_RENDERTIME|R_STAMP_CAMERALENS|R_STAMP_MEMORY)
+ R_STAMP_RENDERTIME|R_STAMP_CAMERALENS|R_STAMP_MEMORY| \
+ R_STAMP_HIDE_LABELS)
/* alphamode */
#define R_ADDSKY 0
@@ -1832,6 +1964,8 @@ enum {
/* scene->r.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_CLAY;
+extern const char *RE_engine_id_BLENDER_EEVEE;
extern const char *RE_engine_id_CYCLES;
/* **************** SCENE ********************* */
@@ -1850,38 +1984,39 @@ extern const char *RE_engine_id_CYCLES;
/* depricate this! */
#define TESTBASE(v3d, base) ( \
- ((base)->flag & SELECT) && \
+ ((base)->flag_legacy & SELECT) && \
((base)->lay & v3d->lay) && \
(((base)->object->restrictflag & OB_RESTRICT_VIEW) == 0))
-#define TESTBASELIB(v3d, base) ( \
- ((base)->flag & SELECT) && \
- ((base)->lay & v3d->lay) && \
+
+#define TESTBASE_NEW(base) ( \
+ (((base)->flag & BASE_SELECTED) != 0) && \
+ (((base)->flag & BASE_VISIBLED) != 0))
+#define TESTBASELIB_NEW(base) ( \
+ (((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_VISIBLED) != 0))
+#define TESTBASELIB_BGMODE_NEW(base) ( \
+ (((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_VISIBLED) != 0))
+#define BASE_EDITABLE_BGMODE_NEW(base) ( \
((base)->object->id.lib == NULL) && \
- (((base)->object->restrictflag & OB_RESTRICT_VIEW) == 0))
-#define BASE_SELECTABLE(v3d, base) ( \
- (base->lay & v3d->lay) && \
- (base->object->restrictflag & (OB_RESTRICT_SELECT | OB_RESTRICT_VIEW)) == 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)
+ (((base)->flag & BASE_VISIBLED) != 0))
+#define BASE_SELECTABLE_NEW(base) \
+ (((base)->flag & BASE_SELECTABLED) != 0)
+#define BASE_VISIBLE_NEW(base) ( \
+ ((base)->flag & BASE_VISIBLED) != 0)
#define FIRSTBASE scene->base.first
#define LASTBASE scene->base.last
#define BASACT (scene->basact)
#define OBACT (BASACT ? BASACT->object: NULL)
+#define FIRSTBASE_NEW (sl)->object_bases.first
+#define LASTBASE_NEW (sl)->object_bases.last
+#define BASACT_NEW ((sl)->basact)
+#define OBACT_NEW (BASACT_NEW ? BASACT_NEW->object: NULL)
+
#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)
@@ -1896,7 +2031,7 @@ extern const char *RE_engine_id_CYCLES;
#define TIME2FRA(a) ((((double) scene->r.frs_sec) * (double)(a)) / (double)scene->r.frs_sec_base)
#define FPS (((double) scene->r.frs_sec) / (double)scene->r.frs_sec_base)
-/* base->flag is in DNA_object_types.h */
+/* base->legacy_flag is in DNA_object_types.h */
/* toolsettings->snap_flag */
#define SCE_SNAP 1
@@ -2006,6 +2141,7 @@ enum {
#endif
FFMPEG_AUTOSPLIT_OUTPUT = 2,
FFMPEG_LOSSLESS_OUTPUT = 4,
+ FFMPEG_USE_MAX_B_FRAMES = (1 << 3),
};
/* Paint.flags */
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index e208ef39719..75ae1cdab95 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"
@@ -52,10 +53,9 @@ typedef struct bScreen {
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 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) */
@@ -76,6 +76,8 @@ typedef struct bScreen {
struct wmTimer *animtimer; /* if set, screen has timer handler added in window */
void *context; /* context callback */
+
+ PreviewImage *preview;
} bScreen;
typedef struct ScrVert {
@@ -191,6 +193,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;
@@ -265,9 +274,10 @@ typedef struct ARegion {
ListBase ui_previews; /* uiPreview */
ListBase handlers; /* wmEventHandler */
ListBase panels_category; /* Panel categories runtime */
-
+
+ struct wmManipulatorMap *manipulator_map; /* manipulator-map of this region */
struct wmTimer *regiontimer; /* blend in/out */
-
+
char *headerstr; /* use this string to draw info */
void *regiondata; /* XXX 2.50, need spacedata equivalent? */
} ARegion;
diff --git a/source/blender/makesdna/DNA_smoke_types.h b/source/blender/makesdna/DNA_smoke_types.h
index 76de8443faa..c95e0a1f54a 100644
--- a/source/blender/makesdna/DNA_smoke_types.h
+++ b/source/blender/makesdna/DNA_smoke_types.h
@@ -52,6 +52,48 @@ enum {
/* viewsettings */
#define MOD_SMOKE_VIEW_SHOWBIG (1<<0)
+/* slice method */
+enum {
+ MOD_SMOKE_SLICE_VIEW_ALIGNED = 0,
+ MOD_SMOKE_SLICE_AXIS_ALIGNED = 1,
+};
+
+/* axis aligned method */
+enum {
+ AXIS_SLICE_FULL = 0,
+ AXIS_SLICE_SINGLE = 1,
+};
+
+/* single slice direction */
+enum {
+ SLICE_AXIS_AUTO = 0,
+ SLICE_AXIS_X = 1,
+ SLICE_AXIS_Y = 2,
+ SLICE_AXIS_Z = 3,
+};
+
+enum {
+ VECTOR_DRAW_NEEDLE = 0,
+ VECTOR_DRAW_STREAMLINE = 1,
+};
+
+enum {
+ FLUID_FIELD_DENSITY = 0,
+ FLUID_FIELD_HEAT = 1,
+ FLUID_FIELD_FUEL = 2,
+ FLUID_FIELD_REACT = 3,
+ FLUID_FIELD_FLAME = 4,
+ FLUID_FIELD_VELOCITY_X = 5,
+ FLUID_FIELD_VELOCITY_Y = 6,
+ FLUID_FIELD_VELOCITY_Z = 7,
+ FLUID_FIELD_COLOR_R = 8,
+ FLUID_FIELD_COLOR_G = 9,
+ FLUID_FIELD_COLOR_B = 10,
+ FLUID_FIELD_FORCE_X = 11,
+ FLUID_FIELD_FORCE_Y = 12,
+ FLUID_FIELD_FORCE_Z = 13,
+};
+
/* cache compression */
#define SM_CACHE_LIGHT 0
#define SM_CACHE_HEAVY 1
@@ -161,6 +203,20 @@ typedef struct SmokeDomainSettings {
float burning_rate, flame_smoke, flame_vorticity;
float flame_ignition, flame_max_temp;
float flame_smoke_color[3];
+
+ /* Display settings */
+ char slice_method, axis_slice_method;
+ char slice_axis, draw_velocity;
+ float slice_per_voxel;
+ float slice_depth;
+ float display_thickness;
+
+ struct ColorBand *coba;
+ float vector_scale;
+ char vector_draw_type;
+ char use_coba;
+ char coba_field; /* simulation field used for the color mapping */
+ char pad2;
} SmokeDomainSettings;
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 41188c2412f..833db376191 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -181,7 +181,8 @@ typedef enum eSpaceButtons_Context {
BCONTEXT_CONSTRAINT = 11,
BCONTEXT_BONE_CONSTRAINT = 12,
BCONTEXT_RENDER_LAYER = 13,
-
+ BCONTEXT_COLLECTION = 14,
+
/* always as last... */
BCONTEXT_TOT
} eSpaceButtons_Context;
@@ -273,21 +274,23 @@ typedef enum eSpaceOutliner_Flag {
/* 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_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_ACT_LAYER = 15,
+ SO_COLLECTIONS = 16,
} eSpaceOutliner_Mode;
/* SpaceOops->storeflag */
@@ -710,7 +713,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),
@@ -898,6 +901,10 @@ typedef struct SpaceImage {
char dt_uvstretch;
char around;
+ /* Filter settings when editor shows other object's UVs. */
+ int other_uv_filter;
+ int pad2;
+
MaskSpaceInfo mask_info;
} SpaceImage;
@@ -935,7 +942,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),
@@ -976,6 +983,12 @@ typedef enum eSpaceImage_Flag {
SI_SHOW_B = (1 << 29),
} eSpaceImage_Flag;
+/* SpaceImage->other_uv_filter */
+typedef enum eSpaceImage_OtherUVFilter {
+ SI_FILTER_SAME_IMAGE = 0,
+ SI_FILTER_ALL = 1,
+} eSpaceImage_OtherUVFilter;
+
/* Text Editor ============================================ */
/* Text Editor */
@@ -1141,7 +1154,7 @@ typedef enum eSpaceNode_Flag {
SNODE_SHOW_G = (1 << 8),
SNODE_SHOW_B = (1 << 9),
SNODE_AUTO_RENDER = (1 << 5),
- SNODE_SHOW_HIGHLIGHT = (1 << 6),
+// SNODE_SHOW_HIGHLIGHT = (1 << 6), DNA_DEPRECATED
// SNODE_USE_HIDDEN_PREVIEW = (1 << 10), DNA_DEPRECATED December2013
SNODE_NEW_SHADERS = (1 << 11),
SNODE_PIN = (1 << 12),
diff --git a/source/blender/makesdna/DNA_tracking_types.h b/source/blender/makesdna/DNA_tracking_types.h
index 9888b735b8b..42b72c1ff93 100644
--- a/source/blender/makesdna/DNA_tracking_types.h
+++ b/source/blender/makesdna/DNA_tracking_types.h
@@ -158,7 +158,10 @@ typedef struct MovieTrackingTrack {
* Used to prevent jumps of the camera when tracks are appearing or
* disappearing.
*/
- float weight, pad;
+ float weight;
+
+ /* track weight especially for 2D stabilization */
+ float weight_stab;
} MovieTrackingTrack;
typedef struct MovieTrackingPlaneMarker {
@@ -250,19 +253,24 @@ typedef struct MovieTrackingSettings {
typedef struct MovieTrackingStabilization {
int flag;
- int tot_track, act_track; /* total number and index of active track in list */
+ int tot_track, act_track; /* total number of translation tracks and index of active track in list */
+ int tot_rot_track, act_rot_track; /* total number of rotation tracks and index of active track in list */
/* 2d stabilization */
float maxscale; /* max auto-scale factor */
- MovieTrackingTrack *rot_track; /* track used to stabilize rotation */
+ MovieTrackingTrack *rot_track DNA_DEPRECATED; /* use TRACK_USE_2D_STAB_ROT on individual tracks instead */
+
+ int anchor_frame; /* reference point to anchor stabilization offset */
+ float target_pos[2]; /* expected target position of frame after raw stabilization, will be subtracted */
+ float target_rot; /* expected target rotation of frame after raw stabilization, will be compensated */
+ float scale; /* zoom factor known to be present on original footage. Also used for autoscale */
float locinf, scaleinf, rotinf; /* influence on location, scale and rotation */
int filter; /* filter used for pixel interpolation */
- /* some pre-computing run-time variables */
- int ok; /* are precomputed values and scaled buf relevant? */
- float scale; /* autoscale factor */
+ /* initialization and run-time data */
+ int ok DNA_DEPRECATED; /* Without effect now, we initialize on every frame. Formerly used for caching of init values */
} MovieTrackingStabilization;
typedef struct MovieTrackingReconstruction {
@@ -386,7 +394,8 @@ enum {
TRACK_USE_2D_STAB = (1 << 8),
TRACK_PREVIEW_GRAYSCALE = (1 << 9),
TRACK_DOPE_SEL = (1 << 10),
- TRACK_PREVIEW_ALPHA = (1 << 11)
+ TRACK_PREVIEW_ALPHA = (1 << 11),
+ TRACK_USE_2D_STAB_ROT = (1 << 12)
};
/* MovieTrackingTrack->motion_model */
@@ -452,7 +461,9 @@ enum {
enum {
TRACKING_2D_STABILIZATION = (1 << 0),
TRACKING_AUTOSCALE = (1 << 1),
- TRACKING_STABILIZE_ROTATION = (1 << 2)
+ TRACKING_STABILIZE_ROTATION = (1 << 2),
+ TRACKING_STABILIZE_SCALE = (1 << 3),
+ TRACKING_SHOW_STAB_TRACKS = (1 << 5)
};
/* MovieTrackingStrabilization->filter */
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 02a0b414bb3..01ad818d0f1 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -161,7 +161,7 @@ typedef struct ThemeUI {
/* Interface Elements (buttons, menus, icons) */
uiWidgetColors wcol_regular, wcol_tool, 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;
@@ -240,9 +240,9 @@ typedef struct ThemeSpace {
char wire[4], wire_edit[4], select[4];
char lamp[4], speaker[4], empty[4], camera[4];
char active[4], group[4], group_active[4], transform[4];
- char vertex[4], vertex_select[4], vertex_unreferenced[4];
+ char vertex[4], vertex_select[4], vertex_bevel[4], vertex_unreferenced[4];
char edge[4], edge_select[4];
- char edge_seam[4], edge_sharp[4], edge_facesel[4], edge_crease[4];
+ char edge_seam[4], edge_sharp[4], edge_facesel[4], edge_crease[4], edge_bevel[4];
char face[4], face_select[4]; /* solid faces */
char face_dot[4]; /* selected color */
char extra_edge_len[4], extra_edge_angle[4], extra_face_angle[4], extra_face_area[4];
@@ -467,13 +467,18 @@ typedef struct UserDef {
int audioformat;
int audiochannels;
- int scrollback; /* console scrollback limit */
- int dpi; /* range 48-128? */
- char node_margin; /* node insert offset (aka auto-offset) margin, but might be useful for later stuff as well */
+ int scrollback; /* console scrollback limit */
+ int dpi; /* range 48-128? */
+ float ui_scale; /* interface scale */
+ int pad1;
+ char node_margin; /* node insert offset (aka auto-offset) margin, but might be useful for later stuff as well */
char pad2;
short transopts;
short menuthreshold1, menuthreshold2;
-
+
+ /* startup template */
+ char app_template[64];
+
struct ListBase themes;
struct ListBase uifonts;
struct ListBase uistyles;
@@ -489,7 +494,8 @@ typedef struct UserDef {
short gp_settings;
short tb_leftmouse, tb_rightmouse;
struct SolidLight light[3];
- short tw_hotspot, tw_flag, tw_handlesize, tw_size;
+ short manipulator_flag, manipulator_size;
+ int pad3;
short textimeout, texcollectrate;
short wmdrawmethod; /* removed wmpad */
short dragthreshold;
@@ -497,7 +503,6 @@ typedef struct UserDef {
int prefetchframes;
float pad_rot_angle; /* control the rotation step of the view when PAD2, PAD4, PAD6&PAD8 is use */
short frameserverport;
- short pad4;
short obcenter_dia;
short rvisize; /* rotating view icon size */
short rvibright; /* rotating view icon brightness */
@@ -509,6 +514,8 @@ typedef struct UserDef {
char ipo_new; /* interpolation mode for newly added F-Curves */
char keyhandles_new; /* handle types for newly added keyframes */
char gpu_select_method;
+ char gpu_select_pick_deph;
+ char pad4;
char view_frame_type;
int view_frame_keyframes; /* number of keyframes to zoom around current frame */
@@ -593,7 +600,7 @@ typedef enum eUserPref_Flag {
/* USER_AUTOGRABGRID = (1 << 1), deprecated */
/* USER_AUTOROTGRID = (1 << 2), deprecated */
/* USER_AUTOSIZEGRID = (1 << 3), deprecated */
- USER_SCENEGLOBAL = (1 << 4),
+/* USER_SCENEGLOBAL = (1 << 4), deprecated */
USER_TRACKBALL = (1 << 5),
/* USER_DUPLILINK = (1 << 6), deprecated */
/* USER_FSCOLLUM = (1 << 7), deprecated */
@@ -782,14 +789,17 @@ typedef enum eText_Draw_Options {
USER_TEXT_DISABLE_AA = (1 << 0),
} eText_Draw_Options;
-/* tw_flag (transform widget) */
-
/* gp_settings (Grease Pencil Settings) */
typedef enum eGP_UserdefSettings {
GP_PAINT_DOSMOOTH = (1 << 0),
GP_PAINT_DOSIMPLIFY = (1 << 1),
} eGP_UserdefSettings;
+enum {
+ USER_MANIPULATOR_DRAW = (1 << 0),
+ USER_MANIPULATOR_SHADED = (1 << 1),
+};
+
/* color picker types */
typedef enum eColorPicker_Types {
USER_CP_CIRCLE_HSV = 0,
@@ -867,14 +877,6 @@ typedef enum eNdof_Flag {
#define NDOF_PIXELS_PER_SECOND 600.0f
-/* compute_device_type */
-typedef enum eCompute_Device_Type {
- USER_COMPUTE_DEVICE_NONE = 0,
- USER_COMPUTE_DEVICE_OPENCL = 1,
- USER_COMPUTE_DEVICE_CUDA = 2,
-} eCompute_Device_Type;
-
-
typedef enum eMultiSample_Type {
USER_MULTISAMPLE_NONE = 0,
USER_MULTISAMPLE_2 = 2,
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 4c243507e82..6a9b979596b 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -45,6 +45,7 @@ struct SmoothView3DStore;
struct wmTimer;
struct Material;
struct GPUFX;
+struct GPUViewport;
/* This is needed to not let VC choke on near and far... old
* proprietary MS extensions... */
@@ -65,6 +66,12 @@ struct GPUFX;
/* The near/far thing is a Win EXCEPTION. Thus, leave near/far in the
* code, and patch for windows. */
+
+typedef struct View3DDebug {
+ float znear, zfar;
+ char background;
+ char pad[7];
+} View3DDebug;
/* Background Picture in 3D-View */
typedef struct BGpic {
@@ -111,7 +118,7 @@ typedef struct RegionView3D {
struct wmTimer *smooth_timer;
- /* transform widget matrix */
+ /* transform manipulator matrix */
float twmat[4][4];
float viewquat[4]; /* view rotation, must be kept normalized */
@@ -130,7 +137,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;
@@ -147,6 +154,7 @@ typedef struct RegionView3D {
float rot_axis[3];
struct GPUFX *compositor;
+ struct GPUViewport *viewport;
} RegionView3D;
/* 3D ViewPort Struct */
@@ -202,7 +210,7 @@ typedef struct View3D {
short gridsubdiv; /* Number of subdivisions in the grid between each highlighted grid line */
char gridflag;
- /* transform widget info */
+ /* transform manipulator info */
char twtype, twmode, twflag;
short flag3;
@@ -217,8 +225,9 @@ typedef struct View3D {
char multiview_eye; /* multiview current eye - for internal use */
- /* built-in shader effects (eGPUFXFlags) */
- char pad3[4];
+ /* The active custom transform orientation of this 3D view. */
+ short custom_orientation_index;
+ char pad3[2];
/* note, 'fx_settings.dof' is currently _not_ allocated,
* instead set (temporarily) from camera */
@@ -244,6 +253,7 @@ typedef struct View3D {
short prev_drawtype;
short pad1;
float pad2;
+ View3DDebug debug;
} View3D;
@@ -314,12 +324,19 @@ typedef struct View3D {
#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_MODE_SHADE_OVERRIDE (1 << 15)
/* View3d->flag3 (short) */
#define V3D_SHOW_WORLD (1 << 0)
+/* View3d->debug.background */
+enum {
+ V3D_DEBUG_BACKGROUND_NONE = (1 << 0),
+ V3D_DEBUG_BACKGROUND_GRADIENT = (1 << 1),
+ V3D_DEBUG_BACKGROUND_WORLD = (1 << 2),
+};
+
/* View3D->around */
enum {
/* center of the bounding box */
@@ -361,13 +378,12 @@ enum {
#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 */
+#define V3D_MANIP_CUSTOM 5
-/* 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*/
+/* View3d->twflag (also) */
+enum {
+ V3D_MANIPULATOR_DRAW = (1 << 0),
+};
/* BGPic->flag */
/* may want to use 1 for select ? */
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index 14400c84b69..8558e3b5a08 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -177,9 +177,13 @@ typedef struct wmWindow {
void *ghostwin; /* don't want to include ghost.h stuff */
- 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 Scene *scene; /* The scene displayed in this window. */
+ struct Scene *new_scene; /* temporary when switching */
+
+ struct WorkSpaceInstanceHook *workspace_hook;
+
+ struct bScreen *screen DNA_DEPRECATED;
+ char screenname[64]; /* MAX_ID_NAME for matching window with active screen after file read */
short posx, posy, sizex, sizey; /* window coords */
short windowstate; /* borderless, full */
diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h
new file mode 100644
index 00000000000..3805e1c0a8a
--- /dev/null
+++ b/source/blender/makesdna/DNA_workspace_types.h
@@ -0,0 +1,135 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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__
+
+
+/* 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
+
+
+/**
+ * \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 DNA_PRIVATE_WORKSPACE;
+ /* 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;
+
+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 */
+
+ /* Custom transform orientations */
+ ListBase transform_orientations DNA_PRIVATE_WORKSPACE;
+
+ int object_mode DNA_PRIVATE_WORKSPACE; /* enum ObjectMode */
+ int pad;
+
+ struct SceneLayer *render_layer DNA_PRIVATE_WORKSPACE;
+} 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 comming 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;
+
+#endif /* __DNA_WORKSPACE_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_world_types.h b/source/blender/makesdna/DNA_world_types.h
index 5fd4c9fd407..2ab99617ee8 100644
--- a/source/blender/makesdna/DNA_world_types.h
+++ b/source/blender/makesdna/DNA_world_types.h
@@ -120,7 +120,8 @@ typedef struct World {
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];
+ short pr_texture, use_nodes, pad;
+ short update_flag; /* XXX temporary flag waiting for depsgraph proper tagging */
/* previews */
struct PreviewImage *preview;
@@ -128,6 +129,7 @@ typedef struct World {
/* nodes */
struct bNodeTree *nodetree;
+ float mistend, pad1; /* runtime : miststa + mistdist, used for drawing camera */
ListBase gpumaterial; /* runtime */
} World;
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index 6a41591e051..181d01e04fc 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -169,7 +169,7 @@ void DNA_sdna_free(SDNA *sdna)
}
MEM_freeN((void *)sdna->names);
- MEM_freeN(sdna->types);
+ MEM_freeN((void *)sdna->types);
MEM_freeN(sdna->structs);
#ifdef WITH_DNA_GHASH
@@ -1294,6 +1294,11 @@ int DNA_elem_offset(SDNA *sdna, const char *stype, const char *vartype, const ch
return (int)((intptr_t)cp);
}
+bool DNA_struct_find(const SDNA *sdna, const char *stype)
+{
+ return DNA_struct_find_nr(sdna, stype) != -1;
+}
+
bool DNA_struct_elem_find(const SDNA *sdna, const char *stype, const char *vartype, const char *name)
{
const int SDNAnr = DNA_struct_find_nr(sdna, stype);
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index 2cea8715a65..182a026df94 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -130,6 +130,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 +508,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++;
@@ -1342,4 +1357,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 7bad8991798..a07cb86fdf7 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -106,6 +106,7 @@ extern StructRNA RNA_ClothCollisionSettings;
extern StructRNA RNA_ClothModifier;
extern StructRNA RNA_ClothSettings;
extern StructRNA RNA_CloudsTexture;
+extern StructRNA RNA_CollectionEngineSettings;
extern StructRNA RNA_CollectionProperty;
extern StructRNA RNA_CollisionModifier;
extern StructRNA RNA_CollisionSensor;
@@ -201,6 +202,8 @@ extern StructRNA RNA_CurveMapPoint;
extern StructRNA RNA_CurveMapping;
extern StructRNA RNA_CurveModifier;
extern StructRNA RNA_CurvePoint;
+extern StructRNA RNA_Depsgraph;
+extern StructRNA RNA_DepsgraphIter;
extern StructRNA RNA_DampedTrackConstraint;
extern StructRNA RNA_DataTransferModifier;
extern StructRNA RNA_DecimateModifier;
@@ -230,6 +233,7 @@ extern StructRNA RNA_EnvironmentMapTexture;
extern StructRNA RNA_Event;
extern StructRNA RNA_ExplodeModifier;
extern StructRNA RNA_ExpressionController;
+extern StructRNA RNA_FaceMap;
extern StructRNA RNA_FCurve;
extern StructRNA RNA_FCurveSample;
extern StructRNA RNA_FFmpegSettings;
@@ -262,6 +266,7 @@ extern StructRNA RNA_GPencilLayer;
extern StructRNA RNA_GPencilPalette;
extern StructRNA RNA_GPencilPaletteColor;
extern StructRNA RNA_GPencilBrush;
+extern StructRNA RNA_GPencilInterpolateSettings;
extern StructRNA RNA_GPencilStroke;
extern StructRNA RNA_GPencilStrokePoint;
extern StructRNA RNA_GPencilSculptSettings;
@@ -316,6 +321,8 @@ extern StructRNA RNA_LaplacianSmoothModifier;
extern StructRNA RNA_Lattice;
extern StructRNA RNA_LatticeModifier;
extern StructRNA RNA_LatticePoint;
+extern StructRNA RNA_LayerCollection;
+extern StructRNA RNA_LayerCollectionOverride;
extern StructRNA RNA_Library;
extern StructRNA RNA_LimitDistanceConstraint;
extern StructRNA RNA_LimitLocationConstraint;
@@ -369,6 +376,8 @@ extern StructRNA RNA_LineStyleThicknessModifier_Tangent;
extern StructRNA RNA_LockedTrackConstraint;
extern StructRNA RNA_Macro;
extern StructRNA RNA_MagicTexture;
+extern StructRNA RNA_Manipulator;
+extern StructRNA RNA_ManipulatorProperties;
extern StructRNA RNA_MarbleTexture;
extern StructRNA RNA_MaskModifier;
extern StructRNA RNA_MaskSequence;
@@ -422,6 +431,7 @@ extern StructRNA RNA_MovieClipSequence;
extern StructRNA RNA_MovieTracking;
extern StructRNA RNA_MovieTrackingObject;
extern StructRNA RNA_MovieTrackingTrack;
+extern StructRNA RNA_MovieTrackingStabilization;
extern StructRNA RNA_MulticamSequence;
extern StructRNA RNA_MultiresModifier;
extern StructRNA RNA_MusgraveTexture;
@@ -480,6 +490,7 @@ extern StructRNA RNA_PointLamp;
extern StructRNA RNA_PointerProperty;
extern StructRNA RNA_Pose;
extern StructRNA RNA_PoseBone;
+extern StructRNA RNA_LightProbe;
extern StructRNA RNA_Property;
extern StructRNA RNA_PropertyGroup;
extern StructRNA RNA_PropertyGroupItem;
@@ -496,12 +507,15 @@ extern StructRNA RNA_RenderLayer;
extern StructRNA RNA_RenderPass;
extern StructRNA RNA_RenderResult;
extern StructRNA RNA_RenderSettings;
+extern StructRNA RNA_RenderEngineSettings;
+extern StructRNA RNA_RenderEngineSettingsClay;
extern StructRNA RNA_RigidBodyWorld;
extern StructRNA RNA_RigidBodyObject;
extern StructRNA RNA_RigidBodyJointConstraint;
extern StructRNA RNA_SPHFluidSettings;
extern StructRNA RNA_Scene;
extern StructRNA RNA_SceneGameData;
+extern StructRNA RNA_SceneLayer;
extern StructRNA RNA_SceneRenderLayer;
extern StructRNA RNA_SceneSequence;
extern StructRNA RNA_SceneObjects;
@@ -596,6 +610,7 @@ extern StructRNA RNA_StucciTexture;
extern StructRNA RNA_SubsurfModifier;
extern StructRNA RNA_SunLamp;
extern StructRNA RNA_SurfaceCurve;
+extern StructRNA RNA_SurfaceDeformModifier;
extern StructRNA RNA_SurfaceModifier;
extern StructRNA RNA_TexMapping;
extern StructRNA RNA_Text;
@@ -697,6 +712,7 @@ 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;
@@ -742,9 +758,10 @@ const char *RNA_struct_ui_description_raw(const StructRNA *type);
const char *RNA_struct_translation_context(const StructRNA *type);
int RNA_struct_ui_icon(const StructRNA *type);
-PropertyRNA *RNA_struct_name_property(StructRNA *type);
+PropertyRNA *RNA_struct_name_property(const StructRNA *type);
PropertyRNA *RNA_struct_iterator_property(StructRNA *type);
StructRNA *RNA_struct_base(StructRNA *type);
+const StructRNA *RNA_struct_base_child_of(const StructRNA *type, const StructRNA *parent_type);
bool RNA_struct_is_ID(const StructRNA *type);
bool RNA_struct_is_a(const StructRNA *type, const StructRNA *srna);
@@ -764,6 +781,8 @@ void RNA_struct_blender_type_set(StructRNA *srna, void *blender_type);
struct IDProperty *RNA_struct_idprops(PointerRNA *ptr, bool create);
bool RNA_struct_idprops_check(StructRNA *srna);
bool RNA_struct_idprops_register_check(const StructRNA *type);
+bool RNA_struct_idprops_datablock_allowed(const StructRNA *type);
+bool RNA_struct_idprops_contains_datablock(const StructRNA *type);
bool RNA_struct_idprops_unset(PointerRNA *ptr, const char *identifier);
PropertyRNA *RNA_struct_find_property(PointerRNA *ptr, const char *identifier);
@@ -792,6 +811,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);
+bool RNA_property_builtin(PropertyRNA *prop);
void *RNA_property_py_data_get(PropertyRNA *prop);
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop);
@@ -855,6 +875,7 @@ StructRNA *RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop);
int RNA_property_pointer_poll(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *value);
bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop);
+bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char **r_info);
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);
@@ -915,6 +936,7 @@ int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop);
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value);
int RNA_property_enum_get_default(PointerRNA *ptr, PropertyRNA *prop);
void *RNA_property_enum_py_data_get(PropertyRNA *prop);
+int RNA_property_enum_step(const struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int from_value, int step);
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop);
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value);
@@ -1139,6 +1161,8 @@ const struct ListBase *RNA_function_defined_parameters(FunctionRNA *func);
/* Utility */
+int RNA_parameter_flag(PropertyRNA *prop);
+
ParameterList *RNA_parameter_list_create(ParameterList *parms, PointerRNA *ptr, FunctionRNA *func);
void RNA_parameter_list_free(ParameterList *parms);
int RNA_parameter_list_size(ParameterList *parms);
@@ -1173,9 +1197,13 @@ int RNA_function_call_direct_va(struct bContext *C, struct ReportList *reports,
int RNA_function_call_direct_va_lookup(struct bContext *C, struct ReportList *reports, PointerRNA *ptr,
const char *identifier, const char *format, va_list args);
+const char *RNA_translate_ui_text(const char *text, const char *text_ctxt,
+ struct StructRNA *type, struct PropertyRNA *prop,
+ int translate);
+
/* ID */
-short RNA_type_to_ID_code(StructRNA *type);
+short RNA_type_to_ID_code(const StructRNA *type);
StructRNA *ID_code_to_RNA_type(short idcode);
diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h
index bf8ea048fae..54938b236d5 100644
--- a/source/blender/makesrna/RNA_define.h
+++ b/source/blender/makesrna/RNA_define.h
@@ -37,6 +37,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);
@@ -137,8 +145,8 @@ void RNA_def_property_enum_bitflag_sdna(PropertyRNA *prop, const char *structnam
void RNA_def_property_pointer_sdna(PropertyRNA *prop, const char *structname, const char *propname);
void RNA_def_property_collection_sdna(PropertyRNA *prop, const char *structname, const char *propname, const char *lengthpropname);
-void RNA_def_property_flag(PropertyRNA *prop, int flag);
-void RNA_def_property_clear_flag(PropertyRNA *prop, int flag);
+void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag);
+void RNA_def_property_clear_flag(PropertyRNA *prop, PropertyFlag flag);
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype);
void RNA_def_property_array(PropertyRNA *prop, int length);
void RNA_def_property_multi_array(PropertyRNA *prop, int dimension, const int length[]);
@@ -167,6 +175,7 @@ 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_update_runtime(PropertyRNA *prop, const void *func);
+void RNA_def_property_poll_runtime(PropertyRNA *prop, const void *func);
void RNA_def_property_dynamic_array_funcs(PropertyRNA *prop, const char *getlength);
void RNA_def_property_boolean_funcs(PropertyRNA *prop, const char *get, const char *set);
@@ -201,6 +210,9 @@ void RNA_def_function_output(FunctionRNA *func, PropertyRNA *ret);
void RNA_def_function_flag(FunctionRNA *func, int flag);
void RNA_def_function_ui_description(FunctionRNA *func, const char *description);
+void RNA_def_parameter_flags(PropertyRNA *prop, PropertyFlag flag_property, ParameterFlag flag_parameter);
+void RNA_def_parameter_clear_flags(PropertyRNA *prop, PropertyFlag flag_property, ParameterFlag flag_parameter);
+
/* Dynamic Enums
* strings are not freed, assumed pointing to static location. */
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index cba0ae12384..dd5e7ffe06f 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -61,6 +61,7 @@ extern EnumPropertyItem rna_enum_object_modifier_type_items[];
extern EnumPropertyItem rna_enum_constraint_type_items[];
extern EnumPropertyItem rna_enum_boidrule_type_items[];
extern EnumPropertyItem rna_enum_sequence_modifier_type_items[];
+extern EnumPropertyItem rna_enum_layer_collection_mode_settings_type_items[];
extern EnumPropertyItem rna_enum_modifier_triangulate_quad_method_items[];
extern EnumPropertyItem rna_enum_modifier_triangulate_ngon_method_items[];
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index 276531992f9..99ef0f9c8c4 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -155,7 +155,8 @@ typedef enum PropertySubType {
} PropertySubType;
/* Make sure enums are updated with these */
-/* HIGHEST FLAG IN USE: 1 << 31 */
+/* HIGHEST FLAG IN USE: 1 << 31
+ * FREE FLAGS: 2, 3, 7, 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
@@ -173,8 +174,10 @@ typedef enum PropertyFlag {
* and collections */
PROP_ANIMATABLE = (1 << 1),
- /* This flag means when the property's widget is in 'textedit' mode, it will be updated after every typed char,
- * instead of waiting final validation. Used e.g. for text searchbox. */
+ /* This flag means when the property's widget is in 'textedit' mode, it will be updated
+ * after every typed char, instead of waiting final validation. Used e.g. for text searchbox.
+ * It will also cause UI_BUT_VALUE_CLEAR to be set for text buttons. We could add an own flag
+ * for search/filter properties, but this works just fine for now. */
PROP_TEXTEDIT_UPDATE = (1 << 31),
/* icon */
@@ -185,20 +188,6 @@ typedef enum PropertyFlag {
/* do not write in presets */
PROP_SKIP_SAVE = (1 << 28),
- /* function parameter flags */
- PROP_REQUIRED = (1 << 2),
- PROP_OUTPUT = (1 << 3),
- PROP_RNAPTR = (1 << 11),
- /* This allows for non-breaking API updates, when adding non-critical new parameter to a callback function.
- * This way, old py code defining funcs without that parameter would still work.
- * WARNING: any parameter after the first PYFUNC_OPTIONAL one will be considered as optional!
- * NOTE: only for input parameters!
- */
- PROP_PYFUNC_OPTIONAL = (1 << 30),
- /* registering */
- PROP_REGISTER = (1 << 4),
- PROP_REGISTER_OPTIONAL = PROP_REGISTER | (1 << 5),
-
/* numbers */
/* each value is related proportionally (object scale, image size) */
@@ -229,25 +218,37 @@ typedef enum PropertyFlag {
/* need context for update function */
PROP_CONTEXT_UPDATE = (1 << 22),
- PROP_CONTEXT_PROPERTY_UPDATE = (1 << 22) | (1 << 27),
+ PROP_CONTEXT_PROPERTY_UPDATE = PROP_CONTEXT_UPDATE | (1 << 27),
+
+ /* registering */
+ PROP_REGISTER = (1 << 4),
+ PROP_REGISTER_OPTIONAL = PROP_REGISTER | (1 << 5),
/* Use for arrays or for any data that should not have a reference kept
* most common case is functions that return arrays where the array */
PROP_THICK_WRAP = (1 << 23),
- /* internal flags */
- PROP_BUILTIN = (1 << 7),
- PROP_EXPORT = (1 << 8),
- PROP_RUNTIME = (1 << 9),
- PROP_IDPROPERTY = (1 << 10),
- PROP_RAW_ACCESS = (1 << 13),
- PROP_RAW_ARRAY = (1 << 14),
- PROP_FREE_POINTERS = (1 << 15),
+ 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) */
} PropertyFlag;
+/* Function parameters flags.
+ * WARNING: 16bits only. */
+typedef enum ParameterFlag {
+ PARM_REQUIRED = (1 << 0),
+ PARM_OUTPUT = (1 << 1),
+ PARM_RNAPTR = (1 << 2),
+ /* This allows for non-breaking API updates, when adding non-critical new parameter to a callback function.
+ * This way, old py code defining funcs without that parameter would still work.
+ * WARNING: any parameter after the first PYFUNC_OPTIONAL one will be considered as optional!
+ * NOTE: only for input parameters!
+ */
+ PARM_PYFUNC_OPTIONAL = (1 << 3),
+} ParameterFlag;
+
struct CollectionPropertyIterator;
struct Link;
typedef int (*IteratorSkipFunc)(struct CollectionPropertyIterator *iter, void *data);
@@ -281,6 +282,7 @@ typedef struct CollectionPropertyIterator {
union {
ArrayIterator array;
ListBaseIterator listbase;
+ void *custom;
} internal;
int idprop;
int level;
@@ -433,6 +435,8 @@ typedef enum StructFlag {
STRUCT_GENERATED = (1 << 4),
STRUCT_FREE_POINTERS = (1 << 5),
STRUCT_NO_IDPROPERTIES = (1 << 6), /* Menus and Panels don't need properties */
+ STRUCT_NO_DATABLOCK_IDPROPERTIES = (1 << 7), /* e.g. for Operator */
+ STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES = (1 << 8), /* for PropertyGroup which contains pointers to datablocks */
} StructFlag;
typedef int (*StructValidateFunc)(struct PointerRNA *ptr, void *data, int *have_function);
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index b1f20bdf786..aede2bd9708 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -73,6 +73,7 @@ set(DEFSRC
rna_palette.c
rna_particle.c
rna_pose.c
+ rna_lightprobe.c
rna_property.c
rna_render.c
rna_rigidbody.c
@@ -95,6 +96,8 @@ set(DEFSRC
rna_userdef.c
rna_vfont.c
rna_wm.c
+ rna_wm_manipulator.c
+ rna_workspace.c
rna_world.c
)
@@ -125,6 +128,7 @@ set(APISRC
rna_ui_api.c
rna_vfont_api.c
rna_wm_api.c
+ rna_wm_manipulator_api.c
)
string(REGEX REPLACE "rna_([a-zA-Z0-9_-]*).c" "${CMAKE_CURRENT_BINARY_DIR}/rna_\\1_gen.c" GENSRC "${DEFSRC}")
@@ -177,9 +181,6 @@ set(INC_SYS
if(WITH_CYCLES)
add_definitions(-DWITH_CYCLES)
- if(WITH_CYCLES_DEBUG)
- add_definitions(-DWITH_CYCLES_DEBUG)
- endif()
endif()
if(WITH_PYTHON)
@@ -193,6 +194,10 @@ if(WITH_GAMEENGINE)
add_definitions(-DWITH_GAMEENGINE)
endif()
+if(WITH_CLAY_ENGINE)
+ add_definitions(-DWITH_CLAY_ENGINE)
+endif()
+
if(WITH_IMAGE_OPENEXR)
add_definitions(-DWITH_OPENEXR)
endif()
@@ -328,6 +333,10 @@ if(WITH_OPENVDB)
endif()
endif()
+if(WITH_INPUT_NDOF)
+ add_definitions(-DWITH_INPUT_NDOF)
+endif()
+
# Build makesrna executable
blender_include_dirs(
.
@@ -338,6 +347,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 daac46b14d1..4c0a1e9c181 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -50,7 +50,7 @@
#ifndef NDEBUG
void BLI_system_backtrace(FILE *fp)
{
- (void)fp;
+ (void)fp;
}
#endif
@@ -463,7 +463,7 @@ static const char *rna_parameter_type_name(PropertyRNA *parm)
{
PointerPropertyRNA *pparm = (PointerPropertyRNA *)parm;
- if (parm->flag & PROP_RNAPTR)
+ if (parm->flag_parameter & PARM_RNAPTR)
return "PointerRNA";
else
return rna_find_dna_type((const char *)pparm->type);
@@ -507,7 +507,7 @@ static void rna_float_print(FILE *f, float num)
{
if (num == -FLT_MAX) fprintf(f, "-FLT_MAX");
else if (num == FLT_MAX) fprintf(f, "FLT_MAX");
- else if ((int64_t)num == num) fprintf(f, "%.1ff", num);
+ else if ((ABS(num) < INT64_MAX) && ((int64_t)num == num)) fprintf(f, "%.1ff", num);
else fprintf(f, "%.10ff", num);
}
@@ -1409,23 +1409,23 @@ static void rna_set_raw_property(PropertyDefRNA *dp, PropertyRNA *prop)
if (STREQ(dp->dnatype, "char")) {
prop->rawtype = PROP_RAW_CHAR;
- prop->flag |= PROP_RAW_ACCESS;
+ prop->flag_internal |= PROP_INTERN_RAW_ACCESS;
}
else if (STREQ(dp->dnatype, "short")) {
prop->rawtype = PROP_RAW_SHORT;
- prop->flag |= PROP_RAW_ACCESS;
+ prop->flag_internal |= PROP_INTERN_RAW_ACCESS;
}
else if (STREQ(dp->dnatype, "int")) {
prop->rawtype = PROP_RAW_INT;
- prop->flag |= PROP_RAW_ACCESS;
+ prop->flag_internal |= PROP_INTERN_RAW_ACCESS;
}
else if (STREQ(dp->dnatype, "float")) {
prop->rawtype = PROP_RAW_FLOAT;
- prop->flag |= PROP_RAW_ACCESS;
+ prop->flag_internal |= PROP_INTERN_RAW_ACCESS;
}
else if (STREQ(dp->dnatype, "double")) {
prop->rawtype = PROP_RAW_DOUBLE;
- prop->flag |= PROP_RAW_ACCESS;
+ prop->flag_internal |= PROP_INTERN_RAW_ACCESS;
}
}
@@ -1536,7 +1536,11 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp)
const char *nextfunc = (const char *)cprop->next;
const char *item_type = (const char *)cprop->item_type;
- if (dp->dnatype && STREQ(dp->dnatype, "ListBase")) {
+ if (cprop->length) {
+ /* always generate if we have a manual implementation */
+ cprop->length = (void *)rna_def_property_length_func(f, srna, prop, dp, (const char *)cprop->length);
+ }
+ else if (dp->dnatype && STREQ(dp->dnatype, "ListBase")) {
/* pass */
}
else if (dp->dnalengthname || dp->dnalengthfixed) {
@@ -1549,7 +1553,7 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp)
if (STREQ((const char *)cprop->next, "rna_iterator_array_next") &&
STREQ((const char *)cprop->get, "rna_iterator_array_get"))
{
- prop->flag |= PROP_RAW_ARRAY;
+ prop->flag_internal |= PROP_INTERN_RAW_ARRAY;
}
cprop->get = (void *)rna_def_property_get_func(f, srna, prop, dp, (const char *)cprop->get);
@@ -1595,8 +1599,9 @@ static void rna_def_property_funcs_header(FILE *f, StructRNA *srna, PropertyDefR
prop = dp->prop;
- if (prop->flag & (PROP_IDPROPERTY | PROP_BUILTIN))
+ if (prop->flag & PROP_IDPROPERTY || prop->flag_internal & PROP_INTERN_BUILTIN) {
return;
+ }
func = rna_alloc_function_name(srna->identifier, rna_safe_id(prop->identifier), "");
@@ -1715,8 +1720,9 @@ static void rna_def_property_funcs_header_cpp(FILE *f, StructRNA *srna, Property
prop = dp->prop;
- if (prop->flag & (PROP_IDPROPERTY | PROP_BUILTIN))
+ if (prop->flag & PROP_IDPROPERTY || prop->flag_internal & PROP_INTERN_BUILTIN) {
return;
+ }
/* disabled for now to avoid msvc compiler error due to large file size */
#if 0
@@ -1818,8 +1824,9 @@ static void rna_def_property_funcs_header_cpp(FILE *f, StructRNA *srna, Property
CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)dp->prop;
const char *collection_funcs = "DefaultCollectionFunctions";
- if (!(dp->prop->flag & (PROP_IDPROPERTY | PROP_BUILTIN)) && cprop->property.srna)
+ if (!(dp->prop->flag & PROP_IDPROPERTY || dp->prop->flag_internal & PROP_INTERN_BUILTIN) && cprop->property.srna) {
collection_funcs = (char *)cprop->property.srna;
+ }
if (cprop->item_type)
fprintf(f, "\tCOLLECTION_PROPERTY(%s, %s, %s, %s, %s, %s, %s)", collection_funcs, (const char *)cprop->item_type, srna->identifier,
@@ -1875,7 +1882,7 @@ static void rna_def_struct_function_prototype_cpp(FILE *f, StructRNA *UNUSED(srn
WRITE_PARAM("Context C");
for (dp = dfunc->cont.properties.first; dp; dp = dp->next) {
- int type, flag, pout;
+ int type, flag, flag_parameter, pout;
const char *ptrstr;
if (dp->prop == func->c_ret)
@@ -1883,7 +1890,8 @@ static void rna_def_struct_function_prototype_cpp(FILE *f, StructRNA *UNUSED(srn
type = dp->prop->type;
flag = dp->prop->flag;
- pout = (flag & PROP_OUTPUT);
+ flag_parameter = dp->prop->flag_parameter;
+ pout = (flag_parameter & PARM_OUTPUT);
if (flag & PROP_DYNAMIC)
ptrstr = pout ? "**" : "*";
@@ -1899,7 +1907,7 @@ static void rna_def_struct_function_prototype_cpp(FILE *f, StructRNA *UNUSED(srn
WRITE_COMMA;
if (flag & PROP_DYNAMIC)
- fprintf(f, "int %s%s_len, ", (flag & PROP_OUTPUT) ? "*" : "", dp->prop->identifier);
+ fprintf(f, "int %s%s_len, ", (flag_parameter & PARM_OUTPUT) ? "*" : "", dp->prop->identifier);
if (!(flag & PROP_DYNAMIC) && dp->prop->arraydimension)
fprintf(f, "%s %s[%u]", rna_parameter_type_cpp_name(dp->prop),
@@ -1937,8 +1945,9 @@ static void rna_def_property_funcs_impl_cpp(FILE *f, StructRNA *srna, PropertyDe
prop = dp->prop;
- if (prop->flag & (PROP_IDPROPERTY | PROP_BUILTIN))
+ if (prop->flag & PROP_IDPROPERTY || prop->flag_internal & PROP_INTERN_BUILTIN) {
return;
+ }
switch (prop->type) {
case PROP_BOOLEAN:
@@ -2071,9 +2080,9 @@ static void rna_def_struct_function_call_impl_cpp(FILE *f, StructRNA *srna, Func
fprintf(f, "%s_len, ", dp->prop->identifier);
if (dp->prop->type == PROP_POINTER)
- if ((dp->prop->flag & PROP_RNAPTR) && !(dp->prop->flag & PROP_THICK_WRAP))
+ if ((dp->prop->flag_parameter & PARM_RNAPTR) && !(dp->prop->flag & PROP_THICK_WRAP))
fprintf(f, "(::%s *) &%s.ptr", rna_parameter_type_name(dp->prop), rna_safe_id(dp->prop->identifier));
- else if (dp->prop->flag & PROP_OUTPUT)
+ else if (dp->prop->flag_parameter & PARM_OUTPUT)
fprintf(f, "(::%s **) &%s->ptr.data", rna_parameter_type_name(dp->prop), rna_safe_id(dp->prop->identifier));
else
fprintf(f, "(::%s *) %s.ptr.data", rna_parameter_type_name(dp->prop), rna_safe_id(dp->prop->identifier));
@@ -2106,7 +2115,7 @@ static void rna_def_struct_function_impl_cpp(FILE *f, StructRNA *srna, FunctionD
fprintf(f, "\t\tPointerRNA result;\n");
- if ((dp->prop->flag & PROP_RNAPTR) == 0) {
+ if ((dp->prop->flag_parameter & PARM_RNAPTR) == 0) {
StructRNA *ret_srna = rna_find_struct((const char *) pprop->type);
fprintf(f, "\t\t::%s *retdata = ", rna_parameter_type_name(dp->prop));
rna_def_struct_function_call_impl_cpp(f, srna, dfunc);
@@ -2217,7 +2226,7 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
const char *funcname, *valstr;
const char *ptrstr;
const bool has_data = (dfunc->cont.properties.first != NULL);
- int flag, pout, cptr, first;
+ int flag, flag_parameter, pout, cptr, first;
srna = dsrna->srna;
func = dfunc->func;
@@ -2250,8 +2259,9 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
for (; dparm; dparm = dparm->next) {
type = dparm->prop->type;
flag = dparm->prop->flag;
- pout = (flag & PROP_OUTPUT);
- cptr = ((type == PROP_POINTER) && !(flag & PROP_RNAPTR));
+ flag_parameter = dparm->prop->flag_parameter;
+ pout = (flag_parameter & PARM_OUTPUT);
+ cptr = ((type == PROP_POINTER) && !(flag_parameter & PARM_RNAPTR));
if (dparm->prop == func->c_ret)
ptrstr = cptr || dparm->prop->arraydimension ? "*" : "";
@@ -2261,7 +2271,7 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
/* fixed size arrays and RNA pointers are pre-allocated on the ParameterList stack, pass a pointer to it */
else if (type == PROP_POINTER || dparm->prop->arraydimension)
ptrstr = "*";
- else if ((type == PROP_POINTER) && (flag & PROP_RNAPTR) && !(flag & PROP_THICK_WRAP))
+ else if ((type == PROP_POINTER) && (flag_parameter & PARM_RNAPTR) && !(flag & PROP_THICK_WRAP))
ptrstr = "*";
/* PROP_THICK_WRAP strings are pre-allocated on the ParameterList stack,
* but type name for string props is already (char *), so leave empty */
@@ -2307,8 +2317,9 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
for (; dparm; dparm = dparm->next) {
type = dparm->prop->type;
flag = dparm->prop->flag;
- pout = (flag & PROP_OUTPUT);
- cptr = ((type == PROP_POINTER) && !(flag & PROP_RNAPTR));
+ flag_parameter = dparm->prop->flag_parameter;
+ pout = (flag_parameter & PARM_OUTPUT);
+ cptr = ((type == PROP_POINTER) && !(flag_parameter & PARM_RNAPTR));
if (dparm->prop == func->c_ret)
fprintf(f, "\t_retdata = _data;\n");
@@ -2418,7 +2429,7 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
if (func->c_ret) {
dparm = rna_find_parameter_def(func->c_ret);
- ptrstr = (((dparm->prop->type == PROP_POINTER) && !(dparm->prop->flag & PROP_RNAPTR)) ||
+ ptrstr = (((dparm->prop->type == PROP_POINTER) && !(dparm->prop->flag_parameter & PARM_RNAPTR)) ||
(dparm->prop->arraydimension)) ? "*" : "";
fprintf(f, "\t*((%s%s %s*)_retdata) = %s;\n", rna_type_struct(dparm->prop),
rna_parameter_type_name(dparm->prop), ptrstr, func->c_ret->identifier);
@@ -2653,7 +2664,7 @@ static void rna_generate_static_parameter_prototypes(FILE *f, StructRNA *srna, F
PropertyDefRNA *dparm;
StructDefRNA *dsrna;
PropertyType type;
- int flag, pout, cptr, first;
+ int flag, flag_parameter, pout, cptr, first;
const char *ptrstr;
dsrna = rna_find_struct_def(srna);
@@ -2664,7 +2675,7 @@ static void rna_generate_static_parameter_prototypes(FILE *f, StructRNA *srna, F
if (dparm->prop == func->c_ret) {
if (dparm->prop->arraydimension)
fprintf(f, "XXX no array return types yet"); /* XXX not supported */
- else if (dparm->prop->type == PROP_POINTER && !(dparm->prop->flag & PROP_RNAPTR))
+ else if (dparm->prop->type == PROP_POINTER && !(dparm->prop->flag_parameter & PARM_RNAPTR))
fprintf(f, "%s%s *", rna_type_struct(dparm->prop), rna_parameter_type_name(dparm->prop));
else
fprintf(f, "%s%s ", rna_type_struct(dparm->prop), rna_parameter_type_name(dparm->prop));
@@ -2726,8 +2737,9 @@ static void rna_generate_static_parameter_prototypes(FILE *f, StructRNA *srna, F
for (dparm = dfunc->cont.properties.first; dparm; dparm = dparm->next) {
type = dparm->prop->type;
flag = dparm->prop->flag;
- pout = (flag & PROP_OUTPUT);
- cptr = ((type == PROP_POINTER) && !(flag & PROP_RNAPTR));
+ flag_parameter = dparm->prop->flag_parameter;
+ pout = (flag_parameter & PARM_OUTPUT);
+ cptr = ((type == PROP_POINTER) && !(flag_parameter & PARM_RNAPTR));
if (dparm->prop == func->c_ret)
continue;
@@ -2982,7 +2994,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, ", prop->flag);
+ fprintf(f, ", %d, %d, %d, ", prop->flag, prop->flag_parameter, prop->flag_internal);
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);
@@ -3004,7 +3016,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
rna_function_string(prop->editable),
rna_function_string(prop->itemeditable));
- if (prop->flag & PROP_RAW_ACCESS) rna_set_raw_offset(f, srna, prop);
+ if (prop->flag_internal & PROP_INTERN_RAW_ACCESS) rna_set_raw_offset(f, srna, prop);
else fprintf(f, "\t0, -1");
/* our own type - collections/arrays only */
@@ -3309,7 +3321,6 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"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},
@@ -3330,10 +3341,12 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"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_lightprobe.c", NULL, RNA_def_lightprobe},
{"rna_property.c", NULL, RNA_def_gameproperty},
{"rna_render.c", NULL, RNA_def_render},
{"rna_rigidbody.c", NULL, RNA_def_rigidbody},
@@ -3353,6 +3366,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_manipulator.c", "rna_wm_manipulator_api.c", RNA_def_wm_manipulator},
+ {"rna_workspace.c", NULL, RNA_def_workspace},
{"rna_world.c", NULL, RNA_def_world},
{"rna_movieclip.c", NULL, RNA_def_movieclip},
{"rna_tracking.c", NULL, RNA_def_tracking},
@@ -3735,7 +3750,7 @@ static const char *cpp_classes = ""
"template<typename T, TBeginFunc Tbegin, TNextFunc Tnext, TEndFunc Tend>\n"
"class CollectionIterator {\n"
"public:\n"
-" CollectionIterator() : t(iter.ptr), init(false) { iter.valid = false; }\n"
+" CollectionIterator() : iter(), t(iter.ptr), init(false) { iter.valid = false; }\n"
" ~CollectionIterator(void) { if (init) Tend(&iter); };\n"
"\n"
" operator bool(void)\n"
@@ -3754,7 +3769,7 @@ static const char *cpp_classes = ""
"\n"
"private:\n"
" const CollectionIterator<T, Tbegin, Tnext, Tend>& operator = "
-"(const CollectionIterator<T, Tbegin, Tnext, Tend>& copy) {}\n"
+"(const CollectionIterator<T, Tbegin, Tnext, Tend>& /*copy*/) {}\n"
""
" CollectionPropertyIterator iter;\n"
" T t;\n"
@@ -3793,9 +3808,11 @@ static const char *cpp_classes = ""
static int rna_is_collection_prop(PropertyRNA *prop)
{
- if (!(prop->flag & (PROP_IDPROPERTY | PROP_BUILTIN)))
- if (prop->type == PROP_COLLECTION)
+ if (!(prop->flag & PROP_IDPROPERTY || prop->flag_internal & PROP_INTERN_BUILTIN)) {
+ if (prop->type == PROP_COLLECTION) {
return 1;
+ }
+ }
return 0;
}
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index fdb93ac1a18..3d162137bd1 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -35,6 +35,7 @@
#include "BLI_utildefines.h"
#include "BKE_icons.h"
+#include "BKE_object.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -73,6 +74,7 @@ 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_LT, "LIGHT_PROBE", ICON_RADIO, "Light Probe", ""},
{ID_SCE, "SCENE", ICON_SCENE_DATA, "Scene", ""},
{ID_SCR, "SCREEN", ICON_SPLITSCREEN, "Screen", ""},
{ID_SO, "SOUND", ICON_PLAY_AUDIO, "Sound", ""},
@@ -81,6 +83,7 @@ EnumPropertyItem rna_enum_id_type_items[] = {
{ID_TE, "TEXTURE", ICON_TEXTURE_DATA, "Texture", ""},
{ID_WM, "WINDOWMANAGER", ICON_FULLSCREEN, "Window Manager", ""},
{ID_WO, "WORLD", ICON_WORLD_DATA, "World", ""},
+ {ID_WS, "WORKSPACE", ICON_NONE, "Workspace", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -97,9 +100,11 @@ EnumPropertyItem rna_enum_id_type_items[] = {
#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 "WM_api.h"
/* name functions that ignore the first two ID characters */
@@ -122,7 +127,7 @@ void rna_ID_name_set(PointerRNA *ptr, const char *value)
BLI_libblock_ensure_unique_name(G.main, id->name);
}
-static int rna_ID_name_editable(PointerRNA *ptr)
+static int rna_ID_name_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
ID *id = (ID *)ptr->data;
@@ -135,48 +140,56 @@ static int rna_ID_name_editable(PointerRNA *ptr)
return PROP_EDITABLE;
}
-short RNA_type_to_ID_code(StructRNA *type)
+short RNA_type_to_ID_code(const StructRNA *type)
{
- if (RNA_struct_is_a(type, &RNA_Action)) return ID_AC;
- if (RNA_struct_is_a(type, &RNA_Armature)) return ID_AR;
- if (RNA_struct_is_a(type, &RNA_Brush)) return ID_BR;
- if (RNA_struct_is_a(type, &RNA_CacheFile)) return ID_CF;
- if (RNA_struct_is_a(type, &RNA_Camera)) return ID_CA;
- if (RNA_struct_is_a(type, &RNA_Curve)) return ID_CU;
- if (RNA_struct_is_a(type, &RNA_GreasePencil)) return ID_GD;
- if (RNA_struct_is_a(type, &RNA_Group)) return ID_GR;
- if (RNA_struct_is_a(type, &RNA_Image)) return ID_IM;
- if (RNA_struct_is_a(type, &RNA_Key)) return ID_KE;
- if (RNA_struct_is_a(type, &RNA_Lamp)) return ID_LA;
- if (RNA_struct_is_a(type, &RNA_Library)) return ID_LI;
- if (RNA_struct_is_a(type, &RNA_FreestyleLineStyle)) return ID_LS;
- if (RNA_struct_is_a(type, &RNA_Lattice)) return ID_LT;
- if (RNA_struct_is_a(type, &RNA_Material)) return ID_MA;
- if (RNA_struct_is_a(type, &RNA_MetaBall)) return ID_MB;
- if (RNA_struct_is_a(type, &RNA_MovieClip)) return ID_MC;
- if (RNA_struct_is_a(type, &RNA_Mesh)) return ID_ME;
- if (RNA_struct_is_a(type, &RNA_Mask)) return ID_MSK;
- if (RNA_struct_is_a(type, &RNA_NodeTree)) return ID_NT;
- if (RNA_struct_is_a(type, &RNA_Object)) return ID_OB;
- if (RNA_struct_is_a(type, &RNA_ParticleSettings)) return ID_PA;
- if (RNA_struct_is_a(type, &RNA_Palette)) return ID_PAL;
- if (RNA_struct_is_a(type, &RNA_PaintCurve)) return ID_PC;
- if (RNA_struct_is_a(type, &RNA_Scene)) return ID_SCE;
- if (RNA_struct_is_a(type, &RNA_Screen)) return ID_SCR;
- if (RNA_struct_is_a(type, &RNA_Sound)) return ID_SO;
- if (RNA_struct_is_a(type, &RNA_Speaker)) return ID_SPK;
- if (RNA_struct_is_a(type, &RNA_Texture)) return ID_TE;
- if (RNA_struct_is_a(type, &RNA_Text)) return ID_TXT;
- if (RNA_struct_is_a(type, &RNA_VectorFont)) return ID_VF;
- if (RNA_struct_is_a(type, &RNA_World)) return ID_WO;
- if (RNA_struct_is_a(type, &RNA_WindowManager)) return ID_WM;
+ const StructRNA *base_type = RNA_struct_base_child_of(type, &RNA_ID);
+ if (UNLIKELY(base_type == NULL)) {
+ return 0;
+ }
+ if (base_type == &RNA_Action) return ID_AC;
+ if (base_type == &RNA_Armature) return ID_AR;
+ if (base_type == &RNA_Brush) return ID_BR;
+ if (base_type == &RNA_CacheFile) return ID_CF;
+ 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_Image) return ID_IM;
+ if (base_type == &RNA_Key) return ID_KE;
+ if (base_type == &RNA_Lamp) 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;
+ if (base_type == &RNA_Material) return ID_MA;
+ if (base_type == &RNA_MetaBall) return ID_MB;
+ if (base_type == &RNA_MovieClip) return ID_MC;
+ if (base_type == &RNA_Mesh) return ID_ME;
+ if (base_type == &RNA_Mask) return ID_MSK;
+ if (base_type == &RNA_NodeTree) return ID_NT;
+ if (base_type == &RNA_Object) return ID_OB;
+ 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;
+ if (base_type == &RNA_Speaker) return ID_SPK;
+ 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;
return 0;
}
StructRNA *ID_code_to_RNA_type(short idcode)
{
- switch (idcode) {
+ /* Note, this switch doesn't use a 'default',
+ * so adding new ID's causes a warning. */
+ switch ((ID_Type)idcode) {
case ID_AC: return &RNA_Action;
case ID_AR: return &RNA_Armature;
case ID_BR: return &RNA_Brush;
@@ -201,6 +214,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;
@@ -210,9 +224,13 @@ 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;
- default: return &RNA_ID;
+ /* deprecated */
+ case ID_IP: break;
}
+
+ return &RNA_ID;
}
StructRNA *rna_ID_refine(PointerRNA *ptr)
@@ -330,7 +348,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)
@@ -341,23 +359,39 @@ static void rna_ID_user_clear(ID *id)
static void rna_ID_user_remap(ID *id, Main *bmain, ID *new_id)
{
- if (GS(id->name) == GS(new_id->name)) {
+ if ((GS(id->name) == GS(new_id->name)) && (id != new_id)) {
/* For now, do not allow remapping data in linked data from here... */
BKE_libblock_remap(bmain, id, new_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
}
}
+static struct ID *rna_ID_make_local(struct ID *self, Main *bmain, int clear_proxy)
+{
+ /* Special case, as we can't rely on id_make_local(); it clears proxies. */
+ if (!clear_proxy && GS(self->name) == ID_OB) {
+ BKE_object_make_local_ex(bmain, (Object *)self, false, clear_proxy);
+ }
+ else {
+ id_make_local(bmain, self, false, false);
+ }
+
+ ID *ret_id = self->newid ? self->newid : self;
+ BKE_id_clear_newpoin(self);
+ return ret_id;
+}
+
+
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);
}
static void rna_IDPArray_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
@@ -386,15 +420,15 @@ int rna_IDMaterials_assign_int(PointerRNA *ptr, int key, const PointerRNA *assig
}
}
-static void rna_IDMaterials_append_id(ID *id, Material *ma)
+static void rna_IDMaterials_append_id(ID *id, Main *bmain, Material *ma)
{
- BKE_material_append_id(id, ma);
+ BKE_material_append_id(bmain, id, ma);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, id);
WM_main_add_notifier(NC_OBJECT | ND_OB_SHADING, id);
}
-static Material *rna_IDMaterials_pop_id(ID *id, ReportList *reports, int index_i, int remove_material_slot)
+static Material *rna_IDMaterials_pop_id(ID *id, Main *bmain, ReportList *reports, int index_i, int remove_material_slot)
{
Material *ma;
short *totcol = give_totcolp_id(id);
@@ -408,14 +442,14 @@ static Material *rna_IDMaterials_pop_id(ID *id, ReportList *reports, int index_i
return NULL;
}
- ma = BKE_material_pop_id(id, index_i, remove_material_slot);
+ ma = BKE_material_pop_id(bmain, id, index_i, remove_material_slot);
if (*totcol == totcol_orig) {
BKE_report(reports, RPT_ERROR, "No material to removed");
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);
@@ -424,9 +458,9 @@ static Material *rna_IDMaterials_pop_id(ID *id, ReportList *reports, int index_i
static void rna_IDMaterials_clear_id(ID *id, int remove_material_slot)
{
- BKE_material_clear_id(id, remove_material_slot);
+ BKE_material_clear_id(G.main, 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);
}
@@ -785,7 +819,11 @@ static void rna_def_ID_properties(BlenderRNA *brna)
RNA_def_struct_name_property(srna, prop);
#endif
- /* IDP_ID -- not implemented yet in id properties */
+ /* 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_struct_type(prop, "ID");
+
/* ID property groups > level 0, since level 0 group is merged
* with native RNA properties. the builtin_properties will take
@@ -820,20 +858,21 @@ static void rna_def_ID_materials(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "ID Materials", "Collection of materials");
func = RNA_def_function(srna, "append", "rna_IDMaterials_append_id");
- RNA_def_function_ui_description(func, "Add a new material to the data block");
+ RNA_def_function_flag(func, FUNC_USE_MAIN);
+ RNA_def_function_ui_description(func, "Add a new material to the data-block");
parm = RNA_def_pointer(func, "material", "Material", "", "Material to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "pop", "rna_IDMaterials_pop_id");
- RNA_def_function_flag(func, FUNC_USE_REPORTS);
- RNA_def_function_ui_description(func, "Remove a material from the data block");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_MAIN);
+ RNA_def_function_ui_description(func, "Remove a material from the data-block");
parm = RNA_def_int(func, "index", -1, -MAXMAT, MAXMAT, "", "Index of material to remove", 0, MAXMAT);
RNA_def_boolean(func, "update_data", 0, "", "Update data by re-adjusting the material slots assigned");
parm = RNA_def_pointer(func, "material", "Material", "", "Material to remove");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "clear", "rna_IDMaterials_clear_id");
- RNA_def_function_ui_description(func, "Remove all materials from the data block");
+ RNA_def_function_ui_description(func, "Remove all materials from the data-block");
RNA_def_boolean(func, "update_data", 0, "", "Update data by re-adjusting the material slots assigned");
}
@@ -959,12 +998,12 @@ static void rna_def_ID(BlenderRNA *brna)
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "tag", LIB_TAG_ID_RECALC);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Is Updated", "Datablock is tagged for recalculation");
+ 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, "tag", LIB_TAG_ID_RECALC_DATA);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Is Updated Data", "Datablock data is tagged for recalculation");
+ 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);
@@ -996,14 +1035,24 @@ static void rna_def_ID(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Replace all usage in the .blend file of this ID by new given one");
RNA_def_function_flag(func, FUNC_USE_MAIN);
parm = RNA_def_pointer(func, "new_id", "ID", "", "New ID to use");
- RNA_def_property_flag(parm, PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
+ func = RNA_def_function(srna, "make_local", "rna_ID_make_local");
+ RNA_def_function_ui_description(func, "Make this datablock local, return local one "
+ "(may be a copy of the original, in case it is also indirectly used)");
+ RNA_def_function_flag(func, FUNC_USE_MAIN);
+ parm = RNA_def_boolean(func, "clear_proxy", true, "",
+ "Whether to clear proxies (the default behavior, "
+ "note that if object has to be duplicated to be made local, proxies are always cleared)");
+ parm = RNA_def_pointer(func, "id", "ID", "", "This ID, or the new ID if it was copied");
+ RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "user_of_id", "BKE_library_ID_use_ID");
RNA_def_function_ui_description(func, "Count the number of times that ID uses/references given one");
parm = RNA_def_pointer(func, "id", "ID", "", "ID to count usages");
- RNA_def_property_flag(parm, PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_int(func, "count", 0, 0, INT_MAX,
- "", "Number of usages/references of given id by current datablock", 0, INT_MAX);
+ "", "Number of usages/references of given id by current data-block", 0, INT_MAX);
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "animation_data_create", "rna_ID_animation_data_create");
@@ -1049,7 +1098,7 @@ static void rna_def_library(BlenderRNA *brna)
func = RNA_def_function(srna, "reload", "WM_lib_reload");
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_CONTEXT);
- RNA_def_function_ui_description(func, "Reload this library and all its linked datablocks");
+ RNA_def_function_ui_description(func, "Reload this library and all its linked data-blocks");
}
void RNA_def_ID(BlenderRNA *brna)
{
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 047e5ea17ab..f349d4a44dc 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -50,9 +50,12 @@
#include "BKE_idcode.h"
#include "BKE_idprop.h"
#include "BKE_fcurve.h"
+#include "BKE_library.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"
@@ -61,7 +64,6 @@
/* flush updates */
#include "DNA_object_types.h"
-#include "BKE_depsgraph.h"
#include "WM_types.h"
#include "rna_internal.h"
@@ -79,9 +81,11 @@ void RNA_init(void)
if (!srna->cont.prophash) {
srna->cont.prophash = BLI_ghash_str_new("RNA_init gh");
- for (prop = srna->cont.properties.first; prop; prop = prop->next)
- if (!(prop->flag & PROP_BUILTIN))
+ for (prop = srna->cont.properties.first; prop; prop = prop->next) {
+ if (!(prop->flag_internal & PROP_INTERN_BUILTIN)) {
BLI_ghash_insert(srna->cont.prophash, (void *)prop->identifier, prop);
+ }
+ }
}
}
}
@@ -378,6 +382,7 @@ static bool rna_idproperty_verify_valid(PointerRNA *ptr, PropertyRNA *prop, IDPr
return false;
break;
case IDP_GROUP:
+ case IDP_ID:
if (prop->type != PROP_POINTER)
return false;
break;
@@ -393,7 +398,8 @@ static PropertyRNA *typemap[IDP_NUMTYPES] = {
(PropertyRNA *)&rna_PropertyGroupItem_int,
(PropertyRNA *)&rna_PropertyGroupItem_float,
NULL, NULL, NULL,
- (PropertyRNA *)&rna_PropertyGroupItem_group, NULL,
+ (PropertyRNA *)&rna_PropertyGroupItem_group,
+ (PropertyRNA *)&rna_PropertyGroupItem_id,
(PropertyRNA *)&rna_PropertyGroupItem_double,
(PropertyRNA *)&rna_PropertyGroupItem_idp_array
};
@@ -555,7 +561,7 @@ const char *RNA_struct_translation_context(const StructRNA *type)
return type->translation_context;
}
-PropertyRNA *RNA_struct_name_property(StructRNA *type)
+PropertyRNA *RNA_struct_name_property(const StructRNA *type)
{
return type->nameproperty;
}
@@ -570,6 +576,22 @@ StructRNA *RNA_struct_base(StructRNA *type)
return type->base;
}
+/**
+ * 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`.
+ */
+const StructRNA *RNA_struct_base_child_of(const StructRNA *type, const StructRNA *parent_type)
+{
+ while (type) {
+ if (type->base == parent_type) {
+ return type;
+ }
+ type = type->base;
+ }
+ return NULL;
+}
+
bool RNA_struct_is_ID(const StructRNA *type)
{
return (type->flag & STRUCT_ID) != 0;
@@ -585,6 +607,21 @@ bool RNA_struct_idprops_register_check(const StructRNA *type)
return (type->flag & STRUCT_NO_IDPROPERTIES) == 0;
}
+bool RNA_struct_idprops_datablock_allowed(const StructRNA *type)
+{
+ return (type->flag & (STRUCT_NO_DATABLOCK_IDPROPERTIES | STRUCT_NO_IDPROPERTIES)) == 0;
+}
+
+/**
+ * Whether given type implies datablock usage by IDProperties.
+ * This is used to prevent classes allowed to have IDProperties, but not datablock ones, to indirectly use some
+ * (e.g. by assigning an IDP_GROUP containing some IDP_ID pointers...).
+ */
+bool RNA_struct_idprops_contains_datablock(const StructRNA *type)
+{
+ return (type->flag & (STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES | STRUCT_ID)) != 0;
+}
+
/* remove an id-property */
bool RNA_struct_idprops_unset(PointerRNA *ptr, const char *identifier)
{
@@ -626,8 +663,11 @@ PropertyRNA *RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
/* id prop lookup, not so common */
PropertyRNA *r_prop = NULL;
PointerRNA r_ptr; /* only support single level props */
- if (RNA_path_resolve(ptr, identifier, &r_ptr, &r_prop) && (r_ptr.type == ptr->type) && (r_ptr.data == ptr->data))
+ if (RNA_path_resolve_property(ptr, identifier, &r_ptr, &r_prop) &&
+ (r_ptr.type == ptr->type) && (r_ptr.data == ptr->data))
+ {
return r_prop;
+ }
}
else {
/* most common case */
@@ -824,6 +864,11 @@ int RNA_property_flag(PropertyRNA *prop)
return rna_ensure_property(prop)->flag;
}
+bool RNA_property_builtin(PropertyRNA *prop)
+{
+ return (rna_ensure_property(prop)->flag_internal & PROP_INTERN_BUILTIN) != 0;
+}
+
void *RNA_property_py_data_get(PropertyRNA *prop)
{
return prop->py_data;
@@ -1194,13 +1239,20 @@ int RNA_property_pointer_poll(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *va
if (prop->type == PROP_POINTER) {
PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
- if (pprop->poll)
- return pprop->poll(ptr, *value);
+
+ if (pprop->poll) {
+ if (rna_idproperty_check(&prop, ptr)) {
+ return ((PropPointerPollFuncPy) pprop->poll)(ptr, *value, prop);
+ }
+ else {
+ return pprop->poll(ptr, *value);
+ }
+ }
return 1;
}
- printf("%s %s: is not a pointer property.\n", __func__, prop->identifier);
+ printf("%s: %s is not a pointer property.\n", __func__, prop->identifier);
return 0;
}
@@ -1619,20 +1671,56 @@ bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop)
{
ID *id = ptr->id.data;
int flag;
+ const char *dummy_info;
prop = rna_ensure_property(prop);
- flag = prop->editable ? prop->editable(ptr) : prop->flag;
+ flag = prop->editable ? prop->editable(ptr, &dummy_info) : prop->flag;
+
return ((flag & PROP_EDITABLE) &&
(flag & PROP_REGISTER) == 0 &&
(!id || !ID_IS_LINKED_DATABLOCK(id) || (prop->flag & PROP_LIB_EXCEPTION)));
}
+/**
+ * Version of #RNA_property_editable that tries to return additional info in \a r_info that can be exposed in UI.
+ */
+bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char **r_info)
+{
+ ID *id = ptr->id.data;
+ int flag;
+
+ prop = rna_ensure_property(prop);
+ *r_info = "";
+
+ /* get flag */
+ if (prop->editable) {
+ flag = prop->editable(ptr, r_info);
+ }
+ else {
+ flag = prop->flag;
+ if ((flag & PROP_EDITABLE) == 0 || (flag & PROP_REGISTER)) {
+ *r_info = "This property is for internal use only and can't be edited.";
+ }
+ }
+
+ /* property from linked data-block */
+ if (id && ID_IS_LINKED_DATABLOCK(id) && (prop->flag & PROP_LIB_EXCEPTION) == 0) {
+ if (!(*r_info)[0]) {
+ *r_info = "Can't edit this property from a linked data-block.";
+ }
+ return false;
+ }
+
+ return ((flag & PROP_EDITABLE) && (flag & PROP_REGISTER) == 0);
+}
+
bool RNA_property_editable_flag(PointerRNA *ptr, PropertyRNA *prop)
{
int flag;
+ const char *dummy_info;
prop = rna_ensure_property(prop);
- flag = prop->editable ? prop->editable(ptr) : prop->flag;
+ flag = prop->editable ? prop->editable(ptr, &dummy_info) : prop->flag;
return (flag & PROP_EDITABLE) != 0;
}
@@ -1647,9 +1735,11 @@ bool RNA_property_editable_index(PointerRNA *ptr, PropertyRNA *prop, int index)
prop = rna_ensure_property(prop);
flag = prop->flag;
-
- if (prop->editable)
- flag &= prop->editable(ptr);
+
+ if (prop->editable) {
+ const char *dummy_info;
+ flag &= prop->editable(ptr, &dummy_info);
+ }
if (prop->itemeditable)
flag &= prop->itemeditable(ptr, index);
@@ -1726,7 +1816,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 {
@@ -1744,7 +1834,7 @@ static void rna_property_update(bContext *C, Main *bmain, Scene *scene, PointerR
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 | OB_RECALC_TIME);
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.
@@ -2692,6 +2782,9 @@ char *RNA_property_string_get_alloc(PointerRNA *ptr, PropertyRNA *prop,
int length;
BLI_assert(RNA_property_type(prop) == PROP_STRING);
+ if (!ptr->data) {
+ return NULL;
+ }
length = RNA_property_string_length(ptr, prop);
@@ -2873,6 +2966,45 @@ void *RNA_property_enum_py_data_get(PropertyRNA *prop)
return eprop->py_data;
}
+/**
+ * Get the value of the item that is \a step items away from \a from_value.
+ *
+ * \param from_value: Item value to start stepping from.
+ * \param step: Absolute value defines step size, sign defines direction.
+ * E.g to get the next item, pass 1, for the previous -1.
+ */
+int RNA_property_enum_step(const bContext *C, PointerRNA *ptr, PropertyRNA *prop, int from_value, int step)
+{
+ EnumPropertyItem *item_array;
+ int totitem;
+ bool free;
+ int result_value = from_value;
+ int i, i_init;
+ int single_step = (step < 0) ? -1 : 1;
+ int step_tot = 0;
+
+ RNA_property_enum_items((bContext *)C, ptr, prop, &item_array, &totitem, &free);
+ i = RNA_enum_from_value(item_array, from_value);
+ i_init = i;
+
+ do {
+ i = mod_i(i + single_step, totitem);
+ if (item_array[i].identifier[0]) {
+ step_tot += single_step;
+ }
+ } while ((i != i_init) && (step_tot != step));
+
+ if (i != i_init) {
+ result_value = item_array[i].value;
+ }
+
+ if (free) {
+ MEM_freeN(item_array);
+ }
+
+ return result_value;
+}
+
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
{
PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
@@ -2883,6 +3015,10 @@ PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
if ((idprop = rna_idproperty_check(&prop, ptr))) {
pprop = (PointerPropertyRNA *)prop;
+ if (RNA_struct_is_ID(pprop->type)) {
+ return rna_pointer_inherit_refine(ptr, pprop->type, IDP_Id(idprop));
+ }
+
/* for groups, data is idprop itself */
if (pprop->typef)
return rna_pointer_inherit_refine(ptr, pprop->typef(ptr), idprop);
@@ -2905,22 +3041,32 @@ PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value)
{
- /*IDProperty *idprop;*/
-
+ PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
BLI_assert(RNA_property_type(prop) == PROP_POINTER);
- if ((/*idprop = */ rna_idproperty_check(&prop, ptr))) {
- /* not supported */
- /* rna_idproperty_touch(idprop); */
+ /* Check types */
+ if (ptr_value.type != NULL && !RNA_struct_is_a(ptr_value.type, pprop->type)) {
+ printf("%s: expected %s type, not %s.\n", __func__, pprop->type->identifier, ptr_value.type->identifier);
+ return;
}
- else {
- PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
- if (pprop->set &&
- !((prop->flag & PROP_NEVER_NULL) && ptr_value.data == NULL) &&
- !((prop->flag & PROP_ID_SELF_CHECK) && ptr->id.data == ptr_value.id.data))
- {
- pprop->set(ptr, ptr_value);
+ /* RNA */
+ if (pprop->set &&
+ !((prop->flag & PROP_NEVER_NULL) && ptr_value.data == NULL) &&
+ !((prop->flag & PROP_ID_SELF_CHECK) && ptr->id.data == ptr_value.id.data))
+ {
+ pprop->set(ptr, ptr_value);
+ }
+ /* IDProperty */
+ else if (prop->flag & PROP_EDITABLE) {
+ IDPropertyTemplate val = {0};
+ IDProperty *group;
+
+ val.id = ptr_value.data;
+
+ group = RNA_struct_idprops(ptr, true);
+ if (group) {
+ IDP_ReplaceInGroup(group, IDP_New(IDP_ID, &val, prop->identifier));
}
}
}
@@ -3030,7 +3176,7 @@ void RNA_property_collection_skip(CollectionPropertyIterator *iter, int num)
CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)rna_ensure_property(iter->prop);
int i;
- if (num > 1 && (iter->idprop || (cprop->property.flag & PROP_RAW_ARRAY))) {
+ if (num > 1 && (iter->idprop || (cprop->property.flag_internal & PROP_INTERN_RAW_ARRAY))) {
/* fast skip for array */
ArrayIterator *internal = &iter->internal.array;
@@ -3372,7 +3518,7 @@ int RNA_property_collection_raw_array(PointerRNA *ptr, PropertyRNA *prop, Proper
BLI_assert(RNA_property_type(prop) == PROP_COLLECTION);
- if (!(prop->flag & PROP_RAW_ARRAY) || !(itemprop->flag & PROP_RAW_ACCESS))
+ if (!(prop->flag_internal & PROP_INTERN_RAW_ARRAY) || !(itemprop->flag_internal & PROP_INTERN_RAW_ACCESS))
return 0;
RNA_property_collection_begin(ptr, prop, &iter);
@@ -5463,6 +5609,9 @@ static char *rna_pointer_as_string__bldata(PointerRNA *ptr)
return BLI_strdup("None");
}
else if (RNA_struct_is_ID(ptr->type)) {
+ if (ptr->id.data == NULL) {
+ return BLI_strdup("None");
+ }
return RNA_path_full_ID_py(ptr->id.data);
}
else {
@@ -5470,9 +5619,13 @@ static char *rna_pointer_as_string__bldata(PointerRNA *ptr)
}
}
-char *RNA_pointer_as_string(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *prop_ptr, PointerRNA *ptr_prop)
+char *RNA_pointer_as_string(bContext *C, PointerRNA *ptr, PropertyRNA *prop_ptr, PointerRNA *ptr_prop)
{
- if (RNA_property_flag(prop_ptr) & PROP_IDPROPERTY) {
+ IDProperty *prop;
+ if (ptr_prop->data == NULL) {
+ return BLI_strdup("None");
+ }
+ else if ((prop = rna_idproperty_check(&prop_ptr, ptr)) && prop->type != IDP_ID) {
return RNA_pointer_as_string_id(C, ptr_prop);
}
else {
@@ -5493,15 +5646,16 @@ char *RNA_pointer_as_string_keywords_ex(bContext *C, PointerRNA *ptr,
DynStr *dynstr = BLI_dynstr_new();
char *cstring, *buf;
bool first_iter = true;
- int flag;
+ int flag, flag_parameter;
RNA_PROP_BEGIN (ptr, propptr, iterprop)
{
prop = propptr.data;
flag = RNA_property_flag(prop);
+ flag_parameter = RNA_parameter_flag(prop);
- if (as_function && (flag & PROP_OUTPUT)) {
+ if (as_function && (flag_parameter & PARM_OUTPUT)) {
continue;
}
@@ -5515,7 +5669,7 @@ char *RNA_pointer_as_string_keywords_ex(bContext *C, PointerRNA *ptr,
continue;
}
- if (as_function && (flag & PROP_REQUIRED)) {
+ if (as_function && (prop->flag_parameter & PARM_REQUIRED)) {
/* required args don't have useful defaults */
BLI_dynstr_appendf(dynstr, first_iter ? "%s" : ", %s", arg_name);
first_iter = false;
@@ -5836,6 +5990,11 @@ const ListBase *RNA_function_defined_parameters(FunctionRNA *func)
/* Utility */
+int RNA_parameter_flag(PropertyRNA *prop)
+{
+ return (int)rna_ensure_property(prop)->flag_parameter;
+}
+
ParameterList *RNA_parameter_list_create(ParameterList *parms, PointerRNA *UNUSED(ptr), FunctionRNA *func)
{
PropertyRNA *parm;
@@ -5849,7 +6008,7 @@ ParameterList *RNA_parameter_list_create(ParameterList *parms, PointerRNA *UNUSE
for (parm = func->cont.properties.first; parm; parm = parm->next) {
alloc_size += rna_parameter_size(parm);
- if (parm->flag & PROP_OUTPUT)
+ if (parm->flag_parameter & PARM_OUTPUT)
parms->ret_count++;
else
parms->arg_count++;
@@ -5872,7 +6031,7 @@ ParameterList *RNA_parameter_list_create(ParameterList *parms, PointerRNA *UNUSE
data_alloc->array = NULL;
}
- if (!(parm->flag & PROP_REQUIRED) && !(parm->flag & PROP_DYNAMIC)) {
+ 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);
@@ -6296,7 +6455,7 @@ static int rna_function_parameter_parse(PointerRNA *ptr, PropertyRNA *prop, Prop
ptype = RNA_property_pointer_type(ptr, prop);
- if (prop->flag & PROP_RNAPTR) {
+ if (prop->flag_parameter & PARM_RNAPTR) {
*((PointerRNA *)dest) = *((PointerRNA *)src);
break;
}
@@ -6307,7 +6466,7 @@ static int rna_function_parameter_parse(PointerRNA *ptr, PropertyRNA *prop, Prop
tid, fid, pid, RNA_struct_identifier(ptype), RNA_struct_identifier(srna));
return -1;
}
-
+
*((void **)dest) = *((void **)src);
break;
@@ -6366,7 +6525,7 @@ int RNA_function_call_direct_va(bContext *C, ReportList *reports, PointerRNA *pt
ParameterIterator iter;
PropertyRNA *pret, *parm;
PropertyType type;
- int i, ofs, flen, flag, len, alen, err = 0;
+ int i, ofs, flen, flag_parameter, len, alen, err = 0;
const char *tid, *fid, *pid = NULL;
char ftype;
void **retdata = NULL;
@@ -6383,20 +6542,20 @@ int RNA_function_call_direct_va(bContext *C, ReportList *reports, PointerRNA *pt
for (i = 0, ofs = 0; iter.valid; RNA_parameter_list_next(&iter), i++) {
parm = iter.parm;
- flag = RNA_property_flag(parm);
+ flag_parameter = RNA_parameter_flag(parm);
if (parm == pret) {
retdata = iter.data;
continue;
}
- else if (flag & PROP_OUTPUT) {
+ else if (flag_parameter & PARM_OUTPUT) {
continue;
}
pid = RNA_property_identifier(parm);
if (ofs >= flen || format[ofs] == 'N') {
- if (flag & PROP_REQUIRED) {
+ if (parm->flag_parameter & PARM_REQUIRED) {
err = -1;
fprintf(stderr, "%s.%s: missing required parameter %s\n", tid, fid, pid);
break;
@@ -6561,6 +6720,13 @@ int RNA_function_call_direct_va_lookup(bContext *C, ReportList *reports, Pointer
return 0;
}
+const char *RNA_translate_ui_text(
+ const char *text, const char *text_ctxt, StructRNA *type, PropertyRNA *prop,
+ int translate)
+{
+ return rna_translate_ui_text(text, text_ctxt, type, prop, translate);
+}
+
bool RNA_property_reset(PointerRNA *ptr, PropertyRNA *prop, int index)
{
int len;
diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c
index 8d7e47e8402..d398ce95a52 100644
--- a/source/blender/makesrna/intern/rna_action.c
+++ b/source/blender/makesrna/intern/rna_action.c
@@ -34,6 +34,8 @@
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+
#include "BKE_action.h"
#include "RNA_access.h"
@@ -310,8 +312,8 @@ static void rna_def_dopesheet(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_datablock_sort", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", ADS_FLAG_NO_DB_SORT);
- RNA_def_property_ui_text(prop, "Sort Datablocks",
- "Alphabetically sorts datablocks - mainly objects in the scene "
+ RNA_def_property_ui_text(prop, "Sort Data-Blocks",
+ "Alphabetically sorts data-blocks - mainly objects in the scene "
"(disable to increase viewport speed)");
RNA_def_property_ui_icon(prop, ICON_SORTALPHA, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -377,7 +379,7 @@ static void rna_def_dopesheet(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_missing_nla", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "filterflag", ADS_FILTER_NLA_NOACT);
RNA_def_property_ui_text(prop, "Include Missing NLA",
- "Include animation data blocks with no NLA data (NLA editor only)");
+ "Include animation data-blocks with no NLA data (NLA editor only)");
RNA_def_property_ui_icon(prop, ICON_ACTION, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -516,7 +518,7 @@ static void rna_def_dopesheet(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_gpencil_3d_only", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "filterflag", ADS_FILTER_GP_3DONLY);
RNA_def_property_ui_text(prop, "Active Scene Only",
- "Only show Grease Pencil datablocks used as part of the active scene");
+ "Only show Grease Pencil data-blocks used as part of the active scene");
RNA_def_property_ui_icon(prop, ICON_SCENE_DATA, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
}
@@ -586,7 +588,7 @@ static void rna_def_action_groups(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Action_groups_new");
RNA_def_function_ui_description(func, "Create a new action group and add it to the action");
parm = RNA_def_string(func, "name", "Group", 0, "", "New name for the action group");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "action_group", "ActionGroup", "", "Newly created action group");
RNA_def_function_return(func, parm);
@@ -596,8 +598,8 @@ static void rna_def_action_groups(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove action group");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "action_group", "ActionGroup", "", "Action group to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_action_fcurves(BlenderRNA *brna, PropertyRNA *cprop)
@@ -617,7 +619,7 @@ static void rna_def_action_fcurves(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add an F-Curve to the action");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "data_path", NULL, 0, "Data Path", "F-Curve data path to use");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "Array index", 0, INT_MAX);
RNA_def_string(func, "action_group", NULL, 0, "Action Group", "Acton group to add this F-Curve into");
@@ -630,9 +632,8 @@ static void rna_def_action_fcurves(BlenderRNA *brna, PropertyRNA *cprop)
"of all F-Curves in the action.");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "data_path", NULL, 0, "Data Path", "F-Curve data path");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "Array index", 0, INT_MAX);
-
parm = RNA_def_pointer(func, "fcurve", "FCurve", "", "The found F-Curve, or None if it doesn't exist");
RNA_def_function_return(func, parm);
@@ -641,8 +642,8 @@ static void rna_def_action_fcurves(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove action group");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "fcurve", "FCurve", "", "F-Curve to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_action_pose_markers(BlenderRNA *brna, PropertyRNA *cprop)
@@ -661,8 +662,7 @@ static void rna_def_action_pose_markers(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Action_pose_markers_new");
RNA_def_function_ui_description(func, "Add a pose marker to the action");
parm = RNA_def_string(func, "name", "Marker", 0, NULL, "New name for the marker (not unique)");
- RNA_def_property_flag(parm, PROP_REQUIRED);
-
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "marker", "TimelineMarker", "", "Newly created marker");
RNA_def_function_return(func, parm);
@@ -670,8 +670,8 @@ static void rna_def_action_pose_markers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a timeline marker");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "marker", "TimelineMarker", "", "Timeline marker to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ 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, "TimelineMarker");
@@ -733,6 +733,7 @@ static void rna_def_action(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "ID Root Type",
"Type of ID block that action can be used on - "
"DO NOT CHANGE UNLESS YOU KNOW WHAT YOU ARE DOING");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
/* API calls */
RNA_api_action(srna);
diff --git a/source/blender/makesrna/intern/rna_actuator.c b/source/blender/makesrna/intern/rna_actuator.c
index a09853eaddc..004acbe4dbd 100644
--- a/source/blender/makesrna/intern/rna_actuator.c
+++ b/source/blender/makesrna/intern/rna_actuator.c
@@ -32,8 +32,9 @@
#include "DNA_actuator_types.h"
#include "DNA_scene_types.h" /* for MAXFRAME */
-#include "BLI_utildefines.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
+#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/makesrna/intern/rna_actuator_api.c b/source/blender/makesrna/intern/rna_actuator_api.c
index 4a34961964d..23fdd8a1d5b 100644
--- a/source/blender/makesrna/intern/rna_actuator_api.c
+++ b/source/blender/makesrna/intern/rna_actuator_api.c
@@ -63,13 +63,13 @@ void RNA_api_actuator(StructRNA *srna)
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_property_flag(parm, PROP_REQUIRED);
+ 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_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_property_update(parm, NC_LOGIC, NULL);
}
diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c
index 7a1954036e3..f49d4717ad6 100644
--- a/source/blender/makesrna/intern/rna_animation.c
+++ b/source/blender/makesrna/intern/rna_animation.c
@@ -32,6 +32,8 @@
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+
#include "MEM_guardedalloc.h"
#include "RNA_access.h"
@@ -71,10 +73,11 @@ 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 "DNA_object_types.h"
#include "WM_api.h"
@@ -86,10 +89,10 @@ static void rna_AnimData_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Point
/* 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);
+ DEG_id_tag_update(id, OB_RECALC_OB | OB_RECALC_DATA);
}
-static int rna_AnimData_action_editable(PointerRNA *ptr)
+static int rna_AnimData_action_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
AnimData *adt = (AnimData *)ptr->data;
@@ -112,7 +115,7 @@ static void rna_AnimData_action_set(PointerRNA *ptr, PointerRNA value)
adt = BKE_animdata_from_id(ownerId);
if (adt) {
adt->recalc |= ADT_RECALC_ANIM;
- DAG_id_tag_update(ownerId, OB_RECALC_TIME);
+ DEG_id_tag_update(ownerId, OB_RECALC_TIME);
}
}
@@ -305,7 +308,7 @@ static StructRNA *rna_ksPath_id_typef(PointerRNA *ptr)
return ID_code_to_RNA_type(ksp->idtype);
}
-static int rna_ksPath_id_editable(PointerRNA *ptr)
+static int rna_ksPath_id_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
KS_Path *ksp = (KS_Path *)ptr->data;
return (ksp->idtype) ? PROP_EDITABLE : 0;
@@ -393,7 +396,7 @@ static void rna_KeyingSet_name_set(PointerRNA *ptr, const char *value)
}
-static int rna_KeyingSet_active_ksPath_editable(PointerRNA *ptr)
+static int rna_KeyingSet_active_ksPath_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
KeyingSet *ks = (KeyingSet *)ptr->data;
@@ -693,27 +696,27 @@ static void rna_def_keyingset_info(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_REGISTER);
RNA_def_function_return(func, RNA_def_boolean(func, "ok", 1, "", ""));
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* iterator */
func = RNA_def_function(srna, "iterator", NULL);
RNA_def_function_ui_description(func, "Call generate() on the structs which have properties to be keyframed");
RNA_def_function_flag(func, FUNC_REGISTER);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "ks", "KeyingSet", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* generate */
func = RNA_def_function(srna, "generate", NULL);
RNA_def_function_ui_description(func, "Add Paths to the Keying Set to keyframe the properties of the given data");
RNA_def_function_flag(func, FUNC_REGISTER);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "ks", "KeyingSet", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "data", "AnyType", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
}
static void rna_def_keyingset_path(BlenderRNA *brna)
@@ -742,6 +745,7 @@ static void rna_def_keyingset_path(BlenderRNA *brna)
RNA_def_property_enum_default(prop, ID_OB);
RNA_def_property_enum_funcs(prop, NULL, "rna_ksPath_id_type_set", NULL);
RNA_def_property_ui_text(prop, "ID Type", "Type of ID-block that can be used");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
RNA_def_property_update(prop, NC_SCENE | ND_KEYINGSET | NA_EDITED, NULL); /* XXX: maybe a bit too noisy */
/* Group */
@@ -806,12 +810,12 @@ static void rna_def_keyingset_paths(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "ksp", "KeyingSetPath", "New Path", "Path created and added to the Keying Set");
RNA_def_function_return(func, parm);
/* ID-block for target */
- parm = RNA_def_pointer(func, "target_id", "ID", "Target ID", "ID-Datablock for the destination");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm = RNA_def_pointer(func, "target_id", "ID", "Target ID", "ID data-block for the destination");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* rna-path */
/* XXX hopefully this is long enough */
parm = RNA_def_string(func, "data_path", NULL, 256, "Data-Path", "RNA-Path to destination property");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* index (defaults to -1 for entire array) */
RNA_def_int(func, "index", -1, -1, INT_MAX, "Index",
"The index of the destination property (i.e. axis of Location/Rotation/etc.), "
@@ -829,8 +833,8 @@ static void rna_def_keyingset_paths(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
/* path to remove */
parm = RNA_def_pointer(func, "path", "KeyingSetPath", "Path", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
/* Remove All Paths */
@@ -939,8 +943,8 @@ static void rna_api_animdata_nla_tracks(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS | 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_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ 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, "NlaTrack");
@@ -979,7 +983,7 @@ static void rna_api_animdata_drivers(BlenderRNA *brna, PropertyRNA *cprop)
"of all driver F-Curves.");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "data_path", NULL, 0, "Data Path", "F-Curve data path");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "Array index", 0, INT_MAX);
/* return type */
parm = RNA_def_pointer(func, "fcurve", "FCurve", "", "The found F-Curve, or None if it doesn't exist");
diff --git a/source/blender/makesrna/intern/rna_animviz.c b/source/blender/makesrna/intern/rna_animviz.c
index 8e42e68ed1e..eea24bfb1e0 100644
--- a/source/blender/makesrna/intern/rna_animviz.c
+++ b/source/blender/makesrna/intern/rna_animviz.c
@@ -153,7 +153,20 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna)
prop = RNA_def_property(srna, "length", PROP_INT, PROP_TIME);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Length", "Number of frames cached");
-
+
+ /* Custom Color */
+ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Color", "Custom color for motion path");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ /* Line width */
+ prop = RNA_def_property(srna, "line_thickness", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "line_thickness");
+ RNA_def_property_range(prop, 1, 6);
+ RNA_def_property_ui_text(prop, "Line thickness", "Line thickness for drawing path");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
/* Settings */
prop = RNA_def_property(srna, "use_bone_head", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOTIONPATH_FLAG_BHEAD);
@@ -164,6 +177,19 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna)
prop = RNA_def_property(srna, "is_modified", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOTIONPATH_FLAG_EDIT);
RNA_def_property_ui_text(prop, "Edit Path", "Path is being edited");
+
+ /* Use custom color */
+ prop = RNA_def_property(srna, "use_custom_color", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOTIONPATH_FLAG_CUSTOM);
+ RNA_def_property_ui_text(prop, "Custom colors", "Use custom color for this motion path");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ /* Draw lines between keyframes */
+ prop = RNA_def_property(srna, "lines", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOTIONPATH_FLAG_LINES);
+ RNA_def_property_ui_text(prop, "Lines", "Draw straight lines between keyframe points");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
}
/* --- */
@@ -337,6 +363,7 @@ static void rna_def_animviz_paths(BlenderRNA *brna)
"Number of frames to show after the current frame "
"(only for 'Around Current Frame' Onion-skinning method)");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); /* XXX since this is only for 3d-view drawing */
+
}
/* --- */
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index 5c7f51516cb..014a08b70ce 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -44,18 +44,19 @@
#ifdef RNA_RUNTIME
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_idprop.h"
#include "BKE_main.h"
#include "ED_armature.h"
#include "BKE_armature.h"
+#include "DEG_depsgraph.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); */
}
@@ -173,7 +174,7 @@ static void rna_Bone_select_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Po
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);
}
}
else if (GS(id->name) == ID_OB) {
@@ -181,12 +182,15 @@ static void rna_Bone_select_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Po
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);
}
}
}
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
+
+ /* spaces that show animation data of the selected bone need updating */
+ WM_main_add_notifier(NC_ANIMATION | ND_ANIMCHAN, id);
}
static char *rna_Bone_path(PointerRNA *ptr)
@@ -948,8 +952,7 @@ static void rna_def_armature_edit_bones(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Add a new bone");
parm = RNA_def_string(func, "name", "Object", 0, "", "New name for the bone");
- RNA_def_property_flag(parm, PROP_REQUIRED);
-
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "bone", "EditBone", "", "Newly created edit bone");
RNA_def_function_return(func, parm);
@@ -960,16 +963,18 @@ static void rna_def_armature_edit_bones(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove an existing bone from the armature");
/* target to remove*/
parm = RNA_def_pointer(func, "bone", "EditBone", "", "EditBone to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_armature(BlenderRNA *brna)
{
StructRNA *srna;
- FunctionRNA *func;
PropertyRNA *prop;
-
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
static EnumPropertyItem prop_drawtype_items[] = {
{ARM_OCTA, "OCTAHEDRAL", 0, "Octahedral", "Display bones as octahedral shape (default)"},
{ARM_LINE, "STICK", 0, "Stick", "Display bones as simple 2D lines with dots"},
@@ -1005,8 +1010,8 @@ static void rna_def_armature(BlenderRNA *brna)
func = RNA_def_function(srna, "transform", "rna_Armature_transform");
RNA_def_function_ui_description(func, "Transform armature bones by a matrix");
- prop = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f);
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ 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);
/* Animation Data */
rna_def_animdata_common(srna);
diff --git a/source/blender/makesrna/intern/rna_armature_api.c b/source/blender/makesrna/intern/rna_armature_api.c
index 1a4a9492543..0616331bc05 100644
--- a/source/blender/makesrna/intern/rna_armature_api.c
+++ b/source/blender/makesrna/intern/rna_armature_api.c
@@ -67,7 +67,7 @@ void RNA_api_armature_edit_bone(StructRNA *srna)
RNA_def_function_ui_description(func, "Align the bone to a localspace roll so the Z axis "
"points in the direction of the vector given");
parm = RNA_def_float_vector(func, "vector", 3, NULL, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
void RNA_api_bone(StructRNA *srna)
@@ -79,7 +79,7 @@ void RNA_api_bone(StructRNA *srna)
RNA_def_function_ui_description(func, "Calculate bone envelope at given point");
parm = RNA_def_float_vector_xyz(func, "point", 3, NULL, -FLT_MAX, FLT_MAX, "Point",
"Position in 3d space to evaluate", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* 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);
diff --git a/source/blender/makesrna/intern/rna_boid.c b/source/blender/makesrna/intern/rna_boid.c
index 72f67b86c23..cee2b7ed9bc 100644
--- a/source/blender/makesrna/intern/rna_boid.c
+++ b/source/blender/makesrna/intern/rna_boid.c
@@ -87,9 +87,11 @@ static 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 14e3c4c277b..6f453c21370 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -371,17 +371,23 @@ 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_main_tex_update(bContext *C, PointerRNA *ptr)
{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Brush *br = (Brush *)ptr->data;
- BKE_paint_invalidate_overlay_tex(scene, br->mtex.tex);
+ BKE_paint_invalidate_overlay_tex(scene, sl, br->mtex.tex);
rna_Brush_update(bmain, scene, ptr);
}
-static void rna_Brush_secondary_tex_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);
+ SceneLayer *sl = CTX_data_scene_layer(C);
Brush *br = (Brush *)ptr->data;
- BKE_paint_invalidate_overlay_tex(scene, br->mask_mtex.tex);
+ BKE_paint_invalidate_overlay_tex(scene, sl, br->mask_mtex.tex);
rna_Brush_update(bmain, scene, ptr);
}
@@ -444,14 +450,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) {
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ BKE_paint_invalidate_overlay_tex(scene, sl, mtex->tex);
+ }
- rna_TextureSlot_update(bmain, scene, ptr);
+ rna_TextureSlot_update(C, ptr);
}
static void rna_Brush_set_size(PointerRNA *ptr, int value)
@@ -665,39 +674,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");
@@ -1366,7 +1382,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 +1394,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");
diff --git a/source/blender/makesrna/intern/rna_cachefile.c b/source/blender/makesrna/intern/rna_cachefile.c
index 7249ebd5feb..bfe419ca8e3 100644
--- a/source/blender/makesrna/intern/rna_cachefile.c
+++ b/source/blender/makesrna/intern/rna_cachefile.c
@@ -35,7 +35,8 @@
#ifdef RNA_RUNTIME
#include "BKE_cachefile.h"
-#include "BKE_depsgraph.h"
+
+#include "BLI_string.h"
#include "DEG_depsgraph.h"
@@ -50,7 +51,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);
@@ -60,6 +61,12 @@ 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(bmain, cache_file);
+ BLI_freelistN(&cache_file->object_paths);
+ cache_file->flag &= ~CACHEFILE_DIRTY;
+ }
+
BKE_cachefile_reload(bmain, cache_file);
rna_CacheFile_update(bmain, scene, ptr);
@@ -71,6 +78,20 @@ static void rna_CacheFile_object_paths_begin(CollectionPropertyIterator *iter, P
rna_iterator_listbase_begin(iter, &cache_file->object_paths, NULL);
}
+static void rna_CacheFile_filename_set(PointerRNA *ptr, const char *value)
+{
+ CacheFile *cache_file = ptr->data;
+
+ if (STREQ(cache_file->filepath, value)) {
+ return;
+ }
+
+ /* Different file is opened, close all readers. */
+ cache_file->flag |= CACHEFILE_DIRTY;
+
+ BLI_strncpy(cache_file->filepath, value, sizeof(cache_file->filepath));
+}
+
#else
/* cachefile.object_paths */
@@ -103,6 +124,7 @@ static void rna_def_cachefile(BlenderRNA *brna)
RNA_def_struct_ui_icon(srna, ICON_FILE);
PropertyRNA *prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_CacheFile_filename_set");
RNA_def_property_ui_text(prop, "File Path", "Path to external displacements file");
RNA_def_property_update(prop, 0, "rna_CacheFile_update_handle");
diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c
index 078ba13d76d..1127940de44 100644
--- a/source/blender/makesrna/intern/rna_camera.c
+++ b/source/blender/makesrna/intern/rna_camera.c
@@ -40,7 +40,9 @@
#include "BKE_camera.h"
#include "BKE_object.h"
-#include "BKE_depsgraph.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
static float rna_Camera_angle_get(PointerRNA *ptr)
{
@@ -84,14 +86,14 @@ 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);
}
#else
diff --git a/source/blender/makesrna/intern/rna_cloth.c b/source/blender/makesrna/intern/rna_cloth.c
index 781e44c9ed6..effd140ab15 100644
--- a/source/blender/makesrna/intern/rna_cloth.c
+++ b/source/blender/makesrna/intern/rna_cloth.c
@@ -46,16 +46,23 @@
#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)
+{
+ DEG_relations_tag_update(bmain);
+ rna_cloth_update(bmain, scene, ptr);
+}
+
static void rna_cloth_pinning_changed(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Object *ob = (Object *)ptr->id.data;
@@ -64,10 +71,20 @@ 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);
}
+static void rna_ClothSettings_bending_set(struct PointerRNA *ptr, float value)
+{
+ ClothSimSettings *settings = (ClothSimSettings *)ptr->data;
+
+ settings->bending = value;
+
+ /* check for max clipping */
+ if (value > settings->max_bend)
+ settings->max_bend = value;
+}
static void rna_ClothSettings_max_bend_set(struct PointerRNA *ptr, float value)
{
@@ -80,6 +97,17 @@ 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)
+{
+ ClothSimSettings *settings = (ClothSimSettings *)ptr->data;
+
+ settings->structural = value;
+
+ /* check for max clipping */
+ if (value > settings->max_struct)
+ settings->max_struct = value;
+}
+
static void rna_ClothSettings_max_struct_set(struct PointerRNA *ptr, float value)
{
ClothSimSettings *settings = (ClothSimSettings *)ptr->data;
@@ -493,6 +521,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "structural_stiffness", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "structural");
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_update(prop, 0, "rna_cloth_update");
@@ -521,6 +550,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
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_update(prop, 0, "rna_cloth_update");
@@ -706,7 +736,7 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "group", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Collision Group", "Limit colliders to this Group");
- RNA_def_property_update(prop, 0, "rna_cloth_update");
+ RNA_def_property_update(prop, 0, "rna_cloth_dependency_update");
prop = RNA_def_property(srna, "vertex_group_self_collisions", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop, "rna_CollSettings_selfcol_vgroup_get", "rna_CollSettings_selfcol_vgroup_length",
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 24f2d8174af..4d9dcdf0fce 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -53,7 +53,6 @@
#include "MEM_guardedalloc.h"
#include "BKE_colortools.h"
-#include "BKE_depsgraph.h"
#include "BKE_image.h"
#include "BKE_movieclip.h"
#include "BKE_node.h"
@@ -61,6 +60,8 @@
#include "BKE_texture.h"
#include "BKE_linestyle.h"
+#include "DEG_depsgraph.h"
+
#include "ED_node.h"
#include "IMB_colormanagement.h"
@@ -315,7 +316,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 +336,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 +351,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 +447,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);
}
}
@@ -508,12 +509,13 @@ static void rna_ColorManagedViewSettings_look_set(PointerRNA *ptr, int value)
}
static EnumPropertyItem *rna_ColorManagedViewSettings_look_itemf(
- bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+ bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
{
+ ColorManagedViewSettings *view = (ColorManagedViewSettings *) ptr->data;
EnumPropertyItem *items = NULL;
int totitem = 0;
- IMB_colormanagement_look_items_add(&items, &totitem);
+ IMB_colormanagement_look_items_add(&items, &totitem, view->view_transform);
RNA_enum_item_end(&items, &totitem);
*r_free = true;
@@ -580,7 +582,7 @@ static void rna_ColorManagedColorspaceSettings_reload_update(Main *UNUSED(bmain)
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(ima, NULL, IMA_SIGNAL_COLORMANAGE);
@@ -663,7 +665,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);
}
}
@@ -727,9 +729,9 @@ static void rna_def_curvemap_points_api(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "curvemap_insert");
RNA_def_function_ui_description(func, "Add point to CurveMap");
parm = RNA_def_float(func, "position", 0.0f, -FLT_MAX, FLT_MAX, "Position", "Position to add point", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_float(func, "value", 0.0f, -FLT_MAX, FLT_MAX, "Value", "Value of point", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "point", "CurveMapPoint", "", "New point");
RNA_def_function_return(func, parm);
@@ -737,8 +739,8 @@ static void rna_def_curvemap_points_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Delete point from CurveMap");
parm = RNA_def_pointer(func, "point", "CurveMapPoint", "", "PointElement to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_curvemap(BlenderRNA *brna)
@@ -771,7 +773,7 @@ static void rna_def_curvemap(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Evaluate curve at given location");
parm = RNA_def_float(func, "position", 0.0f, -FLT_MAX, FLT_MAX, "Position", "Position to evaluate curve at", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_float(func, "value", 0.0f, -FLT_MAX, FLT_MAX, "Value", "Value of curve at given location", -FLT_MAX, FLT_MAX);
RNA_def_function_return(func, parm);
}
@@ -889,7 +891,7 @@ static void rna_def_color_ramp_element_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add element to ColorRamp");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_float(func, "position", 0.0f, 0.0f, 1.0f, "Position", "Position to add element", 0.0f, 1.0f);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "element", "ColorRampElement", "", "New element");
RNA_def_function_return(func, parm);
@@ -898,15 +900,17 @@ static void rna_def_color_ramp_element_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Delete element from ColorRamp");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "element", "ColorRampElement", "", "Element to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_color_ramp(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
+
FunctionRNA *func;
+ PropertyRNA *parm;
static EnumPropertyItem prop_interpolation_items[] = {
{COLBAND_INTERP_EASE, "EASE", 0, "Ease", ""},
@@ -974,13 +978,13 @@ static void rna_def_color_ramp(BlenderRNA *brna)
func = RNA_def_function(srna, "evaluate", "rna_ColorRamp_eval");
RNA_def_function_ui_description(func, "Evaluate ColorRamp");
- prop = RNA_def_float(func, "position", 1.0f, 0.0f, 1.0f, "Position", "Evaluate ColorRamp at position", 0.0f, 1.0f);
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_float(func, "position", 1.0f, 0.0f, 1.0f, "Position", "Evaluate ColorRamp at position", 0.0f, 1.0f);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return */
- prop = RNA_def_float_color(func, "color", 4, NULL, -FLT_MAX, FLT_MAX, "Color", "Color at given position",
+ parm = RNA_def_float_color(func, "color", 4, NULL, -FLT_MAX, FLT_MAX, "Color", "Color at given position",
-FLT_MAX, FLT_MAX);
- RNA_def_property_flag(prop, PROP_THICK_WRAP);
- RNA_def_function_output(func, prop);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_function_output(func, parm);
}
static void rna_def_histogram(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index db3f76f3cfc..8ecbd438c2e 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -148,12 +148,16 @@ static EnumPropertyItem space_object_items[] = {
{0, NULL, 0, NULL, NULL}
};
+#include "DNA_cachefile_types.h"
+
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
+#ifdef WITH_ALEMBIC
+# include "ABC_alembic.h"
+#endif
static StructRNA *rna_ConstraintType_refine(struct PointerRNA *ptr)
{
@@ -471,6 +475,22 @@ static void rna_Constraint_objectSolver_camera_set(PointerRNA *ptr, PointerRNA v
}
}
+static void rna_Constraint_transformCache_object_path_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+#ifdef WITH_ALEMBIC
+ bConstraint *con = (bConstraint *)ptr->data;
+ bTransformCacheConstraint *data = (bTransformCacheConstraint *)con->data;
+ Object *ob = (Object *)ptr->id.data;
+
+ data->reader = CacheReader_open_alembic_object(data->cache_file->handle,
+ data->reader,
+ ob,
+ data->object_path);
+#endif
+
+ rna_Constraint_update(bmain, scene, ptr);
+}
+
#else
static EnumPropertyItem constraint_distance_items[] = {
@@ -2593,7 +2613,7 @@ static void rna_def_constraint_transform_cache(BlenderRNA *brna)
prop = RNA_def_property(srna, "object_path", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Object Path", "Path to the object in the Alembic archive used to lookup the transform matrix");
- RNA_def_property_update(prop, 0, "rna_Constraint_update");
+ RNA_def_property_update(prop, 0, "rna_Constraint_transformCache_object_path_update");
}
/* base struct for constraints */
diff --git a/source/blender/makesrna/intern/rna_context.c b/source/blender/makesrna/intern/rna_context.c
index a512f1d750f..36078cb0864 100644
--- a/source/blender/makesrna/intern/rna_context.c
+++ b/source/blender/makesrna/intern/rna_context.c
@@ -51,6 +51,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;
@@ -101,12 +107,38 @@ static PointerRNA rna_Context_main_get(PointerRNA *ptr)
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_scene_layer_get(PointerRNA *ptr)
+{
+ bContext *C = (bContext *)ptr->data;
+ return rna_pointer_inherit_refine(ptr, &RNA_SceneLayer, CTX_data_scene_layer(C));
+}
+
+static PointerRNA rna_Context_scene_collection_get(PointerRNA *ptr)
+{
+ bContext *C = (bContext *)ptr->data;
+ ptr->id.data = CTX_data_scene(C);
+ return rna_pointer_inherit_refine(ptr, &RNA_SceneCollection, CTX_data_scene_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;
@@ -168,6 +200,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");
@@ -199,11 +236,31 @@ void RNA_def_context(BlenderRNA *brna)
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, "render_layer", PROP_POINTER, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_struct_type(prop, "SceneLayer");
+ RNA_def_property_pointer_funcs(prop, "rna_Context_scene_layer_get", NULL, NULL, NULL);
+
+ prop = RNA_def_property(srna, "scene_collection", PROP_POINTER, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_struct_type(prop, "SceneCollection");
+ RNA_def_property_pointer_funcs(prop, "rna_Context_scene_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");
diff --git a/source/blender/makesrna/intern/rna_controller.c b/source/blender/makesrna/intern/rna_controller.c
index ed700916584..3fa9d7ef270 100644
--- a/source/blender/makesrna/intern/rna_controller.c
+++ b/source/blender/makesrna/intern/rna_controller.c
@@ -29,6 +29,7 @@
#include "DNA_object_types.h"
#include "DNA_controller_types.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index fb4ff6f4856..50938eb75dc 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -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"
@@ -221,7 +223,7 @@ static void rna_Curve_texspace_set(Main *UNUSED(bmain), Scene *UNUSED(scene), Po
BKE_curve_texspace_calc(cu);
}
-static int rna_Curve_texspace_editable(PointerRNA *ptr)
+static int rna_Curve_texspace_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
Curve *cu = (Curve *)ptr->data;
return (cu->texflag & CU_AUTOSPACE) ? 0 : PROP_EDITABLE;
@@ -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);
}
@@ -1257,8 +1259,8 @@ static void rna_def_curve_spline_points(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a spline from a curve");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "spline", "Spline", "", "The spline to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
#endif
}
@@ -1273,7 +1275,7 @@ static void rna_def_curve_spline_bezpoints(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_srna(cprop, "SplineBezierPoints");
srna = RNA_def_struct(brna, "SplineBezierPoints", NULL);
RNA_def_struct_sdna(srna, "Nurb");
- RNA_def_struct_ui_text(srna, "Spline Bezier Points", "Collection of spline bezirt points");
+ RNA_def_struct_ui_text(srna, "Spline Bezier Points", "Collection of spline Bezier points");
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");
@@ -1285,8 +1287,8 @@ static void rna_def_curve_spline_bezpoints(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a spline from a curve");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "spline", "Spline", "", "The spline to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
#endif
}
@@ -1307,7 +1309,7 @@ static void rna_def_curve_splines(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Curve_spline_new");
RNA_def_function_ui_description(func, "Add a new spline to the curve");
parm = RNA_def_enum(func, "type", curve_type_items, CU_POLY, "", "type for the new spline");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "spline", "Spline", "", "The newly created spline");
RNA_def_function_return(func, parm);
@@ -1315,8 +1317,8 @@ static void rna_def_curve_splines(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a spline from a curve");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "spline", "Spline", "", "The spline to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ 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_Curve_spline_clear");
RNA_def_function_ui_description(func, "Remove all splines from a curve");
diff --git a/source/blender/makesrna/intern/rna_curve_api.c b/source/blender/makesrna/intern/rna_curve_api.c
index e85511f08e9..4da262daf8d 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, int shape_keys)
{
BKE_curve_transform(cu, (float (*)[4])mat, shape_keys);
- 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(cu, BKE_CURVE_BATCH_DIRTY_ALL);
+}
+
#else
void RNA_api_curve(StructRNA *srna)
@@ -59,7 +65,7 @@ void RNA_api_curve(StructRNA *srna)
func = RNA_def_function(srna, "transform", "rna_Curve_transform");
RNA_def_function_ui_description(func, "Transform curve by a matrix");
parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "shape_keys", 0, "", "Transform Shape Keys");
func = RNA_def_function(srna, "validate_material_indices", "BKE_curve_material_index_validate");
@@ -67,6 +73,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");
}
#endif
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index 7ff4eaea169..42c0344f46e 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -71,8 +71,8 @@ BlenderDefRNA DefRNA = {NULL, {NULL, NULL}, {NULL, NULL}, NULL, 0, 0, 0, 1, 1};
if (description && (description)[0]) { \
int i = strlen(description); \
if (i > 3 && (description)[i - 1] == '.' && (description)[i - 3] != '.') { \
- fprintf(stderr, "%s: '%s' '%s' description ends with a '.' !\n", \
- __func__, id1 ? id1 : "", id2 ? id2 : ""); \
+ fprintf(stderr, "%s: '%s' description from '%s' '%s' ends with a '.' !\n", \
+ __func__, description, id1 ? id1 : "", id2 ? id2 : ""); \
} \
} (void)0
@@ -618,7 +618,7 @@ void RNA_struct_free(BlenderRNA *brna, StructRNA *srna)
RNA_def_property_free_pointers(prop);
- if (prop->flag & PROP_RUNTIME)
+ if (prop->flag_internal & PROP_INTERN_RUNTIME)
rna_freelinkN(&srna->cont.properties, prop);
}
@@ -630,7 +630,7 @@ void RNA_struct_free(BlenderRNA *brna, StructRNA *srna)
RNA_def_property_free_pointers(parm);
- if (parm->flag & PROP_RUNTIME)
+ if (parm->flag_internal & PROP_INTERN_RUNTIME)
rna_freelinkN(&func->cont.properties, parm);
}
@@ -771,7 +771,7 @@ StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRN
else {
/* define some builtin properties */
prop = RNA_def_property(&srna->cont, "rna_properties", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_flag(prop, PROP_BUILTIN);
+ prop->flag_internal |= PROP_INTERN_BUILTIN;
RNA_def_property_ui_text(prop, "Properties", "RNA property collection");
if (DefRNA.preprocess) {
@@ -1097,7 +1097,7 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier
break;
}
case PROP_POINTER:
- prop->flag |= PROP_THICK_WRAP; /* needed for default behavior when PROP_RNAPTR is set */
+ prop->flag |= PROP_THICK_WRAP; /* needed for default behavior when PARM_RNAPTR is set */
break;
case PROP_ENUM:
case PROP_COLLECTION:
@@ -1189,7 +1189,8 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier
}
}
else {
- prop->flag |= PROP_IDPROPERTY | PROP_RUNTIME;
+ prop->flag |= PROP_IDPROPERTY;
+ prop->flag_internal |= PROP_INTERN_RUNTIME;
#ifdef RNA_RUNTIME
if (cont->prophash)
BLI_ghash_insert(cont->prophash, (void *)prop->identifier, prop);
@@ -1201,16 +1202,28 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier
return prop;
}
-void RNA_def_property_flag(PropertyRNA *prop, int flag)
+void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
{
prop->flag |= flag;
}
-void RNA_def_property_clear_flag(PropertyRNA *prop, int flag)
+void RNA_def_property_clear_flag(PropertyRNA *prop, PropertyFlag flag)
{
prop->flag &= ~flag;
}
+void RNA_def_parameter_flags(PropertyRNA *prop, PropertyFlag flag_property, ParameterFlag flag_parameter)
+{
+ prop->flag |= flag_property;
+ prop->flag_parameter |= flag_parameter;
+}
+
+void RNA_def_parameter_clear_flags(PropertyRNA *prop, PropertyFlag flag_property, ParameterFlag flag_parameter)
+{
+ prop->flag &= ~flag_property;
+ prop->flag_parameter &= ~flag_parameter;
+}
+
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype)
{
prop->subtype = subtype;
@@ -2155,6 +2168,16 @@ void RNA_def_property_update_runtime(PropertyRNA *prop, const void *func)
prop->update = (void *)func;
}
+void RNA_def_property_poll_runtime(PropertyRNA *prop, const void *func)
+{
+ if (prop->type == PROP_POINTER) {
+ ((PointerPropertyRNA *)prop)->poll = func;
+ }
+ else {
+ fprintf(stderr, "%s: %s is not a Pointer Property.\n", __func__, prop->identifier);
+ }
+}
+
void RNA_def_property_dynamic_array_funcs(PropertyRNA *prop, const char *getlength)
{
if (!DefRNA.preprocess) {
@@ -2969,6 +2992,9 @@ PropertyRNA *RNA_def_pointer_runtime(StructOrFunctionRNA *cont_, const char *ide
prop = RNA_def_property(cont, identifier, PROP_POINTER, PROP_NONE);
RNA_def_property_struct_runtime(prop, type);
+ if ((type->flag & STRUCT_ID) != 0) {
+ prop->flag |= PROP_EDITABLE;
+ }
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
@@ -3097,7 +3123,7 @@ void RNA_def_function_return(FunctionRNA *func, PropertyRNA *ret)
void RNA_def_function_output(FunctionRNA *UNUSED(func), PropertyRNA *ret)
{
- ret->flag |= PROP_OUTPUT;
+ ret->flag_parameter |= PARM_OUTPUT;
}
void RNA_def_function_flag(FunctionRNA *func, int flag)
@@ -3144,12 +3170,13 @@ int rna_parameter_size(PropertyRNA *parm)
StringPropertyRNA *sparm = (StringPropertyRNA *)parm;
return sizeof(char) * sparm->maxlength;
}
- else
+ else {
return sizeof(char *);
+ }
case PROP_POINTER:
{
#ifdef RNA_RUNTIME
- if (parm->flag & PROP_RNAPTR)
+ if (parm->flag_parameter & PARM_RNAPTR)
if (parm->flag & PROP_THICK_WRAP) {
return sizeof(PointerRNA);
}
@@ -3159,7 +3186,7 @@ int rna_parameter_size(PropertyRNA *parm)
else
return sizeof(void *);
#else
- if (parm->flag & PROP_RNAPTR) {
+ if (parm->flag_parameter & PARM_RNAPTR) {
if (parm->flag & PROP_THICK_WRAP) {
return sizeof(PointerRNA);
}
@@ -3357,12 +3384,12 @@ void RNA_def_property_duplicate_pointers(StructOrFunctionRNA *cont_, PropertyRNA
break;
}
- prop->flag |= PROP_FREE_POINTERS;
+ prop->flag_internal |= PROP_INTERN_FREE_POINTERS;
}
void RNA_def_property_free_pointers(PropertyRNA *prop)
{
- if (prop->flag & PROP_FREE_POINTERS) {
+ if (prop->flag_internal & PROP_INTERN_FREE_POINTERS) {
int a;
if (prop->identifier)
@@ -3429,7 +3456,7 @@ static void rna_def_property_free(StructOrFunctionRNA *cont_, PropertyRNA *prop)
{
ContainerRNA *cont = cont_;
- if (prop->flag & PROP_RUNTIME) {
+ if (prop->flag_internal & PROP_INTERN_RUNTIME) {
if (cont->prophash)
BLI_ghash_remove(cont->prophash, prop->identifier, NULL, NULL);
@@ -3449,7 +3476,7 @@ int RNA_def_property_free_identifier(StructOrFunctionRNA *cont_, const char *ide
for (prop = cont->properties.first; prop; prop = prop->next) {
if (STREQ(prop->identifier, identifier)) {
- if (prop->flag & PROP_RUNTIME) {
+ if (prop->flag_internal & PROP_INTERN_RUNTIME) {
rna_def_property_free(cont_, prop);
return 1;
}
@@ -3460,7 +3487,7 @@ int RNA_def_property_free_identifier(StructOrFunctionRNA *cont_, const char *ide
}
return 0;
}
-#endif
+#endif /* RNA_RUNTIME */
const char *RNA_property_typename(PropertyType type)
{
diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c
index 8ac1e2acc60..9ea12e3befa 100644
--- a/source/blender/makesrna/intern/rna_depsgraph.c
+++ b/source/blender/makesrna/intern/rna_depsgraph.c
@@ -36,31 +36,107 @@
#include "DEG_depsgraph.h"
-#include "BKE_depsgraph.h"
+#include "DNA_object_types.h"
#ifdef RNA_RUNTIME
+#include "BLI_iterator.h"
#include "BKE_report.h"
+#include "DNA_object_types.h"
+#include "DEG_depsgraph_build.h"
#include "DEG_depsgraph_debug.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MEM_guardedalloc.h"
+
+/* **************** Depsgraph **************** */
+
+static PointerRNA rna_DepsgraphIter_object_get(PointerRNA *ptr)
+{
+ BLI_Iterator *iterator = ptr->data;
+ return rna_pointer_inherit_refine(ptr, &RNA_Object, iterator->current);
+}
+
+static PointerRNA rna_DepsgraphIter_instance_object_get(PointerRNA *ptr)
+{
+ BLI_Iterator *iterator = ptr->data;
+ DEGObjectsIteratorData *deg_iter = (DEGObjectsIteratorData *)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_DepsgraphIter_parent_get(PointerRNA *ptr)
+{
+ BLI_Iterator *iterator = ptr->data;
+ DEGObjectsIteratorData *deg_iter = (DEGObjectsIteratorData *)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 void rna_DepsgraphIter_persistent_id_get(PointerRNA *ptr, int *persistent_id)
+{
+ BLI_Iterator *iterator = ptr->data;
+ DEGObjectsIteratorData *deg_iter = (DEGObjectsIteratorData *)iterator->data;
+ memcpy(persistent_id, deg_iter->dupli_object_current->persistent_id,
+ sizeof(deg_iter->dupli_object_current->persistent_id));
+}
+
+static void rna_DepsgraphIter_orco_get(PointerRNA *ptr, float *orco)
+{
+ BLI_Iterator *iterator = ptr->data;
+ DEGObjectsIteratorData *deg_iter = (DEGObjectsIteratorData *)iterator->data;
+ memcpy(orco, deg_iter->dupli_object_current->orco,
+ sizeof(deg_iter->dupli_object_current->orco));
+}
+
+static unsigned int rna_DepsgraphIter_random_id_get(PointerRNA *ptr)
+{
+ BLI_Iterator *iterator = ptr->data;
+ DEGObjectsIteratorData *deg_iter = (DEGObjectsIteratorData *)iterator->data;
+ return deg_iter->dupli_object_current->random_id;
+}
+
+static void rna_DepsgraphIter_uv_get(PointerRNA *ptr, float *uv)
+{
+ BLI_Iterator *iterator = ptr->data;
+ DEGObjectsIteratorData *deg_iter = (DEGObjectsIteratorData *)iterator->data;
+ memcpy(uv, deg_iter->dupli_object_current->uv,
+ sizeof(deg_iter->dupli_object_current->uv));
+}
+
+static int rna_DepsgraphIter_is_instance_get(PointerRNA *ptr)
+{
+ BLI_Iterator *iterator = ptr->data;
+ DEGObjectsIteratorData *deg_iter = (DEGObjectsIteratorData *)iterator->data;
+ return (deg_iter->dupli_object_current != NULL);
+}
+
+/* **************** Depsgraph **************** */
static void rna_Depsgraph_debug_graphviz(Depsgraph *graph, const char *filename)
{
FILE *f = fopen(filename, "w");
if (f == NULL)
return;
-
+
DEG_debug_graphviz(graph, f, "Depsgraph", false);
-
+
fclose(f);
}
static void rna_Depsgraph_debug_rebuild(Depsgraph *UNUSED(graph), Main *bmain)
{
Scene *sce;
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- DAG_scene_relations_rebuild(bmain, sce);
+ DEG_scene_relations_rebuild(bmain, sce);
DEG_graph_on_visible_update(bmain, sce);
}
}
@@ -68,44 +144,204 @@ static void rna_Depsgraph_debug_rebuild(Depsgraph *UNUSED(graph), Main *bmain)
static void rna_Depsgraph_debug_stats(Depsgraph *graph, ReportList *reports)
{
size_t outer, ops, rels;
-
+
DEG_stats_simple(graph, &outer, &ops, &rels);
-
+
// XXX: report doesn't seem to work
printf("Approx %lu Operations, %lu Relations, %lu Outer Nodes\n",
ops, rels, outer);
-
+
BKE_reportf(reports, RPT_WARNING, "Approx. %lu Operations, %lu Relations, %lu Outer Nodes",
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__);
+ DEGObjectsIteratorData *data = MEM_callocN(sizeof(DEGObjectsIteratorData), __func__);
+
+ data->graph = (Depsgraph *)ptr->data;
+ data->flag = DEG_OBJECT_ITER_FLAG_SET;
+
+ DEG_objects_iterator_begin(iter->internal.custom, data);
+ iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid;
+}
+
+static void rna_Depsgraph_objects_next(CollectionPropertyIterator *iter)
+{
+ DEG_objects_iterator_next(iter->internal.custom);
+ iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid;
+}
+
+static void rna_Depsgraph_objects_end(CollectionPropertyIterator *iter)
+{
+ DEG_objects_iterator_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.
+ */
+
+static void rna_Depsgraph_duplis_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ iter->internal.custom = MEM_callocN(sizeof(BLI_Iterator), __func__);
+ DEGObjectsIteratorData *data = MEM_callocN(sizeof(DEGObjectsIteratorData), __func__);
+
+ data->graph = (Depsgraph *)ptr->data;
+ data->flag = DEG_OBJECT_ITER_FLAG_ALL;
+
+ DEG_objects_iterator_begin(iter->internal.custom, data);
+ iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid;
+}
+
+static void rna_Depsgraph_duplis_next(CollectionPropertyIterator *iter)
+{
+ DEG_objects_iterator_next(iter->internal.custom);
+ iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid;
+}
+
+static void rna_Depsgraph_duplis_end(CollectionPropertyIterator *iter)
+{
+ DEG_objects_iterator_end(iter->internal.custom);
+ MEM_freeN(((BLI_Iterator *)iter->internal.custom)->data);
+ MEM_freeN(iter->internal.custom);
+}
+
+static PointerRNA rna_Depsgraph_duplis_get(CollectionPropertyIterator *iter)
+{
+ BLI_Iterator *iterator = (BLI_Iterator *)iter->internal.custom;
+ return rna_pointer_inherit_refine(&iter->parent, &RNA_DepsgraphIter, iterator);
+}
+
+static ID *rna_Depsgraph_evaluated_id_get(Depsgraph *depsgraph, ID *id_orig)
+{
+ return DEG_get_evaluated_id(depsgraph, id_orig);
+}
+
#else
+static void rna_def_depsgraph_iter(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "DepsgraphIter", NULL);
+ RNA_def_struct_ui_text(srna, "Dependency Graph Iterator",
+ "Extended information about dependency graph object iterator");
+
+ prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_ui_text(prop, "Object", "Object the iterator points to");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+ RNA_def_property_pointer_funcs(prop, "rna_DepsgraphIter_object_get", NULL, NULL, 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", "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_DepsgraphIter_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", "Parent of the duplication list");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+ RNA_def_property_pointer_funcs(prop, "rna_DepsgraphIter_parent_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_DepsgraphIter_persistent_id_get", NULL, NULL);
+
+ prop = RNA_def_property(srna, "orco", PROP_FLOAT, PROP_TRANSLATION);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+ /* Seems system is not smart enough to figure that getter function should return
+ * array for PROP_TRANSLATION.
+ */
+ 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_DepsgraphIter_orco_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_DepsgraphIter_random_id_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_DepsgraphIter_uv_get", 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 ocming from dupli-list");
+ RNA_def_property_boolean_funcs(prop, "rna_DepsgraphIter_is_instance_get", NULL);
+}
+
static void rna_def_depsgraph(BlenderRNA *brna)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
+ PropertyRNA *prop;
srna = RNA_def_struct(brna, "Depsgraph", NULL);
RNA_def_struct_ui_text(srna, "Dependency Graph", "");
-
+
func = RNA_def_function(srna, "debug_graphviz", "rna_Depsgraph_debug_graphviz");
parm = RNA_def_string_file_path(func, "filename", NULL, FILE_MAX, "File Name",
"File in which to store graphviz debug output");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "debug_rebuild", "rna_Depsgraph_debug_rebuild");
RNA_def_function_flag(func, FUNC_USE_MAIN);
- RNA_def_property_flag(parm, PROP_REQUIRED);
-
+
func = RNA_def_function(srna, "debug_stats", "rna_Depsgraph_debug_stats");
RNA_def_function_ui_description(func, "Report the number of elements in the Dependency Graph");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
+
+ 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);
+
+ func = RNA_def_function(srna, "evaluated_id_get", "rna_Depsgraph_evaluated_id_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, "evaluated_id", "ID", "", "Evaluated ID for the given original one");
+ RNA_def_function_return(func, parm);
+
+ /* TODO(sergey): Find a better name. */
+ prop = RNA_def_property(srna, "duplis", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "DepsgraphIter");
+ RNA_def_property_collection_funcs(prop,
+ "rna_Depsgraph_duplis_begin",
+ "rna_Depsgraph_duplis_next",
+ "rna_Depsgraph_duplis_end",
+ "rna_Depsgraph_duplis_get",
+ NULL, NULL, NULL, NULL);
}
void RNA_def_depsgraph(BlenderRNA *brna)
{
+ rna_def_depsgraph_iter(brna);
rna_def_depsgraph(brna);
}
diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c
index fc2b028e829..f51bd9d93cc 100644
--- a/source/blender/makesrna/intern/rna_dynamicpaint.c
+++ b/source/blender/makesrna/intern/rna_dynamicpaint.c
@@ -55,9 +55,10 @@ 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)
@@ -651,9 +652,9 @@ static void rna_def_canvas_surface(BlenderRNA *brna)
func = RNA_def_function(srna, "output_exists", "rna_DynamicPaint_is_output_exists");
RNA_def_function_ui_description(func, "Checks if surface output layer of given name exists");
parm = RNA_def_pointer(func, "object", "Object", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_int(func, "index", 0, 0, 1, "Index", "", 0, 1);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_boolean(func, "exists", 0, "", "");
RNA_def_function_return(func, parm);
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index c521e93d33e..e951e15ca8c 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -35,6 +35,8 @@
#include "BLI_math.h"
+#include "BLT_translation.h"
+
#include "BKE_action.h"
#include "RNA_access.h"
@@ -125,9 +127,11 @@ 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 void rna_ChannelDriver_update_data(Main *bmain, Scene *scene, PointerRNA *ptr)
{
ID *id = ptr->id.data;
@@ -136,8 +140,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);
}
@@ -199,13 +203,13 @@ static StructRNA *rna_DriverTarget_id_typef(PointerRNA *ptr)
return ID_code_to_RNA_type(dtar->idtype);
}
-static int rna_DriverTarget_id_editable(PointerRNA *ptr)
+static int rna_DriverTarget_id_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
DriverTarget *dtar = (DriverTarget *)ptr->data;
return (dtar->idtype) ? PROP_EDITABLE : 0;
}
-static int rna_DriverTarget_id_type_editable(PointerRNA *ptr)
+static int rna_DriverTarget_id_type_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
DriverTarget *dtar = (DriverTarget *)ptr->data;
@@ -585,7 +589,7 @@ static void rna_FModifier_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poin
{
ID *id = ptr->id.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);
if (adt != NULL) {
adt->recalc |= ADT_RECALC_ANIM;
}
@@ -763,6 +767,38 @@ static void rna_FModifierStepped_end_frame_range(PointerRNA *ptr, float *min, fl
*max = MAXFRAMEF;
}
+static void rna_FModifierStepped_frame_start_set(PointerRNA *ptr, float value)
+{
+ FModifier *fcm = (FModifier *)ptr->data;
+ FMod_Stepped *data = fcm->data;
+
+ float prop_clamp_min = -FLT_MAX, prop_clamp_max = FLT_MAX, prop_soft_min, prop_soft_max;
+ rna_FModifierStepped_start_frame_range(ptr, &prop_clamp_min, &prop_clamp_max, &prop_soft_min, &prop_soft_max);
+ value = CLAMPIS(value, prop_clamp_min, prop_clamp_max);
+
+ /* Need to set both step-data's start/end and the start/end on the base-data,
+ * or else Restrict-Range doesn't work due to RNA-property shadowing (T52009)
+ */
+ data->start_frame = value;
+ fcm->sfra = value;
+}
+
+static void rna_FModifierStepped_frame_end_set(PointerRNA *ptr, float value)
+{
+ FModifier *fcm = (FModifier *)ptr->data;
+ FMod_Stepped *data = fcm->data;
+
+ float prop_clamp_min = -FLT_MAX, prop_clamp_max = FLT_MAX, prop_soft_min, prop_soft_max;
+ rna_FModifierStepped_end_frame_range(ptr, &prop_clamp_min, &prop_clamp_max, &prop_soft_min, &prop_soft_max);
+ value = CLAMPIS(value, prop_clamp_min, prop_clamp_max);
+
+ /* Need to set both step-data's start/end and the start/end on the base-data,
+ * or else Restrict-Range doesn't work due to RNA-property shadowing (T52009)
+ */
+ data->end_frame = value;
+ fcm->efra = value;
+}
+
static BezTriple *rna_FKeyframe_points_insert(FCurve *fcu, float frame, float value, int keyframe_type, int flag)
{
int index = insert_vert_fcurve(fcu, frame, value, (char)keyframe_type, flag | INSERTKEY_NO_USERPREF);
@@ -1029,7 +1065,7 @@ static void rna_def_fmodifier_envelope_control_points(BlenderRNA *brna, Property
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_float(func, "frame", 0.0f, -FLT_MAX, FLT_MAX, "",
"Frame to add this control-point", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "point", "FModifierEnvelopeControlPoint", "", "Newly created control-point");
RNA_def_function_return(func, parm);
@@ -1037,7 +1073,7 @@ static void rna_def_fmodifier_envelope_control_points(BlenderRNA *brna, Property
RNA_def_function_ui_description(func, "Remove a control-point from an FModifierEnvelope");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "point", "FModifierEnvelopeControlPoint", "", "Control-point to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
}
@@ -1282,13 +1318,13 @@ static void rna_def_fmodifier_stepped(BlenderRNA *brna)
prop = RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "start_frame");
- RNA_def_property_float_funcs(prop, NULL, NULL, "rna_FModifierStepped_start_frame_range");
+ RNA_def_property_float_funcs(prop, NULL, "rna_FModifierStepped_frame_start_set", "rna_FModifierStepped_start_frame_range");
RNA_def_property_ui_text(prop, "Start Frame", "Frame that modifier's influence starts (if applicable)");
RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
prop = RNA_def_property(srna, "frame_end", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "end_frame");
- RNA_def_property_float_funcs(prop, NULL, NULL, "rna_FModifierStepped_end_frame_range");
+ RNA_def_property_float_funcs(prop, NULL, "rna_FModifierStepped_frame_end_set", "rna_FModifierStepped_end_frame_range");
RNA_def_property_ui_text(prop, "End Frame", "Frame that modifier's influence ends (if applicable)");
RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FModifier_update");
}
@@ -1448,6 +1484,7 @@ static void rna_def_drivertarget(BlenderRNA *brna)
RNA_def_property_enum_funcs(prop, NULL, "rna_DriverTarget_id_type_set", NULL);
RNA_def_property_editable_func(prop, "rna_DriverTarget_id_type_editable");
RNA_def_property_ui_text(prop, "ID Type", "Type of ID-block that can be used");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
RNA_def_property_update(prop, 0, "rna_DriverTarget_update_data");
/* Target Properties - Property to Drive */
@@ -1554,8 +1591,8 @@ static void rna_def_channeldriver_variables(BlenderRNA *brna, PropertyRNA *cprop
RNA_def_function_flag(func, FUNC_USE_REPORTS);
/* target to remove */
parm = RNA_def_pointer(func, "variable", "DriverVariable", "", "Variable to remove from the driver");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_channeldriver(BlenderRNA *brna)
@@ -1774,15 +1811,15 @@ static void rna_def_fcurve_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_return(func, parm);
/* object to add */
parm = RNA_def_enum(func, "type", rna_enum_fmodifier_type_items, 1, "", "Constraint type to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "remove", "rna_FCurve_modifiers_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a modifier from this F-Curve");
/* modifier to remove */
parm = RNA_def_pointer(func, "modifier", "FModifier", "", "Removed modifier");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
/* fcurve.keyframe_points */
@@ -1809,14 +1846,13 @@ static void rna_def_fcurve_keyframe_points(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a keyframe point to a F-Curve");
parm = RNA_def_float(func, "frame", 0.0f, -FLT_MAX, FLT_MAX, "",
"X Value of this keyframe point", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_float(func, "value", 0.0f, -FLT_MAX, FLT_MAX, "",
"Y Value of this keyframe point", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_enum_flag(func, "options", keyframe_flag_items, 0, "", "Keyframe options");
RNA_def_enum(func, "keyframe_type", rna_enum_beztriple_keyframe_type_items, BEZT_KEYTYPE_KEYFRAME, "",
"Type of keyframe to insert");
-
parm = RNA_def_pointer(func, "keyframe", "Keyframe", "", "Newly created keyframe");
RNA_def_function_return(func, parm);
@@ -1828,8 +1864,8 @@ static void rna_def_fcurve_keyframe_points(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove keyframe from an F-Curve");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "keyframe", "Keyframe", "", "Keyframe to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
/* optional */
RNA_def_boolean(func, "fast", 0, "Fast", "Fast keyframe removal to avoid recalculating the curve each time");
}
@@ -1961,7 +1997,7 @@ static void rna_def_fcurve(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Evaluate F-Curve");
parm = RNA_def_float(func, "frame", 1.0f, -FLT_MAX, FLT_MAX, "Frame",
"Evaluate F-Curve at given frame", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return value */
parm = RNA_def_float(func, "value", 0, -FLT_MAX, FLT_MAX, "Value", "Value of F-Curve specific frame", -FLT_MAX, FLT_MAX);
RNA_def_function_return(func, parm);
@@ -1976,7 +2012,7 @@ static void rna_def_fcurve(BlenderRNA *brna)
/* return value */
parm = RNA_def_float_vector(func, "range", 2, NULL, -FLT_MAX, FLT_MAX, "Range",
"Min/Max values", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_function_output(func, parm);
/* -- auto-flag validity (ensures valid handling for data type) -- */
@@ -1986,7 +2022,7 @@ static void rna_def_fcurve(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "data", "AnyType", "Data",
"Data containing the property controlled by given FCurve");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
/* Functions */
diff --git a/source/blender/makesrna/intern/rna_fcurve_api.c b/source/blender/makesrna/intern/rna_fcurve_api.c
index 8551ca609f4..d8ed908f2df 100644
--- a/source/blender/makesrna/intern/rna_fcurve_api.c
+++ b/source/blender/makesrna/intern/rna_fcurve_api.c
@@ -144,9 +144,9 @@ void RNA_api_fcurves(StructRNA *srna)
"Convert current FCurve from keyframes to sample points, if necessary");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_int(func, "start", 0, MINAFRAME, MAXFRAME, "Start Frame", "", MINAFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "end", 0, MINAFRAME, MAXFRAME, "End Frame", "", MINAFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "convert_to_keyframes", "rna_FCurve_convert_to_keyframes");
RNA_def_function_ui_description(func,
@@ -154,9 +154,9 @@ void RNA_api_fcurves(StructRNA *srna)
"if necessary");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_int(func, "start", 0, MINAFRAME, MAXFRAME, "Start Frame", "", MINAFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "end", 0, MINAFRAME, MAXFRAME, "End Frame", "", MINAFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
void RNA_api_drivers(StructRNA *UNUSED(srna))
diff --git a/source/blender/makesrna/intern/rna_fluidsim.c b/source/blender/makesrna/intern/rna_fluidsim.c
index 091950a8e66..de2076868ec 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);
}
@@ -185,12 +186,16 @@ static void rna_DomainFluidSettings_memory_estimate_get(PointerRNA *ptr, char *v
#endif
}
-static int rna_DomainFluidSettings_memory_estimate_length(PointerRNA *UNUSED(ptr))
+static int rna_DomainFluidSettings_memory_estimate_length(PointerRNA *ptr)
{
#ifndef WITH_MOD_FLUID
+ UNUSED_VARS(ptr);
return 0;
#else
- return 31;
+ char value[32];
+
+ rna_DomainFluidSettings_memory_estimate_get(ptr, value);
+ return strlen(value);
#endif
}
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index 80f4d5d05b6..6e0d6ad2bcd 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -31,6 +31,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -59,6 +60,7 @@ static EnumPropertyItem parent_type_items[] = {
#include "WM_api.h"
+#include "BKE_animsys.h"
#include "BKE_gpencil.h"
#include "BKE_action.h"
@@ -120,7 +122,7 @@ static char *rna_GPencilLayer_path(PointerRNA *ptr)
return BLI_sprintfN("layers[\"%s\"]", name_esc);
}
-static int rna_GPencilLayer_active_frame_editable(PointerRNA *ptr)
+static int rna_GPencilLayer_active_frame_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
bGPDlayer *gpl = (bGPDlayer *)ptr->data;
@@ -352,10 +354,16 @@ static void rna_GPencilLayer_info_set(PointerRNA *ptr, const char *value)
bGPdata *gpd = ptr->id.data;
bGPDlayer *gpl = ptr->data;
+ char oldname[128] = "";
+ BLI_strncpy(oldname, gpl->info, sizeof(oldname));
+
/* copy the new name into the name slot */
BLI_strncpy_utf8(gpl->info, value, sizeof(gpl->info));
BLI_uniquename(&gpd->layers, gpl, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl->info));
+
+ /* now fix animation paths */
+ BKE_animdata_fix_paths_rename_all(&gpd->id, "layers", oldname, gpl->info);
}
static void rna_GPencil_use_onion_skinning_set(PointerRNA *ptr, const int value)
@@ -439,12 +447,23 @@ static void rna_GPencil_stroke_point_select_set(PointerRNA *ptr, const int value
}
}
-static void rna_GPencil_stroke_point_add(bGPDstroke *stroke, int count)
+static void rna_GPencil_stroke_point_add(bGPDstroke *stroke, int count, float pressure, float strength)
{
if (count > 0) {
+ /* create space at the end of the array for extra points */
stroke->points = MEM_recallocN_id(stroke->points,
sizeof(bGPDspoint) * (stroke->totpoints + count),
"gp_stroke_points");
+
+ /* 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);
+ pt->pressure = pressure;
+ pt->strength = strength;
+ }
+
stroke->totpoints += count;
}
}
@@ -482,7 +501,9 @@ static void rna_GPencil_stroke_point_pop(bGPDstroke *stroke, ReportList *reports
static bGPDstroke *rna_GPencil_stroke_new(bGPDframe *frame, const char *colorname)
{
bGPDstroke *stroke = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
- strcpy(stroke->colorname, colorname);
+ if (colorname) {
+ BLI_strncpy(stroke->colorname, colorname, sizeof(stroke->colorname));
+ }
stroke->palcolor = NULL;
stroke->flag |= GP_STROKE_RECALC_COLOR;
BLI_addtail(&frame->strokes, stroke);
@@ -572,11 +593,11 @@ static bGPDframe *rna_GPencil_frame_copy(bGPDlayer *layer, bGPDframe *src)
static bGPDlayer *rna_GPencil_layer_new(bGPdata *gpd, const char *name, int setactive)
{
- bGPDlayer *gl = BKE_gpencil_layer_addnew(gpd, name, setactive != 0);
+ bGPDlayer *gpl = BKE_gpencil_layer_addnew(gpd, name, setactive != 0);
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- return gl;
+ return gpl;
}
static void rna_GPencil_layer_remove(bGPdata *gpd, ReportList *reports, PointerRNA *layer_ptr)
@@ -763,11 +784,26 @@ 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)
@@ -790,14 +826,20 @@ static void rna_GPencilPaletteColor_info_set(PointerRNA *ptr, const char *value)
bGPdata *gpd = ptr->id.data;
bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
bGPDpalettecolor *palcolor = ptr->data;
-
- /* rename all strokes */
- BKE_gpencil_palettecolor_changename(gpd, palcolor->info, value);
+
+ char oldname[64] = "";
+ BLI_strncpy(oldname, palcolor->info, sizeof(oldname));
/* copy the new name into the name slot */
BLI_strncpy_utf8(palcolor->info, value, sizeof(palcolor->info));
BLI_uniquename(&palette->colors, palcolor, DATA_("Color"), '.', offsetof(bGPDpalettecolor, info),
sizeof(palcolor->info));
+
+ /* rename all strokes */
+ BKE_gpencil_palettecolor_changename(gpd, oldname, palcolor->info);
+
+ /* now fix animation paths */
+ BKE_animdata_fix_paths_rename_all(&gpd->id, "colors", oldname, palcolor->info);
}
static void rna_GPencilStrokeColor_info_set(PointerRNA *ptr, const char *value)
@@ -886,9 +928,7 @@ static void rna_def_gpencil_stroke_point(BlenderRNA *brna)
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);
@@ -898,6 +938,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);
+ 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);
func = RNA_def_function(srna, "pop", "rna_GPencil_stroke_point_pop");
RNA_def_function_ui_description(func, "Remove a grease pencil stroke point");
@@ -918,19 +960,19 @@ static void rna_def_gpencil_triangle(BlenderRNA *brna)
/* point v1 */
prop = RNA_def_property(srna, "v1", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "v1");
- RNA_def_property_ui_text(prop, "v1", "First triangle vertice index");
+ RNA_def_property_ui_text(prop, "v1", "First triangle vertex index");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
/* point v2 */
prop = RNA_def_property(srna, "v2", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "v2");
- RNA_def_property_ui_text(prop, "v2", "Second triangle vertice index");
+ RNA_def_property_ui_text(prop, "v2", "Second triangle vertex index");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
/* point v3 */
prop = RNA_def_property(srna, "v3", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "v3");
- RNA_def_property_ui_text(prop, "v3", "Third triangle vertice index");
+ RNA_def_property_ui_text(prop, "v3", "Third triangle vertex index");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
@@ -1028,8 +1070,8 @@ static void rna_def_gpencil_strokes_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a grease pencil stroke");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "stroke", "GPencilStroke", "Stroke", "The stroke to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_gpencil_frame(BlenderRNA *brna)
@@ -1089,7 +1131,7 @@ static void rna_def_gpencil_frames_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_int(func, "frame_number", 1, MINAFRAME, MAXFRAME, "Frame Number",
"The frame on which this sketch appears", MINAFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "frame", "GPencilFrame", "", "The newly created frame");
RNA_def_function_return(func, parm);
@@ -1097,13 +1139,13 @@ static void rna_def_gpencil_frames_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a grease pencil frame");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "frame", "GPencilFrame", "Frame", "The frame to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ 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, "copy", "rna_GPencil_frame_copy");
RNA_def_function_ui_description(func, "Copy a grease pencil frame");
parm = RNA_def_pointer(func, "source", "GPencilFrame", "Source", "The source frame");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_pointer(func, "copy", "GPencilFrame", "", "The newly copied frame");
RNA_def_function_return(func, parm);
}
@@ -1145,7 +1187,8 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
// 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_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");
prop = RNA_def_property(srna, "opacity", PROP_FLOAT, PROP_NONE);
@@ -1174,7 +1217,7 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
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 current strokes (in pixels)");
+ RNA_def_property_ui_text(prop, "Thickness", "Thickness change to apply to current strokes (in pixels)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Onion-Skinning */
@@ -1218,6 +1261,13 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "After Color", "Base color for ghosts after the active frame");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ prop = RNA_def_property(srna, "use_ghosts_always", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_GHOST_ALWAYS);
+ RNA_def_property_ui_text(prop, "Always Show Ghosts",
+ "Ghosts are shown in renders and animation playback. Useful for special effects (e.g. motion blur)");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+
/* Flags */
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_HIDE);
@@ -1241,8 +1291,8 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
prop = RNA_def_property(srna, "unlock_color", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_UNLOCK_COLOR);
RNA_def_property_ui_icon(prop, ICON_RESTRICT_COLOR_OFF, 1);
- RNA_def_property_ui_text(prop, "Unlock color", "Unprotect colors selected from further editing "
- "and/or frame changes");
+ RNA_def_property_ui_text(prop, "Unlock Color",
+ "Unprotect selected colors from further editing and/or frame changes");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
@@ -1252,13 +1302,13 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_ACTIVE);
RNA_def_property_boolean_funcs(prop, NULL, "rna_GPencilLayer_active_set");
RNA_def_property_ui_text(prop, "Active", "Set active layer for editing");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
#endif
prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_SELECT);
RNA_def_property_ui_text(prop, "Select", "Layer is selected for editing in the Dope Sheet");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ 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);
@@ -1299,7 +1349,7 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "inverse");
RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "MatrixInverse", "Parent inverse transformation matrix");
+ RNA_def_property_ui_text(prop, "Inverse Matrix", "Parent inverse transformation matrix");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* read only parented flag */
@@ -1329,8 +1379,8 @@ static void rna_def_gpencil_layers_api(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_GPencil_layer_new");
RNA_def_function_ui_description(func, "Add a new grease pencil layer");
parm = RNA_def_string(func, "name", "GPencilLayer", MAX_NAME, "Name", "Name of the layer");
- RNA_def_property_flag(parm, PROP_REQUIRED);
- RNA_def_boolean(func, "set_active", 0, "Set Active", "Set the newly created layer to the active layer");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_boolean(func, "set_active", true, "Set Active", "Set the newly created layer to the active layer");
parm = RNA_def_pointer(func, "layer", "GPencilLayer", "", "The newly created layer");
RNA_def_function_return(func, parm);
@@ -1338,22 +1388,23 @@ static void rna_def_gpencil_layers_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a grease pencil layer");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "layer", "GPencilLayer", "", "The layer to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ 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, "GPencilLayer");
RNA_def_property_pointer_funcs(prop, "rna_GPencil_active_layer_get", "rna_GPencil_active_layer_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Active Layer", "Active grease pencil layer");
+ 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_ui_text(prop, "Active Layer Index", "Index of active grease pencil layer");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
}
static void rna_def_gpencil_palettecolor(BlenderRNA *brna)
@@ -1381,8 +1432,9 @@ static void rna_def_gpencil_palettecolor(BlenderRNA *brna)
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Name */
- prop = RNA_def_property(srna, "info", PROP_STRING, PROP_NONE);
- RNA_def_property_ui_text(prop, "Info", "Color name");
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "info");
+ RNA_def_property_ui_text(prop, "Name", "Color name");
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilPaletteColor_info_set");
RNA_def_struct_name_property(srna, prop);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
@@ -1418,7 +1470,7 @@ static void rna_def_gpencil_palettecolor(BlenderRNA *brna)
prop = RNA_def_property(srna, "ghost", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PC_COLOR_ONIONSKIN);
RNA_def_property_ui_icon(prop, ICON_GHOST_ENABLED, 0);
- RNA_def_property_ui_text(prop, "Ghost", "Display the color in onion skinning");
+ RNA_def_property_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 */
@@ -1470,8 +1522,8 @@ static void rna_def_gpencil_palettecolors_api(BlenderRNA *brna, PropertyRNA *cpr
RNA_def_function_ui_description(func, "Remove a color from the palette");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "color", "GPencilPaletteColor", "", "The color to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ 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");
@@ -1495,6 +1547,7 @@ static void rna_def_gpencil_palette(BlenderRNA *brna)
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 */
@@ -1530,8 +1583,8 @@ static void rna_def_gpencil_palettes_api(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_GPencil_palette_new");
RNA_def_function_ui_description(func, "Add a new grease pencil palette");
parm = RNA_def_string(func, "name", "GPencilPalette", MAX_NAME, "Name", "Name of the palette");
- RNA_def_property_flag(parm, PROP_REQUIRED);
- RNA_def_boolean(func, "set_active", 0, "Set Active", "Activate the newly created palette");
+ 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);
@@ -1539,8 +1592,8 @@ static void rna_def_gpencil_palettes_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a grease pencil palette");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "palette", "GPencilPalette", "", "The palette to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ 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");
diff --git a/source/blender/makesrna/intern/rna_group.c b/source/blender/makesrna/intern/rna_group.c
index 47bee589615..2a5a0011279 100644
--- a/source/blender/makesrna/intern/rna_group.c
+++ b/source/blender/makesrna/intern/rna_group.c
@@ -53,9 +53,9 @@ static PointerRNA rna_Group_objects_get(CollectionPropertyIterator *iter)
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)
+static void rna_Group_objects_link(Group *group, ReportList *reports, Object *object)
{
- if (!BKE_group_object_add(group, object, CTX_data_scene(C), NULL)) {
+ if (!BKE_group_object_add(group, object)) {
BKE_reportf(reports, RPT_ERROR, "Object '%s' already in group '%s'", object->id.name + 2, group->id.name + 2);
return;
}
@@ -63,9 +63,9 @@ static void rna_Group_objects_link(Group *group, bContext *C, ReportList *report
WM_main_add_notifier(NC_OBJECT | ND_DRAW, &object->id);
}
-static void rna_Group_objects_unlink(Group *group, bContext *C, ReportList *reports, Object *object)
+static void rna_Group_objects_unlink(Group *group, ReportList *reports, Object *object)
{
- if (!BKE_group_object_unlink(group, object, CTX_data_scene(C), NULL)) {
+ if (!BKE_group_object_unlink(group, object)) {
BKE_reportf(reports, RPT_ERROR, "Object '%s' not in group '%s'", object->id.name + 2, group->id.name + 2);
return;
}
@@ -91,19 +91,19 @@ static void rna_def_group_objects(BlenderRNA *brna, PropertyRNA *cprop)
/* 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_flag(func, 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_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ 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);
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
/* object to remove */
parm = RNA_def_pointer(func, "object", "Object", "", "Object to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index f65aa90ea71..686e830f1ba 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -32,9 +32,10 @@
#include "BLI_utildefines.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"
@@ -104,7 +105,7 @@ static void rna_Image_source_set(PointerRNA *ptr, int value)
if (value != ima->source) {
ima->source = value;
BKE_image_signal(ima, NULL, IMA_SIGNAL_SRC_CHANGE);
- DAG_id_tag_update(&ima->id, 0);
+ DEG_id_tag_update(&ima->id, 0);
}
}
@@ -134,7 +135,7 @@ static void rna_Image_reload_update(Main *UNUSED(bmain), Scene *UNUSED(scene), P
Image *ima = ptr->id.data;
BKE_image_signal(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 *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
@@ -147,7 +148,7 @@ static void rna_Image_colormanage_update(Main *UNUSED(bmain), Scene *UNUSED(scen
{
Image *ima = ptr->id.data;
BKE_image_signal(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);
}
@@ -871,7 +872,7 @@ static void rna_def_image(BlenderRNA *brna)
prop = RNA_def_property(srna, "has_data", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_Image_has_data_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Has data", "True if this image has data");
+ RNA_def_property_ui_text(prop, "Has Data", "True if the image data is loaded into memory");
prop = RNA_def_property(srna, "depth", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_funcs(prop, "rna_Image_depth_get", NULL, NULL);
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index 6530e0938f6..936674a1e96 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"
@@ -251,6 +248,8 @@ static int rna_Image_gl_load(Image *image, ReportList *reports, int frame, int f
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) {
@@ -314,7 +313,7 @@ void RNA_api_image(StructRNA *srna)
RNA_def_function_ui_description(func, "Save image to a specific path using a scenes render settings");
RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
parm = RNA_def_string_file_path(func, "filepath", NULL, 0, "", "Save path");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_pointer(func, "scene", "Scene", "", "Scene to take image parameters from");
func = RNA_def_function(srna, "save", "rna_Image_save");
@@ -346,9 +345,9 @@ void RNA_api_image(StructRNA *srna)
RNA_def_function_ui_description(func, "Scale the image in pixels");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_int(func, "width", 1, 1, 10000, "", "Width", 1, 10000);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "height", 1, 1, 10000, "", "Height", 1, 10000);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "gl_touch", "rna_Image_gl_touch");
RNA_def_function_ui_description(func, "Delay the image from being cleaned from the cache due inactivity");
@@ -372,7 +371,6 @@ void RNA_api_image(StructRNA *srna)
"The texture minifying function", -INT_MAX, INT_MAX);
RNA_def_int(func, "mag", GL_LINEAR, -INT_MAX, INT_MAX, "Magnification",
"The texture magnification function", -INT_MAX, INT_MAX);
-
/* return value */
parm = RNA_def_int(func, "error", 0, -INT_MAX, INT_MAX, "Error", "OpenGL error value", -INT_MAX, INT_MAX);
RNA_def_function_return(func, parm);
@@ -386,7 +384,7 @@ void RNA_api_image(StructRNA *srna)
RNA_def_pointer(func, "image_user", "ImageUser", "", "Image user of the image to get filepath for");
parm = RNA_def_string_file_path(func, "filepath", NULL, FILE_MAX, "File Path",
"The resulting filepath from the image and it's user");
- RNA_def_property_flag(parm, PROP_THICK_WRAP); /* needed for string return value */
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); /* needed for string return value */
RNA_def_function_output(func, parm);
func = RNA_def_function(srna, "buffers_free", "rna_Image_buffers_free");
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 0ae9257e789..90fb7d0dec4 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -167,6 +167,7 @@ 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);
@@ -187,6 +188,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_manipulator(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);
@@ -237,7 +240,7 @@ int rna_object_shapekey_index_set(struct ID *id, PointerRNA value, int current);
/* 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 */
int rna_Armature_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
@@ -268,6 +271,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_manipulator(struct StructRNA *srna);
+void RNA_api_manipulatorgroup(struct StructRNA *srna);
void RNA_api_keyconfig(struct StructRNA *srna);
void RNA_api_keyconfigs(struct StructRNA *srna);
void RNA_api_keyingset(struct StructRNA *srna);
@@ -280,7 +285,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);
@@ -335,6 +340,9 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_cachefiles(BlenderRNA *brna, PropertyRNA *cprop);
+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 */
@@ -344,6 +352,7 @@ extern IntPropertyRNA rna_PropertyGroupItem_int_array;
extern FloatPropertyRNA rna_PropertyGroupItem_float;
extern FloatPropertyRNA rna_PropertyGroupItem_float_array;
extern PointerPropertyRNA rna_PropertyGroupItem_group;
+extern PointerPropertyRNA rna_PropertyGroupItem_id;
extern CollectionPropertyRNA rna_PropertyGroupItem_collection;
extern CollectionPropertyRNA rna_PropertyGroupItem_idp_array;
extern FloatPropertyRNA rna_PropertyGroupItem_double;
@@ -412,6 +421,8 @@ void rna_mtex_texture_slots_clear(struct ID *self, struct bContext *C, struct Re
int rna_IDMaterials_assign_int(struct PointerRNA *ptr, int key, const struct PointerRNA *assign_ptr);
+const char *rna_translate_ui_text(
+ const char *text, const char *text_ctxt, struct StructRNA *type, struct PropertyRNA *prop, int translate);
/* Internal functions that cycles uses so we need to declare (tsk tsk) */
void rna_RenderLayer_rect_set(PointerRNA *ptr, const float *values);
diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h
index ba0705b5caa..c412d110e5e 100644
--- a/source/blender/makesrna/intern/rna_internal_types.h
+++ b/source/blender/makesrna/intern/rna_internal_types.h
@@ -45,15 +45,6 @@ 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"
@@ -62,7 +53,7 @@ struct Scene;
typedef void (*UpdateFunc)(struct Main *main, struct Scene *scene, struct PointerRNA *ptr);
typedef void (*ContextPropUpdateFunc)(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop);
typedef void (*ContextUpdateFunc)(struct bContext *C, struct PointerRNA *ptr);
-typedef int (*EditableFunc)(struct PointerRNA *ptr);
+typedef int (*EditableFunc)(struct PointerRNA *ptr, const char **r_info);
typedef int (*ItemEditableFunc)(struct PointerRNA *ptr, int index);
typedef struct IDProperty *(*IDPropertiesFunc)(struct PointerRNA *ptr, bool create);
typedef struct StructRNA *(*StructRefineFunc)(struct PointerRNA *ptr);
@@ -94,6 +85,7 @@ typedef PointerRNA (*PropPointerGetFunc)(struct PointerRNA *ptr);
typedef StructRNA *(*PropPointerTypeFunc)(struct PointerRNA *ptr);
typedef void (*PropPointerSetFunc)(struct PointerRNA *ptr, const PointerRNA value);
typedef int (*PropPointerPollFunc)(struct PointerRNA *ptr, const PointerRNA value);
+typedef int (*PropPointerPollFuncPy)(struct PointerRNA *ptr, const PointerRNA value, const PropertyRNA *prop);
typedef void (*PropCollectionBeginFunc)(struct CollectionPropertyIterator *iter, struct PointerRNA *ptr);
typedef void (*PropCollectionNextFunc)(struct CollectionPropertyIterator *iter);
typedef void (*PropCollectionEndFunc)(struct CollectionPropertyIterator *iter);
@@ -162,6 +154,10 @@ struct PropertyRNA {
const char *identifier;
/* various options */
int flag;
+ /* Function parameters flags. */
+ short flag_parameter;
+ /* Internal ("private") flags. */
+ short flag_internal;
/* user readable name */
const char *name;
@@ -183,12 +179,14 @@ struct PropertyRNA {
/* array lengths lengths for all dimensions (when arraydimension > 0) */
unsigned int arraylength[RNA_MAX_ARRAY_DIMENSION];
unsigned int totarraylength;
-
+
/* callback for updates on change */
UpdateFunc update;
int noteflag;
- /* callback for testing if editable */
+ /* Callback for testing if editable. Its r_info parameter can be used to
+ * return info on editable state that might be shown to user. E.g. tooltips
+ * of disabled buttons can show reason why button is disabled using this. */
EditableFunc editable;
/* callback for testing if array-item editable (if applicable) */
ItemEditableFunc itemeditable;
@@ -207,6 +205,15 @@ struct PropertyRNA {
void *py_data;
};
+/* internal flags WARNING! 16bits only! */
+typedef enum PropertyFlagIntern {
+ PROP_INTERN_BUILTIN = (1 << 0),
+ PROP_INTERN_RUNTIME = (1 << 1),
+ PROP_INTERN_RAW_ACCESS = (1 << 2),
+ PROP_INTERN_RAW_ARRAY = (1 << 3),
+ PROP_INTERN_FREE_POINTERS = (1 << 4),
+} PropertyFlagIntern;
+
/* Property Types */
typedef struct BoolPropertyRNA {
@@ -345,7 +352,7 @@ struct StructRNA {
* which is useful for subclassing RNA */
void *py_type;
void *blender_type;
-
+
/* various options */
int flag;
@@ -357,7 +364,7 @@ struct StructRNA {
const char *translation_context;
/* icon ID */
int icon;
-
+
/* property that defines the name */
PropertyRNA *nameproperty;
diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c
index 502e22e2c07..5cf7e7238e0 100644
--- a/source/blender/makesrna/intern/rna_key.c
+++ b/source/blender/makesrna/intern/rna_key.c
@@ -33,6 +33,7 @@
#include "DNA_lattice_types.h"
#include "DNA_mesh_types.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -50,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"
@@ -483,7 +485,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);
}
}
@@ -748,7 +750,7 @@ static void rna_def_keyblock(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Compute local space vertices' normals for this shape key");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_property(func, "normals", PROP_FLOAT, /* PROP_DIRECTION */ PROP_NONE);
- RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_OUTPUT);
+ RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_OUTPUT);
RNA_def_property_multi_array(parm, 2, NULL);
RNA_def_property_range(parm, -1.0f, 1.0f);
RNA_def_property_dynamic_array_funcs(parm, "rna_KeyBlock_normals_vert_len");
@@ -757,7 +759,7 @@ static void rna_def_keyblock(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Compute local space faces' normals for this shape key");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_property(func, "normals", PROP_FLOAT, /* PROP_DIRECTION */ PROP_NONE);
- RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_OUTPUT);
+ RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_OUTPUT);
RNA_def_property_multi_array(parm, 2, NULL);
RNA_def_property_range(parm, -1.0f, 1.0f);
RNA_def_property_dynamic_array_funcs(parm, "rna_KeyBlock_normals_poly_len");
@@ -766,7 +768,7 @@ static void rna_def_keyblock(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Compute local space face corners' normals for this shape key");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_property(func, "normals", PROP_FLOAT, /* PROP_DIRECTION */ PROP_NONE);
- RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_OUTPUT);
+ RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_OUTPUT);
RNA_def_property_multi_array(parm, 2, NULL);
RNA_def_property_range(parm, -1.0f, 1.0f);
RNA_def_property_dynamic_array_funcs(parm, "rna_KeyBlock_normals_loop_len");
@@ -797,7 +799,7 @@ static void rna_def_key(BlenderRNA *brna)
prop = RNA_def_property(srna, "user", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "from");
- RNA_def_property_ui_text(prop, "User", "Datablock using these shape keys");
+ RNA_def_property_ui_text(prop, "User", "Data-block using these shape keys");
prop = RNA_def_property(srna, "use_relative", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "type", KEY_RELATIVE);
diff --git a/source/blender/makesrna/intern/rna_lamp.c b/source/blender/makesrna/intern/rna_lamp.c
index e4e3699f301..76f5044a95c 100644
--- a/source/blender/makesrna/intern/rna_lamp.c
+++ b/source/blender/makesrna/intern/rna_lamp.c
@@ -45,10 +45,11 @@
#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"
@@ -134,7 +135,7 @@ static void rna_Lamp_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRN
{
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);
}
@@ -142,7 +143,7 @@ static void rna_Lamp_draw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poin
{
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);
}
@@ -150,7 +151,7 @@ static void rna_Lamp_sky_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Point
{
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_SKY, la);
}
@@ -546,7 +547,7 @@ static void rna_def_lamp_shadow(StructRNA *srna, int spot, int area)
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_update");
+ RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
prop = RNA_def_property(srna, "shadow_buffer_size", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "bufsize");
@@ -587,7 +588,7 @@ static void rna_def_lamp_shadow(StructRNA *srna, int spot, int area)
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_ui_text(prop, "Shadow Buffer Bias", "Bias for reducing self shadowing");
RNA_def_property_update(prop, 0, "rna_Lamp_update");
prop = RNA_def_property(srna, "shadow_buffer_bleed_bias", PROP_FLOAT, PROP_NONE);
@@ -596,6 +597,12 @@ static void rna_def_lamp_shadow(StructRNA *srna, int spot, int area)
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");
+ prop = RNA_def_property(srna, "shadow_buffer_exp", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "bleedexp");
+ 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_Lamp_update");
+
prop = RNA_def_property(srna, "shadow_buffer_soft", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "soft");
RNA_def_property_range(prop, 0.0f, 100.0f);
@@ -722,6 +729,7 @@ static void rna_def_area_lamp(BlenderRNA *brna)
RNA_def_struct_ui_icon(srna, ICON_LAMP_AREA);
rna_def_lamp_shadow(srna, 0, 1);
+ rna_def_lamp_falloff(srna);
prop = RNA_def_property(srna, "use_umbra", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "ray_samp_type", LA_SAMP_UMBRA);
diff --git a/source/blender/makesrna/intern/rna_lattice.c b/source/blender/makesrna/intern/rna_lattice.c
index 6bc9cc38a7d..904a6289fc1 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);
}
@@ -171,7 +172,7 @@ static void rna_Lattice_use_outside_set(PointerRNA *ptr, int value)
}
}
-static int rna_Lattice_size_editable(PointerRNA *ptr)
+static int rna_Lattice_size_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
Lattice *lt = (Lattice *)ptr->data;
diff --git a/source/blender/makesrna/intern/rna_lattice_api.c b/source/blender/makesrna/intern/rna_lattice_api.c
index ed0489db1a2..5637f8d9248 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, int 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(lt, BKE_LATTICE_BATCH_DIRTY_ALL);
+}
+
#else
void RNA_api_lattice(StructRNA *srna)
@@ -57,8 +63,10 @@ void RNA_api_lattice(StructRNA *srna)
func = RNA_def_function(srna, "transform", "rna_Lattice_transform");
RNA_def_function_ui_description(func, "Transform lattice by a matrix");
parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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_lightprobe.c b/source/blender/makesrna/intern/rna_lightprobe.c
new file mode 100644
index 00000000000..a628dade59b
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_lightprobe.c
@@ -0,0 +1,188 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "DNA_object_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_main.h"
+#include "DEG_depsgraph.h"
+
+#include "DNA_object_types.h"
+
+#include "WM_api.h"
+#include "WM_types.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_NONE, "Reflection Cubemap", "Capture reflections"},
+ {LIGHTPROBE_TYPE_PLANAR, "PLANAR", ICON_NONE, "Reflection Plane", ""},
+ {LIGHTPROBE_TYPE_GRID, "GRID", ICON_NONE, "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_RADIO);
+
+ 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_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_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 parallax 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_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_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_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_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_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_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");
+
+ /* 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 debuging purpose");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, NULL);
+
+ prop = RNA_def_property(srna, "data_draw_size", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.05f, 10.0f);
+ RNA_def_property_ui_text(prop, "Data Draw Size", "Size of the spheres to debug captured light");
+ 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 d8cc61bf906..13d655f81bf 100644
--- a/source/blender/makesrna/intern/rna_linestyle.c
+++ b/source/blender/makesrna/intern/rna_linestyle.c
@@ -27,6 +27,9 @@
#include <stdio.h>
#include <stdlib.h>
+#include "BLI_utildefines.h"
+#include "BLI_string_utils.h"
+
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -98,7 +101,8 @@ 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"
@@ -320,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);
}
@@ -344,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;
@@ -362,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);
}
@@ -376,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;
@@ -394,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);
}
@@ -408,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;
@@ -426,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);
}
@@ -440,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;
@@ -458,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);
}
@@ -1447,9 +1451,9 @@ static void rna_def_freestyle_color_modifiers(BlenderRNA *brna, PropertyRNA *cpr
RNA_def_function_ui_description(func, "Add a color modifier to line style");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "name", "ColorModifier", 0, "", "New name for the color modifier (not unique)");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "type", rna_enum_linestyle_color_modifier_type_items, 0, "", "Color modifier type to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "modifier", "LineStyleColorModifier", "", "Newly added color modifier");
RNA_def_function_return(func, parm);
@@ -1457,8 +1461,8 @@ static void rna_def_freestyle_color_modifiers(BlenderRNA *brna, PropertyRNA *cpr
RNA_def_function_ui_description(func, "Remove a color modifier from line style");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "modifier", "LineStyleColorModifier", "", "Color modifier to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_freestyle_alpha_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
@@ -1476,9 +1480,9 @@ static void rna_def_freestyle_alpha_modifiers(BlenderRNA *brna, PropertyRNA *cpr
RNA_def_function_ui_description(func, "Add a alpha modifier to line style");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "name", "AlphaModifier", 0, "", "New name for the alpha modifier (not unique)");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "type", rna_enum_linestyle_alpha_modifier_type_items, 0, "", "Alpha modifier type to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "modifier", "LineStyleAlphaModifier", "", "Newly added alpha modifier");
RNA_def_function_return(func, parm);
@@ -1486,8 +1490,8 @@ static void rna_def_freestyle_alpha_modifiers(BlenderRNA *brna, PropertyRNA *cpr
RNA_def_function_ui_description(func, "Remove a alpha modifier from line style");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "modifier", "LineStyleAlphaModifier", "", "Alpha modifier to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_freestyle_thickness_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
@@ -1499,15 +1503,16 @@ static void rna_def_freestyle_thickness_modifiers(BlenderRNA *brna, PropertyRNA
RNA_def_property_srna(cprop, "LineStyleThicknessModifiers");
srna = RNA_def_struct(brna, "LineStyleThicknessModifiers", NULL);
RNA_def_struct_sdna(srna, "FreestyleLineStyle");
- RNA_def_struct_ui_text(srna, "Thickness Modifiers", "Thickness modifiers for changing line thicknesss");
+ RNA_def_struct_ui_text(srna, "Thickness Modifiers", "Thickness modifiers for changing line thickness");
func = RNA_def_function(srna, "new", "rna_LineStyle_thickness_modifier_add");
RNA_def_function_ui_description(func, "Add a thickness modifier to line style");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "name", "ThicknessModifier", 0, "", "New name for the thickness modifier (not unique)");
- RNA_def_property_flag(parm, PROP_REQUIRED);
- parm = RNA_def_enum(func, "type", rna_enum_linestyle_thickness_modifier_type_items, 0, "", "Thickness modifier type to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_enum(func, "type", rna_enum_linestyle_thickness_modifier_type_items, 0,
+ "", "Thickness modifier type to add");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "modifier", "LineStyleThicknessModifier", "", "Newly added thickness modifier");
RNA_def_function_return(func, parm);
@@ -1515,8 +1520,8 @@ static void rna_def_freestyle_thickness_modifiers(BlenderRNA *brna, PropertyRNA
RNA_def_function_ui_description(func, "Remove a thickness modifier from line style");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "modifier", "LineStyleThicknessModifier", "", "Thickness modifier to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_freestyle_geometry_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
@@ -1528,15 +1533,16 @@ static void rna_def_freestyle_geometry_modifiers(BlenderRNA *brna, PropertyRNA *
RNA_def_property_srna(cprop, "LineStyleGeometryModifiers");
srna = RNA_def_struct(brna, "LineStyleGeometryModifiers", NULL);
RNA_def_struct_sdna(srna, "FreestyleLineStyle");
- RNA_def_struct_ui_text(srna, "Geometry Modifiers", "Geometry modifiers for changing line geometrys");
+ RNA_def_struct_ui_text(srna, "Geometry Modifiers", "Geometry modifiers for changing line geometries");
func = RNA_def_function(srna, "new", "rna_LineStyle_geometry_modifier_add");
RNA_def_function_ui_description(func, "Add a geometry modifier to line style");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "name", "GeometryModifier", 0, "", "New name for the geometry modifier (not unique)");
- RNA_def_property_flag(parm, PROP_REQUIRED);
- parm = RNA_def_enum(func, "type", rna_enum_linestyle_geometry_modifier_type_items, 0, "", "Geometry modifier type to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_enum(func, "type", rna_enum_linestyle_geometry_modifier_type_items, 0,
+ "", "Geometry modifier type to add");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "modifier", "LineStyleGeometryModifier", "", "Newly added geometry modifier");
RNA_def_function_return(func, parm);
@@ -1544,8 +1550,8 @@ static void rna_def_freestyle_geometry_modifiers(BlenderRNA *brna, PropertyRNA *
RNA_def_function_ui_description(func, "Remove a geometry modifier from line style");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "modifier", "LineStyleGeometryModifier", "", "Geometry modifier to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_linestyle(BlenderRNA *brna)
@@ -1615,6 +1621,7 @@ static void rna_def_linestyle(BlenderRNA *brna)
prop = RNA_def_property(srna, "panel", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "panel");
RNA_def_property_enum_items(prop, panel_items);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Panel", "Select the property panel to be shown");
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c
index 3392d0d9b3a..6479826b7b3 100644
--- a/source/blender/makesrna/intern/rna_main.c
+++ b/source/blender/makesrna/intern/rna_main.c
@@ -287,6 +287,24 @@ static void rna_Main_cachefiles_begin(CollectionPropertyIterator *iter, PointerR
rna_iterator_listbase_begin(iter, &bmain->cachefiles, NULL);
}
+static void rna_Main_paintcurves_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Main *bmain = (Main *)ptr->data;
+ 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 void rna_Main_version_get(PointerRNA *ptr, int *value)
{
Main *bmain = (Main *)ptr->data;
@@ -329,38 +347,41 @@ void RNA_def_main(BlenderRNA *brna)
/* plural must match idtypes in readblenentry.c */
MainCollectionDef lists[] = {
- {"cameras", "Camera", "rna_Main_camera_begin", "Cameras", "Camera datablocks", RNA_def_main_cameras},
- {"scenes", "Scene", "rna_Main_scene_begin", "Scenes", "Scene datablocks", RNA_def_main_scenes},
- {"objects", "Object", "rna_Main_object_begin", "Objects", "Object datablocks", RNA_def_main_objects},
- {"materials", "Material", "rna_Main_mat_begin", "Materials", "Material datablocks", RNA_def_main_materials},
- {"node_groups", "NodeTree", "rna_Main_nodetree_begin", "Node Groups", "Node group datablocks", RNA_def_main_node_groups},
- {"meshes", "Mesh", "rna_Main_mesh_begin", "Meshes", "Mesh datablocks", RNA_def_main_meshes},
- {"lamps", "Lamp", "rna_Main_lamp_begin", "Lamps", "Lamp datablocks", RNA_def_main_lamps},
- {"libraries", "Library", "rna_Main_library_begin", "Libraries", "Library datablocks", RNA_def_main_libraries},
- {"screens", "Screen", "rna_Main_screen_begin", "Screens", "Screen datablocks", RNA_def_main_screens},
- {"window_managers", "WindowManager", "rna_Main_wm_begin", "Window Managers", "Window manager datablocks", RNA_def_main_window_managers},
- {"images", "Image", "rna_Main_image_begin", "Images", "Image datablocks", RNA_def_main_images},
- {"lattices", "Lattice", "rna_Main_latt_begin", "Lattices", "Lattice datablocks", RNA_def_main_lattices},
- {"curves", "Curve", "rna_Main_curve_begin", "Curves", "Curve datablocks", RNA_def_main_curves},
- {"metaballs", "MetaBall", "rna_Main_mball_begin", "Metaballs", "Metaball datablocks", RNA_def_main_metaballs},
- {"fonts", "VectorFont", "rna_Main_font_begin", "Vector Fonts", "Vector font datablocks", RNA_def_main_fonts},
- {"textures", "Texture", "rna_Main_tex_begin", "Textures", "Texture datablocks", RNA_def_main_textures},
- {"brushes", "Brush", "rna_Main_brush_begin", "Brushes", "Brush datablocks", RNA_def_main_brushes},
- {"worlds", "World", "rna_Main_world_begin", "Worlds", "World datablocks", RNA_def_main_worlds},
- {"groups", "Group", "rna_Main_group_begin", "Groups", "Group datablocks", RNA_def_main_groups},
- {"shape_keys", "Key", "rna_Main_key_begin", "Shape Keys", "Shape Key datablocks", NULL},
- {"texts", "Text", "rna_Main_text_begin", "Texts", "Text datablocks", RNA_def_main_texts},
- {"speakers", "Speaker", "rna_Main_speaker_begin", "Speakers", "Speaker datablocks", RNA_def_main_speakers},
- {"sounds", "Sound", "rna_Main_sound_begin", "Sounds", "Sound datablocks", RNA_def_main_sounds},
- {"armatures", "Armature", "rna_Main_armature_begin", "Armatures", "Armature datablocks", RNA_def_main_armatures},
- {"actions", "Action", "rna_Main_action_begin", "Actions", "Action datablocks", RNA_def_main_actions},
- {"particles", "ParticleSettings", "rna_Main_particle_begin", "Particles", "Particle datablocks", RNA_def_main_particles},
- {"palettes", "Palette", "rna_Main_palettes_begin", "Palettes", "Palette datablocks", RNA_def_main_palettes},
- {"grease_pencil", "GreasePencil", "rna_Main_gpencil_begin", "Grease Pencil", "Grease Pencil datablocks", RNA_def_main_gpencil},
- {"movieclips", "MovieClip", "rna_Main_movieclips_begin", "Movie Clips", "Movie Clip datablocks", RNA_def_main_movieclips},
- {"masks", "Mask", "rna_Main_masks_begin", "Masks", "Masks datablocks", RNA_def_main_masks},
- {"linestyles", "FreestyleLineStyle", "rna_Main_linestyle_begin", "Line Styles", "Line Style datablocks", RNA_def_main_linestyles},
- {"cache_files", "CacheFile", "rna_Main_cachefiles_begin", "Cache Files", "Cache Files datablocks", RNA_def_main_cachefiles},
+ {"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},
+ {"workspaces", "WorkSpace", "rna_Main_workspaces_begin", "Workspaces", "Workspace data-blocks", RNA_def_main_workspaces},
+ {"lightprobes", "LightProbe", "rna_Main_lightprobes_begin", "LightProbes", "LightProbe data-blocks", RNA_def_main_lightprobes},
{NULL, NULL, NULL, NULL, NULL, NULL}
};
@@ -368,7 +389,7 @@ void RNA_def_main(BlenderRNA *brna)
srna = RNA_def_struct(brna, "BlendData", NULL);
RNA_def_struct_ui_text(srna, "Blendfile Data",
- "Main data structure representing a .blend file and all its datablocks");
+ "Main data structure representing a .blend file and all its data-blocks");
RNA_def_struct_ui_icon(srna, ICON_BLENDER);
prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
@@ -392,7 +413,7 @@ void RNA_def_main(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Use Autopack", "Automatically pack all external data into .blend file");
prop = RNA_def_int_vector(srna, "version", 3, NULL, 0, INT_MAX,
- "Version", "Version of the blender the .blend was saved with", 0, INT_MAX);
+ "Version", "Version of Blender the .blend was saved with", 0, INT_MAX);
RNA_def_property_int_funcs(prop, "rna_Main_version_get", NULL, NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_flag(prop, PROP_THICK_WRAP);
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index 7c627e72fd5..5b898d7fd40 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -78,12 +78,15 @@
#include "BKE_paint.h"
#include "BKE_font.h"
#include "BKE_node.h"
-#include "BKE_depsgraph.h"
#include "BKE_speaker.h"
+#include "BKE_lightprobe.h"
#include "BKE_movieclip.h"
#include "BKE_mask.h"
#include "BKE_gpencil.h"
#include "BKE_linestyle.h"
+#include "BKE_workspace.h"
+
+#include "DEG_depsgraph_query.h"
#include "DNA_armature_types.h"
#include "DNA_camera_types.h"
@@ -93,6 +96,7 @@
#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"
@@ -115,6 +119,15 @@
# include "BPY_extern.h"
#endif
+#include "WM_api.h"
+
+
+static void rna_idname_validate(const char *name, char *r_name)
+{
+ BLI_strncpy(r_name, name, MAX_ID_NAME - 2);
+ BLI_utf8_invalid_strip(r_name, strlen(r_name));
+}
+
static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_ptr, int do_unlink)
{
@@ -137,14 +150,20 @@ static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_
static Camera *rna_Main_cameras_new(Main *bmain, const char *name)
{
- ID *id = BKE_camera_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ ID *id = BKE_camera_add(bmain, safe_name);
id_us_min(id);
return (Camera *)id;
}
static Scene *rna_Main_scenes_new(Main *bmain, const char *name)
{
- return BKE_scene_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ return BKE_scene_add(bmain, safe_name);
}
static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports, PointerRNA *scene_ptr, int do_unlink)
{
@@ -156,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_change_active_scene(bmain, C, win, scene_new);
#ifdef WITH_PYTHON
BPy_END_ALLOW_THREADS;
@@ -180,6 +200,9 @@ static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports
static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char *name, ID *data)
{
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
Object *ob;
int type = OB_EMPTY;
if (data) {
@@ -223,7 +246,7 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char
id_us_plus(data);
}
- ob = BKE_object_add_only_object(bmain, type, name);
+ ob = BKE_object_add_only_object(bmain, type, safe_name);
id_us_min(&ob->id);
ob->data = data;
@@ -234,7 +257,10 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char
static Material *rna_Main_materials_new(Main *bmain, const char *name)
{
- ID *id = (ID *)BKE_material_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ ID *id = (ID *)BKE_material_add(bmain, safe_name);
id_us_min(id);
return (Material *)id;
}
@@ -245,20 +271,27 @@ static EnumPropertyItem *rna_Main_nodetree_type_itemf(bContext *UNUSED(C), Point
}
static struct bNodeTree *rna_Main_nodetree_new(Main *bmain, const char *name, int type)
{
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
bNodeTreeType *typeinfo = rna_node_tree_type_from_enum(type);
if (typeinfo) {
- bNodeTree *ntree = ntreeAddTree(bmain, name, typeinfo->idname);
+ bNodeTree *ntree = ntreeAddTree(bmain, safe_name, typeinfo->idname);
id_us_min(&ntree->id);
return ntree;
}
- else
+ else {
return NULL;
+ }
}
static Mesh *rna_Main_meshes_new(Main *bmain, const char *name)
{
- Mesh *me = BKE_mesh_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ Mesh *me = BKE_mesh_add(bmain, safe_name);
id_us_min(&me->id);
return me;
}
@@ -286,7 +319,10 @@ Mesh *rna_Main_meshes_new_from_object(
static Lamp *rna_Main_lamps_new(Main *bmain, const char *name, int type)
{
- Lamp *lamp = BKE_lamp_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ Lamp *lamp = BKE_lamp_add(bmain, safe_name);
lamp->type = type;
id_us_min(&lamp->id);
return lamp;
@@ -294,8 +330,11 @@ static Lamp *rna_Main_lamps_new(Main *bmain, const char *name, int type)
static Image *rna_Main_images_new(Main *bmain, const char *name, int width, int height, int alpha, int float_buffer, int stereo3d)
{
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
float color[4] = {0.0, 0.0, 0.0, 1.0};
- Image *image = BKE_image_add_generated(bmain, width, height, name, alpha ? 32 : 24, float_buffer, 0, color, stereo3d);
+ Image *image = BKE_image_add_generated(bmain, width, height, safe_name, alpha ? 32 : 24, float_buffer, 0, color, stereo3d);
id_us_min(&image->id);
return image;
}
@@ -322,21 +361,30 @@ static Image *rna_Main_images_load(Main *bmain, ReportList *reports, const char
static Lattice *rna_Main_lattices_new(Main *bmain, const char *name)
{
- Lattice *lt = BKE_lattice_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ Lattice *lt = BKE_lattice_add(bmain, safe_name);
id_us_min(&lt->id);
return lt;
}
static Curve *rna_Main_curves_new(Main *bmain, const char *name, int type)
{
- Curve *cu = BKE_curve_add(bmain, name, type);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ Curve *cu = BKE_curve_add(bmain, safe_name, type);
id_us_min(&cu->id);
return cu;
}
static MetaBall *rna_Main_metaballs_new(Main *bmain, const char *name)
{
- MetaBall *mb = BKE_mball_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ MetaBall *mb = BKE_mball_add(bmain, safe_name);
id_us_min(&mb->id);
return mb;
}
@@ -364,7 +412,10 @@ static VFont *rna_Main_fonts_load(Main *bmain, ReportList *reports, const char *
static Tex *rna_Main_textures_new(Main *bmain, const char *name, int type)
{
- Tex *tex = BKE_texture_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ Tex *tex = BKE_texture_add(bmain, safe_name);
BKE_texture_type_set(tex, type);
id_us_min(&tex->id);
return tex;
@@ -372,26 +423,38 @@ static Tex *rna_Main_textures_new(Main *bmain, const char *name, int type)
static Brush *rna_Main_brushes_new(Main *bmain, const char *name, int mode)
{
- Brush *brush = BKE_brush_add(bmain, name, mode);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ Brush *brush = BKE_brush_add(bmain, safe_name, mode);
id_us_min(&brush->id);
return brush;
}
static World *rna_Main_worlds_new(Main *bmain, const char *name)
{
- World *world = add_world(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ World *world = add_world(bmain, safe_name);
id_us_min(&world->id);
return world;
}
static Group *rna_Main_groups_new(Main *bmain, const char *name)
{
- return BKE_group_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ return BKE_group_add(bmain, safe_name);
}
static Speaker *rna_Main_speakers_new(Main *bmain, const char *name)
{
- Speaker *speaker = BKE_speaker_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ Speaker *speaker = BKE_speaker_add(bmain, safe_name);
id_us_min(&speaker->id);
return speaker;
}
@@ -413,7 +476,10 @@ static bSound *rna_Main_sounds_load(Main *bmain, const char *name, int check_exi
static Text *rna_Main_texts_new(Main *bmain, const char *name)
{
- return BKE_text_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ return BKE_text_add(bmain, safe_name);
}
static Text *rna_Main_texts_load(Main *bmain, ReportList *reports, const char *filepath, int is_internal)
@@ -432,28 +498,40 @@ static Text *rna_Main_texts_load(Main *bmain, ReportList *reports, const char *f
static bArmature *rna_Main_armatures_new(Main *bmain, const char *name)
{
- bArmature *arm = BKE_armature_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ bArmature *arm = BKE_armature_add(bmain, safe_name);
id_us_min(&arm->id);
return arm;
}
static bAction *rna_Main_actions_new(Main *bmain, const char *name)
{
- bAction *act = add_empty_action(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ bAction *act = add_empty_action(bmain, safe_name);
id_fake_user_clear(&act->id);
return act;
}
static ParticleSettings *rna_Main_particles_new(Main *bmain, const char *name)
{
- ParticleSettings *part = psys_new_settings(name, bmain);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ ParticleSettings *part = psys_new_settings(safe_name, bmain);
id_us_min(&part->id);
return part;
}
static Palette *rna_Main_palettes_new(Main *bmain, const char *name)
{
- Palette *palette = BKE_palette_add(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ Palette *palette = BKE_palette_add(bmain, safe_name);
id_us_min(&palette->id);
return (Palette *)palette;
}
@@ -481,27 +559,39 @@ static MovieClip *rna_Main_movieclip_load(Main *bmain, ReportList *reports, cons
static Mask *rna_Main_mask_new(Main *bmain, const char *name)
{
- Mask *mask;
-
- mask = BKE_mask_new(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
- return mask;
+ return BKE_mask_new(bmain, safe_name);
}
static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name)
{
- FreestyleLineStyle *linestyle = BKE_linestyle_new(bmain, name);
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ FreestyleLineStyle *linestyle = BKE_linestyle_new(bmain, safe_name);
id_us_min(&linestyle->id);
return linestyle;
}
+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 and is_updated 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, int value) { \
BKE_main_id_tag_listbase(&bmain->_listbase_name, LIB_TAG_DOIT, value); \
} \
static int rna_Main_##_func_name##_is_updated_get(PointerRNA *ptr) { \
- return DAG_id_type_tagged(ptr->data, _id_type) != 0; \
+ return DEG_id_type_tagged(ptr->data, _id_type) != 0; \
}
RNA_MAIN_ID_TAG_FUNCS_DEF(cameras, camera, ID_CA)
@@ -536,6 +626,9 @@ RNA_MAIN_ID_TAG_FUNCS_DEF(movieclips, movieclip, ID_MC)
RNA_MAIN_ID_TAG_FUNCS_DEF(masks, mask, ID_MSK)
RNA_MAIN_ID_TAG_FUNCS_DEF(linestyle, linestyle, ID_LS)
RNA_MAIN_ID_TAG_FUNCS_DEF(cachefiles, cachefiles, ID_CF)
+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
@@ -552,7 +645,7 @@ void RNA_api_main(StructRNA *UNUSED(srna))
func = RNA_def_function(srna, "add_image", "rna_Main_add_image");
RNA_def_function_ui_description(func, "Add a new image");
parm = RNA_def_string_file_path(func, "filepath", NULL, 0, "", "File path to load image from");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "image", "Image", "", "New image");
RNA_def_function_return(func, parm);
#endif
@@ -573,7 +666,7 @@ void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_cameras_new");
RNA_def_function_ui_description(func, "Add a new camera to the main database");
parm = RNA_def_string(func, "name", "Camera", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "camera", "Camera", "", "New camera data-block");
RNA_def_function_return(func, parm);
@@ -582,15 +675,15 @@ void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a camera from the current blendfile");
parm = RNA_def_pointer(func, "camera", "Camera", "", "Camera to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "",
+ 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 camera before deleting it "
"(WARNING: will also delete objects instancing that camera data)");
func = RNA_def_function(srna, "tag", "rna_Main_cameras_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -612,7 +705,7 @@ void RNA_def_main_scenes(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_scenes_new");
RNA_def_function_ui_description(func, "Add a new scene to the main database");
parm = RNA_def_string(func, "name", "Scene", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "scene", "Scene", "", "New scene data-block");
RNA_def_function_return(func, parm);
@@ -621,13 +714,13 @@ void RNA_def_main_scenes(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a scene from the current blendfile");
parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this scene before deleting it");
+ 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 scene before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_scenes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -650,9 +743,9 @@ void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Add a new object to the main database");
parm = RNA_def_string(func, "name", "Object", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "object_data", "ID", "", "Object data or None for an empty object");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "object", "Object", "", "New object data-block");
@@ -662,13 +755,13 @@ void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a object from the current blendfile");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "object", "Object", "", "Object to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this object before deleting it");
+ 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 object before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_objects_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -690,7 +783,7 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_materials_new");
RNA_def_function_ui_description(func, "Add a new material to the main database");
parm = RNA_def_string(func, "name", "Material", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "material", "Material", "", "New material data-block");
RNA_def_function_return(func, parm);
@@ -699,13 +792,13 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a material from the current blendfile");
parm = RNA_def_pointer(func, "material", "Material", "", "Material to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this material before deleting it");
+ 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 material before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_materials_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -731,10 +824,10 @@ void RNA_def_main_node_groups(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_nodetree_new");
RNA_def_function_ui_description(func, "Add a new node tree to the main database");
parm = RNA_def_string(func, "name", "NodeGroup", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "type", dummy_items, 0, "Type", "The type of node_group to add");
RNA_def_property_enum_funcs(parm, NULL, NULL, "rna_Main_nodetree_type_itemf");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "tree", "NodeTree", "", "New node tree data-block");
RNA_def_function_return(func, parm);
@@ -743,13 +836,13 @@ void RNA_def_main_node_groups(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a node tree from the current blendfile");
parm = RNA_def_pointer(func, "tree", "NodeTree", "", "Node tree to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this node tree before deleting it");
+ 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 node tree before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_node_groups_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -776,7 +869,7 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_meshes_new");
RNA_def_function_ui_description(func, "Add a new mesh to the main database");
parm = RNA_def_string(func, "name", "Mesh", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "mesh", "Mesh", "", "New mesh data-block");
RNA_def_function_return(func, parm);
@@ -785,13 +878,13 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop)
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");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_pointer(func, "object", "Object", "", "Object to create mesh from");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_boolean(func, "apply_modifiers", 0, "", "Apply modifiers");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Modifier settings to apply");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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", "",
@@ -802,15 +895,15 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a mesh from the current blendfile");
parm = RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "",
+ 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 mesh before deleting it "
"(WARNING: will also delete objects instancing that mesh data)");
func = RNA_def_function(srna, "tag", "rna_Main_meshes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -831,9 +924,9 @@ void RNA_def_main_lamps(BlenderRNA *brna, PropertyRNA *cprop)
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");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "lamp", "Lamp", "", "New lamp data-block");
RNA_def_function_return(func, parm);
@@ -842,15 +935,15 @@ void RNA_def_main_lamps(BlenderRNA *brna, PropertyRNA *cprop)
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_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "",
+ 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)");
func = RNA_def_function(srna, "tag", "rna_Main_lamps_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -871,7 +964,7 @@ 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_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -892,7 +985,7 @@ 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_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -913,7 +1006,7 @@ 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_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -934,11 +1027,11 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_images_new");
RNA_def_function_ui_description(func, "Add a new image to the main database");
parm = RNA_def_string(func, "name", "Image", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "width", 1024, 1, INT_MAX, "", "Width of the image", 1, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "height", 1024, 1, INT_MAX, "", "Height of the image", 1, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "alpha", 0, "Alpha", "Use alpha channel");
RNA_def_boolean(func, "float_buffer", 0, "Float Buffer", "Create an image with floating point color");
RNA_def_boolean(func, "stereo3d", 0, "Stereo 3D", "Create left and right views");
@@ -950,7 +1043,7 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Load a new image into the main database");
parm = RNA_def_string_file_path(func, "filepath", "File Path", 0, "", "path of the file to load");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "check_existing", false, "", "Using existing data-block if this file is already loaded");
/* return type */
parm = RNA_def_pointer(func, "image", "Image", "", "New image data-block");
@@ -960,13 +1053,13 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove an image from the current blendfile");
parm = RNA_def_pointer(func, "image", "Image", "", "Image to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this image before deleting it");
+ 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 image before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_images_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -988,7 +1081,7 @@ void RNA_def_main_lattices(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_lattices_new");
RNA_def_function_ui_description(func, "Add a new lattice to the main database");
parm = RNA_def_string(func, "name", "Lattice", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "lattice", "Lattice", "", "New lattices data-block");
RNA_def_function_return(func, parm);
@@ -997,15 +1090,15 @@ void RNA_def_main_lattices(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a lattice from the current blendfile");
parm = RNA_def_pointer(func, "lattice", "Lattice", "", "Lattice to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "",
+ 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 lattice before deleting it "
"(WARNING: will also delete objects instancing that lattice data)");
func = RNA_def_function(srna, "tag", "rna_Main_lattices_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -1026,9 +1119,9 @@ void RNA_def_main_curves(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_curves_new");
RNA_def_function_ui_description(func, "Add a new curve to the main database");
parm = RNA_def_string(func, "name", "Curve", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "type", rna_enum_object_type_curve_items, 0, "Type", "The type of curve to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "curve", "Curve", "", "New curve data-block");
RNA_def_function_return(func, parm);
@@ -1037,15 +1130,15 @@ void RNA_def_main_curves(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a curve from the current blendfile");
parm = RNA_def_pointer(func, "curve", "Curve", "", "Curve to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "",
+ 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 curve before deleting it "
"(WARNING: will also delete objects instancing that curve data)");
func = RNA_def_function(srna, "tag", "rna_Main_curves_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -1066,7 +1159,7 @@ void RNA_def_main_metaballs(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_metaballs_new");
RNA_def_function_ui_description(func, "Add a new metaball to the main database");
parm = RNA_def_string(func, "name", "MetaBall", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "metaball", "MetaBall", "", "New metaball data-block");
RNA_def_function_return(func, parm);
@@ -1075,15 +1168,15 @@ void RNA_def_main_metaballs(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a metaball from the current blendfile");
parm = RNA_def_pointer(func, "metaball", "MetaBall", "", "Metaball to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "",
+ 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 metaball before deleting it "
"(WARNING: will also delete objects instancing that metaball data)");
func = RNA_def_function(srna, "tag", "rna_Main_metaballs_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -1105,7 +1198,7 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Load a new font into the main database");
parm = RNA_def_string_file_path(func, "filepath", "File Path", 0, "", "path of the font to load");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "check_existing", false, "", "Using existing data-block if this file is already loaded");
/* return type */
parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "New font data-block");
@@ -1115,13 +1208,13 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a font from the current blendfile");
parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "Font to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this font before deleting it");
+ 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 font before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_fonts_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -1142,9 +1235,9 @@ void RNA_def_main_textures(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_textures_new");
RNA_def_function_ui_description(func, "Add a new texture to the main database");
parm = RNA_def_string(func, "name", "Texture", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "type", rna_enum_texture_type_items, 0, "Type", "The type of texture to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "texture", "Texture", "", "New texture data-block");
RNA_def_function_return(func, parm);
@@ -1153,13 +1246,13 @@ void RNA_def_main_textures(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a texture from the current blendfile");
parm = RNA_def_pointer(func, "texture", "Texture", "", "Texture to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this texture before deleting it");
+ 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 texture before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_textures_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -1180,7 +1273,7 @@ void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_brushes_new");
RNA_def_function_ui_description(func, "Add a new brush to the main database");
parm = RNA_def_string(func, "name", "Brush", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "mode", rna_enum_object_mode_items, OB_MODE_TEXTURE_PAINT, "", "Paint Mode for the new brush");
/* return type */
parm = RNA_def_pointer(func, "brush", "Brush", "", "New brush data-block");
@@ -1190,13 +1283,13 @@ void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a brush from the current blendfile");
parm = RNA_def_pointer(func, "brush", "Brush", "", "Brush to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this brush before deleting it");
+ 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 brush before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_brushes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -1218,7 +1311,7 @@ void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_worlds_new");
RNA_def_function_ui_description(func, "Add a new world to the main database");
parm = RNA_def_string(func, "name", "World", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "world", "World", "", "New world data-block");
RNA_def_function_return(func, parm);
@@ -1227,13 +1320,13 @@ void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a world from the current blendfile");
parm = RNA_def_pointer(func, "world", "World", "", "World to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this world before deleting it");
+ 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 world before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_worlds_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -1255,7 +1348,7 @@ void RNA_def_main_groups(BlenderRNA *brna, PropertyRNA *cprop)
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");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "group", "Group", "", "New group data-block");
RNA_def_function_return(func, parm);
@@ -1264,13 +1357,13 @@ void RNA_def_main_groups(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a group from the current blendfile");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "group", "Group", "", "Group to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this group before deleting it");
+ 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");
func = RNA_def_function(srna, "tag", "rna_Main_groups_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -1292,7 +1385,7 @@ void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_speakers_new");
RNA_def_function_ui_description(func, "Add a new speaker to the main database");
parm = RNA_def_string(func, "name", "Speaker", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "speaker", "Speaker", "", "New speaker data-block");
RNA_def_function_return(func, parm);
@@ -1301,15 +1394,15 @@ void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a speaker from the current blendfile");
parm = RNA_def_pointer(func, "speaker", "Speaker", "", "Speaker to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "",
+ 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 speaker before deleting it "
"(WARNING: will also delete objects instancing that speaker data)");
func = RNA_def_function(srna, "tag", "rna_Main_speakers_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -1331,7 +1424,7 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_texts_new");
RNA_def_function_ui_description(func, "Add a new text to the main database");
parm = RNA_def_string(func, "name", "Text", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "text", "Text", "", "New text data-block");
RNA_def_function_return(func, parm);
@@ -1340,16 +1433,16 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a text from the current blendfile");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "text", "Text", "", "Text to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this text before deleting it");
+ 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 text before deleting it");
/* load func */
func = RNA_def_function(srna, "load", "rna_Main_texts_load");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Add a new text to the main database from a file");
parm = RNA_def_string_file_path(func, "filepath", "Path", FILE_MAX, "", "path for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_boolean(func, "internal", 0, "Make internal", "Make text file internal after loading");
/* return type */
parm = RNA_def_pointer(func, "text", "Text", "", "New text data-block");
@@ -1357,7 +1450,7 @@ 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_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -1380,7 +1473,7 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "load", "rna_Main_sounds_load");
RNA_def_function_ui_description(func, "Add a new sound to the main database from a file");
parm = RNA_def_string_file_path(func, "filepath", "Path", FILE_MAX, "", "path for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "check_existing", false, "", "Using existing data-block if this file is already loaded");
/* return type */
parm = RNA_def_pointer(func, "sound", "Sound", "", "New text data-block");
@@ -1390,13 +1483,13 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a sound from the current blendfile");
parm = RNA_def_pointer(func, "sound", "Sound", "", "Sound to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this sound before deleting it");
+ 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 sound before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_sounds_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -1418,7 +1511,7 @@ void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_armatures_new");
RNA_def_function_ui_description(func, "Add a new armature to the main database");
parm = RNA_def_string(func, "name", "Armature", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "armature", "Armature", "", "New armature data-block");
RNA_def_function_return(func, parm);
@@ -1427,15 +1520,15 @@ void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a armature from the current blendfile");
parm = RNA_def_pointer(func, "armature", "Armature", "", "Armature to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "",
+ 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 armature before deleting it "
"(WARNING: will also delete objects instancing that armature data)");
func = RNA_def_function(srna, "tag", "rna_Main_armatures_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -1456,7 +1549,7 @@ void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_actions_new");
RNA_def_function_ui_description(func, "Add a new action to the main database");
parm = RNA_def_string(func, "name", "Action", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "action", "Action", "", "New action data-block");
RNA_def_function_return(func, parm);
@@ -1465,13 +1558,13 @@ void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a action from the current blendfile");
parm = RNA_def_pointer(func, "action", "Action", "", "Action to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this action before deleting it");
+ 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 action before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_actions_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -1492,7 +1585,7 @@ void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_particles_new");
RNA_def_function_ui_description(func, "Add a new particle settings instance to the main database");
parm = RNA_def_string(func, "name", "ParticleSettings", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "particle", "ParticleSettings", "", "New particle settings data-block");
RNA_def_function_return(func, parm);
@@ -1501,18 +1594,19 @@ void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a particle settings instance from the current blendfile");
parm = RNA_def_pointer(func, "particle", "ParticleSettings", "", "Particle Settings to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of those particle settings before deleting them");
+ 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 those particle settings before deleting them");
func = RNA_def_function(srna, "tag", "rna_Main_particles_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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;
@@ -1528,7 +1622,7 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_palettes_new");
RNA_def_function_ui_description(func, "Add a new palette to the main database");
parm = RNA_def_string(func, "name", "Palette", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "palette", "Palette", "", "New palette data-block");
RNA_def_function_return(func, parm);
@@ -1537,13 +1631,13 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a palette from the current blendfile");
parm = RNA_def_pointer(func, "palette", "Palette", "", "Palette to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this palette before deleting it");
+ 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 palette before deleting it");
func = RNA_def_function(srna, "tag", "rna_Main_palettes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -1551,19 +1645,44 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop)
}
void RNA_def_main_cachefiles(BlenderRNA *brna, PropertyRNA *cprop)
{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+ PropertyRNA *prop;
+
RNA_def_property_srna(cprop, "BlendDataCacheFiles");
- StructRNA *srna = RNA_def_struct(brna, "BlendDataCacheFiles", NULL);
+ srna = RNA_def_struct(brna, "BlendDataCacheFiles", NULL);
RNA_def_struct_sdna(srna, "Main");
RNA_def_struct_ui_text(srna, "Main Cache Files", "Collection of cache files");
- FunctionRNA *func = RNA_def_function(srna, "tag", "rna_Main_cachefiles_tag");
- PropertyRNA *parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
- PropertyRNA *prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
+ 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);
+ RNA_def_struct_sdna(srna, "Main");
+ RNA_def_struct_ui_text(srna, "Main Paint Curves", "Collection of paint curves");
+
+ 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;
@@ -1578,12 +1697,12 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_gpencil_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "new", "BKE_gpencil_data_addnew");
RNA_def_function_flag(func, FUNC_NO_SELF);
parm = RNA_def_string(func, "name", "GreasePencil", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "grease_pencil", "GreasePencil", "", "New grease pencil data-block");
RNA_def_function_return(func, parm);
@@ -1592,9 +1711,9 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a grease pencil instance from the current blendfile");
parm = RNA_def_pointer(func, "grease_pencil", "GreasePencil", "", "Grease Pencil to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this grease pencil before deleting it");
+ 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 grease pencil before deleting it");
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1615,15 +1734,15 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_movieclips_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
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 movie clip from the current blendfile.");
parm = RNA_def_pointer(func, "clip", "MovieClip", "", "Movie clip to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this movie clip before deleting it");
+ 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 movie clip before deleting it");
/* load func */
func = RNA_def_function(srna, "load", "rna_Main_movieclip_load");
@@ -1633,7 +1752,7 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop)
"(while ``check_existing`` is disabled for consistency with other load functions, "
"behavior with multiple movie-clips using the same file may incorrectly generate proxies)");
parm = RNA_def_string_file_path(func, "filepath", "Path", FILE_MAX, "", "path for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "check_existing", false, "", "Using existing data-block if this file is already loaded");
/* return type */
parm = RNA_def_pointer(func, "clip", "MovieClip", "", "New movie clip data-block");
@@ -1658,7 +1777,7 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_masks_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* new func */
func = RNA_def_function(srna, "new", "rna_Main_mask_new");
@@ -1673,9 +1792,9 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a masks from the current blendfile.");
parm = RNA_def_pointer(func, "mask", "Mask", "", "Mask to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this mask before deleting it");
+ 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 mask before deleting it");
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1696,12 +1815,12 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_linestyle_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "new", "rna_Main_linestyles_new");
RNA_def_function_ui_description(func, "Add a new line style instance to the main database");
parm = RNA_def_string(func, "name", "FreestyleLineStyle", 0, "", "New name for the data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "New line style data-block");
RNA_def_function_return(func, parm);
@@ -1710,13 +1829,73 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a line style instance from the current blendfile");
parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "Line style to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this line style before deleting it");
+ 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 line style before deleting it");
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);
}
+void RNA_def_main_workspaces(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+ PropertyRNA *prop;
+
+ 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);
+
+ 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_workspaces_is_updated_get", NULL);
+}
+
+void RNA_def_main_lightprobes(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+ PropertyRNA *prop;
+
+ 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)");
+
+ 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);
+
+ 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_lightprobes_is_updated_get", NULL);
+}
+
#endif
diff --git a/source/blender/makesrna/intern/rna_mask.c b/source/blender/makesrna/intern/rna_mask.c
index a23d4444861..12f8a584c2c 100644
--- a/source/blender/makesrna/intern/rna_mask.c
+++ b/source/blender/makesrna/intern/rna_mask.c
@@ -54,9 +54,10 @@
#include "DNA_movieclip_types.h"
-#include "BKE_depsgraph.h"
#include "BKE_mask.h"
+#include "DEG_depsgraph.h"
+
#include "BLI_math.h"
#include "RNA_access.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);
}
@@ -632,13 +633,13 @@ static void rna_def_maskParent(BlenderRNA *brna)
/* parent */
prop = RNA_def_property(srna, "parent", PROP_STRING, PROP_NONE);
- RNA_def_property_ui_text(prop, "Parent", "Name of parent object in specified data block to which parenting happens");
+ RNA_def_property_ui_text(prop, "Parent", "Name of parent object in specified data-block to which parenting happens");
RNA_def_property_string_maxlength(prop, MAX_ID_NAME - 2);
RNA_def_property_update(prop, 0, "rna_Mask_update_parent");
/* sub_parent */
prop = RNA_def_property(srna, "sub_parent", PROP_STRING, PROP_NONE);
- RNA_def_property_ui_text(prop, "Sub Parent", "Name of parent sub-object in specified data block to which parenting happens");
+ RNA_def_property_ui_text(prop, "Sub Parent", "Name of parent sub-object in specified data-block to which parenting happens");
RNA_def_property_string_maxlength(prop, MAX_ID_NAME - 2);
RNA_def_property_update(prop, 0, "rna_Mask_update_parent");
}
@@ -778,8 +779,8 @@ static void rna_def_mask_splines(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Remove a spline from a layer");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "spline", "MaskSpline", "", "The spline to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
/* active spline */
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
@@ -818,8 +819,8 @@ static void rna_def_maskSplinePoints(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Remove a point from a spline");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "point", "MaskSplinePoint", "", "The point to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_maskSpline(BlenderRNA *brna)
@@ -1014,8 +1015,8 @@ static void rna_def_masklayers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove layer from this mask");
parm = RNA_def_pointer(func, "layer", "MaskLayer", "", "Shape to be removed");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
/* clear all layers */
func = RNA_def_function(srna, "clear", "rna_Mask_layers_clear");
diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c
index e4f9f856db7..d01ce407815 100644
--- a/source/blender/makesrna/intern/rna_material.c
+++ b/source/blender/makesrna/intern/rna_material.c
@@ -86,13 +86,14 @@ EnumPropertyItem rna_enum_ramp_blend_items[] = {
#include "DNA_space_types.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_texture.h"
#include "BKE_node.h"
#include "BKE_paint.h"
+#include "DEG_depsgraph.h"
+
#include "ED_node.h"
#include "ED_image.h"
#include "BKE_scene.h"
@@ -101,7 +102,7 @@ static void rna_Material_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Point
{
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, ma);
}
@@ -119,7 +120,7 @@ static void rna_Material_draw_update(Main *UNUSED(bmain), Scene *UNUSED(scene),
{
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);
}
@@ -213,7 +214,7 @@ static void rna_Material_active_paint_texture_index_update(Main *bmain, Scene *s
}
}
- DAG_id_tag_update(&ma->id, 0);
+ DEG_id_tag_update(&ma->id, 0);
WM_main_add_notifier(NC_MATERIAL | ND_SHADING, ma);
}
@@ -233,7 +234,7 @@ static void rna_Material_active_texture_set(PointerRNA *ptr, PointerRNA value)
set_current_material_texture(ma, value.data);
}
-static int rna_Material_active_texture_editable(PointerRNA *ptr)
+static int rna_Material_active_texture_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
Material *ma = (Material *)ptr->id.data;
@@ -427,7 +428,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 */
@@ -1804,6 +1805,24 @@ void RNA_def_material(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ 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}
+ };
+
srna = RNA_def_struct(brna, "Material", "ID");
RNA_def_struct_ui_text(srna, "Material",
"Material data-block to define the appearance of geometric objects for rendering");
@@ -1826,7 +1845,30 @@ void RNA_def_material(BlenderRNA *brna)
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");
-
+
+ /* 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, "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, "alpha_threshold", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_range(prop, 0, 1);
+ 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, "transparent_hide_backside", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "blend_flag", MA_BL_HIDE_BACKSIDE);
+ RNA_def_property_ui_text(prop, "Hide Backside" , "Limit transparency to a single layer "
+ "(avoids transparency sorting problems)");
+ RNA_def_property_update(prop, 0, "rna_Material_draw_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");
@@ -1887,9 +1929,15 @@ void RNA_def_material(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Light Group", "Limit lighting to lamps in this Group");
RNA_def_property_update(prop, 0, "rna_Material_update");
+ prop = RNA_def_property(srna, "edit_image", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "edit_image");
+ RNA_def_property_struct_type(prop, "Image");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Edit Image", "Image to use for UV-mapping");
+
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 IndexMA render pass");
+ 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 */
@@ -1964,18 +2012,6 @@ void RNA_def_material(BlenderRNA *brna)
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",
@@ -2163,14 +2199,14 @@ static void rna_def_texture_slots(BlenderRNA *brna, PropertyRNA *cprop, const ch
func = RNA_def_function(srna, "create", "rna_mtex_texture_slots_create");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_NO_SELF | FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
parm = RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "Slot index to initialize", 0, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "mtex", structname, "", "The newly initialized mtex");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "clear", "rna_mtex_texture_slots_clear");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_NO_SELF | FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
parm = RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "Slot index to clear", 0, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
void rna_def_mtex_common(BlenderRNA *brna, StructRNA *srna, const char *begin,
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index 1d734864833..3accd2f23f1 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -67,11 +67,12 @@ 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_report.h"
+#include "DEG_depsgraph.h"
+
#include "ED_mesh.h" /* XXX Bad level call */
#include "WM_api.h"
@@ -223,7 +224,7 @@ 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);
}
}
@@ -237,6 +238,20 @@ static void rna_Mesh_update_data_edit_color(Main *bmain, Scene *scene, PointerRN
}
}
+static void rna_Mesh_update_data_edit_weight(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ BKE_mesh_batch_cache_dirty(rna_mesh(ptr), BKE_MESH_BATCH_DIRTY_NOCHECK);
+
+ rna_Mesh_update_data(bmain, scene, ptr);
+}
+
+
+static void rna_Mesh_update_data_edit_active_color(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ BKE_mesh_batch_cache_dirty(rna_mesh(ptr), BKE_MESH_BATCH_DIRTY_NOCHECK);
+
+ 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;
@@ -262,6 +277,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(me, BKE_MESH_BATCH_DIRTY_NOCHECK);
+
rna_Mesh_update_draw(bmain, scene, ptr);
}
@@ -271,6 +289,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(me, BKE_MESH_BATCH_DIRTY_NOCHECK);
+
rna_Mesh_update_draw(bmain, scene, ptr);
}
@@ -662,7 +683,7 @@ static void rna_MeshLoopColor_color_set(PointerRNA *ptr, const float *values)
(&mcol->r)[2] = (char)(CLAMPIS(values[2] * 255.0f, 0, 255));
}
-static int rna_Mesh_texspace_editable(PointerRNA *ptr)
+static int rna_Mesh_texspace_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
Mesh *me = (Mesh *)ptr->data;
return (me->texflag & ME_AUTOSPACE) ? 0 : PROP_EDITABLE;
@@ -747,13 +768,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);
}
@@ -858,6 +872,36 @@ static int rna_MeshUVLoopLayer_data_length(PointerRNA *ptr)
return (me->edit_btmesh) ? 0 : me->totloop;
}
+static int rna_MeshUVLoopLayer_active_render_get(PointerRNA *ptr)
+{
+ return rna_CustomDataLayer_active_get(ptr, rna_mesh_ldata(ptr), CD_MLOOPUV, 1);
+}
+
+static int rna_MeshUVLoopLayer_active_get(PointerRNA *ptr)
+{
+ return rna_CustomDataLayer_active_get(ptr, rna_mesh_ldata(ptr), CD_MLOOPUV, 0);
+}
+
+static int rna_MeshUVLoopLayer_clone_get(PointerRNA *ptr)
+{
+ return rna_CustomDataLayer_clone_get(ptr, rna_mesh_ldata(ptr), CD_MLOOPUV);
+}
+
+static void rna_MeshUVLoopLayer_active_render_set(PointerRNA *ptr, int value)
+{
+ rna_CustomDataLayer_active_set(ptr, rna_mesh_ldata(ptr), value, CD_MLOOPUV, 1);
+}
+
+static void rna_MeshUVLoopLayer_active_set(PointerRNA *ptr, int value)
+{
+ rna_CustomDataLayer_active_set(ptr, rna_mesh_ldata(ptr), value, CD_MLOOPUV, 0);
+}
+
+static void rna_MeshUVLoopLayer_clone_set(PointerRNA *ptr, int value)
+{
+ rna_CustomDataLayer_clone_set(ptr, rna_mesh_ldata(ptr), value, CD_MLOOPUV);
+}
+
/* face uv_textures */
DEFINE_CUSTOMDATA_LAYER_COLLECTION(tessface_uv_texture, fdata, CD_MTFACE)
@@ -909,57 +953,6 @@ 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 int rna_MeshTexturePolyLayer_active_render_get(PointerRNA *ptr)
-{
- return rna_CustomDataLayer_active_get(ptr, rna_mesh_pdata(ptr), CD_MTEXPOLY, 1);
-}
-
-static int rna_MeshTexturePolyLayer_active_get(PointerRNA *ptr)
-{
- return rna_CustomDataLayer_active_get(ptr, rna_mesh_pdata(ptr), CD_MTEXPOLY, 0);
-}
-
-static int 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, int 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, int value)
-{
- rna_CustomDataLayer_clone_set(ptr, rna_mesh_pdata(ptr), value, CD_MTEXPOLY);
-}
-
/* vertex_color_layers */
DEFINE_CUSTOMDATA_LAYER_COLLECTION(tessface_vertex_color, fdata, CD_MCOL)
@@ -1183,42 +1176,6 @@ 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;
-
- 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);
- }
-
- tf->tpage = (struct Image *)id;
-}
-
-/* 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)
-{
- 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);
- }
-
- tf->tpage = (struct Image *)id;
-}
-
static int rna_MeshTessFace_verts_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
{
MFace *face = (MFace *)ptr->data;
@@ -1369,14 +1326,6 @@ static char *rna_MeshTextureFaceLayer_path(PointerRNA *ptr)
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;
@@ -1472,11 +1421,6 @@ 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;
@@ -1757,23 +1701,23 @@ 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);
@@ -1848,10 +1792,6 @@ static void UNUSED_FUNCTION(rna_mesh_unused)(void)
(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;
@@ -1883,7 +1823,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)
@@ -1962,7 +1902,7 @@ static void rna_def_medge(BlenderRNA *brna)
prop = RNA_def_property(srna, "crease", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_funcs(prop, "rna_MEdge_crease_get", "rna_MEdge_crease_set", NULL);
- RNA_def_property_ui_text(prop, "Crease", "Weight used by the Subsurf modifier for creasing");
+ RNA_def_property_ui_text(prop, "Crease", "Weight used by the Subdivision Surface modifier for creasing");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop = RNA_def_property(srna, "bevel_weight", PROP_FLOAT, PROP_NONE);
@@ -1987,7 +1927,7 @@ static void rna_def_medge(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_edge_sharp", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_SHARP);
- RNA_def_property_ui_text(prop, "Sharp", "Sharp edge for the EdgeSplit modifier");
+ RNA_def_property_ui_text(prop, "Sharp", "Sharp edge for the Edge Split modifier");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop = RNA_def_property(srna, "is_loose", PROP_BOOLEAN, PROP_NONE);
@@ -2229,7 +2169,6 @@ static void rna_def_mpolygon(BlenderRNA *brna)
func = RNA_def_function(srna, "flip", "rna_MeshPolygon_flip");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Invert winding of this polygon (flip its normal)");
-
}
/* mesh.loop_uvs */
@@ -2254,6 +2193,24 @@ 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");
+ prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
+ 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_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_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");
+
srna = RNA_def_struct(brna, "MeshUVLoop", NULL);
RNA_def_struct_sdna(srna, "MLoopUV");
RNA_def_struct_path_func(srna, "rna_MeshUVLoop_path");
@@ -2323,13 +2280,6 @@ static void rna_def_mtface(BlenderRNA *brna)
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);
@@ -2384,84 +2334,6 @@ static void rna_def_mtface(BlenderRNA *brna)
}
-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_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_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_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);
-
- 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", "");
- 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_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;
@@ -2878,7 +2750,7 @@ static void rna_def_tessface_vertex_colors(BlenderRNA *brna, PropertyRNA *cprop)
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_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
@@ -2912,14 +2784,14 @@ static void rna_def_loop_colors(BlenderRNA *brna, PropertyRNA *cprop)
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", "MeshLoopColorLayer", "", "The newly created layer");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Mesh_vertex_color_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", "MeshLoopColorLayer", "", "The layer to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
@@ -2928,13 +2800,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)
@@ -2942,14 +2814,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",
@@ -2982,7 +2867,7 @@ static void rna_def_vertex_float_layers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a float property layer to Mesh");
RNA_def_string(func, "name", "Float Prop", 0, "", "Float property name");
parm = RNA_def_pointer(func, "layer", "MeshVertexFloatPropertyLayer", "", "The newly created layer");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
}
@@ -3003,7 +2888,7 @@ static void rna_def_vertex_int_layers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a integer property layer to Mesh");
RNA_def_string(func, "name", "Int Prop", 0, "", "Int property name");
parm = RNA_def_pointer(func, "layer", "MeshVertexIntPropertyLayer", "", "The newly created layer");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
}
@@ -3024,7 +2909,7 @@ static void rna_def_vertex_string_layers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a string property layer to Mesh");
RNA_def_string(func, "name", "String Prop", 0, "", "String property name");
parm = RNA_def_pointer(func, "layer", "MeshVertexStringPropertyLayer", "", "The newly created layer");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
}
@@ -3045,7 +2930,7 @@ static void rna_def_polygon_float_layers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a float property layer to Mesh");
RNA_def_string(func, "name", "Float Prop", 0, "", "Float property name");
parm = RNA_def_pointer(func, "layer", "MeshPolygonFloatPropertyLayer", "", "The newly created layer");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
}
@@ -3066,7 +2951,7 @@ static void rna_def_polygon_int_layers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a integer property layer to Mesh");
RNA_def_string(func, "name", "Int Prop", 0, "", "Int property name");
parm = RNA_def_pointer(func, "layer", "MeshPolygonIntPropertyLayer", "", "The newly created layer");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
}
@@ -3087,7 +2972,7 @@ static void rna_def_polygon_string_layers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a string property layer to Mesh");
RNA_def_string(func, "name", "String Prop", 0, "", "String property name");
parm = RNA_def_pointer(func, "layer", "MeshPolygonStringPropertyLayer", "", "The newly created layer");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
}
@@ -3111,10 +2996,9 @@ static void rna_def_tessface_uv_textures(BlenderRNA *brna, PropertyRNA *cprop)
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_property_flag(parm, PROP_RNAPTR);
+ 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",
@@ -3124,49 +3008,7 @@ static void rna_def_tessface_uv_textures(BlenderRNA *brna, PropertyRNA *cprop)
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_property_flag(parm, PROP_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_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
-
- 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_Mesh_tessface_uv_texture_active_index_set", "rna_Mesh_uv_layer_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");
}
@@ -3200,9 +3042,9 @@ static void rna_def_skin_vertices(BlenderRNA *brna, PropertyRNA *UNUSED(cprop))
RNA_def_struct_ui_text(srna, "Skin Vertex", "Per-vertex skin data for use with the Skin modifier");
RNA_def_struct_path_func(srna, "rna_MeshSkinVertex_path");
- prop = RNA_def_property(srna, "radius", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "radius", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_array(prop, 2);
- RNA_def_property_ui_range(prop, 0.001, 100, 1, 3);
+ RNA_def_property_ui_range(prop, 0.001, 100.0, 1, 3);
RNA_def_property_ui_text(prop, "Radius", "Radius of the skin");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
@@ -3338,41 +3180,6 @@ static void rna_def_mesh(BlenderRNA *brna)
"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);
@@ -3561,7 +3368,7 @@ static void rna_def_mesh(BlenderRNA *brna)
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 subsurf weighting");
+ 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);
@@ -3576,7 +3383,7 @@ static void rna_def_mesh(BlenderRNA *brna)
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 EdgeSplit modifier");
+ 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);
@@ -3713,7 +3520,6 @@ void RNA_def_mesh(BlenderRNA *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);
diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c
index a3bc21b0170..6886321a498 100644
--- a/source/blender/makesrna/intern/rna_mesh_api.c
+++ b/source/blender/makesrna/intern/rna_mesh_api.c
@@ -48,6 +48,7 @@
#include "DNA_mesh_types.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_tangent.h"
#include "BKE_mesh_mapping.h"
#include "ED_mesh.h"
@@ -92,7 +93,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)
@@ -172,7 +173,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 +191,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, int 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)
@@ -206,9 +207,20 @@ static void rna_Mesh_flip_normals(Mesh *mesh)
BKE_mesh_tessface_clear(mesh);
BKE_mesh_calc_normals(mesh);
- DAG_id_tag_update(&mesh->id, 0);
+ DEG_id_tag_update(&mesh->id, 0);
}
+static void rna_Mesh_split_faces(Mesh *mesh, int 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(mesh, BKE_MESH_BATCH_DIRTY_NOCHECK);
+}
+
+
#else
void RNA_api_mesh(StructRNA *srna)
@@ -221,7 +233,7 @@ void RNA_api_mesh(StructRNA *srna)
RNA_def_function_ui_description(func, "Transform mesh vertices by a matrix "
"(Warning: inverts normals if matrix is negative)");
parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "shape_keys", 0, "", "Transform Shape Keys");
func = RNA_def_function(srna, "flip_normals", "rna_Mesh_flip_normals");
@@ -240,6 +252,11 @@ void RNA_api_mesh(StructRNA *srna)
func = RNA_def_function(srna, "free_normals_split", "rna_Mesh_free_normals_split");
RNA_def_function_ui_description(func, "Free split vertex normals");
+ func = RNA_def_function(srna, "split_faces", "rna_Mesh_split_faces");
+ RNA_def_function_ui_description(func, "Split faces based on the edge angle");
+ RNA_def_boolean(func, "free_loop_normals", 1, "Free Loop Notmals",
+ "Free loop normals custom data layer");
+
func = RNA_def_function(srna, "calc_tangents", "rna_Mesh_calc_tangents");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func,
@@ -264,9 +281,9 @@ void RNA_api_mesh(StructRNA *srna)
RNA_def_boolean(func, "use_bitflags", false, "", "Produce bitflags groups instead of simple numeric values");
/* return values */
parm = RNA_def_int_array(func, "poly_groups", 1, NULL, 0, 0, "", "Smooth Groups", 0, 0);
- RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_OUTPUT);
+ RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_OUTPUT);
parm = RNA_def_int(func, "groups", 0, 0, INT_MAX, "groups", "Total number of groups", 0, INT_MAX);
- RNA_def_property_flag(parm, PROP_OUTPUT);
+ RNA_def_parameter_flags(parm, 0, PARM_OUTPUT);
func = RNA_def_function(srna, "normals_split_custom_set", "rna_Mesh_normals_split_custom_set");
RNA_def_function_ui_description(func,
@@ -276,7 +293,7 @@ void RNA_api_mesh(StructRNA *srna)
/* TODO, see how array size of 0 works, this shouldnt be used */
parm = RNA_def_float_array(func, "normals", 1, NULL, -1.0f, 1.0f, "", "Normals", 0.0f, 0.0f);
RNA_def_property_multi_array(parm, 2, normals_array_dim);
- RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_REQUIRED);
func = RNA_def_function(srna, "normals_split_custom_set_from_vertices",
"rna_Mesh_normals_split_custom_set_from_vertices");
@@ -287,13 +304,15 @@ void RNA_api_mesh(StructRNA *srna)
/* TODO, see how array size of 0 works, this shouldnt be used */
parm = RNA_def_float_array(func, "normals", 1, NULL, -1.0f, 1.0f, "", "Normals", 0.0f, 0.0f);
RNA_def_property_multi_array(parm, 2, normals_array_dim);
- RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_REQUIRED);
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_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 */
@@ -317,4 +336,3 @@ void RNA_api_mesh(StructRNA *srna)
}
#endif
-
diff --git a/source/blender/makesrna/intern/rna_mesh_utils.h b/source/blender/makesrna/intern/rna_mesh_utils.h
index 0f42596ff13..05274e13e1e 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 d3b66e4c3b4..9c91bea7c45 100644
--- a/source/blender/makesrna/intern/rna_meta.c
+++ b/source/blender/makesrna/intern/rna_meta.c
@@ -47,13 +47,14 @@
#include "DNA_object_types.h"
#include "BKE_mball.h"
-#include "BKE_depsgraph.h"
#include "BKE_main.h"
+#include "DEG_depsgraph.h"
+
#include "WM_types.h"
#include "WM_api.h"
-static int rna_Meta_texspace_editable(PointerRNA *ptr)
+static int rna_Meta_texspace_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
MetaBall *mb = (MetaBall *)ptr->data;
return (mb->texflag & MB_AUTOSPACE) ? 0 : PROP_EDITABLE;
@@ -103,7 +104,7 @@ static void rna_MetaBall_update_data(Main *bmain, Scene *scene, PointerRNA *ptr)
if (ob->data == mb)
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 +122,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 +143,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 +154,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);
}
}
@@ -280,8 +281,8 @@ static void rna_def_metaball_elements(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove an element from the metaball");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "element", "MetaElement", "", "The element to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ 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_MetaBall_elements_clear");
RNA_def_function_ui_description(func, "Remove all elements from the metaball");
diff --git a/source/blender/makesrna/intern/rna_meta_api.c b/source/blender/makesrna/intern/rna_meta_api.c
index 43dca6fe4f1..117162babd5 100644
--- a/source/blender/makesrna/intern/rna_meta_api.c
+++ b/source/blender/makesrna/intern/rna_meta_api.c
@@ -47,7 +47,7 @@ static void rna_Meta_transform(struct MetaBall *mb, float *mat)
{
BKE_mball_transform(mb, (float (*)[4])mat);
- DAG_id_tag_update(&mb->id, 0);
+ DEG_id_tag_update(&mb->id, 0);
}
#else
@@ -59,7 +59,7 @@ void RNA_api_meta(StructRNA *srna)
func = RNA_def_function(srna, "transform", "rna_Meta_transform");
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_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 0b55c19c374..03340c6c356 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -105,6 +105,7 @@ EnumPropertyItem rna_enum_object_modifier_type_items[] = {
{eModifierType_Shrinkwrap, "SHRINKWRAP", ICON_MOD_SHRINKWRAP, "Shrinkwrap", ""},
{eModifierType_SimpleDeform, "SIMPLE_DEFORM", ICON_MOD_SIMPLEDEFORM, "Simple Deform", ""},
{eModifierType_Smooth, "SMOOTH", ICON_MOD_SMOOTH, "Smooth", ""},
+ {eModifierType_SurfaceDeform, "SURFACE_DEFORM", ICON_MOD_MESHDEFORM, "Surface Deform", ""},
{eModifierType_Warp, "WARP", ICON_MOD_WARP, "Warp", ""},
{eModifierType_Wave, "WAVE", ICON_MOD_WAVE, "Wave", ""},
{0, "", 0, N_("Simulate"), ""},
@@ -285,12 +286,14 @@ 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_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
@@ -408,6 +411,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
return &RNA_CorrectiveSmoothModifier;
case eModifierType_MeshSequenceCache:
return &RNA_MeshSequenceCacheModifier;
+ case eModifierType_SurfaceDeform:
+ return &RNA_SurfaceDeformModifier;
/* Default */
case eModifierType_None:
case eModifierType_ShapeKey:
@@ -450,14 +455,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 */
@@ -573,6 +578,7 @@ RNA_MOD_OBJECT_SET(MeshDeform, object, OB_MESH);
RNA_MOD_OBJECT_SET(NormalEdit, target, OB_EMPTY);
RNA_MOD_OBJECT_SET(Shrinkwrap, target, OB_MESH);
RNA_MOD_OBJECT_SET(Shrinkwrap, auxTarget, OB_MESH);
+RNA_MOD_OBJECT_SET(SurfaceDeform, target, OB_MESH);
static void rna_HookModifier_object_set(PointerRNA *ptr, PointerRNA value)
{
@@ -789,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);
}
}
}
@@ -802,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);
}
}
}
@@ -929,20 +935,21 @@ static EnumPropertyItem *rna_DataTransferModifier_layers_select_src_itemf(bConte
if (ob_src) {
DerivedMesh *dm_src;
- CustomData *pdata;
+ CustomData *ldata;
int num_data, i;
- /* XXX Is this OK? */
- dm_src = mesh_get_derived_final(dtmd->modifier.scene, ob_src, CD_MASK_BAREMESH | CD_MTEXPOLY);
- pdata = dm_src->getPolyDataLayout(dm_src);
- num_data = CustomData_number_of_layers(pdata, CD_MTEXPOLY);
+ 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_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(ldata, CD_MLOOPUV, i);
+ RNA_enum_item_add(&item, &totitem, &tmp_item);
+ }
}
}
}
@@ -954,17 +961,18 @@ static EnumPropertyItem *rna_DataTransferModifier_layers_select_src_itemf(bConte
CustomData *ldata;
int num_data, i;
- /* XXX Is this OK? */
- dm_src = mesh_get_derived_final(dtmd->modifier.scene, ob_src, CD_MASK_BAREMESH | CD_MLOOPCOL);
- ldata = dm_src->getLoopDataLayout(dm_src);
- num_data = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
+ 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);
- 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(ldata, CD_MLOOPCOL, i);
+ RNA_enum_item_add(&item, &totitem, &tmp_item);
+ }
}
}
}
@@ -1018,18 +1026,18 @@ static EnumPropertyItem *rna_DataTransferModifier_layers_select_dst_itemf(bConte
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);
}
}
@@ -1129,6 +1137,26 @@ static int rna_CorrectiveSmoothModifier_is_bind_get(PointerRNA *ptr)
return (csmd->bind_coords != NULL);
}
+static int rna_SurfaceDeformModifier_is_bound_get(PointerRNA *ptr)
+{
+ return (((SurfaceDeformModifierData *)ptr->data)->verts != NULL);
+}
+
+static void rna_MeshSequenceCache_object_path_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+#ifdef WITH_ALEMBIC
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)ptr->data;
+ Object *ob = (Object *)ptr->id.data;
+
+ mcmd->reader = CacheReader_open_alembic_object(mcmd->cache_file->handle,
+ mcmd->reader,
+ ob,
+ mcmd->object_path);
+#endif
+
+ rna_Modifier_update(bmain, scene, ptr);
+}
+
#else
static PropertyRNA *rna_def_property_subdivision_common(StructRNA *srna, const char type[])
@@ -1500,6 +1528,20 @@ static void rna_def_modifier_mirror(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Mirror V", "Mirror the V texture coordinate around the 0.5 point");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "mirror_offset_u", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "uv_offset[0]");
+ RNA_def_property_range(prop, -1, 1);
+ RNA_def_property_ui_range(prop, -1, 1, 2, 4);
+ RNA_def_property_ui_text(prop, "U Offset", "Amount to offset mirrored UVs from the 0.5 point on the U axis");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "mirror_offset_v", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "uv_offset[1]");
+ RNA_def_property_range(prop, -1, 1);
+ RNA_def_property_ui_range(prop, -1, 1, 2, 4);
+ RNA_def_property_ui_text(prop, "V Offset", "Amount to offset mirrored UVs from the 0.5 point on the V axis");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "merge_threshold", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "tolerance");
RNA_def_property_range(prop, 0, FLT_MAX);
@@ -2098,6 +2140,12 @@ static void rna_def_modifier_displace(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem prop_space_items[] = {
+ {MOD_DISP_SPACE_LOCAL, "LOCAL", 0, "Local", "Direction is defined in local coordinates"},
+ {MOD_DISP_SPACE_GLOBAL, "GLOBAL", 0, "Global", "Direction is defined in global coordinates"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "DisplaceModifier", "Modifier");
RNA_def_struct_ui_text(srna, "Displace Modifier", "Displacement modifier");
RNA_def_struct_sdna(srna, "DisplaceModifierData");
@@ -2128,6 +2176,11 @@ static void rna_def_modifier_displace(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Direction", "");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "space", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, prop_space_items);
+ RNA_def_property_ui_text(prop, "Space", "");
+ RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
+
rna_def_modifier_generic_map_info(srna);
}
@@ -2197,11 +2250,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");
@@ -4244,7 +4292,7 @@ static void rna_def_modifier_meshseqcache(BlenderRNA *brna)
prop = RNA_def_property(srna, "object_path", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Object Path", "Path to the object in the Alembic archive used to lookup geometric data");
- RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ RNA_def_property_update(prop, 0, "rna_MeshSequenceCache_object_path_update");
static EnumPropertyItem read_flag_items[] = {
{MOD_MESHSEQ_READ_VERT, "VERT", 0, "Vertex", ""},
@@ -4674,6 +4722,33 @@ static void rna_def_modifier_normaledit(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
+static void rna_def_modifier_surfacedeform(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "SurfaceDeformModifier", "Modifier");
+ RNA_def_struct_ui_text(srna, "SurfaceDeform Modifier", "");
+ RNA_def_struct_sdna(srna, "SurfaceDeformModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_MESHDEFORM);
+
+ prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Target", "Mesh object to deform with");
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_SurfaceDeformModifier_target_set", NULL, "rna_Mesh_object_poll");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
+
+ prop = RNA_def_property(srna, "falloff", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 2.0f, 16.0f);
+ RNA_def_property_ui_text(prop, "Interpolation falloff", "Controls how much nearby polygons influence deformation");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "is_bound", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_SurfaceDeformModifier_is_bound_get", NULL);
+ RNA_def_property_ui_text(prop, "Bound", "Whether geometry has been bound to target mesh");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+}
+
void RNA_def_modifier(BlenderRNA *brna)
{
StructRNA *srna;
@@ -4791,6 +4866,7 @@ void RNA_def_modifier(BlenderRNA *brna)
rna_def_modifier_datatransfer(brna);
rna_def_modifier_normaledit(brna);
rna_def_modifier_meshseqcache(brna);
+ rna_def_modifier_surfacedeform(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c
index 19d78361019..925bc048bc3 100644
--- a/source/blender/makesrna/intern/rna_movieclip.c
+++ b/source/blender/makesrna/intern/rna_movieclip.c
@@ -47,7 +47,7 @@
#ifdef RNA_RUNTIME
-#include "BKE_depsgraph.h"
+#include "DEG_depsgraph.h"
#include "ED_clip.h"
@@ -59,7 +59,7 @@ static void rna_MovieClip_reload_update(Main *UNUSED(bmain), Scene *UNUSED(scene
MovieClip *clip = (MovieClip *)ptr->id.data;
BKE_movieclip_reload(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)
@@ -347,6 +347,8 @@ static void rna_def_movieclip(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "colorspace_settings");
RNA_def_property_struct_type(prop, "ColorManagedInputColorspaceSettings");
RNA_def_property_ui_text(prop, "Color Space Settings", "Input color space settings");
+
+ rna_def_animdata_common(srna);
}
void RNA_def_movieclip(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c
index eb87eafe16c..0e43f12b64b 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"
@@ -282,7 +281,7 @@ static void rna_NlaStrip_use_auto_blend_set(PointerRNA *ptr, int value)
}
}
-static int rna_NlaStrip_action_editable(PointerRNA *ptr)
+static int rna_NlaStrip_action_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
NlaStrip *strip = (NlaStrip *)ptr->data;
@@ -508,7 +507,7 @@ static void rna_def_strip_fcurves(BlenderRNA *brna, PropertyRNA *cprop)
"of all F-Curves in the NLA strip.");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "data_path", NULL, 0, "Data Path", "F-Curve data path");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "Array index", 0, INT_MAX);
parm = RNA_def_pointer(func, "fcurve", "FCurve", "", "The found F-Curve, or None if it doesn't exist");
@@ -659,11 +658,17 @@ static void rna_def_nlastrip(BlenderRNA *brna)
prop = RNA_def_property(srna, "influence", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Influence", "Amount the strip contributes to the current result");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
+ /* XXX: Update temporarily disabled so that the property can be edited at all!
+ * Even autokey only applies after the curves have been re-evaluated, causing the unkeyed values to be lost
+ */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, /*"rna_NlaStrip_update"*/ NULL);
prop = RNA_def_property(srna, "strip_time", PROP_FLOAT, PROP_TIME);
RNA_def_property_ui_text(prop, "Strip Time", "Frame of referenced Action to evaluate");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
+ /* XXX: Update temporarily disabled so that the property can be edited at all!
+ * Even autokey only applies after the curves have been re-evaluated, causing the unkeyed values to be lost
+ */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, /*"rna_NlaStrip_update"*/ NULL);
/* TODO: should the animated_influence/time settings be animatable themselves? */
prop = RNA_def_property(srna, "use_animated_influence", PROP_BOOLEAN, PROP_NONE);
@@ -733,12 +738,12 @@ static void rna_api_nlatrack_strips(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, 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_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "start", 0, INT_MIN, INT_MAX, "Start Frame",
"Start frame for this strip", INT_MIN, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "action", "Action", "", "Action to assign to this strip");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "strip", "NlaStrip", "", "New NLA Strip");
RNA_def_function_return(func, parm);
@@ -747,8 +752,8 @@ static void rna_api_nlatrack_strips(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, 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_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_nlatrack(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 2f9e6741677..5ecfc495cd4 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -64,6 +64,8 @@
#include "RE_render_ext.h"
+#include "NOD_composite.h"
+
EnumPropertyItem rna_enum_node_socket_in_out_items[] = {
{ SOCK_IN, "IN", 0, "Input", "" },
{ SOCK_OUT, "OUT", 0, "Output", "" },
@@ -178,6 +180,8 @@ static EnumPropertyItem node_sampler_type_items[] = {
#include "ED_node.h"
#include "ED_render.h"
+#include "GPU_material.h"
+
#include "NOD_common.h"
#include "NOD_socket.h"
@@ -2271,13 +2275,45 @@ static void rna_NodeSocketStandard_vector_range(PointerRNA *ptr, float *min, flo
*softmax = dval->max;
}
+static void rna_NodeSocket_value_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ /* XXX: TODO (sergey/dalai) move this to depsgraph. */
+ bNodeTree *ntree = (bNodeTree *)ptr->id.data;
+ if (ntree->type == NTREE_SHADER) {
+ FOREACH_NODETREE(bmain, tntree, id) {
+ if (GS(id->name) == ID_WO) {
+ World *wo = (World *)id;
+ if ((BLI_listbase_is_empty(&wo->gpumaterial) == false) &&
+ ntreeHasTree(tntree, ntree))
+ {
+ wo->update_flag = 1;
+ GPU_material_uniform_buffer_tag_dirty(&wo->gpumaterial);
+ WM_main_add_notifier(NC_MATERIAL | ND_SHADING, NULL);
+ }
+ }
+ else if (GS(id->name) == ID_MA) {
+ Material *ma = (Material *)id;
+ if ((BLI_listbase_is_empty(&ma->gpumaterial) == false) &&
+ ntreeHasTree(tntree, ntree))
+ {
+ GPU_material_uniform_buffer_tag_dirty(&ma->gpumaterial);
+ WM_main_add_notifier(NC_MATERIAL | ND_SHADING, ma);
+ }
+ }
+ } FOREACH_NODETREE_END
+ }
+ else {
+ rna_NodeSocket_update(bmain, scene, ptr);
+ }
+}
+
/* using a context update function here, to avoid searching the node if possible */
static void rna_NodeSocketStandard_value_update(struct bContext *C, PointerRNA *ptr)
{
bNode *node;
/* default update */
- rna_NodeSocket_update(CTX_data_main(C), CTX_data_scene(C), ptr);
+ rna_NodeSocket_value_update(CTX_data_main(C), CTX_data_scene(C), ptr);
/* try to use node from context, faster */
node = CTX_data_pointer_get(C, "node").data;
@@ -2608,7 +2644,7 @@ static void rna_Node_image_layer_update(Main *bmain, Scene *scene, PointerRNA *p
rna_Node_update(bmain, scene, ptr);
if (scene->nodetree != NULL) {
- ntreeCompositForceHidden(scene->nodetree);
+ ntreeCompositUpdateRLayers(scene->nodetree);
}
}
@@ -2747,7 +2783,7 @@ static void rna_Node_scene_layer_update(Main *bmain, Scene *scene, PointerRNA *p
{
rna_Node_update(bmain, scene, ptr);
if (scene->nodetree != NULL) {
- ntreeCompositForceHidden(scene->nodetree);
+ ntreeCompositUpdateRLayers(scene->nodetree);
}
}
@@ -2995,6 +3031,15 @@ static void rna_ShaderNodeScript_update(Main *bmain, Scene *scene, PointerRNA *p
ED_node_tag_update_nodetree(bmain, ntree, node);
}
+static void rna_ShaderNodePrincipled_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ bNodeTree *ntree = (bNodeTree *)ptr->id.data;
+ bNode *node = (bNode *)ptr->data;
+
+ nodeUpdate(ntree, node);
+ rna_Node_update(bmain, scene, ptr);
+}
+
static void rna_ShaderNodeSubsurface_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->id.data;
@@ -3107,6 +3152,9 @@ void rna_ShaderNodePointDensity_density_cache(bNode *self,
sizeof(pd->vertex_attribute_name));
}
+ /* Store resolution, so it can be changed in the UI. */
+ shader_point_density->cached_resolution = shader_point_density->resolution;
+
/* Single-threaded sampling of the voxel domain. */
RE_point_density_cache(scene,
pd,
@@ -3121,15 +3169,15 @@ void rna_ShaderNodePointDensity_density_calc(bNode *self,
{
NodeShaderTexPointDensity *shader_point_density = self->storage;
PointDensity *pd = &shader_point_density->pd;
+ const int resolution = shader_point_density->cached_resolution;
if (scene == NULL) {
*length = 0;
return;
}
- *length = 4 * shader_point_density->resolution *
- shader_point_density->resolution *
- shader_point_density->resolution;
+ /* TODO(sergey): Will likely overflow, but how to pass size_t via RNA? */
+ *length = 4 * resolution * resolution * resolution;
if (*values == NULL) {
*values = MEM_mallocN(sizeof(float) * (*length), "point density dynamic array");
@@ -3137,13 +3185,14 @@ void rna_ShaderNodePointDensity_density_calc(bNode *self,
/* Single-threaded sampling of the voxel domain. */
RE_point_density_sample(scene, pd,
- shader_point_density->resolution,
+ resolution,
settings == 1,
*values);
/* We're done, time to clean up. */
BKE_texture_pointdensity_free_data(pd);
memset(pd, 0, sizeof(*pd));
+ shader_point_density->cached_resolution = 0.0f;
}
void rna_ShaderNodePointDensity_density_minmax(bNode *self,
@@ -3250,6 +3299,12 @@ static EnumPropertyItem node_script_mode_items[] = {
{0, NULL, 0, NULL, NULL}
};
+static EnumPropertyItem node_principled_distribution_items[] = {
+ { SHD_GLOSSY_GGX, "GGX", 0, "GGX", "" },
+ { SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", "" },
+ { 0, NULL, 0, NULL, NULL }
+};
+
/* -- Common nodes ---------------------------------------------------------- */
static void def_group_input(StructRNA *srna)
@@ -3323,6 +3378,7 @@ static void def_frame(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
RNA_def_struct_sdna_from(srna, "NodeFrame", "storage");
+ RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_ID_NODETREE);
prop = RNA_def_property(srna, "shrink", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_FRAME_SHRINK);
@@ -4021,7 +4077,9 @@ static void def_sh_tex_wireframe(StructRNA *srna)
static void def_sh_tex_pointdensity(StructRNA *srna)
{
PropertyRNA *prop;
+
FunctionRNA *func;
+ PropertyRNA *parm;
static EnumPropertyItem point_source_items[] = {
{SHD_POINTDENSITY_SOURCE_PSYS, "PARTICLE_SYSTEM", 0, "Particle System",
@@ -4141,22 +4199,22 @@ static void def_sh_tex_pointdensity(StructRNA *srna)
RNA_def_pointer(func, "scene", "Scene", "", "");
RNA_def_enum(func, "settings", calc_mode_items, 1, "", "Calculate density for rendering");
/* TODO, See how array size of 0 works, this shouldnt be used. */
- prop = RNA_def_float_array(func, "rgba_values", 1, NULL, 0, 0, "", "RGBA Values", 0, 0);
- RNA_def_property_flag(prop, PROP_DYNAMIC);
- RNA_def_function_output(func, prop);
+ parm = RNA_def_float_array(func, "rgba_values", 1, NULL, 0, 0, "", "RGBA Values", 0, 0);
+ RNA_def_parameter_flags(parm, PROP_DYNAMIC, 0);
+ RNA_def_function_output(func, parm);
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");
- prop = RNA_def_property(func, "min", PROP_FLOAT, PROP_COORDS);
- RNA_def_property_array(prop, 3);
- RNA_def_property_flag(prop, PROP_THICK_WRAP);
- RNA_def_function_output(func, prop);
- prop = RNA_def_property(func, "max", PROP_FLOAT, PROP_COORDS);
- RNA_def_property_array(prop, 3);
- RNA_def_property_flag(prop, PROP_THICK_WRAP);
- RNA_def_function_output(func, prop);
+ 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);
+ RNA_def_function_output(func, parm);
+ parm = RNA_def_property(func, "max", PROP_FLOAT, PROP_COORDS);
+ RNA_def_property_array(parm, 3);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_function_output(func, parm);
}
static void def_glossy(StructRNA *srna)
@@ -4181,6 +4239,17 @@ static void def_glass(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_principled(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, node_principled_distribution_items);
+ RNA_def_property_ui_text(prop, "Distribution", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNodePrincipled_update");
+}
+
static void def_refraction(StructRNA *srna)
{
PropertyRNA *prop;
@@ -4392,7 +4461,7 @@ static void def_sh_script(StructRNA *srna)
func = RNA_def_function(srna, "find_socket", "rna_ShaderNodeScript_find_socket");
RNA_def_function_ui_description(func, "Find a socket by name");
parm = RNA_def_string(func, "name", NULL, 0, "Socket name", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/*parm =*/ RNA_def_boolean(func, "is_output", false, "Output", "Whether the socket is an output");
parm = RNA_def_pointer(func, "result", "NodeSocket", "", "");
RNA_def_function_return(func, parm);
@@ -4401,9 +4470,9 @@ static void def_sh_script(StructRNA *srna)
RNA_def_function_ui_description(func, "Add a socket socket");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_string(func, "name", NULL, 0, "Name", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "type", node_socket_type_items, SOCK_FLOAT, "Type", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/*parm =*/ RNA_def_boolean(func, "is_output", false, "Output", "Whether the socket is an output");
parm = RNA_def_pointer(func, "result", "NodeSocket", "", "");
RNA_def_function_return(func, parm);
@@ -4412,7 +4481,7 @@ static void def_sh_script(StructRNA *srna)
RNA_def_function_ui_description(func, "Remove a socket socket");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_pointer(func, "sock", "NodeSocket", "Socket", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
#endif
}
@@ -4437,31 +4506,6 @@ static void def_cmp_alpha_over(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
-static void def_cmp_hue_saturation(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeHueSat", "storage");
-
- prop = RNA_def_property(srna, "color_hue", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "hue");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Hue", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-
- prop = RNA_def_property(srna, "color_saturation", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "sat");
- RNA_def_property_range(prop, 0.0f, 2.0f);
- RNA_def_property_ui_text(prop, "Saturation", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-
- prop = RNA_def_property(srna, "color_value", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "val");
- RNA_def_property_range(prop, 0.0f, 2.0f);
- RNA_def_property_ui_text(prop, "Value", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-}
-
static void def_cmp_blur(StructRNA *srna)
{
PropertyRNA *prop;
@@ -4788,7 +4832,7 @@ static void def_cmp_render_layers(StructRNA *srna)
RNA_def_property_struct_type(prop, "Scene");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Scene", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_scene_layer_update");
prop = RNA_def_property(srna, "layer", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
@@ -4854,7 +4898,7 @@ static void rna_def_cmp_output_file_slots_api(BlenderRNA *brna, PropertyRNA *cpr
RNA_def_function_ui_description(func, "Add a file slot to this node");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS | FUNC_USE_CONTEXT);
parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return value */
parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "New socket");
RNA_def_function_return(func, parm);
@@ -4867,7 +4911,7 @@ static void rna_def_cmp_output_file_slots_api(BlenderRNA *brna, PropertyRNA *cpr
RNA_def_function_ui_description(func, "Remove a file slot from this node");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "The socket to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "clear", "rna_Node_inputs_clear");
RNA_def_function_ui_description(func, "Remove all file slots from this node");
@@ -4877,9 +4921,9 @@ static void rna_def_cmp_output_file_slots_api(BlenderRNA *brna, PropertyRNA *cpr
RNA_def_function_ui_description(func, "Move a file slot to another position");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_int(func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the socket to move", 0, 10000);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the socket", 0, 10000);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
static void def_cmp_output_file(BlenderRNA *brna, StructRNA *srna)
{
@@ -5229,6 +5273,16 @@ static void def_cmp_luma_matte(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_cmp_brightcontrast(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "use_premultiply", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1);
+ RNA_def_property_ui_text(prop, "Convert Premul", "Keep output image premultiplied alpha");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_cmp_chroma_matte(StructRNA *srna)
{
PropertyRNA *prop;
@@ -5391,13 +5445,13 @@ static void def_cmp_double_edge_mask(StructRNA *srna)
};
prop = RNA_def_property(srna, "inner_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "custom2");
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, InnerEdgeMode_items);
RNA_def_property_ui_text(prop, "Inner Edge Mode", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "edge_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_sdna(prop, NULL, "custom2");
RNA_def_property_enum_items(prop, BufEdgeMode_items);
RNA_def_property_ui_text(prop, "Buffer Edge Mode", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
@@ -5740,8 +5794,8 @@ static void def_cmp_glare(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "streaks", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "angle");
- RNA_def_property_range(prop, 2, 16);
+ RNA_def_property_int_sdna(prop, NULL, "streaks");
+ RNA_def_property_range(prop, 1, 16);
RNA_def_property_ui_text(prop, "Streaks", "Total number of streaks");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
@@ -5758,7 +5812,7 @@ static void def_cmp_glare(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "use_rotate_45", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "angle", 0);
+ RNA_def_property_boolean_sdna(prop, NULL, "star_45", 0);
RNA_def_property_ui_text(prop, "Rotate 45", "Simple star filter: add 45 degree rotation offset");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
@@ -6300,14 +6354,8 @@ static void def_cmp_switch(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
-static void def_cmp_switch_view(StructRNA *srna)
+static void def_cmp_switch_view(StructRNA *UNUSED(srna))
{
- PropertyRNA *prop;
-
- prop = RNA_def_property(srna, "check", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "custom1", 0);
- RNA_def_property_ui_text(prop, "Switch", "Off: first socket, On: second socket");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_cmp_colorcorrection(StructRNA *srna)
@@ -6965,29 +7013,29 @@ static void rna_def_node_socket(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Draw socket");
RNA_def_function_flag(func, FUNC_REGISTER);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "UILayout");
RNA_def_property_ui_text(parm, "Layout", "Layout in the UI");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "node", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "Node");
RNA_def_property_ui_text(parm, "Node", "Node the socket belongs to");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_property(func, "text", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(parm, "Text", "Text label to draw alongside properties");
// RNA_def_property_string_default(parm, "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "draw_color", NULL);
RNA_def_function_ui_description(func, "Color of the socket icon");
RNA_def_function_flag(func, FUNC_REGISTER);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "node", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "Node");
RNA_def_property_ui_text(parm, "Node", "Node the socket belongs to");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_float_array(func, "color", 4, default_draw_color, 0.0f, 1.0f, "Color", "", 0.0f, 1.0f);
RNA_def_function_output(func, parm);
}
@@ -7038,17 +7086,17 @@ static void rna_def_node_socket_interface(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Draw template settings");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "UILayout");
RNA_def_property_ui_text(parm, "Layout", "Layout in the UI");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
func = RNA_def_function(srna, "draw_color", NULL);
RNA_def_function_ui_description(func, "Color of the socket icon");
RNA_def_function_flag(func, FUNC_REGISTER);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_float_array(func, "color", 4, default_draw_color, 0.0f, 1.0f, "Color", "", 0.0f, 1.0f);
RNA_def_function_output(func, parm);
@@ -7056,25 +7104,25 @@ static void rna_def_node_socket_interface(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Define RNA properties of a socket");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
parm = RNA_def_pointer(func, "data_rna_type", "Struct", "Data RNA Type", "RNA type for special socket properties");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "init_socket", NULL);
RNA_def_function_ui_description(func, "Initialize a node socket instance");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
parm = RNA_def_pointer(func, "node", "Node", "Node", "Node of the socket to initialize");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_pointer(func, "socket", "NodeSocket", "Socket", "Socket to initialize");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(func, "data_path", NULL, 0, "Data Path", "Path to specialized socket data");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "from_socket", NULL);
RNA_def_function_ui_description(func, "Setup template parameters from an existing socket");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
parm = RNA_def_pointer(func, "node", "Node", "Node", "Node of the original socket");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_pointer(func, "socket", "NodeSocket", "Socket", "Original socket");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
}
static void rna_def_node_socket_float(BlenderRNA *brna, const char *idname, const char *interface_idname, PropertySubType subtype)
@@ -7409,29 +7457,29 @@ static void rna_def_node_socket_standard_types(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Draw socket");
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "UILayout");
RNA_def_property_ui_text(parm, "Layout", "Layout in the UI");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "node", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "Node");
RNA_def_property_ui_text(parm, "Node", "Node the socket belongs to");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_property(func, "text", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(parm, "Text", "Text label to draw alongside properties");
// RNA_def_property_string_default(parm, "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "draw_color", "rna_NodeSocketStandard_draw_color");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Color of the socket icon");
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "node", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "Node");
RNA_def_property_ui_text(parm, "Node", "Node the socket belongs to");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_float_array(func, "color", 4, default_draw_color, 0.0f, 1.0f, "Color", "", 0.0f, 1.0f);
RNA_def_function_output(func, parm);
@@ -7451,17 +7499,17 @@ static void rna_def_node_socket_standard_types(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Draw template settings");
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "UILayout");
RNA_def_property_ui_text(parm, "Layout", "Layout in the UI");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
func = RNA_def_function(srna, "draw_color", "rna_NodeSocketInterfaceStandard_draw_color");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Color of the socket icon");
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_float_array(func, "color", 4, default_draw_color, 0.0f, 1.0f, "Color", "", 0.0f, 1.0f);
RNA_def_function_output(func, parm);
@@ -7543,13 +7591,13 @@ static void rna_def_internal_node(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_SELF_TYPE);
RNA_def_function_return(func, RNA_def_boolean(func, "visible", false, "", ""));
parm = RNA_def_pointer(func, "node_tree", "NodeTree", "Node Tree", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "poll_instance", "rna_NodeInternal_poll_instance");
RNA_def_function_ui_description(func, "If non-null output is returned, the node can be added to the tree");
RNA_def_function_return(func, RNA_def_boolean(func, "visible", false, "", ""));
parm = RNA_def_pointer(func, "node_tree", "NodeTree", "Node Tree", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* update */
func = RNA_def_function(srna, "update", "rna_NodeInternal_update");
@@ -7561,22 +7609,22 @@ static void rna_def_internal_node(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Draw node buttons");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "UILayout");
RNA_def_property_ui_text(parm, "Layout", "Layout in the UI");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* draw buttons extended */
func = RNA_def_function(srna, "draw_buttons_ext", "rna_NodeInternal_draw_buttons_ext");
RNA_def_function_ui_description(func, "Draw node buttons in the sidebar");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "UILayout");
RNA_def_property_ui_text(parm, "Layout", "Layout in the UI");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
}
static void rna_def_node_sockets_api(BlenderRNA *brna, PropertyRNA *cprop, int in_out)
@@ -7599,9 +7647,9 @@ static void rna_def_node_sockets_api(BlenderRNA *brna, PropertyRNA *cprop, int i
RNA_def_function_ui_description(func, "Add a socket to this node");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS);
parm = RNA_def_string(func, "type", NULL, MAX_NAME, "Type", "Data type");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_string(func, "identifier", NULL, MAX_NAME, "Identifier", "Unique socket identifier");
/* return value */
parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "New socket");
@@ -7611,7 +7659,7 @@ static void rna_def_node_sockets_api(BlenderRNA *brna, PropertyRNA *cprop, int i
RNA_def_function_ui_description(func, "Remove a socket from this node");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "The socket to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "clear", clearfunc);
RNA_def_function_ui_description(func, "Remove all sockets from this node");
@@ -7621,9 +7669,9 @@ static void rna_def_node_sockets_api(BlenderRNA *brna, PropertyRNA *cprop, int i
RNA_def_function_ui_description(func, "Move a socket to another position");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_int(func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the socket to move", 0, 10000);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the socket", 0, 10000);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
static void rna_def_node(BlenderRNA *brna)
@@ -7774,7 +7822,7 @@ static void rna_def_node(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Update after property changes");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
func = RNA_def_function(srna, "is_registered_node_type", "rna_Node_is_registered_node_type");
RNA_def_function_ui_description(func, "True if a registered node type");
@@ -7849,14 +7897,14 @@ static void rna_def_node(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER);
RNA_def_function_return(func, RNA_def_boolean(func, "visible", false, "", ""));
parm = RNA_def_pointer(func, "node_tree", "NodeTree", "Node Tree", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "poll_instance", NULL);
RNA_def_function_ui_description(func, "If non-null output is returned, the node can be added to the tree");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
RNA_def_function_return(func, RNA_def_boolean(func, "visible", false, "", ""));
parm = RNA_def_pointer(func, "node_tree", "NodeTree", "Node Tree", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* update */
func = RNA_def_function(srna, "update", NULL);
@@ -7868,21 +7916,21 @@ static void rna_def_node(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Handle creation of a link to or from the node");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
parm = RNA_def_pointer(func, "link", "NodeLink", "Link", "Node link that will be inserted");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* init */
func = RNA_def_function(srna, "init", NULL);
RNA_def_function_ui_description(func, "Initialize a new instance of this node");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* copy */
func = RNA_def_function(srna, "copy", NULL);
RNA_def_function_ui_description(func, "Initialize a new instance of this node from an existing node");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
parm = RNA_def_pointer(func, "node", "Node", "Node", "Existing node to copy");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* free */
func = RNA_def_function(srna, "free", NULL);
@@ -7894,29 +7942,29 @@ static void rna_def_node(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Draw node buttons");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "UILayout");
RNA_def_property_ui_text(parm, "Layout", "Layout in the UI");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* draw buttons extended */
func = RNA_def_function(srna, "draw_buttons_ext", NULL);
RNA_def_function_ui_description(func, "Draw node buttons in the sidebar");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "UILayout");
RNA_def_property_ui_text(parm, "Layout", "Layout in the UI");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* dynamic label */
func = RNA_def_function(srna, "draw_label", NULL);
RNA_def_function_ui_description(func, "Returns a dynamic label string");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
parm = RNA_def_string(func, "label", NULL, MAX_NAME, "Label", "");
- RNA_def_property_flag(parm, PROP_THICK_WRAP); /* needed for string return value */
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); /* needed for string return value */
RNA_def_function_output(func, parm);
}
@@ -7983,7 +8031,7 @@ static void rna_def_nodetree_nodes_api(BlenderRNA *brna, PropertyRNA *cprop)
* added this here to avoid frequent confusion with API changes from "type" to "bl_idname"
*/
parm = RNA_def_string(func, "type", NULL, MAX_NAME, "Type", "Type of node to add (Warning: should be same as node.bl_idname, not node.type!)");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return value */
parm = RNA_def_pointer(func, "node", "Node", "", "New node");
RNA_def_function_return(func, parm);
@@ -7992,8 +8040,8 @@ static void rna_def_nodetree_nodes_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a node from this node tree");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "node", "Node", "", "The node to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ 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_NodeTree_node_clear");
RNA_def_function_ui_description(func, "Remove all nodes from this node tree");
@@ -8022,9 +8070,9 @@ static void rna_def_nodetree_link_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a node link to this node tree");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "input", "NodeSocket", "", "The input socket");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_pointer(func, "output", "NodeSocket", "", "The output socket");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
RNA_def_boolean(func, "verify_limits", true, "Verify Limits", "Remove existing links if connection limit is exceeded");
/* return */
parm = RNA_def_pointer(func, "link", "NodeLink", "", "New node link");
@@ -8034,8 +8082,8 @@ static void rna_def_nodetree_link_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "remove a node link from the node tree");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "link", "NodeLink", "", "The node link to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ 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_NodeTree_link_clear");
RNA_def_function_ui_description(func, "remove all node links from the node tree");
@@ -8062,9 +8110,9 @@ static void rna_def_node_tree_sockets_api(BlenderRNA *brna, PropertyRNA *cprop,
RNA_def_function_ui_description(func, "Add a socket to this node tree");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "type", NULL, MAX_NAME, "Type", "Data type");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return value */
parm = RNA_def_pointer(func, "socket", "NodeSocketInterface", "", "New socket");
RNA_def_function_return(func, parm);
@@ -8073,7 +8121,7 @@ static void rna_def_node_tree_sockets_api(BlenderRNA *brna, PropertyRNA *cprop,
RNA_def_function_ui_description(func, "Remove a socket from this node tree");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "socket", "NodeSocketInterface", "", "The socket to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "clear", clearfunc);
RNA_def_function_ui_description(func, "Remove all sockets from this node tree");
@@ -8082,9 +8130,9 @@ static void rna_def_node_tree_sockets_api(BlenderRNA *brna, PropertyRNA *cprop,
func = RNA_def_function(srna, "move", movefunc);
RNA_def_function_ui_description(func, "Move a socket to another position");
parm = RNA_def_int(func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the socket to move", 0, 10000);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the socket", 0, 10000);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
static void rna_def_nodetree(BlenderRNA *brna)
@@ -8172,7 +8220,7 @@ static void rna_def_nodetree(BlenderRNA *brna)
func = RNA_def_function(srna, "interface_update", "rna_NodeTree_interface_update");
RNA_def_function_ui_description(func, "Updated node group interface");
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* registration */
prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
@@ -8201,7 +8249,7 @@ static void rna_def_nodetree(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Check visibility in the editor");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
RNA_def_function_return(func, RNA_def_boolean(func, "visible", false, "", ""));
/* update */
@@ -8214,12 +8262,12 @@ static void rna_def_nodetree(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Get a node tree from the context");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_pointer(func, "result_1", "NodeTree", "Node Tree", "Active node tree from context");
RNA_def_function_output(func, parm);
- parm = RNA_def_pointer(func, "result_2", "ID", "Owner ID", "ID data block that owns the node tree");
+ parm = RNA_def_pointer(func, "result_2", "ID", "Owner ID", "ID data-block that owns the node tree");
RNA_def_function_output(func, parm);
- parm = RNA_def_pointer(func, "result_3", "ID", "From ID", "Original ID data block selected from the context");
+ parm = RNA_def_pointer(func, "result_3", "ID", "From ID", "Original ID data-block selected from the context");
RNA_def_function_output(func, parm);
}
@@ -8318,10 +8366,10 @@ static StructRNA *define_specific_node(BlenderRNA *brna, const char *struct_name
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_SELF_TYPE);
parm = RNA_def_property(func, "index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_ui_text(parm, "Index", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_property(func, "result", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "NodeInternalSocketTemplate");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "output_template", "rna_NodeInternal_output_template");
@@ -8329,10 +8377,10 @@ static StructRNA *define_specific_node(BlenderRNA *brna, const char *struct_name
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_SELF_TYPE);
parm = RNA_def_property(func, "index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_ui_text(parm, "Index", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_property(func, "result", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(parm, "NodeInternalSocketTemplate");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
if (def_func)
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index a59f08d483f..513e25cbd15 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -47,6 +47,7 @@
#include "BKE_editmesh.h"
#include "BKE_group.h" /* needed for BKE_group_object_exists() */
#include "BKE_object_deform.h"
+#include "BKE_object_facemap.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -97,16 +98,27 @@ static EnumPropertyItem parent_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
-#ifndef RNA_RUNTIME
+#define DUPLI_ITEMS_SHARED \
+ {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"}
+
+#define DUPLI_ITEM_GROUP \
+ {OB_DUPLIGROUP, "GROUP", 0, "Group", "Enable group instancing"}
static 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"},
+ DUPLI_ITEMS_SHARED,
+ DUPLI_ITEM_GROUP,
+ {0, NULL, 0, NULL, NULL}
+};
+#ifdef RNA_RUNTIME
+static EnumPropertyItem dupli_items_nogroup[] = {
+ DUPLI_ITEMS_SHARED,
{0, NULL, 0, NULL, NULL}
};
#endif
+#undef DUPLI_ITEMS_SHARED
+#undef DUPLI_ITEM_GROUP
static EnumPropertyItem collision_bounds_items[] = {
{OB_BOUND_BOX, "BOX", ICON_MESH_CUBE, "Box", ""},
@@ -148,6 +160,7 @@ EnumPropertyItem rna_enum_object_type_items[] = {
{OB_CAMERA, "CAMERA", 0, "Camera", ""},
{OB_LAMP, "LAMP", 0, "Lamp", ""},
{OB_SPEAKER, "SPEAKER", 0, "Speaker", ""},
+ {OB_LIGHTPROBE, "LIGHT_PROBE", 0, "Probe", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -182,7 +195,6 @@ EnumPropertyItem rna_enum_object_axis_items[] = {
#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"
@@ -193,6 +205,9 @@ EnumPropertyItem rna_enum_object_axis_items[] = {
#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,7 +215,7 @@ 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_matrix_world_update(Main *bmain, Scene *scene, PointerRNA *ptr)
@@ -212,7 +227,7 @@ static void rna_Object_matrix_world_update(Main *bmain, Scene *scene, PointerRNA
static void rna_Object_hide_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
- DAG_id_type_tag(bmain, ID_OB);
+ DEG_id_type_tag(bmain, ID_OB);
}
static void rna_Object_matrix_local_get(PointerRNA *ptr, float values[16])
@@ -255,7 +270,7 @@ 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);
}
@@ -270,7 +285,7 @@ static void rna_Object_active_shape_update(Main *bmain, Scene *scene, PointerRNA
EDBM_mesh_load(ob);
EDBM_mesh_make(scene->toolsettings, ob, 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);
@@ -292,29 +307,20 @@ 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;
+ BaseLegacy *base = (BaseLegacy *)ptr->data;
+ short mode = (base->flag_legacy & 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)
+static void rna_Object_layer_update__internal(Main *bmain, Scene *scene, BaseLegacy *base, Object *ob)
{
/* try to avoid scene sort */
if (scene == NULL) {
@@ -327,16 +333,16 @@ static void rna_Object_layer_update__internal(Main *bmain, Scene *scene, Base *b
/* pass */
}
else {
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
}
- DAG_id_type_tag(bmain, ID_OB);
+ DEG_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;
+ BaseLegacy *base;
base = scene ? BKE_scene_base_find(scene, ob) : NULL;
if (!base)
@@ -352,7 +358,7 @@ static void rna_Object_layer_update(Main *bmain, Scene *scene, PointerRNA *ptr)
static void rna_Base_layer_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- Base *base = (Base *)ptr->data;
+ BaseLegacy *base = (BaseLegacy *)ptr->data;
Object *ob = (Object *)base->object;
rna_Object_layer_update__internal(bmain, scene, base, ob);
@@ -425,6 +431,7 @@ static StructRNA *rna_Object_data_typef(PointerRNA *ptr)
case OB_LATTICE: return &RNA_Lattice;
case OB_ARMATURE: return &RNA_Armature;
case OB_SPEAKER: return &RNA_Speaker;
+ case OB_LIGHTPROBE: return &RNA_LightProbe;
default: return &RNA_ID;
}
}
@@ -433,11 +440,7 @@ static void rna_Object_parent_set(PointerRNA *ptr, PointerRNA value)
{
Object *ob = (Object *)ptr->data;
Object *par = (Object *)value.data;
-
-#ifdef FREE_WINDOWS
- /* NOTE: this dummy check here prevents this method causing weird runtime errors on mingw 4.6.2 */
- if (ob)
-#endif
+
{
ED_object_parent(ob, par, ob->partype, ob->parsubstr);
}
@@ -524,6 +527,23 @@ static void rna_Object_parent_bone_set(PointerRNA *ptr, const char *value)
ED_object_parent(ob, ob->parent, ob->partype, value);
}
+static EnumPropertyItem *rna_Object_dupli_type_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
+{
+ Object *ob = (Object *)ptr->data;
+ EnumPropertyItem *item;
+
+ if (ob->type == OB_EMPTY) {
+ item = dupli_items;
+ }
+ else {
+ item = dupli_items_nogroup;
+ }
+
+ return item;
+}
+
static void rna_Object_dup_group_set(PointerRNA *ptr, PointerRNA value)
{
Object *ob = (Object *)ptr->data;
@@ -533,8 +553,15 @@ static void rna_Object_dup_group_set(PointerRNA *ptr, PointerRNA value)
* thus causing a cycle/infinite-recursion leading to crashes on load [#25298]
*/
if (BKE_group_object_exists(grp, ob) == 0) {
- ob->dup_group = grp;
- id_lib_extern((ID *)grp);
+ 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,
@@ -622,6 +649,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;
@@ -632,10 +740,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;
}
@@ -709,11 +817,11 @@ static void rna_Object_active_material_set(PointerRNA *ptr, PointerRNA value)
{
Object *ob = (Object *)ptr->id.data;
- DAG_id_tag_update(value.data, 0);
+ DEG_id_tag_update(value.data, 0);
assign_material(ob, value.data, ob->actcol, BKE_MAT_ASSIGN_EXISTING);
}
-static int rna_Object_active_material_editable(PointerRNA *ptr)
+static int rna_Object_active_material_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
Object *ob = (Object *)ptr->id.data;
bool is_editable;
@@ -942,7 +1050,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)
@@ -1069,7 +1177,7 @@ static void rna_GameObjectSettings_physics_type_set(PointerRNA *ptr, int value)
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);
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
}
}
@@ -1121,7 +1229,7 @@ static void rna_Object_layer_set(PointerRNA *ptr, const int *values)
static void rna_Base_layer_set(PointerRNA *ptr, const int *values)
{
- Base *base = (Base *)ptr->data;
+ BaseLegacy *base = (BaseLegacy *)ptr->data;
unsigned int lay;
lay = rna_Object_layer_validate__internal(values, base->lay);
@@ -1322,8 +1430,12 @@ static void rna_Object_active_constraint_set(PointerRNA *ptr, PointerRNA value)
static bConstraint *rna_Object_constraints_new(Object *object, int type)
{
+ bConstraint *new_con = BKE_constraint_add_for_object(object, NULL, type);
+
+ ED_object_constraint_tag_update(object, new_con);
WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_ADDED, object);
- return BKE_constraint_add_for_object(object, NULL, type);
+
+ return new_con;
}
static void rna_Object_constraints_remove(Object *object, ReportList *reports, PointerRNA *con_ptr)
@@ -1462,6 +1574,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 */
int rna_Lattice_object_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
{
@@ -1522,6 +1697,7 @@ static void rna_def_vertex_group(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
FunctionRNA *func;
+ PropertyRNA *parm;
static EnumPropertyItem assign_mode_items[] = {
{WEIGHT_REPLACE, "REPLACE", 0, "Replace", "Replace"},
@@ -1557,27 +1733,65 @@ static void rna_def_vertex_group(BlenderRNA *brna)
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_property_flag(prop, PROP_DYNAMIC | PROP_REQUIRED);
- prop = RNA_def_float(func, "weight", 0, 0.0f, 1.0f, "", "Vertex weight", 0.0f, 1.0f);
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_enum(func, "type", assign_mode_items, 0, "", "Vertex assign mode");
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_int_array(func, "index", 1, NULL, 0, 0, "", "Index List", 0, 0);
+ RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_REQUIRED);
+ parm = RNA_def_float(func, "weight", 0, 0.0f, 1.0f, "", "Vertex weight", 0.0f, 1.0f);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_enum(func, "type", assign_mode_items, 0, "", "Vertex assign mode");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "remove", "rna_VertexGroup_vertex_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_property_flag(prop, PROP_DYNAMIC | PROP_REQUIRED);
+ parm = RNA_def_int_array(func, "index", 1, NULL, 0, 0, "", "Index List", 0, 0);
+ RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_REQUIRED);
func = RNA_def_function(srna, "weight", "rna_VertexGroup_weight");
RNA_def_function_ui_description(func, "Get a vertex weight from the group");
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID);
- prop = RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "The index of the vertex", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_float(func, "weight", 0, 0.0f, 1.0f, "", "Vertex weight", 0.0f, 1.0f);
- RNA_def_function_return(func, prop);
+ parm = RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "The index of the vertex", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_float(func, "weight", 0, 0.0f, 1.0f, "", "Vertex weight", 0.0f, 1.0f);
+ 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, "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)
@@ -1956,7 +2170,7 @@ static void rna_def_object_constraints(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a new constraint to this object");
/* object to add */
parm = RNA_def_enum(func, "type", rna_enum_constraint_type_items, 1, "", "Constraint type to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "constraint", "Constraint", "", "New constraint");
RNA_def_function_return(func, parm);
@@ -1966,8 +2180,8 @@ static void rna_def_object_constraints(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
/* constraint to remove */
parm = RNA_def_pointer(func, "constraint", "Constraint", "", "Removed constraint");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ 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_Object_constraints_clear");
RNA_def_function_ui_description(func, "Remove all constraint from this object");
@@ -2004,10 +2218,10 @@ static void rna_def_object_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Add a new modifier");
parm = RNA_def_string(func, "name", "Name", 0, "", "New name for the modifier");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* modifier to add */
parm = RNA_def_enum(func, "type", rna_enum_object_modifier_type_items, 1, "", "Modifier type to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "modifier", "Modifier", "", "Newly created modifier");
RNA_def_function_return(func, parm);
@@ -2018,8 +2232,8 @@ static void rna_def_object_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove an existing modifier from the object");
/* modifier to remove */
parm = RNA_def_pointer(func, "modifier", "Modifier", "", "Modifier to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ 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_Object_modifier_clear");
@@ -2100,13 +2314,61 @@ static void rna_def_object_vertex_groups(BlenderRNA *brna, PropertyRNA *cprop)
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", "VertexGroup", "", "Vertex group to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ 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_Object_vgroup_clear");
RNA_def_function_ui_description(func, "Delete all vertex groups from object");
}
+/* object.face_maps */
+static void rna_def_object_face_maps(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+
+ PropertyRNA *prop;
+
+ 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");
+
+ /* 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);
+
+ 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);
+
+ 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_lodlevel(BlenderRNA *brna)
{
@@ -2246,11 +2508,6 @@ static void rna_def_object(BlenderRNA *brna)
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);
@@ -2529,6 +2786,14 @@ 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);
RNA_def_property_enum_sdna(prop, NULL, "empty_drawtype");
@@ -2560,7 +2825,7 @@ static void rna_def_object(BlenderRNA *brna)
/* render */
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 IndexOB render pass");
+ RNA_def_property_ui_text(prop, "Pass Index", "Index number for the \"Object Index\" render pass");
RNA_def_property_update(prop, NC_OBJECT, "rna_Object_internal_update");
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
@@ -2623,6 +2888,12 @@ static void rna_def_object(BlenderRNA *brna)
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, "collection_properties", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "base_collection_properties->data.group", NULL);
+ RNA_def_property_struct_type(prop, "LayerCollectionSettings");
+ RNA_def_property_ui_text(prop, "Collection Settings",
+ "Engine specific render settings to be overridden by collections");
+
/* anim */
rna_def_animdata_common(srna);
@@ -2657,6 +2928,7 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "dupli_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_enum_funcs(prop, NULL, NULL, "rna_Object_dupli_type_itemf");
RNA_def_property_ui_text(prop, "Dupli Type", "If not None, object duplication method to use");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_dependency_update");
@@ -2893,16 +3165,20 @@ static void rna_def_dupli_object(BlenderRNA *brna)
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)
+static void rna_def_object_base_legacy(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
- srna = RNA_def_struct(brna, "ObjectBase", NULL);
+ srna = RNA_def_struct(brna, "ObjectBaseLegacy", 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_text(srna, "Object Base Legacy", "An object instance in a scene (deprecated)");
RNA_def_struct_ui_icon(srna, ICON_OBJECT_DATA);
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
@@ -2922,13 +3198,13 @@ static void rna_def_object_base(BlenderRNA *brna)
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 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_boolean_sdna(prop, NULL, "flag_legacy", 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");
-
- RNA_api_object_base(srna);
+
+ RNA_api_object_base_legacy(srna);
}
void RNA_def_object(BlenderRNA *brna)
@@ -2937,8 +3213,9 @@ void RNA_def_object(BlenderRNA *brna)
RNA_define_animate_sdna(false);
rna_def_object_game_settings(brna);
- rna_def_object_base(brna);
+ rna_def_object_base_legacy(brna);
rna_def_vertex_group(brna);
+ rna_def_face_map(brna);
rna_def_material_slot(brna);
rna_def_dupli_object(brna);
RNA_define_animate_sdna(true);
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index b66556109e6..1e2d4d6ab18 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 */
@@ -88,7 +91,61 @@ static EnumPropertyItem space_items[] = {
#include "MEM_guardedalloc.h"
-#include "DEG_depsgraph.h"
+static void rna_Object_select_set(Object *ob, bContext *C, ReportList *reports, int action)
+{
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Base *base = BKE_scene_layer_base_find(sl, ob);
+
+ if (!base) {
+ BKE_reportf(reports, RPT_ERROR, "Object '%s' not in Render Layer '%s'!", ob->id.name + 2, sl->name);
+ return;
+ }
+
+ if (action == 2) { /* TOGGLE */
+ if ((base->flag & BASE_SELECTED) != 0) {
+ action = 1; /* DESELECT */
+ }
+ else {
+ action = 0; /* SELECT */
+ }
+ }
+
+ switch (action) {
+ case 1: /* DESELECT */
+ base->flag &= ~BASE_SELECTED;
+ break;
+ case 0: /* SELECT */
+ default:
+ BKE_scene_layer_base_select(sl, base);
+ break;
+ }
+}
+
+static int rna_Object_select_get(Object *ob, bContext *C, ReportList *reports)
+{
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Base *base = BKE_scene_layer_base_find(sl, ob);
+
+ if (!base) {
+ BKE_reportf(reports, RPT_ERROR, "Object '%s' not in Render Layer '%s'!", ob->id.name + 2, sl->name);
+ return -1;
+ }
+
+ return ((base->flag & BASE_SELECTED) != 0) ? 1 : 0;
+}
+
+static int rna_Object_visible_get(Object *ob, bContext *C, ReportList *reports)
+{
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Base *base = BKE_scene_layer_base_find(sl, ob);
+
+ if (!base) {
+ BKE_reportf(reports, RPT_ERROR, "Object '%s' not in Render Layer '%s'!", ob->id.name + 2, sl->name);
+ return -1;
+ }
+
+ return ((base->flag & BASE_VISIBLED) != 0) ? 1 : 0;
+}
/* Convert a given matrix from a space to another (using the object and/or a bone as reference). */
static void rna_Scene_mat_convert_space(Object *ob, ReportList *reports, bPoseChannel *pchan,
@@ -261,7 +318,7 @@ 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);
@@ -321,49 +378,55 @@ static void rna_Object_ray_cast(
float origin[3], float direction[3], float distance,
int *r_success, float r_location[3], float r_normal[3], int *r_index)
{
- BVHTreeFromMesh treeData = {NULL};
-
+ bool success = false;
+
if (ob->derivedFinal == NULL) {
BKE_reportf(reports, RPT_ERROR, "Object '%s' has no mesh data to be used for ray casting", 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_looptri(&treeData, ob->derivedFinal, 0.0f, 4, 6);
+ /* Test BoundBox first (efficiency) */
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+ float distmin;
+ if (!bb || (isect_ray_aabb_v3_simple(origin, direction, bb->vec[0], bb->vec[6], &distmin, NULL) && distmin <= distance)) {
- /* may fail if the mesh has no faces, in that case the ray-cast misses */
- if (treeData.tree != NULL) {
- BVHTreeRayHit hit;
+ BVHTreeFromMesh treeData = {NULL};
- hit.index = -1;
- hit.dist = distance;
-
- normalize_v3(direction);
+ /* no need to managing allocation or freeing of the BVH data. this is generated and freed as needed */
+ bvhtree_from_mesh_looptri(&treeData, ob->derivedFinal, 0.0f, 4, 6);
+
+ /* may fail if the mesh has no faces, in that case the ray-cast misses */
+ if (treeData.tree != NULL) {
+ BVHTreeRayHit hit;
+
+ hit.index = -1;
+ hit.dist = distance;
+ normalize_v3(direction);
- if (BLI_bvhtree_ray_cast(treeData.tree, origin, direction, 0.0f, &hit,
- treeData.raycast_callback, &treeData) != -1)
- {
- if (hit.dist <= distance) {
- *r_success = true;
- 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]);
+ if (BLI_bvhtree_ray_cast(treeData.tree, origin, direction, 0.0f, &hit,
+ treeData.raycast_callback, &treeData) != -1)
+ {
+ if (hit.dist <= distance) {
+ *r_success = success = true;
- goto finally;
+ 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]);
+ }
}
+
+ free_bvhtree_from_mesh(&treeData);
}
}
+ if (success == false) {
+ *r_success = false;
- *r_success = false;
-
- zero_v3(r_location);
- zero_v3(r_normal);
- *r_index = -1;
-
-finally:
- free_bvhtree_from_mesh(&treeData);
+ zero_v3(r_location);
+ zero_v3(r_normal);
+ *r_index = -1;
+ }
}
static void rna_Object_closest_point_on_mesh(
@@ -413,9 +476,9 @@ finally:
free_bvhtree_from_mesh(&treeData);
}
-/* ObjectBase */
+/* ObjectBaseLegacy */
-static void rna_ObjectBase_layers_from_view(Base *base, View3D *v3d)
+static void rna_ObjectBaseLegacy_layers_from_view(BaseLegacy *base, View3D *v3d)
{
base->lay = base->object->lay = v3d->lay;
}
@@ -504,6 +567,32 @@ void RNA_api_object(StructRNA *srna)
};
#endif
+ static EnumPropertyItem object_select_items[] = {
+ {0, "SELECT", 0, "Select", "Select object from the active render layer"},
+ {1, "DESELECT", 0, "Deselect", "Deselect object from the active render layer"},
+ {2, "TOGGLE", 0, "Toggle", "Toggle object selection from the active render layer"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* 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 render layer)");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
+ parm = RNA_def_enum(func, "action", object_select_items, 0, "Action", "Select mode");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+ func = RNA_def_function(srna, "select_get", "rna_Object_select_get");
+ RNA_def_function_ui_description(func, "Get the object selection for the active render 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 render layer");
+ 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);
+
/* Matrix space conversion */
func = RNA_def_function(srna, "convert_space", "rna_Scene_mat_convert_space");
RNA_def_function_ui_description(func, "Convert (transform) the given matrix from one space to another");
@@ -540,28 +629,28 @@ void RNA_api_object(StructRNA *srna)
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");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_DYNAMIC);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL | PROP_DYNAMIC, PARM_REQUIRED);
parm = RNA_def_property(func, "co_return", PROP_FLOAT, PROP_XYZ);
RNA_def_property_array(parm, 3);
RNA_def_property_ui_text(parm, "", "The location to aim to be able to see all given points");
- RNA_def_property_flag(parm, PROP_OUTPUT);
+ RNA_def_parameter_flags(parm, 0, PARM_OUTPUT);
parm = RNA_def_property(func, "scale_return", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(parm, "", "The ortho scale to aim to be able to see all given points (if relevant)");
- RNA_def_property_flag(parm, PROP_OUTPUT);
+ RNA_def_parameter_flags(parm, 0, PARM_OUTPUT);
/* 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_REPORTS);
parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene within which to evaluate modifiers");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_boolean(func, "apply_modifiers", 0, "", "Apply modifiers");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Modifier settings to apply");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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", "",
@@ -574,7 +663,7 @@ void RNA_api_object(StructRNA *srna)
"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_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ 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");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
@@ -594,15 +683,15 @@ void RNA_api_object(StructRNA *srna)
RNA_def_string(func, "name", "Key", 0, "", "Unique name for the new keyblock"); /* optional */
RNA_def_boolean(func, "from_mix", 1, "", "Create new shape from existing mix of shapes");
parm = RNA_def_pointer(func, "key", "ShapeKey", "", "New shape keyblock");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "shape_key_remove", "rna_Object_shape_key_remove");
RNA_def_function_ui_description(func, "Remove a Shape Key from this object");
RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "key", "ShapeKey", "", "Keyblock to be removed");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ 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");
@@ -611,9 +700,9 @@ void RNA_api_object(StructRNA *srna)
/* ray start and end */
parm = RNA_def_float_vector(func, "origin", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_float_vector(func, "direction", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -622,11 +711,11 @@ void RNA_api_object(StructRNA *srna)
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);
- RNA_def_property_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_function_output(func, parm);
parm = RNA_def_float_vector(func, "normal", 3, NULL, -FLT_MAX, FLT_MAX, "Normal",
"The face normal at the ray cast hit location", -1e4, 1e4);
- RNA_def_property_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_function_output(func, parm);
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);
@@ -638,7 +727,7 @@ void RNA_api_object(StructRNA *srna)
/* location of point for test and max distance */
parm = RNA_def_float_vector(func, "origin", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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);
@@ -647,11 +736,11 @@ void RNA_api_object(StructRNA *srna)
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);
- RNA_def_property_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_function_output(func, parm);
parm = RNA_def_float_vector(func, "normal", 3, NULL, -FLT_MAX, FLT_MAX, "Normal",
"The face normal at the closest point", -1e4, 1e4);
- RNA_def_property_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_function_output(func, parm);
parm = RNA_def_int(func, "index", 0, 0, 0, "", "The face index, -1 when original data isn't available", 0, 0);
@@ -661,7 +750,7 @@ void RNA_api_object(StructRNA *srna)
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_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ 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);
@@ -669,18 +758,18 @@ void RNA_api_object(StructRNA *srna)
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", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ 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_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_boolean(func, "result", 0, "", "Object visibility");
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", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ 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_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_boolean(func, "result", 0, "", "Object visibility");
RNA_def_function_return(func, parm);
@@ -690,10 +779,10 @@ void RNA_api_object(StructRNA *srna)
RNA_def_function_ui_description(func, "Returns a string for derived mesh data");
parm = RNA_def_enum(func, "type", mesh_dm_info_items, 0, "", "Modifier settings to apply");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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", "");
- RNA_def_property_flag(parm, PROP_THICK_WRAP); /* needed for string return value */
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); /* needed for string return value */
RNA_def_function_output(func, parm);
#endif /* NDEBUG */
@@ -707,16 +796,16 @@ void RNA_api_object(StructRNA *srna)
}
-void RNA_api_object_base(StructRNA *srna)
+void RNA_api_object_base_legacy(StructRNA *srna)
{
FunctionRNA *func;
PropertyRNA *parm;
- func = RNA_def_function(srna, "layers_from_view", "rna_ObjectBase_layers_from_view");
+ func = RNA_def_function(srna, "layers_from_view", "rna_ObjectBaseLegacy_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_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ 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 f05813043ca..2ae674ea961 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -94,10 +94,13 @@ static 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_modifier.h"
#include "BKE_pointcache.h"
-#include "BKE_depsgraph.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "ED_object.h"
@@ -115,7 +118,7 @@ static void rna_Cache_change(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerR
BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
for (pid = pidlist.first; pid; pid = pid->next) {
if (pid->cache == cache)
@@ -184,7 +187,7 @@ static void rna_Cache_idname_change(Main *UNUSED(bmain), Scene *UNUSED(scene), P
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 {
@@ -499,7 +502,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);
}
@@ -511,7 +514,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);
}
}
@@ -547,7 +550,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;
@@ -563,12 +566,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);
}
@@ -605,23 +608,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(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);
}
@@ -718,7 +721,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);
}
@@ -726,10 +729,15 @@ 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)
+{
+ DEG_relations_tag_update(bmain);
+ rna_softbody_update(bmain, scene, ptr);
+}
static EnumPropertyItem *rna_Effector_shape_itemf(bContext *UNUSED(C), PointerRNA *ptr,
PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
@@ -1270,7 +1278,7 @@ static void rna_def_field(BlenderRNA *brna)
prop = RNA_def_property(srna, "falloff_power", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_power");
RNA_def_property_range(prop, 0.0f, 10.0f);
- RNA_def_property_ui_text(prop, "Falloff Power", "Falloff power (real gravitational falloff = 2)");
+ RNA_def_property_ui_text(prop, "Falloff Power", "");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
prop = RNA_def_property(srna, "distance_min", PROP_FLOAT, PROP_NONE);
@@ -1378,7 +1386,7 @@ static void rna_def_field(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_absorption", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PFIELD_VISIBILITY);
RNA_def_property_ui_text(prop, "Absorption", "Force gets absorbed by collision objects");
- RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
+ RNA_def_property_update(prop, 0, "rna_FieldSettings_dependency_update");
prop = RNA_def_property(srna, "use_multiple_springs", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PFIELD_MULTIPLE_SPRINGS);
@@ -1389,6 +1397,11 @@ static void rna_def_field(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", PFIELD_SMOKE_DENSITY);
RNA_def_property_ui_text(prop, "Apply Density", "Adjust force strength based on smoke density");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
+ prop = RNA_def_property(srna, "use_gravity_falloff", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", PFIELD_GRAVITATION);
+ RNA_def_property_ui_text(prop, "Gravity Falloff", "Multiply force by 1/distance²");
+ RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
+
/* Pointer */
@@ -1855,7 +1868,7 @@ static void rna_def_softbody(BlenderRNA *brna)
prop = RNA_def_property(srna, "collision_group", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Collision Group", "Limit colliders to this Group");
- RNA_def_property_update(prop, 0, "rna_softbody_update");
+ RNA_def_property_update(prop, 0, "rna_softbody_dependency_update");
prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "effector_weights");
diff --git a/source/blender/makesrna/intern/rna_palette.c b/source/blender/makesrna/intern/rna_palette.c
index 8cbb57fde2c..4d6b94bf709 100644
--- a/source/blender/makesrna/intern/rna_palette.c
+++ b/source/blender/makesrna/intern/rna_palette.c
@@ -115,8 +115,8 @@ static void rna_def_palettecolors(BlenderRNA *brna, PropertyRNA *cprop)
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", "PaletteColor", "", "The color to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ 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_Palette_color_clear");
RNA_def_function_ui_description(func, "Remove all colors from the palette");
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index eabf41cb332..0f2eb9412e7 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -45,6 +45,8 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "BLI_string_utils.h"
+
#include "BLT_translation.h"
#include "rna_internal.h"
@@ -133,7 +135,6 @@ static 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"
@@ -143,6 +144,9 @@ static 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)
@@ -444,10 +448,12 @@ static int rna_ParticleSystem_tessfaceidx_on_emitter(ParticleSystem *particlesys
int totpart;
int totchild = 0;
int totface;
+ 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);
/* 1. check that everything is ok & updated */
if (!particlesystem || !totface) {
@@ -482,13 +488,29 @@ static int rna_ParticleSystem_tessfaceidx_on_emitter(ParticleSystem *particlesys
return num;
}
}
+ else if (part->from == PART_FROM_VERT) {
+ if (num != DMCACHE_NOTFOUND && num < totvert) {
+ MFace *mface = modifier->dm_final->getTessFaceDataArray(modifier->dm_final, CD_MFACE);
+
+ *r_fuv = &particle->fuv;
+
+ /* 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 < totface; i++, mface++) {
+ if (ELEM(num, mface->v1, mface->v2, mface->v3, mface->v4)) {
+ return i;
+ }
+ }
+ }
+ }
}
else {
ChildParticle *cpa = particlesystem->child + particle_no - totpart;
num = cpa->num;
if (part->childtype == PART_CHILD_FACES) {
- if (ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) {
+ if (ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME, PART_FROM_VERT)) {
if (num != DMCACHE_NOTFOUND && num < totface) {
*r_fuv = &cpa->fuv;
return num;
@@ -508,6 +530,22 @@ static int rna_ParticleSystem_tessfaceidx_on_emitter(ParticleSystem *particlesys
return num;
}
}
+ else if (part->from == PART_FROM_VERT) {
+ if (num != DMCACHE_NOTFOUND && num < totvert) {
+ MFace *mface = modifier->dm_final->getTessFaceDataArray(modifier->dm_final, CD_MFACE);
+
+ *r_fuv = &parent->fuv;
+
+ /* 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 < totface; i++, mface++) {
+ if (ELEM(num, mface->v1, mface->v2, mface->v3, mface->v4)) {
+ return i;
+ }
+ }
+ }
+ }
}
}
@@ -607,10 +645,10 @@ static void particle_recalc(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRN
psys->recalc = flag;
- 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 | flag);
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA | flag);
WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, NULL);
}
@@ -621,7 +659,7 @@ 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);
}
@@ -630,6 +668,12 @@ static void rna_Particle_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
particle_recalc(bmain, scene, ptr, PSYS_RECALC_RESET);
}
+static void rna_Particle_reset_dependency(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ DEG_relations_tag_update(bmain);
+ rna_Particle_reset(bmain, scene, ptr);
+}
+
static void rna_Particle_change_type(Main *bmain, Scene *scene, PointerRNA *ptr)
{
particle_recalc(bmain, scene, ptr, PSYS_RECALC_RESET | PSYS_RECALC_TYPE);
@@ -649,7 +693,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);
}
@@ -694,8 +738,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);
@@ -710,7 +754,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);
}
}
@@ -730,7 +774,7 @@ static void rna_Particle_hair_dynamics(Main *bmain, Scene *scene, PointerRNA *pt
else
WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, NULL);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
static PointerRNA rna_particle_settings_get(PointerRNA *ptr)
{
@@ -1289,7 +1333,9 @@ static void rna_def_particle_hair_key(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
+
FunctionRNA *func;
+ PropertyRNA *parm;
srna = RNA_def_struct(brna, "ParticleHairKey", NULL);
RNA_def_struct_sdna(srna, "HairKey");
@@ -1317,18 +1363,16 @@ static void rna_def_particle_hair_key(BlenderRNA *brna)
/* Aided co func */
func = RNA_def_function(srna, "co_object", "rna_ParticleHairKey_co_object");
RNA_def_function_ui_description(func, "Obtain hairkey location with particle and modifier data");
-
- prop = RNA_def_pointer(func, "object", "Object", "", "Object");
- RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL);
- prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
- RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL);
- prop = RNA_def_pointer(func, "particle", "Particle", "", "hair particle");
- RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL);
-
- prop = RNA_def_float_vector(func, "co", 3, NULL, -FLT_MAX, FLT_MAX, "Co",
+ parm = RNA_def_pointer(func, "object", "Object", "", "Object");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "particle", "Particle", "", "hair particle");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_float_vector(func, "co", 3, NULL, -FLT_MAX, FLT_MAX, "Co",
"Exported hairkey location", -1e4, 1e4);
- RNA_def_property_flag(prop, PROP_THICK_WRAP);
- RNA_def_function_output(func, prop);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_function_output(func, parm);
}
static void rna_def_particle_key(BlenderRNA *brna)
@@ -1380,7 +1424,9 @@ static void rna_def_particle(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
+
FunctionRNA *func;
+ PropertyRNA *parm;
static EnumPropertyItem alive_items[] = {
/*{PARS_KILLED, "KILLED", 0, "Killed", ""}, */
@@ -1490,12 +1536,12 @@ static void rna_def_particle(BlenderRNA *brna)
func = RNA_def_function(srna, "uv_on_emitter", "rna_Particle_uv_on_emitter");
RNA_def_function_ui_description(func, "Obtain uv for particle on derived mesh");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
- prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
- RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL);
- prop = RNA_def_property(func, "uv", PROP_FLOAT, PROP_COORDS);
- RNA_def_property_array(prop, 2);
- RNA_def_property_flag(prop, PROP_THICK_WRAP);
- RNA_def_function_output(func, prop);
+ parm = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_property(func, "uv", PROP_FLOAT, PROP_COORDS);
+ RNA_def_property_array(parm, 2);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_function_output(func, parm);
}
static void rna_def_particle_dupliweight(BlenderRNA *brna)
@@ -2085,7 +2131,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Even Distribution",
"Use even distribution from faces based on face areas or edge lengths");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
-
+
prop = RNA_def_property(srna, "use_die_on_collision", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_DIE_ON_COL);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -2290,7 +2336,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_render_adaptive", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_REN_ADAPT);
- RNA_def_property_ui_text(prop, "Adaptive render", "Draw steps of the particle path");
+ RNA_def_property_ui_text(prop, "Adaptive Render", "Draw steps of the particle path");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
prop = RNA_def_property(srna, "use_velocity_length", PROP_BOOLEAN, PROP_NONE);
@@ -2305,7 +2351,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_strand_primitive", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_REN_STRAND);
- RNA_def_property_ui_text(prop, "Strand render", "Use the strand primitive for rendering");
+ 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);
@@ -2328,10 +2374,10 @@ static void rna_def_particle_settings(BlenderRNA *brna)
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, "draw_size", PROP_FLOAT, PROP_NONE);
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 (0.1 = default)");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
prop = RNA_def_property(srna, "child_type", PROP_ENUM, PROP_NONE);
@@ -2353,7 +2399,8 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Render", "How many steps paths are rendered with (power of 2)");
prop = RNA_def_property(srna, "hair_step", PROP_INT, PROP_NONE);
- RNA_def_property_range(prop, 2, 50);
+ RNA_def_property_range(prop, 2, SHRT_MAX);
+ RNA_def_property_ui_range(prop, 2, 50, 1, 1);
RNA_def_property_ui_text(prop, "Segments", "Number of hair segments");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
@@ -2744,7 +2791,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "collision_group", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Collision Group", "Limit colliders to this Group");
- RNA_def_property_update(prop, 0, "rna_Particle_reset");
+ RNA_def_property_update(prop, 0, "rna_Particle_reset_dependency");
/* global physical properties */
prop = RNA_def_property(srna, "drag_factor", PROP_FLOAT, PROP_NONE);
@@ -3188,7 +3235,9 @@ static void rna_def_particle_system(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
+
FunctionRNA *func;
+ PropertyRNA *parm;
static EnumPropertyItem resolution_items[] = {
{eModifierMode_Realtime, "PREVIEW", 0, "Preview", "Apply modifier preview settings"},
@@ -3497,53 +3546,51 @@ static void rna_def_particle_system(BlenderRNA *brna)
/* 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");
- prop = RNA_def_pointer(func, "scene", "Scene", "", "Scene");
- prop = RNA_def_pointer(func, "object", "Object", "", "Object");
- prop = RNA_def_enum(func, "resolution", resolution_items, 0, "", "Resolution settings to apply");
+ 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");
-
- prop = RNA_def_pointer(func, "object", "Object", "", "Object");
- RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL);
- prop = RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX);
- prop = RNA_def_int(func, "step", 0, INT_MIN, INT_MAX, "step no", "", INT_MIN, INT_MAX);
-
- prop = RNA_def_float_vector(func, "co", 3, NULL, -FLT_MAX, FLT_MAX, "Co",
+ parm = RNA_def_pointer(func, "object", "Object", "", "Object");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX);
+ RNA_def_int(func, "step", 0, INT_MIN, INT_MAX, "step no", "", INT_MIN, INT_MAX);
+ parm = RNA_def_float_vector(func, "co", 3, NULL, -FLT_MAX, FLT_MAX, "Co",
"Exported hairkey location", -1e4, 1e4);
- RNA_def_property_flag(prop, PROP_THICK_WRAP);
- RNA_def_function_output(func, prop);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_function_output(func, parm);
/* extract hair UVs */
func = RNA_def_function(srna, "uv_on_emitter", "rna_ParticleSystem_uv_on_emitter");
RNA_def_function_ui_description(func, "Obtain uv for all particles");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
- prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
- RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL);
+ parm = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
prop = RNA_def_pointer(func, "particle", "Particle", "", "Particle");
- RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL);
- prop = RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX);
- prop = RNA_def_int(func, "uv_no", 0, INT_MIN, INT_MAX, "UV no", "", INT_MIN, INT_MAX);
- prop = RNA_def_property(func, "uv", PROP_FLOAT, PROP_COORDS);
- RNA_def_property_array(prop, 2);
- RNA_def_property_flag(prop, PROP_THICK_WRAP);
- RNA_def_function_output(func, prop);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX);
+ RNA_def_int(func, "uv_no", 0, INT_MIN, INT_MAX, "UV no", "", INT_MIN, INT_MAX);
+ parm = RNA_def_property(func, "uv", PROP_FLOAT, PROP_COORDS);
+ RNA_def_property_array(parm, 2);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_function_output(func, parm);
/* extract hair mcols */
func = RNA_def_function(srna, "mcol_on_emitter", "rna_ParticleSystem_mcol_on_emitter");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Obtain mcol for all particles");
- prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
- RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL);
- prop = RNA_def_pointer(func, "particle", "Particle", "", "Particle");
- RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL);
- prop = RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX);
- prop = RNA_def_int(func, "vcol_no", 0, INT_MIN, INT_MAX, "vcol no", "", INT_MIN, INT_MAX);
- prop = RNA_def_property(func, "mcol", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_array(prop, 3);
- RNA_def_property_flag(prop, PROP_THICK_WRAP);
- RNA_def_function_output(func, prop);
+ parm = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "particle", "Particle", "", "Particle");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX);
+ RNA_def_int(func, "vcol_no", 0, INT_MIN, INT_MAX, "vcol no", "", INT_MIN, INT_MAX);
+ parm = RNA_def_property(func, "mcol", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_array(parm, 3);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_function_output(func, parm);
}
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index 1f34d8f23d4..d8ed9800b4c 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -40,6 +40,7 @@
#include "DNA_scene_types.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -105,9 +106,11 @@ EnumPropertyItem rna_enum_color_sets_items[] = {
#include "BKE_context.h"
#include "BKE_constraint.h"
-#include "BKE_depsgraph.h"
#include "BKE_idprop.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "ED_object.h"
#include "ED_armature.h"
@@ -119,7 +122,7 @@ 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);
}
static void rna_Pose_IK_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
@@ -127,7 +130,7 @@ 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);
BIK_clear_data(ob->pose);
}
@@ -232,13 +235,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(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 */
@@ -348,7 +351,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)
@@ -523,12 +526,15 @@ static void rna_PoseChannel_active_constraint_set(PointerRNA *ptr, PointerRNA va
BKE_constraints_active_set(&pchan->constraints, (bConstraint *)value.data);
}
-static bConstraint *rna_PoseChannel_constraints_new(bPoseChannel *pchan, int type)
+static bConstraint *rna_PoseChannel_constraints_new(ID *id, bPoseChannel *pchan, Main *main, int type)
{
- /*WM_main_add_notifier(NC_OBJECT|ND_CONSTRAINT|NA_ADDED, object); */
- /* TODO, pass object also */
- /* TODO, new pose bones don't have updated draw flags */
- return BKE_constraint_add_for_pose(NULL, pchan, NULL, type);
+ Object *ob = (Object *)id;
+ bConstraint *new_con = BKE_constraint_add_for_pose(ob, pchan, NULL, type);
+
+ ED_object_constraint_dependency_tag_update(main, ob, new_con);
+ WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_ADDED, id);
+
+ return new_con;
}
static void rna_PoseChannel_constraints_remove(ID *id, bPoseChannel *pchan, ReportList *reports, PointerRNA *con_ptr)
@@ -556,13 +562,18 @@ static void rna_PoseChannel_constraints_remove(ID *id, bPoseChannel *pchan, Repo
}
}
-static int rna_PoseChannel_proxy_editable(PointerRNA *ptr)
+static int rna_PoseChannel_proxy_editable(PointerRNA *ptr, const char **r_info)
{
Object *ob = (Object *)ptr->id.data;
bArmature *arm = ob->data;
bPoseChannel *pchan = (bPoseChannel *)ptr->data;
- return (ob->proxy && pchan->bone && (pchan->bone->layer & arm->layer_protected)) ? 0 : PROP_EDITABLE;
+ if (ob->proxy && pchan->bone && (pchan->bone->layer & arm->layer_protected)) {
+ *r_info = "Can't edit property of a proxy on a protected layer";
+ return 0;
+ }
+
+ return PROP_EDITABLE;
}
static int rna_PoseChannel_location_editable(PointerRNA *ptr, int index)
@@ -758,20 +769,21 @@ static void rna_def_pose_channel_constraints(BlenderRNA *brna, PropertyRNA *cpro
/* Constraint collection */
func = RNA_def_function(srna, "new", "rna_PoseChannel_constraints_new");
RNA_def_function_ui_description(func, "Add a constraint to this object");
+ RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_SELF_ID); /* ID and Main needed for refresh */
/* return type */
parm = RNA_def_pointer(func, "constraint", "Constraint", "", "New constraint");
RNA_def_function_return(func, parm);
/* constraint to add */
parm = RNA_def_enum(func, "type", rna_enum_constraint_type_items, 1, "", "Constraint type to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "remove", "rna_PoseChannel_constraints_remove");
RNA_def_function_ui_description(func, "Remove a constraint from this object");
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID); /* ID needed for refresh */
/* constraint to remove */
parm = RNA_def_pointer(func, "constraint", "Constraint", "", "Removed constraint");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_pose_channel(BlenderRNA *brna)
@@ -1354,8 +1366,8 @@ static void rna_def_bone_groups(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID); /* ID needed for refresh */
/* bone group to remove */
parm = RNA_def_pointer(func, "group", "BoneGroup", "", "Removed bone group");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ 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, "BoneGroup");
diff --git a/source/blender/makesrna/intern/rna_pose_api.c b/source/blender/makesrna/intern/rna_pose_api.c
index 465a86adc31..f523b725b18 100644
--- a/source/blender/makesrna/intern/rna_pose_api.c
+++ b/source/blender/makesrna/intern/rna_pose_api.c
@@ -76,7 +76,7 @@ void RNA_api_pose_channel(StructRNA *srna)
RNA_def_function_ui_description(func, "Calculate bone envelope at given point");
parm = RNA_def_float_vector_xyz(func, "point", 3, NULL, -FLT_MAX, FLT_MAX, "Point",
"Position in 3d space to evaluate", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* 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);
diff --git a/source/blender/makesrna/intern/rna_property.c b/source/blender/makesrna/intern/rna_property.c
index 07bdbb03357..fb70870f49b 100644
--- a/source/blender/makesrna/intern/rna_property.c
+++ b/source/blender/makesrna/intern/rna_property.c
@@ -31,6 +31,7 @@
#include "DNA_object_types.h"
#include "BLI_path_util.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c
index 84382704b2b..267a81c81af 100644
--- a/source/blender/makesrna/intern/rna_render.c
+++ b/source/blender/makesrna/intern/rna_render.c
@@ -26,12 +26,15 @@
#include <stdlib.h>
+#include "DNA_node_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "BLI_utildefines.h"
#include "BLI_path_util.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -41,6 +44,7 @@
#include "RE_pipeline.h"
+/* Deprecated, only provided for API compatibility. */
EnumPropertyItem rna_enum_render_pass_type_items[] = {
{SCE_PASS_COMBINED, "COMBINED", 0, "Combined", ""},
{SCE_PASS_Z, "Z", 0, "Z", ""},
@@ -77,13 +81,6 @@ EnumPropertyItem rna_enum_render_pass_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem rna_enum_render_pass_debug_type_items[] = {
- {RENDER_PASS_DEBUG_BVH_TRAVERSAL_STEPS, "BVH_TRAVERSAL_STEPS", 0, "BVH Traversal Steps", ""},
- {RENDER_PASS_DEBUG_BVH_TRAVERSED_INSTANCES, "BVH_TRAVERSED_INSTANCES", 0, "BVH Traversed Instances", ""},
- {RENDER_PASS_DEBUG_RAY_BOUNCES, "RAY_BOUNCES", 0, "Ray Steps", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
EnumPropertyItem rna_enum_bake_pass_type_items[] = {
{SCE_PASS_COMBINED, "COMBINED", 0, "Combined", ""},
{SCE_PASS_AO, "AO", 0, "AO", ""},
@@ -141,7 +138,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 *graph, Scene *scene)
{
extern FunctionRNA rna_RenderEngine_update_func;
PointerRNA ptr;
@@ -153,24 +150,25 @@ 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, "depsgraph", &graph);
RNA_parameter_set_lookup(&list, "scene", &scene);
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_to_image(RenderEngine *engine, struct Depsgraph *depsgraph)
{
- extern FunctionRNA rna_RenderEngine_render_func;
+ extern FunctionRNA rna_RenderEngine_render_to_image_func;
PointerRNA ptr;
ParameterList list;
FunctionRNA *func;
RNA_pointer_create(NULL, engine->type->ext.srna, engine, &ptr);
- func = &rna_RenderEngine_render_func;
+ func = &rna_RenderEngine_render_to_image_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);
@@ -221,15 +219,15 @@ static void engine_view_update(RenderEngine *engine, const struct bContext *cont
RNA_parameter_list_free(&list);
}
-static void engine_view_draw(RenderEngine *engine, const struct bContext *context)
+static void engine_render_to_view(RenderEngine *engine, const struct bContext *context)
{
- extern FunctionRNA rna_RenderEngine_view_draw_func;
+ extern FunctionRNA rna_RenderEngine_render_to_view_func;
PointerRNA ptr;
ParameterList list;
FunctionRNA *func;
RNA_pointer_create(NULL, engine->type->ext.srna, engine, &ptr);
- func = &rna_RenderEngine_view_draw_func;
+ func = &rna_RenderEngine_render_to_view_func;
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "context", &context);
@@ -256,6 +254,41 @@ static void engine_update_script_node(RenderEngine *engine, struct bNodeTree *nt
RNA_parameter_list_free(&list);
}
+static void engine_collection_settings_create(RenderEngine *engine, struct IDProperty *props)
+{
+ extern FunctionRNA rna_RenderEngine_collection_settings_create_func;
+ PointerRNA ptr;
+ ParameterList list;
+ FunctionRNA *func;
+
+ RNA_pointer_create(NULL, engine->type->ext.srna, engine, &ptr);
+ func = &rna_RenderEngine_collection_settings_create_func;
+
+ RNA_parameter_list_create(&list, &ptr, func);
+ RNA_parameter_set_lookup(&list, "props", &props);
+ engine->type->ext.call(NULL, &ptr, func, &list);
+
+ RNA_parameter_list_free(&list);
+}
+
+static void engine_update_render_passes(RenderEngine *engine, struct Scene *scene, struct SceneRenderLayer *srl)
+{
+ extern FunctionRNA rna_RenderEngine_update_render_passes_func;
+ PointerRNA ptr;
+ ParameterList list;
+ FunctionRNA *func;
+
+ RNA_pointer_create(NULL, engine->type->ext.srna, engine, &ptr);
+ func = &rna_RenderEngine_update_render_passes_func;
+
+ RNA_parameter_list_create(&list, &ptr, func);
+ RNA_parameter_set_lookup(&list, "scene", &scene);
+ RNA_parameter_set_lookup(&list, "renderlayer", &srl);
+ engine->type->ext.call(NULL, &ptr, func, &list);
+
+ RNA_parameter_list_free(&list);
+}
+
/* RenderEngine registration */
static void rna_RenderEngine_unregister(Main *UNUSED(bmain), StructRNA *type)
@@ -276,7 +309,7 @@ static StructRNA *rna_RenderEngine_register(Main *bmain, ReportList *reports, vo
RenderEngineType *et, dummyet = {NULL};
RenderEngine dummyengine = {NULL};
PointerRNA dummyptr;
- int have_function[6];
+ int have_function[8];
/* setup dummy engine & engine type to store static properties in */
dummyengine.type = &dummyet;
@@ -313,13 +346,15 @@ static StructRNA *rna_RenderEngine_register(Main *bmain, ReportList *reports, vo
RNA_struct_blender_type_set(et->ext.srna, et);
et->update = (have_function[0]) ? engine_update : NULL;
- et->render = (have_function[1]) ? engine_render : NULL;
+ et->render_to_image = (have_function[1]) ? engine_render_to_image : NULL;
et->bake = (have_function[2]) ? engine_bake : NULL;
et->view_update = (have_function[3]) ? engine_view_update : NULL;
- et->view_draw = (have_function[4]) ? engine_view_draw : NULL;
+ et->render_to_view = (have_function[4]) ? engine_render_to_view : NULL;
et->update_script_node = (have_function[5]) ? engine_update_script_node : NULL;
+ et->update_render_passes = (have_function[6]) ? engine_update_render_passes : NULL;
+ et->collection_settings_create = (have_function[7]) ? engine_collection_settings_create : NULL;
- BLI_addtail(&R_engines, et);
+ RE_engines_register(bmain, et);
return et->ext.srna;
}
@@ -414,14 +449,28 @@ static RenderPass *rna_RenderPass_find_by_type(RenderLayer *rl, int passtype, co
return RE_pass_find_by_type(rl, passtype, view);
}
+static RenderPass *rna_RenderPass_find_by_name(RenderLayer *rl, const char *name, const char *view)
+{
+ return RE_pass_find_by_name(rl, name, view);
+}
+
#else /* RNA_RUNTIME */
static void rna_def_render_engine(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
+
FunctionRNA *func;
-
+ PropertyRNA *parm;
+
+ static EnumPropertyItem render_pass_type_items[] = {
+ {SOCK_FLOAT, "VALUE", 0, "Value", ""},
+ {SOCK_VECTOR, "VECTOR", 0, "Vector", ""},
+ {SOCK_RGBA, "COLOR", 0, "Color", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "RenderEngine", NULL);
RNA_def_struct_sdna(srna, "RenderEngine");
RNA_def_struct_ui_text(srna, "Render Engine", "Render engine");
@@ -434,35 +483,36 @@ 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, "depsgraph", "Depsgraph", "", "");
RNA_def_pointer(func, "scene", "Scene", "", "");
- func = RNA_def_function(srna, "render", NULL);
+ func = RNA_def_function(srna, "render_to_image", 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", "", "");
+ RNA_def_pointer(func, "desgraph", "Depsgraph", "", "");
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);
- prop = RNA_def_pointer(func, "scene", "Scene", "", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_pointer(func, "object", "Object", "", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_enum(func, "pass_type", rna_enum_bake_pass_type_items, 0, "Pass", "Pass to bake");
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_int(func, "pass_filter", 0, 0, INT_MAX, "Pass Filter", "Filter to combined, diffuse, glossy, transmission and subsurface passes", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_int(func, "object_id", 0, 0, INT_MAX, "Object Id", "Id of the current object being baked in relation to the others", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_pointer(func, "pixel_array", "BakePixel", "", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_int(func, "num_pixels", 0, 0, INT_MAX, "Number of Pixels", "Size of the baking batch", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_int(func, "depth", 0, 0, INT_MAX, "Pixels depth", "Number of channels", 1, INT_MAX);
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_pointer(func, "scene", "Scene", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "object", "Object", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_enum(func, "pass_type", rna_enum_bake_pass_type_items, 0, "Pass", "Pass to bake");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "pass_filter", 0, 0, INT_MAX, "Pass Filter", "Filter to combined, diffuse, glossy, transmission and subsurface passes", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "object_id", 0, 0, INT_MAX, "Object Id", "Id of the current object being baked in relation to the others", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "pixel_array", "BakePixel", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "num_pixels", 0, 0, INT_MAX, "Number of Pixels", "Size of the baking batch", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "depth", 0, 0, INT_MAX, "Pixels depth", "Number of channels", 1, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* TODO, see how array size of 0 works, this shouldnt be used */
- prop = RNA_def_pointer(func, "result", "AnyType", "", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_pointer(func, "result", "AnyType", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* viewport render callbacks */
func = RNA_def_function(srna, "view_update", NULL);
@@ -470,7 +520,7 @@ static void rna_def_render_engine(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
RNA_def_pointer(func, "context", "Context", "", "");
- func = RNA_def_function(srna, "view_draw", NULL);
+ func = RNA_def_function(srna, "render_to_view", NULL);
RNA_def_function_ui_description(func, "Draw viewport render");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
RNA_def_pointer(func, "context", "Context", "", "");
@@ -479,8 +529,21 @@ static void rna_def_render_engine(BlenderRNA *brna)
func = RNA_def_function(srna, "update_script_node", NULL);
RNA_def_function_ui_description(func, "Compile shader script node");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
- prop = RNA_def_pointer(func, "node", "Node", "", "");
- RNA_def_property_flag(prop, PROP_RNAPTR);
+ 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", "SceneRenderLayer", "", "");
+
+ /* per-collection engine settings initialization */
+ func = RNA_def_function(srna, "collection_settings_create", NULL);
+ RNA_def_function_ui_description(func, "Create the per collection settings for the engine");
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
+ parm = RNA_def_pointer(func, "collection_settings", "LayerCollectionSettings", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
/* tag for redraw */
func = RNA_def_function(srna, "tag_redraw", "engine_tag_redraw");
@@ -492,115 +555,126 @@ static void rna_def_render_engine(BlenderRNA *brna)
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");
- prop = RNA_def_int(func, "x", 0, 0, INT_MAX, "X", "", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_int(func, "y", 0, 0, INT_MAX, "Y", "", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_int(func, "w", 0, 0, INT_MAX, "Width", "", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_int(func, "h", 0, 0, INT_MAX, "Height", "", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_int(func, "x", 0, 0, INT_MAX, "X", "", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "y", 0, 0, INT_MAX, "Y", "", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "w", 0, 0, INT_MAX, "Width", "", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "h", 0, 0, INT_MAX, "Height", "", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_string(func, "layer", NULL, 0, "Layer", "Single layer to get render result for"); /* NULL ok here */
RNA_def_string(func, "view", NULL, 0, "View", "Single view to get render result for"); /* NULL ok here */
- prop = RNA_def_pointer(func, "result", "RenderResult", "Result", "");
- RNA_def_function_return(func, prop);
+ parm = RNA_def_pointer(func, "result", "RenderResult", "Result", "");
+ RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "update_result", "RE_engine_update_result");
RNA_def_function_ui_description(func, "Signal that pixels have been updated and can be redrawn in the user interface");
- prop = RNA_def_pointer(func, "result", "RenderResult", "Result", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_pointer(func, "result", "RenderResult", "Result", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "end_result", "RE_engine_end_result");
RNA_def_function_ui_description(func, "All pixels in the render result have been set and are final");
- prop = RNA_def_pointer(func, "result", "RenderResult", "Result", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_pointer(func, "result", "RenderResult", "Result", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "cancel", 0, "Cancel", "Don't mark tile as done, don't merge results unless forced");
+ RNA_def_boolean(func, "highlight", 0, "Highlight", "Don't mark tile as done yet");
RNA_def_boolean(func, "do_merge_results", 0, "Merge Results", "Merge results even if cancel=true");
+ func = RNA_def_function(srna, "add_pass", "RE_engine_add_pass");
+ RNA_def_function_ui_description(func, "Add a pass to the render layer");
+ parm = RNA_def_string(func, "name", NULL, 0, "Name", "Name of the Pass, without view or channel tag");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "channels", 0, 0, INT_MAX, "Channels", "", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_string(func, "chan_id", NULL, 0, "Channel IDs", "Channel names, one character per channel");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_string(func, "layer", NULL, 0, "Layer", "Single layer to add render pass to"); /* NULL ok here */
+
+
func = RNA_def_function(srna, "test_break", "RE_engine_test_break");
RNA_def_function_ui_description(func, "Test if the render operation should been canceled, this is a fast call that should be used regularly for responsiveness");
- prop = RNA_def_boolean(func, "do_break", 0, "Break", "");
- RNA_def_function_return(func, prop);
+ parm = RNA_def_boolean(func, "do_break", 0, "Break", "");
+ RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "active_view_get", "RE_engine_active_view_get");
- prop = RNA_def_string(func, "view", NULL, 0, "View", "Single view active");
- RNA_def_function_return(func, prop);
+ parm = RNA_def_string(func, "view", NULL, 0, "View", "Single view active");
+ RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "active_view_set", "RE_engine_active_view_set");
- RNA_def_string(func, "view", NULL, 0, "View", "Single view to set as active"); /* NULL ok here */
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_string(func, "view", NULL, 0, "View", "Single view to set as active"); /* NULL ok here */
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "camera_shift_x", "RE_engine_get_camera_shift_x");
- prop = RNA_def_pointer(func, "camera", "Object", "", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_boolean(func, "use_spherical_stereo", 0, "Spherical Stereo", "");
- prop = RNA_def_float(func, "shift_x", 0.0f, 0.0f, FLT_MAX, "Shift X", "", 0.0f, FLT_MAX);
- RNA_def_function_return(func, prop);
+ parm = RNA_def_pointer(func, "camera", "Object", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_boolean(func, "use_spherical_stereo", 0, "Spherical Stereo", "");
+ parm = RNA_def_float(func, "shift_x", 0.0f, 0.0f, FLT_MAX, "Shift X", "", 0.0f, FLT_MAX);
+ RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "camera_model_matrix", "RE_engine_get_camera_model_matrix");
- prop = RNA_def_pointer(func, "camera", "Object", "", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_boolean(func, "use_spherical_stereo", 0, "Spherical Stereo", "");
- prop = RNA_def_float_matrix(func, "r_model_matrix", 4, 4, NULL, 0.0f, 0.0f, "Model Matrix", "Normalized camera model matrix", 0.0f, 0.0f);
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_pointer(func, "camera", "Object", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_boolean(func, "use_spherical_stereo", 0, "Spherical Stereo", "");
+ parm = RNA_def_float_matrix(func, "r_model_matrix", 4, 4, NULL, 0.0f, 0.0f, "Model Matrix", "Normalized camera model matrix", 0.0f, 0.0f);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "use_spherical_stereo", "RE_engine_get_spherical_stereo");
- prop = RNA_def_pointer(func, "camera", "Object", "", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_boolean(func, "use_spherical_stereo", 0, "Spherical Stereo", "");
- RNA_def_function_return(func, prop);
+ parm = RNA_def_pointer(func, "camera", "Object", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_boolean(func, "use_spherical_stereo", 0, "Spherical Stereo", "");
+ RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "update_stats", "RE_engine_update_stats");
RNA_def_function_ui_description(func, "Update and signal to redraw render status text");
- prop = RNA_def_string(func, "stats", NULL, 0, "Stats", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_string(func, "info", NULL, 0, "Info", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_string(func, "stats", NULL, 0, "Stats", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_string(func, "info", NULL, 0, "Info", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "frame_set", "RE_engine_frame_set");
RNA_def_function_ui_description(func, "Evaluate scene at a different frame (for motion blur)");
- prop = RNA_def_int(func, "frame", 0, INT_MIN, INT_MAX, "Frame", "", INT_MIN, INT_MAX);
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_float(func, "subframe", 0.0f, 0.0f, 1.0f, "Subframe", "", 0.0f, 1.0f);
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_int(func, "frame", 0, INT_MIN, INT_MAX, "Frame", "", INT_MIN, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_float(func, "subframe", 0.0f, 0.0f, 1.0f, "Subframe", "", 0.0f, 1.0f);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "update_progress", "RE_engine_update_progress");
RNA_def_function_ui_description(func, "Update progress percentage of render");
- prop = RNA_def_float(func, "progress", 0, 0.0f, 1.0f, "", "Percentage of render that's done", 0.0f, 1.0f);
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_float(func, "progress", 0, 0.0f, 1.0f, "", "Percentage of render that's done", 0.0f, 1.0f);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "update_memory_stats", "RE_engine_update_memory_stats");
RNA_def_function_ui_description(func, "Update memory usage statistics");
RNA_def_float(func, "memory_used", 0, 0.0f, FLT_MAX, "", "Current memory usage in megabytes", 0.0f, FLT_MAX);
RNA_def_float(func, "memory_peak", 0, 0.0f, FLT_MAX, "", "Peak memory usage in megabytes", 0.0f, FLT_MAX);
- RNA_def_property_flag(prop, PROP_REQUIRED);
func = RNA_def_function(srna, "report", "RE_engine_report");
RNA_def_function_ui_description(func, "Report info, warning or error messages");
- prop = RNA_def_enum_flag(func, "type", rna_enum_wm_report_items, 0, "Type", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_string(func, "message", NULL, 0, "Report Message", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_enum_flag(func, "type", rna_enum_wm_report_items, 0, "Type", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_string(func, "message", NULL, 0, "Report Message", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "error_set", "RE_engine_set_error_message");
RNA_def_function_ui_description(func, "Set error message displaying after the render is finished");
- prop = RNA_def_string(func, "message", NULL, 0, "Report Message", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_string(func, "message", NULL, 0, "Report Message", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "bind_display_space_shader", "engine_bind_display_space_shader");
RNA_def_function_ui_description(func, "Bind GLSL fragment shader that converts linear colors to display space colors using scene color management settings");
- prop = RNA_def_pointer(func, "scene", "Scene", "", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_pointer(func, "scene", "Scene", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "unbind_display_space_shader", "engine_unbind_display_space_shader");
RNA_def_function_ui_description(func, "Unbind GLSL display space shader, must always be called after binding the shader");
func = RNA_def_function(srna, "support_display_space_shader", "engine_support_display_space_shader");
RNA_def_function_ui_description(func, "Test if GLSL display space shader is supported for the combination of graphics card and scene settings");
- prop = RNA_def_pointer(func, "scene", "Scene", "", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_boolean(func, "supported", 0, "Supported", "");
- RNA_def_function_return(func, prop);
+ parm = RNA_def_pointer(func, "scene", "Scene", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_boolean(func, "supported", 0, "Supported", "");
+ RNA_def_function_return(func, parm);
RNA_define_verify_sdna(0);
@@ -640,6 +714,21 @@ static void rna_def_render_engine(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_highlight_tiles", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", RE_ENGINE_HIGHLIGHT_TILES);
+ 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", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ prop = RNA_def_pointer(func, "srl", "SceneRenderLayer", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ prop = 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);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ prop = 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", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
/* registration */
prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
@@ -689,6 +778,8 @@ static void rna_def_render_engine(BlenderRNA *brna)
static void rna_def_render_result(BlenderRNA *brna)
{
StructRNA *srna;
+ PropertyRNA *prop;
+
FunctionRNA *func;
PropertyRNA *parm;
@@ -701,27 +792,27 @@ static void rna_def_render_result(BlenderRNA *brna)
parm = RNA_def_string_file_name(func, "filename", NULL, FILE_MAX, "File Name",
"Filename to load into this render tile, must be no smaller than "
"the render result");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_define_verify_sdna(0);
- parm = RNA_def_property(srna, "resolution_x", PROP_INT, PROP_PIXEL);
- RNA_def_property_int_sdna(parm, NULL, "rectx");
- RNA_def_property_clear_flag(parm, PROP_EDITABLE);
+ prop = RNA_def_property(srna, "resolution_x", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "rectx");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- parm = RNA_def_property(srna, "resolution_y", PROP_INT, PROP_PIXEL);
- RNA_def_property_int_sdna(parm, NULL, "recty");
- RNA_def_property_clear_flag(parm, PROP_EDITABLE);
+ prop = RNA_def_property(srna, "resolution_y", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "recty");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- parm = RNA_def_property(srna, "layers", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_struct_type(parm, "RenderLayer");
- RNA_def_property_collection_funcs(parm, "rna_RenderResult_layers_begin", "rna_iterator_listbase_next",
+ prop = RNA_def_property(srna, "layers", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "RenderLayer");
+ RNA_def_property_collection_funcs(prop, "rna_RenderResult_layers_begin", "rna_iterator_listbase_next",
"rna_iterator_listbase_end", "rna_iterator_listbase_get",
NULL, NULL, NULL, NULL);
- parm = RNA_def_property(srna, "views", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_struct_type(parm, "RenderView");
- RNA_def_property_collection_funcs(parm, "rna_RenderResult_views_begin", "rna_iterator_listbase_next",
+ prop = RNA_def_property(srna, "views", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "RenderView");
+ RNA_def_property_collection_funcs(prop, "rna_RenderResult_views_begin", "rna_iterator_listbase_next",
"rna_iterator_listbase_end", "rna_iterator_listbase_get",
NULL, NULL, NULL, NULL);
@@ -761,19 +852,29 @@ static void rna_def_render_passes(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "find_by_type", "rna_RenderPass_find_by_type");
RNA_def_function_ui_description(func, "Get the render pass for a given type and view");
parm = RNA_def_enum(func, "pass_type", rna_enum_render_pass_type_items, SCE_PASS_COMBINED, "Pass", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "view", NULL, 0, "View", "Render view to get pass from"); /* NULL ok here */
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "render_pass", "RenderPass", "", "The matching render pass");
RNA_def_function_return(func, parm);
+ func = RNA_def_function(srna, "find_by_name", "rna_RenderPass_find_by_name");
+ RNA_def_function_ui_description(func, "Get the render pass for a given name and view");
+ parm = RNA_def_string(func, "name", RE_PASSNAME_COMBINED, 0, "Pass", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_string(func, "view", NULL, 0, "View", "Render view to get pass from"); /* NULL ok here */
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "render_pass", "RenderPass", "", "The matching render pass");
+ RNA_def_function_return(func, parm);
}
static void rna_def_render_layer(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
+
FunctionRNA *func;
+ PropertyRNA *parm;
srna = RNA_def_struct(brna, "RenderLayer", NULL);
RNA_def_struct_ui_text(srna, "Render Layer", "");
@@ -781,9 +882,9 @@ static void rna_def_render_layer(BlenderRNA *brna)
func = RNA_def_function(srna, "load_from_file", "RE_layer_load_from_file");
RNA_def_function_ui_description(func, "Copies the pixels of this renderlayer from an image file");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
- prop = RNA_def_string(func, "filename", NULL, 0, "Filename",
+ parm = RNA_def_string(func, "filename", NULL, 0, "Filename",
"Filename to load into this render tile, must be no smaller than the renderlayer");
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_int(func, "x", 0, 0, INT_MAX, "Offset X",
"Offset the position to copy from if the image is larger than the render layer", 0, INT_MAX);
RNA_def_int(func, "y", 0, 0, INT_MAX, "Offset Y",
@@ -813,6 +914,11 @@ static void rna_def_render_pass(BlenderRNA *brna)
RNA_define_verify_sdna(0);
+ prop = RNA_def_property(srna, "fullname", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "fullname");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_struct_name_property(srna, prop);
+
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "name");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -826,11 +932,6 @@ static void rna_def_render_pass(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "channels");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "passtype");
- RNA_def_property_enum_items(prop, rna_enum_render_pass_type_items);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
prop = RNA_def_property(srna, "rect", PROP_FLOAT, PROP_NONE);
RNA_def_property_flag(prop, PROP_DYNAMIC);
RNA_def_property_multi_array(prop, 2, NULL);
@@ -841,11 +942,6 @@ static void rna_def_render_pass(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "view_id");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- prop = RNA_def_property(srna, "debug_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "debug_type");
- RNA_def_property_enum_items(prop, rna_enum_render_pass_debug_type_items);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
RNA_define_verify_sdna(1);
}
diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c
index bdf001ed0e1..1ed375706df 100644
--- a/source/blender/makesrna/intern/rna_rigidbody.c
+++ b/source/blender/makesrna/intern/rna_rigidbody.c
@@ -91,7 +91,6 @@ static EnumPropertyItem rigidbody_mesh_source_items[] = {
# include "RBI_api.h"
#endif
-#include "BKE_depsgraph.h"
#include "BKE_rigidbody.h"
#include "WM_api.h"
@@ -507,6 +506,45 @@ static void rna_RigidBodyCon_spring_stiffness_z_set(PointerRNA *ptr, float value
#endif
}
+static void rna_RigidBodyCon_spring_stiffness_ang_x_set(PointerRNA *ptr, float value)
+{
+ RigidBodyCon *rbc = (RigidBodyCon *)ptr->data;
+
+ rbc->spring_stiffness_ang_x = value;
+
+#ifdef WITH_BULLET
+ if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_X)) {
+ RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, value);
+ }
+#endif
+}
+
+static void rna_RigidBodyCon_spring_stiffness_ang_y_set(PointerRNA *ptr, float value)
+{
+ RigidBodyCon *rbc = (RigidBodyCon *)ptr->data;
+
+ rbc->spring_stiffness_ang_y = value;
+
+#ifdef WITH_BULLET
+ if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_Y)) {
+ RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, value);
+ }
+#endif
+}
+
+static void rna_RigidBodyCon_spring_stiffness_ang_z_set(PointerRNA *ptr, float value)
+{
+ RigidBodyCon *rbc = (RigidBodyCon *)ptr->data;
+
+ rbc->spring_stiffness_ang_z = value;
+
+#ifdef WITH_BULLET
+ if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_Z)) {
+ RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, value);
+ }
+#endif
+}
+
static void rna_RigidBodyCon_spring_damping_x_set(PointerRNA *ptr, float value)
{
RigidBodyCon *rbc = (RigidBodyCon *)ptr->data;
@@ -544,6 +582,43 @@ static void rna_RigidBodyCon_spring_damping_z_set(PointerRNA *ptr, float value)
#endif
}
+static void rna_RigidBodyCon_spring_damping_ang_x_set(PointerRNA *ptr, float value)
+{
+ RigidBodyCon *rbc = (RigidBodyCon *)ptr->data;
+
+ rbc->spring_damping_ang_x = value;
+
+#ifdef WITH_BULLET
+ if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_X)) {
+ RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, value);
+ }
+#endif
+}
+
+static void rna_RigidBodyCon_spring_damping_ang_y_set(PointerRNA *ptr, float value)
+{
+ RigidBodyCon *rbc = (RigidBodyCon *)ptr->data;
+
+ rbc->spring_damping_ang_y = value;
+#ifdef WITH_BULLET
+ if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_Y)) {
+ RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, value);
+ }
+#endif
+}
+
+static void rna_RigidBodyCon_spring_damping_ang_z_set(PointerRNA *ptr, float value)
+{
+ RigidBodyCon *rbc = (RigidBodyCon *)ptr->data;
+
+ rbc->spring_damping_ang_z = value;
+#ifdef WITH_BULLET
+ if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_Z)) {
+ RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, value);
+ }
+#endif
+}
+
static void rna_RigidBodyCon_motor_lin_max_impulse_set(PointerRNA *ptr, float value)
{
RigidBodyCon *rbc = (RigidBodyCon *)ptr->data;
@@ -654,7 +729,9 @@ static void rna_def_rigidbody_world(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
+
FunctionRNA *func;
+ PropertyRNA *parm;
srna = RNA_def_struct(brna, "RigidBodyWorld", NULL);
RNA_def_struct_sdna(srna, "RigidBodyWorld");
@@ -737,34 +814,28 @@ static void rna_def_rigidbody_world(BlenderRNA *brna)
func = RNA_def_function(srna, "convex_sweep_test", "rna_RigidBodyWorld_convex_sweep_test");
RNA_def_function_ui_description(func, "Sweep test convex rigidbody against the current rigidbody world");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
-
- prop = RNA_def_pointer(func, "object", "Object", "", "Rigidbody object with a convex collision shape");
- RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL);
- RNA_def_property_clear_flag(prop, PROP_THICK_WRAP);
-
+ parm = RNA_def_pointer(func, "object", "Object", "", "Rigidbody object with a convex collision shape");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
/* ray start and end */
- prop = RNA_def_float_vector(func, "start", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_float_vector(func, "end", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
- RNA_def_property_flag(prop, PROP_REQUIRED);
-
- prop = RNA_def_float_vector(func, "object_location", 3, NULL, -FLT_MAX, FLT_MAX, "Location",
+ parm = RNA_def_float_vector(func, "start", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_float_vector(func, "end", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_float_vector(func, "object_location", 3, NULL, -FLT_MAX, FLT_MAX, "Location",
"The hit location of this sweep test", -1e4, 1e4);
- RNA_def_property_flag(prop, PROP_THICK_WRAP);
- RNA_def_function_output(func, prop);
-
- prop = RNA_def_float_vector(func, "hitpoint", 3, NULL, -FLT_MAX, FLT_MAX, "Hitpoint",
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_function_output(func, parm);
+ parm = RNA_def_float_vector(func, "hitpoint", 3, NULL, -FLT_MAX, FLT_MAX, "Hitpoint",
"The hit location of this sweep test", -1e4, 1e4);
- RNA_def_property_flag(prop, PROP_THICK_WRAP);
- RNA_def_function_output(func, prop);
-
- prop = RNA_def_float_vector(func, "normal", 3, NULL, -FLT_MAX, FLT_MAX, "Normal",
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_function_output(func, parm);
+ parm = RNA_def_float_vector(func, "normal", 3, NULL, -FLT_MAX, FLT_MAX, "Normal",
"The face normal at the sweep test hit location", -1e4, 1e4);
- RNA_def_property_flag(prop, PROP_THICK_WRAP);
- RNA_def_function_output(func, prop);
-
- prop = RNA_def_int(func, "has_hit", 0, 0, 0, "", "If the function has found collision point, value is 1, otherwise 0", 0, 0);
- RNA_def_function_output(func, prop);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_function_output(func, parm);
+ parm = RNA_def_int(func, "has_hit", 0, 0, 0, "", "If the function has found collision point, value is 1, otherwise 0", 0, 0);
+ RNA_def_function_output(func, parm);
}
static void rna_def_rigidbody_object(BlenderRNA *brna)
@@ -1061,6 +1132,21 @@ static void rna_def_rigidbody_constraint(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Z Spring", "Enable spring on Z axis");
RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
+ prop = RNA_def_property(srna, "use_spring_ang_x", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_SPRING_ANG_X);
+ RNA_def_property_ui_text(prop, "X Angle Spring", "Enable spring on X rotational axis");
+ RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
+
+ prop = RNA_def_property(srna, "use_spring_ang_y", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_SPRING_ANG_Y);
+ RNA_def_property_ui_text(prop, "Y Angle Spring", "Enable spring on Y rotational axis");
+ RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
+
+ prop = RNA_def_property(srna, "use_spring_ang_z", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_SPRING_ANG_Z);
+ RNA_def_property_ui_text(prop, "Z Angle Spring", "Enable spring on Z rotational axis");
+ RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
+
prop = RNA_def_property(srna, "use_motor_lin", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_MOTOR_LIN);
RNA_def_property_boolean_funcs(prop, NULL, "rna_RigidBodyCon_use_motor_lin_set");
@@ -1178,6 +1264,33 @@ static void rna_def_rigidbody_constraint(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Z Axis Stiffness", "Stiffness on the Z axis");
RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
+ prop = RNA_def_property(srna, "spring_stiffness_ang_x", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "spring_stiffness_ang_x");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3);
+ RNA_def_property_float_default(prop, 10.0f);
+ RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_stiffness_ang_x_set", NULL);
+ RNA_def_property_ui_text(prop, "X Angle Stiffness", "Stiffness on the X rotational axis");
+ RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
+
+ prop = RNA_def_property(srna, "spring_stiffness_ang_y", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "spring_stiffness_ang_y");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3);
+ RNA_def_property_float_default(prop, 10.0f);
+ RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_stiffness_ang_y_set", NULL);
+ RNA_def_property_ui_text(prop, "Y Angle Stiffness", "Stiffness on the Y rotational axis");
+ RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
+
+ prop = RNA_def_property(srna, "spring_stiffness_ang_z", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "spring_stiffness_ang_z");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3);
+ RNA_def_property_float_default(prop, 10.0f);
+ RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_stiffness_ang_z_set", NULL);
+ RNA_def_property_ui_text(prop, "Z Angle Stiffness", "Stiffness on the Z rotational axis");
+ RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
+
prop = RNA_def_property(srna, "spring_damping_x", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "spring_damping_x");
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -1202,6 +1315,30 @@ static void rna_def_rigidbody_constraint(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Damping Z", "Damping on the Z axis");
RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
+ prop = RNA_def_property(srna, "spring_damping_ang_x", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "spring_damping_ang_x");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_damping_ang_x_set", NULL);
+ RNA_def_property_ui_text(prop, "Damping X Angle", "Damping on the X rotational axis");
+ RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
+
+ prop = RNA_def_property(srna, "spring_damping_ang_y", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "spring_damping_ang_y");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_damping_ang_y_set", NULL);
+ RNA_def_property_ui_text(prop, "Damping Y Angle", "Damping on the Y rotational axis");
+ RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
+
+ prop = RNA_def_property(srna, "spring_damping_ang_z", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "spring_damping_ang_z");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_damping_ang_z_set", NULL);
+ RNA_def_property_ui_text(prop, "Damping Z Angle", "Damping on the Z rotational axis");
+ RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
+
prop = RNA_def_property(srna, "motor_lin_target_velocity", PROP_FLOAT, PROP_UNIT_VELOCITY);
RNA_def_property_float_sdna(prop, NULL, "motor_lin_target_velocity");
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index 727bdac087b..abded187b33 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -178,7 +178,7 @@ static int rna_idproperty_known(CollectionPropertyIterator *iter, void *data)
* for the second loop where we go over unknown id properties */
do {
for (prop = ptype->cont.properties.first; prop; prop = prop->next)
- if ((prop->flag & PROP_BUILTIN) == 0 && STREQ(prop->identifier, idprop->name))
+ if ((prop->flag_internal & PROP_INTERN_BUILTIN) == 0 && STREQ(prop->identifier, idprop->name))
return 1;
} while ((ptype = ptype->base));
@@ -191,7 +191,7 @@ static int rna_property_builtin(CollectionPropertyIterator *UNUSED(iter), void *
/* function to skip builtin rna properties */
- return (prop->flag & PROP_BUILTIN);
+ return (prop->flag_internal & PROP_INTERN_BUILTIN);
}
static int rna_function_builtin(CollectionPropertyIterator *UNUSED(iter), void *data)
@@ -385,7 +385,7 @@ int rna_builtin_properties_lookup_string(PointerRNA *ptr, const char *key, Point
}
else {
for (prop = srna->cont.properties.first; prop; prop = prop->next) {
- if (!(prop->flag & PROP_BUILTIN) && STREQ(prop->identifier, key)) {
+ if (!(prop->flag_internal & PROP_INTERN_BUILTIN) && STREQ(prop->identifier, key)) {
propptr.type = &RNA_Property;
propptr.data = prop;
@@ -557,19 +557,19 @@ static int rna_Property_animatable_get(PointerRNA *ptr)
static int rna_Property_use_output_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- return (prop->flag & PROP_OUTPUT) != 0;
+ return (prop->flag_parameter & PARM_OUTPUT) != 0;
}
static int rna_Property_is_required_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- return (prop->flag & PROP_REQUIRED) != 0;
+ return (prop->flag_parameter & PARM_REQUIRED) != 0;
}
static int rna_Property_is_argument_optional_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- return (prop->flag & PROP_PYFUNC_OPTIONAL) != 0;
+ return (prop->flag_parameter & PARM_PYFUNC_OPTIONAL) != 0;
}
static int rna_Property_is_never_none_get(PointerRNA *ptr)
@@ -625,7 +625,7 @@ static int rna_Property_is_registered_optional_get(PointerRNA *ptr)
static int rna_Property_is_runtime_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- return (prop->flag & PROP_RUNTIME) != 0;
+ return (prop->flag_internal & PROP_INTERN_RUNTIME) != 0;
}
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 3185411c838..7b0174bfb5d 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -32,6 +32,7 @@
#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"
@@ -40,14 +41,19 @@
#include "IMB_imbuf_types.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
#include "BKE_editmesh.h"
#include "BKE_paint.h"
+#include "ED_object.h"
+
#include "GPU_extensions.h"
+#include "DRW_engine.h"
+
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -87,7 +93,8 @@ EnumPropertyItem rna_enum_exr_codec_items[] = {
{R_IMF_EXR_CODEC_B44, "B44", 0, "B44 (lossy)", ""},
{R_IMF_EXR_CODEC_B44A, "B44A", 0, "B44A (lossy)", ""},
{R_IMF_EXR_CODEC_DWAA, "DWAA", 0, "DWAA (lossy)", ""},
- {R_IMF_EXR_CODEC_DWAB, "DWAB", 0, "DWAB (lossy)", ""},
+ /* NOTE: Commented out for until new OpenEXR is released, see T50673. */
+ /* {R_IMF_EXR_CODEC_DWAB, "DWAB", 0, "DWAB (lossy)", ""}, */
{0, NULL, 0, NULL, NULL}
};
#endif
@@ -282,16 +289,11 @@ EnumPropertyItem rna_enum_image_type_items[] = {
{R_IMF_IMTYPE_FRAMESERVER, "FRAMESERVER", ICON_FILE_SCRIPT, "Frame Server", "Output image to a frameserver"},
#endif
#ifdef WITH_FFMPEG
- {R_IMF_IMTYPE_H264, "H264", ICON_FILE_MOVIE, "H.264", "Output video in H.264 format"},
- {R_IMF_IMTYPE_FFMPEG, "FFMPEG", ICON_FILE_MOVIE, "MPEG", "Output video in MPEG format"},
- {R_IMF_IMTYPE_THEORA, "THEORA", ICON_FILE_MOVIE, "Ogg Theora", "Output video in Ogg format"},
+ {R_IMF_IMTYPE_FFMPEG, "FFMPEG", ICON_FILE_MOVIE, "FFmpeg video", "The most versatile way to output video files"},
#endif
#ifdef WITH_QUICKTIME
{R_IMF_IMTYPE_QUICKTIME, "QUICKTIME", ICON_FILE_MOVIE, "QuickTime", "Output video in Quicktime format"},
#endif
-#ifdef WITH_FFMPEG
- {R_IMF_IMTYPE_XVID, "XVID", ICON_FILE_MOVIE, "Xvid", "Output video in Xvid format"},
-#endif
{0, NULL, 0, NULL, NULL}
};
@@ -411,9 +413,42 @@ EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
+EnumPropertyItem rna_enum_gpencil_interpolation_mode_items[] = {
+ /* interpolation */
+ {0, "", 0, N_("Interpolation"), "Standard transitions between keyframes"},
+ {GP_IPO_LINEAR, "LINEAR", ICON_IPO_LINEAR, "Linear", "Straight-line interpolation between A and B (i.e. no ease in/out)"},
+ {GP_IPO_CURVEMAP, "CUSTOM", ICON_IPO_BEZIER, "Custom", "Custom interpolation defined using a curve map"},
+
+ /* easing */
+ {0, "", 0, N_("Easing (by strength)"), "Predefined inertial transitions, useful for motion graphics (from least to most ''dramatic'')"},
+ {GP_IPO_SINE, "SINE", ICON_IPO_SINE, "Sinusoidal", "Sinusoidal easing (weakest, almost linear but with a slight curvature)"},
+ {GP_IPO_QUAD, "QUAD", ICON_IPO_QUAD, "Quadratic", "Quadratic easing"},
+ {GP_IPO_CUBIC, "CUBIC", ICON_IPO_CUBIC, "Cubic", "Cubic easing"},
+ {GP_IPO_QUART, "QUART", ICON_IPO_QUART, "Quartic", "Quartic easing"},
+ {GP_IPO_QUINT, "QUINT", ICON_IPO_QUINT, "Quintic", "Quintic easing"},
+ {GP_IPO_EXPO, "EXPO", ICON_IPO_EXPO, "Exponential", "Exponential easing (dramatic)"},
+ {GP_IPO_CIRC, "CIRC", ICON_IPO_CIRC, "Circular", "Circular easing (strongest and most dynamic)"},
+
+ {0, "", 0, N_("Dynamic Effects"), "Simple physics-inspired easing effects"},
+ {GP_IPO_BACK, "BACK", ICON_IPO_BACK, "Back", "Cubic easing with overshoot and settle"},
+ {GP_IPO_BOUNCE, "BOUNCE", ICON_IPO_BOUNCE, "Bounce", "Exponentially decaying parabolic bounce, like when objects collide"},
+ {GP_IPO_ELASTIC, "ELASTIC", ICON_IPO_ELASTIC, "Elastic", "Exponentially decaying sine wave, like an elastic band"},
+
+ {0, NULL, 0, NULL, NULL}
+};
+
+EnumPropertyItem rna_enum_layer_collection_mode_settings_type_items[] = {
+ {COLLECTION_MODE_OBJECT, "OBJECT", 0, "Object", ""},
+ {COLLECTION_MODE_EDIT, "EDIT", 0, "Edit", ""},
+ {COLLECTION_MODE_PAINT_WEIGHT, "PAINT_WEIGHT", 0, "Weight Paint", ""},
+ {COLLECTION_MODE_PAINT_WEIGHT, "PAINT_VERTEX", 0, "Vertex Paint", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
#ifdef RNA_RUNTIME
#include "DNA_anim_types.h"
+#include "DNA_color_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_mesh_types.h"
@@ -424,14 +459,18 @@ EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = {
#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_idprop.h"
#include "BKE_mesh.h"
#include "BKE_sound.h"
#include "BKE_screen.h"
@@ -440,17 +479,47 @@ EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = {
#include "BKE_freestyle.h"
#include "BKE_gpencil.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "ED_info.h"
#include "ED_node.h"
#include "ED_view3d.h"
#include "ED_mesh.h"
#include "ED_keyframing.h"
#include "ED_image.h"
+#include "ED_scene.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#ifdef WITH_FREESTYLE
#include "FRS_freestyle.h"
#endif
+/* Grease Pencil Interpolation settings */
+static char *rna_GPencilInterpolateSettings_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_strdup("tool_settings.gpencil_interpolate");
+}
+
+static void rna_GPencilInterpolateSettings_type_set(PointerRNA *ptr, int value)
+{
+ GP_Interpolate_Settings *settings = (GP_Interpolate_Settings *)ptr->data;
+
+ /* NOTE: This cast should be fine, as we have a small + finite set of values (eGP_Interpolate_Type)
+ * that should fit well within a char
+ */
+ settings->type = (char)value;
+
+ /* init custom interpolation curve here now the first time it's used */
+ if ((settings->type == GP_IPO_CURVEMAP) &&
+ (settings->custom_ipo == NULL))
+ {
+ 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, int setactive)
{
@@ -561,11 +630,11 @@ static void rna_SpaceImageEditor_uv_sculpt_update(Main *bmain, Scene *scene, Poi
static int rna_Scene_object_bases_lookup_string(PointerRNA *ptr, const char *key, PointerRNA *r_ptr)
{
Scene *scene = (Scene *)ptr->data;
- Base *base;
+ BaseLegacy *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);
+ *r_ptr = rna_pointer_inherit_refine(ptr, &RNA_ObjectBaseLegacy, base);
return true;
}
}
@@ -578,13 +647,13 @@ 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);
+ return rna_pointer_inherit_refine(&iter->parent, &RNA_Object, ((BaseLegacy *)internal->link)->object);
}
-static Base *rna_Scene_object_link(Scene *scene, bContext *C, ReportList *reports, Object *ob)
+static BaseLegacy *rna_Scene_object_link(Scene *scene, bContext *C, ReportList *reports, Object *ob)
{
Scene *scene_act = CTX_data_scene(C);
- Base *base;
+ BaseLegacy *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);
@@ -602,11 +671,11 @@ static Base *rna_Scene_object_link(Scene *scene, bContext *C, ReportList *report
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);
+ DEG_relations_tag_update(CTX_data_main(C));
+ DEG_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(G.main); */
+ /* DEG_srelations_tag_update(G.main); */
WM_main_add_notifier(NC_SCENE | ND_OB_ACTIVE, scene);
@@ -615,7 +684,7 @@ static Base *rna_Scene_object_link(Scene *scene, bContext *C, ReportList *report
static void rna_Scene_object_unlink(Scene *scene, ReportList *reports, Object *ob)
{
- Base *base = BKE_scene_base_find(scene, ob);
+ BaseLegacy *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;
@@ -634,7 +703,7 @@ static void rna_Scene_object_unlink(Scene *scene, ReportList *reports, Object *o
id_us_min(&ob->id);
/* needed otherwise the depgraph will contain freed objects which can crash, see [#20958] */
- DAG_relations_tag_update(G.main);
+ DEG_relations_tag_update(G.main);
WM_main_add_notifier(NC_SCENE | ND_OB_ACTIVE, scene);
}
@@ -697,19 +766,21 @@ static int rna_Scene_active_layer_get(PointerRNA *ptr)
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);
+ WM_windows_scene_data_sync(&wm->windows, scene);
}
-static void rna_Scene_layer_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Scene_layer_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(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);
+ DEG_on_visible_update(bmain, false);
+
+ /* No need to sync scene data here (WM_windows_scene_data_sync), handled through notifier. */
}
static void rna_Scene_fps_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
@@ -747,6 +818,21 @@ static void rna_Scene_frame_current_set(PointerRNA *ptr, int value)
data->r.cfra = value;
}
+static float rna_Scene_frame_float_get(PointerRNA *ptr)
+{
+ Scene *data = (Scene *)ptr->data;
+ return (float)data->r.cfra + data->r.subframe;
+}
+
+static void rna_Scene_frame_float_set(PointerRNA *ptr, float value)
+{
+ Scene *data = (Scene *)ptr->data;
+ /* if negative frames aren't allowed, then we can't use them */
+ FRAMENUMBER_MIN_CLAMP(value);
+ data->r.cfra = (int)value;
+ data->r.subframe = value - data->r.cfra;
+}
+
static float rna_Scene_frame_current_final_get(PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->data;
@@ -827,6 +913,12 @@ static void rna_Scene_preview_range_end_frame_set(PointerRNA *ptr, int value)
data->r.pefra = value;
}
+static void rna_Scene_show_subframe_update(Main *UNUSED(bmain), Scene *UNUSED(current_scene), PointerRNA *ptr)
+{
+ Scene *scene = (Scene *)ptr->id.data;
+ scene->r.subframe = 0.0f;
+}
+
static void rna_Scene_frame_update(Main *bmain, Scene *UNUSED(current_scene), PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->id.data;
@@ -922,6 +1014,53 @@ static char *rna_RenderSettings_path(PointerRNA *UNUSED(ptr))
return BLI_sprintfN("render");
}
+static char *rna_ImageFormatSettings_path(PointerRNA *ptr)
+{
+ ImageFormatData *imf = (ImageFormatData *)ptr->data;
+ ID *id = ptr->id.data;
+
+ switch (GS(id->name)) {
+ case ID_SCE:
+ {
+ Scene *scene = (Scene *)id;
+
+ if (&scene->r.im_format == imf) {
+ return BLI_sprintfN("render.image_settings");
+ }
+ else if (&scene->r.bake.im_format == imf) {
+ return BLI_sprintfN("render.bake.image_settings");
+ }
+ return BLI_sprintfN("..");
+ }
+ case ID_NT:
+ {
+ bNodeTree *ntree = (bNodeTree *)id;
+ bNode *node;
+
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_OUTPUT_FILE) {
+ if (&((NodeImageMultiFile *)node->storage)->format == imf) {
+ return BLI_sprintfN("nodes['%s'].format", node->name);
+ }
+ else {
+ bNodeSocket *sock;
+
+ for (sock = node->inputs.first; sock; sock = sock->next) {
+ NodeImageMultiFileSocket *sockdata = sock->storage;
+ if (&sockdata->format == imf) {
+ return BLI_sprintfN("nodes['%s'].file_slots['%s'].format", node->name, sockdata->path);
+ }
+ }
+ }
+ }
+ }
+ return BLI_sprintfN("..");
+ }
+ default:
+ return BLI_sprintfN("..");
+ }
+}
+
static int rna_RenderSettings_threads_get(PointerRNA *ptr)
{
RenderData *rd = (RenderData *)ptr->data;
@@ -1338,7 +1477,7 @@ static SceneRenderLayer *rna_RenderLayer_new(ID *id, RenderData *UNUSED(rd), con
Scene *scene = (Scene *)id;
SceneRenderLayer *srl = BKE_scene_add_render_layer(scene, 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 srl;
@@ -1358,7 +1497,7 @@ static void rna_RenderLayer_remove(
RNA_POINTER_INVALIDATE(srl_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);
}
@@ -1478,14 +1617,22 @@ static void rna_Scene_glsl_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poi
{
Scene *scene = (Scene *)ptr->id.data;
- DAG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, 0);
+}
+
+static void rna_Scene_world_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ Scene *sc = (Scene *)ptr->id.data;
+
+ rna_Scene_glsl_update(bmain, scene, ptr);
+ WM_main_add_notifier(NC_WORLD | ND_WORLD, &sc->id);
}
static void rna_Scene_freestyle_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->id.data;
- DAG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, 0);
}
static void rna_Scene_use_view_map_cache_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
@@ -1495,6 +1642,18 @@ static void rna_Scene_use_view_map_cache_update(Main *UNUSED(bmain), Scene *UNUS
#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;
+}
+
static void rna_SceneRenderLayer_name_set(PointerRNA *ptr, const char *value)
{
Scene *scene = (Scene *)ptr->id.data;
@@ -1599,11 +1758,18 @@ static void rna_SceneRenderLayer_pass_update(Main *bmain, Scene *activescene, Po
Scene *scene = (Scene *)ptr->id.data;
if (scene->nodetree)
- ntreeCompositForceHidden(scene->nodetree);
-
+ ntreeCompositUpdateRLayers(scene->nodetree);
+
rna_Scene_glsl_update(bmain, activescene, ptr);
}
+static void rna_SceneRenderLayer_update_render_passes(ID *id)
+{
+ Scene *scene = (Scene *)id;
+ if (scene->nodetree)
+ ntreeCompositUpdateRLayers(scene->nodetree);
+}
+
static void rna_Scene_use_nodes_update(bContext *C, PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->data;
@@ -1615,23 +1781,25 @@ static void rna_Scene_use_nodes_update(bContext *C, PointerRNA *ptr)
static void rna_Physics_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->id.data;
- Base *base;
-
- for (base = scene->base.first; base; base = base->next)
- BKE_ptcache_object_reset(scene, base->object, PTCACHE_RESET_DEPSGRAPH);
+ FOREACH_SCENE_OBJECT(scene, ob)
+ {
+ BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH);
+ }
+ FOREACH_SCENE_OBJECT_END
}
static void rna_Scene_editmesh_select_mode_set(PointerRNA *ptr, const int *value)
{
Scene *scene = (Scene *)ptr->id.data;
+ SceneLayer *sl = BKE_scene_layer_context_active_PLACEHOLDER(scene);
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 (sl->basact) {
+ Mesh *me = BKE_mesh_from_object(sl->basact->object);
if (me && me->edit_btmesh && me->edit_btmesh->selectmode != flag) {
me->edit_btmesh->selectmode = flag;
EDBM_selectmode_set(me->edit_btmesh);
@@ -1640,12 +1808,13 @@ static void rna_Scene_editmesh_select_mode_set(PointerRNA *ptr, const int *value
}
}
-static void rna_Scene_editmesh_select_mode_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
+static void rna_Scene_editmesh_select_mode_update(Main *UNUSED(bmain), bContext *C, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
+ SceneLayer *sl = CTX_data_scene_layer(C);
Mesh *me = NULL;
- if (scene->basact) {
- me = BKE_mesh_from_object(scene->basact->object);
+ if (sl->basact) {
+ me = BKE_mesh_from_object(sl->basact->object);
if (me && me->edit_btmesh == NULL)
me = NULL;
}
@@ -1667,7 +1836,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);
}
}
@@ -1682,7 +1851,7 @@ static void object_simplify_update(Object *ob)
}
}
-static void rna_Scene_use_simplify_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_Scene_use_simplify_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
Scene *sce = ptr->id.data;
Scene *sce_iter;
@@ -1693,6 +1862,7 @@ static void rna_Scene_use_simplify_update(Main *bmain, Scene *UNUSED(scene), Poi
object_simplify_update(base->object);
WM_main_add_notifier(NC_GEOM | ND_DATA, NULL);
+ DEG_id_tag_update(&scene->id, 0);
}
static void rna_Scene_simplify_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
@@ -1775,6 +1945,71 @@ static void rna_GameSettings_exit_key_set(PointerRNA *ptr, int value)
gm->exitkey = value;
}
+static StructRNA *rna_SceneLayerSettings_refine(PointerRNA *ptr)
+{
+ IDProperty *props = (IDProperty *)ptr->data;
+ BLI_assert(props && props->type == IDP_GROUP);
+
+ switch (props->subtype) {
+ case IDP_GROUP_SUB_ENGINE_RENDER:
+#ifdef WITH_CLAY_ENGINE
+ if (STREQ(props->name, RE_engine_id_BLENDER_CLAY)) {
+ return &RNA_SceneLayerEngineSettingsClay;
+ }
+#endif
+ if (STREQ(props->name, RE_engine_id_BLENDER_EEVEE)) {
+ return &RNA_SceneLayerEngineSettingsEevee;
+ }
+ break;
+ case IDP_GROUP_SUB_MODE_OBJECT:
+ case IDP_GROUP_SUB_MODE_EDIT:
+ case IDP_GROUP_SUB_MODE_PAINT_WEIGHT:
+ case IDP_GROUP_SUB_MODE_PAINT_VERTEX:
+ default:
+ BLI_assert(!"Mode not fully implemented");
+ break;
+ }
+
+ return &RNA_SceneLayerSettings;
+}
+
+static StructRNA *rna_LayerCollectionSettings_refine(PointerRNA *ptr)
+{
+ IDProperty *props = (IDProperty *)ptr->data;
+ BLI_assert(props && props->type == IDP_GROUP);
+
+ switch (props->subtype) {
+ case IDP_GROUP_SUB_ENGINE_RENDER:
+#ifdef WITH_CLAY_ENGINE
+ if (STREQ(props->name, RE_engine_id_BLENDER_CLAY)) {
+ return &RNA_LayerCollectionEngineSettingsClay;
+ }
+#endif
+ if (STREQ(props->name, RE_engine_id_BLENDER_EEVEE)) {
+ /* printf("Mode not fully implemented\n"); */
+ return &RNA_LayerCollectionSettings;
+ }
+ break;
+ case IDP_GROUP_SUB_MODE_OBJECT:
+ return &RNA_LayerCollectionModeSettingsObject;
+ break;
+ case IDP_GROUP_SUB_MODE_EDIT:
+ return &RNA_LayerCollectionModeSettingsEdit;
+ break;
+ case IDP_GROUP_SUB_MODE_PAINT_WEIGHT:
+ return &RNA_LayerCollectionModeSettingsPaintWeight;
+ break;
+ case IDP_GROUP_SUB_MODE_PAINT_VERTEX:
+ return &RNA_LayerCollectionModeSettingsPaintVertex;
+ break;
+ default:
+ BLI_assert(!"Mode not fully implemented");
+ break;
+ }
+
+ return &RNA_LayerCollectionSettings;
+}
+
static TimeMarker *rna_TimeLine_add(Scene *scene, const char name[], int frame)
{
TimeMarker *marker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
@@ -1830,9 +2065,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);
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Brush *br = BKE_paint_brush(BKE_paint_get_active(scene, sl));
WM_main_add_notifier(NC_BRUSH | NA_EDITED, br);
}
@@ -1855,11 +2092,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))
@@ -1873,18 +2110,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(Main *UNUSED(bmain), bContext *C, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
+ SceneLayer *sl = CTX_data_scene_layer(C);
Mesh *me = NULL;
- if (scene->basact) {
- me = BKE_mesh_from_object(scene->basact->object);
+ if (sl->basact) {
+ me = BKE_mesh_from_object(sl->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);
}
}
@@ -1899,11 +2137,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;
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *ob = OBACT_NEW;
+
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);
}
}
@@ -1914,7 +2154,7 @@ static void rna_SceneCamera_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Po
Object *camera = scene->camera;
if (camera)
- DAG_id_tag_update(&camera->id, 0);
+ DEG_id_tag_update(&camera->id, 0);
}
static void rna_SceneSequencer_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
@@ -1951,7 +2191,7 @@ static FreestyleLineSet *rna_FreestyleSettings_lineset_add(
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;
@@ -1970,7 +2210,7 @@ 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);
}
@@ -2007,7 +2247,7 @@ static FreestyleModuleConfig *rna_FreestyleSettings_module_add(ID *id, Freestyle
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;
@@ -2029,7 +2269,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);
}
@@ -2090,11 +2330,872 @@ static void rna_Stereo3dFormat_update(Main *UNUSED(bmain), Scene *UNUSED(scene),
static int rna_gpu_is_hq_supported_get(PointerRNA *UNUSED(ptr))
{
- return GPU_instanced_drawing_support() && GPU_geometry_shader_support();
+ return true;
+}
+
+static void rna_SceneCollection_name_set(PointerRNA *ptr, const char *value)
+{
+ Scene *scene = (Scene *)ptr->id.data;
+ SceneCollection *sc = (SceneCollection *)ptr->data;
+ BKE_collection_rename(scene, sc, value);
}
+static void rna_SceneCollection_filter_set(PointerRNA *ptr, const char *value)
+{
+ Scene *scene = (Scene *)ptr->id.data;
+ SceneCollection *sc = (SceneCollection *)ptr->data;
+ BLI_strncpy_utf8(sc->filter, value, sizeof(sc->filter));
+
+ TODO_LAYER_SYNC_FILTER;
+ (void)scene;
+}
+
+static PointerRNA rna_SceneCollection_objects_get(CollectionPropertyIterator *iter)
+{
+ ListBaseIterator *internal = &iter->internal.listbase;
+
+ /* we are actually iterating a LinkData list, so override get */
+ return rna_pointer_inherit_refine(&iter->parent, &RNA_Object, ((LinkData *)internal->link)->data);
+}
+
+static int rna_SceneCollection_move_above(ID *id, SceneCollection *sc_src, Main *bmain, SceneCollection *sc_dst)
+{
+ Scene *scene = (Scene *)id;
+
+ if (!BKE_collection_move_above(scene, sc_dst, sc_src)) {
+ return 0;
+ }
+
+ DEG_relations_tag_update(bmain);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+
+ return 1;
+}
+
+static int rna_SceneCollection_move_below(ID *id, SceneCollection *sc_src, Main *bmain, SceneCollection *sc_dst)
+{
+ Scene *scene = (Scene *)id;
+
+ if (!BKE_collection_move_below(scene, sc_dst, sc_src)) {
+ return 0;
+ }
+
+ DEG_relations_tag_update(bmain);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+
+ return 1;
+}
+
+static int rna_SceneCollection_move_into(ID *id, SceneCollection *sc_src, Main *bmain, SceneCollection *sc_dst)
+{
+ Scene *scene = (Scene *)id;
+
+ if (!BKE_collection_move_into(scene, sc_dst, sc_src)) {
+ return 0;
+ }
+
+ DEG_relations_tag_update(bmain);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+
+ return 1;
+}
+
+static SceneCollection *rna_SceneCollection_new(
+ ID *id, SceneCollection *sc_parent, Main *bmain, const char *name)
+{
+ Scene *scene = (Scene *)id;
+ SceneCollection *sc = BKE_collection_add(scene, sc_parent, name);
+
+ DEG_relations_tag_update(bmain);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+
+ return sc;
+}
+
+static void rna_SceneCollection_remove(
+ ID *id, SceneCollection *sc_parent, Main *bmain, ReportList *reports, PointerRNA *sc_ptr)
+{
+ Scene *scene = (Scene *)id;
+ SceneCollection *sc = sc_ptr->data;
+
+ const int index = BLI_findindex(&sc_parent->scene_collections, sc);
+ if (index == -1) {
+ BKE_reportf(reports, RPT_ERROR, "Collection '%s' is not a sub-collection of '%s'",
+ sc->name, sc_parent->name);
+ return;
+ }
+
+ if (!BKE_collection_remove(scene, sc)) {
+ BKE_reportf(reports, RPT_ERROR, "Collection '%s' could not be removed from collection '%s'",
+ sc->name, sc_parent->name);
+ return;
+ }
+
+ RNA_POINTER_INVALIDATE(sc_ptr);
+
+ DEG_relations_tag_update(bmain);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+}
+
+static int rna_SceneCollection_objects_active_index_get(PointerRNA *ptr)
+{
+ SceneCollection *sc = (SceneCollection *)ptr->data;
+ return sc->active_object_index;
+}
+
+static void rna_SceneCollection_objects_active_index_set(PointerRNA *ptr, int value)
+{
+ SceneCollection *sc = (SceneCollection *)ptr->data;
+ sc->active_object_index = value;
+}
+
+static void rna_SceneCollection_objects_active_index_range(
+ PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
+{
+ SceneCollection *sc = (SceneCollection *)ptr->data;
+ *min = 0;
+ *max = max_ii(0, BLI_listbase_count(&sc->objects) - 1);
+}
+
+void rna_SceneCollection_object_link(
+ ID *id, SceneCollection *sc, Main *bmain, ReportList *reports, Object *ob)
+{
+ Scene *scene = (Scene *)id;
+
+ if (BLI_findptr(&sc->objects, ob, offsetof(LinkData, data))) {
+ BKE_reportf(reports, RPT_ERROR, "Object '%s' is already in collection '%s'", ob->id.name + 2, sc->name);
+ return;
+ }
+
+ BKE_collection_object_add(scene, sc, ob);
+
+ /* TODO(sergey): Only update relations for the current scene. */
+ DEG_relations_tag_update(bmain);
+
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update(&scene->id, 0);
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+
+ WM_main_add_notifier(NC_SCENE | ND_LAYER | ND_OB_ACTIVE, scene);
+}
+
+static void rna_SceneCollection_object_unlink(
+ ID *id, SceneCollection *sc, Main *bmain, ReportList *reports, Object *ob)
+{
+ Scene *scene = (Scene *)id;
+
+ if (!BLI_findptr(&sc->objects, ob, offsetof(LinkData, data))) {
+ BKE_reportf(reports, RPT_ERROR, "Object '%s' is not in collection '%s'", ob->id.name + 2, sc->name);
+ return;
+ }
+
+ BKE_collection_object_remove(bmain, scene, sc, ob, false);
+
+ /* needed otherwise the depgraph will contain freed objects which can crash, see [#20958] */
+ DEG_relations_tag_update(bmain);
+
+ WM_main_add_notifier(NC_SCENE | ND_LAYER | ND_OB_ACTIVE, scene);
+}
+
+/****** layer collection engine settings *******/
+
+#define RNA_LAYER_ENGINE_GET_SET(_TYPE_, _ENGINE_, _MODE_, _NAME_) \
+static _TYPE_ rna_LayerEngineSettings_##_ENGINE_##_##_NAME_##_get(PointerRNA *ptr) \
+{ \
+ IDProperty *props = (IDProperty *)ptr->data; \
+ return BKE_collection_engine_property_value_get_##_TYPE_(props, #_NAME_); \
+} \
+ \
+static void rna_LayerEngineSettings_##_ENGINE_##_##_NAME_##_set(PointerRNA *ptr, _TYPE_ value) \
+{ \
+ IDProperty *props = (IDProperty *)ptr->data; \
+ BKE_collection_engine_property_value_set_##_TYPE_(props, #_NAME_, value); \
+}
+
+#define RNA_LAYER_ENGINE_GET_SET_ARRAY(_TYPE_, _ENGINE_, _MODE_, _NAME_, _LEN_) \
+static void rna_LayerEngineSettings_##_ENGINE_##_##_NAME_##_get(PointerRNA *ptr, _TYPE_ *values) \
+{ \
+ IDProperty *props = (IDProperty *)ptr->data; \
+ IDProperty *idprop = IDP_GetPropertyFromGroup(props, #_NAME_); \
+ if (idprop != NULL) { \
+ memcpy(values, IDP_Array(idprop), sizeof(_TYPE_) * idprop->len); \
+ } \
+} \
+ \
+static void rna_LayerEngineSettings_##_ENGINE_##_##_NAME_##_set(PointerRNA *ptr, const _TYPE_ *values) \
+{ \
+ IDProperty *props = (IDProperty *)ptr->data; \
+ BKE_collection_engine_property_value_set_##_TYPE_##_array(props, #_NAME_, values); \
+}
+
+#define RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(_NAME_) \
+ RNA_LAYER_ENGINE_GET_SET(float, Clay, COLLECTION_MODE_NONE, _NAME_)
+
+#define RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT_ARRAY(_NAME_, _LEN_) \
+ RNA_LAYER_ENGINE_GET_SET_ARRAY(float, Clay, COLLECTION_MODE_NONE, _NAME_, _LEN_)
+
+#define RNA_LAYER_ENGINE_CLAY_GET_SET_INT(_NAME_) \
+ RNA_LAYER_ENGINE_GET_SET(int, Clay, COLLECTION_MODE_NONE, _NAME_)
+
+#define RNA_LAYER_ENGINE_CLAY_GET_SET_BOOL(_NAME_) \
+ RNA_LAYER_ENGINE_GET_SET(bool, Clay, COLLECTION_MODE_NONE, _NAME_)
+
+#define RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(_NAME_) \
+ RNA_LAYER_ENGINE_GET_SET(float, Eevee, COLLECTION_MODE_NONE, _NAME_)
+
+#define RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(_NAME_) \
+ RNA_LAYER_ENGINE_GET_SET(int, Eevee, COLLECTION_MODE_NONE, _NAME_)
+
+#define RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(_NAME_) \
+ RNA_LAYER_ENGINE_GET_SET(bool, Eevee, COLLECTION_MODE_NONE, _NAME_)
+
+/* mode engines */
+
+#define RNA_LAYER_MODE_OBJECT_GET_SET_FLOAT(_NAME_) \
+ RNA_LAYER_ENGINE_GET_SET(float, ObjectMode, COLLECTION_MODE_OBJECT, _NAME_)
+
+#define RNA_LAYER_MODE_OBJECT_GET_SET_INT(_NAME_) \
+ RNA_LAYER_ENGINE_GET_SET(int, ObjectMode, COLLECTION_MODE_OBJECT, _NAME_)
+
+#define RNA_LAYER_MODE_OBJECT_GET_SET_BOOL(_NAME_) \
+ RNA_LAYER_ENGINE_GET_SET(bool, ObjectMode, COLLECTION_MODE_OBJECT, _NAME_)
+
+#define RNA_LAYER_MODE_EDIT_GET_SET_FLOAT(_NAME_) \
+ RNA_LAYER_ENGINE_GET_SET(float, EditMode, COLLECTION_MODE_EDIT, _NAME_)
+
+#define RNA_LAYER_MODE_EDIT_GET_SET_INT(_NAME_) \
+ RNA_LAYER_ENGINE_GET_SET(int, EditMode, COLLECTION_MODE_EDIT, _NAME_)
+
+#define RNA_LAYER_MODE_EDIT_GET_SET_BOOL(_NAME_) \
+ RNA_LAYER_ENGINE_GET_SET(bool, EditMode, COLLECTION_MODE_EDIT, _NAME_)
+
+#define RNA_LAYER_MODE_PAINT_WEIGHT_GET_SET_BOOL(_NAME_) \
+ RNA_LAYER_ENGINE_GET_SET(bool, PaintWeightMode, COLLECTION_MODE_PAINT_WEIGHT, _NAME_)
+
+#define RNA_LAYER_MODE_PAINT_VERTEX_GET_SET_BOOL(_NAME_) \
+ RNA_LAYER_ENGINE_GET_SET(bool, PaintVertexMode, COLLECTION_MODE_PAINT_VERTEX, _NAME_)
+
+/* clay engine */
+#ifdef WITH_CLAY_ENGINE
+/* SceneLayer settings. */
+RNA_LAYER_ENGINE_CLAY_GET_SET_INT(ssao_samples)
+
+/* LayerCollection settings. */
+RNA_LAYER_ENGINE_CLAY_GET_SET_INT(matcap_icon)
+RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(matcap_rotation)
+RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(matcap_hue)
+RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(matcap_saturation)
+RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(matcap_value)
+RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(ssao_factor_cavity)
+RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(ssao_factor_edge)
+RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(ssao_distance)
+RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(ssao_attenuation)
+RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(hair_brightness_randomness)
+#endif /* WITH_CLAY_ENGINE */
+
+/* eevee engine */
+/* SceneLayer settings. */
+RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(gtao_enable)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(gtao_use_bent_normals)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(gtao_factor)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(gtao_distance)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(gtao_samples)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(dof_enable)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(bokeh_max_size)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(bokeh_threshold)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(bloom_enable)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(bloom_threshold)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(bloom_knee)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(bloom_radius)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(bloom_intensity)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(motion_blur_enable)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(motion_blur_samples)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(motion_blur_shutter)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(volumetric_enable)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(volumetric_start)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(volumetric_end)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(volumetric_samples)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(volumetric_sample_distribution)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(volumetric_lights)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(volumetric_light_clamp)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(volumetric_shadows)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(volumetric_shadow_samples)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(volumetric_colored_transmittance)
+
+/* object engine */
+RNA_LAYER_MODE_OBJECT_GET_SET_BOOL(show_wire)
+RNA_LAYER_MODE_OBJECT_GET_SET_BOOL(show_backface_culling)
+
+/* mesh engine */
+RNA_LAYER_MODE_EDIT_GET_SET_BOOL(show_occlude_wire)
+RNA_LAYER_MODE_EDIT_GET_SET_BOOL(show_weight)
+RNA_LAYER_MODE_EDIT_GET_SET_BOOL(face_normals_show)
+RNA_LAYER_MODE_EDIT_GET_SET_BOOL(vert_normals_show)
+RNA_LAYER_MODE_EDIT_GET_SET_BOOL(loop_normals_show)
+RNA_LAYER_MODE_EDIT_GET_SET_FLOAT(normals_length)
+RNA_LAYER_MODE_EDIT_GET_SET_FLOAT(backwire_opacity)
+
+/* weight paint engine */
+RNA_LAYER_MODE_PAINT_WEIGHT_GET_SET_BOOL(use_shading)
+RNA_LAYER_MODE_PAINT_WEIGHT_GET_SET_BOOL(use_wire)
+
+/* vertex paint engine */
+RNA_LAYER_MODE_PAINT_VERTEX_GET_SET_BOOL(use_shading)
+RNA_LAYER_MODE_PAINT_VERTEX_GET_SET_BOOL(use_wire)
+
+#undef RNA_LAYER_ENGINE_GET_SET
+
+static void rna_SceneLayerEngineSettings_update(bContext *C, PointerRNA *UNUSED(ptr))
+{
+ Scene *scene = CTX_data_scene(C);
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update(&scene->id, 0);
+}
+
+static void rna_LayerCollectionEngineSettings_update(bContext *C, PointerRNA *UNUSED(ptr))
+{
+ Scene *scene = CTX_data_scene(C);
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update(&scene->id, 0);
+}
+
+static void rna_LayerCollectionEngineSettings_wire_update(bContext *C, PointerRNA *UNUSED(ptr))
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *ob = OBACT_NEW;
+
+ if (ob != NULL && ob->type == OB_MESH) {
+ BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_NOCHECK);
+ }
+
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update(&scene->id, 0);
+}
+
+/***********************************/
+
+static void engine_settings_use(IDProperty *root, IDProperty *props, PointerRNA *props_ptr, const char *identifier)
+{
+ PropertyRNA *prop = RNA_struct_find_property(props_ptr, identifier);
+
+ switch (RNA_property_type(prop)) {
+ case PROP_FLOAT:
+ {
+ float value = BKE_collection_engine_property_value_get_float(props, identifier);
+ BKE_collection_engine_property_add_float(root, identifier, value);
+ break;
+ }
+ case PROP_ENUM:
+ {
+ int value = BKE_collection_engine_property_value_get_int(props, identifier);
+ BKE_collection_engine_property_add_int(root, identifier, value);
+ break;
+ }
+ case PROP_INT:
+ {
+ int value = BKE_collection_engine_property_value_get_int(props, identifier);
+ BKE_collection_engine_property_add_int(root, identifier, value);
+ break;
+ }
+ case PROP_BOOLEAN:
+ {
+ int value = BKE_collection_engine_property_value_get_int(props, identifier);
+ BKE_collection_engine_property_add_bool(root, identifier, value);
+ break;
+ }
+ case PROP_STRING:
+ case PROP_POINTER:
+ case PROP_COLLECTION:
+ default:
+ break;
+ }
+}
+
+static void rna_SceneLayerSettings_name_get(PointerRNA *ptr, char *value)
+{
+ IDProperty *props = (IDProperty *)ptr->data;
+ strcpy(value, props->name);
+}
+
+static int rna_SceneLayerSettings_name_length(PointerRNA *ptr)
+{
+ IDProperty *props = (IDProperty *)ptr->data;
+ return strnlen(props->name, sizeof(props->name));
+}
+
+static void rna_SceneLayerSettings_use(ID *id, IDProperty *props, const char *identifier)
+{
+ Scene *scene = (Scene *)id;
+ PointerRNA scene_props_ptr;
+ IDProperty *scene_props;
+
+ scene_props = BKE_scene_layer_engine_scene_get(scene, COLLECTION_MODE_NONE, props->name);
+ RNA_pointer_create(id, &RNA_SceneLayerSettings, scene_props, &scene_props_ptr);
+
+ engine_settings_use(props, scene_props, &scene_props_ptr, identifier);
+
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update(id, 0);
+}
+
+static void rna_SceneLayerSettings_unuse(ID *id, IDProperty *props, const char *identifier)
+{
+ IDProperty *prop_to_remove = IDP_GetPropertyFromGroup(props, identifier);
+ IDP_FreeFromGroup(props, prop_to_remove);
+
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update(id, 0);
+}
+
+static void rna_LayerCollectionSettings_name_get(PointerRNA *ptr, char *value)
+{
+ IDProperty *props = (IDProperty *)ptr->data;
+ strcpy(value, props->name);
+}
+
+static int rna_LayerCollectionSettings_name_length(PointerRNA *ptr)
+{
+ IDProperty *props = (IDProperty *)ptr->data;
+ return strnlen(props->name, sizeof(props->name));
+}
+
+static void rna_LayerCollectionSettings_use(ID *id, IDProperty *props, const char *identifier)
+{
+ Scene *scene = (Scene *)id;
+ PointerRNA scene_props_ptr;
+ IDProperty *scene_props;
+
+ scene_props = BKE_layer_collection_engine_scene_get(scene, COLLECTION_MODE_NONE, props->name);
+ RNA_pointer_create(id, &RNA_LayerCollectionSettings, scene_props, &scene_props_ptr);
+ engine_settings_use(props, scene_props, &scene_props_ptr, identifier);
+
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update(id, 0);
+}
+
+static void rna_LayerCollectionSettings_unuse(ID *id, IDProperty *props, const char *identifier)
+{
+ IDProperty *prop_to_remove = IDP_GetPropertyFromGroup(props, identifier);
+ IDP_FreeFromGroup(props, prop_to_remove);
+
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update(id, 0);
+}
+
+static void rna_LayerCollection_name_get(PointerRNA *ptr, char *value)
+{
+ SceneCollection *sc = ((LayerCollection *)ptr->data)->scene_collection;
+ strcpy(value, sc->name);
+}
+
+static int rna_LayerCollection_name_length(PointerRNA *ptr)
+{
+ SceneCollection *sc = ((LayerCollection *)ptr->data)->scene_collection;
+ return strnlen(sc->name, sizeof(sc->name));
+}
+
+static void rna_LayerCollection_name_set(PointerRNA *ptr, const char *value)
+{
+ Scene *scene = (Scene *)ptr->id.data;
+ SceneCollection *sc = ((LayerCollection *)ptr->data)->scene_collection;
+ BKE_collection_rename(scene, sc, value);
+}
+
+static PointerRNA rna_LayerCollection_objects_get(CollectionPropertyIterator *iter)
+{
+ ListBaseIterator *internal = &iter->internal.listbase;
+ Base *base = ((LinkData *)internal->link)->data;
+ return rna_pointer_inherit_refine(&iter->parent, &RNA_Object, base->object);
+}
+
+static int rna_LayerCollection_move_above(ID *id, LayerCollection *lc_src, Main *bmain, LayerCollection *lc_dst)
+{
+ Scene *scene = (Scene *)id;
+
+ if (!BKE_layer_collection_move_above(scene, lc_dst, lc_src)) {
+ return 0;
+ }
+
+ DEG_relations_tag_update(bmain);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+
+ return 1;
+}
+
+static int rna_LayerCollection_move_below(ID *id, LayerCollection *lc_src, Main *bmain, LayerCollection *lc_dst)
+{
+ Scene *scene = (Scene *)id;
+
+ if (!BKE_layer_collection_move_below(scene, lc_dst, lc_src)) {
+ return 0;
+ }
+
+ DEG_relations_tag_update(bmain);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+
+ return 1;
+}
+
+static int rna_LayerCollection_move_into(ID *id, LayerCollection *lc_src, Main *bmain, LayerCollection *lc_dst)
+{
+ Scene *scene = (Scene *)id;
+
+ if (!BKE_layer_collection_move_into(scene, lc_dst, lc_src)) {
+ return 0;
+ }
+
+ DEG_relations_tag_update(bmain);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+
+ return 1;
+}
+
+static void rna_LayerCollection_flag_update(bContext *C, PointerRNA *UNUSED(ptr))
+{
+ Scene *scene = CTX_data_scene(C);
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update(&scene->id, 0);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+}
+
+static int rna_LayerCollections_active_collection_index_get(PointerRNA *ptr)
+{
+ SceneLayer *sl = (SceneLayer *)ptr->data;
+ return sl->active_collection;
+}
+
+static void rna_LayerCollections_active_collection_index_set(PointerRNA *ptr, int value)
+{
+ SceneLayer *sl = (SceneLayer *)ptr->data;
+ int num_collections = BKE_layer_collection_count(sl);
+ sl->active_collection = min_ff(value, num_collections - 1);
+}
+
+static void rna_LayerCollections_active_collection_index_range(
+ PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
+{
+ SceneLayer *sl = (SceneLayer *)ptr->data;
+ *min = 0;
+ *max = max_ii(0, BKE_layer_collection_count(sl) - 1);
+}
+
+static PointerRNA rna_LayerCollections_active_collection_get(PointerRNA *ptr)
+{
+ SceneLayer *sl = (SceneLayer *)ptr->data;
+ LayerCollection *lc = BKE_layer_collection_get_active(sl);
+ return rna_pointer_inherit_refine(ptr, &RNA_LayerCollection, lc);
+}
+
+static void rna_LayerCollections_active_collection_set(PointerRNA *ptr, PointerRNA value)
+{
+ SceneLayer *sl = (SceneLayer *)ptr->data;
+ LayerCollection *lc = (LayerCollection *)value.data;
+ const int index = BKE_layer_collection_findindex(sl, lc);
+ if (index != -1) sl->active_collection = index;
+}
+
+LayerCollection * rna_SceneLayer_collection_link(
+ ID *id, SceneLayer *sl, Main *bmain, SceneCollection *sc)
+{
+ Scene *scene = (Scene *)id;
+ LayerCollection *lc = BKE_collection_link(sl, sc);
+
+ DEG_relations_tag_update(bmain);
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update(id, 0);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, scene);
+
+ return lc;
+}
+
+static void rna_SceneLayer_collection_unlink(
+ ID *id, SceneLayer *sl, Main *bmain, ReportList *reports, LayerCollection *lc)
+{
+ Scene *scene = (Scene *)id;
+
+ if (BLI_findindex(&sl->layer_collections, lc) == -1) {
+ BKE_reportf(reports, RPT_ERROR, "Layer collection '%s' is not in '%s'", lc->scene_collection->name, sl->name);
+ return;
+ }
+
+ BKE_collection_unlink(sl, lc);
+
+ DEG_relations_tag_update(bmain);
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update(id, 0);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER | ND_OB_ACTIVE, scene);
+}
+
+static PointerRNA rna_LayerObjects_active_object_get(PointerRNA *ptr)
+{
+ SceneLayer *sl = (SceneLayer *)ptr->data;
+ return rna_pointer_inherit_refine(ptr, &RNA_Object, sl->basact ? sl->basact->object : NULL);
+}
+
+static void rna_LayerObjects_active_object_set(PointerRNA *ptr, PointerRNA value)
+{
+ SceneLayer *sl = (SceneLayer *)ptr->data;
+ if (value.data)
+ sl->basact = BKE_scene_layer_base_find(sl, (Object *)value.data);
+ else
+ sl->basact = NULL;
+}
+
+static void rna_SceneLayer_name_set(PointerRNA *ptr, const char *value)
+{
+ Scene *scene = (Scene *)ptr->id.data;
+ SceneLayer *sl = (SceneLayer *)ptr->data;
+ char oldname[sizeof(sl->name)];
+
+ BLI_strncpy(oldname, sl->name, sizeof(sl->name));
+
+ BLI_strncpy_utf8(sl->name, value, sizeof(sl->name));
+ BLI_uniquename(&scene->render_layers, sl, DATA_("SceneLayer"), '.', offsetof(SceneLayer, name), sizeof(sl->name));
+
+ if (scene->nodetree) {
+ bNode *node;
+ int index = BLI_findindex(&scene->render_layers, sl);
+
+ 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, sl->name, NODE_MAXSTR);
+ }
+ }
+ }
+}
+
+static PointerRNA rna_SceneLayer_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 int rna_SceneLayer_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 void rna_LayerObjects_selected_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ SceneLayer *sl = (SceneLayer *)ptr->data;
+ rna_iterator_listbase_begin(iter, &sl->object_bases, rna_SceneLayer_objects_selected_skip);
+}
+
+static void rna_SceneLayer_engine_set(PointerRNA *ptr, int value)
+{
+ SceneLayer *sl = (SceneLayer *)ptr->data;
+ RenderEngineType *type = BLI_findlink(&R_engines, value);
+
+ if (type)
+ BKE_scene_layer_engine_set(sl, type->idname);
+}
+
+static EnumPropertyItem *rna_SceneLayer_engine_itemf(
+ bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ RenderEngineType *type;
+ EnumPropertyItem *item = NULL;
+ EnumPropertyItem tmp = {0, "", 0, "", ""};
+ int a = 0, totitem = 0;
+
+ for (type = R_engines.first; type; type = type->next, a++) {
+ tmp.value = a;
+ tmp.identifier = type->idname;
+ tmp.name = type->name;
+ RNA_enum_item_add(&item, &totitem, &tmp);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+static int rna_SceneLayer_engine_get(PointerRNA *ptr)
+{
+ SceneLayer *sl = (SceneLayer *)ptr->data;
+ RenderEngineType *type;
+ int a = 0;
+
+ for (type = R_engines.first; type; type = type->next, a++)
+ if (STREQ(type->idname, sl->engine))
+ return a;
+
+ return 0;
+}
+
+static void rna_SceneLayer_engine_update(Main *bmain, Scene *UNUSED(unused), PointerRNA *UNUSED(ptr))
+{
+ ED_render_engine_changed(bmain);
+}
+
+static int rna_SceneLayer_multiple_engines_get(PointerRNA *UNUSED(ptr))
+{
+ return (BLI_listbase_count(&R_engines) > 1);
+}
+
+static void rna_SceneLayer_update_tagged(SceneLayer *UNUSED(sl), bContext *C)
+{
+ Depsgraph *graph = CTX_data_depsgraph(C);
+ DEG_OBJECT_ITER(graph, ob, DEG_OBJECT_ITER_FLAG_ALL)
+ {
+ /* Don't do anything, we just need to run the iterator to flush
+ * the base info to the objects. */
+ UNUSED_VARS(ob);
+ }
+ DEG_OBJECT_ITER_END
+}
+
+static int rna_SceneLayer_active_layer_index_get(PointerRNA *ptr)
+{
+ Scene *scene = (Scene *)ptr->data;
+ return scene->active_layer;
+}
+
+static void rna_SceneLayer_active_layer_index_set(PointerRNA *ptr, int value)
+{
+ Scene *scene = (Scene *)ptr->data;
+ int num_layers = BLI_listbase_count(&scene->render_layers);
+ scene->active_layer = min_ff(value, num_layers - 1);
+}
+
+static void rna_SceneLayer_active_layer_index_range(
+ PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
+{
+ Scene *scene = (Scene *)ptr->data;
+
+ *min = 0;
+ *max = max_ii(0, BLI_listbase_count(&scene->render_layers) - 1);
+}
+
+static PointerRNA rna_SceneLayer_active_layer_get(PointerRNA *ptr)
+{
+ Scene *scene = (Scene *)ptr->data;
+ SceneLayer *sl = BLI_findlink(&scene->render_layers, scene->active_layer);
+
+ return rna_pointer_inherit_refine(ptr, &RNA_SceneLayer, sl);
+}
+
+static void rna_SceneLayer_active_layer_set(PointerRNA *ptr, PointerRNA value)
+{
+ Scene *scene = (Scene *)ptr->data;
+ SceneLayer *sl = (SceneLayer *)value.data;
+ const int index = BLI_findindex(&scene->render_layers, sl);
+ if (index != -1) scene->active_layer = index;
+}
+
+static SceneLayer *rna_SceneLayer_new(
+ ID *id, Scene *UNUSED(sce), Main *bmain, const char *name)
+{
+ Scene *scene = (Scene *)id;
+ SceneLayer *sl = BKE_scene_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 sl;
+}
+
+static void rna_SceneLayer_remove(
+ ID *id, Scene *UNUSED(sce), Main *bmain, ReportList *reports, PointerRNA *sl_ptr)
+{
+ Scene *scene = (Scene *)id;
+ SceneLayer *sl = sl_ptr->data;
+
+ if (ED_scene_render_layer_delete(bmain, scene, sl, reports)) {
+ RNA_POINTER_INVALIDATE(sl_ptr);
+ }
+}
+
+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);
+}
#else
+/* Grease Pencil Interpolation tool settings */
+static void rna_def_gpencil_interpolate(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "GPencilInterpolateSettings", NULL);
+ RNA_def_struct_sdna(srna, "GP_Interpolate_Settings");
+ RNA_def_struct_path_func(srna, "rna_GPencilInterpolateSettings_path");
+ RNA_def_struct_ui_text(srna, "Grease Pencil Interpolate Settings",
+ "Settings for Grease Pencil interpolation tools");
+
+ /* flags */
+ prop = RNA_def_property(srna, "interpolate_all_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS);
+ RNA_def_property_ui_text(prop, "Interpolate All Layers", "Interpolate all layers, not only active");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "interpolate_selected_only", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED);
+ RNA_def_property_ui_text(prop, "Interpolate Selected Strokes", "Interpolate only selected strokes in the original frame");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ /* interpolation type */
+ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "type");
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_interpolation_mode_items);
+ RNA_def_property_enum_funcs(prop, NULL, "rna_GPencilInterpolateSettings_type_set", NULL);
+ RNA_def_property_ui_text(prop, "Type",
+ "Interpolation method to use the next time 'Interpolate Sequence' is run");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ /* easing */
+ prop = RNA_def_property(srna, "easing", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "easing");
+ RNA_def_property_enum_items(prop, rna_enum_beztriple_interpolation_easing_items);
+ RNA_def_property_ui_text(prop, "Easing",
+ "Which ends of the segment between the preceding and following grease pencil frames "
+ "easing interpolation is applied to");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ /* easing options */
+ prop = RNA_def_property(srna, "back", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "back");
+ RNA_def_property_ui_text(prop, "Back", "Amount of overshoot for 'back' easing");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "amplitude", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "amplitude");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX); /* only positive values... */
+ RNA_def_property_ui_text(prop, "Amplitude", "Amount to boost elastic bounces for 'elastic' easing");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "period", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "period");
+ RNA_def_property_ui_text(prop, "Period", "Time between bounces for elastic easing");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ /* custom curvemap */
+ prop = RNA_def_property(srna, "interpolation_curve", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "custom_ipo");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_ui_text(prop, "Interpolation Curve",
+ "Custom curve to control 'sequence' interpolation between Grease Pencil frames");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+}
+
/* Grease Pencil Drawing Brushes */
static void rna_def_gpencil_brush(BlenderRNA *brna)
{
@@ -2161,23 +3262,26 @@ static void rna_def_gpencil_brush(BlenderRNA *brna)
/* Angle when brush is full size */
prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "draw_angle");
- RNA_def_property_range(prop, 0.0f, M_PI_2);
- RNA_def_property_ui_text(prop, "Angle", "Angle of drawing when brush has full size");
+ RNA_def_property_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", "Factor to apply when the brush rotate of its full size");
+ 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_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 */
@@ -2185,8 +3289,7 @@ static void rna_def_gpencil_brush(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "draw_smoothlvl");
RNA_def_property_range(prop, 1, 3);
RNA_def_property_ui_text(prop, "Iterations",
- "Number of times to smooth newly created strokes "
- "[+ reason/effect of using higher values of this property]");
+ "Number of times to smooth newly created strokes");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
/* Subdivision level for new strokes */
@@ -2266,7 +3369,7 @@ static void rna_def_gpencil_brushes(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_GPencil_brush_new");
RNA_def_function_ui_description(func, "Add a new grease pencil brush");
parm = RNA_def_string(func, "name", "GPencilBrush", MAX_NAME, "Name", "Name of the brush");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_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);
@@ -2275,8 +3378,8 @@ static void rna_def_gpencil_brushes(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a grease pencil brush");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "brush", "GPencilBrush", "", "The brush to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ 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");
@@ -2289,25 +3392,7 @@ static void rna_def_gpencil_brushes(BlenderRNA *brna, PropertyRNA *cprop)
"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;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "TransformOrientation", NULL);
-
- 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_3x3);
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
- RNA_def_struct_name_property(srna, prop);
- RNA_def_property_ui_text(prop, "Name", "Name of the custom transform orientation");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ RNA_def_property_ui_text(prop, "Active Brush Index", "Index of active brush");
}
static void rna_def_tool_settings(BlenderRNA *brna)
@@ -2401,6 +3486,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 "
@@ -2408,6 +3494,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, "
@@ -2415,12 +3502,14 @@ 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");
@@ -2626,13 +3715,20 @@ static void rna_def_tool_settings(BlenderRNA *brna)
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",
- "Datablock where active Grease Pencil data is found from");
+ "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, "gpencil_sculpt", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gp_sculpt");
RNA_def_property_struct_type(prop, "GPencilSculptSettings");
- RNA_def_property_ui_text(prop, "Grease Pencil Sculpt", "");
+ RNA_def_property_ui_text(prop, "Grease Pencil Sculpt",
+ "Settings for stroke sculpting tools and brushes");
+
+ prop = RNA_def_property(srna, "gpencil_interpolate", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "gp_interpolate");
+ RNA_def_property_struct_type(prop, "GPencilInterpolateSettings");
+ 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);
@@ -2728,6 +3824,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);
@@ -2863,6 +3960,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");
@@ -2870,6 +3968,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");
@@ -2877,6 +3976,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);
@@ -2885,6 +3985,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);
@@ -2892,12 +3993,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", "");
@@ -3039,6 +4142,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");
@@ -3049,6 +4153,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);
@@ -3057,12 +4162,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");
@@ -3073,6 +4180,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);
@@ -3081,12 +4189,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 */
@@ -3096,6 +4206,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);
@@ -3104,6 +4215,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 */
@@ -3113,6 +4225,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);
@@ -3121,6 +4234,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 Max", "Maximum angle to display");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_EditMesh_update");
}
@@ -3569,8 +4683,8 @@ static void rna_def_freestyle_modules(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a style module from scene render layer Freestyle settings");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "module", "FreestyleModuleSettings", "", "Style module to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_freestyle_linesets(BlenderRNA *brna, PropertyRNA *cprop)
@@ -3602,7 +4716,7 @@ static void rna_def_freestyle_linesets(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a line set to scene render layer Freestyle settings");
RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_SELF_ID);
parm = RNA_def_string(func, "name", "LineSet", 0, "", "New name for the line set (not unique)");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "lineset", "FreestyleLineSet", "", "Newly created line set");
RNA_def_function_return(func, parm);
@@ -3610,8 +4724,8 @@ static void rna_def_freestyle_linesets(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a line set from scene render layer Freestyle settings");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "lineset", "FreestyleLineSet", "", "Line set to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_freestyle_settings(BlenderRNA *brna)
@@ -4633,11 +5747,6 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
"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",
@@ -4797,11 +5906,23 @@ 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, NULL);
+ prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_ui_text(prop, "Rotation", "Rotation of blades in apperture");
+ 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, "ratio", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Ratio", "Distortion to simulate anamorphic lens bokeh");
+ 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);
+
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, NULL);
+ /* NOTE: high quality is always supported */
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);
@@ -4882,19 +6003,1049 @@ static void rna_def_gpu_fx(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPUFXSettings_fx_update");
}
+/* Render Layers and Collections */
+
+static void rna_def_scene_collections(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "SceneCollections");
+ srna = RNA_def_struct(brna, "SceneCollections", NULL);
+ RNA_def_struct_sdna(srna, "SceneCollection");
+ RNA_def_struct_ui_text(srna, "Scene Collection", "Collection of scene collections");
+
+ func = RNA_def_function(srna, "new", "rna_SceneCollection_new");
+ RNA_def_function_ui_description(func, "Add a collection to scene");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
+ parm = RNA_def_string(func, "name", "SceneCollection", 0, "", "New name for the collection (not unique)");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "result", "SceneCollection", "", "Newly created collection");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_SceneCollection_remove");
+ RNA_def_function_ui_description(func, "Remove a collection layer");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "layer", "SceneCollection", "", "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);
+}
+
+static void rna_def_collection_objects(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+ PropertyRNA *prop;
+
+ RNA_def_property_srna(cprop, "CollectionObjects");
+ srna = RNA_def_struct(brna, "CollectionObjects", NULL);
+ RNA_def_struct_sdna(srna, "SceneCollection");
+ RNA_def_struct_ui_text(srna, "Collection Objects", "Objects of a collection");
+
+ prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_funcs(prop, "rna_SceneCollection_objects_active_index_get",
+ "rna_SceneCollection_objects_active_index_set",
+ "rna_SceneCollection_objects_active_index_range");
+ RNA_def_property_ui_text(prop, "Active Object Index", "Active index in collection objects array");
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, NULL);
+
+ func = RNA_def_function(srna, "link", "rna_SceneCollection_object_link");
+ RNA_def_function_ui_description(func, "Link an object to collection");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "object", "Object", "", "Object to add to collection");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
+ func = RNA_def_function(srna, "unlink", "rna_SceneCollection_object_unlink");
+ RNA_def_function_ui_description(func, "Unlink object from collection");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "object", "Object", "", "Object to remove from collection");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+}
+
+static void rna_def_scene_collection(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ srna = RNA_def_struct(brna, "SceneCollection", NULL);
+ RNA_def_struct_ui_text(srna, "Scene Collection", "Collection");
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SceneCollection_name_set");
+ RNA_def_property_ui_text(prop, "Name", "Collection name");
+ RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, NULL);
+
+ prop = RNA_def_property(srna, "filter", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SceneCollection_filter_set");
+ RNA_def_property_ui_text(prop, "Filter", "Filter to dynamically include objects based on their names (e.g., CHAR_*)");
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, NULL);
+
+ prop = RNA_def_property(srna, "collections", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "scene_collections", NULL);
+ RNA_def_property_struct_type(prop, "SceneCollection");
+ RNA_def_property_ui_text(prop, "SceneCollections", "");
+ rna_def_scene_collections(brna, prop);
+
+ prop = RNA_def_property(srna, "objects", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "objects", NULL);
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, "rna_SceneCollection_objects_get", NULL, NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Objects", "All the objects directly added to this collection (not including sub-collection objects)");
+ rna_def_collection_objects(brna, prop);
+
+ prop = RNA_def_property(srna, "filters_objects", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "filter_objects", NULL);
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, "rna_SceneCollection_objects_get", NULL, NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Filter Objects", "All the objects dynamically added to this collection via the filter");
+
+ /* Functions */
+ func = RNA_def_function(srna, "move_above", "rna_SceneCollection_move_above");
+ RNA_def_function_ui_description(func, "Move collection after another");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
+ parm = RNA_def_pointer(func, "sc_dst", "SceneCollection", "Collection", "Reference collection above which the collection will move");
+ parm = RNA_def_boolean(func, "result", false, "Result", "Whether the operation succeded");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "move_below", "rna_SceneCollection_move_below");
+ RNA_def_function_ui_description(func, "Move collection before another");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
+ parm = RNA_def_pointer(func, "sc_dst", "SceneCollection", "Collection", "Reference collection below which the collection will move");
+ parm = RNA_def_boolean(func, "result", false, "Result", "Whether the operation succeded");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "move_into", "rna_SceneCollection_move_into");
+ RNA_def_function_ui_description(func, "Move collection into another");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
+ parm = RNA_def_pointer(func, "sc_dst", "SceneCollection", "Collection", "Collection to insert into");
+ parm = RNA_def_boolean(func, "result", false, "Result", "Whether the operation succeded");
+ RNA_def_function_return(func, parm);
+}
+
+static void rna_def_layer_collection_override(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "LayerCollectionOverride", NULL);
+ RNA_def_struct_sdna(srna, "CollectionOverride");
+ RNA_def_struct_ui_text(srna, "Collection Override", "Collection Override");
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Name", "Collection name");
+ RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, NULL);
+}
+
+
+#ifdef WITH_CLAY_ENGINE
+static void rna_def_scene_layer_engine_settings_clay(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "SceneLayerEngineSettingsClay", "SceneLayerSettings");
+ RNA_def_struct_ui_text(srna, "Clay Scene Layer Settings", "Clay Engine settings");
+
+ RNA_define_verify_sdna(0); /* not in sdna */
+
+ /* see RNA_LAYER_ENGINE_GET_SET macro */
+ prop = RNA_def_property(srna, "ssao_samples", PROP_INT, PROP_NONE);
+ RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Clay_ssao_samples_get",
+ "rna_LayerEngineSettings_Clay_ssao_samples_set", NULL);
+ RNA_def_property_ui_text(prop, "Samples", "Number of samples");
+ RNA_def_property_range(prop, 1, 500);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ RNA_define_verify_sdna(1); /* not in sdna */
+}
+#endif /* WITH_CLAY_ENGINE */
+
+static void rna_def_scene_layer_engine_settings_eevee(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "SceneLayerEngineSettingsEevee", "SceneLayerSettings");
+ RNA_def_struct_ui_text(srna, "Eevee Scene Layer Settings", "Eevee Engine settings");
+
+ RNA_define_verify_sdna(0); /* not in sdna */
+
+ /* see RNA_LAYER_ENGINE_GET_SET macro */
+
+ /* Volumetrics */
+ prop = RNA_def_property(srna, "volumetric_enable", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_volumetric_enable_get",
+ "rna_LayerEngineSettings_Eevee_volumetric_enable_set");
+ RNA_def_property_ui_text(prop, "Volumetrics", "Enable scattering and absorbance of volumetric material");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ prop = RNA_def_property(srna, "volumetric_start", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_volumetric_start_get",
+ "rna_LayerEngineSettings_Eevee_volumetric_start_set", NULL);
+ 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_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ prop = RNA_def_property(srna, "volumetric_end", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_volumetric_end_get",
+ "rna_LayerEngineSettings_Eevee_volumetric_end_set", NULL);
+ 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_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ prop = RNA_def_property(srna, "volumetric_samples", PROP_INT, PROP_NONE);
+ RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Eevee_volumetric_samples_get",
+ "rna_LayerEngineSettings_Eevee_volumetric_samples_set", NULL);
+ RNA_def_property_ui_text(prop, "Samples", "Number of samples to compute volumetric effects");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_range(prop, 1, 256);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ prop = RNA_def_property(srna, "volumetric_sample_distribution", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_volumetric_sample_distribution_get",
+ "rna_LayerEngineSettings_Eevee_volumetric_sample_distribution_set", NULL);
+ RNA_def_property_ui_text(prop, "Exponential Sampling", "Distribute more samples closer to the camera");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ prop = RNA_def_property(srna, "volumetric_lights", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_volumetric_lights_get",
+ "rna_LayerEngineSettings_Eevee_volumetric_lights_set");
+ RNA_def_property_ui_text(prop, "Volumetric Lighting", "Enable scene lamps interactions with volumetrics");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ prop = RNA_def_property(srna, "volumetric_light_clamp", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_volumetric_light_clamp_get",
+ "rna_LayerEngineSettings_Eevee_volumetric_light_clamp_set", NULL);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Clamp", "Maximum light contribution, reducing noise");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ prop = RNA_def_property(srna, "volumetric_shadows", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_volumetric_shadows_get",
+ "rna_LayerEngineSettings_Eevee_volumetric_shadows_set");
+ RNA_def_property_ui_text(prop, "Volumetric Shadows", "Generate shadows from volumetric material (Very expensive)");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ prop = RNA_def_property(srna, "volumetric_shadow_samples", PROP_INT, PROP_NONE);
+ RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Eevee_volumetric_shadow_samples_get",
+ "rna_LayerEngineSettings_Eevee_volumetric_shadow_samples_set", NULL);
+ 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_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ prop = RNA_def_property(srna, "volumetric_colored_transmittance", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_volumetric_colored_transmittance_get",
+ "rna_LayerEngineSettings_Eevee_volumetric_colored_transmittance_set");
+ RNA_def_property_ui_text(prop, "Colored Transmittance", "Enable wavelength dependent volumetric transmittance");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ /* Ambient Occlusion */
+ prop = RNA_def_property(srna, "gtao_enable", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_gtao_enable_get",
+ "rna_LayerEngineSettings_Eevee_gtao_enable_set");
+ RNA_def_property_ui_text(prop, "Ambient Occlusion", "Enable ambient occlusion to simulate medium scale indirect shadowing");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ prop = RNA_def_property(srna, "gtao_use_bent_normals", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_gtao_use_bent_normals_get",
+ "rna_LayerEngineSettings_Eevee_gtao_use_bent_normals_set");
+ RNA_def_property_ui_text(prop, "Bent Normals", "Compute main non occluded direction to sample the environment");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ prop = RNA_def_property(srna, "gtao_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_gtao_factor_get", "rna_LayerEngineSettings_Eevee_gtao_factor_set", NULL);
+ RNA_def_property_ui_text(prop, "Factor", "Factor for ambient occlusion blending");
+ RNA_def_property_range(prop, 0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1f, 2);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+
+ prop = RNA_def_property(srna, "gtao_distance", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_gtao_distance_get", "rna_LayerEngineSettings_Eevee_gtao_distance_set", NULL);
+ 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_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+
+ prop = RNA_def_property(srna, "gtao_samples", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Eevee_gtao_samples_get",
+ "rna_LayerEngineSettings_Eevee_gtao_samples_set", NULL);
+ RNA_def_property_ui_text(prop, "Samples", "Number of samples to take to compute occlusion");
+ RNA_def_property_range(prop, 2, 32);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ /* Depth of Field */
+ prop = RNA_def_property(srna, "dof_enable", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_dof_enable_get",
+ "rna_LayerEngineSettings_Eevee_dof_enable_set");
+ RNA_def_property_ui_text(prop, "Depth of Field", "Enable depth of field using the values from the active camera");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ prop = RNA_def_property(srna, "bokeh_max_size", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_bokeh_max_size_get",
+ "rna_LayerEngineSettings_Eevee_bokeh_max_size_set", NULL);
+ 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_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ prop = RNA_def_property(srna, "bokeh_threshold", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_bokeh_threshold_get",
+ "rna_LayerEngineSettings_Eevee_bokeh_threshold_set", NULL);
+ 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_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ /* Bloom */
+ prop = RNA_def_property(srna, "bloom_enable", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_bloom_enable_get",
+ "rna_LayerEngineSettings_Eevee_bloom_enable_set");
+ RNA_def_property_ui_text(prop, "Bloom", "High brighness pixels generate a glowing effect");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ prop = RNA_def_property(srna, "bloom_threshold", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_bloom_threshold_get",
+ "rna_LayerEngineSettings_Eevee_bloom_threshold_set", NULL);
+ 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_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ prop = RNA_def_property(srna, "bloom_knee", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_bloom_knee_get",
+ "rna_LayerEngineSettings_Eevee_bloom_knee_set", NULL);
+ 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_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ prop = RNA_def_property(srna, "bloom_radius", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_bloom_radius_get",
+ "rna_LayerEngineSettings_Eevee_bloom_radius_set", NULL);
+ 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_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ prop = RNA_def_property(srna, "bloom_intensity", PROP_FLOAT, PROP_UNSIGNED);
+ RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_bloom_intensity_get",
+ "rna_LayerEngineSettings_Eevee_bloom_intensity_set", NULL);
+ 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_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ /* Motion blur */
+ prop = RNA_def_property(srna, "motion_blur_enable", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_motion_blur_enable_get",
+ "rna_LayerEngineSettings_Eevee_motion_blur_enable_set");
+ RNA_def_property_ui_text(prop, "Motion Blur", "Enable motion blur effect (only in camera view)");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ prop = RNA_def_property(srna, "motion_blur_samples", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Eevee_motion_blur_samples_get",
+ "rna_LayerEngineSettings_Eevee_motion_blur_samples_set", NULL);
+ 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_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ prop = RNA_def_property(srna, "motion_blur_shutter", PROP_FLOAT, PROP_UNSIGNED);
+ RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_motion_blur_shutter_get",
+ "rna_LayerEngineSettings_Eevee_motion_blur_shutter_set", NULL);
+ 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_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
+
+ RNA_define_verify_sdna(1); /* not in sdna */
+}
+
+#ifdef WITH_CLAY_ENGINE
+static void rna_def_layer_collection_engine_settings_clay(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem clay_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, "LayerCollectionEngineSettingsClay", "LayerCollectionSettings");
+ RNA_def_struct_ui_text(srna, "Collections Clay Engine Settings", "Engine specific settings for this collection");
+
+ RNA_define_verify_sdna(0); /* not in sdna */
+
+ /* see RNA_LAYER_ENGINE_GET_SET macro */
+ prop = RNA_def_property(srna, "matcap_icon", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_funcs(prop, "rna_LayerEngineSettings_Clay_matcap_icon_get", "rna_LayerEngineSettings_Clay_matcap_icon_set", NULL);
+ RNA_def_property_enum_items(prop, clay_matcap_items);
+ RNA_def_property_ui_text(prop, "Matcap", "Image to use for Material Capture by this material");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+
+ prop = RNA_def_property(srna, "matcap_rotation", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_matcap_rotation_get", "rna_LayerEngineSettings_Clay_matcap_rotation_set", NULL);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Matcap Rotation", "Orientation of the matcap on the model");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+
+ prop = RNA_def_property(srna, "matcap_hue", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_matcap_hue_get", "rna_LayerEngineSettings_Clay_matcap_hue_set", NULL);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Matcap Hue Shift", "Hue correction of the matcap");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+
+ prop = RNA_def_property(srna, "matcap_saturation", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_matcap_saturation_get", "rna_LayerEngineSettings_Clay_matcap_saturation_set", NULL);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Matcap Saturation", "Saturation correction of the matcap");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+
+ prop = RNA_def_property(srna, "matcap_value", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_matcap_value_get", "rna_LayerEngineSettings_Clay_matcap_value_set", NULL);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Matcap Value", "Value correction of the matcap");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+
+ prop = RNA_def_property(srna, "ssao_factor_cavity", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_ssao_factor_cavity_get", "rna_LayerEngineSettings_Clay_ssao_factor_cavity_set", NULL);
+ RNA_def_property_ui_text(prop, "Cavity Strength", "Strength of the Cavity effect");
+ RNA_def_property_range(prop, 0.0f, 250.0f);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+
+ prop = RNA_def_property(srna, "ssao_factor_edge", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_ssao_factor_edge_get", "rna_LayerEngineSettings_Clay_ssao_factor_edge_set", NULL);
+ RNA_def_property_ui_text(prop, "Edge Strength", "Strength of the Edge effect");
+ RNA_def_property_range(prop, 0.0f, 250.0f);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+
+ prop = RNA_def_property(srna, "ssao_distance", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_ssao_distance_get", "rna_LayerEngineSettings_Clay_ssao_distance_set", NULL);
+ 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);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+
+ prop = RNA_def_property(srna, "ssao_attenuation", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_ssao_attenuation_get", "rna_LayerEngineSettings_Clay_ssao_attenuation_set", NULL);
+ 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);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+
+ prop = RNA_def_property(srna, "hair_brightness_randomness", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_hair_brightness_randomness_get", "rna_LayerEngineSettings_Clay_hair_brightness_randomness_set", NULL);
+ RNA_def_property_ui_text(prop, "Hair Brightness Randomness", "Brightness randomness for hair");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+
+ RNA_define_verify_sdna(1); /* not in sdna */
+}
+#endif /* WITH_CLAY_ENGINE */
+
+static void rna_def_layer_collection_mode_settings_object(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "LayerCollectionModeSettingsObject", "LayerCollectionSettings");
+ RNA_def_struct_ui_text(srna, "Collections Object Mode Settings", "Object Mode specific settings for this collection");
+ RNA_define_verify_sdna(0); /* not in sdna */
+
+ /* see RNA_LAYER_ENGINE_GET_SET macro */
+
+ prop = RNA_def_property(srna, "show_wire", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Wire", "Add the object's wireframe over solid drawing");
+ RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_ObjectMode_show_wire_get", "rna_LayerEngineSettings_ObjectMode_show_wire_set");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+
+ prop = RNA_def_property(srna, "show_backface_culling", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Backface Culling", "");
+ RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_ObjectMode_show_backface_culling_get", "rna_LayerEngineSettings_ObjectMode_show_backface_culling_set");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+
+ RNA_define_verify_sdna(1); /* not in sdna */
+}
+
+static void rna_def_layer_collection_mode_settings_edit(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "LayerCollectionModeSettingsEdit", "LayerCollectionSettings");
+ RNA_def_struct_ui_text(srna, "Collections Edit Mode Settings", "Edit Mode specific settings to be overridden per collection");
+ RNA_define_verify_sdna(0); /* not in sdna */
+
+ /* see RNA_LAYER_ENGINE_GET_SET macro */
+
+ prop = RNA_def_property(srna, "show_occlude_wire", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Hidden Wire", "Use hidden wireframe display");
+ RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_EditMode_show_occlude_wire_get", "rna_LayerEngineSettings_EditMode_show_occlude_wire_set");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+
+ prop = RNA_def_property(srna, "show_weight", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Show Weights", "Draw weights in editmode");
+ RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_EditMode_show_weight_get", "rna_LayerEngineSettings_EditMode_show_weight_set");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+
+ prop = RNA_def_property(srna, "face_normals_show", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Draw Normals", "Display face normals as lines");
+ RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_EditMode_face_normals_show_get", "rna_LayerEngineSettings_EditMode_face_normals_show_set");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+
+ prop = RNA_def_property(srna, "vert_normals_show", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Draw Vertex Normals", "Display vertex normals as lines");
+ RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_EditMode_vert_normals_show_get", "rna_LayerEngineSettings_EditMode_vert_normals_show_set");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+
+ prop = RNA_def_property(srna, "loop_normals_show", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Draw Split Normals", "Display vertex-per-face normals as lines");
+ RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_EditMode_loop_normals_show_get", "rna_LayerEngineSettings_EditMode_loop_normals_show_set");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+
+ prop = RNA_def_property(srna, "normals_length", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_ui_text(prop, "Normal Size", "Display size for normals in the 3D view");
+ RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_EditMode_normals_length_get", "rna_LayerEngineSettings_EditMode_normals_length_set", NULL);
+ 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_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+
+ prop = RNA_def_property(srna, "backwire_opacity", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_ui_text(prop, "Backwire Opacity", "Opacity when rendering transparent wires");
+ RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_EditMode_backwire_opacity_get", "rna_LayerEngineSettings_EditMode_backwire_opacity_set", NULL);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+
+ RNA_define_verify_sdna(1); /* not in sdna */
+}
+
+static void rna_def_layer_collection_mode_settings_paint_weight(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "LayerCollectionModeSettingsPaintWeight", "LayerCollectionSettings");
+ RNA_def_struct_ui_text(srna, "Collections Weight Paint Mode Settings", "Weight Paint Mode specific settings to be overridden per collection");
+ RNA_define_verify_sdna(0); /* not in sdna */
+
+ /* see RNA_LAYER_ENGINE_GET_SET macro */
+
+ prop = RNA_def_property(srna, "use_shading", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Use Shading", "Whether to use shaded or shadeless drawing");
+ RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_PaintWeightMode_use_shading_get", "rna_LayerEngineSettings_PaintWeightMode_use_shading_set");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+
+ prop = RNA_def_property(srna, "use_wire", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Show Wire", "Whether to overlay wireframe onto the mesh");
+ RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_PaintWeightMode_use_wire_get", "rna_LayerEngineSettings_PaintWeightMode_use_wire_set");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_wire_update");
+
+ RNA_define_verify_sdna(1); /* not in sdna */
+}
+
+static void rna_def_layer_collection_mode_settings_paint_vertex(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "LayerCollectionModeSettingsPaintVertex", "LayerCollectionSettings");
+ RNA_def_struct_ui_text(srna, "Collections Vertex Paint Mode Settings", "Vertex Paint Mode specific settings to be overridden per collection");
+ RNA_define_verify_sdna(0); /* not in sdna */
+
+ /* see RNA_LAYER_ENGINE_GET_SET macro */
+
+ prop = RNA_def_property(srna, "use_shading", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Use Shading", "Whether to use shaded or shadeless drawing");
+ RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_PaintVertexMode_use_shading_get", "rna_LayerEngineSettings_PaintVertexMode_use_shading_set");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+
+ prop = RNA_def_property(srna, "use_wire", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Show Wire", "Whether to overlay wireframe onto the mesh");
+ RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_PaintVertexMode_use_wire_get", "rna_LayerEngineSettings_PaintVertexMode_use_wire_set");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_wire_update");
+
+ RNA_define_verify_sdna(1); /* not in sdna */
+}
+
+static void rna_def_scene_layer_settings(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ srna = RNA_def_struct(brna, "SceneLayerSettings", NULL);
+ RNA_def_struct_sdna(srna, "IDProperty");
+ RNA_def_struct_ui_text(srna, "Scene Layer Settings",
+ "Engine specific settings that can be overriden by SceneLayer");
+ RNA_def_struct_refine_func(srna, "rna_SceneLayerSettings_refine");
+
+ RNA_define_verify_sdna(0);
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop, "rna_SceneLayerSettings_name_get", "rna_SceneLayerSettings_name_length", NULL);
+ RNA_def_property_ui_text(prop, "Name", "Engine Name");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_struct_name_property(srna, prop);
+
+ func = RNA_def_function(srna, "use", "rna_SceneLayerSettings_use");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID);
+ RNA_def_function_ui_description(func, "Initialize this property to use");
+ parm = RNA_def_string(func, "identifier", NULL, 0, "Property Name", "Name of the property to set");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+ func = RNA_def_function(srna, "unuse", "rna_SceneLayerSettings_unuse");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID);
+ RNA_def_function_ui_description(func, "Remove the property");
+ parm = RNA_def_string(func, "identifier", NULL, 0, "Property Name", "Name of the property to unset");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+#ifdef WITH_CLAY_ENGINE
+ rna_def_scene_layer_engine_settings_clay(brna);
+#endif
+ rna_def_scene_layer_engine_settings_eevee(brna);
+
+#if 0
+ rna_def_scene_layer_mode_settings_object(brna);
+ rna_def_scene_layer_mode_settings_edit(brna);
+ rna_def_scene_layer_mode_settings_paint_weight(brna);
+ rna_def_scene_layer_mode_settings_paint_vertex(brna);
+#endif
+
+ RNA_define_verify_sdna(1);
+}
+
+static void rna_def_layer_collection_settings(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ srna = RNA_def_struct(brna, "LayerCollectionSettings", NULL);
+ RNA_def_struct_sdna(srna, "IDProperty");
+ RNA_def_struct_ui_text(srna, "Layer Collection Settings",
+ "Engine specific settings that can be overriden by LayerCollection");
+ RNA_def_struct_refine_func(srna, "rna_LayerCollectionSettings_refine");
+
+ RNA_define_verify_sdna(0);
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop, "rna_LayerCollectionSettings_name_get", "rna_LayerCollectionSettings_name_length", NULL);
+ RNA_def_property_ui_text(prop, "Name", "Engine Name");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_struct_name_property(srna, prop);
+
+ func = RNA_def_function(srna, "use", "rna_LayerCollectionSettings_use");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID);
+ RNA_def_function_ui_description(func, "Initialize this property to use");
+ parm = RNA_def_string(func, "identifier", NULL, 0, "Property Name", "Name of the property to set");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+ func = RNA_def_function(srna, "unuse", "rna_LayerCollectionSettings_unuse");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID);
+ RNA_def_function_ui_description(func, "Remove the property");
+ parm = RNA_def_string(func, "identifier", NULL, 0, "Property Name", "Name of the property to unset");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+#ifdef WITH_CLAY_ENGINE
+ rna_def_layer_collection_engine_settings_clay(brna);
+#endif
+
+ rna_def_layer_collection_mode_settings_object(brna);
+ rna_def_layer_collection_mode_settings_edit(brna);
+ rna_def_layer_collection_mode_settings_paint_weight(brna);
+ rna_def_layer_collection_mode_settings_paint_vertex(brna);
+
+ RNA_define_verify_sdna(1);
+}
+
+static void rna_def_layer_collection(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ srna = RNA_def_struct(brna, "LayerCollection", NULL);
+ RNA_def_struct_ui_text(srna, "Layer Collection", "Layer collection");
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop, "rna_LayerCollection_name_get", "rna_LayerCollection_name_length", "rna_LayerCollection_name_set");
+ RNA_def_property_ui_text(prop, "Name", "Collection name");
+ RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, NULL);
+
+ 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, "scene_collection");
+ RNA_def_property_struct_type(prop, "SceneCollection");
+ RNA_def_property_ui_text(prop, "Collection", "Collection this layer collection is wrapping");
+
+ prop = RNA_def_property(srna, "collections", 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, "Layer Collections", "");
+
+ 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_LayerCollection_objects_get", NULL, NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Objects", "All the objects directly or indirectly added to this collection (not including sub-collection objects)");
+
+ prop = RNA_def_property(srna, "overrides", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "overrides", NULL);
+ RNA_def_property_struct_type(prop, "LayerCollectionOverride");
+ RNA_def_property_ui_text(prop, "Collection Overrides", "");
+
+ /* Override settings */
+ prop = RNA_def_property(srna, "engine_overrides", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "properties->data.group", NULL);
+ RNA_def_property_struct_type(prop, "LayerCollectionSettings");
+ RNA_def_property_ui_text(prop, "Collection Settings", "Override of engine specific render settings");
+
+ /* Functions */
+ func = RNA_def_function(srna, "move_above", "rna_LayerCollection_move_above");
+ RNA_def_function_ui_description(func, "Move collection after another");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
+ parm = RNA_def_pointer(func, "lc_dst", "LayerCollection", "Collection", "Reference collection above which the collection will move");
+ parm = RNA_def_boolean(func, "result", false, "Result", "Whether the operation succeded");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "move_below", "rna_LayerCollection_move_below");
+ RNA_def_function_ui_description(func, "Move collection before another");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
+ parm = RNA_def_pointer(func, "lc_dst", "LayerCollection", "Collection", "Reference collection below which the collection will move");
+ parm = RNA_def_boolean(func, "result", false, "Result", "Whether the operation succeded");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "move_into", "rna_LayerCollection_move_into");
+ RNA_def_function_ui_description(func, "Move collection into another");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
+ parm = RNA_def_pointer(func, "lc_dst", "LayerCollection", "Collection", "Collection to insert into");
+ parm = RNA_def_boolean(func, "result", false, "Result", "Whether the operation succeded");
+ RNA_def_function_return(func, parm);
+
+ /* Flags */
+ prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", COLLECTION_VISIBLE);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 1);
+ RNA_def_property_ui_text(prop, "Hide", "Restrict visiblity");
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollection_flag_update");
+
+ prop = RNA_def_property(srna, "hide_select", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", COLLECTION_SELECTABLE);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, 1);
+ RNA_def_property_ui_text(prop, "Hide Selectable", "Restrict selection");
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollection_flag_update");
+
+ /* TODO_LAYER_OVERRIDE */
+}
+
+static void rna_def_layer_collections(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *prop;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "LayerCollections");
+ srna = RNA_def_struct(brna, "LayerCollections", NULL);
+ RNA_def_struct_sdna(srna, "SceneLayer");
+ RNA_def_struct_ui_text(srna, "Layer Collections", "Collections of render layer");
+
+ prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "active_collection");
+ RNA_def_property_int_funcs(prop, "rna_LayerCollections_active_collection_index_get",
+ "rna_LayerCollections_active_collection_index_set",
+ "rna_LayerCollections_active_collection_index_range");
+ RNA_def_property_ui_text(prop, "Active Collection Index", "Active index in layer collection array");
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER, NULL);
+
+ prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "LayerCollection");
+ RNA_def_property_pointer_funcs(prop, "rna_LayerCollections_active_collection_get",
+ "rna_LayerCollections_active_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");
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER, NULL);
+
+ func = RNA_def_function(srna, "link", "rna_SceneLayer_collection_link");
+ RNA_def_function_ui_description(func, "Link a collection to render layer");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
+ parm = RNA_def_pointer(func, "scene_collection", "SceneCollection", "", "Collection to add to render layer");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "result", "LayerCollection", "", "Newly created layer collection");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "unlink", "rna_SceneLayer_collection_unlink");
+ RNA_def_function_ui_description(func, "Unlink a collection from render layer");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "layer_collection", "LayerCollection", "", "Layer collection to remove from render layer");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+}
+
+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, "SceneLayer");
+ 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_base_object_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_SceneLayer_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_scene_layer(BlenderRNA *brna)
+{
+ FunctionRNA *func;
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem engine_items[] = {
+ {0, "BLENDER_RENDER", 0, "Blender Render", "Use the Blender internal rendering engine for rendering"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ srna = RNA_def_struct(brna, "SceneLayer", NULL);
+ RNA_def_struct_ui_text(srna, "Render Layer", "Render layer");
+ RNA_def_struct_ui_icon(srna, ICON_RENDERLAYERS);
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SceneLayer_name_set");
+ RNA_def_property_ui_text(prop, "Name", "Render layer name");
+ RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, NULL);
+
+ prop = RNA_def_property(srna, "collections", 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, "Layer Collections", "");
+ rna_def_layer_collections(brna, prop);
+
+ 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_SceneLayer_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", SCENE_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);
+
+ /* Override settings */
+ prop = RNA_def_property(srna, "engine_overrides", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "properties->data.group", NULL);
+ RNA_def_property_struct_type(prop, "SceneLayerSettings");
+ RNA_def_property_ui_text(prop, "Layer Settings", "Override of engine specific render settings");
+
+ /* engine */
+ prop = RNA_def_property(srna, "engine", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, engine_items);
+ RNA_def_property_enum_funcs(prop, "rna_SceneLayer_engine_get", "rna_SceneLayer_engine_set",
+ "rna_SceneLayer_engine_itemf");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Engine", "Engine to use for rendering");
+ RNA_def_property_update(prop, NC_WINDOW, "rna_SceneLayer_engine_update");
+
+ prop = RNA_def_property(srna, "has_multiple_engines", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_SceneLayer_multiple_engines_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Multiple Engines", "More than one rendering engine is available");
+
+ /* debug update routine */
+ func = RNA_def_function(srna, "update", "rna_SceneLayer_update_tagged");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func,
+ "Update data tagged to be updated from previous access to data or operators");
+}
+
+static void rna_def_scene_layers(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+ PropertyRNA *prop;
+
+ RNA_def_property_srna(cprop, "SceneLayers");
+ srna = RNA_def_struct(brna, "SceneLayers", 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, "active_layer");
+ RNA_def_property_int_funcs(prop, "rna_SceneLayer_active_layer_index_get",
+ "rna_SceneLayer_active_layer_index_set",
+ "rna_SceneLayer_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_LAYER, NULL);
+
+ prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "SceneLayer");
+ RNA_def_property_pointer_funcs(prop, "rna_SceneLayer_active_layer_get",
+ "rna_SceneLayer_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_LAYER, NULL);
+
+ func = RNA_def_function(srna, "new", "rna_SceneLayer_new");
+ RNA_def_function_ui_description(func, "Add a render layer to scene");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
+ parm = RNA_def_string(func, "name", "SceneLayer", 0, "", "New name for the render layer (not unique)");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "result", "SceneLayer", "", "Newly created render layer");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_SceneLayer_remove");
+ RNA_def_function_ui_description(func, "Remove a render layer");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "layer", "SceneLayer", "", "Render 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);
+}
+
+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");
+}
+
+/* TODO LAYERS: legacy SceneRenderLayers, to be removed */
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);
@@ -4939,7 +7090,7 @@ static void rna_def_render_layers(BlenderRNA *brna, PropertyRNA *cprop)
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)");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "result", "SceneRenderLayer", "", "Newly created render layer");
RNA_def_function_return(func, parm);
@@ -4947,8 +7098,8 @@ static void rna_def_render_layers(BlenderRNA *brna, PropertyRNA *cprop)
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");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
/* Render Views - MultiView */
@@ -5018,7 +7169,7 @@ static void rna_def_render_views(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Add a render view to scene");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_string(func, "name", "RenderView", 0, "", "New name for the marker (not unique)");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "result", "SceneRenderView", "", "Newly created render view");
RNA_def_function_return(func, parm);
@@ -5026,8 +7177,8 @@ static void rna_def_render_views(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a render view");
RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS | FUNC_USE_SELF_ID);
parm = RNA_def_pointer(func, "view", "SceneRenderView", "", "Render view to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_image_format_stereo3d_format(BlenderRNA *brna)
@@ -5118,7 +7269,7 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
srna = RNA_def_struct(brna, "ImageFormatSettings", NULL);
RNA_def_struct_sdna(srna, "ImageFormatData");
RNA_def_struct_nested(brna, srna, "Scene");
- /* RNA_def_struct_path_func(srna, "rna_RenderSettings_path"); *//* no need for the path, its not animated! */
+ RNA_def_struct_path_func(srna, "rna_ImageFormatSettings_path");
RNA_def_struct_ui_text(srna, "Image Format", "Settings for image formats");
prop = RNA_def_property(srna, "file_format", PROP_ENUM, PROP_NONE);
@@ -5205,7 +7356,7 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "jpeg2k_codec", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "jp2_codec");
RNA_def_property_enum_items(prop, jp2_codec_items);
- RNA_def_property_ui_text(prop, "Codec", "Codec settings for Jpek2000");
+ RNA_def_property_ui_text(prop, "Codec", "Codec settings for Jpeg2000");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
#endif
@@ -5275,6 +7426,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
PropertyRNA *prop;
#ifdef WITH_FFMPEG
+ /* Container types */
static EnumPropertyItem ffmpeg_format_items[] = {
{FFMPEG_MPEG1, "MPEG1", 0, "MPEG-1", ""},
{FFMPEG_MPEG2, "MPEG2", 0, "MPEG-2", ""},
@@ -5282,8 +7434,8 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
{FFMPEG_AVI, "AVI", 0, "AVI", ""},
{FFMPEG_MOV, "QUICKTIME", 0, "Quicktime", ""},
{FFMPEG_DV, "DV", 0, "DV", ""},
- {FFMPEG_H264, "H264", 0, "H.264", ""},
- {FFMPEG_XVID, "XVID", 0, "Xvid", ""},
+// {FFMPEG_H264, "H264", 0, "H.264", ""}, not a container
+// {FFMPEG_XVID, "XVID", 0, "Xvid", ""}, not a container
{FFMPEG_OGG, "OGG", 0, "Ogg", ""},
{FFMPEG_MKV, "MKV", 0, "Matroska", ""},
{FFMPEG_FLV, "FLASH", 0, "Flash", ""},
@@ -5307,6 +7459,32 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem ffmpeg_preset_items[] = {
+ {FFM_PRESET_ULTRAFAST, "ULTRAFAST", 0, "Ultra fast; biggest file", ""},
+ {FFM_PRESET_SUPERFAST, "SUPERFAST", 0, "Super fast", ""},
+ {FFM_PRESET_VERYFAST, "VERYFAST", 0, "Very fast", ""},
+ {FFM_PRESET_FASTER, "FASTER", 0, "Faster", ""},
+ {FFM_PRESET_FAST, "FAST", 0, "Fast", ""},
+ {FFM_PRESET_MEDIUM, "MEDIUM", 0, "Medium speed", ""},
+ {FFM_PRESET_SLOW, "SLOW", 0, "Slow", ""},
+ {FFM_PRESET_SLOWER, "SLOWER", 0, "Slower", ""},
+ {FFM_PRESET_VERYSLOW, "VERYSLOW", 0, "Very slow; smallest file", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem ffmpeg_crf_items[] = {
+ {FFM_CRF_NONE, "NONE", 0, "None; use constant bit-rate",
+ "Use constant bit rate, rather than constant output quality"},
+ {FFM_CRF_LOSSLESS, "LOSSLESS", 0, "Lossless", ""},
+ {FFM_CRF_PERC_LOSSLESS, "PERC_LOSSLESS", 0, "Perceptually lossless", ""},
+ {FFM_CRF_HIGH, "HIGH", 0, "High quality", ""},
+ {FFM_CRF_MEDIUM, "MEDIUM", 0, "Medium quality", ""},
+ {FFM_CRF_LOW, "LOW", 0, "Low quality", ""},
+ {FFM_CRF_VERYLOW, "VERYLOW", 0, "Very low quality", ""},
+ {FFM_CRF_LOWEST, "LOWEST", 0, "Lowest quality", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
static EnumPropertyItem ffmpeg_audio_codec_items[] = {
{AV_CODEC_ID_NONE, "NONE", 0, "None", ""},
{AV_CODEC_ID_MP2, "MP2", 0, "MP2", ""},
@@ -5338,13 +7516,15 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
RNA_def_property_enum_bitflag_sdna(prop, NULL, "type");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_enum_items(prop, ffmpeg_format_items);
- RNA_def_property_ui_text(prop, "Format", "Output file format");
+ RNA_def_property_enum_default(prop, FFMPEG_MKV);
+ RNA_def_property_ui_text(prop, "Container", "Output file container");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_FFmpegSettings_codec_settings_update");
prop = RNA_def_property(srna, "codec", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "codec");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_enum_items(prop, ffmpeg_codec_items);
+ RNA_def_property_enum_default(prop, AV_CODEC_ID_H264);
RNA_def_property_ui_text(prop, "Codec", "FFmpeg codec to use");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_FFmpegSettings_codec_settings_update");
@@ -5376,8 +7556,25 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "gopsize", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "gop_size");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_range(prop, 0, 100);
- RNA_def_property_ui_text(prop, "GOP Size", "Distance between key frames");
+ RNA_def_property_range(prop, 0, 500);
+ RNA_def_property_int_default(prop, 25);
+ RNA_def_property_ui_text(prop, "Keyframe interval",
+ "Distance between key frames, also known as GOP size; "
+ "influences file size and seekability");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "max_b_frames", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "max_b_frames");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_range(prop, 0, 16);
+ RNA_def_property_ui_text(prop, "Max B-frames",
+ "Maximum number of B-frames between non-B-frames; influences file size and seekability");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "use_max_b_frames", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FFMPEG_USE_MAX_B_FRAMES);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Use max B-frames", "Set a maximum number of B-frames");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "buffersize", PROP_INT, PROP_NONE);
@@ -5394,6 +7591,24 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Mux Packet Size", "Mux packet size (byte)");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ prop = RNA_def_property(srna, "constant_rate_factor", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "constant_rate_factor");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_enum_items(prop, ffmpeg_crf_items);
+ RNA_def_property_enum_default(prop, FFM_CRF_MEDIUM);
+ RNA_def_property_ui_text(prop, "Output quality",
+ "Constant Rate Factor (CRF); tradeoff between video quality and file size");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "ffmpeg_preset", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "ffmpeg_preset");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_enum_items(prop, ffmpeg_preset_items);
+ RNA_def_property_enum_default(prop, FFM_PRESET_MEDIUM);
+ RNA_def_property_ui_text(prop, "Encoding speed",
+ "Tradeoff between encoding speed and compression ratio");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
prop = RNA_def_property(srna, "use_autosplit", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FFMPEG_AUTOSPLIT_OUTPUT);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -6291,6 +8506,11 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Stamp Output", "Render the stamp info text in the rendered image");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ 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_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
prop = RNA_def_property(srna, "use_stamp_strip_meta", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_STRIPMETA);
RNA_def_property_ui_text(prop, "Strip Metadata", "Use metadata from the strips in the sequencer");
@@ -6488,14 +8708,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "BakeSettings");
RNA_def_property_ui_text(prop, "Bake Data", "");
- /* Debugging settings. */
-#ifdef WITH_CYCLES_DEBUG
- prop = RNA_def_property(srna, "debug_pass_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_enum_render_pass_debug_type_items);
- RNA_def_property_ui_text(prop, "Debug Pass Type", "Type of the debug pass to use");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-#endif
-
/* Nestled Data */
/* *** Non-Animated *** */
RNA_define_animate_sdna(false);
@@ -6526,15 +8738,15 @@ static void rna_def_scene_objects(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Link object to scene, run scene.update() after");
RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "object", "Object", "", "Object to add to scene");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
- parm = RNA_def_pointer(func, "base", "ObjectBase", "", "The newly created base");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "base", "ObjectBaseLegacy", "", "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_REPORTS);
parm = RNA_def_pointer(func, "object", "Object", "", "Object to remove from scene");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ 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");
@@ -6562,7 +8774,7 @@ static void rna_def_scene_bases(BlenderRNA *brna, PropertyRNA *cprop)
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_struct_type(prop, "ObjectBaseLegacy");
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");
@@ -6585,7 +8797,7 @@ static void rna_def_timeline_markers(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_TimeLine_add");
RNA_def_function_ui_description(func, "Add a keyframe to the curve");
parm = RNA_def_string(func, "name", "Marker", 0, "", "New name for the marker (not unique)");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "frame", 1, -MAXFRAME, MAXFRAME, "", "The frame for the new marker", -MAXFRAME, MAXFRAME);
parm = RNA_def_pointer(func, "marker", "TimelineMarker", "", "Newly created timeline marker");
RNA_def_function_return(func, parm);
@@ -6595,8 +8807,8 @@ static void rna_def_timeline_markers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove a timeline marker");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "marker", "TimelineMarker", "", "Timeline marker to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ 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_TimeLine_clear");
RNA_def_function_ui_description(func, "Remove all timeline markers");
@@ -6623,7 +8835,6 @@ static void rna_def_scene_keying_sets(BlenderRNA *brna, PropertyRNA *cprop)
/* name */
RNA_def_string(func, "idname", "KeyingSet", 64, "IDName", "Internal identifier of Keying Set");
RNA_def_string(func, "name", "KeyingSet", 64, "Name", "User visible name of Keying Set");
-
/* returns the new KeyingSet */
parm = RNA_def_pointer(func, "keyingset", "KeyingSet", "", "Newly created Keying Set");
RNA_def_function_return(func, parm);
@@ -6715,7 +8926,7 @@ static void rna_def_display_safe_areas(BlenderRNA *brna)
RNA_def_property_array(prop, 2);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_float_array_default(prop, default_title);
- RNA_def_property_ui_text(prop, "Title Safe margins", "Safe area for text and graphics");
+ RNA_def_property_ui_text(prop, "Title Safe Margins", "Safe area for text and graphics");
RNA_def_property_update(prop, NC_SCENE | ND_DRAW_RENDER_VIEWPORT, NULL);
prop = RNA_def_property(srna, "action", PROP_FLOAT, PROP_XYZ);
@@ -6726,7 +8937,6 @@ static void rna_def_display_safe_areas(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Action Safe Margins", "Safe area for general elements");
RNA_def_property_update(prop, NC_SCENE | ND_DRAW_RENDER_VIEWPORT, NULL);
-
prop = RNA_def_property(srna, "title_center", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "title_center");
RNA_def_property_array(prop, 2);
@@ -6773,8 +8983,8 @@ void RNA_def_scene(BlenderRNA *brna)
/* Struct definition */
srna = RNA_def_struct(brna, "Scene", "ID");
- RNA_def_struct_ui_text(srna, "Scene",
- "Scene data block, consisting in objects and defining time and render related settings");
+ RNA_def_struct_ui_text(srna, "Scene", "Scene data-block, consisting in objects and "
+ "defining time and render related settings");
RNA_def_struct_ui_icon(srna, ICON_SCENE_DATA);
RNA_def_struct_clear_flag(srna, STRUCT_ID_REFCOUNT);
@@ -6796,7 +9006,7 @@ void RNA_def_scene(BlenderRNA *brna)
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");
@@ -6807,7 +9017,7 @@ void RNA_def_scene(BlenderRNA *brna)
/* 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_struct_type(prop, "ObjectBaseLegacy");
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);
@@ -6849,8 +9059,19 @@ void RNA_def_scene(BlenderRNA *brna)
prop = RNA_def_property(srna, "frame_subframe", PROP_FLOAT, PROP_TIME);
RNA_def_property_float_sdna(prop, NULL, "r.subframe");
RNA_def_property_ui_text(prop, "Current Sub-Frame", "");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
-
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.01, 2);
+ RNA_def_property_update(prop, NC_SCENE | ND_FRAME, "rna_Scene_frame_update");
+
+ prop = RNA_def_property(srna, "frame_float", PROP_FLOAT, PROP_TIME);
+ RNA_def_property_ui_text(prop, "Current Sub-Frame", "");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_range(prop, MINAFRAME, MAXFRAME);
+ RNA_def_property_ui_range(prop, MINAFRAME, MAXFRAME, 0.1, 2);
+ RNA_def_property_float_funcs(prop, "rna_Scene_frame_float_get", "rna_Scene_frame_float_set", NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_FRAME, "rna_Scene_frame_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, "r.sfra");
@@ -6915,7 +9136,15 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_int_funcs(prop, NULL, "rna_Scene_preview_range_end_frame_set", NULL);
RNA_def_property_ui_text(prop, "Preview Range End Frame", "Alternative end frame for UI playback");
RNA_def_property_update(prop, NC_SCENE | ND_FRAME, NULL);
-
+
+ /* Subframe for moblur debug. */
+ prop = RNA_def_property(srna, "show_subframe", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_boolean_sdna(prop, NULL, "r.flag", SCER_SHOW_SUBFRAME);
+ RNA_def_property_ui_text(prop, "Show Subframe",
+ "Show current scene subframe and allow set it using interface tools");
+ RNA_def_property_update(prop, NC_SCENE | ND_FRAME, "rna_Scene_show_subframe_update");
+
/* Timeline / Time Navigation settings */
prop = RNA_def_property(srna, "show_keys_from_selected_only", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SCE_KEYS_NO_SELONLY);
@@ -7037,7 +9266,20 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "r");
RNA_def_property_struct_type(prop, "RenderSettings");
RNA_def_property_ui_text(prop, "Render Data", "");
-
+
+ /* Render Engine Data */
+ prop = RNA_def_property(srna, "layer_properties", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "layer_properties->data.group", NULL);
+ RNA_def_property_struct_type(prop, "SceneLayerSettings");
+ RNA_def_property_ui_text(prop, "Layer Settings",
+ "Engine specific render settings to be overridden by layers");
+
+ prop = RNA_def_property(srna, "collection_properties", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "collection_properties->data.group", NULL);
+ RNA_def_property_struct_type(prop, "LayerCollectionSettings");
+ RNA_def_property_ui_text(prop, "Collection Settings",
+ "Engine specific render settings to be overridden by collections");
+
/* Safe Areas */
prop = RNA_def_property(srna, "safe_areas", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "safe_areas");
@@ -7107,8 +9349,10 @@ void RNA_def_scene(BlenderRNA *brna)
/* Statistics */
func = RNA_def_function(srna, "statistics", "ED_info_stats_string");
- prop = RNA_def_string(func, "statistics", NULL, 0, "Statistics", "");
- RNA_def_function_return(func, prop);
+ parm = RNA_def_pointer(func, "scene_layer", "SceneLayer", "", "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);
/* Grease Pencil */
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
@@ -7117,12 +9361,6 @@ void RNA_def_scene(BlenderRNA *brna)
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_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);
@@ -7150,25 +9388,46 @@ void RNA_def_scene(BlenderRNA *brna)
/* Dependency Graph */
prop = RNA_def_property(srna, "depsgraph", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "depsgraph_legacy");
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, "render_layers", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "render_layers", NULL);
+ RNA_def_property_struct_type(prop, "SceneLayer");
+ RNA_def_property_ui_text(prop, "Render Layers", "");
+ rna_def_scene_layers(brna, prop);
+
+ prop = RNA_def_property(srna, "master_collection", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_pointer_sdna(prop, NULL, "collection");
+ RNA_def_property_struct_type(prop, "SceneCollection");
+ RNA_def_property_ui_text(prop, "Master Collection", "Collection that contains all other collections");
+
/* 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_collection(brna);
+ rna_def_layer_collection(brna);
+ rna_def_layer_collection_override(brna);
+ rna_def_scene_layer(brna);
+ rna_def_object_base(brna);
RNA_define_animate_sdna(true);
/* *** Animated *** */
+ rna_def_scene_layer_settings(brna);
+ rna_def_layer_collection_settings(brna);
rna_def_scene_render_data(brna);
rna_def_scene_render_layer(brna);
rna_def_gpu_fx(brna);
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index ed51f0cffb0..2ebd0eb2f11 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -60,7 +60,6 @@ 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"
@@ -86,8 +85,7 @@ static void rna_Scene_frame_set(Scene *scene, int frame, float subframe)
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(G.main->eval_ctx, G.main, scene, (1 << 20) - 1, true);
+ BKE_scene_update_for_newframe(G.main->eval_ctx, G.main, scene);
#ifdef WITH_PYTHON
BPy_END_ALLOW_THREADS;
@@ -112,7 +110,7 @@ static void rna_Scene_uvedit_aspect(Scene *scene, Object *ob, float *aspect)
if ((ob->type == OB_MESH) && (ob->mode == OB_MODE_EDIT)) {
BMEditMesh *em;
em = BKE_editmesh_from_object(ob);
- if (EDBM_mtexpoly_check(em)) {
+ if (EDBM_uv_check(em)) {
ED_uvedit_get_aspect(scene, ob, em->bm, aspect, aspect + 1);
return;
}
@@ -153,18 +151,17 @@ static void rna_SceneRender_get_frame_path(RenderData *rd, int frame, int previe
}
static void rna_Scene_ray_cast(
- Scene *scene, float origin[3], float direction[3], float ray_dist,
+ Scene *scene, SceneLayer *sl, float origin[3], float direction[3], float ray_dist,
int *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(
- G.main, scene, 0);
+ G.main, scene, sl, 0);
bool ret = ED_transform_snap_object_project_ray_ex(
sctx,
- SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
},
@@ -208,9 +205,14 @@ static void rna_Scene_alembic_export(
int renderable_only,
int face_sets,
int use_subdiv_schema,
+ int export_hair,
+ int export_particles,
int compression_type,
int packuv,
- float scale)
+ float scale,
+ int triangulate,
+ int quad_method,
+ int ngon_method)
{
/* We have to enable allow_threads, because we may change scene frame number
* during export. */
@@ -222,8 +224,8 @@ static void rna_Scene_alembic_export(
.frame_start = frame_start,
.frame_end = frame_end,
- .frame_step_xform = 1.0 / (double)xform_samples,
- .frame_step_shape = 1.0 / (double)geom_samples,
+ .frame_samples_xform = xform_samples,
+ .frame_samples_shape = geom_samples,
.shutter_open = shutter_open,
.shutter_close = shutter_close,
@@ -238,13 +240,18 @@ static void rna_Scene_alembic_export(
.renderable_only = renderable_only,
.face_sets = face_sets,
.use_subdiv_schema = use_subdiv_schema,
+ .export_hair = export_hair,
+ .export_particles = export_particles,
.compression_type = compression_type,
.packuv = packuv,
+ .triangulate = triangulate,
+ .quad_method = quad_method,
+ .ngon_method = ngon_method,
.global_scale = scale,
};
- ABC_export(scene, C, filepath, &params);
+ ABC_export(scene, C, filepath, &params, true);
#ifdef WITH_PYTHON
BPy_END_ALLOW_THREADS;
@@ -257,34 +264,57 @@ static void rna_Scene_alembic_export(
/* don't remove this, as COLLADA exporting cannot be done through operators in render() callback. */
#include "../../collada/collada.h"
+/* Note: This definition must match to the generated function call */
static void rna_Scene_collada_export(
Scene *scene,
- const char *filepath,
+ bContext *C,
+ const char *filepath,
int apply_modifiers,
- int export_mesh_type,
+ int export_mesh_type,
int selected,
int include_children,
int include_armatures,
int include_shapekeys,
int deform_bones_only,
-
int active_uv_only,
- int include_uv_textures,
int include_material_textures,
int use_texture_copies,
-
- int use_ngons,
+ int triangulate,
int use_object_instantiation,
int use_blender_profile,
int sort_by_name,
int export_transformation_type,
- int open_sim)
+ int open_sim,
+ int limit_precision,
+ int keep_bind_info)
{
- collada_export(scene, filepath, apply_modifiers, export_mesh_type, selected,
- include_children, include_armatures, include_shapekeys, deform_bones_only,
- active_uv_only, include_uv_textures, include_material_textures,
- use_texture_copies, use_ngons, use_object_instantiation, use_blender_profile, sort_by_name, export_transformation_type, open_sim);
+ collada_export(scene,
+ CTX_data_scene_layer(C),
+ filepath,
+
+ apply_modifiers,
+ export_mesh_type,
+
+ selected,
+ include_children,
+ include_armatures,
+ include_shapekeys,
+ deform_bones_only,
+
+ active_uv_only,
+ include_material_textures,
+ use_texture_copies,
+
+ triangulate,
+ use_object_instantiation,
+ use_blender_profile,
+ sort_by_name,
+
+ export_transformation_type,
+ open_sim,
+ limit_precision,
+ keep_bind_info);
}
#endif
@@ -299,7 +329,7 @@ void RNA_api_scene(StructRNA *srna)
func = RNA_def_function(srna, "frame_set", "rna_Scene_frame_set");
RNA_def_function_ui_description(func, "Set scene frame updating all objects immediately");
parm = RNA_def_int(func, "frame", 0, MINAFRAME, MAXFRAME, "", "Frame number to set", MINAFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_float(func, "subframe", 0.0, 0.0, 1.0, "", "Sub-frame time, between 0.0 and 1.0", 0.0, 1.0);
func = RNA_def_function(srna, "update", "rna_Scene_update_tagged");
@@ -309,34 +339,33 @@ void RNA_api_scene(StructRNA *srna)
func = RNA_def_function(srna, "uvedit_aspect", "rna_Scene_uvedit_aspect");
RNA_def_function_ui_description(func, "Get uv aspect for current object");
parm = RNA_def_pointer(func, "object", "Object", "", "Object");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
-
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_float_vector(func, "result", 2, NULL, 0.0f, FLT_MAX, "", "aspect", 0.0f, FLT_MAX);
- RNA_def_property_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_function_output(func, parm);
/* Ray Cast */
func = RNA_def_function(srna, "ray_cast", "rna_Scene_ray_cast");
RNA_def_function_ui_description(func, "Cast a ray onto in object space");
-
+ parm = RNA_def_pointer(func, "scene_layer", "SceneLayer", "", "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_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_float_vector(func, "direction", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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, "", "");
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);
- RNA_def_property_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_function_output(func, parm);
parm = RNA_def_float_vector(func, "normal", 3, NULL, -FLT_MAX, FLT_MAX, "Normal",
"The face normal at the ray cast hit location", -1e4, 1e4);
- RNA_def_property_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_function_output(func, parm);
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);
@@ -349,40 +378,71 @@ void RNA_api_scene(StructRNA *srna)
/* don't remove this, as COLLADA exporting cannot be done through operators in render() callback. */
func = RNA_def_function(srna, "collada_export", "rna_Scene_collada_export");
parm = RNA_def_string(func, "filepath", NULL, FILE_MAX, "File Path", "File path to write Collada file");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_property_subtype(parm, PROP_FILEPATH); /* allow non utf8 */
- parm = RNA_def_boolean(func, "apply_modifiers", 0, "Apply Modifiers", "Apply modifiers");
- parm = RNA_def_int(func, "export_mesh_type", 0, INT_MIN, INT_MAX,
+
+ RNA_def_boolean(func, "apply_modifiers", false,
+ "Apply Modifiers", "Apply modifiers to exported mesh (non destructive))");
+
+ RNA_def_int(func, "export_mesh_type", 0, INT_MIN, INT_MAX,
"Resolution", "Modifier resolution for export", INT_MIN, INT_MAX);
- parm = RNA_def_boolean(func, "selected", 0, "Selection Only", "Export only selected elements");
- parm = RNA_def_boolean(func, "include_children", 0, "Include Children", "Export all children of selected objects (even if not selected)");
- parm = RNA_def_boolean(func, "include_armatures", 0, "Include Armatures", "Export related armatures (even if not selected)");
- parm = RNA_def_boolean(func, "include_shapekeys", 0, "Include Shape Keys", "Export all Shape Keys from Mesh Objects");
- parm = RNA_def_boolean(func, "deform_bones_only", 0, "Deform Bones only", "Only export deforming bones with armatures");
-
- parm = RNA_def_boolean(func, "active_uv_only", 0, "Active UV Layer only", "Export only the active UV Layer");
- parm = RNA_def_boolean(func, "include_uv_textures", 0, "Include UV Textures", "Export textures assigned to the object UV maps");
- parm = RNA_def_boolean(func, "include_material_textures", 0, "Include Material Textures", "Export textures assigned to the object Materials");
- parm = RNA_def_boolean(func, "use_texture_copies", 0, "copy", "Copy textures to same folder where the .dae file is exported");
-
- parm = RNA_def_boolean(func, "use_ngons", 1, "Use NGons", "Keep NGons in Export");
- parm = RNA_def_boolean(func, "use_object_instantiation", 1, "Use Object Instances", "Instantiate multiple Objects from same Data");
- parm = RNA_def_boolean(func, "use_blender_profile", 1, "Use Blender Profile", "Export additional Blender specific information (for material, shaders, bones, etc.)");
- parm = RNA_def_boolean(func, "sort_by_name", 0, "Sort by Object name", "Sort exported data by Object name");
- parm = RNA_def_boolean(func, "open_sim", 0, "Export for SL/OpenSim", "Compatibility mode for SL, OpenSim and similar online worlds");
-
- parm = RNA_def_int(func, "export_transformation_type", 0, INT_MIN, INT_MAX,
- "Transformation", "Transformation type for translation, scale and rotation", INT_MIN, INT_MAX);
-
- RNA_def_function_ui_description(func, "Export to collada file");
+
+ RNA_def_boolean(func, "selected", false, "Selection Only", "Export only selected elements");
+
+ RNA_def_boolean(func, "include_children", false,
+ "Include Children", "Export all children of selected objects (even if not selected)");
+
+ RNA_def_boolean(func, "include_armatures", false,
+ "Include Armatures", "Export related armatures (even if not selected)");
+
+ RNA_def_boolean(func, "include_shapekeys", true, "Include Shape Keys", "Export all Shape Keys from Mesh Objects");
+
+ RNA_def_boolean(func, "deform_bones_only", false,
+ "Deform Bones only", "Only export deforming bones with armatures");
+
+ RNA_def_boolean(func, "active_uv_only", false, "Only Selected UV Map", "Export only the selected UV Map");
+
+ RNA_def_boolean(func, "include_material_textures", false,
+ "Include Material Textures", "Export textures assigned to the object Materials");
+
+ RNA_def_boolean(func, "use_texture_copies", true,
+ "Copy", "Copy textures to same folder where the .dae file is exported");
+
+ RNA_def_boolean(func, "triangulate", true, "Triangulate", "Export Polygons (Quads & NGons) as Triangles");
+
+ RNA_def_boolean(func, "use_object_instantiation", true,
+ "Use Object Instances", "Instantiate multiple Objects from same Data");
+
+ RNA_def_boolean(func, "use_blender_profile", true, "Use Blender Profile",
+ "Export additional Blender specific information (for material, shaders, bones, etc.)");
+
+ RNA_def_boolean(func, "sort_by_name", false, "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);
+
+ RNA_def_boolean(func, "open_sim", false,
+ "Export to SL/OpenSim", "Compatibility mode for SL, OpenSim and other compatible online worlds");
+
+ RNA_def_boolean(func, "limit_precision", false,
+ "Limit Precision",
+ "Reduce the precision of the exported data to 6 digits");
+
+ RNA_def_boolean(func, "keep_bind_info", false,
+ "Keep Bind Info",
+ "Store bind pose information in custom bone properties for later use during Collada export");
+
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+
#endif
#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");
- RNA_def_function_ui_description(func, "Export to Alembic file");
+ RNA_def_function_ui_description(func, "Export to Alembic file (deprecated, use the Alembic export operator)");
parm = RNA_def_string(func, "filepath", NULL, FILE_MAX, "File Path", "File path to write Alembic file");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_property_subtype(parm, PROP_FILEPATH); /* allow non utf8 */
RNA_def_int(func, "frame_start", 1, INT_MIN, INT_MAX, "Start", "Start Frame", INT_MIN, INT_MAX);
@@ -401,9 +461,14 @@ void RNA_api_scene(StructRNA *srna)
RNA_def_boolean(func, "renderable_only" , 0, "Renderable objects only", "Export only objects marked renderable in the outliner");
RNA_def_boolean(func, "face_sets" , 0, "Facesets", "Export face sets");
RNA_def_boolean(func, "subdiv_schema", 0, "Use Alembic subdivision Schema", "Use Alembic subdivision Schema");
+ RNA_def_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_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");
+ RNA_def_enum(func, "ngon_method", rna_enum_modifier_triangulate_quad_method_items, 0, "Polygon Method", "Method for splitting the polygons into triangles");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
#endif
@@ -419,13 +484,12 @@ void RNA_api_scene_render(StructRNA *srna)
RNA_def_function_ui_description(func, "Return the absolute path to the filename to be written for a given frame");
RNA_def_int(func, "frame", INT_MIN, INT_MIN, INT_MAX, "",
"Frame number to use, if unset the current frame will be used", MINAFRAME, MAXFRAME);
- parm = RNA_def_boolean(func, "preview", 0, "Preview", "Use preview range");
- parm = RNA_def_string_file_path(func, "view", NULL, FILE_MAX, "View",
+ RNA_def_boolean(func, "preview", 0, "Preview", "Use preview range");
+ RNA_def_string_file_path(func, "view", NULL, FILE_MAX, "View",
"The name of the view to use to replace the \"%\" chars");
-
parm = RNA_def_string_file_path(func, "filepath", NULL, FILE_MAX, "File Path",
"The resulting filepath from the scenes render settings");
- RNA_def_property_flag(parm, PROP_THICK_WRAP); /* needed for string return value */
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); /* needed for string return value */
RNA_def_function_output(func, parm);
}
diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c
index 43d5cda17ae..003445889c3 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"
EnumPropertyItem rna_enum_region_type_items[] = {
{RGN_TYPE_WINDOW, "WINDOW", 0, "Window", ""},
@@ -56,7 +57,9 @@ EnumPropertyItem rna_enum_region_type_items[] = {
#ifdef RNA_RUNTIME
#include "BKE_global.h"
-#include "BKE_depsgraph.h"
+#include "BKE_workspace.h"
+
+#include "DEG_depsgraph.h"
#include "UI_view2d.h"
@@ -64,55 +67,58 @@ EnumPropertyItem rna_enum_region_type_items[] = {
# include "BPY_extern.h"
#endif
-static void rna_Screen_scene_set(PointerRNA *ptr, PointerRNA value)
-{
- bScreen *sc = (bScreen *)ptr->data;
- if (value.data == NULL)
- return;
+static void rna_Screen_redraw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ bScreen *screen = (bScreen *)ptr->data;
- sc->newscene = value.data;
+ /* 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);
}
-static void rna_Screen_scene_update(bContext *C, PointerRNA *ptr)
+static int rna_Screen_is_animation_playing_get(PointerRNA *UNUSED(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
-
- ED_screen_set_scene(C, sc, sc->newscene);
-
-#ifdef WITH_PYTHON
- BPy_END_ALLOW_THREADS;
-#endif
-
- WM_event_add_notifier(C, NC_SCENE | ND_SCENEBROWSE, sc->newscene);
+ /* can be NULL on file load, T42619 */
+ wmWindowManager *wm = G.main->wm.first;
+ return wm ? (ED_screen_animation_playing(wm) != NULL) : 0;
+}
- 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 int 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 int rna_Screen_fullscreen_get(PointerRNA *ptr)
@@ -152,7 +158,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);
@@ -166,7 +172,7 @@ static void rna_Area_type_update(bContext *C, PointerRNA *ptr)
/* 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);
@@ -285,22 +291,22 @@ static void rna_def_view2d_api(StructRNA *srna)
func = RNA_def_function(srna, "region_to_view", "rna_View2D_region_to_view");
RNA_def_function_ui_description(func, "Transform region coordinates to 2D view");
parm = RNA_def_int(func, "x", 0, INT_MIN, INT_MAX, "x", "Region x coordinate", -10000, 10000);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "y", 0, INT_MIN, INT_MAX, "y", "Region y coordinate", -10000, 10000);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_float_array(func, "result", 2, view_default, -FLT_MAX, FLT_MAX, "Result", "View coordinates", -10000.0f, 10000.0f);
- RNA_def_property_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_function_output(func, parm);
func = RNA_def_function(srna, "view_to_region", "rna_View2D_view_to_region");
RNA_def_function_ui_description(func, "Transform 2D view coordinates to region");
parm = RNA_def_float(func, "x", 0.0f, -FLT_MAX, FLT_MAX, "x", "2D View x coordinate", -10000.0f, 10000.0f);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_float(func, "y", 0.0f, -FLT_MAX, FLT_MAX, "y", "2D View y coordinate", -10000.0f, 10000.0f);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "clip", 1, "Clip", "Clip coordinates to the visible region");
parm = RNA_def_int_array(func, "result", 2, region_default, INT_MIN, INT_MAX, "Result", "Region coordinates", -10000, 10000);
- RNA_def_property_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_function_output(func, parm);
}
@@ -377,13 +383,11 @@ static void rna_def_screen(BlenderRNA *brna)
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);
- /* 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);
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 57cb0d95b38..5951d82cd1a 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -75,6 +75,14 @@ EnumPropertyItem rna_enum_gpencil_sculpt_brush_items[] = {
{ 0, NULL, 0, NULL, NULL }
};
+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 }
+};
+
EnumPropertyItem rna_enum_symmetrize_direction_items[] = {
{BMO_SYMMETRIZE_NEGATIVE_X, "NEGATIVE_X", 0, "-X to +X", ""},
{BMO_SYMMETRIZE_POSITIVE_X, "POSITIVE_X", 0, "+X to -X", ""},
@@ -96,9 +104,10 @@ EnumPropertyItem rna_enum_symmetrize_direction_items[] = {
#include "BKE_effect.h"
#include "BKE_pointcache.h"
#include "BKE_particle.h"
-#include "BKE_depsgraph.h"
#include "BKE_pbvh.h"
+#include "DEG_depsgraph.h"
+
#include "GPU_buffers.h"
#include "ED_particle.h"
@@ -142,10 +151,12 @@ static PointerRNA rna_ParticleBrush_curve_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_CurveMapping, NULL);
}
-static void rna_ParticleEdit_redo(Main *UNUSED(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(scene, ob);
+ Scene *scene = CTX_data_scene(C);
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *ob = OBACT_NEW;
+ PTCacheEdit *edit = PE_get_current(scene, sl, ob);
if (!edit)
return;
@@ -153,21 +164,23 @@ static void rna_ParticleEdit_redo(Main *UNUSED(bmain), Scene *scene, PointerRNA
psys_free_path_cache(edit->psys, edit);
}
-static void rna_ParticleEdit_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
+static void rna_ParticleEdit_update(Main *UNUSED(bmain), Scene *UNUSED(scene), bContext *C, PointerRNA *UNUSED(ptr))
{
- Object *ob = (scene->basact) ? scene->basact->object : NULL;
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *ob = OBACT_NEW;
- if (ob) DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ if (ob) DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
+
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->scene_layer) {
+ Object *ob = (pset->scene_layer->basact) ? pset->scene_layer->basact->object : NULL;
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);
}
}
@@ -177,9 +190,10 @@ static void rna_ParticleEdit_tool_set(PointerRNA *ptr, int value)
static 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;
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *ob = OBACT_NEW;
#if 0
+ Scene *scene = CTX_data_scene(C);
PTCacheEdit *edit = PE_get_current(scene, ob);
ParticleSystem *psys = edit ? edit->psys : NULL;
#else
@@ -205,14 +219,14 @@ static int rna_ParticleEdit_editable_get(PointerRNA *ptr)
{
ParticleEditSettings *pset = (ParticleEditSettings *)ptr->data;
- return (pset->object && pset->scene && PE_get_current(pset->scene, pset->object));
+ return (pset->object && pset->scene && PE_get_current(pset->scene, pset->scene_layer, pset->object));
}
static int rna_ParticleEdit_hair_get(PointerRNA *ptr)
{
ParticleEditSettings *pset = (ParticleEditSettings *)ptr->data;
if (pset->scene) {
- PTCacheEdit *edit = PE_get_current(pset->scene, pset->object);
+ PTCacheEdit *edit = PE_get_current(pset->scene, pset->scene_layer, pset->object);
return (edit && edit->psys);
}
@@ -249,12 +263,14 @@ static int rna_Brush_mode_poll(PointerRNA *ptr, PointerRNA value)
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);
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *ob = OBACT_NEW;
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) {
@@ -264,9 +280,10 @@ 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, Scene *scene, PointerRNA *UNUSED(ptr))
{
- Object *ob = (scene->basact) ? scene->basact->object : NULL;
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *ob = OBACT_NEW;
if (ob && ob->sculpt) {
Sculpt *sd = scene->toolsettings->sculpt;
@@ -325,9 +342,11 @@ 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);\
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *ob = OBACT_NEW;
if (ob && ob->type == OB_MESH) {
/* of course we need to invalidate here */
@@ -340,9 +359,11 @@ static void rna_ImaPaint_mode_update(Main *UNUSED(bmain), Scene *scene, PointerR
}
}
-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);
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *ob = OBACT_NEW;
if (ob && ob->type == OB_MESH) {
GPU_drawobject_free(ob->derivedFinal);
@@ -351,19 +372,22 @@ static void rna_ImaPaint_stencil_update(Main *UNUSED(bmain), Scene *scene, Point
}
}
-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);
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *ob = OBACT_NEW;
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(sima, scene, scene->obedit, ima);
@@ -418,7 +442,7 @@ static void rna_HairEdit_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *U
Object *ob = OBACT;
if (ob)
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
static void rna_HairEdit_brush_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
@@ -600,12 +624,14 @@ 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, "detail_size", PROP_FLOAT, PROP_PIXEL);
@@ -618,10 +644,12 @@ static void rna_def_sculpt(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Detail Percentage", "Maximum edge length for dynamic topology sculpting (in brush percenage)");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
- prop = RNA_def_property(srna, "constant_detail", PROP_FLOAT, PROP_PERCENTAGE);
- RNA_def_property_range(prop, 0.001, 10000.0);
- RNA_def_property_ui_range(prop, 0.1, 100.0, 10, 2);
- RNA_def_property_ui_text(prop, "Detail Size", "Maximum edge length for dynamic topology sculpting (as percentage of blender unit)");
+ prop = RNA_def_property(srna, "constant_detail_resolution", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "constant_detail");
+ RNA_def_property_range(prop, 0.0001, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001, 1000.0, 10, 2);
+ RNA_def_property_ui_text(prop, "Resolution", "Maximum edge length for dynamic topology sculpting (as divisor "
+ "of blender unit - higher value means smaller edge length)");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "use_smooth_shading", PROP_BOOLEAN, PROP_NONE);
@@ -629,6 +657,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);
@@ -756,12 +785,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");
@@ -803,6 +832,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");
@@ -882,6 +912,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);
@@ -904,6 +935,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);
@@ -911,6 +943,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");
@@ -931,6 +964,7 @@ static void rna_def_particle_edit(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Brush", "");
prop = RNA_def_property(srna, "draw_step", PROP_INT, PROP_NONE);
+ 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_update(prop, NC_OBJECT | ND_DRAW, "rna_ParticleEdit_redo");
@@ -938,9 +972,11 @@ static void rna_def_particle_edit(BlenderRNA *brna)
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", "");
@@ -961,7 +997,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");
@@ -1050,25 +1086,33 @@ static void rna_def_gpencil_sculpt(BlenderRNA *brna)
prop = RNA_def_property(srna, "affect_position", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_APPLY_POSITION);
- RNA_def_property_ui_text(prop, "Affect position", "The brush affects the position of the point");
+ RNA_def_property_ui_text(prop, "Affect Position", "The brush affects the position of the point");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "affect_strength", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_APPLY_STRENGTH);
- RNA_def_property_ui_text(prop, "Affect strength", "The brush affects the color strength of the point");
+ RNA_def_property_ui_text(prop, "Affect Strength", "The brush affects the color strength of the point");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "affect_thickness", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_APPLY_THICKNESS);
- RNA_def_property_ui_text(prop, "Affect thickness", "The brush affects the thickness of the point");
+ RNA_def_property_ui_text(prop, "Affect Thickness", "The brush affects the thickness of the point");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
prop = RNA_def_property(srna, "selection_alpha", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "alpha");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Alpha", "Alpha value for selected vertices");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_GPencil_update");
+ /* lock axis */
+ prop = RNA_def_property(srna, "lockaxis", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "lock_axis");
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_lockaxis_items);
+ RNA_def_property_ui_text(prop, "Lock", "");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
/* brush */
srna = RNA_def_struct(brna, "GPencilSculptBrush", NULL);
RNA_def_struct_sdna(srna, "GP_EditBrush_Data");
diff --git a/source/blender/makesrna/intern/rna_sensor.c b/source/blender/makesrna/intern/rna_sensor.c
index ee24a434486..d0afab7a1e3 100644
--- a/source/blender/makesrna/intern/rna_sensor.c
+++ b/source/blender/makesrna/intern/rna_sensor.c
@@ -32,6 +32,7 @@
#include "BLI_utildefines.h"
#include "BLI_math.h"
+#include "BLI_string_utils.h"
#include "BLT_translation.h"
diff --git a/source/blender/makesrna/intern/rna_sensor_api.c b/source/blender/makesrna/intern/rna_sensor_api.c
index 476f0589bc9..b0c4109b1df 100644
--- a/source/blender/makesrna/intern/rna_sensor_api.c
+++ b/source/blender/makesrna/intern/rna_sensor_api.c
@@ -65,13 +65,13 @@ void RNA_api_sensor(StructRNA *srna)
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_property_flag(parm, PROP_REQUIRED);
+ 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_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_property_update(parm, NC_LOGIC, NULL);
}
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index c3a66058888..f628c5f14d9 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -292,7 +292,7 @@ static int rna_Sequence_frame_length_get(PointerRNA *ptr)
return BKE_sequence_tx_get_final_right(seq, false) - BKE_sequence_tx_get_final_left(seq, false);
}
-static int rna_Sequence_frame_editable(PointerRNA *ptr)
+static int rna_Sequence_frame_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
Sequence *seq = (Sequence *)ptr->data;
/* Effect sequences' start frame and length must be readonly! */
@@ -341,7 +341,7 @@ static void rna_Sequence_use_translation_set(PointerRNA *ptr, int value)
}
}
else {
- seq->flag ^= SEQ_USE_TRANSFORM;
+ seq->flag &= ~SEQ_USE_TRANSFORM;
}
}
@@ -355,7 +355,7 @@ static void rna_Sequence_use_crop_set(PointerRNA *ptr, int value)
}
}
else {
- seq->flag ^= SEQ_USE_CROP;
+ seq->flag &= ~SEQ_USE_CROP;
}
}
@@ -1095,7 +1095,7 @@ static void rna_def_strip_element(BlenderRNA *brna)
prop = RNA_def_property(srna, "filename", PROP_STRING, PROP_FILENAME);
RNA_def_property_string_sdna(prop, NULL, "name");
- RNA_def_property_ui_text(prop, "Filename", "");
+ RNA_def_property_ui_text(prop, "Filename", "Name of the source file");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceElement_update");
prop = RNA_def_property(srna, "orig_width", PROP_INT, PROP_NONE);
@@ -1120,25 +1120,25 @@ static void rna_def_strip_crop(BlenderRNA *brna)
prop = RNA_def_property(srna, "max_y", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "top");
- RNA_def_property_ui_text(prop, "Top", "");
+ RNA_def_property_ui_text(prop, "Top", "Number of pixels to crop from the top");
RNA_def_property_ui_range(prop, 0, 4096, 1, -1);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceCrop_update");
prop = RNA_def_property(srna, "min_y", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "bottom");
- RNA_def_property_ui_text(prop, "Bottom", "");
+ RNA_def_property_ui_text(prop, "Bottom", "Number of pixels to crop from the bottom");
RNA_def_property_ui_range(prop, 0, 4096, 1, -1);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceCrop_update");
prop = RNA_def_property(srna, "min_x", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "left");
- RNA_def_property_ui_text(prop, "Left", "");
+ RNA_def_property_ui_text(prop, "Left", "Number of pixels to crop from the left side");
RNA_def_property_ui_range(prop, 0, 4096, 1, -1);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceCrop_update");
prop = RNA_def_property(srna, "max_x", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "right");
- RNA_def_property_ui_text(prop, "Right", "");
+ RNA_def_property_ui_text(prop, "Right", "Number of pixels to crop from the right side");
RNA_def_property_ui_range(prop, 0, 4096, 1, -1);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceCrop_update");
@@ -1156,13 +1156,13 @@ static void rna_def_strip_transform(BlenderRNA *brna)
prop = RNA_def_property(srna, "offset_x", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "xofs");
- RNA_def_property_ui_text(prop, "Offset X", "");
+ RNA_def_property_ui_text(prop, "Offset X", "Amount to move the input on the X axis within its boundaries");
RNA_def_property_ui_range(prop, -4096, 4096, 1, -1);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceTransform_update");
prop = RNA_def_property(srna, "offset_y", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "yofs");
- RNA_def_property_ui_text(prop, "Offset Y", "");
+ RNA_def_property_ui_text(prop, "Offset Y", "Amount to move the input on the Y axis within its boundaries");
RNA_def_property_ui_range(prop, -4096, 4096, 1, -1);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceTransform_update");
@@ -1246,7 +1246,7 @@ static void rna_def_strip_proxy(BlenderRNA *brna)
prop = RNA_def_property(srna, "timecode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "tc");
RNA_def_property_enum_items(prop, seq_tc_items);
- RNA_def_property_ui_text(prop, "Timecode", "");
+ RNA_def_property_ui_text(prop, "Timecode", "Method for reading the inputs timecode");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_tcindex_update");
prop = RNA_def_property(srna, "use_proxy_custom_directory", PROP_BOOLEAN, PROP_NONE);
@@ -1289,17 +1289,17 @@ static void rna_def_color_balance(BlenderRNA *brna)
prop = RNA_def_property(srna, "invert_gain", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_COLOR_BALANCE_INVERSE_GAIN);
- RNA_def_property_ui_text(prop, "Inverse Gain", "");
+ RNA_def_property_ui_text(prop, "Inverse Gain", "Invert the gain color`");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceColorBalance_update");
prop = RNA_def_property(srna, "invert_gamma", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_COLOR_BALANCE_INVERSE_GAMMA);
- RNA_def_property_ui_text(prop, "Inverse Gamma", "");
+ RNA_def_property_ui_text(prop, "Inverse Gamma", "Invert the gamma color");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceColorBalance_update");
prop = RNA_def_property(srna, "invert_lift", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_COLOR_BALANCE_INVERSE_LIFT);
- RNA_def_property_ui_text(prop, "Inverse Lift", "");
+ RNA_def_property_ui_text(prop, "Inverse Lift", "Invert the lift color");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceColorBalance_update");
/* not yet used */
@@ -1357,10 +1357,10 @@ static void rna_def_sequence_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Add a new modifier");
parm = RNA_def_string(func, "name", "Name", 0, "", "New name for the modifier");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* modifier to add */
parm = RNA_def_enum(func, "type", rna_enum_sequence_modifier_type_items, seqModifierType_ColorBalance, "", "Modifier type to add");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "modifier", "SequenceModifier", "", "Newly created modifier");
RNA_def_function_return(func, parm);
@@ -1371,8 +1371,8 @@ static void rna_def_sequence_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove an existing modifier from the sequence");
/* modifier to remove */
parm = RNA_def_pointer(func, "modifier", "SequenceModifier", "", "Modifier to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ 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_Sequence_modifier_clear");
@@ -1453,13 +1453,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_text(prop, "Mute", "");
+ 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_ui_icon(prop, ICON_UNLOCKED, true);
- RNA_def_property_ui_text(prop, "Lock", "Lock strip so that it can't be transformed");
+ 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);
/* strip positioning */
@@ -1481,7 +1481,7 @@ static void rna_def_sequence(BlenderRNA *brna)
prop = RNA_def_property(srna, "frame_start", PROP_INT, PROP_TIME);
RNA_def_property_int_sdna(prop, NULL, "start");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Start Frame", "");
+ RNA_def_property_ui_text(prop, "Start Frame", "X position where the strip begins");
RNA_def_property_int_funcs(prop, NULL, "rna_Sequence_start_frame_set", NULL); /* overlap tests and calc_seq_disp */
RNA_def_property_editable_func(prop, "rna_Sequence_frame_editable");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
@@ -1552,12 +1552,12 @@ static void rna_def_sequence(BlenderRNA *brna)
prop = RNA_def_property(srna, "blend_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "blend_mode");
RNA_def_property_enum_items(prop, blend_mode_items);
- RNA_def_property_ui_text(prop, "Blend Mode", "");
+ RNA_def_property_ui_text(prop, "Blend Mode", "Method for controlling how the strip combines with other strips");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
prop = RNA_def_property(srna, "blend_alpha", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Blend Opacity", "");
+ RNA_def_property_ui_text(prop, "Blend Opacity", "Percentage of how much the strip's colors affect other strips");
/* stupid 0-100 -> 0-1 */
RNA_def_property_float_funcs(prop, "rna_Sequence_opacity_get", "rna_Sequence_opacity_set", NULL);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
@@ -1566,7 +1566,7 @@ static void rna_def_sequence(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3);
RNA_def_property_float_sdna(prop, NULL, "effect_fader");
- RNA_def_property_ui_text(prop, "Effect fader position", "");
+ RNA_def_property_ui_text(prop, "Effect fader position", "Custom fade value");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
prop = RNA_def_property(srna, "use_default_fade", PROP_BOOLEAN, PROP_NONE);
@@ -1674,7 +1674,7 @@ static void rna_def_filter_video(StructRNA *srna)
prop = RNA_def_property(srna, "use_deinterlace", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_FILTERY);
- RNA_def_property_ui_text(prop, "De-Interlace", "For video movies to remove fields");
+ RNA_def_property_ui_text(prop, "Deinterlace", "Remove fields from video movies");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update_reopen_files");
prop = RNA_def_property(srna, "alpha_mode", PROP_ENUM, PROP_NONE);
@@ -1714,7 +1714,7 @@ static void rna_def_filter_video(StructRNA *srna)
RNA_def_property_range(prop, 0.0f, 20.0f);
RNA_def_property_ui_range(prop, 0.0f, 2.0f, 3, 3);
RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_ui_text(prop, "Saturation", "");
+ RNA_def_property_ui_text(prop, "Saturation", "Adjust the intensity of the input's color");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
prop = RNA_def_property(srna, "strobe", PROP_FLOAT, PROP_NONE);
@@ -2205,13 +2205,13 @@ static void rna_def_transform(StructRNA *srna)
prop = RNA_def_property(srna, "scale_start_x", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_float_sdna(prop, NULL, "ScalexIni");
- RNA_def_property_ui_text(prop, "Scale X", "");
+ RNA_def_property_ui_text(prop, "Scale X", "Amount to scale the input in the X axis");
RNA_def_property_ui_range(prop, 0, 10, 3, 6);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
prop = RNA_def_property(srna, "scale_start_y", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_float_sdna(prop, NULL, "ScaleyIni");
- RNA_def_property_ui_text(prop, "Scale Y", "");
+ RNA_def_property_ui_text(prop, "Scale Y", "Amount to scale the input in the Y axis");
RNA_def_property_ui_range(prop, 0, 10, 3, 6);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
@@ -2222,33 +2222,33 @@ static void rna_def_transform(StructRNA *srna)
prop = RNA_def_property(srna, "translate_start_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "xIni");
- RNA_def_property_ui_text(prop, "Translate X", "");
+ RNA_def_property_ui_text(prop, "Translate X", "Amount to move the input on the X axis");
RNA_def_property_ui_range(prop, -4000.0f, 4000.0f, 3, 6);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
prop = RNA_def_property(srna, "translate_start_y", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "yIni");
- RNA_def_property_ui_text(prop, "Translate Y", "");
+ RNA_def_property_ui_text(prop, "Translate Y", "Amount to move the input on the Y axis");
RNA_def_property_ui_range(prop, -4000.0f, 4000.0f, 3, 6);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
prop = RNA_def_property(srna, "rotation_start", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "rotIni");
RNA_def_property_range(prop, -360.0f, 360.0f);
- RNA_def_property_ui_text(prop, "Rotation", "");
+ RNA_def_property_ui_text(prop, "Rotation", "Degrees to rotate the input");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
prop = RNA_def_property(srna, "translation_unit", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "percent");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); /* not meant to be animated */
RNA_def_property_enum_items(prop, translation_unit_items);
- RNA_def_property_ui_text(prop, "Translation Unit", "");
+ RNA_def_property_ui_text(prop, "Translation Unit", "Unit of measure to translate the input");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
prop = RNA_def_property(srna, "interpolation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, interpolation_items);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); /* not meant to be animated */
- RNA_def_property_ui_text(prop, "Interpolation", "");
+ RNA_def_property_ui_text(prop, "Interpolation", "Method to determine how missing pixels are created");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
}
@@ -2260,7 +2260,7 @@ static void rna_def_solid_color(StructRNA *srna)
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "col");
- RNA_def_property_ui_text(prop, "Color", "");
+ RNA_def_property_ui_text(prop, "Color", "Effect Strip color");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
}
@@ -2333,7 +2333,7 @@ static void rna_def_text(StructRNA *srna)
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "color");
- RNA_def_property_ui_text(prop, "Color", "");
+ RNA_def_property_ui_text(prop, "Color", "Text color");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
prop = RNA_def_property(srna, "shadow_color", PROP_FLOAT, PROP_COLOR_GAMMA);
@@ -2358,13 +2358,13 @@ static void rna_def_text(StructRNA *srna)
prop = RNA_def_property(srna, "align_x", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "align");
RNA_def_property_enum_items(prop, text_align_x_items);
- RNA_def_property_ui_text(prop, "Align X", "");
+ RNA_def_property_ui_text(prop, "Align X", "Align the text along the X axis");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
prop = RNA_def_property(srna, "align_y", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "align_y");
RNA_def_property_enum_items(prop, text_align_y_items);
- RNA_def_property_ui_text(prop, "Align Y", "");
+ RNA_def_property_ui_text(prop, "Align Y", "Align the image along the Y axis");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
prop = RNA_def_property(srna, "text", PROP_STRING, PROP_NONE);
@@ -2512,7 +2512,7 @@ static void rna_def_colorbalance_modifier(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "color_multiply");
RNA_def_property_range(prop, 0.0f, 20.0f);
RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_ui_text(prop, "Multiply Colors", "");
+ RNA_def_property_ui_text(prop, "Multiply Colors", "Multiply the intensity of each pixel");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
}
@@ -2576,13 +2576,13 @@ static void rna_def_brightcontrast_modifier(BlenderRNA *brna)
prop = RNA_def_property(srna, "bright", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_float_sdna(prop, NULL, "bright");
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
- RNA_def_property_ui_text(prop, "Bright", "");
+ RNA_def_property_ui_text(prop, "Bright", "Adjust the luminosity of the colors");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
prop = RNA_def_property(srna, "contrast", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_float_sdna(prop, NULL, "contrast");
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
- RNA_def_property_ui_text(prop, "Contrast", "");
+ RNA_def_property_ui_text(prop, "Contrast", "Adjust the difference in luminosity between pixels");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
}
@@ -2599,13 +2599,12 @@ static void rna_def_tonemap_modifier(BlenderRNA *brna)
srna = RNA_def_struct(brna, "SequencerTonemapModifierData", "SequenceModifier");
RNA_def_struct_sdna(srna, "SequencerTonemapModifierData");
- RNA_def_struct_ui_text(srna, "SequencerTonemapModifierData",
- "Tone mapping modifier");
+ RNA_def_struct_ui_text(srna, "SequencerTonemapModifierData", "Tone mapping modifier");
prop = RNA_def_property(srna, "tonemap_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_enum_items(prop, type_items);
- RNA_def_property_ui_text(prop, "Tonemap Type", "");
+ RNA_def_property_ui_text(prop, "Tonemap Type", "Tone mapping algorithm");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
prop = RNA_def_property(srna, "key", PROP_FLOAT, PROP_FACTOR);
diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c
index 13fda02c7c8..76f5a4934cf 100644
--- a/source/blender/makesrna/intern/rna_sequencer_api.c
+++ b/source/blender/makesrna/intern/rna_sequencer_api.c
@@ -414,14 +414,14 @@ void RNA_api_sequence_strip(StructRNA *srna)
RNA_def_function_ui_description(func, "Return the strip element from a given frame or None");
parm = RNA_def_int(func, "frame", 0, -MAXFRAME, MAXFRAME, "Frame",
"The frame to get the strip element from", -MAXFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_function_return(func, RNA_def_pointer(func, "elem", "SequenceElement", "",
"strip element of the current frame"));
func = RNA_def_function(srna, "swap", "rna_Sequence_swap_internal");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "other", "Sequence", "Other", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
}
void RNA_api_sequence_elements(BlenderRNA *brna, PropertyRNA *cprop)
@@ -439,7 +439,7 @@ void RNA_api_sequence_elements(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Push an image from ImageSequence.directory");
parm = RNA_def_string(func, "filename", "File", 0, "", "Filepath to image");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "elem", "SequenceElement", "", "New SequenceElement");
RNA_def_function_return(func, parm);
@@ -448,7 +448,7 @@ void RNA_api_sequence_elements(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Pop an image off the collection");
parm = RNA_def_int(func, "index", -1, INT_MIN, INT_MAX, "", "Index of image to remove", INT_MIN, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop)
@@ -487,15 +487,15 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Add a new movie clip sequence");
parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "clip", "MovieClip", "", "Movie clip to add");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_int(func, "channel", 0, 1, MAXSEQ, "Channel",
"The channel for the new sequence", 1, MAXSEQ);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "frame_start", 0, -MAXFRAME, MAXFRAME, "",
"The start frame for the new sequence", -MAXFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence");
RNA_def_function_return(func, parm);
@@ -504,15 +504,15 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Add a new mask sequence");
parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "mask", "Mask", "", "Mask to add");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_int(func, "channel", 0, 1, MAXSEQ, "Channel",
"The channel for the new sequence", 1, MAXSEQ);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "frame_start", 0, -MAXFRAME, MAXFRAME, "",
"The start frame for the new sequence", -MAXFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence");
RNA_def_function_return(func, parm);
@@ -521,15 +521,15 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Add a new scene sequence");
parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene to add");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_int(func, "channel", 0, 1, MAXSEQ, "Channel",
"The channel for the new sequence", 1, MAXSEQ);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "frame_start", 0, -MAXFRAME, MAXFRAME, "",
"The start frame for the new sequence", -MAXFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence");
RNA_def_function_return(func, parm);
@@ -538,15 +538,15 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Add a new image sequence");
parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "filepath", "File", 0, "", "Filepath to image");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "channel", 0, 1, MAXSEQ, "Channel",
"The channel for the new sequence", 1, MAXSEQ);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "frame_start", 0, -MAXFRAME, MAXFRAME, "",
"The start frame for the new sequence", -MAXFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence");
RNA_def_function_return(func, parm);
@@ -555,15 +555,15 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Add a new movie sequence");
parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "filepath", "File", 0, "", "Filepath to movie");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "channel", 0, 1, MAXSEQ, "Channel",
"The channel for the new sequence", 1, MAXSEQ);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "frame_start", 0, -MAXFRAME, MAXFRAME, "",
"The start frame for the new sequence", -MAXFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence");
RNA_def_function_return(func, parm);
@@ -572,15 +572,15 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID | FUNC_USE_MAIN);
RNA_def_function_ui_description(func, "Add a new sound sequence");
parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "filepath", "File", 0, "", "Filepath to movie");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "channel", 0, 1, MAXSEQ, "Channel",
"The channel for the new sequence", 1, MAXSEQ);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "frame_start", 0, -MAXFRAME, MAXFRAME, "",
"The start frame for the new sequence", -MAXFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence");
RNA_def_function_return(func, parm);
@@ -589,17 +589,17 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Add a new effect sequence");
parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "type", seq_effect_items, 0, "Type",
"type for the new sequence");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "channel", 0, 1, MAXSEQ, "Channel",
"The channel for the new sequence", 1, MAXSEQ);
/* don't use MAXFRAME since it makes importer scripts fail */
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "frame_start", 0, INT_MIN, INT_MAX, "",
"The start frame for the new sequence", INT_MIN, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_int(func, "frame_end", 0, INT_MIN, INT_MAX, "",
"The end frame for the new sequence", INT_MIN, INT_MAX);
RNA_def_pointer(func, "seq1", "Sequence", "", "Sequence 1 for effect");
@@ -614,8 +614,8 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a Sequence");
parm = RNA_def_pointer(func, "sequence", "Sequence", "", "Sequence to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c
index dad5577dc12..687541b96b0 100644
--- a/source/blender/makesrna/intern/rna_smoke.c
+++ b/source/blender/makesrna/intern/rna_smoke.c
@@ -30,6 +30,7 @@
#include <limits.h>
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "rna_internal.h"
@@ -51,21 +52,24 @@
#ifdef RNA_RUNTIME
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_particle.h"
+#include "BKE_texture.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)
@@ -73,7 +77,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)
@@ -383,6 +387,17 @@ static void rna_SmokeFlow_uvlayer_set(PointerRNA *ptr, const char *value)
rna_object_uvlayer_name_set(ptr, value, flow->uvlayer_name, sizeof(flow->uvlayer_name));
}
+static void rna_Smoke_use_color_ramp_set(PointerRNA *ptr, int value)
+{
+ SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
+
+ sds->use_coba = value;
+
+ if (value && sds->coba == NULL) {
+ sds->coba = add_colorband(false);
+ }
+}
+
#else
static void rna_def_smoke_domain_settings(BlenderRNA *brna)
@@ -443,6 +458,32 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem smoke_view_items[] = {
+ {MOD_SMOKE_SLICE_VIEW_ALIGNED, "VIEW_ALIGNED", 0, "View", "Slice volume parallel to the view plane"},
+ {MOD_SMOKE_SLICE_AXIS_ALIGNED, "AXIS_ALIGNED", 0, "Axis", "Slice volume parallel to the major axis"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem axis_slice_method_items[] = {
+ {AXIS_SLICE_FULL, "FULL", 0, "Full", "Slice the whole domain object"},
+ {AXIS_SLICE_SINGLE, "SINGLE", 0, "Single", "Perform a single slice of the domain object"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static 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"},
+ {SLICE_AXIS_Y, "Y", 0, "Y", "Slice along the Y axis"},
+ {SLICE_AXIS_Z, "Z", 0, "Z", "Slice along the Z axis"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem vector_draw_items[] = {
+ {VECTOR_DRAW_NEEDLE, "NEEDLE", 0, "Needle", "Draw vectors as needles"},
+ {VECTOR_DRAW_STREAMLINE, "STREAMLINE", 0, "Streamlines", "Draw vectors as streamlines"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "SmokeDomainSettings", NULL);
RNA_def_struct_ui_text(srna, "Domain Settings", "Smoke domain settings");
RNA_def_struct_sdna(srna, "SmokeDomainSettings");
@@ -719,6 +760,101 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
RNA_def_property_enum_funcs(prop, NULL, "rna_Smoke_cachetype_set", NULL);
RNA_def_property_ui_text(prop, "File Format", "Select the file format to be used for caching");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
+
+ /* display settings */
+
+ prop = RNA_def_property(srna, "slice_method", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "slice_method");
+ RNA_def_property_enum_items(prop, smoke_view_items);
+ RNA_def_property_ui_text(prop, "View Method", "How to slice the volume for viewport rendering");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "axis_slice_method", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "axis_slice_method");
+ RNA_def_property_enum_items(prop, axis_slice_method_items);
+ RNA_def_property_ui_text(prop, "Method", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "slice_axis", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "slice_axis");
+ RNA_def_property_enum_items(prop, axis_slice_position_items);
+ RNA_def_property_ui_text(prop, "Axis", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "slice_per_voxel", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "slice_per_voxel");
+ RNA_def_property_range(prop, 0.0, 100.0);
+ RNA_def_property_ui_range(prop, 0.0, 5.0, 0.1, 1);
+ RNA_def_property_ui_text(prop, "Slice Per Voxel",
+ "How many slices per voxel should be generated");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "slice_depth", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "slice_depth");
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 3);
+ RNA_def_property_ui_text(prop, "Position", "Position of the slice");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "display_thickness", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "display_thickness");
+ RNA_def_property_range(prop, 0.001, 1000.0);
+ RNA_def_property_ui_range(prop, 0.1, 100.0, 0.1, 3);
+ 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);
+ 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_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "vector_draw_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_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "vector_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "vector_scale");
+ RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_ui_range(prop, 0.0, 100.0, 0.1, 3);
+ RNA_def_property_ui_text(prop, "Scale", "Multiplier for scaling the vectors");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ /* --------- Color mapping. --------- */
+
+ prop = RNA_def_property(srna, "use_color_ramp", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "use_coba", 0);
+ RNA_def_property_boolean_funcs(prop, NULL, "rna_Smoke_use_color_ramp_set");
+ RNA_def_property_ui_text(prop, "Use Color Ramp",
+ "Render a simulation field while mapping its voxels values to the colors of a ramp");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ static EnumPropertyItem coba_field_items[] = {
+ {FLUID_FIELD_COLOR_R, "COLOR_R", 0, "Red", "Red component of the color field"},
+ {FLUID_FIELD_COLOR_G, "COLOR_G", 0, "Green", "Green component of the color field"},
+ {FLUID_FIELD_COLOR_B, "COLOR_B", 0, "Blue", "Blue component of the color field"},
+ {FLUID_FIELD_DENSITY, "DENSITY", 0, "Density", "Quantity of soot in the fluid"},
+ {FLUID_FIELD_FLAME, "FLAME", 0, "Flame", "Flame field"},
+ {FLUID_FIELD_FUEL, "FUEL", 0, "Fuel", "Fuel field"},
+ {FLUID_FIELD_HEAT, "HEAT", 0, "Heat", "Temperature of the fluid"},
+ {FLUID_FIELD_VELOCITY_X, "VELOCITY_X", 0, "X Velocity", "X component of the velocity field"},
+ {FLUID_FIELD_VELOCITY_Y, "VELOCITY_Y", 0, "Y Velocity", "Y component of the velocity field"},
+ {FLUID_FIELD_VELOCITY_Z, "VELOCITY_Z", 0, "Z Velocity", "Z component of the velocity field"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ prop = RNA_def_property(srna, "coba_field", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "coba_field");
+ RNA_def_property_enum_items(prop, coba_field_items);
+ RNA_def_property_ui_text(prop, "Field", "Simulation field to color map");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ 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, NC_OBJECT | ND_DRAW, NULL);
}
static void rna_def_smoke_flow_settings(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 1c8d4a4c818..c8cceb54f9b 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -45,6 +45,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"
@@ -71,10 +72,10 @@ EnumPropertyItem rna_enum_space_type_items[] = {
{SPACE_NLA, "NLA_EDITOR", ICON_NLA, "NLA Editor", "Combine and layer Actions"},
{0, "", ICON_NONE, NULL, NULL},
{SPACE_IMAGE, "IMAGE_EDITOR", ICON_IMAGE_COL, "UV/Image Editor", "View and edit images and UV Maps"},
- {SPACE_SEQ, "SEQUENCE_EDITOR", ICON_SEQUENCE, "Video Sequence Editor", "Video editing tools"},
{SPACE_CLIP, "CLIP_EDITOR", ICON_CLIP, "Movie Clip Editor", "Motion tracking tools"},
- {SPACE_TEXT, "TEXT_EDITOR", ICON_TEXT, "Text Editor", "Edit scripts and in-file documentation"},
+ {SPACE_SEQ, "SEQUENCE_EDITOR", ICON_SEQUENCE, "Video Sequence Editor", "Video editing tools"},
{SPACE_NODE, "NODE_EDITOR", ICON_NODETREE, "Node Editor", "Editor for node-based shading and compositing tools"},
+ {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"},
{0, "", ICON_NONE, NULL, NULL},
{SPACE_BUTS, "PROPERTIES", ICON_BUTS, "Properties", "Edit properties of active object and related data-blocks"},
@@ -208,6 +209,7 @@ static EnumPropertyItem buttons_context_items[] = {
{BCONTEXT_TEXTURE, "TEXTURE", ICON_TEXTURE, "Texture", "Texture"},
{BCONTEXT_PARTICLE, "PARTICLES", ICON_PARTICLES, "Particles", "Particle"},
{BCONTEXT_PHYSICS, "PHYSICS", ICON_PHYSICS, "Physics", "Physics"},
+ {BCONTEXT_COLLECTION, "COLLECTION", ICON_COLLAPSEMENU, "Collection", "Collection"},
{0, NULL, 0, NULL, NULL}
};
@@ -253,17 +255,23 @@ 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_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"
@@ -403,43 +411,63 @@ static void rna_Space_view2d_sync_update(Main *UNUSED(bmain), Scene *UNUSED(scen
}
}
-static PointerRNA rna_CurrentOrientation_get(PointerRNA *ptr)
+static int rna_View3D_transform_orientation_get(PointerRNA *ptr)
+{
+ const View3D *v3d = (View3D *)ptr->data;
+ /* convert to enum value */
+ return (v3d->twmode == V3D_MANIP_CUSTOM) ? (v3d->twmode + v3d->custom_orientation_index) : v3d->twmode;
+}
+
+void rna_View3D_transform_orientation_set(PointerRNA *ptr, int value)
{
- Scene *scene = ((bScreen *)ptr->id.data)->scene;
View3D *v3d = (View3D *)ptr->data;
+ BIF_selectTransformOrientationValue(v3d, value);
+}
- 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));
+static PointerRNA rna_View3D_current_orientation_get(PointerRNA *ptr)
+{
+ View3D *v3d = (View3D *)ptr->data;
+ TransformOrientation *orientation;
+
+ if (v3d->twmode < V3D_MANIP_CUSTOM) {
+ orientation = NULL;
+ }
+ else {
+ WorkSpace *workspace;
+ bScreen *screen = ptr->id.data;
+
+ BKE_workspace_layout_find_global(G.main, screen, &workspace);
+ orientation = BKE_workspace_transform_orientation_find(workspace, v3d->custom_orientation_index);
+ }
+
+ return rna_pointer_inherit_refine(ptr, &RNA_TransformOrientation, orientation);
}
EnumPropertyItem *rna_TransformOrientation_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
{
- Scene *scene = NULL;
- ListBase *transform_spaces;
- TransformOrientation *ts = NULL;
+ WorkSpace *workspace;
+ ListBase *transform_orientations;
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 (ptr->type == &RNA_SpaceView3D) {
+ bScreen *screen = ptr->id.data;
+ BKE_workspace_layout_find_global(G.main, screen, &workspace);
}
+ else {
+ /* can't use scene from ptr->id.data because that enum is also used by operators */
+ workspace = C ? CTX_wm_workspace(C) : NULL;
+ }
+
+ transform_orientations = workspace ? BKE_workspace_transform_orientations_get(workspace) : NULL;
- if (ts) {
+ if (transform_orientations && (BLI_listbase_is_empty(transform_orientations) == false)) {
RNA_enum_item_add_separator(&item, &totitem);
- for (; ts; ts = ts->next) {
+ for (TransformOrientation *ts = transform_orientations->first; ts; ts = ts->next) {
tmp.identifier = ts->name;
tmp.name = ts->name;
tmp.value = i++;
@@ -454,6 +482,17 @@ EnumPropertyItem *rna_TransformOrientation_itemf(bContext *C, PointerRNA *ptr, P
}
/* Space 3D View */
+static void rna_SpaceView3D_camera_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ View3D *v3d = (View3D *)(ptr->data);
+ if (v3d->scenelock) {
+ wmWindowManager *wm = bmain->wm.first;
+
+ scene->camera = v3d->camera;
+ WM_windows_scene_data_sync(&wm->windows, scene);
+ }
+}
+
static void rna_SpaceView3D_lock_camera_and_layers_set(PointerRNA *ptr, int value)
{
View3D *v3d = (View3D *)(ptr->data);
@@ -462,8 +501,10 @@ static void rna_SpaceView3D_lock_camera_and_layers_set(PointerRNA *ptr, int valu
v3d->scenelock = value;
if (value) {
+ Scene *scene = ED_screen_scene_find(sc, G.main->wm.first);
int bit;
- v3d->lay = sc->scene->lay;
+
+ v3d->lay = scene->lay;
/* seek for layact */
bit = 0;
while (bit < 32) {
@@ -473,35 +514,35 @@ static void rna_SpaceView3D_lock_camera_and_layers_set(PointerRNA *ptr, int valu
}
bit++;
}
- v3d->camera = sc->scene->camera;
+ v3d->camera = scene->camera;
}
}
static void rna_View3D_CursorLocation_get(PointerRNA *ptr, float *values)
{
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);
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;
+ bScreen *screen = ptr->id.data;
+ Scene *scene = ED_screen_scene_find(screen, G.main->wm.first);
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);
}
@@ -509,13 +550,20 @@ static float rna_View3D_GridScaleUnit_get(PointerRNA *ptr)
static void rna_SpaceView3D_layer_set(PointerRNA *ptr, const int *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);
+ DEG_on_visible_update(bmain, false);
}
static void rna_SpaceView3D_viewport_shade_update(Main *bmain, Scene *scene, PointerRNA *ptr)
@@ -529,16 +577,16 @@ static void rna_SpaceView3D_viewport_shade_update(Main *bmain, Scene *scene, Poi
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);
}
}
@@ -546,7 +594,7 @@ static void rna_SpaceView3D_matcap_update(Main *UNUSED(bmain), Scene *UNUSED(sce
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)
{
@@ -678,12 +726,12 @@ static void rna_RegionView3D_view_matrix_set(PointerRNA *ptr, const float *value
static int rna_SpaceView3D_viewport_shade_get(PointerRNA *ptr)
{
- Scene *scene = ((bScreen *)ptr->id.data)->scene;
+ Scene *scene = WM_windows_scene_get_from_screen(G.main->wm.first, ptr->id.data);
RenderEngineType *type = RE_engines_find(scene->r.engine);
View3D *v3d = (View3D *)ptr->data;
int drawtype = v3d->drawtype;
- if (drawtype == OB_RENDER && !(type && type->view_draw))
+ if (drawtype == OB_RENDER && !(type && type->render_to_view))
return OB_SOLID;
return drawtype;
@@ -698,12 +746,13 @@ static void rna_SpaceView3D_viewport_shade_set(PointerRNA *ptr, int value)
v3d->drawtype = value;
}
-static EnumPropertyItem *rna_SpaceView3D_viewport_shade_itemf(bContext *UNUSED(C), PointerRNA *ptr,
+static EnumPropertyItem *rna_SpaceView3D_viewport_shade_itemf(bContext *C, PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop), bool *r_free)
{
- Scene *scene = ((bScreen *)ptr->id.data)->scene;
+ wmWindow *win = CTX_wm_window(C);
+ Scene *scene = WM_window_get_active_scene(win);
RenderEngineType *type = RE_engines_find(scene->r.engine);
-
+
EnumPropertyItem *item = NULL;
int totitem = 0;
@@ -712,8 +761,8 @@ static EnumPropertyItem *rna_SpaceView3D_viewport_shade_itemf(bContext *UNUSED(C
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);
-
- if (type && type->view_draw)
+
+ if (type && type->render_to_view)
RNA_enum_items_add_value(&item, &totitem, rna_enum_viewport_shade_items, OB_RENDER);
RNA_enum_item_end(&item, &totitem);
@@ -722,10 +771,10 @@ static EnumPropertyItem *rna_SpaceView3D_viewport_shade_itemf(bContext *UNUSED(C
return item;
}
-static EnumPropertyItem *rna_SpaceView3D_stereo3d_camera_itemf(bContext *UNUSED(C), PointerRNA *ptr,
+static EnumPropertyItem *rna_SpaceView3D_stereo3d_camera_itemf(bContext *C, PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
{
- Scene *scene = ((bScreen *)ptr->id.data)->scene;
+ Scene *scene = CTX_data_scene(C);
if (scene->r.views_format == SCE_VIEWS_FORMAT_MULTIVIEW)
return multiview_camera_items;
@@ -793,22 +842,28 @@ static int 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);
+ Scene *scene = ED_screen_scene_find(sc, G.main->wm.first);
+
+ return ED_space_image_show_uvedit(sima, scene->obedit);
}
static int 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);
+ Scene *scene = ED_screen_scene_find(sc, G.main->wm.first);
+ SceneLayer *sl = BKE_scene_layer_context_active_PLACEHOLDER(scene);
+
+ return ED_space_image_check_show_maskedit(sl, sima);
}
static void rna_SpaceImageEditor_image_set(PointerRNA *ptr, PointerRNA value)
{
SpaceImage *sima = (SpaceImage *)(ptr->data);
bScreen *sc = (bScreen *)ptr->id.data;
+ Scene *scene = ED_screen_scene_find(sc, G.main->wm.first);
- ED_space_image_set(sima, sc->scene, sc->scene->obedit, (Image *)value.data);
+ ED_space_image_set(sima, scene, scene->obedit, (Image *)value.data);
}
static void rna_SpaceImageEditor_mask_set(PointerRNA *ptr, PointerRNA value)
@@ -828,7 +883,7 @@ static EnumPropertyItem *rna_SpaceImageEditor_draw_channels_itemf(bContext *UNUS
int zbuf, alpha, totitem = 0;
ibuf = ED_space_image_acquire_buffer(sima, &lock);
-
+
alpha = ibuf && (ibuf->channels == 4);
zbuf = ibuf && (ibuf->zbuf || ibuf->zbuf_float || (ibuf->channels == 1));
@@ -879,14 +934,14 @@ static void rna_SpaceImageEditor_zoom_get(PointerRNA *ptr, float *values)
static void rna_SpaceImageEditor_cursor_location_get(PointerRNA *ptr, float *values)
{
SpaceImage *sima = (SpaceImage *)ptr->data;
-
+
if (sima->flag & SI_COORDFLOATS) {
copy_v2_v2(values, sima->cursor);
}
else {
int w, h;
ED_space_image_get_size(sima, &w, &h);
-
+
values[0] = sima->cursor[0] * w;
values[1] = sima->cursor[1] * h;
}
@@ -895,14 +950,14 @@ static void rna_SpaceImageEditor_cursor_location_get(PointerRNA *ptr, float *val
static void rna_SpaceImageEditor_cursor_location_set(PointerRNA *ptr, const float *values)
{
SpaceImage *sima = (SpaceImage *)ptr->data;
-
+
if (sima->flag & SI_COORDFLOATS) {
copy_v2_v2(sima->cursor, values);
}
else {
int w, h;
ED_space_image_get_size(sima, &w, &h);
-
+
sima->cursor[0] = values[0] / w;
sima->cursor[1] = values[1] / h;
}
@@ -931,7 +986,7 @@ static void rna_SpaceImageEditor_scopes_update(struct bContext *C, struct Pointe
SpaceImage *sima = (SpaceImage *)ptr->data;
ImBuf *ibuf;
void *lock;
-
+
ibuf = ED_space_image_acquire_buffer(sima, &lock);
if (ibuf) {
ED_space_image_scopes_update(C, sima, ibuf, true);
@@ -1010,12 +1065,12 @@ static void rna_SpaceProperties_pin_id_update(Main *UNUSED(bmain), Scene *UNUSED
{
SpaceButs *sbuts = (SpaceButs *)(ptr->data);
ID *id = sbuts->pinid;
-
+
if (id == NULL) {
sbuts->flag &= ~SB_PIN_CONTEXT;
return;
}
-
+
switch (GS(id->name)) {
case ID_MA:
WM_main_add_notifier(NC_MATERIAL | ND_SHADING, NULL);
@@ -1036,7 +1091,7 @@ static void rna_SpaceProperties_pin_id_update(Main *UNUSED(bmain), Scene *UNUSED
static void rna_SpaceProperties_context_set(PointerRNA *ptr, int value)
{
SpaceButs *sbuts = (SpaceButs *)(ptr->data);
-
+
sbuts->mainb = value;
sbuts->mainbuser = value;
}
@@ -1060,6 +1115,10 @@ static EnumPropertyItem *rna_SpaceProperties_context_itemf(bContext *UNUSED(C),
RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_SCENE);
}
+ if (sbuts->pathflag & (1 << BCONTEXT_COLLECTION)) {
+ RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_COLLECTION);
+ }
+
if (sbuts->pathflag & (1 << BCONTEXT_WORLD)) {
RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_WORLD);
}
@@ -1114,7 +1173,8 @@ static EnumPropertyItem *rna_SpaceProperties_context_itemf(bContext *UNUSED(C),
static void rna_SpaceProperties_context_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
SpaceButs *sbuts = (SpaceButs *)(ptr->data);
- if (ELEM(sbuts->mainb, BCONTEXT_WORLD, BCONTEXT_MATERIAL, BCONTEXT_TEXTURE)) {
+ /* XXX BCONTEXT_DATA is ugly, but required for lamps... See T51318. */
+ if (ELEM(sbuts->mainb, BCONTEXT_WORLD, BCONTEXT_MATERIAL, BCONTEXT_TEXTURE, BCONTEXT_DATA)) {
sbuts->preview = 1;
}
}
@@ -1187,7 +1247,7 @@ static void rna_ConsoleLine_body_set(PointerRNA *ptr, const char *value)
{
ConsoleLine *ci = (ConsoleLine *)ptr->data;
int len = strlen(value);
-
+
if ((len >= ci->len_alloc) || (len * 2 < ci->len_alloc) ) { /* allocate a new string */
MEM_freeN(ci->line);
ci->line = MEM_mallocN((len + 1) * sizeof(char), "rna_consoleline");
@@ -1215,7 +1275,7 @@ static void rna_SpaceDopeSheetEditor_action_set(PointerRNA *ptr, PointerRNA valu
{
SpaceAction *saction = (SpaceAction *)(ptr->data);
bAction *act = (bAction *)value.data;
-
+
if ((act == NULL) || (act->idroot == 0)) {
/* just set if we're clearing the action or if the action is "amorphous" still */
saction->action = act;
@@ -1244,15 +1304,16 @@ 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(Main *bmain, bContext *C, Scene *UNUSED(scene), PointerRNA *ptr)
{
SpaceAction *saction = (SpaceAction *)(ptr->data);
- Object *obact = (scene->basact) ? scene->basact->object : NULL;
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *obact = OBACT_NEW;
/* we must set this action to be the one used by active object (if not pinned) */
if (obact /* && saction->pin == 0*/) {
AnimData *adt = NULL;
-
+
if (saction->mode == SACTCONT_ACTION) {
/* TODO: context selector could help decide this with more control? */
adt = BKE_animdata_add_id(&obact->id); /* this only adds if non-existent */
@@ -1262,7 +1323,7 @@ static void rna_SpaceDopeSheetEditor_action_update(Main *bmain, Scene *scene, Po
if (key)
adt = BKE_animdata_add_id(&key->id); /* this only adds if non-existent */
}
-
+
/* set action */
// FIXME: this overlaps a lot with the BKE_animdata_set_action() API method
if (adt) {
@@ -1270,11 +1331,11 @@ static void rna_SpaceDopeSheetEditor_action_update(Main *bmain, Scene *scene, Po
if (adt->action != saction->action) {
/* NLA Tweak Mode needs special handling... */
if (adt->flag & ADT_NLA_EDIT_ON) {
- /* Exit editmode first - we cannot change actions while in tweakmode
+ /* Exit editmode first - we cannot change actions while in tweakmode
* NOTE: This will clear the action ref properly
*/
BKE_nla_tweakmode_exit(adt);
-
+
/* Assign new action, and adjust the usercounts accordingly */
adt->action = saction->action;
id_us_plus((ID *)adt->action);
@@ -1284,7 +1345,7 @@ static void rna_SpaceDopeSheetEditor_action_update(Main *bmain, Scene *scene, Po
if (adt->action) {
/* Fix id-count of action we're replacing */
id_us_min(&adt->action->id);
-
+
/* To prevent data loss (i.e. if users flip between actions using the Browse menu),
* stash this action if nothing else uses it.
*
@@ -1301,39 +1362,40 @@ static void rna_SpaceDopeSheetEditor_action_update(Main *bmain, Scene *scene, Po
BKE_nla_action_stash(adt);
}
}
-
+
/* Assign new action, and adjust the usercounts accordingly */
adt->action = saction->action;
id_us_plus((ID *)adt->action);
}
}
-
+
/* Force update of animdata */
adt->recalc |= ADT_RECALC_ANIM;
}
-
+
/* 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;
-
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *obact = OBACT_NEW;
+
/* special exceptions for ShapeKey Editor mode */
if (saction->mode == SACTCONT_SHAPEKEY) {
Key *key = BKE_key_from_object(obact);
-
+
/* 1) update the action stored for the editor */
if (key)
saction->action = (key->adt) ? key->adt->action : NULL;
else
saction->action = NULL;
-
+
/* 2) enable 'show sliders' by default, since one of the main
* points of the ShapeKey Editor is to provide a one-stop shop
* for controlling the shapekeys, whose main control is the value
@@ -1349,7 +1411,7 @@ static void rna_SpaceDopeSheetEditor_mode_update(Main *UNUSED(bmain), Scene *sce
else
saction->action = NULL;
}
-
+
/* recalculate extents of channel list */
saction->flag |= SACTION_TEMP_NEEDCHANSYNC;
}
@@ -1359,7 +1421,7 @@ static void rna_SpaceDopeSheetEditor_mode_update(Main *UNUSED(bmain), Scene *sce
static void rna_SpaceGraphEditor_display_mode_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
ScrArea *sa = rna_area_from_space(ptr);
-
+
/* after changing view mode, must force recalculation of F-Curve colors
* which can only be achieved using refresh as opposed to redraw
*/
@@ -1449,7 +1511,7 @@ static int rna_SpaceNodeEditor_node_tree_poll(PointerRNA *ptr, const PointerRNA
{
SpaceNode *snode = (SpaceNode *)ptr->data;
bNodeTree *ntree = (bNodeTree *)value.data;
-
+
/* node tree type must match the selected type in node editor */
return (STREQ(snode->tree_idname, ntree->idname));
}
@@ -1528,7 +1590,7 @@ static void rna_SpaceNodeEditor_show_backdrop_update(Main *UNUSED(bmain), Scene
static void rna_SpaceNodeEditor_cursor_location_from_region(SpaceNode *snode, bContext *C, int x, int y)
{
ARegion *ar = CTX_wm_region(C);
-
+
UI_view2d_region_to_view(&ar->v2d, x, y, &snode->cursor[0], &snode->cursor[1]);
snode->cursor[0] /= UI_DPI_FAC;
snode->cursor[1] /= UI_DPI_FAC;
@@ -1645,7 +1707,7 @@ static void rna_FileBrowser_FSMenuEntry_name_set(PointerRNA *ptr, const char *va
ED_fsmenu_entry_set_name(fsm, value);
}
-static int rna_FileBrowser_FSMenuEntry_name_get_editable(PointerRNA *ptr)
+static int rna_FileBrowser_FSMenuEntry_name_get_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
FSMenuEntry *fsm = ptr->data;
@@ -1880,12 +1942,12 @@ static void rna_def_space(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
-
+
srna = RNA_def_struct(brna, "Space", NULL);
RNA_def_struct_sdna(srna, "SpaceLink");
RNA_def_struct_ui_text(srna, "Space", "Space data for a screen area");
RNA_def_struct_refine_func(srna, "rna_Space_refine");
-
+
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);
@@ -1961,6 +2023,13 @@ static void rna_def_space_image_uv(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static 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");
@@ -2048,6 +2117,13 @@ 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)
@@ -2070,30 +2146,33 @@ static void rna_def_space_outliner(BlenderRNA *brna)
{SO_USERDEF, "USER_PREFERENCES", 0, "User Preferences", "Display user preference data"},
{SO_ID_ORPHANS, "ORPHAN_DATA", 0, "Orphan Data",
"Display data-blocks which are unused and/or will be lost when the file is reloaded"},
+ {SO_ACT_LAYER, "ACT_LAYER", 0, "Active Render Layer", "Display the collections of the active render layer"},
+ {SO_COLLECTIONS, "MASTER_COLLECTION", 0, "Master Collection Tree", "Display all collections based on the "
+ "master collection hierarchy"},
{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");
-
+
prop = RNA_def_property(srna, "display_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "outlinevis");
RNA_def_property_enum_items(prop, display_mode_items);
RNA_def_property_ui_text(prop, "Display Mode", "Type of information to display");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
-
+
prop = RNA_def_property(srna, "filter_text", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "search_string");
RNA_def_property_ui_text(prop, "Display Filter", "Live search filtering string");
RNA_def_property_flag(prop, PROP_TEXTEDIT_UPDATE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
-
+
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_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");
@@ -2189,17 +2268,17 @@ static void rna_def_background_image(BlenderRNA *brna)
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_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");
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");
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);
@@ -2290,8 +2369,8 @@ static void rna_def_backgroundImages(BlenderRNA *brna, PropertyRNA *cprop)
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_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ 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_BackgroundImage_clear");
RNA_def_function_ui_description(func, "Remove all background images");
@@ -2319,7 +2398,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
{RV3D_CAMOB, "CAMERA", 0, "Camera", ""},
{0, NULL, 0, NULL, NULL}
};
-
+
static EnumPropertyItem bundle_drawtype_items[] = {
{OB_PLAINAXES, "PLAIN_AXES", 0, "Plain Axes", ""},
{OB_ARROWS, "ARROWS", 0, "Arrows", ""},
@@ -2330,7 +2409,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
{OB_EMPTY_CONE, "CONE", 0, "Cone", ""},
{0, NULL, 0, NULL, NULL}
};
-
+
static EnumPropertyItem view3d_matcap_items[] = {
{ICON_MATCAP_01, "01", ICON_MATCAP_01, "", ""},
{ICON_MATCAP_02, "02", ICON_MATCAP_02, "", ""},
@@ -2358,17 +2437,17 @@ static void rna_def_space_view3d(BlenderRNA *brna)
{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");
-
+
prop = RNA_def_property(srna, "camera", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_pointer_sdna(prop, NULL, "camera");
RNA_def_property_ui_text(prop, "Camera",
"Active camera used in this view (when unlocked from the scene's active camera)");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_camera_update");
/* render border */
prop = RNA_def_property(srna, "use_render_border", PROP_BOOLEAN, PROP_NONE);
@@ -2407,7 +2486,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "ob_centre");
RNA_def_property_ui_text(prop, "Lock to Object", "3D View center is locked to this object's position");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
+
prop = RNA_def_property(srna, "lock_bone", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "ob_centre_bone");
RNA_def_property_ui_text(prop, "Lock to Bone", "3D View center is locked to this bone's position");
@@ -2430,7 +2509,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
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);
@@ -2438,13 +2517,13 @@ static void rna_def_space_view3d(BlenderRNA *brna)
"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");
RNA_def_property_range(prop, 1.0f, 250.0f);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
+
prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "near");
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
@@ -2475,7 +2554,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
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");
@@ -2492,28 +2571,28 @@ static void rna_def_space_view3d(BlenderRNA *brna)
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",
@@ -2525,7 +2604,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
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",
@@ -2542,9 +2621,9 @@ static void rna_def_space_view3d(BlenderRNA *brna)
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");
+ prop = RNA_def_property(srna, "show_mode_shade_override", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_SHOW_MODE_SHADE_OVERRIDE);
+ RNA_def_property_ui_text(prop, "Full Shading", "Use full shading for mode drawing (to view final result)");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "show_occlude_wire", PROP_BOOLEAN, PROP_NONE);
@@ -2561,7 +2640,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
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, "flag3", V3D_SHOW_WORLD);
RNA_def_property_ui_text(prop, "World Background", "Display world colors in the background");
@@ -2591,15 +2670,15 @@ static void rna_def_space_view3d(BlenderRNA *brna)
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 and pose mode only)");
+ 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_boolean_sdna(prop, NULL, "twflag", V3D_MANIPULATOR_DRAW);
RNA_def_property_ui_text(prop, "Manipulator", "Use a 3D manipulator widget for controlling transforms");
RNA_def_property_ui_icon(prop, ICON_MANIPUL, 0);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
@@ -2610,17 +2689,18 @@ static void rna_def_space_view3d(BlenderRNA *brna)
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_enum_funcs(prop, "rna_View3D_transform_orientation_get", "rna_View3D_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_CurrentOrientation_get", NULL, NULL, NULL);
+ RNA_def_property_pointer_funcs(prop, "rna_View3D_current_orientation_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);
@@ -2638,12 +2718,17 @@ static void rna_def_space_view3d(BlenderRNA *brna)
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);
@@ -2695,7 +2780,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
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);
@@ -2758,17 +2843,17 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "viewlock", RV3D_LOCKED);
RNA_def_property_ui_text(prop, "Lock", "Lock view rotation in side views");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_RegionView3D_quadview_update");
-
+
prop = RNA_def_property(srna, "show_sync_view", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "viewlock", RV3D_BOXVIEW);
RNA_def_property_ui_text(prop, "Box", "Sync view position between side views");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_RegionView3D_quadview_update");
-
+
prop = RNA_def_property(srna, "use_box_clip", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "viewlock", RV3D_BOXCLIP);
RNA_def_property_ui_text(prop, "Clip", "Clip objects based on what's visible in other side views");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_RegionView3D_quadview_clip_update");
-
+
prop = RNA_def_property(srna, "perspective_matrix", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_float_sdna(prop, NULL, "persmat");
RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* XXX: for now, it's too risky for users to do this */
@@ -2781,7 +2866,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
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, "Window Matrix", "Current window matrix");
-
+
prop = RNA_def_property(srna, "view_matrix", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_float_sdna(prop, NULL, "viewmat");
RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
@@ -2799,7 +2884,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "is_persp", 1);
RNA_def_property_ui_text(prop, "Is Perspective", "");
RNA_def_property_flag(prop, PROP_EDITABLE);
-
+
prop = RNA_def_property(srna, "view_location", PROP_FLOAT, PROP_TRANSLATION);
#if 0
RNA_def_property_float_sdna(prop, NULL, "ofs"); /* cant use because its negated */
@@ -2811,7 +2896,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "View Location", "View pivot location");
RNA_def_property_ui_range(prop, -10000.0, 10000.0, 10, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_update(prop, NC_WINDOW, NULL);
-
+
prop = RNA_def_property(srna, "view_rotation", PROP_FLOAT, PROP_QUATERNION); /* cant use because its inverted */
#if 0
RNA_def_property_float_sdna(prop, NULL, "viewquat");
@@ -2822,7 +2907,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
#endif
RNA_def_property_ui_text(prop, "View Rotation", "Rotation in quaternions (keep normalized)");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
+
/* not sure we need rna access to these but adding anyway */
prop = RNA_def_property(srna, "view_distance", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_float_sdna(prop, NULL, "dist");
@@ -2858,14 +2943,14 @@ static void rna_def_space_buttons(BlenderRNA *brna)
srna = RNA_def_struct(brna, "SpaceProperties", "Space");
RNA_def_struct_sdna(srna, "SpaceButs");
RNA_def_struct_ui_text(srna, "Properties Space", "Properties space data");
-
+
prop = RNA_def_property(srna, "context", PROP_ENUM, PROP_NONE);
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_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);
@@ -2953,7 +3038,7 @@ static void rna_def_space_image(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_float_funcs(prop, "rna_SpaceImageEditor_zoom_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Zoom", "Zoom factor");
-
+
/* image draw */
prop = RNA_def_property(srna, "show_repeat", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SI_DRAW_TILE);
@@ -2985,7 +3070,7 @@ static void rna_def_space_image(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "SpaceUVEditor");
RNA_def_property_pointer_funcs(prop, "rna_SpaceImageEditor_uvedit_get", NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "UV Editor", "UV editor settings");
-
+
/* mode */
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mode");
@@ -3015,7 +3100,7 @@ static void rna_def_space_image(BlenderRNA *brna)
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);
-
+
/* update */
prop = RNA_def_property(srna, "use_realtime_update", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "lock", 0);
@@ -3054,7 +3139,7 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
-
+
static EnumPropertyItem view_type_items[] = {
{SEQ_VIEW_SEQUENCE, "SEQUENCER", ICON_SEQ_SEQUENCER, "Sequencer", ""},
{SEQ_VIEW_PREVIEW, "PREVIEW", ICON_SEQ_PREVIEW, "Image Preview", ""},
@@ -3108,7 +3193,7 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
srna = RNA_def_struct(brna, "SpaceSequenceEditor", "Space");
RNA_def_struct_sdna(srna, "SpaceSeq");
RNA_def_struct_ui_text(srna, "Space Sequence Editor", "Sequence editor space data");
-
+
/* view type, fairly important */
prop = RNA_def_property(srna, "view_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "view");
@@ -3129,17 +3214,17 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
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_SEQUENCER, NULL);
-
+
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_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
-
+
prop = RNA_def_property(srna, "use_marker_sync", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_MARKER_TRANS);
RNA_def_property_ui_text(prop, "Sync Markers", "Transform markers as well as strips");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
-
+
prop = RNA_def_property(srna, "show_separate_color", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_DRAW_COLOR_SEPARATED);
RNA_def_property_ui_text(prop, "Separate Colors", "Separate color channels in preview");
@@ -3164,7 +3249,7 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SEQ_DRAWFRAMES);
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);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_GPENCIL);
RNA_def_property_ui_text(prop, "Show Grease Pencil",
@@ -3195,14 +3280,14 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Show Overexposed", "Show overexposed areas with zebra stripes");
RNA_def_property_range(prop, 0, 110);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
-
+
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_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");
@@ -3263,7 +3348,7 @@ static void rna_def_space_text(BlenderRNA *brna)
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_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL);
-
+
prop = RNA_def_property(srna, "show_line_highlight", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "line_hlight", 0);
RNA_def_property_ui_text(prop, "Highlight Line", "Highlight the current line");
@@ -3308,12 +3393,12 @@ static void rna_def_space_text(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "overwrite", 1);
RNA_def_property_ui_text(prop, "Overwrite", "Overwrite characters when typing rather than inserting them");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL);
-
+
prop = RNA_def_property(srna, "use_live_edit", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "live_edit", 1);
RNA_def_property_ui_text(prop, "Live Edit", "Run python while editing");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL);
-
+
/* find */
prop = RNA_def_property(srna, "use_find_all", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", ST_FIND_ALL);
@@ -3347,7 +3432,7 @@ 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 EnumPropertyItem mode_items[] = {
{SACTCONT_DOPESHEET, "DOPESHEET", ICON_OOPS, "Dope Sheet", "Edit all keyframes in scene"},
@@ -3358,8 +3443,8 @@ static void rna_def_space_dopesheet(BlenderRNA *brna)
{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");
@@ -3370,52 +3455,54 @@ 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 */
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_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 */
prop = RNA_def_property(srna, "show_seconds", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SACTION_DRAWTIME);
RNA_def_property_ui_text(prop, "Show Seconds", "Show timing in seconds not frames");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, NULL);
-
+
prop = RNA_def_property(srna, "show_frame_indicator", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SACTION_NODRAWCFRANUM);
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_DOPESHEET, NULL);
-
+
prop = RNA_def_property(srna, "show_sliders", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SACTION_SLIDERS);
RNA_def_property_ui_text(prop, "Show Sliders", "Show sliders beside F-Curve channels");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, NULL);
-
+
prop = RNA_def_property(srna, "show_pose_markers", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SACTION_POSEMARKERS_SHOW);
RNA_def_property_ui_text(prop, "Show Pose Markers",
"Show markers belonging to the active action instead of Scene markers "
"(Action and Shape Key Editors only)");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, NULL);
-
+
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 "
"(pose bones only currently)");
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);
RNA_def_property_ui_text(prop, "AutoMerge Keyframes", "Automatically merge nearby keyframes");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, NULL);
-
+
prop = RNA_def_property(srna, "use_realtime_update", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SACTION_NOREALTIMEUPDATES);
RNA_def_property_ui_text(prop, "Realtime Updates",
@@ -3444,14 +3531,14 @@ static void rna_def_space_graph(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
-
+
static 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 EnumPropertyItem gpivot_items[] = {
{V3D_AROUND_CENTER_BOUNDS, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center", ""},
@@ -3462,93 +3549,93 @@ static void rna_def_space_graph(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
-
+
srna = RNA_def_struct(brna, "SpaceGraphEditor", "Space");
RNA_def_struct_sdna(srna, "SpaceIpo");
RNA_def_struct_ui_text(srna, "Space Graph Editor", "Graph Editor space data");
-
+
/* 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_ui_text(prop, "Mode", "Editing context being displayed");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, "rna_SpaceGraphEditor_display_mode_update");
-
+
/* display */
prop = RNA_def_property(srna, "show_seconds", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SIPO_DRAWTIME);
RNA_def_property_ui_text(prop, "Show Seconds", "Show timing in seconds not frames");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
-
+
prop = RNA_def_property(srna, "show_frame_indicator", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_NODRAWCFRANUM);
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_GRAPH, NULL);
-
+
prop = RNA_def_property(srna, "show_sliders", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SIPO_SLIDERS);
RNA_def_property_ui_text(prop, "Show Sliders", "Show sliders beside F-Curve channels");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
-
+
prop = RNA_def_property(srna, "show_handles", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_NOHANDLES);
RNA_def_property_ui_text(prop, "Show Handles", "Show handles of Bezier control points");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
-
+
prop = RNA_def_property(srna, "use_only_selected_curves_handles", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SIPO_SELCUVERTSONLY);
RNA_def_property_ui_text(prop, "Only Selected Curve Keyframes",
"Only keyframes of selected F-Curves are visible and editable");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
-
+
prop = RNA_def_property(srna, "use_only_selected_keyframe_handles", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SIPO_SELVHANDLESONLY);
RNA_def_property_ui_text(prop, "Only Selected Keyframes Handles",
"Only show and edit handles of selected keyframes");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
-
+
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 "
"(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");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
-
+
/* editing */
prop = RNA_def_property(srna, "use_auto_merge_keyframes", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_NOTRANSKEYCULL);
RNA_def_property_ui_text(prop, "AutoMerge Keyframes", "Automatically merge nearby keyframes");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
-
+
prop = RNA_def_property(srna, "use_realtime_update", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_NOREALTIMEUPDATES);
RNA_def_property_ui_text(prop, "Realtime Updates",
"When transforming keyframes, changes to the animation data are flushed to other views");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
-
+
/* cursor */
prop = RNA_def_property(srna, "show_cursor", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_NODRAWCURSOR);
RNA_def_property_ui_text(prop, "Show Cursor", "Show 2D cursor");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
-
+
prop = RNA_def_property(srna, "cursor_position_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "cursorTime");
RNA_def_property_ui_text(prop, "Cursor X-Value", "Graph Editor 2D-Value cursor - X-Value component");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
-
+
prop = RNA_def_property(srna, "cursor_position_y", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "cursorVal");
RNA_def_property_ui_text(prop, "Cursor Y-Value", "Graph Editor 2D-Value cursor - Y-Value component");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, 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, gpivot_items);
@@ -3592,34 +3679,34 @@ static void rna_def_space_nla(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
-
+
srna = RNA_def_struct(brna, "SpaceNLA", "Space");
RNA_def_struct_sdna(srna, "SpaceNla");
RNA_def_struct_ui_text(srna, "Space Nla Editor", "NLA editor space data");
-
+
/* display */
prop = RNA_def_property(srna, "show_seconds", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SNLA_DRAWTIME);
RNA_def_property_ui_text(prop, "Show Seconds", "Show timing in seconds not frames");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NLA, NULL);
-
+
prop = RNA_def_property(srna, "show_frame_indicator", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SNLA_NODRAWCFRANUM);
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_NLA, NULL);
-
+
prop = RNA_def_property(srna, "show_strip_curves", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SNLA_NOSTRIPCURVES);
RNA_def_property_ui_text(prop, "Show Control F-Curves", "Show influence F-Curves on strips");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NLA, NULL);
-
+
prop = RNA_def_property(srna, "show_local_markers", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SNLA_NOLOCALMARKERS);
RNA_def_property_ui_text(prop, "Show Local Markers",
"Show action-local markers on the strips, useful when synchronizing timing across strips");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NLA, NULL);
-
+
/* editing */
prop = RNA_def_property(srna, "use_realtime_update", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SNLA_NOREALTIMEUPDATES);
@@ -3645,54 +3732,54 @@ 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");
@@ -3711,17 +3798,17 @@ static void rna_def_console_line(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
-
+
srna = RNA_def_struct(brna, "ConsoleLine", NULL);
RNA_def_struct_ui_text(srna, "Console Input", "Input line for the interactive console");
-
+
prop = RNA_def_property(srna, "body", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop, "rna_ConsoleLine_body_get", "rna_ConsoleLine_body_length",
"rna_ConsoleLine_body_set");
RNA_def_property_ui_text(prop, "Line", "Text in the line");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CONSOLE, NULL);
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_TEXT);
-
+
prop = RNA_def_property(srna, "current_character", PROP_INT, PROP_NONE); /* copied from text editor */
RNA_def_property_int_sdna(prop, NULL, "cursor");
RNA_def_property_int_funcs(prop, NULL, NULL, "rna_ConsoleLine_cursor_index_range");
@@ -3732,16 +3819,16 @@ static void rna_def_console_line(BlenderRNA *brna)
RNA_def_property_enum_items(prop, console_line_type_items);
RNA_def_property_ui_text(prop, "Type", "Console line type when used in scrollback");
}
-
+
static void rna_def_space_console(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
-
+
srna = RNA_def_struct(brna, "SpaceConsole", "Space");
RNA_def_struct_sdna(srna, "SpaceConsole");
RNA_def_struct_ui_text(srna, "Space Console", "Interactive python console");
-
+
/* display */
prop = RNA_def_property(srna, "font_size", PROP_INT, PROP_NONE); /* copied from text editor */
RNA_def_property_int_sdna(prop, NULL, "lheight");
@@ -3753,14 +3840,14 @@ static void rna_def_space_console(BlenderRNA *brna)
prop = RNA_def_property(srna, "select_start", PROP_INT, PROP_UNSIGNED); /* copied from text editor */
RNA_def_property_int_sdna(prop, NULL, "sel_start");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CONSOLE, NULL);
-
+
prop = RNA_def_property(srna, "select_end", PROP_INT, PROP_UNSIGNED); /* copied from text editor */
RNA_def_property_int_sdna(prop, NULL, "sel_end");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CONSOLE, NULL);
prop = RNA_def_property(srna, "prompt", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Prompt", "Command line prompt");
-
+
prop = RNA_def_property(srna, "language", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Language", "Command line prompt language");
@@ -3768,7 +3855,7 @@ static void rna_def_space_console(BlenderRNA *brna)
RNA_def_property_collection_sdna(prop, NULL, "history", NULL);
RNA_def_property_struct_type(prop, "ConsoleLine");
RNA_def_property_ui_text(prop, "History", "Command history");
-
+
prop = RNA_def_property(srna, "scrollback", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "scrollback", NULL);
RNA_def_property_struct_type(prop, "ConsoleLine");
@@ -3779,7 +3866,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
-
+
static EnumPropertyItem file_display_items[] = {
{FILE_SHORTDISPLAY, "LIST_SHORT", ICON_SHORTDISPLAY, "Short List", "Display files as short list"},
{FILE_LONGDISPLAY, "LIST_LONG", ICON_LONGDISPLAY, "Long List", "Display files as a detailed list"},
@@ -3820,6 +3907,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_RADIO, "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"},
@@ -3827,6 +3915,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}
};
@@ -3844,7 +3933,7 @@ 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,
+ {FILTER_ID_CA | FILTER_ID_LA | FILTER_ID_SPK | FILTER_ID_WO | FILTER_ID_WS,
"ENVIRONMENT", ICON_WORLD_DATA, "Environment", "Show/hide worlds, lamps, cameras and speakers"},
{FILTER_ID_BR | FILTER_ID_GD | FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_CF,
"MISC", ICON_GREASEPENCIL, "Miscellaneous", "Show/hide other data types"},
@@ -4043,7 +4132,7 @@ static void rna_def_space_filebrowser(BlenderRNA *brna)
prop = RNA_def_property(srna, "params", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "params");
RNA_def_property_ui_text(prop, "Filebrowser Parameter", "Parameters and Settings for the Filebrowser");
-
+
prop = RNA_def_property(srna, "active_operator", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "op");
RNA_def_property_ui_text(prop, "Active Operator", "");
@@ -4124,28 +4213,28 @@ static void rna_def_space_info(BlenderRNA *brna)
srna = RNA_def_struct(brna, "SpaceInfo", "Space");
RNA_def_struct_sdna(srna, "SpaceInfo");
RNA_def_struct_ui_text(srna, "Space Info", "Info space data");
-
+
/* reporting display */
prop = RNA_def_property(srna, "show_report_debug", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "rpt_mask", INFO_RPT_DEBUG);
RNA_def_property_ui_text(prop, "Show Debug", "Display debug reporting info");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
-
+
prop = RNA_def_property(srna, "show_report_info", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "rpt_mask", INFO_RPT_INFO);
RNA_def_property_ui_text(prop, "Show Info", "Display general information");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
-
+
prop = RNA_def_property(srna, "show_report_operator", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "rpt_mask", INFO_RPT_OP);
RNA_def_property_ui_text(prop, "Show Operator", "Display the operator log");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
-
+
prop = RNA_def_property(srna, "show_report_warning", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "rpt_mask", INFO_RPT_WARN);
RNA_def_property_ui_text(prop, "Show Warn", "Display warnings");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
-
+
prop = RNA_def_property(srna, "show_report_error", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "rpt_mask", INFO_RPT_ERR);
RNA_def_property_ui_text(prop, "Show Error", "Display error text");
@@ -4161,7 +4250,7 @@ static void rna_def_space_userpref(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
-
+
srna = RNA_def_struct(brna, "SpaceUserPreferences", "Space");
RNA_def_struct_sdna(srna, "SpaceUserPref");
RNA_def_struct_ui_text(srna, "Space User Preferences", "User preferences space data");
@@ -4183,7 +4272,7 @@ static void rna_def_node_tree_path(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
-
+
srna = RNA_def_struct(brna, "NodeTreePath", NULL);
RNA_def_struct_sdna(srna, "bNodeTreePath");
RNA_def_struct_ui_text(srna, "Node Tree Path", "Element of the node space tree path");
@@ -4218,15 +4307,15 @@ static void rna_def_space_node_path_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Set the root node tree");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "node_tree", "NodeTree", "Node Tree", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
func = RNA_def_function(srna, "append", "rna_SpaceNodeEditor_path_append");
RNA_def_function_ui_description(func, "Append a node group tree to the path");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "node_tree", "NodeTree", "Node Tree", "Node tree to append to the node editor path");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_pointer(func, "node", "Node", "Node", "Group node linking to this node tree");
- RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
func = RNA_def_function(srna, "pop", "rna_SpaceNodeEditor_path_pop");
RNA_def_function_ui_description(func, "Remove the last node tree from the path");
@@ -4303,17 +4392,17 @@ static void rna_def_space_node(BlenderRNA *brna)
prop = RNA_def_property(srna, "id", PROP_POINTER, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "ID", "Datablock whose nodes are being edited");
+ RNA_def_property_ui_text(prop, "ID", "Data-block whose nodes are being edited");
prop = RNA_def_property(srna, "id_from", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "from");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "ID From", "Datablock from which the edited data-block is linked");
+ RNA_def_property_ui_text(prop, "ID From", "Data-block from which the edited data-block is linked");
prop = RNA_def_property(srna, "path", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "treepath", NULL);
RNA_def_property_struct_type(prop, "NodeTreePath");
- RNA_def_property_ui_text(prop, "Node Tree Path", "Path from the data block to the currently edited node tree");
+ RNA_def_property_ui_text(prop, "Node Tree Path", "Path from the data-block to the currently edited node tree");
rna_def_space_node_path_api(brna, prop);
prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE);
@@ -4350,7 +4439,7 @@ static void rna_def_space_node(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", SNODE_AUTO_RENDER);
RNA_def_property_ui_text(prop, "Auto Render", "Re-render and composite changed layers on 3D edits");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
-
+
prop = RNA_def_property(srna, "backdrop_zoom", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "zoom");
RNA_def_property_float_default(prop, 1.0f);
@@ -4358,15 +4447,11 @@ static void rna_def_space_node(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0.01, 100, 1, 2);
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);
- 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");
+ prop = RNA_def_property(srna, "backdrop_offset", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "xof");
+ 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);
@@ -4375,11 +4460,6 @@ static void rna_def_space_node(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Draw Channels", "Channels of the image to draw");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
- prop = RNA_def_property(srna, "show_highlight", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SNODE_SHOW_HIGHLIGHT);
- RNA_def_property_ui_text(prop, "Highlight", "Highlight nodes that are being calculated");
- 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 */
prop = RNA_def_property(srna, "cursor_location", PROP_FLOAT, PROP_XYZ);
RNA_def_property_array(prop, 2);
@@ -4418,12 +4498,12 @@ static void rna_def_space_logic(BlenderRNA *brna)
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");
@@ -4439,7 +4519,7 @@ static void rna_def_space_logic(BlenderRNA *brna)
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");
@@ -4455,12 +4535,12 @@ static void rna_def_space_logic(BlenderRNA *brna)
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");
diff --git a/source/blender/makesrna/intern/rna_space_api.c b/source/blender/makesrna/intern/rna_space_api.c
index 3cfbd798ad6..aabe421b872 100644
--- a/source/blender/makesrna/intern/rna_space_api.c
+++ b/source/blender/makesrna/intern/rna_space_api.c
@@ -31,6 +31,9 @@
#ifdef RNA_RUNTIME
+#include "BKE_global.h"
+
+#include "ED_screen.h"
#include "ED_text.h"
static void rna_RegionView3D_update(ID *id, RegionView3D *rv3d)
@@ -43,11 +46,10 @@ 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;
+ View3D *v3d = sa->spacedata.first;
+ Scene *scene = ED_screen_scene_find(sc, G.main->wm.first);
- ED_view3d_update_viewmat(sc->scene, v3d, ar, NULL, NULL);
+ ED_view3d_update_viewmat(scene, v3d, ar, NULL, NULL, NULL);
}
}
@@ -84,9 +86,9 @@ void RNA_api_space_node(StructRNA *srna)
RNA_def_function_ui_description(func, "Set the cursor location using region coordinates");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_int(func, "x", 0, INT_MIN, INT_MAX, "x", "Region x coordinate", -10000, 10000);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "y", 0, INT_MIN, INT_MAX, "y", "Region y coordinate", -10000, 10000);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
void RNA_api_space_text(StructRNA *srna)
@@ -98,9 +100,9 @@ void RNA_api_space_text(StructRNA *srna)
RNA_def_function_ui_description(func, "Retrieve the region position from the given line and character position");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
parm = RNA_def_int(func, "line", 0, INT_MIN, INT_MAX, "Line", "Line index", 0, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "column", 0, INT_MIN, INT_MAX, "Column", "Column index", 0, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int_array(func, "result", 2, NULL, -1, INT_MAX, "", "Region coordinates", -1, INT_MAX);
RNA_def_function_output(func, parm);
}
diff --git a/source/blender/makesrna/intern/rna_speaker.c b/source/blender/makesrna/intern/rna_speaker.c
index f47b54c2d95..f37b75b3db2 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_text_api.c b/source/blender/makesrna/intern/rna_text_api.c
index 2478ad0fe1a..0287f74587b 100644
--- a/source/blender/makesrna/intern/rna_text_api.c
+++ b/source/blender/makesrna/intern/rna_text_api.c
@@ -55,15 +55,15 @@ static void rna_Text_write(Text *text, const char *str)
void RNA_api_text(StructRNA *srna)
{
FunctionRNA *func;
- PropertyRNA *prop;
+ PropertyRNA *parm;
func = RNA_def_function(srna, "clear", "rna_Text_clear");
RNA_def_function_ui_description(func, "clear the text block");
func = RNA_def_function(srna, "write", "rna_Text_write");
RNA_def_function_ui_description(func, "write text at the cursor location and advance to the end of the text block");
- prop = RNA_def_string(func, "text", "Text", 0, "", "New text for this data-block");
- RNA_def_property_flag(prop, PROP_REQUIRED);
+ parm = RNA_def_string(func, "text", "Text", 0, "", "New text for this data-block");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index 1e88585a286..1c7b750fbe1 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -113,11 +113,12 @@ static EnumPropertyItem blend_type_items[] = {
#include "RNA_access.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"
@@ -168,7 +169,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);
}
@@ -214,7 +215,7 @@ static void rna_Texture_nodes_update(Main *UNUSED(bmain), Scene *UNUSED(scene),
{
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);
}
@@ -225,11 +226,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:
@@ -245,8 +246,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);
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ BKE_paint_invalidate_overlay_tex(scene, sl, mtex->tex);
WM_main_add_notifier(NC_BRUSH, id);
break;
}
@@ -263,7 +266,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;
}
@@ -645,7 +648,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");
@@ -653,6 +656,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");
@@ -660,12 +664,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");
@@ -673,6 +678,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");
@@ -680,26 +686,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");
@@ -708,6 +719,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");
@@ -734,7 +746,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",
diff --git a/source/blender/makesrna/intern/rna_texture_api.c b/source/blender/makesrna/intern/rna_texture_api.c
index ef1ef5e1469..a8fcf0ca3b6 100644
--- a/source/blender/makesrna/intern/rna_texture_api.c
+++ b/source/blender/makesrna/intern/rna_texture_api.c
@@ -93,11 +93,11 @@ void RNA_api_texture(StructRNA *srna)
RNA_def_function_ui_description(func, "Evaluate the texture at the coordinates given");
parm = RNA_def_float_vector(func, "value", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return location and normal */
parm = RNA_def_float_vector(func, "result", 4, NULL, -FLT_MAX, FLT_MAX, "Result", NULL, -1e4, 1e4);
- RNA_def_property_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_function_output(func, parm);
}
@@ -119,7 +119,7 @@ void RNA_api_environment_map(StructRNA *srna)
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_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_pointer(func, "scene", "Scene", "", "Overrides the scene from which image parameters are taken");
diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index 2564bdb800f..ea45b08458c 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -48,9 +48,10 @@
#ifdef RNA_RUNTIME
-#include "BKE_depsgraph.h"
#include "BKE_node.h"
+#include "DEG_depsgraph.h"
+
#include "IMB_imbuf.h"
#include "WM_api.h"
@@ -394,6 +395,16 @@ static int rna_track_2d_stabilization(CollectionPropertyIterator *UNUSED(iter),
return 0;
}
+static int rna_track_2d_stabilization_rotation(CollectionPropertyIterator *UNUSED(iter), void *data)
+{
+ MovieTrackingTrack *track = (MovieTrackingTrack *)data;
+
+ if ((track->flag & TRACK_USE_2D_STAB_ROT) == 0)
+ return 1;
+
+ return 0;
+}
+
static void rna_tracking_stabTracks_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
MovieClip *clip = (MovieClip *)ptr->id.data;
@@ -421,29 +432,53 @@ static void rna_tracking_stabTracks_active_index_range(PointerRNA *ptr, int *min
*max = max_ii(0, clip->tracking.stabilization.tot_track - 1);
}
-static void rna_tracking_resetIntrinsics(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_tracking_stabRotTracks_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
MovieClip *clip = (MovieClip *)ptr->id.data;
- MovieTracking *tracking = &clip->tracking;
+ rna_iterator_listbase_begin(iter, &clip->tracking.tracks, rna_track_2d_stabilization_rotation);
+}
- if (tracking->camera.intrinsics) {
- BKE_tracking_distortion_free(tracking->camera.intrinsics);
- tracking->camera.intrinsics = NULL;
- }
+static int rna_tracking_stabRotTracks_active_index_get(PointerRNA *ptr)
+{
+ MovieClip *clip = (MovieClip *)ptr->id.data;
+ return clip->tracking.stabilization.act_rot_track;
}
-static void rna_tracking_flushUpdate(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
+static void rna_tracking_stabRotTracks_active_index_set(PointerRNA *ptr, int value)
{
MovieClip *clip = (MovieClip *)ptr->id.data;
- MovieTrackingStabilization *stab = &clip->tracking.stabilization;
+ clip->tracking.stabilization.act_rot_track = value;
+}
- stab->ok = 0;
+static void rna_tracking_stabRotTracks_active_index_range(PointerRNA *ptr, int *min, int *max,
+ int *UNUSED(softmin), int *UNUSED(softmax))
+{
+ MovieClip *clip = (MovieClip *)ptr->id.data;
+
+ *min = 0;
+ *max = max_ii(0, clip->tracking.stabilization.tot_rot_track - 1);
+}
+
+static void rna_tracking_flushUpdate(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
+{
+ MovieClip *clip = (MovieClip *)ptr->id.data;
nodeUpdateID(scene->nodetree, &clip->id);
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)
+{
+ MovieClip *clip = (MovieClip *)ptr->id.data;
+ MovieTracking *tracking = &clip->tracking;
+
+ if (tracking->camera.intrinsics) {
+ BKE_tracking_distortion_free(tracking->camera.intrinsics);
+ tracking->camera.intrinsics = NULL;
+ }
}
static void rna_trackingObject_tracks_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
@@ -521,7 +556,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)
@@ -1255,7 +1290,7 @@ static void rna_def_trackingMarkers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Get marker for specified frame");
parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame",
"Frame number to find marker for", MINFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "exact", true, "Exact",
"Get marker at exact frame number rather than get estimated marker");
parm = RNA_def_pointer(func, "marker", "MovieTrackingMarker", "", "Marker for specified frame");
@@ -1265,11 +1300,11 @@ static void rna_def_trackingMarkers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Insert a new marker at the specified frame");
parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame",
"Frame number to insert marker to", MINFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_float_vector(func, "co", 2, NULL, -1.0, 1.0, "Coordinate",
"Place new marker at the given frame using specified in normalized space coordinates",
-1.0, 1.0);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "marker", "MovieTrackingMarker", "", "Newly created marker");
RNA_def_function_return(func, parm);
@@ -1277,7 +1312,7 @@ static void rna_def_trackingMarkers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Delete marker at specified frame");
parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame",
"Frame number to delete marker from", MINFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
static void rna_def_trackingTrack(BlenderRNA *brna)
@@ -1495,6 +1530,12 @@ static void rna_def_trackingTrack(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Weight", "Influence of this track on a final solution");
+ /* weight_stab */
+ prop = RNA_def_property(srna, "weight_stab", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "weight_stab");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Stab Weight", "Influence of this track on 2D stabilization");
+
/* offset */
prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_array(prop, 2);
@@ -1553,7 +1594,7 @@ static void rna_def_trackingPlaneMarkers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Get plane marker for specified frame");
parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame",
"Frame number to find marker for", MINFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "exact", true, "Exact",
"Get plane marker at exact frame number rather than get estimated marker");
parm = RNA_def_pointer(func, "plane_marker", "MovieTrackingPlaneMarker", "", "Plane marker for specified frame");
@@ -1563,7 +1604,7 @@ static void rna_def_trackingPlaneMarkers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Insert a new plane marker at the specified frame");
parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame",
"Frame number to insert marker to", MINFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "plane_marker", "MovieTrackingPlaneMarker", "", "Newly created plane marker");
RNA_def_function_return(func, parm);
@@ -1571,7 +1612,7 @@ static void rna_def_trackingPlaneMarkers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Delete plane marker at specified frame");
parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame",
"Frame number to delete plane marker from", MINFRAME, MAXFRAME);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
static void rna_def_trackingPlaneTrack(BlenderRNA *brna)
@@ -1634,15 +1675,15 @@ static void rna_def_trackingStabilization(BlenderRNA *brna)
PropertyRNA *prop;
static EnumPropertyItem filter_items[] = {
- {TRACKING_FILTER_NEAREST, "NEAREST", 0, "Nearest", ""},
- {TRACKING_FILTER_BILINEAR, "BILINEAR", 0, "Bilinear", ""},
- {TRACKING_FILTER_BICUBIC, "BICUBIC", 0, "Bicubic", ""},
+ {TRACKING_FILTER_NEAREST, "NEAREST", 0, "Nearest", "No interpolation, use nearest neighbor pixel"},
+ {TRACKING_FILTER_BILINEAR, "BILINEAR", 0, "Bilinear", "Simple interpolation between adjacent pixels"},
+ {TRACKING_FILTER_BICUBIC, "BICUBIC", 0, "Bicubic", "High quality pixel interpolation"},
{0, NULL, 0, NULL, NULL}
};
srna = RNA_def_struct(brna, "MovieTrackingStabilization", NULL);
RNA_def_struct_path_func(srna, "rna_trackingStabilization_path");
- RNA_def_struct_ui_text(srna, "Movie tracking stabilization data", "Match-moving stabilization data for tracking");
+ RNA_def_struct_ui_text(srna, "Movie tracking stabilization data", "2D stabilization based on tracking markers");
/* 2d stabilization */
prop = RNA_def_property(srna, "use_2d_stabilization", PROP_BOOLEAN, PROP_NONE);
@@ -1651,22 +1692,30 @@ static void rna_def_trackingStabilization(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Use 2D stabilization", "Use 2D stabilization for footage");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
+ /* use_stabilize_rotation */
+ prop = RNA_def_property(srna, "use_stabilize_rotation", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", TRACKING_STABILIZE_ROTATION);
+ RNA_def_property_ui_text(prop, "Stabilize Rotation", "Stabilize detected rotation around center of frame");
+ RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
+
+ /* use_stabilize_scale */
+ prop = RNA_def_property(srna, "use_stabilize_scale", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", TRACKING_STABILIZE_SCALE);
+ RNA_def_property_ui_text(prop, "Stabilize Scale", "Compensate any scale changes relative to center of rotation");
+ RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
+
/* tracks */
prop = RNA_def_property(srna, "tracks", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_funcs(prop, "rna_tracking_stabTracks_begin", "rna_iterator_listbase_next",
"rna_iterator_listbase_end", "rna_iterator_listbase_get",
NULL, NULL, NULL, NULL);
RNA_def_property_struct_type(prop, "MovieTrackingTrack");
- RNA_def_property_ui_text(prop, "Tracks", "Collection of tracks used for stabilization");
+ RNA_def_property_ui_text(prop, "Translation Tracks",
+ "Collection of tracks used for 2D stabilization (translation)");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
- /* rotation track */
- prop = RNA_def_property(srna, "rotation_track", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "rot_track");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Rotation Track", "Track used to compensate rotation");
- RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, "rna_tracking_flushUpdate");
-
/* active track index */
prop = RNA_def_property(srna, "active_track_index", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "act_track");
@@ -1674,7 +1723,65 @@ static void rna_def_trackingStabilization(BlenderRNA *brna)
RNA_def_property_int_funcs(prop, "rna_tracking_stabTracks_active_index_get",
"rna_tracking_stabTracks_active_index_set",
"rna_tracking_stabTracks_active_index_range");
- RNA_def_property_ui_text(prop, "Active Track Index", "Index of active track in stabilization tracks list");
+ RNA_def_property_ui_text(prop, "Active Track Index",
+ "Index of active track in translation stabilization tracks list");
+
+ /* tracks used for rotation stabilization */
+ prop = RNA_def_property(srna, "rotation_tracks", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_funcs(prop, "rna_tracking_stabRotTracks_begin", "rna_iterator_listbase_next",
+ "rna_iterator_listbase_end", "rna_iterator_listbase_get",
+ NULL, NULL, NULL, NULL);
+ RNA_def_property_struct_type(prop, "MovieTrackingTrack");
+ RNA_def_property_ui_text(prop, "Rotation Tracks", "Collection of tracks used for 2D stabilization (translation)");
+ RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
+
+ /* active rotation track index */
+ prop = RNA_def_property(srna, "active_rotation_track_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "act_rot_track");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_int_funcs(prop, "rna_tracking_stabRotTracks_active_index_get",
+ "rna_tracking_stabRotTracks_active_index_set",
+ "rna_tracking_stabRotTracks_active_index_range");
+ RNA_def_property_ui_text(prop, "Active Rotation Track Index",
+ "Index of active track in rotation stabilization tracks list");
+
+ /* anchor frame */
+ prop = RNA_def_property(srna, "anchor_frame", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "anchor_frame");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_range(prop, MINFRAME, MAXFRAME);
+ RNA_def_property_ui_text(prop, "Anchor Frame",
+ "Reference point to anchor stabilization "
+ "(other frames will be adjusted relative to this frame's position)");
+ RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
+
+ /* target position */
+ prop = RNA_def_property(srna, "target_position", PROP_FLOAT, PROP_TRANSLATION);
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 3); /* increment in steps of 0.01 and show 3 digit after point */
+ RNA_def_property_float_sdna(prop, NULL, "target_pos");
+ RNA_def_property_ui_text(prop, "Expected Position",
+ "Known relative offset of original shot, will be subtracted "
+ "(e.g. for panning shot, can be animated)");
+ RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL);
+
+ /* target rotation */
+ prop = RNA_def_property(srna, "target_rotation", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "target_rot");
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 10.0f, 3);
+ RNA_def_property_ui_text(prop, "Expected Rotation",
+ "Rotation present on original shot, will be compensated (e.g. for deliberate tilting)");
+ RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL);
+
+ /* target scale */
+ prop = RNA_def_property(srna, "target_scale", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "scale");
+ RNA_def_property_range(prop, FLT_EPSILON, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.01f, 10.0f, 0.001f, 3); /* increment in steps of 0.001. Show 3 digit after point */
+ RNA_def_property_ui_text(prop, "Expected Scale",
+ "Explicitly scale resulting frame to compensate zoom of original shot");
+ RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
/* autoscale */
prop = RNA_def_property(srna, "use_autoscale", PROP_BOOLEAN, PROP_NONE);
@@ -1705,13 +1812,6 @@ static void rna_def_trackingStabilization(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Scale Influence", "Influence of stabilization algorithm on footage scale");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
- /* use_stabilize_rotation */
- prop = RNA_def_property(srna, "use_stabilize_rotation", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", TRACKING_STABILIZE_ROTATION);
- RNA_def_property_ui_text(prop, "Stabilize Rotation", "Stabilize horizon line on the shot");
- RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
-
/* influence_rotation */
prop = RNA_def_property(srna, "influence_rotation", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "rotinf");
@@ -1723,8 +1823,16 @@ static void rna_def_trackingStabilization(BlenderRNA *brna)
prop = RNA_def_property(srna, "filter_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "filter");
RNA_def_property_enum_items(prop, filter_items);
- RNA_def_property_ui_text(prop, "Filter", "Method to use to filter stabilization");
+ RNA_def_property_ui_text(prop, "Interpolate",
+ "Interpolation to use for sub-pixel shifts and rotations due to stabilization");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
+
+ /* UI display : show participating tracks */
+ prop = RNA_def_property(srna, "show_tracks_expanded", PROP_BOOLEAN, PROP_NONE);
+ 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);
}
static void rna_def_reconstructedCamera(BlenderRNA *brna)
@@ -1779,7 +1887,7 @@ static void rna_def_trackingReconstructedCameras(BlenderRNA *brna)
RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame", "Frame number to find camera for", MINFRAME, MAXFRAME);
parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, -FLT_MAX, FLT_MAX, "Matrix",
"Interpolated camera matrix for a given frame", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_THICK_WRAP); /* needed for string return value */
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); /* needed for string return value */
RNA_def_function_output(func, parm);
}
@@ -1987,12 +2095,12 @@ static void rna_def_trackingObjects(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_srna(cprop, "MovieTrackingObjects");
srna = RNA_def_struct(brna, "MovieTrackingObjects", NULL);
RNA_def_struct_sdna(srna, "MovieTracking");
- RNA_def_struct_ui_text(srna, "Movie Objects", "Collection of movie trackingobjects");
+ RNA_def_struct_ui_text(srna, "Movie Objects", "Collection of movie tracking objects");
func = RNA_def_function(srna, "new", "rna_trackingObject_new");
RNA_def_function_ui_description(func, "Add tracking object to this movie clip");
parm = RNA_def_string(func, "name", NULL, 0, "", "Name of new object");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "object", "MovieTrackingObject", "", "New motion tracking object");
RNA_def_function_return(func, parm);
@@ -2000,8 +2108,8 @@ static void rna_def_trackingObjects(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove tracking object from this movie clip");
parm = RNA_def_pointer(func, "object", "MovieTrackingObject", "", "Motion tracking object to be removed");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
/* active object */
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c
index 5f11dd51282..54b82fc89d6 100644
--- a/source/blender/makesrna/intern/rna_ui.c
+++ b/source/blender/makesrna/intern/rna_ui.c
@@ -944,20 +944,20 @@ static void rna_def_panel(BlenderRNA *brna)
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_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* draw */
func = RNA_def_function(srna, "draw", NULL);
RNA_def_function_ui_description(func, "Draw UI elements into the panel UI layout");
RNA_def_function_flag(func, FUNC_REGISTER);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
func = RNA_def_function(srna, "draw_header", NULL);
RNA_def_function_ui_description(func, "Draw UI elements into the panel's header UI layout");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ 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");
@@ -1039,6 +1039,7 @@ static void rna_def_uilist(BlenderRNA *brna)
RNA_def_struct_refine_func(srna, "rna_UIList_refine");
RNA_def_struct_register_funcs(srna, "rna_UIList_register", "rna_UIList_unregister", NULL);
RNA_def_struct_idprops_func(srna, "rna_UIList_idprops");
+ RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES);
/* Registration */
prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
@@ -1084,35 +1085,35 @@ static void rna_def_uilist(BlenderRNA *brna)
"function, you may want to check given 'item' is of the right type...)");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "layout", "UILayout", "", "Layout to draw the item");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take Collection property");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_pointer(func, "item", "AnyType", "", "Item of the collection property");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_int(func, "icon", 0, 0, INT_MAX, "", "Icon of the item in the collection", 0, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "active_data", "AnyType", "",
"Data from which to take property for the active element");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(func, "active_property", NULL, 0, "",
"Identifier of property in active_data, for the active element");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_int(func, "index", 0, 0, INT_MAX, "", "Index of the item in the collection", 0, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_PYFUNC_OPTIONAL);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_PYFUNC_OPTIONAL);
prop = RNA_def_property(func, "flt_flag", PROP_INT, PROP_UNSIGNED);
RNA_def_property_ui_text(prop, "", "The filter-flag result for this item");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_PYFUNC_OPTIONAL);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_PYFUNC_OPTIONAL);
/* draw_filter */
func = RNA_def_function(srna, "draw_filter", NULL);
RNA_def_function_ui_description(func, "Draw filtering options");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "layout", "UILayout", "", "Layout to draw the item");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* filter */
func = RNA_def_function(srna, "filter_items", NULL);
@@ -1120,19 +1121,19 @@ static void rna_def_uilist(BlenderRNA *brna)
"filter_flags, and reorder results in filter_neworder arrays)");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take Collection property");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in data, for the collection");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
prop = RNA_def_property(func, "filter_flags", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_flag(prop, PROP_REQUIRED | PROP_DYNAMIC);
+ RNA_def_property_flag(prop, PARM_REQUIRED | PROP_DYNAMIC);
RNA_def_property_array(prop, 1); /* XXX Dummy value, default 0 does not work */
RNA_def_property_ui_text(prop, "", "An array of filter flags, one for each item in the collection (NOTE: "
"FILTER_ITEM bit is reserved, it defines whether the item is shown or not)");
RNA_def_function_output(func, prop);
prop = RNA_def_property(func, "filter_neworder", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_flag(prop, PROP_REQUIRED | PROP_DYNAMIC);
+ RNA_def_property_flag(prop, PARM_REQUIRED | PROP_DYNAMIC);
RNA_def_property_array(prop, 1); /* XXX Dummy value, default 0 does not work */
RNA_def_property_ui_text(prop, "", "An array of indices, one for each item in the collection, mapping the org "
"index to the new one");
@@ -1166,7 +1167,7 @@ static void rna_def_header(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Draw UI elements into the header UI layout");
RNA_def_function_flag(func, FUNC_REGISTER);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_define_verify_sdna(0); /* not in sdna */
@@ -1214,14 +1215,14 @@ static void rna_def_menu(BlenderRNA *brna)
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_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* draw */
func = RNA_def_function(srna, "draw", NULL);
RNA_def_function_ui_description(func, "Draw UI elements into the menu UI layout");
RNA_def_function_flag(func, FUNC_REGISTER);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_define_verify_sdna(false); /* not in sdna */
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index a751c414d83..fd7346379a1 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -60,7 +60,7 @@ EnumPropertyItem rna_enum_icon_items[] = {
#ifdef RNA_RUNTIME
-static const char *rna_translate_ui_text(const char *text, const char *text_ctxt, StructRNA *type, PropertyRNA *prop,
+const char *rna_translate_ui_text(const char *text, const char *text_ctxt, StructRNA *type, PropertyRNA *prop,
int translate)
{
/* Also return text if UI labels translation is disabled. */
@@ -397,7 +397,7 @@ static void api_ui_item_op(FunctionRNA *func)
{
PropertyRNA *parm;
parm = RNA_def_string(func, "operator", NULL, 0, "", "Identifier of the operator");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
static void api_ui_item_op_common(FunctionRNA *func)
@@ -411,9 +411,9 @@ static void api_ui_item_rna_common(FunctionRNA *func)
PropertyRNA *parm;
parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ 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_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
void RNA_api_ui_layout(StructRNA *srna)
@@ -481,7 +481,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_return(func, parm);
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take the icon");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_function_ui_description(func, "Return the custom icon for this data, "
"use it e.g. to get materials or texture icons");
@@ -492,7 +492,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
api_ui_item_rna_common(func);
parm = RNA_def_string(func, "identifier", NULL, 0, "", "Identifier of the enum item");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_function_ui_description(func, "Return the UI name for this enum item");
func = RNA_def_function(srna, "enum_item_description", "rna_ui_get_enum_description");
@@ -501,7 +501,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
api_ui_item_rna_common(func);
parm = RNA_def_string(func, "identifier", NULL, 0, "", "Identifier of the enum item");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_function_ui_description(func, "Return the UI description for this enum item");
func = RNA_def_function(srna, "enum_item_icon", "rna_ui_get_enum_icon");
@@ -510,7 +510,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
api_ui_item_rna_common(func);
parm = RNA_def_string(func, "identifier", NULL, 0, "", "Identifier of the enum item");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_function_ui_description(func, "Return the icon for this enum item");
/* items */
@@ -541,15 +541,15 @@ void RNA_api_ui_layout(StructRNA *srna)
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");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
api_ui_item_common(func);
func = RNA_def_function(srna, "prop_search", "rna_uiItemPointerR");
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_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ 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_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
api_ui_item_common(func);
func = RNA_def_function(srna, "operator", "rna_uiItemO");
@@ -557,23 +557,22 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_boolean(func, "emboss", true, "", "Draw the button itself, just the icon/text");
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");
- parm = RNA_def_pointer(func, "properties", "OperatorProperties", "",
- "Operator properties to fill in, return when 'properties' is set to true");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+ 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);
RNA_def_function_ui_description(func, "Item. Places a button into the layout to call an Operator");
func = RNA_def_function(srna, "operator_enum", "uiItemsEnumO");
parm = RNA_def_string(func, "operator", NULL, 0, "", "Identifier of the operator");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in operator");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "operator_menu_enum", "rna_uiItemMenuEnumO");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
api_ui_item_op(func); /* cant use api_ui_item_op_common because property must come right after */
parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in operator");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
api_ui_item_common(func);
/* useful in C but not in python */
@@ -582,43 +581,43 @@ void RNA_api_ui_layout(StructRNA *srna)
func = RNA_def_function(srna, "operator_enum_single", "uiItemEnumO_string");
api_ui_item_op_common(func);
parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in operator");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "value", NULL, 0, "", "Enum property value");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "operator_boolean", "uiItemBooleanO");
api_ui_item_op_common(func);
parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in operator");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_boolean(func, "value", false, "", "Value of the property to call the operator with");
- RNA_def_property_flag(parm, PROP_REQUIRED); */
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); */
func = RNA_def_function(srna, "operator_int", "uiItemIntO");
api_ui_item_op_common(func);
parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in operator");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "value", 0, INT_MIN, INT_MAX, "",
"Value of the property to call the operator with", INT_MIN, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED); */
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); */
func = RNA_def_function(srna, "operator_float", "uiItemFloatO");
api_ui_item_op_common(func);
parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in operator");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_float(func, "value", 0, -FLT_MAX, FLT_MAX, "",
"Value of the property to call the operator with", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED); */
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); */
func = RNA_def_function(srna, "operator_string", "uiItemStringO");
api_ui_item_op_common(func);
parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in operator");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "value", NULL, 0, "", "Value of the property to call the operator with");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
#endif
func = RNA_def_function(srna, "label", "rna_uiItemL");
- RNA_def_function_ui_description(func, "Item. Display text and/or icon in the layout");
+ RNA_def_function_ui_description(func, "Item. Displays text and/or icon in the layout");
api_ui_item_common(func);
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");
@@ -627,7 +626,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_string(func, "menu", NULL, 0, "", "Identifier of the menu");
api_ui_item_common(func);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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");
@@ -637,13 +636,14 @@ void RNA_api_ui_layout(StructRNA *srna)
/* context */
func = RNA_def_function(srna, "context_pointer_set", "uiLayoutSetContextPointer");
parm = RNA_def_string(func, "name", NULL, 0, "Name", "Name of entry in the context");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "data", "AnyType", "", "Pointer to put in context");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
/* templates */
func = RNA_def_function(srna, "template_header", "uiTemplateHeader");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Inserts common Space header UI (editor type selector)");
func = RNA_def_function(srna, "template_ID", "uiTemplateID");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
@@ -663,35 +663,59 @@ void RNA_api_ui_layout(StructRNA *srna)
func = RNA_def_function(srna, "template_any_ID", "rna_uiTemplateAnyID");
parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ 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_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "type_property", NULL, 0, "",
"Identifier of property in data giving the type of the ID-blocks to use");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
api_ui_item_common_text(func);
-
+
+ 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_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ 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_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "root", "ID", "", "ID-block from which path is evaluated from");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
api_ui_item_common_text(func);
func = RNA_def_function(srna, "template_modifier", "uiTemplateModifier");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
RNA_def_function_ui_description(func, "Generates the UI layout for modifiers");
parm = RNA_def_pointer(func, "data", "Modifier", "", "Modifier data");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ 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_constraint", "uiTemplateConstraint");
RNA_def_function_ui_description(func, "Generates the UI layout for constraints");
parm = RNA_def_pointer(func, "data", "Constraint", "", "Constraint data");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ 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);
@@ -699,7 +723,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_ui_description(func, "Item. A preview window for materials, textures, lamps or worlds");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "id", "ID", "", "ID data-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "show_buttons", true, "", "Show preview buttons?");
RNA_def_pointer(func, "parent", "ID", "", "ID data-block");
RNA_def_pointer(func, "slot", "TextureSlot", "", "Texture slot");
@@ -741,11 +765,11 @@ void RNA_api_ui_layout(StructRNA *srna)
func = RNA_def_function(srna, "template_layers", "uiTemplateLayers");
api_ui_item_rna_common(func);
parm = RNA_def_pointer(func, "used_layers_data", "AnyType", "", "Data from which to take property");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(func, "used_layers_property", NULL, 0, "", "Identifier of property in data");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "active_layer", 0, 0, INT_MAX, "Active Layer", "", 0, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "template_color_picker", "uiTemplateColorPicker");
RNA_def_function_ui_description(func, "Item. A color wheel widget to pick colors");
@@ -763,34 +787,34 @@ void RNA_api_ui_layout(StructRNA *srna)
func = RNA_def_function(srna, "template_image_layers", "uiTemplateImageLayers");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "image", "Image", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "image_user", "ImageUser", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "template_image", "uiTemplateImage");
RNA_def_function_ui_description(func, "Item(s). User interface for selecting images and their source paths");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
api_ui_item_rna_common(func);
parm = RNA_def_pointer(func, "image_user", "ImageUser", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_boolean(func, "compact", false, "", "Use more compact layout");
RNA_def_boolean(func, "multiview", false, "", "Expose Multi-View options");
func = RNA_def_function(srna, "template_image_settings", "uiTemplateImageSettings");
RNA_def_function_ui_description(func, "User interface for setting image format options");
parm = RNA_def_pointer(func, "image_settings", "ImageFormatSettings", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_boolean(func, "color_management", false, "", "Show color management settings");
func = RNA_def_function(srna, "template_image_stereo_3d", "uiTemplateImageStereo3d");
RNA_def_function_ui_description(func, "User interface for setting image stereo 3d options");
parm = RNA_def_pointer(func, "stereo_3d_format", "Stereo3dFormat", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
func = RNA_def_function(srna, "template_image_views", "uiTemplateImageViews");
RNA_def_function_ui_description(func, "User interface for setting image views output options");
parm = RNA_def_pointer(func, "image_settings", "ImageFormatSettings", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
func = RNA_def_function(srna, "template_movieclip", "uiTemplateMovieClip");
RNA_def_function_ui_description(func, "Item(s). User interface for selecting movie clips and their source paths");
@@ -806,22 +830,22 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_ui_description(func, "Item. A widget to control single marker settings.");
api_ui_item_rna_common(func);
parm = RNA_def_pointer(func, "clip_user", "MovieClipUser", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_pointer(func, "track", "MovieTrackingTrack", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_boolean(func, "compact", false, "", "Use more compact layout");
func = RNA_def_function(srna, "template_movieclip_information", "uiTemplateMovieclipInformation");
RNA_def_function_ui_description(func, "Item. Movie clip information data.");
api_ui_item_rna_common(func);
parm = RNA_def_pointer(func, "clip_user", "MovieClipUser", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
func = RNA_def_function(srna, "template_list", "uiTemplateList");
RNA_def_function_ui_description(func, "Item. A list widget to display data, e.g. vertexgroups.");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_string(func, "listtype_name", NULL, 0, "", "Identifier of the list type to use");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "list_id", NULL, 0, "",
"Identifier of this list widget (mandatory when using default \"" UI_UL_DEFAULT_CLASS_NAME
"\" class). "
@@ -830,15 +854,15 @@ void RNA_api_ui_layout(StructRNA *srna)
"class name is \"OBJECT_UL_vgroups\", and list_id is not set by the "
"script, then bl_idname = \"OBJECT_UL_vgroups\")");
parm = RNA_def_pointer(func, "dataptr", "AnyType", "", "Data from which to take the Collection property");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+ 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");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "active_dataptr", "AnyType", "",
"Data from which to take the integer property, index of the active item");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(func, "active_propname", NULL, 0, "",
"Identifier of the integer property in active_data, index of the active item");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_string(func, "item_dyntip_propname", NULL, 0, "",
"Identifier of a string property in items, to use as tooltip content");
RNA_def_int(func, "rows", 5, 0, INT_MAX, "", "Default and minimum number of rows to display", 0, INT_MAX);
@@ -853,43 +877,56 @@ void RNA_api_ui_layout(StructRNA *srna)
func = RNA_def_function(srna, "template_header_3D", "uiTemplateHeader3D");
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_edit_mode_selection", "uiTemplateEditModeSelection");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Inserts common 3DView Edit modes header UI (selector for selection mode)");
func = RNA_def_function(srna, "template_reports_banner", "uiTemplateReportsBanner");
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_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "node", "Node", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "template_node_view", "uiTemplateNodeView");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "ntree", "NodeTree", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "node", "Node", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "template_texture_user", "uiTemplateTextureUser");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
func = RNA_def_function(srna, "template_keymap_item_properties", "uiTemplateKeymapItemProperties");
parm = RNA_def_pointer(func, "item", "KeyMapItem", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+
+ func = RNA_def_function(srna, "template_override_property", "uiTemplateOverrideProperty");
+ parm = RNA_def_pointer(func, "collection_render_overrides", "AnyType", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ parm = RNA_def_pointer(func, "scene_collection_properties", "AnyType", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in collection_properties");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ api_ui_item_common(func);
+ parm = RNA_def_string(func, "custom_template", NULL, 0, "", "Optional template to use for property");
func = RNA_def_function(srna, "template_component_menu", "uiTemplateComponentMenu");
RNA_def_function_ui_description(func, "Item. Display expanded property in a popup menu");
parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in data");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_string(func, "name", NULL, 0, "", "");
func = RNA_def_function(srna, "introspect", "uiLayoutIntrospect");
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index cbf7bb4d5e0..af77d037b69 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -52,15 +52,6 @@
#include "BLT_lang.h"
#include "GPU_buffers.h"
-#ifdef WITH_CYCLES
-static EnumPropertyItem compute_device_type_items[] = {
- {USER_COMPUTE_DEVICE_NONE, "NONE", 0, "None", "Don't use compute device"},
- {USER_COMPUTE_DEVICE_CUDA, "CUDA", 0, "CUDA", "Use CUDA for GPU acceleration"},
- {USER_COMPUTE_DEVICE_OPENCL, "OPENCL", 0, "OpenCL", "Use OpenCL for GPU acceleration"},
- { 0, NULL, 0, NULL, NULL}
-};
-#endif
-
#ifdef WITH_OPENSUBDIV
static EnumPropertyItem opensubdiv_compute_type_items[] = {
{USER_OPENSUBDIV_COMPUTE_NONE, "NONE", 0, "None", ""},
@@ -83,7 +74,7 @@ static EnumPropertyItem audio_device_items[] = {
{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"},
+ {3, "JACK", 0, "JACK", "JACK Audio Connection Kit, recommended for pro audio users"},
#endif
{0, NULL, 0, NULL, NULL}
};
@@ -107,13 +98,14 @@ static EnumPropertyItem rna_enum_language_default_items[] = {
#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_pbvh.h"
#include "BKE_paint.h"
+#include "DEG_depsgraph.h"
+
#include "GPU_draw.h"
#include "GPU_select.h"
@@ -124,8 +116,6 @@ static EnumPropertyItem rna_enum_language_default_items[] = {
#include "UI_interface.h"
-#include "CCL_api.h"
-
#ifdef WITH_OPENSUBDIV
# include "opensubdiv_capi.h"
#endif
@@ -135,28 +125,24 @@ static EnumPropertyItem rna_enum_language_default_items[] = {
#endif
-static void rna_userdef_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+static void rna_userdef_version_get(PointerRNA *ptr, int *value)
{
- WM_main_add_notifier(NC_WINDOW, NULL);
+ UserDef *userdef = (UserDef *)ptr->data;
+ value[0] = userdef->versionfile / 100;
+ value[1] = userdef->versionfile % 100;
+ value[2] = userdef->subversionfile;
}
-/* also used by buffer swap switching */
-static void rna_userdef_dpi_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+static void rna_userdef_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();
-
- BKE_blender_userdef_refresh();
- WM_main_add_notifier(NC_WINDOW, NULL); /* full redraw */
- WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); /* refresh region sizes */
+ WM_main_add_notifier(NC_WINDOW, NULL);
}
-static void rna_userdef_virtual_pixel_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+/* also used by buffer swap switching */
+static void rna_userdef_dpi_update(Main *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();
-
- BKE_blender_userdef_refresh();
/* force setting drawable again */
wmWindowManager *wm = bmain->wm.first;
@@ -190,10 +176,12 @@ static void rna_userdef_show_manipulator_update(Main *bmain, Scene *scene, Point
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;
+ if (userdef->manipulator_flag & USER_MANIPULATOR_DRAW) {
+ v3d->twflag |= V3D_MANIPULATOR_DRAW;
+ }
+ else {
+ v3d->twflag &= ~V3D_MANIPULATOR_DRAW;
+ }
}
}
}
@@ -292,11 +280,13 @@ static void rna_userdef_autokeymode_set(PointerRNA *ptr, int value)
}
}
+#ifdef WITH_INPUT_NDOF
static void rna_userdef_ndof_deadzone_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
UserDef *userdef = ptr->data;
WM_ndof_deadzone_set(userdef->ndof_deadzone);
}
+#endif
static void rna_userdef_timecode_style_set(PointerRNA *ptr, int value)
{
@@ -376,7 +366,7 @@ static void rna_UserDef_weight_color_update(Main *bmain, Scene *scene, PointerRN
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);
@@ -474,78 +464,6 @@ static PointerRNA rna_Theme_space_list_generic_get(PointerRNA *ptr)
}
-#ifdef WITH_CYCLES
-static EnumPropertyItem *rna_userdef_compute_device_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop), bool *r_free)
-{
- EnumPropertyItem *item = NULL;
- int totitem = 0;
-
- /* add supported device types */
- RNA_enum_items_add_value(&item, &totitem, compute_device_type_items, USER_COMPUTE_DEVICE_NONE);
- if (CCL_compute_device_list(0))
- RNA_enum_items_add_value(&item, &totitem, compute_device_type_items, USER_COMPUTE_DEVICE_CUDA);
- if (CCL_compute_device_list(1))
- RNA_enum_items_add_value(&item, &totitem, compute_device_type_items, USER_COMPUTE_DEVICE_OPENCL);
-
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- return item;
-}
-
-static int rna_userdef_compute_device_get(PointerRNA *UNUSED(ptr))
-{
- if (U.compute_device_type == USER_COMPUTE_DEVICE_NONE)
- return 0;
-
- return U.compute_device_id;
-}
-
-static EnumPropertyItem *rna_userdef_compute_device_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop), bool *r_free)
-{
- EnumPropertyItem tmp = {0, "", 0, "", ""};
- EnumPropertyItem *item = NULL;
- int totitem = 0;
-
- if (U.compute_device_type == USER_COMPUTE_DEVICE_NONE) {
- /* only add a single CPU device */
- tmp.value = 0;
- tmp.name = "CPU";
- tmp.identifier = "CPU";
- RNA_enum_item_add(&item, &totitem, &tmp);
- }
- else {
- /* get device list from cycles. it would be good to make this generic
- * once we have more subsystems using opencl, for now this is easiest */
- int opencl = (U.compute_device_type == USER_COMPUTE_DEVICE_OPENCL);
- CCLDeviceInfo *devices = CCL_compute_device_list(opencl);
- int a;
-
- if (devices) {
- for (a = 0; devices[a].identifier[0]; a++) {
- tmp.value = devices[a].value;
- tmp.identifier = devices[a].identifier;
- tmp.name = devices[a].name;
- RNA_enum_item_add(&item, &totitem, &tmp);
- }
- }
- else {
- tmp.value = 0;
- tmp.name = "CPU";
- tmp.identifier = "CPU";
- RNA_enum_item_add(&item, &totitem, &tmp);
- }
- }
-
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- return item;
-}
-#endif
-
#ifdef WITH_OPENSUBDIV
static EnumPropertyItem *rna_userdef_opensubdiv_compute_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop), bool *r_free)
@@ -587,7 +505,7 @@ static void rna_userdef_opensubdiv_update(Main *bmain, Scene *UNUSED(scene), Poi
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);
}
}
}
@@ -1363,6 +1281,11 @@ static void rna_def_userdef_theme_spaces_vertex(StructRNA *srna)
RNA_def_property_ui_text(prop, "Vertex Size", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "vertex_bevel", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Vertex Bevel", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
prop = RNA_def_property(srna, "vertex_unreferenced", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Vertex Group Unreferenced", "");
@@ -1393,6 +1316,11 @@ static void rna_def_userdef_theme_spaces_edge(StructRNA *srna)
RNA_def_property_ui_text(prop, "Edge Crease", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "edge_bevel", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Edge Bevel", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
prop = RNA_def_property(srna, "edge_facesel", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Edge UV Face Select", "");
@@ -1889,37 +1817,12 @@ static void rna_def_userdef_theme_space_file(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Theme File Browser", "Theme settings for the File Browser");
rna_def_userdef_theme_spaces_main(srna);
- rna_def_userdef_theme_spaces_list_main(srna);
prop = RNA_def_property(srna, "selected_file", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "hilite");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Selected File", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
-
- prop = RNA_def_property(srna, "scrollbar", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "shade1");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Scrollbar", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
- prop = RNA_def_property(srna, "scroll_handle", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "shade2");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Scroll Handle", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
- prop = RNA_def_property(srna, "active_file", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "active");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Active File", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
- prop = RNA_def_property(srna, "active_file_text", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "grid");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Active File Text", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
}
static void rna_def_userdef_theme_space_outliner(BlenderRNA *brna)
@@ -2833,13 +2736,13 @@ static void rna_def_userdef_theme_space_nla(BlenderRNA *brna)
prop = RNA_def_property(srna, "active_action", 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, "Active Action", "Animation data block has active action");
+ RNA_def_property_ui_text(prop, "Active Action", "Animation data-block has active action");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "active_action_unset", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "anim_non_active");
RNA_def_property_array(prop, 4);
- RNA_def_property_ui_text(prop, "No Active Action", "Animation data block doesn't have active action");
+ 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, "strips", PROP_FLOAT, PROP_COLOR_GAMMA);
@@ -3256,6 +3159,7 @@ static void rna_def_userdef_addon_pref(BlenderRNA *brna)
RNA_def_struct_refine_func(srna, "rna_AddonPref_refine");
RNA_def_struct_register_funcs(srna, "rna_AddonPref_register", "rna_AddonPref_unregister", NULL);
RNA_def_struct_idprops_func(srna, "rna_AddonPref_idprops");
+ RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES); /* Mandatory! */
/* registration */
RNA_define_verify_sdna(0);
@@ -3375,7 +3279,7 @@ static void rna_def_userdef_walk_navigation(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_mouse_reverse", PROP_BOOLEAN, PROP_BOOLEAN);
RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_WALK_MOUSE_REVERSE);
- RNA_def_property_ui_text(prop, "Reverse Mouse", "Reverse the mouse look");
+ RNA_def_property_ui_text(prop, "Reverse Mouse", "Reverse the vertical movement of the mouse");
}
static void rna_def_userdef_view(BlenderRNA *brna)
@@ -3413,6 +3317,12 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "View & Controls", "Preferences related to viewing data");
/* View */
+ prop = RNA_def_property(srna, "ui_scale", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_ui_text(prop, "UI Scale", "Changes the size of the fonts and buttons in the interface");
+ RNA_def_property_range(prop, 0.25f, 4.0f);
+ RNA_def_property_ui_range(prop, 0.5f, 2.0f, 1, 2);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
/* display */
prop = RNA_def_property(srna, "show_tooltips", PROP_BOOLEAN, PROP_NONE);
@@ -3428,11 +3338,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");
@@ -3593,30 +3498,25 @@ static void rna_def_userdef_view(BlenderRNA *brna)
/* 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_boolean_sdna(prop, NULL, "manipulator_flag", USER_MANIPULATOR_DRAW);
RNA_def_property_ui_text(prop, "Manipulator", "Use 3D transform manipulator");
RNA_def_property_update(prop, 0, "rna_userdef_show_manipulator_update");
+ /* TODO, expose once it's working. */
+#if 0
+ prop = RNA_def_property(srna, "show_manipulator_shaded", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "manipulator_flag", USER_MANIPULATOR_SHADED);
+ RNA_def_property_ui_text(prop, "Manipulator Shaded", "Use 3D transform manipulator");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+#endif
+
prop = RNA_def_property(srna, "manipulator_size", PROP_INT, PROP_PIXEL);
- RNA_def_property_int_sdna(prop, NULL, "tw_size");
+ RNA_def_property_int_sdna(prop, NULL, "manipulator_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_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);
@@ -3990,13 +3890,6 @@ static void rna_def_userdef_system(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
-#ifdef WITH_CYCLES
- static EnumPropertyItem compute_device_items[] = {
- {0, "CPU", 0, "CPU", ""},
- { 0, NULL, 0, NULL, NULL}
- };
-#endif
-
static EnumPropertyItem image_draw_methods[] = {
{IMAGE_DRAW_METHOD_2DTEXTURE, "2DTEXTURE", 0, "2D Texture", "Use CPU for display transform and draw image with 2D texture"},
{IMAGE_DRAW_METHOD_GLSL, "GLSL", 0, "GLSL", "Use GLSL shaders for display transform and draw image with 2D texture"},
@@ -4011,12 +3904,6 @@ static void rna_def_userdef_system(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
- static EnumPropertyItem virtual_pixel_mode_items[] = {
- {VIRTUAL_PIXEL_NATIVE, "NATIVE", 0, "Native", "Use native pixel size of the display"},
- {VIRTUAL_PIXEL_DOUBLE, "DOUBLE", 0, "Double", "Use double the native pixel size of the display"},
- {0, NULL, 0, NULL, NULL}
- };
-
srna = RNA_def_struct(brna, "UserPreferencesSystem", NULL);
RNA_def_struct_sdna(srna, "UserDef");
RNA_def_struct_nested(brna, srna, "UserPreferences");
@@ -4031,16 +3918,8 @@ static void rna_def_userdef_system(BlenderRNA *brna)
RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_language_update");
prop = RNA_def_property(srna, "dpi", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "dpi");
- RNA_def_property_range(prop, 48, 144);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "DPI", "Font size and resolution for display");
- RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
-
- prop = RNA_def_property(srna, "virtual_pixel_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "virtual_pixel");
- RNA_def_property_enum_items(prop, virtual_pixel_mode_items);
- RNA_def_property_ui_text(prop, "Virtual Pixel Mode", "Modify the pixel size for hi-res devices");
- RNA_def_property_update(prop, 0, "rna_userdef_virtual_pixel_update");
prop = RNA_def_property(srna, "pixel_size", PROP_FLOAT, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -4275,6 +4154,10 @@ static void rna_def_userdef_system(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Selection Method",
"Use OpenGL occlusion queries or selection render mode to accelerate selection");
+ prop = RNA_def_property(srna, "use_select_pick_depth", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gpu_select_pick_deph", 1);
+ RNA_def_property_ui_text(prop, "OpenGL Depth Picking", "Use the depth buffer for picking 3D View selection");
+
/* Full scene anti-aliasing */
prop = RNA_def_property(srna, "multi_sample", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "ogl_multisamples");
@@ -4288,23 +4171,6 @@ 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");
-#ifdef WITH_CYCLES
- prop = RNA_def_property(srna, "compute_device_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
- RNA_def_property_enum_sdna(prop, NULL, "compute_device_type");
- RNA_def_property_enum_items(prop, compute_device_type_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_userdef_compute_device_type_itemf");
- RNA_def_property_ui_text(prop, "Compute Device Type", "Device to use for computation (rendering with Cycles)");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_PROPERTIES, NULL);
-
- prop = RNA_def_property(srna, "compute_device", PROP_ENUM, PROP_NONE);
- RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
- RNA_def_property_enum_sdna(prop, NULL, "compute_device_id");
- RNA_def_property_enum_items(prop, compute_device_items);
- RNA_def_property_enum_funcs(prop, "rna_userdef_compute_device_get", NULL, "rna_userdef_compute_device_itemf");
- RNA_def_property_ui_text(prop, "Compute Device", "Device to use for computation");
-#endif
-
#ifdef WITH_OPENSUBDIV
prop = RNA_def_property(srna, "opensubdiv_compute_type", PROP_ENUM, PROP_NONE);
RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
@@ -4314,6 +4180,14 @@ static void rna_def_userdef_system(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "OpenSubdiv Compute Type", "Type of computer back-end used with OpenSubdiv");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_PROPERTIES, "rna_userdef_opensubdiv_update");
#endif
+
+#ifdef WITH_CYCLES
+ prop = RNA_def_property(srna, "legacy_compute_device_type", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "compute_device_type");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ RNA_def_property_ui_text(prop, "Legacy Compute Device Type", "For backwards compatibility only");
+#endif
}
static void rna_def_userdef_input(BlenderRNA *brna)
@@ -4333,6 +4207,7 @@ static void rna_def_userdef_input(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+#ifdef WITH_INPUT_NDOF
static EnumPropertyItem ndof_view_navigation_items[] = {
{0, "FREE", 0, "Free", "Use full 6 degrees of freedom by default"},
{NDOF_MODE_ORBIT, "ORBIT", 0, "Orbit", "Orbit about the view center by default"},
@@ -4344,6 +4219,7 @@ static void rna_def_userdef_input(BlenderRNA *brna)
{0, "TRACKBALL", 0, "Trackball", "Use trackball style rotation in the viewport"},
{0, NULL, 0, NULL, NULL}
};
+#endif /* WITH_INPUT_NDOF */
static EnumPropertyItem view_zoom_styles[] = {
{USER_ZOOM_CONT, "CONTINUE", 0, "Continue", "Old style zoom, continues while moving mouse up or down"},
@@ -4421,6 +4297,7 @@ 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");
+#ifdef WITH_INPUT_NDOF
/* 3D mouse settings */
/* global options */
prop = RNA_def_property(srna, "ndof_sensitivity", PROP_FLOAT, PROP_NONE);
@@ -4433,7 +4310,7 @@ static void rna_def_userdef_input(BlenderRNA *brna)
prop = RNA_def_property(srna, "ndof_deadzone", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Deadzone", "Deadzone of the 3D Mouse");
+ RNA_def_property_ui_text(prop, "Deadzone", "Threshold of initial movement needed from the device's rest position");
RNA_def_property_update(prop, 0, "rna_userdef_ndof_deadzone_update");
prop = RNA_def_property(srna, "ndof_pan_yz_swap_axis", PROP_BOOLEAN, PROP_NONE);
@@ -4501,6 +4378,13 @@ static void rna_def_userdef_input(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "ndof_flag", NDOF_FLY_HELICOPTER);
RNA_def_property_ui_text(prop, "Helicopter Mode", "Device up/down directly controls your Z position");
+ /* let Python know whether NDOF is enabled */
+ prop = RNA_def_boolean(srna, "use_ndof", true, "", "");
+#else
+ prop = RNA_def_boolean(srna, "use_ndof", false, "", "");
+#endif /* WITH_INPUT_NDOF */
+ RNA_def_property_flag(prop, PROP_IDPROPERTY);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "mouse_double_click_time", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "dbl_click_time");
@@ -4564,7 +4448,7 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_hidden_files_datablocks", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_HIDE_DOT);
- RNA_def_property_ui_text(prop, "Hide Dot Files/Datablocks", "Hide files/data-blocks that start with a dot (.*)");
+ RNA_def_property_ui_text(prop, "Hide Dot Files/Data-Blocks", "Hide files/data-blocks that start with a dot (.*)");
prop = RNA_def_property(srna, "use_filter_files", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_FILTERFILEEXTS);
@@ -4706,8 +4590,8 @@ static void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cpro
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove add-on");
parm = RNA_def_pointer(func, "addon", "Addon", "", "Add-on to remove");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_userdef_autoexec_path_collection(BlenderRNA *brna, PropertyRNA *cprop)
@@ -4732,8 +4616,8 @@ static void rna_def_userdef_autoexec_path_collection(BlenderRNA *brna, PropertyR
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove path");
parm = RNA_def_pointer(func, "pathcmp", "PathCompare", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
void RNA_def_userdef(BlenderRNA *brna)
@@ -4768,6 +4652,11 @@ void RNA_def_userdef(BlenderRNA *brna)
"Active section of the user preferences shown in the user interface");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ /* don't expose this directly via the UI, modify via an operator */
+ prop = RNA_def_property(srna, "app_template", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "app_template");
+ RNA_def_property_ui_text(prop, "Application Template", "");
+
prop = RNA_def_property(srna, "themes", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "themes", NULL);
RNA_def_property_struct_type(prop, "Theme");
@@ -4821,6 +4710,12 @@ void RNA_def_userdef(BlenderRNA *brna)
RNA_def_property_pointer_funcs(prop, "rna_UserDef_system_get", NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "System & OpenGL", "Graphics driver and operating system settings");
+ prop = RNA_def_int_vector(srna, "version", 3, NULL, 0, INT_MAX,
+ "Version", "Version of Blender the userpref.blend was saved with", 0, INT_MAX);
+ RNA_def_property_int_funcs(prop, "rna_userdef_version_get", NULL, NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_THICK_WRAP);
+
rna_def_userdef_view(brna);
rna_def_userdef_edit(brna);
rna_def_userdef_input(brna);
diff --git a/source/blender/makesrna/intern/rna_vfont.c b/source/blender/makesrna/intern/rna_vfont.c
index e9ba0c78439..78d46d35246 100644
--- a/source/blender/makesrna/intern/rna_vfont.c
+++ b/source/blender/makesrna/intern/rna_vfont.c
@@ -38,13 +38,14 @@
#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 */
-static int rna_VectorFont_filepath_editable(PointerRNA *ptr)
+static int rna_VectorFont_filepath_editable(PointerRNA *ptr, const char **UNUSED(r_info))
{
VFont *vfont = ptr->id.data;
if (BKE_vfont_is_builtin(vfont)) {
@@ -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 026d2e209a3..fe30890d5ba 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -167,7 +167,7 @@ static EnumPropertyItem event_ndof_type_items[] = {
{NDOF_BUTTON_C, "NDOF_BUTTON_C", 0, "Button C", ""},
{0, NULL, 0, NULL, NULL}
};
-#endif
+#endif /* RNA_RUNTIME */
/* not returned: CAPSLOCKKEY, UNKNOWNKEY */
EnumPropertyItem rna_enum_event_type_items[] = {
@@ -419,6 +419,7 @@ static EnumPropertyItem keymap_modifiers_items[] = {
static EnumPropertyItem operator_flag_items[] = {
{OPTYPE_REGISTER, "REGISTER", 0, "Register", "Display in the info window and support the redo toolbar panel"},
{OPTYPE_UNDO, "UNDO", 0, "Undo", "Push an undo event (needed for operator redo)"},
+ {OPTYPE_UNDO_GROUPED, "UNDO_GROUPED", 0, "Grouped Undo", "Push a single undo event for repetead instances of this operator"},
{OPTYPE_BLOCKING, "BLOCKING", 0, "Blocking", "Block anything else from using the cursor"},
{OPTYPE_MACRO, "MACRO", 0, "Macro", "Use to check if an operator is a macro"},
{OPTYPE_GRAB_CURSOR, "GRAB_CURSOR", 0, "Grab Pointer",
@@ -460,12 +461,23 @@ EnumPropertyItem rna_enum_wm_report_items[] = {
#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
+
+
static wmOperator *rna_OperatorProperties_find_operator(PointerRNA *ptr)
{
wmWindowManager *wm = ptr->id.data;
@@ -620,39 +632,120 @@ 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_change_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;
+ }
+}
- if (value.data == 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));
+}
+
+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 int 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;
}
}
@@ -938,35 +1031,8 @@ static void rna_wmClipboard_set(PointerRNA *UNUSED(ptr), const char *value)
}
#ifdef WITH_PYTHON
-static void rna_Operator_unregister(struct Main *bmain, StructRNA *type)
-{
- const char *idname;
- wmOperatorType *ot = RNA_struct_blender_type_get(type);
- wmWindowManager *wm;
-
- if (!ot)
- return;
-
- /* update while blender is running */
- wm = bmain->wm.first;
- if (wm) {
- WM_operator_stack_clear(wm);
-
- WM_operator_handlers_clear(wm, ot);
- }
- WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
-
- RNA_struct_free_extension(type, &ot->ext);
- idname = ot->idname;
- WM_operatortype_remove_ptr(ot);
- MEM_freeN((void *)idname);
-
- /* not to be confused with the RNA_struct_free that WM_operatortype_remove calls, they are 2 different srna's */
- RNA_struct_free(&BLENDER_RNA, type);
-}
-
-static int operator_poll(bContext *C, wmOperatorType *ot)
+static int rna_operator_poll_cb(bContext *C, wmOperatorType *ot)
{
extern FunctionRNA rna_Operator_poll_func;
@@ -991,7 +1057,7 @@ static int operator_poll(bContext *C, wmOperatorType *ot)
return visible;
}
-static int operator_execute(bContext *C, wmOperator *op)
+static int rna_operator_execute_cb(bContext *C, wmOperator *op)
{
extern FunctionRNA rna_Operator_execute_func;
@@ -1017,7 +1083,7 @@ static int operator_execute(bContext *C, wmOperator *op)
}
/* same as execute() but no return value */
-static bool operator_check(bContext *C, wmOperator *op)
+static bool rna_operator_check_cb(bContext *C, wmOperator *op)
{
extern FunctionRNA rna_Operator_check_func;
@@ -1042,7 +1108,7 @@ static bool operator_check(bContext *C, wmOperator *op)
return result;
}
-static int operator_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int rna_operator_invoke_cb(bContext *C, wmOperator *op, const wmEvent *event)
{
extern FunctionRNA rna_Operator_invoke_func;
@@ -1069,7 +1135,7 @@ static int operator_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
/* same as invoke */
-static int operator_modal(bContext *C, wmOperator *op, const wmEvent *event)
+static int rna_operator_modal_cb(bContext *C, wmOperator *op, const wmEvent *event)
{
extern FunctionRNA rna_Operator_modal_func;
@@ -1095,7 +1161,7 @@ static int operator_modal(bContext *C, wmOperator *op, const wmEvent *event)
return result;
}
-static void operator_draw(bContext *C, wmOperator *op)
+static void rna_operator_draw_cb(bContext *C, wmOperator *op)
{
extern FunctionRNA rna_Operator_draw_func;
@@ -1114,7 +1180,7 @@ static void operator_draw(bContext *C, wmOperator *op)
}
/* same as exec(), but call cancel */
-static void operator_cancel(bContext *C, wmOperator *op)
+static void rna_operator_cancel_cb(bContext *C, wmOperator *op)
{
extern FunctionRNA rna_Operator_cancel_func;
@@ -1132,33 +1198,42 @@ static void operator_cancel(bContext *C, wmOperator *op)
RNA_parameter_list_free(&list);
}
-void operator_wrapper(wmOperatorType *ot, void *userdata);
-void macro_wrapper(wmOperatorType *ot, void *userdata);
+static void rna_Operator_unregister(struct Main *bmain, StructRNA *type);
-static char _operator_idname[OP_MAX_TYPENAME];
-static char _operator_name[OP_MAX_TYPENAME];
-static char _operator_descr[RNA_DYN_DESCR_MAX];
-static char _operator_ctxt[RNA_DYN_DESCR_MAX];
-static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
- StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+/* bpy_operator_wrap.c */
+extern void BPY_RNA_operator_wrapper(wmOperatorType *ot, void *userdata);
+extern void BPY_RNA_operator_macro_wrapper(wmOperatorType *ot, void *userdata);
+
+static StructRNA *rna_Operator_register(
+ Main *bmain, ReportList *reports, void *data, const char *identifier,
+ StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
{
wmOperatorType dummyot = {NULL};
wmOperator dummyop = {NULL};
PointerRNA dummyotr;
int have_function[7];
+ struct {
+ char idname[OP_MAX_TYPENAME];
+ char name[OP_MAX_TYPENAME];
+ char descr[RNA_DYN_DESCR_MAX];
+ char ctxt[RNA_DYN_DESCR_MAX];
+ char undo_group[OP_MAX_TYPENAME];
+ } temp_buffers;
+
/* setup dummy operator & operator type to store static properties in */
dummyop.type = &dummyot;
- dummyot.idname = _operator_idname; /* only assigne the pointer, string is NULL'd */
- dummyot.name = _operator_name; /* only assigne the pointer, string is NULL'd */
- dummyot.description = _operator_descr; /* only assigne the pointer, string is NULL'd */
- dummyot.translation_context = _operator_ctxt; /* only assigne the pointer, string is NULL'd */
+ dummyot.idname = temp_buffers.idname; /* only assigne the pointer, string is NULL'd */
+ dummyot.name = temp_buffers.name; /* only assigne the pointer, string is NULL'd */
+ dummyot.description = temp_buffers.descr; /* only assigne the pointer, string is NULL'd */
+ dummyot.translation_context = temp_buffers.ctxt; /* only assigne the pointer, string is NULL'd */
+ dummyot.undo_group = temp_buffers.undo_group; /* only assigne the pointer, string is NULL'd */
RNA_pointer_create(NULL, &RNA_Operator, &dummyop, &dummyotr);
/* clear in case they are left unset */
- _operator_idname[0] = _operator_name[0] = _operator_descr[0] = '\0';
+ temp_buffers.idname[0] = temp_buffers.name[0] = temp_buffers.descr[0] = temp_buffers.undo_group[0] = '\0';
/* We have to set default op context! */
- strcpy(_operator_ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
+ strcpy(temp_buffers.ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
/* validate the python class */
if (validate(&dummyotr, data, have_function) != 0)
@@ -1169,7 +1244,7 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *
/* inconveniently long name sanity check */
{
- char *ch = _operator_idname;
+ char *ch = temp_buffers.idname;
int i;
int dot = 0;
for (i = 0; *ch; i++) {
@@ -1182,7 +1257,7 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *
else {
BKE_reportf(reports, RPT_ERROR,
"Registering operator class: '%s', invalid bl_idname '%s', at position %d",
- identifier, _operator_idname, i);
+ identifier, temp_buffers.idname, i);
return NULL;
}
@@ -1191,7 +1266,7 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *
if (i > ((int)sizeof(dummyop.idname)) - 3) {
BKE_reportf(reports, RPT_ERROR, "Registering operator class: '%s', invalid bl_idname '%s', "
- "is too long, maximum length is %d", identifier, _operator_idname,
+ "is too long, maximum length is %d", identifier, temp_buffers.idname,
(int)sizeof(dummyop.idname) - 3);
return NULL;
}
@@ -1199,31 +1274,35 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *
if (dot != 1) {
BKE_reportf(reports, RPT_ERROR,
"Registering operator class: '%s', invalid bl_idname '%s', must contain 1 '.' character",
- identifier, _operator_idname);
+ identifier, temp_buffers.idname);
return NULL;
}
}
/* end sanity check */
{
- int idlen = strlen(_operator_idname) + 4;
- int namelen = strlen(_operator_name) + 1;
- int desclen = strlen(_operator_descr) + 1;
- int ctxtlen = strlen(_operator_ctxt) + 1;
- char *ch;
+ const uint idname_len = strlen(temp_buffers.idname) + 4;
+ const uint name_len = strlen(temp_buffers.name) + 1;
+ const uint desc_len = strlen(temp_buffers.descr) + 1;
+ const uint ctxt_len = strlen(temp_buffers.ctxt) + 1;
+ const uint undo_group_len = strlen(temp_buffers.undo_group) + 1;
/* 2 terminators and 3 to convert a.b -> A_OT_b */
- ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen), "_operator_idname");
- WM_operator_bl_idname(ch, _operator_idname); /* convert the idname from python */
+ char *ch = MEM_mallocN(
+ sizeof(char) * (idname_len + name_len + desc_len + ctxt_len + undo_group_len), __func__);
+ WM_operator_bl_idname(ch, temp_buffers.idname); /* convert the idname from python */
dummyot.idname = ch;
- ch += idlen;
- strcpy(ch, _operator_name);
+ ch += idname_len;
+ memcpy(ch, temp_buffers.name, name_len);
dummyot.name = ch;
- ch += namelen;
- strcpy(ch, _operator_descr);
+ ch += name_len;
+ memcpy(ch, temp_buffers.descr, desc_len);
dummyot.description = ch;
- ch += desclen;
- strcpy(ch, _operator_ctxt);
+ ch += desc_len;
+ memcpy(ch, temp_buffers.ctxt, ctxt_len);
dummyot.translation_context = ch;
+ ch += ctxt_len;
+ memcpy(ch, temp_buffers.undo_group, undo_group_len);
+ dummyot.undo_group = ch;
}
}
@@ -1245,14 +1324,14 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *
dummyot.ext.call = call;
dummyot.ext.free = free;
- dummyot.pyop_poll = (have_function[0]) ? operator_poll : NULL;
- dummyot.exec = (have_function[1]) ? operator_execute : NULL;
- dummyot.check = (have_function[2]) ? operator_check : NULL;
- dummyot.invoke = (have_function[3]) ? operator_invoke : NULL;
- dummyot.modal = (have_function[4]) ? operator_modal : NULL;
- dummyot.ui = (have_function[5]) ? operator_draw : NULL;
- dummyot.cancel = (have_function[6]) ? operator_cancel : NULL;
- WM_operatortype_append_ptr(operator_wrapper, (void *)&dummyot);
+ dummyot.pyop_poll = (have_function[0]) ? rna_operator_poll_cb : NULL;
+ dummyot.exec = (have_function[1]) ? rna_operator_execute_cb : NULL;
+ dummyot.check = (have_function[2]) ? rna_operator_check_cb : NULL;
+ dummyot.invoke = (have_function[3]) ? rna_operator_invoke_cb : NULL;
+ dummyot.modal = (have_function[4]) ? rna_operator_modal_cb : NULL;
+ dummyot.ui = (have_function[5]) ? rna_operator_draw_cb : NULL;
+ dummyot.cancel = (have_function[6]) ? rna_operator_cancel_cb : NULL;
+ WM_operatortype_append_ptr(BPY_RNA_operator_wrapper, (void *)&dummyot);
/* update while blender is running */
WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
@@ -1260,63 +1339,105 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *
return dummyot.ext.srna;
}
+static void rna_Operator_unregister(struct Main *bmain, StructRNA *type)
+{
+ const char *idname;
+ wmOperatorType *ot = RNA_struct_blender_type_get(type);
+ wmWindowManager *wm;
+
+ if (!ot)
+ return;
+
+ /* update while blender is running */
+ wm = bmain->wm.first;
+ if (wm) {
+ WM_operator_stack_clear(wm);
+
+ WM_operator_handlers_clear(wm, ot);
+ }
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
+
+ RNA_struct_free_extension(type, &ot->ext);
+
+ idname = ot->idname;
+ WM_operatortype_remove_ptr(ot);
+ MEM_freeN((void *)idname);
+
+ /* not to be confused with the RNA_struct_free that WM_operatortype_remove calls, they are 2 different srna's */
+ RNA_struct_free(&BLENDER_RNA, type);
+}
+
static void **rna_Operator_instance(PointerRNA *ptr)
{
wmOperator *op = ptr->data;
return &op->py_instance;
}
-static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
- StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+static StructRNA *rna_MacroOperator_register(
+ Main *bmain, ReportList *reports, void *data, const char *identifier,
+ StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
{
wmOperatorType dummyot = {NULL};
wmOperator dummyop = {NULL};
PointerRNA dummyotr;
int have_function[4];
+ struct {
+ char idname[OP_MAX_TYPENAME];
+ char name[OP_MAX_TYPENAME];
+ char descr[RNA_DYN_DESCR_MAX];
+ char ctxt[RNA_DYN_DESCR_MAX];
+ char undo_group[OP_MAX_TYPENAME];
+ } temp_buffers;
+
/* setup dummy operator & operator type to store static properties in */
dummyop.type = &dummyot;
- dummyot.idname = _operator_idname; /* only assigne the pointer, string is NULL'd */
- dummyot.name = _operator_name; /* only assigne the pointer, string is NULL'd */
- dummyot.description = _operator_descr; /* only assigne the pointer, string is NULL'd */
- dummyot.translation_context = _operator_ctxt; /* only assigne the pointer, string is NULL'd */
+ dummyot.idname = temp_buffers.idname; /* only assigne the pointer, string is NULL'd */
+ dummyot.name = temp_buffers.name; /* only assigne the pointer, string is NULL'd */
+ dummyot.description = temp_buffers.descr; /* only assigne the pointer, string is NULL'd */
+ dummyot.translation_context = temp_buffers.ctxt; /* only assigne the pointer, string is NULL'd */
+ dummyot.undo_group = temp_buffers.undo_group; /* only assigne the pointer, string is NULL'd */
RNA_pointer_create(NULL, &RNA_Macro, &dummyop, &dummyotr);
/* clear in case they are left unset */
- _operator_idname[0] = _operator_name[0] = _operator_descr[0] = '\0';
+ temp_buffers.idname[0] = temp_buffers.name[0] = temp_buffers.descr[0] = temp_buffers.undo_group[0] = '\0';
/* We have to set default op context! */
- strcpy(_operator_ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
+ strcpy(temp_buffers.ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
/* validate the python class */
if (validate(&dummyotr, data, have_function) != 0)
return NULL;
+ if (strlen(identifier) >= sizeof(dummyop.idname)) {
+ BKE_reportf(reports, RPT_ERROR, "Registering operator class: '%s' is too long, maximum length is %d",
+ identifier, (int)sizeof(dummyop.idname));
+ return NULL;
+ }
+
{ /* convert foo.bar to FOO_OT_bar
* allocate the description and the idname in 1 go */
- int idlen = strlen(_operator_idname) + 4;
- int namelen = strlen(_operator_name) + 1;
- int desclen = strlen(_operator_descr) + 1;
- int ctxtlen = strlen(_operator_ctxt) + 1;
- char *ch;
+ const uint idname_len = strlen(temp_buffers.idname) + 4;
+ const uint name_len = strlen(temp_buffers.name) + 1;
+ const uint desc_len = strlen(temp_buffers.descr) + 1;
+ const uint ctxt_len = strlen(temp_buffers.ctxt) + 1;
+ const uint undo_group_len = strlen(temp_buffers.undo_group) + 1;
/* 2 terminators and 3 to convert a.b -> A_OT_b */
- ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen), "_operator_idname");
- WM_operator_bl_idname(ch, _operator_idname); /* convert the idname from python */
+ char *ch = MEM_mallocN(
+ sizeof(char) * (idname_len + name_len + desc_len + ctxt_len + undo_group_len), __func__);
+ WM_operator_bl_idname(ch, temp_buffers.idname); /* convert the idname from python */
dummyot.idname = ch;
- ch += idlen;
- strcpy(ch, _operator_name);
+ ch += idname_len;
+ memcpy(ch, temp_buffers.name, name_len);
dummyot.name = ch;
- ch += namelen;
- strcpy(ch, _operator_descr);
+ ch += name_len;
+ memcpy(ch, temp_buffers.descr, desc_len);
dummyot.description = ch;
- ch += desclen;
- strcpy(ch, _operator_ctxt);
+ ch += desc_len;
+ memcpy(ch, temp_buffers.ctxt, ctxt_len);
dummyot.translation_context = ch;
- }
-
- if (strlen(identifier) >= sizeof(dummyop.idname)) {
- BKE_reportf(reports, RPT_ERROR, "Registering operator class: '%s' is too long, maximum length is %d",
- identifier, (int)sizeof(dummyop.idname));
- return NULL;
+ ch += ctxt_len;
+ memcpy(ch, temp_buffers.undo_group, undo_group_len);
+ dummyot.undo_group = ch;
}
/* check if we have registered this operator type before, and remove it */
@@ -1336,10 +1457,10 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, v
dummyot.ext.call = call;
dummyot.ext.free = free;
- dummyot.pyop_poll = (have_function[0]) ? operator_poll : NULL;
- dummyot.ui = (have_function[3]) ? operator_draw : NULL;
+ dummyot.pyop_poll = (have_function[0]) ? rna_operator_poll_cb : NULL;
+ dummyot.ui = (have_function[3]) ? rna_operator_draw_cb : NULL;
- WM_operatortype_append_macro_ptr(macro_wrapper, (void *)&dummyot);
+ WM_operatortype_append_macro_ptr(BPY_RNA_operator_macro_wrapper, (void *)&dummyot);
/* update while blender is running */
WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
@@ -1401,6 +1522,16 @@ static void rna_Operator_bl_description_set(PointerRNA *ptr, const char *value)
assert(!"setting the bl_description on a non-builtin operator");
}
+static void rna_Operator_bl_undo_group_set(PointerRNA *ptr, const char *value)
+{
+ wmOperator *data = (wmOperator *)(ptr->data);
+ char *str = (char *)data->type->undo_group;
+ if (!str[0])
+ BLI_strncpy(str, value, OP_MAX_TYPENAME); /* utf8 already ensured */
+ else
+ assert(!"setting the bl_undo_group on a non-builtin operator");
+}
+
static void rna_KeyMapItem_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
wmKeyMapItem *kmi = ptr->data;
@@ -1509,6 +1640,14 @@ static void rna_def_operator(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_undo_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "type->undo_group");
+ RNA_def_property_string_maxlength(prop, OP_MAX_TYPENAME); /* else it uses the pointer size! */
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_undo_group_set");
+ /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */
+ 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_options", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type->flag");
RNA_def_property_enum_items(prop, operator_flag_items);
@@ -1526,6 +1665,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_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES);
}
static void rna_def_macro_operator(BlenderRNA *brna)
@@ -1587,6 +1727,14 @@ static void rna_def_macro_operator(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_undo_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "type->undo_group");
+ RNA_def_property_string_maxlength(prop, OP_MAX_TYPENAME); /* else it uses the pointer size! */
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_undo_group_set");
+ /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */
+ 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_options", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type->flag");
RNA_def_property_enum_items(prop, operator_flag_items);
@@ -1871,14 +2019,28 @@ static void rna_def_window(BlenderRNA *brna)
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, "x", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "posx");
@@ -1935,15 +2097,15 @@ static void rna_def_wm_keyconfigs(BlenderRNA *brna, PropertyRNA *cprop)
prop = RNA_def_property(srna, "addon", PROP_POINTER, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "addonconf");
RNA_def_property_struct_type(prop, "KeyConfig");
- RNA_def_property_ui_text(prop, "Addon Key Configuration",
- "Key configuration that can be extended by addons, and is added to the active "
+ RNA_def_property_ui_text(prop, "Add-on Key Configuration",
+ "Key configuration that can be extended by add-ons, and is added to the active "
"configuration when handling events");
prop = RNA_def_property(srna, "user", PROP_POINTER, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "userconf");
RNA_def_property_struct_type(prop, "KeyConfig");
RNA_def_property_ui_text(prop, "User Key Configuration",
- "Final key configuration that combines keymaps from the active and addon configurations, "
+ "Final key configuration that combines keymaps from the active and add-on configurations, "
"and can be edited by the user");
RNA_api_keyconfigs(srna);
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index 7cf0cf67269..166b6f96956 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -71,6 +71,8 @@ EnumPropertyItem rna_enum_window_cursor_items[] = {
#include "UI_interface.h"
#include "BKE_context.h"
+#include "WM_types.h"
+
static wmKeyMap *rna_keymap_active(wmKeyMap *km, bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -87,6 +89,11 @@ static void rna_Operator_report(wmOperator *op, int type, const char *msg)
BKE_report(op->reports, type, msg);
}
+static int rna_Operator_is_repeat(wmOperator *op, bContext *C)
+{
+ return WM_operator_is_repeat(C, op);
+}
+
/* since event isn't needed... */
static void rna_Operator_enum_search_invoke(bContext *C, wmOperator *op)
{
@@ -110,6 +117,37 @@ static void rna_event_timer_remove(struct wmWindowManager *wm, wmTimer *timer)
WM_event_remove_timer(wm, timer->win, timer);
}
+
+static wmManipulatorGroupType *wm_manipulatorgrouptype_find_for_add_remove(ReportList *reports, const char *idname)
+{
+ wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(idname, true);
+ if (wgt == NULL) {
+ BKE_reportf(reports, RPT_ERROR, "Manipulator group type '%s' not found!", idname);
+ return NULL;
+ }
+ if (wgt->flag & WM_MANIPULATORGROUPTYPE_PERSISTENT) {
+ BKE_reportf(reports, RPT_ERROR, "Manipulator group '%s' has 'PERSISTENT' option set!", idname);
+ return NULL;
+ }
+ return wgt;
+}
+
+static void rna_manipulator_group_type_add(ReportList *reports, const char *idname)
+{
+ wmManipulatorGroupType *wgt = wm_manipulatorgrouptype_find_for_add_remove(reports, idname);
+ if (wgt != NULL) {
+ WM_manipulator_group_add_ptr(wgt);
+ }
+}
+
+static void rna_manipulator_group_type_remove(Main *bmain, ReportList *reports, const char *idname)
+{
+ wmManipulatorGroupType *wgt = wm_manipulatorgrouptype_find_for_add_remove(reports, idname);
+ if (wgt != NULL) {
+ WM_manipulator_group_remove_ptr(bmain, wgt);
+ }
+}
+
/* placeholder data for final implementation of a true progressbar */
static struct wmStaticProgress {
float min;
@@ -340,11 +378,11 @@ static void rna_generic_op_invoke(FunctionRNA *func, int flag)
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "operator", "Operator", "", "Operator to call");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
if (flag & WM_GEN_INVOKE_EVENT) {
parm = RNA_def_pointer(func, "event", "Event", "", "Event");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
if (flag & WM_GEN_INVOKE_SIZE) {
@@ -365,21 +403,21 @@ void RNA_api_window(StructRNA *srna)
func = RNA_def_function(srna, "cursor_warp", "WM_cursor_warp");
parm = RNA_def_int(func, "x", 0, INT_MIN, INT_MAX, "", "", INT_MIN, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(func, "y", 0, INT_MIN, INT_MAX, "", "", INT_MIN, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_function_ui_description(func, "Set the cursor position");
func = RNA_def_function(srna, "cursor_set", "WM_cursor_set");
parm = RNA_def_property(func, "cursor", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(parm, rna_enum_window_cursor_items);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_function_ui_description(func, "Set the cursor");
func = RNA_def_function(srna, "cursor_modal_set", "WM_cursor_modal_set");
parm = RNA_def_property(func, "cursor", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(parm, rna_enum_window_cursor_items);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_function_ui_description(func, "Set the cursor, so the previous cursor can be restored");
RNA_def_function(srna, "cursor_modal_restore", "WM_cursor_modal_restore");
@@ -398,67 +436,87 @@ void RNA_api_wm(StructRNA *srna)
rna_generic_op_invoke(func, 0);
func = RNA_def_function(srna, "modal_handler_add", "rna_event_modal_handler_add");
+ RNA_def_function_ui_description(func, "Add a modal handler to the window manager, for the given modal operator "
+ "(called by invoke() with self, just before returning {'RUNNING_MODAL'})");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "operator", "Operator", "", "Operator to call");
- RNA_def_property_flag(parm, PROP_REQUIRED);
- RNA_def_function_return(func, RNA_def_boolean(func, "handle", 1, "", ""));
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_function_return(func, RNA_def_boolean(func, "handle", 1, "", "Whether adding the handler was successful"));
func = RNA_def_function(srna, "event_timer_add", "rna_event_timer_add");
+ RNA_def_function_ui_description(func, "Add a timer to the given window, to generate periodic 'TIMER' events");
parm = RNA_def_property(func, "time_step", PROP_FLOAT, PROP_NONE);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_property_range(parm, 0.0, FLT_MAX);
RNA_def_property_ui_text(parm, "Time Step", "Interval in seconds between timer events");
- RNA_def_pointer(func, "window", "Window", "", "Window to attach the timer to or None");
+ RNA_def_pointer(func, "window", "Window", "", "Window to attach the timer to, or None");
parm = RNA_def_pointer(func, "result", "Timer", "", "");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "event_timer_remove", "rna_event_timer_remove");
parm = RNA_def_pointer(func, "timer", "Timer", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
+ func = RNA_def_function(srna, "manipulator_group_type_add", "rna_manipulator_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, "", "Manipulator group type name");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+ func = RNA_def_function(srna, "manipulator_group_type_remove", "rna_manipulator_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, "", "Manipulator 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");
-
parm = RNA_def_property(func, "min", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(parm, "min", "any value in range [0,9999]");
- RNA_def_property_flag(parm, PROP_REQUIRED);
-
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_property(func, "max", PROP_FLOAT, PROP_NONE);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_property_ui_text(parm, "max", "any value in range [min+1,9998]");
func = RNA_def_function(srna, "progress_update", "rna_progress_update");
+ RNA_def_function_ui_description(func, "Update the progress feedback");
parm = RNA_def_property(func, "value", PROP_FLOAT, PROP_NONE);
- RNA_def_property_flag(parm, PROP_REQUIRED);
- RNA_def_property_ui_text(parm, "value", "any value between min and max as set in progress_begin()");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_property_ui_text(parm, "value", "Any value between min and max as set in progress_begin()");
func = RNA_def_function(srna, "progress_end", "rna_progress_end");
RNA_def_function_ui_description(func, "Terminate progress report");
/* invoke functions, for use with python */
func = RNA_def_function(srna, "invoke_props_popup", "rna_Operator_props_popup");
- RNA_def_function_ui_description(func, "Operator popup invoke");
+ RNA_def_function_ui_description(func, "Operator popup invoke "
+ "(show operator properties and execute it automatically on changes)");
rna_generic_op_invoke(func, WM_GEN_INVOKE_EVENT | WM_GEN_INVOKE_RETURN);
/* invoked dialog opens popup with OK button, does not auto-exec operator. */
func = RNA_def_function(srna, "invoke_props_dialog", "WM_operator_props_dialog_popup");
- RNA_def_function_ui_description(func, "Operator dialog (non-autoexec popup) invoke");
+ RNA_def_function_ui_description(func, "Operator dialog (non-autoexec popup) invoke "
+ "(show operator properties and only execute it on click on OK button)");
rna_generic_op_invoke(func, WM_GEN_INVOKE_SIZE | WM_GEN_INVOKE_RETURN);
/* invoke enum */
func = RNA_def_function(srna, "invoke_search_popup", "rna_Operator_enum_search_invoke");
+ RNA_def_function_ui_description(func, "Operator search popup invoke (search in values of "
+ "operator's type 'prop' EnumProperty, and execute it on confirmation)");
rna_generic_op_invoke(func, 0);
/* invoke functions, for use with python */
func = RNA_def_function(srna, "invoke_popup", "WM_operator_ui_popup");
- RNA_def_function_ui_description(func, "Operator popup invoke");
+ RNA_def_function_ui_description(func, "Operator popup invoke "
+ "(only shows operator's properties, without executing it)");
rna_generic_op_invoke(func, WM_GEN_INVOKE_SIZE | WM_GEN_INVOKE_RETURN);
func = RNA_def_function(srna, "invoke_confirm", "rna_Operator_confirm");
- RNA_def_function_ui_description(func, "Operator confirmation");
+ RNA_def_function_ui_description(func, "Operator confirmation popup "
+ "(only to let user confirm the execution, no operator properties shown)");
rna_generic_op_invoke(func, WM_GEN_INVOKE_EVENT | WM_GEN_INVOKE_RETURN);
@@ -466,39 +524,39 @@ void RNA_api_wm(StructRNA *srna)
func = RNA_def_function(srna, "pupmenu_begin__internal", "rna_PupMenuBegin");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
parm = RNA_def_string(func, "title", NULL, 0, "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_property(func, "icon", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(parm, rna_enum_icon_items);
/* return */
parm = RNA_def_pointer(func, "menu", "UIPopupMenu", "", "");
- RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_RNAPTR);
RNA_def_function_return(func, parm);
/* wrap UI_popup_menu_end */
func = RNA_def_function(srna, "pupmenu_end__internal", "rna_PupMenuEnd");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "menu", "UIPopupMenu", "", "");
- RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_RNAPTR);
/* wrap uiPieMenuBegin */
func = RNA_def_function(srna, "piemenu_begin__internal", "rna_PieMenuBegin");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
parm = RNA_def_string(func, "title", NULL, 0, "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_property(func, "icon", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(parm, rna_enum_icon_items);
parm = RNA_def_pointer(func, "event", "Event", "", "");
- RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_RNAPTR);
/* return */
parm = RNA_def_pointer(func, "menu_pie", "UIPieMenu", "", "");
- RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_RNAPTR);
RNA_def_function_return(func, parm);
/* wrap uiPieMenuEnd */
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_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_RNAPTR);
}
void RNA_api_operator(StructRNA *srna)
@@ -509,10 +567,16 @@ void RNA_api_operator(StructRNA *srna)
/* utility, not for registering */
func = RNA_def_function(srna, "report", "rna_Operator_report");
parm = RNA_def_enum_flag(func, "type", rna_enum_wm_report_items, 0, "Type", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "message", NULL, 0, "Report Message", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* utility, not for registering */
+ func = RNA_def_function(srna, "is_repeat", "rna_Operator_is_repeat");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ /* return */
+ parm = RNA_def_boolean(func, "result", 0, "result", "");
+ RNA_def_function_return(func, parm);
/* Registration */
@@ -522,14 +586,14 @@ void RNA_api_operator(StructRNA *srna)
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_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* exec */
func = RNA_def_function(srna, "execute", NULL);
RNA_def_function_ui_description(func, "Execute the operator");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* better name? */
parm = RNA_def_enum_flag(func, "result", rna_enum_operator_return_items, OPERATOR_CANCELLED, "result", "");
@@ -540,7 +604,7 @@ void RNA_api_operator(StructRNA *srna)
RNA_def_function_ui_description(func, "Check the operator settings, return True to signal a change to redraw");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_boolean(func, "result", 0, "result", ""); /* better name? */
RNA_def_function_return(func, parm);
@@ -550,9 +614,9 @@ void RNA_api_operator(StructRNA *srna)
RNA_def_function_ui_description(func, "Invoke the operator");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_pointer(func, "event", "Event", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* better name? */
parm = RNA_def_enum_flag(func, "result", rna_enum_operator_return_items, OPERATOR_CANCELLED, "result", "");
@@ -562,9 +626,9 @@ void RNA_api_operator(StructRNA *srna)
RNA_def_function_ui_description(func, "Modal operator function");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_pointer(func, "event", "Event", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* better name? */
parm = RNA_def_enum_flag(func, "result", rna_enum_operator_return_items, OPERATOR_CANCELLED, "result", "");
@@ -575,14 +639,14 @@ void RNA_api_operator(StructRNA *srna)
RNA_def_function_ui_description(func, "Draw function for the operator");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* cancel */
func = RNA_def_function(srna, "cancel", NULL);
RNA_def_function_ui_description(func, "Called when the operator is canceled");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
}
void RNA_api_macro(StructRNA *srna)
@@ -593,9 +657,9 @@ void RNA_api_macro(StructRNA *srna)
/* utility, not for registering */
func = RNA_def_function(srna, "report", "rna_Operator_report");
parm = RNA_def_enum_flag(func, "type", rna_enum_wm_report_items, 0, "Type", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "message", NULL, 0, "Report Message", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* Registration */
@@ -606,14 +670,14 @@ void RNA_api_macro(StructRNA *srna)
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_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* draw */
func = RNA_def_function(srna, "draw", NULL);
RNA_def_function_ui_description(func, "Draw function for the operator");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
parm = RNA_def_pointer(func, "context", "Context", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
}
void RNA_api_keyconfig(StructRNA *UNUSED(srna))
@@ -638,7 +702,7 @@ void RNA_api_keymap(StructRNA *srna)
func = RNA_def_function(srna, "restore_item_to_default", "rna_keymap_restore_item_to_default");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
}
void RNA_api_keymapitem(StructRNA *srna)
@@ -648,7 +712,7 @@ void RNA_api_keymapitem(StructRNA *srna)
func = RNA_def_function(srna, "compare", "WM_keymap_item_compare");
parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_boolean(func, "result", 0, "Comparison result", "");
RNA_def_function_return(func, parm);
}
@@ -661,11 +725,11 @@ void RNA_api_keymapitems(StructRNA *srna)
func = RNA_def_function(srna, "new", "rna_KeyMap_item_new");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "idname", NULL, 0, "Operator Identifier", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "type", rna_enum_event_type_items, 0, "Type", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "value", rna_enum_event_value_items, 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "any", 0, "Any", "");
RNA_def_boolean(func, "shift", 0, "Shift", "");
RNA_def_boolean(func, "ctrl", 0, "Ctrl", "");
@@ -681,11 +745,11 @@ void RNA_api_keymapitems(StructRNA *srna)
func = RNA_def_function(srna, "new_modal", "rna_KeyMap_item_new_modal");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "propvalue", NULL, 0, "Property Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "type", rna_enum_event_type_items, 0, "Type", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_enum(func, "value", rna_enum_event_value_items, 0, "Value", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "any", 0, "Any", "");
RNA_def_boolean(func, "shift", 0, "Shift", "");
RNA_def_boolean(func, "ctrl", 0, "Ctrl", "");
@@ -698,12 +762,12 @@ void RNA_api_keymapitems(StructRNA *srna)
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", "");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ 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, "from_id", "WM_keymap_item_find_id");
parm = RNA_def_property(func, "id", PROP_INT, PROP_NONE);
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_property_ui_text(parm, "id", "ID of the item");
parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", "");
RNA_def_function_return(func, parm);
@@ -716,7 +780,7 @@ void RNA_api_keymaps(StructRNA *srna)
func = RNA_def_function(srna, "new", "rna_keymap_new"); /* add_keymap */
parm = RNA_def_string(func, "name", NULL, 0, "Name", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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", "");
@@ -726,12 +790,12 @@ void RNA_api_keymaps(StructRNA *srna)
func = RNA_def_function(srna, "remove", "rna_KeyMap_remove"); /* remove_keymap */
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "Removed key map");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ 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, "find", "rna_keymap_find"); /* find_keymap */
parm = RNA_def_string(func, "name", NULL, 0, "Name", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ 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", "");
parm = RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "Corresponding key map");
@@ -739,7 +803,7 @@ void RNA_api_keymaps(StructRNA *srna)
func = RNA_def_function(srna, "find_modal", "rna_keymap_find_modal"); /* find_keymap_modal */
parm = RNA_def_string(func, "name", NULL, 0, "Operator Name", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "Corresponding key map");
RNA_def_function_return(func, parm);
}
@@ -751,15 +815,15 @@ void RNA_api_keyconfigs(StructRNA *srna)
func = RNA_def_function(srna, "new", "WM_keyconfig_new_user"); /* add_keyconfig */
parm = RNA_def_string(func, "name", NULL, 0, "Name", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "keyconfig", "KeyConfig", "Key Configuration", "Added key configuration");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_KeyConfig_remove"); /* remove_keyconfig */
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "keyconfig", "KeyConfig", "Key Configuration", "Removed key configuration");
- RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
- RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_wm_manipulator.c b/source/blender/makesrna/intern/rna_wm_manipulator.c
new file mode 100644
index 00000000000..030f1a1628c
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_wm_manipulator.c
@@ -0,0 +1,1234 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_manipulator.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 "BLT_translation.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"
+
+#ifdef RNA_RUNTIME
+/* enum definitions */
+#endif /* RNA_RUNTIME */
+
+#ifdef RNA_RUNTIME
+
+#include <assert.h>
+
+#include "WM_api.h"
+#include "WM_types.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 "BKE_utildefines.h"
+
+#include "MEM_guardedalloc.h"
+
+#ifdef WITH_PYTHON
+# include "BPY_extern.h"
+#endif
+
+/* -------------------------------------------------------------------- */
+
+/** \name Manipulator API
+ * \{ */
+
+static void rna_manipulator_draw_cb(
+ const struct bContext *C, struct wmManipulator *mpr)
+{
+ extern FunctionRNA rna_Manipulator_draw_func;
+ wmManipulatorGroup *mgroup = mpr->parent_mgroup;
+ PointerRNA mpr_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr);
+ /* RNA_struct_find_function(&mpr_ptr, "draw"); */
+ func = &rna_Manipulator_draw_func;
+ RNA_parameter_list_create(&list, &mpr_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ mgroup->type->ext.call((bContext *)C, &mpr_ptr, func, &list);
+ RNA_parameter_list_free(&list);
+}
+
+static void rna_manipulator_draw_select_cb(
+ const struct bContext *C, struct wmManipulator *mpr, int select_id)
+{
+ extern FunctionRNA rna_Manipulator_draw_select_func;
+ wmManipulatorGroup *mgroup = mpr->parent_mgroup;
+ PointerRNA mpr_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr);
+ /* RNA_struct_find_function(&mpr_ptr, "draw_select"); */
+ func = &rna_Manipulator_draw_select_func;
+ RNA_parameter_list_create(&list, &mpr_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ RNA_parameter_set_lookup(&list, "select_id", &select_id);
+ mgroup->type->ext.call((bContext *)C, &mpr_ptr, func, &list);
+ RNA_parameter_list_free(&list);
+}
+
+static int rna_manipulator_test_select_cb(
+ struct bContext *C, struct wmManipulator *mpr, const struct wmEvent *event)
+{
+ extern FunctionRNA rna_Manipulator_test_select_func;
+ wmManipulatorGroup *mgroup = mpr->parent_mgroup;
+ PointerRNA mpr_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr);
+ /* RNA_struct_find_function(&mpr_ptr, "test_select"); */
+ func = &rna_Manipulator_test_select_func;
+ RNA_parameter_list_create(&list, &mpr_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ RNA_parameter_set_lookup(&list, "event", &event);
+ mgroup->type->ext.call((bContext *)C, &mpr_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 void rna_manipulator_modal_cb(
+ struct bContext *C, struct wmManipulator *mpr, const struct wmEvent *event, int tweak)
+{
+ extern FunctionRNA rna_Manipulator_modal_func;
+ wmManipulatorGroup *mgroup = mpr->parent_mgroup;
+ PointerRNA mpr_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr);
+ /* RNA_struct_find_function(&mpr_ptr, "modal"); */
+ func = &rna_Manipulator_modal_func;
+ RNA_parameter_list_create(&list, &mpr_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ RNA_parameter_set_lookup(&list, "event", &event);
+ RNA_parameter_set_lookup(&list, "tweak", &tweak);
+ mgroup->type->ext.call((bContext *)C, &mpr_ptr, func, &list);
+ RNA_parameter_list_free(&list);
+}
+
+static void rna_manipulator_setup_cb(
+ struct wmManipulator *mpr)
+{
+ extern FunctionRNA rna_Manipulator_setup_func;
+ wmManipulatorGroup *mgroup = mpr->parent_mgroup;
+ PointerRNA mpr_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr);
+ /* RNA_struct_find_function(&mpr_ptr, "setup"); */
+ func = &rna_Manipulator_setup_func;
+ RNA_parameter_list_create(&list, &mpr_ptr, func);
+ mgroup->type->ext.call((bContext *)NULL, &mpr_ptr, func, &list);
+ RNA_parameter_list_free(&list);
+}
+
+
+static void rna_manipulator_invoke_cb(
+ struct bContext *C, struct wmManipulator *mpr, const struct wmEvent *event)
+{
+ extern FunctionRNA rna_Manipulator_invoke_func;
+ wmManipulatorGroup *mgroup = mpr->parent_mgroup;
+ PointerRNA mpr_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr);
+ /* RNA_struct_find_function(&mpr_ptr, "invoke"); */
+ func = &rna_Manipulator_invoke_func;
+ RNA_parameter_list_create(&list, &mpr_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ RNA_parameter_set_lookup(&list, "event", &event);
+ mgroup->type->ext.call((bContext *)C, &mpr_ptr, func, &list);
+ RNA_parameter_list_free(&list);
+}
+
+static void rna_manipulator_exit_cb(
+ struct bContext *C, struct wmManipulator *mpr, bool cancel)
+{
+ extern FunctionRNA rna_Manipulator_exit_func;
+ wmManipulatorGroup *mgroup = mpr->parent_mgroup;
+ PointerRNA mpr_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr);
+ /* RNA_struct_find_function(&mpr_ptr, "exit"); */
+ func = &rna_Manipulator_exit_func;
+ RNA_parameter_list_create(&list, &mpr_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ {
+ int cancel_i = cancel;
+ RNA_parameter_set_lookup(&list, "cancel", &cancel_i);
+ }
+ mgroup->type->ext.call((bContext *)C, &mpr_ptr, func, &list);
+ RNA_parameter_list_free(&list);
+}
+
+static void rna_manipulator_select_cb(
+ struct bContext *C, struct wmManipulator *mpr, int action)
+{
+ extern FunctionRNA rna_Manipulator_select_func;
+ wmManipulatorGroup *mgroup = mpr->parent_mgroup;
+ PointerRNA mpr_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr);
+ /* RNA_struct_find_function(&mpr_ptr, "select"); */
+ func = &rna_Manipulator_select_func;
+ RNA_parameter_list_create(&list, &mpr_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ RNA_parameter_set_lookup(&list, "action", &action);
+ mgroup->type->ext.call((bContext *)C, &mpr_ptr, func, &list);
+ RNA_parameter_list_free(&list);
+}
+
+/* just to work around 'const char *' warning and to ensure this is a python op */
+static void rna_Manipulator_bl_idname_set(PointerRNA *ptr, const char *value)
+{
+ wmManipulator *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 wmManipulator *rna_ManipulatorProperties_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->manipulator_map) {
+ wmManipulatorMap *mmap = ar->manipulator_map;
+ for (wmManipulatorGroup *mgroup = WM_manipulatormap_group_list(mmap)->first;
+ mgroup;
+ mgroup = mgroup->next)
+ {
+ for (wmManipulator *mpr = mgroup->manipulators.first; mpr; mpr = mpr->next) {
+ if (mpr->properties == properties) {
+ return mpr;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+static StructRNA *rna_ManipulatorProperties_refine(PointerRNA *ptr)
+{
+ wmManipulator *mpr = rna_ManipulatorProperties_find_operator(ptr);
+
+ if (mpr)
+ return mpr->type->srna;
+ else
+ return ptr->type;
+}
+
+static IDProperty *rna_ManipulatorProperties_idprops(PointerRNA *ptr, bool create)
+{
+ if (create && !ptr->data) {
+ IDPropertyTemplate val = {0};
+ ptr->data = IDP_New(IDP_GROUP, &val, "RNA_ManipulatorProperties group");
+ }
+
+ return ptr->data;
+}
+
+static PointerRNA rna_Manipulator_properties_get(PointerRNA *ptr)
+{
+ wmManipulator *mpr = ptr->data;
+ return rna_pointer_inherit_refine(ptr, mpr->type->srna, mpr->properties);
+}
+
+/* wmManipulator.float */
+#define RNA_MANIPULATOR_GENERIC_FLOAT_RW_DEF(func_id, member_id) \
+static float rna_Manipulator_##func_id##_get(PointerRNA *ptr) \
+{ \
+ wmManipulator *mpr = ptr->data; \
+ return mpr->member_id; \
+} \
+static void rna_Manipulator_##func_id##_set(PointerRNA *ptr, float value) \
+{ \
+ wmManipulator *mpr = ptr->data; \
+ mpr->member_id = value; \
+}
+/* wmManipulator.float[len] */
+#define RNA_MANIPULATOR_GENERIC_FLOAT_ARRAY_RW_DEF(func_id, member_id, len) \
+static void rna_Manipulator_##func_id##_get(PointerRNA *ptr, float value[len]) \
+{ \
+ wmManipulator *mpr = ptr->data; \
+ memcpy(value, mpr->member_id, sizeof(float[len])); \
+} \
+static void rna_Manipulator_##func_id##_set(PointerRNA *ptr, const float value[len]) \
+{ \
+ wmManipulator *mpr = ptr->data; \
+ memcpy(mpr->member_id, value, sizeof(float[len])); \
+}
+
+/* wmManipulator.flag */
+#define RNA_MANIPULATOR_GENERIC_FLAG_RW_DEF(func_id, member_id, flag_value) \
+static int rna_Manipulator_##func_id##_get(PointerRNA *ptr) \
+{ \
+ wmManipulator *mpr = ptr->data; \
+ return (mpr->member_id & flag_value) != 0; \
+} \
+static void rna_Manipulator_##func_id##_set(PointerRNA *ptr, int value) \
+{ \
+ wmManipulator *mpr = ptr->data; \
+ BKE_BIT_TEST_SET(mpr->member_id, value, flag_value); \
+}
+
+#define RNA_MANIPULATOR_FLAG_RO_DEF(func_id, member_id, flag_value) \
+static int rna_Manipulator_##func_id##_get(PointerRNA *ptr) \
+{ \
+ wmManipulator *mpr = ptr->data; \
+ return (mpr->member_id & flag_value) != 0; \
+}
+
+RNA_MANIPULATOR_GENERIC_FLOAT_ARRAY_RW_DEF(color, color, 4);
+RNA_MANIPULATOR_GENERIC_FLOAT_ARRAY_RW_DEF(color_hi, color_hi, 4);
+
+RNA_MANIPULATOR_GENERIC_FLOAT_ARRAY_RW_DEF(matrix_basis, matrix_basis, 16);
+RNA_MANIPULATOR_GENERIC_FLOAT_ARRAY_RW_DEF(matrix_offset, matrix_offset, 16);
+
+RNA_MANIPULATOR_GENERIC_FLOAT_RW_DEF(scale_basis, scale_basis);
+RNA_MANIPULATOR_GENERIC_FLOAT_RW_DEF(line_width, line_width);
+
+RNA_MANIPULATOR_GENERIC_FLAG_RW_DEF(flag_use_draw_hover, flag, WM_MANIPULATOR_DRAW_HOVER);
+RNA_MANIPULATOR_GENERIC_FLAG_RW_DEF(flag_use_draw_active, flag, WM_MANIPULATOR_DRAW_ACTIVE);
+RNA_MANIPULATOR_GENERIC_FLAG_RW_DEF(flag_use_draw_value, flag, WM_MANIPULATOR_DRAW_VALUE);
+RNA_MANIPULATOR_GENERIC_FLAG_RW_DEF(flag_hide, flag, WM_MANIPULATOR_HIDDEN);
+
+/* wmManipulator.state */
+RNA_MANIPULATOR_FLAG_RO_DEF(state_is_highlight, state, WM_MANIPULATOR_STATE_HIGHLIGHT);
+RNA_MANIPULATOR_FLAG_RO_DEF(state_is_active, state, WM_MANIPULATOR_STATE_ACTIVE);
+RNA_MANIPULATOR_FLAG_RO_DEF(state_select, state, WM_MANIPULATOR_STATE_SELECT);
+
+static void rna_Manipulator_name_get(PointerRNA *ptr, char *value)
+{
+ wmManipulator *mpr = ptr->data;
+ strcpy(value, mpr->name);
+}
+
+static void rna_Manipulator_name_set(PointerRNA *ptr, const char *value)
+{
+ wmManipulator *mpr = ptr->data;
+ WM_manipulator_name_set(mpr->parent_mgroup, mpr, value);
+}
+
+static int rna_Manipulator_name_length(PointerRNA *ptr)
+{
+ wmManipulator *mpr = ptr->data;
+ return strlen(mpr->name);
+}
+
+#ifdef WITH_PYTHON
+
+static void rna_Manipulator_unregister(struct Main *bmain, StructRNA *type);
+void BPY_RNA_manipulator_wrapper(wmManipulatorType *wgt, void *userdata);
+
+static StructRNA *rna_Manipulator_register(
+ Main *bmain, ReportList *reports, void *data, const char *identifier,
+ StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+{
+ struct {
+ char idname[MAX_NAME];
+ } temp_buffers;
+
+ wmManipulatorType dummywt = {NULL};
+ wmManipulator dummymnp = {NULL};
+ PointerRNA mnp_ptr;
+
+ /* Two sets of functions. */
+ int have_function[8];
+
+ /* setup dummy manipulator & manipulator type to store static properties in */
+ dummymnp.type = &dummywt;
+ dummywt.idname = temp_buffers.idname;
+ RNA_pointer_create(NULL, &RNA_Manipulator, &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 manipulator class: '%s' is too long, maximum length is %d",
+ identifier, (int)sizeof(temp_buffers.idname));
+ return NULL;
+ }
+
+ /* check if we have registered this manipulator type before, and remove it */
+ {
+ const wmManipulatorType *wt = WM_manipulatortype_find(dummywt.idname, true);
+ if (wt && wt->ext.srna) {
+ rna_Manipulator_unregister(bmain, wt->ext.srna);
+ }
+ }
+
+ /* create a new manipulator type */
+ dummywt.ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummywt.idname, &RNA_Manipulator);
+ /* manipulator properties are registered separately */
+ RNA_def_struct_flag(dummywt.ext.srna, STRUCT_NO_IDPROPERTIES);
+ dummywt.ext.data = data;
+ dummywt.ext.call = call;
+ dummywt.ext.free = free;
+
+ {
+ int i = 0;
+ dummywt.draw = (have_function[i++]) ? rna_manipulator_draw_cb : NULL;
+ dummywt.draw_select = (have_function[i++]) ? rna_manipulator_draw_select_cb : NULL;
+ dummywt.test_select = (have_function[i++]) ? rna_manipulator_test_select_cb : NULL;
+ dummywt.modal = (have_function[i++]) ? rna_manipulator_modal_cb : NULL;
+// dummywt.property_update = (have_function[i++]) ? rna_manipulator_property_update : NULL;
+// dummywt.position_get = (have_function[i++]) ? rna_manipulator_position_get : NULL;
+ dummywt.setup = (have_function[i++]) ? rna_manipulator_setup_cb : NULL;
+ dummywt.invoke = (have_function[i++]) ? rna_manipulator_invoke_cb : NULL;
+ dummywt.exit = (have_function[i++]) ? rna_manipulator_exit_cb : NULL;
+ dummywt.select = (have_function[i++]) ? rna_manipulator_select_cb : NULL;
+
+ BLI_assert(i == ARRAY_SIZE(have_function));
+ }
+
+ RNA_def_struct_duplicate_pointers(dummywt.ext.srna);
+
+ /* use duplicated string */
+ dummywt.idname = dummywt.ext.srna->identifier;
+
+ WM_manipulatortype_append_ptr(BPY_RNA_manipulator_wrapper, (void *)&dummywt);
+
+ /* update while blender is running */
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
+
+ return dummywt.ext.srna;
+}
+
+static void rna_Manipulator_unregister(struct Main *UNUSED(bmain), StructRNA *type)
+{
+ wmManipulatorType *wt = RNA_struct_blender_type_get(type);
+
+ /* TODO, remove widgets from interface! */
+
+ if (!wt)
+ return;
+
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
+
+ RNA_struct_free_extension(type, &wt->ext);
+
+ WM_manipulatortype_remove_ptr(wt);
+
+ RNA_struct_free(&BLENDER_RNA, type);
+}
+
+static void **rna_Manipulator_instance(PointerRNA *ptr)
+{
+ wmManipulator *mpr = ptr->data;
+ return &mpr->py_instance;
+}
+
+#endif /* WITH_PYTHON */
+
+
+static StructRNA *rna_Manipulator_refine(PointerRNA *mnp_ptr)
+{
+ wmManipulator *mpr = mnp_ptr->data;
+ return (mpr->type && mpr->type->ext.srna) ? mpr->type->ext.srna : &RNA_Manipulator;
+}
+
+/** \} */
+
+/** \name Manipulator Group API
+ * \{ */
+
+static wmManipulator *rna_ManipulatorGroup_manipulator_new(
+ wmManipulatorGroup *mgroup, ReportList *reports, const char *idname, const char *name)
+{
+ const wmManipulatorType *wt = WM_manipulatortype_find(idname, true);
+ if (wt == NULL) {
+ BKE_reportf(reports, RPT_ERROR, "ManipulatorType '%s' not known", idname);
+ return NULL;
+ }
+ wmManipulator *mpr = WM_manipulator_new_ptr(wt, mgroup, name, NULL);
+ return mpr;
+}
+
+static void rna_ManipulatorGroup_manipulator_remove(
+ wmManipulatorGroup *mgroup, bContext *C, wmManipulator *mpr)
+{
+ WM_manipulator_free(&mgroup->manipulators, mgroup->parent_mmap, mpr, C);
+}
+
+static void rna_ManipulatorGroup_manipulator_clear(
+ wmManipulatorGroup *mgroup, bContext *C)
+{
+ while (mgroup->manipulators.first) {
+ WM_manipulator_free(&mgroup->manipulators, mgroup->parent_mmap, mgroup->manipulators.first, C);
+ }
+}
+
+static void rna_ManipulatorGroup_name_get(PointerRNA *ptr, char *value)
+{
+ wmManipulatorGroup *mgroup = ptr->data;
+ strcpy(value, mgroup->type->name);
+}
+
+static int rna_ManipulatorGroup_name_length(PointerRNA *ptr)
+{
+ wmManipulatorGroup *mgroup = ptr->data;
+ return strlen(mgroup->type->name);
+}
+
+/* just to work around 'const char *' warning and to ensure this is a python op */
+static void rna_ManipulatorGroup_bl_idname_set(PointerRNA *ptr, const char *value)
+{
+ wmManipulatorGroup *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_ManipulatorGroup_bl_label_set(PointerRNA *ptr, const char *value)
+{
+ wmManipulatorGroup *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 int rna_ManipulatorGroup_has_reports_get(PointerRNA *ptr)
+{
+ wmManipulatorGroup *mgroup = ptr->data;
+ return (mgroup->reports && mgroup->reports->list.first);
+}
+
+#ifdef WITH_PYTHON
+
+static bool rna_manipulatorgroup_poll_cb(const bContext *C, wmManipulatorGroupType *wgt)
+{
+
+ extern FunctionRNA rna_ManipulatorGroup_poll_func;
+
+ PointerRNA ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ void *ret;
+ int visible;
+
+ RNA_pointer_create(NULL, wgt->ext.srna, NULL, &ptr); /* dummy */
+ func = &rna_ManipulatorGroup_poll_func; /* RNA_struct_find_function(&ptr, "poll"); */
+
+ RNA_parameter_list_create(&list, &ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ wgt->ext.call((bContext *)C, &ptr, func, &list);
+
+ RNA_parameter_get_lookup(&list, "visible", &ret);
+ visible = *(int *)ret;
+
+ RNA_parameter_list_free(&list);
+
+ return visible;
+}
+
+static void rna_manipulatorgroup_setup_cb(const bContext *C, wmManipulatorGroup *mgroup)
+{
+ extern FunctionRNA rna_ManipulatorGroup_setup_func;
+
+ PointerRNA mgroup_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+
+ RNA_pointer_create(NULL, mgroup->type->ext.srna, mgroup, &mgroup_ptr);
+ func = &rna_ManipulatorGroup_setup_func; /* RNA_struct_find_function(&wgroupr, "setup"); */
+
+ RNA_parameter_list_create(&list, &mgroup_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ mgroup->type->ext.call((bContext *)C, &mgroup_ptr, func, &list);
+
+ RNA_parameter_list_free(&list);
+}
+
+static wmKeyMap *rna_manipulatorgroup_setup_keymap_cb(const wmManipulatorGroupType *wgt, wmKeyConfig *config)
+{
+ extern FunctionRNA rna_ManipulatorGroup_setup_keymap_func;
+ const char *wgroupname = wgt->name;
+ void *ret;
+
+ PointerRNA ptr;
+ ParameterList list;
+ FunctionRNA *func;
+
+ RNA_pointer_create(NULL, wgt->ext.srna, NULL, &ptr); /* dummy */
+ func = &rna_ManipulatorGroup_setup_keymap_func; /* RNA_struct_find_function(&wgroupr, "setup_keymap"); */
+
+ RNA_parameter_list_create(&list, &ptr, func);
+ RNA_parameter_set_lookup(&list, "keyconfig", &config);
+ RNA_parameter_set_lookup(&list, "manipulator_group", &wgroupname);
+ wgt->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_manipulatorgroup_refresh_cb(const bContext *C, wmManipulatorGroup *mgroup)
+{
+ extern FunctionRNA rna_ManipulatorGroup_refresh_func;
+
+ PointerRNA mgroup_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+
+ RNA_pointer_create(NULL, mgroup->type->ext.srna, mgroup, &mgroup_ptr);
+ func = &rna_ManipulatorGroup_refresh_func; /* RNA_struct_find_function(&wgroupr, "refresh"); */
+
+ RNA_parameter_list_create(&list, &mgroup_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ mgroup->type->ext.call((bContext *)C, &mgroup_ptr, func, &list);
+
+ RNA_parameter_list_free(&list);
+}
+
+static void rna_manipulatorgroup_draw_prepare_cb(const bContext *C, wmManipulatorGroup *mgroup)
+{
+ extern FunctionRNA rna_ManipulatorGroup_draw_prepare_func;
+
+ PointerRNA mgroup_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+
+ RNA_pointer_create(NULL, mgroup->type->ext.srna, mgroup, &mgroup_ptr);
+ func = &rna_ManipulatorGroup_draw_prepare_func; /* RNA_struct_find_function(&wgroupr, "draw_prepare"); */
+
+ RNA_parameter_list_create(&list, &mgroup_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ mgroup->type->ext.call((bContext *)C, &mgroup_ptr, func, &list);
+
+ RNA_parameter_list_free(&list);
+}
+
+void BPY_RNA_manipulatorgroup_wrapper(wmManipulatorGroupType *wgt, void *userdata);
+
+static StructRNA *rna_ManipulatorGroup_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;
+
+ wmManipulatorGroupType dummywgt = {NULL};
+ wmManipulatorGroup dummywg = {NULL};
+ PointerRNA wgptr;
+
+ /* Two sets of functions. */
+ int have_function[5];
+
+ /* setup dummy manipulatorgroup & manipulatorgroup type to store static properties in */
+ dummywg.type = &dummywgt;
+ dummywgt.name = temp_buffers.name;
+ dummywgt.idname = temp_buffers.idname;
+
+ RNA_pointer_create(NULL, &RNA_ManipulatorGroup, &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 manipulatorgroup 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 wmManipulatorMapType_Params wmap_params = {
+ .spaceid = dummywgt.mmap_params.spaceid,
+ .regionid = dummywgt.mmap_params.regionid,
+ };
+
+ wmManipulatorMapType *mmap_type = WM_manipulatormaptype_ensure(&wmap_params);
+ if (mmap_type == NULL) {
+ BKE_reportf(reports, RPT_ERROR, "Area type does not support manipulators");
+ return NULL;
+ }
+
+ /* check if we have registered this manipulatorgroup type before, and remove it */
+ {
+ wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(dummywgt.idname, true);
+ if (wgt && wgt->ext.srna) {
+ WM_manipulatormaptype_group_unlink(NULL, bmain, mmap_type, wgt);
+ WM_manipulatorgrouptype_remove_ptr(wgt);
+
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
+ }
+ }
+
+ /* create a new manipulatorgroup type */
+ dummywgt.ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummywgt.idname, &RNA_ManipulatorGroup);
+ RNA_def_struct_flag(dummywgt.ext.srna, STRUCT_NO_IDPROPERTIES); /* manipulatorgroup 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_manipulatorgroup_poll_cb : NULL;
+ dummywgt.setup_keymap = (have_function[1]) ? rna_manipulatorgroup_setup_keymap_cb : NULL;
+ dummywgt.setup = (have_function[2]) ? rna_manipulatorgroup_setup_cb : NULL;
+ dummywgt.refresh = (have_function[3]) ? rna_manipulatorgroup_refresh_cb : NULL;
+ dummywgt.draw_prepare = (have_function[4]) ? rna_manipulatorgroup_draw_prepare_cb : NULL;
+
+ RNA_def_struct_duplicate_pointers(dummywgt.ext.srna);
+ dummywgt.idname = dummywgt.ext.srna->identifier;
+ dummywgt.name = dummywgt.ext.srna->name;
+
+ wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_append_ptr(
+ BPY_RNA_manipulatorgroup_wrapper, (void *)&dummywgt);
+
+ if (wgt->flag & WM_MANIPULATORGROUPTYPE_PERSISTENT) {
+ WM_manipulator_group_add_ptr_ex(wgt, mmap_type);
+
+ /* update while blender is running */
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
+ }
+
+ return dummywgt.ext.srna;
+}
+
+static void rna_ManipulatorGroup_unregister(struct Main *bmain, StructRNA *type)
+{
+ wmManipulatorGroupType *wgt = RNA_struct_blender_type_get(type);
+
+ if (!wgt)
+ return;
+
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
+
+ RNA_struct_free_extension(type, &wgt->ext);
+
+ WM_manipulator_group_remove_ptr(bmain, wgt);
+
+ RNA_struct_free(&BLENDER_RNA, type);
+}
+
+static void **rna_ManipulatorGroup_instance(PointerRNA *ptr)
+{
+ wmManipulatorGroup *mgroup = ptr->data;
+ return &mgroup->py_instance;
+}
+
+#endif /* WITH_PYTHON */
+
+static StructRNA *rna_ManipulatorGroup_refine(PointerRNA *mgroup_ptr)
+{
+ wmManipulatorGroup *mgroup = mgroup_ptr->data;
+ return (mgroup->type && mgroup->type->ext.srna) ? mgroup->type->ext.srna : &RNA_ManipulatorGroup;
+}
+
+static void rna_ManipulatorGroup_manipulators_begin(CollectionPropertyIterator *iter, PointerRNA *mgroup_ptr)
+{
+ wmManipulatorGroup *mgroup = mgroup_ptr->data;
+ rna_iterator_listbase_begin(iter, &mgroup->manipulators, NULL);
+}
+
+/** \} */
+
+
+#else /* RNA_RUNTIME */
+
+
+/* ManipulatorGroup.manipulators */
+static void rna_def_manipulators(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "Manipulators");
+ srna = RNA_def_struct(brna, "Manipulators", NULL);
+ RNA_def_struct_sdna(srna, "wmManipulatorGroup");
+ RNA_def_struct_ui_text(srna, "Manipulators", "Collection of manipulators");
+
+ func = RNA_def_function(srna, "new", "rna_ManipulatorGroup_manipulator_new");
+ RNA_def_function_ui_description(func, "Add manipulator");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_string(func, "type", "Type", 0, "", "Manipulator identifier"); /* optional */
+ RNA_def_string(func, "name", "Name", 0, "", "Manipulator name"); /* optional */
+ parm = RNA_def_pointer(func, "manipulator", "Manipulator", "", "New manipulator");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_ManipulatorGroup_manipulator_remove");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Delete manipulator");
+ parm = RNA_def_pointer(func, "manipulator", "Manipulator", "", "New manipulator");
+ 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_ManipulatorGroup_manipulator_clear");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Delete all manipulators");
+}
+
+
+static void rna_def_manipulator(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "Manipulator");
+ srna = RNA_def_struct(brna, "Manipulator", NULL);
+ RNA_def_struct_sdna(srna, "wmManipulator");
+ RNA_def_struct_ui_text(srna, "Manipulator", "Collection of manipulators");
+ RNA_def_struct_refine_func(srna, "rna_Manipulator_refine");
+
+#ifdef WITH_PYTHON
+ RNA_def_struct_register_funcs(
+ srna,
+ "rna_Manipulator_register",
+ "rna_Manipulator_unregister",
+ "rna_Manipulator_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, "ManipulatorProperties");
+ RNA_def_property_ui_text(prop, "Properties", "");
+ RNA_def_property_pointer_funcs(prop, "rna_Manipulator_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_Manipulator_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 */
+
+ /* wmManipulator.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);
+
+ /* wmManipulator.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);
+
+ /* wmManipulator.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_pointer(func, "event", "Event", "", "");
+ 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);
+
+ /* wmManipulator.handler */
+ static EnumPropertyItem tweak_actions[] = {
+ {WM_MANIPULATOR_TWEAK_PRECISE, "PRECISE", 0, "Precise", ""},
+ {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);
+ 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(func, "tweak", tweak_actions, 0, "Tweak", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_property_flag(parm, PROP_ENUM_FLAG);
+
+ /* wmManipulator.property_update */
+ /* TODO */
+
+ /* wmManipulator.setup */
+ func = RNA_def_function(srna, "setup", NULL);
+ RNA_def_function_ui_description(func, "");
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
+
+ /* wmManipulator.invoke */
+ func = RNA_def_function(srna, "invoke", 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_pointer(func, "event", "Event", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
+ /* wmManipulator.exit */
+ func = RNA_def_function(srna, "exit", 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_boolean(func, "cancel", 0, "Cancel, otherwise confirm", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+ /* wmManipulator.cursor_get */
+ /* TODO */
+
+ /* wmManipulator.select */
+ /* TODO, de-duplicate! */
+ static EnumPropertyItem select_actions[] = {
+ {SEL_TOGGLE, "TOGGLE", 0, "Toggle", "Toggle selection for all elements"},
+ {SEL_SELECT, "SELECT", 0, "Select", "Select all elements"},
+ {SEL_DESELECT, "DESELECT", 0, "Deselect", "Deselect all elements"},
+ {SEL_INVERT, "INVERT", 0, "Invert", "Invert selection of all elements"},
+ {0, NULL, 0, NULL, NULL}
+ };
+ func = RNA_def_function(srna, "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_enum(func, "action", select_actions, 0, "Action", "Selection action to execute");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+
+ /* -------------------------------------------------------------------- */
+ /* Instance Variables */
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(
+ prop, "rna_Manipulator_name_get", "rna_Manipulator_name_length", "rna_Manipulator_name_set");
+ RNA_def_property_ui_text(prop, "Name", "");
+ RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
+
+ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_float_funcs(prop, "rna_Manipulator_color_get", "rna_Manipulator_color_set", NULL);
+
+ prop = RNA_def_property(srna, "color_highlight", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_float_funcs(prop, "rna_Manipulator_color_hi_get", "rna_Manipulator_color_hi_set", NULL);
+ RNA_def_property_ui_text(prop, "Color", "");
+
+ 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_Manipulator_matrix_basis_get", "rna_Manipulator_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_Manipulator_matrix_offset_get", "rna_Manipulator_matrix_offset_set", NULL);
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+
+ prop = RNA_def_property(srna, "scale_basis", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_ui_text(prop, "Scale Basis", "");
+ RNA_def_property_float_funcs(prop, "rna_Manipulator_scale_basis_get", "rna_Manipulator_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_MATRIX);
+ RNA_def_property_ui_text(prop, "Line Width", "");
+ RNA_def_property_float_funcs(prop, "rna_Manipulator_line_width_get", "rna_Manipulator_line_width_set", NULL);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+
+ /* wmManipulator.flag */
+ /* WM_MANIPULATOR_HIDDEN */
+ prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Manipulator_flag_hide_get", "rna_Manipulator_flag_hide_set");
+ RNA_def_property_ui_text(prop, "Hide", "");
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+ /* WM_MANIPULATOR_DRAW_HOVER */
+ prop = RNA_def_property(srna, "use_draw_hover", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Manipulator_flag_use_draw_hover_get", "rna_Manipulator_flag_use_draw_hover_set");
+ RNA_def_property_ui_text(prop, "Draw Hover", "");
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+ /* WM_MANIPULATOR_DRAW_ACTIVE */
+ prop = RNA_def_property(srna, "use_draw_active", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Manipulator_flag_use_draw_active_get", "rna_Manipulator_flag_use_draw_active_set");
+ RNA_def_property_ui_text(prop, "Draw Active", "Draw while dragging");
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+ /* WM_MANIPULATOR_DRAW_VALUE */
+ prop = RNA_def_property(srna, "use_draw_value", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Manipulator_flag_use_draw_value_get", "rna_Manipulator_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);
+
+ /* wmManipulator.state (readonly) */
+ /* WM_MANIPULATOR_STATE_HIGHLIGHT */
+ prop = RNA_def_property(srna, "is_highlight", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_Manipulator_state_is_highlight_get", NULL);
+ RNA_def_property_ui_text(prop, "Highlight", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ /* WM_MANIPULATOR_STATE_ACTIVE */
+ prop = RNA_def_property(srna, "is_active", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_Manipulator_state_is_active_get", NULL);
+ RNA_def_property_ui_text(prop, "Highlight", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ /* WM_MANIPULATOR_STATE_SELECT */
+ prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_Manipulator_state_select_get", NULL);
+ RNA_def_property_ui_text(prop, "Select", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ RNA_api_manipulator(srna);
+
+ srna = RNA_def_struct(brna, "ManipulatorProperties", NULL);
+ RNA_def_struct_ui_text(srna, "Manipulator Properties", "Input properties of an Manipulator");
+ RNA_def_struct_refine_func(srna, "rna_ManipulatorProperties_refine");
+ RNA_def_struct_idprops_func(srna, "rna_ManipulatorProperties_idprops");
+ RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES);
+}
+
+static void rna_def_manipulatorgroup(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ srna = RNA_def_struct(brna, "ManipulatorGroup", NULL);
+ RNA_def_struct_ui_text(srna, "ManipulatorGroup", "Storage of an operator being executed, or registered after execution");
+ RNA_def_struct_sdna(srna, "wmManipulatorGroup");
+ RNA_def_struct_refine_func(srna, "rna_ManipulatorGroup_refine");
+#ifdef WITH_PYTHON
+ RNA_def_struct_register_funcs(
+ srna,
+ "rna_ManipulatorGroup_register",
+ "rna_ManipulatorGroup_unregister",
+ "rna_ManipulatorGroup_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_ManipulatorGroup_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_ManipulatorGroup_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->mmap_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->mmap_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");
+
+ /* bl_options */
+ static EnumPropertyItem manipulatorgroup_flag_items[] = {
+ {WM_MANIPULATORGROUPTYPE_3D, "3D", 0, "3D",
+ "Use in 3D viewport"},
+ {WM_MANIPULATORGROUPTYPE_SCALE, "SCALE", 0, "Scale",
+ "Scale to respect zoom (otherwise zoom independent draw size)"},
+ {WM_MANIPULATORGROUPTYPE_DEPTH_3D, "DEPTH_3D", 0, "Depth 3D",
+ "Supports culled depth by other objects in the view"},
+ {WM_MANIPULATORGROUPTYPE_SELECT, "SELECT", 0, "Select",
+ "Supports selection"},
+ {WM_MANIPULATORGROUPTYPE_PERSISTENT, "PERSISTENT", 0, "Persistent",
+ ""},
+ {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, manipulatorgroup_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 manipulator 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);
+
+ /* keymap_init */
+ func = RNA_def_function(srna, "setup_keymap", NULL);
+ RNA_def_function_ui_description(
+ func,
+ "Initialize keymaps for this manipulator group, use fallback keymap when not present");
+ RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL);
+ parm = RNA_def_pointer(func, "keyconf", "KeyConfig", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_property(func, "manipulator_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(parm, "Manipulator Group", "Manipulator Group ID");
+ // RNA_def_property_string_default(parm, "");
+ RNA_def_parameter_flags(parm, 0, 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 manipulators function for the manipulator 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);
+
+ /* -------------------------------------------------------------------- */
+ /* 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_ManipulatorGroup_name_get", "rna_ManipulatorGroup_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_ManipulatorGroup_has_reports_get", NULL);
+ RNA_def_property_ui_text(prop, "Has Reports",
+ "ManipulatorGroup has a set of reports (warnings and errors) from last execution");
+
+
+ RNA_define_verify_sdna(0); /* not in sdna */
+
+ prop = RNA_def_property(srna, "manipulators", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "manipulators", NULL);
+ RNA_def_property_struct_type(prop, "Manipulator");
+ RNA_def_property_collection_funcs(
+ prop, "rna_ManipulatorGroup_manipulators_begin", "rna_iterator_listbase_next",
+ "rna_iterator_listbase_end", "rna_iterator_listbase_get",
+ NULL, NULL, NULL, NULL);
+
+ RNA_def_property_ui_text(prop, "Manipulators", "List of manipulators in the Manipulator Map");
+ rna_def_manipulator(brna, prop);
+ rna_def_manipulators(brna, prop);
+
+ RNA_define_verify_sdna(1); /* not in sdna */
+
+ RNA_api_manipulatorgroup(srna);
+}
+
+void RNA_def_wm_manipulator(BlenderRNA *brna)
+{
+ rna_def_manipulatorgroup(brna);
+}
+
+#endif /* RNA_RUNTIME */
diff --git a/source/blender/makesrna/intern/rna_wm_manipulator_api.c b/source/blender/makesrna/intern/rna_wm_manipulator_api.c
new file mode 100644
index 00000000000..9f011ad7b7d
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_wm_manipulator_api.c
@@ -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 blender/makesrna/intern/rna_wm_manipulator_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_manipulator_library.h"
+
+static void rna_manipulator_draw_preset_box(
+ wmManipulator *mpr, float matrix[16], int select_id)
+{
+ ED_manipulator_draw_preset_box(mpr, (float (*)[4])matrix, select_id);
+}
+
+static void rna_manipulator_draw_preset_arrow(
+ wmManipulator *mpr, float matrix[16], int axis, int select_id)
+{
+ ED_manipulator_draw_preset_arrow(mpr, (float (*)[4])matrix, axis, select_id);
+}
+
+static void rna_manipulator_draw_preset_circle(
+ wmManipulator *mpr, float matrix[16], int axis, int select_id)
+{
+ ED_manipulator_draw_preset_circle(mpr, (float (*)[4])matrix, axis, select_id);
+}
+
+static void rna_manipulator_draw_preset_facemap(
+ wmManipulator *mpr, struct bContext *C, struct Object *ob, int facemap, int select_id)
+{
+ struct Scene *scene = CTX_data_scene(C);
+ ED_manipulator_draw_preset_facemap(mpr, scene, ob, facemap, select_id);
+}
+
+static void rna_manipulator_target_set_prop(
+ wmManipulator *mpr, ReportList *reports, const char *target_propname,
+ PointerRNA *ptr, const char *propname, int index)
+{
+ const wmManipulatorPropertyType *mpr_prop_type =
+ WM_manipulatortype_target_property_find(mpr->type, target_propname);
+ if (mpr_prop_type == NULL) {
+ BKE_reportf(reports, RPT_ERROR, "Manipulator target property '%s.%s' not found",
+ mpr->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 (mpr_prop_type->data_type != RNA_property_type(prop)) {
+ const int manipulator_type_index = RNA_enum_from_value(rna_enum_property_type_items, mpr_prop_type->data_type);
+ const int prop_type_index = RNA_enum_from_value(rna_enum_property_type_items, RNA_property_type(prop));
+ BLI_assert((manipulator_type_index != -1) && (prop_type_index == -1));
+
+ BKE_reportf(reports, RPT_ERROR, "Manipulator target '%s.%s' expects '%s', '%s.%s' is '%s'",
+ mpr->type->idname, target_propname,
+ rna_enum_property_type_items[manipulator_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 (mpr_prop_type->array_length != prop_array_length) {
+ BKE_reportf(reports, RPT_ERROR,
+ "Manipulator target property '%s.%s' expects an array of length %d, found %d",
+ mpr->type->idname, target_propname,
+ mpr_prop_type->array_length,
+ prop_array_length);
+ return;
+ }
+ }
+ }
+ else {
+ if (mpr_prop_type->array_length != 1) {
+ BKE_reportf(reports, RPT_ERROR,
+ "Manipulator target property '%s.%s' expects an array of length %d",
+ mpr->type->idname, target_propname,
+ mpr_prop_type->array_length);
+ return;
+ }
+ }
+
+ if (index >= mpr_prop_type->array_length) {
+ BKE_reportf(reports, RPT_ERROR, "Manipulator target property '%s.%s', index %d must be below %d",
+ mpr->type->idname, target_propname, index, mpr_prop_type->array_length);
+ return;
+ }
+
+ WM_manipulator_target_property_def_rna_ptr(mpr, mpr_prop_type, ptr, prop, index);
+}
+
+static PointerRNA rna_manipulator_target_set_operator(
+ wmManipulator *mpr, ReportList *reports, const char *opname)
+{
+ 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, "wmManipulatorProperties");
+ }
+
+ WM_manipulator_set_operator(mpr, ot, properties);
+
+ return mpr->op_data.ptr;
+}
+
+#else
+
+void RNA_api_manipulator(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_manipulator_draw_preset_box");
+ RNA_def_function_ui_description(func, "Draw a box");
+ parm = RNA_def_property(func, "matrix", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_flag(parm, 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_manipulator_draw_preset_arrow");
+ RNA_def_function_ui_description(func, "Draw a box");
+ parm = RNA_def_property(func, "matrix", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_flag(parm, 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_manipulator_draw_preset_circle");
+ RNA_def_function_ui_description(func, "Draw a box");
+ parm = RNA_def_property(func, "matrix", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_flag(parm, 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_manipulator_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);
+ RNA_def_int(func, "facemap", 0, 0, INT_MAX, "Face map index", "", 0, INT_MAX);
+ RNA_def_int(func, "select_id", -1, -1, INT_MAX, "Zero when not selecting", "", -1, INT_MAX);
+
+
+ /* -------------------------------------------------------------------- */
+ /* Property API */
+
+ /* note, 'target_set_handler' is defined in 'bpy_rna_manipulator.c' */
+ func = RNA_def_function(srna, "target_set_prop", "rna_manipulator_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_manipulator_target_set_operator");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(
+ func,"Operator to run when activating the manipulator "
+ "(overrides property targets)");
+ parm = RNA_def_string(func, "operator", NULL, 0, "", "Target operator");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* 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);
+
+}
+
+
+void RNA_api_manipulatorgroup(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..c09cc204bbc
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_workspace.c
@@ -0,0 +1,183 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "WM_api.h"
+#include "WM_types.h"
+
+#include "rna_internal.h"
+
+
+#ifdef RNA_RUNTIME
+
+#include "BKE_global.h"
+
+#include "BLI_listbase.h"
+
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_workspace_types.h"
+
+#include "RNA_access.h"
+
+
+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);
+}
+
+#ifdef USE_WORKSPACE_MODE
+
+static int rna_workspace_object_mode_get(PointerRNA *ptr)
+{
+ WorkSpace *workspace = ptr->data;
+ return (int)BKE_workspace_object_mode_get(workspace);
+}
+
+static void rna_workspace_object_mode_set(PointerRNA *ptr, int value)
+{
+ WorkSpace *workspace = ptr->data;
+ BKE_workspace_object_mode_set(workspace, value);
+}
+
+#endif /* USE_WORKSPACE_MODE */
+
+void rna_workspace_transform_orientations_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ WorkSpace *workspace = ptr->id.data;
+ rna_iterator_listbase_begin(iter, BKE_workspace_transform_orientations_get(workspace), NULL);
+}
+
+static PointerRNA rna_workspace_transform_orientations_item_get(CollectionPropertyIterator *iter)
+{
+ TransformOrientation *transform_orientation = rna_iterator_listbase_get(iter);
+ return rna_pointer_inherit_refine(&iter->parent, &RNA_TransformOrientation, transform_orientation);
+}
+
+static PointerRNA rna_workspace_render_layer_get(PointerRNA *ptr)
+{
+ WorkSpace *workspace = ptr->data;
+ SceneLayer *render_layer = BKE_workspace_render_layer_get(workspace);
+
+ /* XXX hmrf... lookup in getter... but how could we avoid it? */
+ for (Scene *scene = G.main->scene.first; scene; scene = scene->id.next) {
+ if (BLI_findindex(&scene->render_layers, render_layer) != -1) {
+ PointerRNA scene_ptr;
+
+ RNA_id_pointer_create(&scene->id, &scene_ptr);
+ return rna_pointer_inherit_refine(&scene_ptr, &RNA_SceneLayer, render_layer);
+ }
+ }
+
+ return PointerRNA_NULL;
+}
+
+static void rna_workspace_render_layer_set(PointerRNA *ptr, PointerRNA value)
+{
+ WorkSpace *workspace = ptr->data;
+ BKE_workspace_render_layer_set(workspace, value.data);
+}
+
+#else /* RNA_RUNTIME */
+
+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_RENDER_RESULT);
+
+ 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");
+
+#ifdef USE_WORKSPACE_MODE
+ prop = RNA_def_property(srna, "object_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_object_mode_items);
+ RNA_def_property_enum_funcs(prop, "rna_workspace_object_mode_get", "rna_workspace_object_mode_set", NULL);
+ RNA_def_property_ui_text(prop, "Mode", "Object interaction mode");
+#endif
+
+ prop = RNA_def_property(srna, "orientations", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "transform_orientations", NULL);
+ RNA_def_property_struct_type(prop, "TransformOrientation");
+ RNA_def_property_collection_funcs(prop, "rna_workspace_transform_orientations_begin", NULL, NULL,
+ "rna_workspace_transform_orientations_item_get", NULL, NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Transform Orientations", "");
+
+ prop = RNA_def_property(srna, "render_layer", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "SceneLayer");
+ RNA_def_property_pointer_funcs(prop, "rna_workspace_render_layer_get", "rna_workspace_render_layer_set",
+ NULL, NULL);
+ RNA_def_property_ui_text(prop, "Active Render Layer", "The active render layer used in this workspace");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_NULL);
+ RNA_def_property_update(prop, NC_SCREEN | ND_LAYER, NULL);
+}
+
+static void rna_def_transform_orientation(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "TransformOrientation", NULL);
+
+ 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_3x3);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_ui_text(prop, "Name", "Name of the custom transform orientation");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+}
+
+void RNA_def_workspace(BlenderRNA *brna)
+{
+ rna_def_workspace(brna);
+ rna_def_transform_orientation(brna);
+}
+
+#endif /* RNA_RUNTIME */
diff --git a/source/blender/makesrna/intern/rna_world.c b/source/blender/makesrna/intern/rna_world.c
index 7c1ef6b0d87..8e3e5b67a76 100644
--- a/source/blender/makesrna/intern/rna_world.c
+++ b/source/blender/makesrna/intern/rna_world.c
@@ -43,10 +43,11 @@
#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"
@@ -88,7 +89,7 @@ static void rna_World_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerR
{
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 +98,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 +107,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);
}
@@ -119,6 +120,7 @@ static void rna_World_use_nodes_update(bContext *C, PointerRNA *ptr)
ED_node_shader_default(C, &wrld->id);
rna_World_update(CTX_data_main(C), CTX_data_scene(C), ptr);
+ rna_World_draw_update(CTX_data_main(C), CTX_data_scene(C), ptr);
}
#else
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index b8ebb375a48..d6a7b94505f 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -93,6 +93,7 @@ set(SRC
intern/MOD_solidify.c
intern/MOD_subsurf.c
intern/MOD_surface.c
+ intern/MOD_surfacedeform.c
intern/MOD_triangulate.c
intern/MOD_util.c
intern/MOD_uvwarp.c
@@ -157,4 +158,7 @@ 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 4c881445893..bf121af2bd1 100644
--- a/source/blender/modifiers/MOD_modifiertypes.h
+++ b/source/blender/modifiers/MOD_modifiertypes.h
@@ -85,6 +85,7 @@ extern ModifierTypeInfo modifierType_DataTransfer;
extern ModifierTypeInfo modifierType_NormalEdit;
extern ModifierTypeInfo modifierType_CorrectiveSmooth;
extern ModifierTypeInfo modifierType_MeshSequenceCache;
+extern ModifierTypeInfo modifierType_SurfaceDeform;
/* 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 567505ea45d..8f26077ea82 100644
--- a/source/blender/modifiers/intern/MOD_armature.c
+++ b/source/blender/modifiers/intern/MOD_armature.c
@@ -50,8 +50,6 @@
#include "MEM_guardedalloc.h"
-#include "depsgraph_private.h"
-
#include "MOD_util.h"
@@ -96,23 +94,7 @@ static void foreachObjectLink(
{
ArmatureModifierData *amd = (ArmatureModifierData *) md;
- walk(userData, ob, &amd->object, IDWALK_NOP);
-}
-
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- DagNode *obNode)
-{
- ArmatureModifierData *amd = (ArmatureModifierData *) md;
-
- if (amd->object) {
- DagNode *curNode = dag_get_node(forest, amd->object);
-
- dag_add_relation(forest, curNode, obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Armature Modifier");
- }
+ walk(userData, ob, &amd->object, IDWALK_CB_NOP);
}
static void updateDepsgraph(ModifierData *md,
@@ -221,7 +203,6 @@ ModifierTypeInfo modifierType_Armature = {
/* 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 ecbc3891e8c..57f90fb4b51 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -50,10 +50,11 @@
#include "BKE_curve.h"
#include "BKE_library_query.h"
#include "BKE_modifier.h"
+#include "BKE_mesh.h"
#include "MOD_util.h"
-#include "depsgraph_private.h"
+#include "DEG_depsgraph.h"
/* Due to cyclic dependencies it's possible that curve used for
* deformation here is not evaluated at the time of evaluating
@@ -95,87 +96,35 @@ static void foreachObjectLink(
{
ArrayModifierData *amd = (ArrayModifierData *) md;
- walk(userData, ob, &amd->start_cap, IDWALK_NOP);
- walk(userData, ob, &amd->end_cap, IDWALK_NOP);
- walk(userData, ob, &amd->curve_ob, IDWALK_NOP);
- walk(userData, ob, &amd->offset_ob, IDWALK_NOP);
-}
-
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob), DagNode *obNode)
-{
- ArrayModifierData *amd = (ArrayModifierData *) md;
-
- if (amd->start_cap) {
- DagNode *curNode = dag_get_node(forest, amd->start_cap);
-
- dag_add_relation(forest, curNode, obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Array Modifier");
- }
- if (amd->end_cap) {
- DagNode *curNode = dag_get_node(forest, amd->end_cap);
-
- dag_add_relation(forest, curNode, obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Array Modifier");
- }
- if (amd->curve_ob) {
- DagNode *curNode = dag_get_node(forest, amd->curve_ob);
- curNode->eval_flags |= DAG_EVAL_NEED_CURVE_PATH;
-
- dag_add_relation(forest, curNode, obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Array Modifier");
- }
- if (amd->offset_ob) {
- DagNode *curNode = dag_get_node(forest, amd->offset_ob);
-
- dag_add_relation(forest, curNode, obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Array Modifier");
- }
+ walk(userData, ob, &amd->start_cap, IDWALK_CB_NOP);
+ walk(userData, ob, &amd->end_cap, IDWALK_CB_NOP);
+ walk(userData, ob, &amd->curve_ob, IDWALK_CB_NOP);
+ walk(userData, ob, &amd->offset_ob, IDWALK_CB_NOP);
}
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
- struct Scene *scene,
+ struct Scene *UNUSED(scene),
Object *UNUSED(ob),
struct DepsNodeHandle *node)
{
ArrayModifierData *amd = (ArrayModifierData *)md;
if (amd->start_cap != NULL) {
- DEG_add_object_relation(node, amd->start_cap, DEG_OB_COMP_TRANSFORM, "Hook Modifier Start Cap");
+ DEG_add_object_relation(node, amd->start_cap, DEG_OB_COMP_TRANSFORM, "Array Modifier Start Cap");
}
if (amd->end_cap != NULL) {
- DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_TRANSFORM, "Hook Modifier End Cap");
+ DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_TRANSFORM, "Array Modifier End Cap");
}
if (amd->curve_ob) {
- DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_GEOMETRY, "Hook Modifier Curve");
- DEG_add_special_eval_flag(scene->depsgraph, &amd->curve_ob->id, DAG_EVAL_NEED_CURVE_PATH);
+ struct Depsgraph *depsgraph = DEG_get_graph_from_handle(node);
+ DEG_add_object_relation(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);
}
if (amd->offset_ob != NULL) {
- DEG_add_object_relation(node, amd->offset_ob, DEG_OB_COMP_TRANSFORM, "Hook Modifier Offset");
+ DEG_add_object_relation(node, amd->offset_ob, DEG_OB_COMP_TRANSFORM, "Array Modifier Offset");
}
}
-static float vertarray_size(const MVert *mvert, int numVerts, int axis)
-{
- int i;
- float min_co, max_co;
-
- /* if there are no vertices, width is 0 */
- if (numVerts == 0) return 0;
-
- /* find the minimum and maximum coordinates on the desired axis */
- min_co = max_co = mvert->co[axis];
- mvert++;
- for (i = 1; i < numVerts; ++i, ++mvert) {
- if (mvert->co[axis] < min_co) min_co = mvert->co[axis];
- if (mvert->co[axis] > max_co) max_co = mvert->co[axis];
- }
-
- return max_co - min_co;
-}
-
BLI_INLINE float sum_v3(const float v[3])
{
return v[0] + v[1] + v[2];
@@ -472,12 +421,22 @@ static DerivedMesh *arrayModifier_doArray(
unit_m4(offset);
src_mvert = dm->getVertArray(dm);
- if (amd->offset_type & MOD_ARR_OFF_CONST)
- add_v3_v3v3(offset[3], offset[3], amd->offset);
+ if (amd->offset_type & MOD_ARR_OFF_CONST) {
+ add_v3_v3(offset[3], amd->offset);
+ }
if (amd->offset_type & MOD_ARR_OFF_RELATIVE) {
- for (j = 0; j < 3; j++)
- offset[3][j] += amd->scale[j] * vertarray_size(src_mvert, chunk_nverts, j);
+ float min[3], max[3];
+ const MVert *src_mv;
+
+ INIT_MINMAX(min, max);
+ for (src_mv = src_mvert, j = chunk_nverts; j--; src_mv++) {
+ minmax_v3v3_v3(min, max, src_mv->co);
+ }
+
+ for (j = 3; j--; ) {
+ offset[3][j] += amd->scale[j] * (max[j] - min[j]);
+ }
}
if (use_offset_ob) {
@@ -797,7 +756,6 @@ ModifierTypeInfo modifierType_Array = {
/* 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 5874029ae08..17b0cd4d7f5 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -213,7 +213,6 @@ ModifierTypeInfo modifierType_Bevel = {
/* 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 da0f5aa3923..e649c8821fa 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -49,8 +49,6 @@
#include "BKE_library_query.h"
#include "BKE_modifier.h"
-#include "depsgraph_private.h"
-
#include "MOD_boolean_util.h"
#include "MOD_util.h"
@@ -101,23 +99,7 @@ static void foreachObjectLink(
{
BooleanModifierData *bmd = (BooleanModifierData *) md;
- walk(userData, ob, &bmd->object, IDWALK_NOP);
-}
-
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- DagNode *obNode)
-{
- BooleanModifierData *bmd = (BooleanModifierData *) md;
-
- if (bmd->object) {
- DagNode *curNode = dag_get_node(forest, bmd->object);
-
- dag_add_relation(forest, curNode, obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Boolean Modifier");
- }
+ walk(userData, ob, &bmd->object, IDWALK_CB_NOP);
}
static void updateDepsgraph(ModifierData *md,
@@ -319,6 +301,7 @@ static DerivedMesh *applyModifier_bmesh(
use_separate,
use_dissolve,
use_island_connect,
+ false,
bmd->operation,
bmd->double_threshold);
@@ -459,7 +442,6 @@ ModifierTypeInfo modifierType_Boolean = {
/* 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 a364eef2974..d2467a8fc4a 100644
--- a/source/blender/modifiers/intern/MOD_build.c
+++ b/source/blender/modifiers/intern/MOD_build.c
@@ -322,7 +322,6 @@ ModifierTypeInfo modifierType_Build = {
/* 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 33e5b3615d9..2dcc01b89d9 100644
--- a/source/blender/modifiers/intern/MOD_cast.c
+++ b/source/blender/modifiers/intern/MOD_cast.c
@@ -45,9 +45,6 @@
#include "BKE_library_query.h"
#include "BKE_modifier.h"
-
-#include "depsgraph_private.h"
-
#include "MOD_util.h"
static void initData(ModifierData *md)
@@ -102,34 +99,19 @@ static void foreachObjectLink(
{
CastModifierData *cmd = (CastModifierData *) md;
- walk(userData, ob, &cmd->object, IDWALK_NOP);
-}
-
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- DagNode *obNode)
-{
- CastModifierData *cmd = (CastModifierData *) md;
-
- if (cmd->object) {
- DagNode *curNode = dag_get_node(forest, cmd->object);
-
- dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA,
- "Cast Modifier");
- }
+ walk(userData, ob, &cmd->object, IDWALK_CB_NOP);
}
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
+ Object *object,
struct DepsNodeHandle *node)
{
CastModifierData *cmd = (CastModifierData *)md;
if (cmd->object != NULL) {
DEG_add_object_relation(node, cmd->object, DEG_OB_COMP_TRANSFORM, "Cast Modifier");
+ DEG_add_object_relation(node, object, DEG_OB_COMP_TRANSFORM, "Cast Modifier");
}
}
@@ -512,7 +494,6 @@ ModifierTypeInfo modifierType_Cast = {
/* 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 6cc2f097be8..00161366b93 100644
--- a/source/blender/modifiers/intern/MOD_cloth.c
+++ b/source/blender/modifiers/intern/MOD_cloth.c
@@ -53,8 +53,6 @@
#include "BKE_modifier.h"
#include "BKE_pointcache.h"
-#include "depsgraph_private.h"
-
#include "MOD_util.h"
static void initData(ModifierData *md)
@@ -117,28 +115,6 @@ static void deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData,
dm->release(dm);
}
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- Scene *scene, Object *ob, DagNode *obNode)
-{
- ClothModifierData *clmd = (ClothModifierData *) md;
-
- Base *base;
-
- if (clmd) {
- for (base = scene->base.first; base; base = base->next) {
- Object *ob1 = base->object;
- if (ob1 != ob) {
- CollisionModifierData *coll_clmd = (CollisionModifierData *)modifiers_findByType(ob1, eModifierType_Collision);
- if (coll_clmd) {
- DagNode *curNode = dag_get_node(forest, ob1);
- dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Cloth Collision");
- }
- }
- }
- }
-}
-
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *scene,
@@ -147,16 +123,10 @@ static void updateDepsgraph(ModifierData *md,
{
ClothModifierData *clmd = (ClothModifierData *)md;
if (clmd != NULL) {
- Base *base;
- for (base = scene->base.first; base; base = base->next) {
- Object *ob1 = base->object;
- if (ob1 != ob) {
- CollisionModifierData *coll_clmd = (CollisionModifierData *)modifiers_findByType(ob1, eModifierType_Collision);
- if (coll_clmd) {
- DEG_add_object_relation(node, ob1, DEG_OB_COMP_TRANSFORM, "Cloth Modifier");
- }
- }
- }
+ /* Actual code uses get_collisionobjects */
+ DEG_add_collision_relations(node, scene, ob, clmd->coll_parms->group, eModifierType_Collision, NULL, true, "Cloth Collision");
+
+ DEG_add_forcefield_relations(node, scene, ob, clmd->sim_parms->effector_weights, true, 0, "Cloth Field");
}
}
@@ -242,11 +212,11 @@ static void foreachIDLink(ModifierData *md, Object *ob,
ClothModifierData *clmd = (ClothModifierData *) md;
if (clmd->coll_parms) {
- walk(userData, ob, (ID **)&clmd->coll_parms->group, IDWALK_NOP);
+ walk(userData, ob, (ID **)&clmd->coll_parms->group, IDWALK_CB_NOP);
}
if (clmd->sim_parms && clmd->sim_parms->effector_weights) {
- walk(userData, ob, (ID **)&clmd->sim_parms->effector_weights->group, IDWALK_NOP);
+ walk(userData, ob, (ID **)&clmd->sim_parms->effector_weights->group, IDWALK_CB_NOP);
}
}
@@ -270,7 +240,6 @@ ModifierTypeInfo modifierType_Cloth = {
/* 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 ff0c6500479..a2a4b2e1274 100644
--- a/source/blender/modifiers/intern/MOD_collision.c
+++ b/source/blender/modifiers/intern/MOD_collision.c
@@ -60,6 +60,7 @@ static void initData(ModifierData *md)
collmd->time_x = collmd->time_xnew = -1000;
collmd->mvert_num = 0;
collmd->tri_num = 0;
+ collmd->is_static = false;
collmd->bvhtree = NULL;
}
@@ -87,6 +88,7 @@ static void freeData(ModifierData *md)
collmd->time_x = collmd->time_xnew = -1000;
collmd->mvert_num = 0;
collmd->tri_num = 0;
+ collmd->is_static = false;
}
}
@@ -169,6 +171,7 @@ static void deformVerts(ModifierData *md, Object *ob,
ob->pd->pdef_sboft);
collmd->time_x = collmd->time_xnew = current_time;
+ collmd->is_static = true;
}
else if (mvert_num == collmd->mvert_num) {
/* put positions to old positions */
@@ -179,14 +182,19 @@ static void deformVerts(ModifierData *md, Object *ob,
memcpy(collmd->xnew, dm->getVertArray(dm), mvert_num * sizeof(MVert));
+ bool is_static = true;
+
for (i = 0; i < mvert_num; i++) {
/* we save global positions */
mul_m4_v3(ob->obmat, collmd->xnew[i].co);
+
+ /* 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));
-
+
/* check if GUI setting has changed for bvh */
if (collmd->bvhtree) {
if (ob->pd->pdef_sboft != BLI_bvhtree_get_epsilon(collmd->bvhtree)) {
@@ -206,7 +214,7 @@ static void deformVerts(ModifierData *md, Object *ob,
collmd->tri, collmd->tri_num,
ob->pd->pdef_sboft);
}
- else {
+ else if (!collmd->is_static || !is_static) {
/* recalc static bounding boxes */
bvhtree_update_from_mvert(
collmd->bvhtree,
@@ -214,7 +222,8 @@ static void deformVerts(ModifierData *md, Object *ob,
collmd->tri, collmd->tri_num,
true);
}
-
+
+ collmd->is_static = is_static;
collmd->time_xnew = current_time;
}
else if (mvert_num != collmd->mvert_num) {
@@ -256,7 +265,6 @@ ModifierTypeInfo modifierType_Collision = {
/* 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 77fd84a2948..0718b0f85fa 100644
--- a/source/blender/modifiers/intern/MOD_correctivesmooth.c
+++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c
@@ -759,7 +759,6 @@ ModifierTypeInfo modifierType_CorrectiveSmooth = {
/* 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 9bc96e593fd..3200caedc32 100644
--- a/source/blender/modifiers/intern/MOD_curve.c
+++ b/source/blender/modifiers/intern/MOD_curve.c
@@ -45,10 +45,9 @@
#include "BKE_library_query.h"
#include "BKE_modifier.h"
-#include "depsgraph_private.h"
+#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
-
static void initData(ModifierData *md)
{
CurveModifierData *cmd = (CurveModifierData *) md;
@@ -89,29 +88,12 @@ static void foreachObjectLink(
{
CurveModifierData *cmd = (CurveModifierData *) md;
- walk(userData, ob, &cmd->object, IDWALK_NOP);
-}
-
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- Scene *UNUSED(scene),
- Object *UNUSED(ob),
- DagNode *obNode)
-{
- CurveModifierData *cmd = (CurveModifierData *) md;
-
- if (cmd->object) {
- DagNode *curNode = dag_get_node(forest, cmd->object);
- curNode->eval_flags |= DAG_EVAL_NEED_CURVE_PATH;
-
- dag_add_relation(forest, curNode, obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Curve Modifier");
- }
+ walk(userData, ob, &cmd->object, IDWALK_CB_NOP);
}
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
- struct Scene *scene,
+ struct Scene *UNUSED(scene),
Object *object,
struct DepsNodeHandle *node)
{
@@ -123,8 +105,9 @@ static void updateDepsgraph(ModifierData *md,
/* 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(node);
DEG_add_object_relation(node, cmd->object, DEG_OB_COMP_GEOMETRY, "Curve Modifier");
- DEG_add_special_eval_flag(scene->depsgraph, &cmd->object->id, DAG_EVAL_NEED_CURVE_PATH);
+ DEG_add_special_eval_flag(depsgraph, &cmd->object->id, DAG_EVAL_NEED_CURVE_PATH);
}
DEG_add_object_relation(node, object, DEG_OB_COMP_TRANSFORM, "Curve Modifier");
@@ -178,7 +161,6 @@ ModifierTypeInfo modifierType_Curve = {
/* 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 f5ab28d3d88..9fd23598cb6 100644
--- a/source/blender/modifiers/intern/MOD_datatransfer.c
+++ b/source/blender/modifiers/intern/MOD_datatransfer.c
@@ -50,8 +50,6 @@
#include "MEM_guardedalloc.h"
#include "MOD_util.h"
-#include "depsgraph_private.h"
-
/**************************************
* Modifiers functions. *
**************************************/
@@ -124,23 +122,7 @@ static void foreachObjectLink(
ObjectWalkFunc walk, void *userData)
{
DataTransferModifierData *dtmd = (DataTransferModifierData *) md;
- walk(userData, ob, &dtmd->ob_source, IDWALK_NOP);
-}
-
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob), DagNode *obNode)
-{
- DataTransferModifierData *dtmd = (DataTransferModifierData *) md;
- DagNode *curNode;
-
- if (dtmd->ob_source) {
- curNode = dag_get_node(forest, dtmd->ob_source);
-
- dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA,
- "DataTransfer Modifier");
- }
+ walk(userData, ob, &dtmd->ob_source, IDWALK_CB_NOP);
}
static void updateDepsgraph(ModifierData *md,
@@ -179,7 +161,6 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
/* Only used to check wehther we are operating on org data or not... */
Mesh *me = ob->data;
- MVert *mvert;
const bool invert_vgroup = (dtmd->flags & MOD_DATATRANSFER_INVERT_VGROUP) != 0;
@@ -192,8 +173,9 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
BLI_SPACE_TRANSFORM_SETUP(space_transform, ob, dtmd->ob_source);
}
- mvert = dm->getVertArray(dm);
- if ((me->mvert == mvert) && (dtmd->data_types & DT_TYPES_AFFECT_MESH)) {
+ MVert *mvert = dm->getVertArray(dm);
+ MEdge *medge = dm->getEdgeArray(dm);
+ if (((me->mvert == mvert) || (me->medge == 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);
@@ -211,6 +193,9 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
if (BKE_reports_contain(&reports, RPT_ERROR)) {
modifier_setError(md, "%s", BKE_reports_string(&reports, RPT_ERROR));
}
+ 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) {
modifier_setError(md, "You are using a rather high poly as source or destination, computation might be slow");
}
@@ -251,7 +236,6 @@ ModifierTypeInfo modifierType_DataTransfer = {
/* 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 617ae5a89f3..bcb52e4e0ca 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -227,7 +227,6 @@ ModifierTypeInfo modifierType_Decimate = {
/* 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 9ba2d214d50..c422aa05b12 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -38,16 +38,18 @@
#include "BLI_utildefines.h"
#include "BLI_math.h"
+#include "BLI_task.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_image.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_texture.h"
#include "BKE_deform.h"
+#include "BKE_object.h"
-#include "depsgraph_private.h"
#include "MEM_guardedalloc.h"
#include "MOD_util.h"
@@ -65,6 +67,7 @@ static void initData(ModifierData *md)
dmd->strength = 1;
dmd->direction = MOD_DISP_DIR_NOR;
dmd->midlevel = 0.5;
+ dmd->space = MOD_DISP_SPACE_LOCAL;
}
static void copyData(ModifierData *md, ModifierData *target)
@@ -130,7 +133,7 @@ static void foreachObjectLink(ModifierData *md, Object *ob,
{
DisplaceModifierData *dmd = (DisplaceModifierData *) md;
- walk(userData, ob, &dmd->map_object, IDWALK_NOP);
+ walk(userData, ob, &dmd->map_object, IDWALK_CB_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob,
@@ -138,7 +141,7 @@ static void foreachIDLink(ModifierData *md, Object *ob,
{
DisplaceModifierData *dmd = (DisplaceModifierData *) md;
- walk(userData, ob, (ID **)&dmd->texture, IDWALK_USER);
+ walk(userData, ob, (ID **)&dmd->texture, IDWALK_CB_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
@@ -155,28 +158,6 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
return ((!dmd->texture && dmd->direction == MOD_DISP_DIR_RGB_XYZ) || dmd->strength == 0.0f);
}
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- DagNode *obNode)
-{
- DisplaceModifierData *dmd = (DisplaceModifierData *) md;
-
- if (dmd->map_object && dmd->texmapping == MOD_DISP_MAP_OBJECT) {
- DagNode *curNode = dag_get_node(forest, dmd->map_object);
-
- dag_add_relation(forest, curNode, obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Displace Modifier");
- }
-
-
- if (dmd->texmapping == MOD_DISP_MAP_GLOBAL)
- dag_add_relation(forest, obNode, obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Displace Modifier");
-
-}
-
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
@@ -187,25 +168,139 @@ static void updateDepsgraph(ModifierData *md,
if (dmd->map_object != NULL && dmd->texmapping == MOD_DISP_MAP_OBJECT) {
DEG_add_object_relation(node, dmd->map_object, DEG_OB_COMP_TRANSFORM, "Displace Modifier");
}
- if (dmd->texmapping == MOD_DISP_MAP_GLOBAL) {
+ 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))
+ {
DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "Displace Modifier");
}
}
+typedef struct DisplaceUserdata {
+ /*const*/ DisplaceModifierData *dmd;
+ struct ImagePool *pool;
+ MDeformVert *dvert;
+ float weight;
+ int defgrp_index;
+ int direction;
+ bool use_global_direction;
+ float (*tex_co)[3];
+ float (*vertexCos)[3];
+ float local_mat[4][4];
+ MVert *mvert;
+ float (*vert_clnors)[3];
+} DisplaceUserdata;
+
+static void displaceModifier_do_task(void *userdata, const int iter)
+{
+ DisplaceUserdata *data = (DisplaceUserdata *)userdata;
+ DisplaceModifierData *dmd = data->dmd;
+ MDeformVert *dvert = data->dvert;
+ float weight = data->weight;
+ int defgrp_index = data->defgrp_index;
+ int direction = data->direction;
+ bool use_global_direction = data->use_global_direction;
+ float (*tex_co)[3] = data->tex_co;
+ float (*vertexCos)[3] = data->vertexCos;
+ MVert *mvert = data->mvert;
+ float (*vert_clnors)[3] = data->vert_clnors;
+
+ const float delta_fixed = 1.0f - dmd->midlevel; /* when no texture is used, we fallback to white */
+
+ TexResult texres;
+ float strength = dmd->strength;
+ float delta;
+ float local_vec[3];
+
+ if (dvert) {
+ weight = defvert_find_weight(dvert + iter, defgrp_index);
+ if (weight == 0.0f) {
+ return;
+ }
+ }
+
+ if (dmd->texture) {
+ texres.nor = NULL;
+ BKE_texture_get_value_ex(dmd->modifier.scene, dmd->texture, tex_co[iter], &texres, data->pool, false);
+ delta = texres.tin - dmd->midlevel;
+ }
+ else {
+ delta = delta_fixed; /* (1.0f - dmd->midlevel) */ /* never changes */
+ }
+
+ if (dvert) {
+ strength *= weight;
+ }
+
+ delta *= strength;
+ CLAMP(delta, -10000, 10000);
+
+ switch (direction) {
+ case MOD_DISP_DIR_X:
+ if (use_global_direction) {
+ vertexCos[iter][0] += delta * data->local_mat[0][0];
+ vertexCos[iter][1] += delta * data->local_mat[1][0];
+ vertexCos[iter][2] += delta * data->local_mat[2][0];
+ }
+ else {
+ vertexCos[iter][0] += delta;
+ }
+ break;
+ case MOD_DISP_DIR_Y:
+ if (use_global_direction) {
+ vertexCos[iter][0] += delta * data->local_mat[0][1];
+ vertexCos[iter][1] += delta * data->local_mat[1][1];
+ vertexCos[iter][2] += delta * data->local_mat[2][1];
+ }
+ else {
+ vertexCos[iter][1] += delta;
+ }
+ break;
+ case MOD_DISP_DIR_Z:
+ if (use_global_direction) {
+ vertexCos[iter][0] += delta * data->local_mat[0][2];
+ vertexCos[iter][1] += delta * data->local_mat[1][2];
+ vertexCos[iter][2] += delta * data->local_mat[2][2];
+ }
+ else {
+ vertexCos[iter][2] += delta;
+ }
+ break;
+ case MOD_DISP_DIR_RGB_XYZ:
+ local_vec[0] = texres.tr - dmd->midlevel;
+ local_vec[1] = texres.tg - dmd->midlevel;
+ local_vec[2] = texres.tb - dmd->midlevel;
+ if (use_global_direction) {
+ mul_transposed_mat3_m4_v3(data->local_mat, local_vec);
+ }
+ mul_v3_fl(local_vec, strength);
+ add_v3_v3(vertexCos[iter], local_vec);
+ break;
+ case MOD_DISP_DIR_NOR:
+ vertexCos[iter][0] += delta * (mvert[iter].no[0] / 32767.0f);
+ vertexCos[iter][1] += delta * (mvert[iter].no[1] / 32767.0f);
+ vertexCos[iter][2] += delta * (mvert[iter].no[2] / 32767.0f);
+ break;
+ case MOD_DISP_DIR_CLNOR:
+ madd_v3_v3fl(vertexCos[iter], vert_clnors[iter], delta);
+ break;
+ }
+}
+
/* dm must be a CDDerivedMesh */
static void displaceModifier_do(
DisplaceModifierData *dmd, Object *ob,
DerivedMesh *dm, float (*vertexCos)[3], int numVerts)
{
- int i;
MVert *mvert;
MDeformVert *dvert;
int direction = dmd->direction;
int defgrp_index;
float (*tex_co)[3];
float weight = 1.0f; /* init value unused but some compilers may complain */
- const float delta_fixed = 1.0f - dmd->midlevel; /* when no texture is used, we fallback to white */
float (*vert_clnors)[3] = NULL;
+ float local_mat[4][4] = {{0}};
+ const bool use_global_direction = dmd->space == MOD_DISP_SPACE_GLOBAL;
if (!dmd->texture && dmd->direction == MOD_DISP_DIR_RGB_XYZ) return;
if (dmd->strength == 0.0f) return;
@@ -243,55 +338,32 @@ static void displaceModifier_do(
direction = MOD_DISP_DIR_NOR;
}
}
+ else if (ELEM(direction, MOD_DISP_DIR_X, MOD_DISP_DIR_Y, MOD_DISP_DIR_Z, MOD_DISP_DIR_RGB_XYZ) &&
+ use_global_direction)
+ {
+ copy_m4_m4(local_mat, ob->obmat);
+ }
- for (i = 0; i < numVerts; i++) {
- TexResult texres;
- float strength = dmd->strength;
- float delta;
-
- if (dvert) {
- weight = defvert_find_weight(dvert + i, defgrp_index);
- if (weight == 0.0f) continue;
- }
-
- if (dmd->texture) {
- texres.nor = NULL;
- BKE_texture_get_value(dmd->modifier.scene, dmd->texture, tex_co[i], &texres, false);
- delta = texres.tin - dmd->midlevel;
- }
- else {
- delta = delta_fixed; /* (1.0f - dmd->midlevel) */ /* never changes */
- }
+ DisplaceUserdata data = {NULL};
+ data.dmd = dmd;
+ data.dvert = dvert;
+ data.weight = weight;
+ data.defgrp_index = defgrp_index;
+ data.direction = direction;
+ data.use_global_direction = use_global_direction;
+ data.tex_co = tex_co;
+ data.vertexCos = vertexCos;
+ copy_m4_m4(data.local_mat, local_mat);
+ data.mvert = mvert;
+ data.vert_clnors = vert_clnors;
+ if (dmd->texture != NULL) {
+ data.pool = BKE_image_pool_new();
+ BKE_texture_fetch_images_for_pool(dmd->texture, data.pool);
+ }
+ BLI_task_parallel_range(0, numVerts, &data, displaceModifier_do_task, numVerts > 512);
- if (dvert) strength *= weight;
-
- delta *= strength;
- CLAMP(delta, -10000, 10000);
-
- switch (direction) {
- case MOD_DISP_DIR_X:
- vertexCos[i][0] += delta;
- break;
- case MOD_DISP_DIR_Y:
- vertexCos[i][1] += delta;
- break;
- case MOD_DISP_DIR_Z:
- vertexCos[i][2] += delta;
- break;
- case MOD_DISP_DIR_RGB_XYZ:
- vertexCos[i][0] += (texres.tr - dmd->midlevel) * strength;
- vertexCos[i][1] += (texres.tg - dmd->midlevel) * strength;
- vertexCos[i][2] += (texres.tb - dmd->midlevel) * strength;
- break;
- case MOD_DISP_DIR_NOR:
- vertexCos[i][0] += delta * (mvert[i].no[0] / 32767.0f);
- vertexCos[i][1] += delta * (mvert[i].no[1] / 32767.0f);
- vertexCos[i][2] += delta * (mvert[i].no[2] / 32767.0f);
- break;
- case MOD_DISP_DIR_CLNOR:
- madd_v3_v3fl(vertexCos[i], vert_clnors[i], delta);
- break;
- }
+ if (data.pool != NULL) {
+ BKE_image_pool_free(data.pool);
}
if (tex_co) {
@@ -351,7 +423,6 @@ ModifierTypeInfo modifierType_Displace = {
/* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
/* 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 edf959f42c6..ade416f39eb 100644
--- a/source/blender/modifiers/intern/MOD_dynamicpaint.c
+++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c
@@ -36,10 +36,11 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_dynamicpaint.h"
+#include "BKE_layer.h"
+#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_modifier.h"
-#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
@@ -58,6 +59,15 @@ static void copyData(ModifierData *md, ModifierData *target)
DynamicPaintModifierData *tpmd = (DynamicPaintModifierData *)target;
dynamicPaint_Modifier_copy(pmd, tpmd);
+
+ if (tpmd->canvas) {
+ for (DynamicPaintSurface *surface = tpmd->canvas->surfaces.first; surface; surface = surface->next) {
+ id_us_plus((ID *)surface->init_texture);
+ }
+ }
+ if (tpmd->brush) {
+ id_us_plus((ID *)tpmd->brush->mat);
+ }
}
static void freeData(ModifierData *md)
@@ -78,7 +88,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 ||
@@ -95,7 +105,7 @@ 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;
+ dataMask |= CD_MASK_MLOOPUV;
}
}
return dataMask;
@@ -109,33 +119,14 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
/* dont apply dynamic paint on orco dm stack */
if (!(flag & MOD_APPLY_ORCO)) {
- return dynamicPaint_Modifier_do(pmd, md->scene, ob, dm);
+ return dynamicPaint_Modifier_do(pmd, md->scene, BKE_scene_layer_context_active_PLACEHOLDER(md->scene), ob, dm);
}
return dm;
}
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- struct Scene *scene,
- Object *ob,
- DagNode *obNode)
+static bool is_brush_cb(Object *UNUSED(ob), ModifierData *pmd)
{
- DynamicPaintModifierData *pmd = (DynamicPaintModifierData *) md;
-
- /* add relation from canvases to all brush objects */
- if (pmd && pmd->canvas) {
- Base *base = scene->base.first;
-
- for (; base; base = base->next) {
- DynamicPaintModifierData *pmd2 =
- (DynamicPaintModifierData *)modifiers_findByType(base->object, eModifierType_DynamicPaint);
-
- if (pmd2 && pmd2->brush && ob != base->object) {
- DagNode *brushNode = dag_get_node(forest, base->object);
- dag_add_relation(forest, brushNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Dynamic Paint Brush");
- }
- }
- }
+ return ((DynamicPaintModifierData *)pmd)->brush != NULL;
}
static void updateDepsgraph(ModifierData *md,
@@ -147,13 +138,13 @@ static void updateDepsgraph(ModifierData *md,
DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
/* Add relation from canvases to all brush objects. */
if (pmd->canvas != NULL) {
- Base *base = scene->base.first;
- for (; base; base = base->next) {
- DynamicPaintModifierData *pmd2 =
- (DynamicPaintModifierData *)modifiers_findByType(base->object, eModifierType_DynamicPaint);
- if (pmd2 && pmd2->brush && ob != base->object) {
- DEG_add_object_relation(node, base->object, DEG_OB_COMP_TRANSFORM, "Dynamic Paint Brush");
+ for (DynamicPaintSurface *surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
+ if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
+ DEG_add_forcefield_relations(node, scene, ob, 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(node, scene, ob, surface->brush_group, eModifierType_DynamicPaint, is_brush_cb, false, "Dynamic Paint Brush");
}
}
}
@@ -172,15 +163,15 @@ static void foreachIDLink(ModifierData *md, Object *ob,
DynamicPaintSurface *surface = pmd->canvas->surfaces.first;
for (; surface; surface = surface->next) {
- walk(userData, ob, (ID **)&surface->brush_group, IDWALK_NOP);
- walk(userData, ob, (ID **)&surface->init_texture, IDWALK_USER);
+ walk(userData, ob, (ID **)&surface->brush_group, IDWALK_CB_NOP);
+ walk(userData, ob, (ID **)&surface->init_texture, IDWALK_CB_USER);
if (surface->effector_weights) {
- walk(userData, ob, (ID **)&surface->effector_weights->group, IDWALK_NOP);
+ walk(userData, ob, (ID **)&surface->effector_weights->group, IDWALK_CB_NOP);
}
}
}
if (pmd->brush) {
- walk(userData, ob, (ID **)&pmd->brush->mat, IDWALK_USER);
+ walk(userData, ob, (ID **)&pmd->brush->mat, IDWALK_CB_USER);
}
}
@@ -212,7 +203,6 @@ ModifierTypeInfo modifierType_DynamicPaint = {
/* 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 4441edb299b..f239807a7d3 100644
--- a/source/blender/modifiers/intern/MOD_edgesplit.c
+++ b/source/blender/modifiers/intern/MOD_edgesplit.c
@@ -157,7 +157,6 @@ ModifierTypeInfo modifierType_EdgeSplit = {
/* 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 38ffdaa709b..24ce2e3cc8e 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -1001,8 +1001,6 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
ExplodeModifierData *emd = (ExplodeModifierData *) md;
ParticleSystemModifierData *psmd = findPrecedingParticlesystem(ob, md);
- DM_ensure_tessface(dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
-
if (psmd) {
ParticleSystem *psys = psmd->psys;
@@ -1010,6 +1008,8 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
if (psys->part == NULL || psys->particles == NULL) return derivedData;
if (psmd->dm_final == NULL) return derivedData;
+ DM_ensure_tessface(dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
+
/* 1. find faces to be exploded if needed */
if (emd->facepa == NULL ||
psmd->flag & eParticleSystemFlag_Pars ||
@@ -1059,7 +1059,6 @@ ModifierTypeInfo modifierType_Explode = {
/* 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 c202c5e1cb4..85eb7b2ffc9 100644
--- a/source/blender/modifiers/intern/MOD_fluidsim.c
+++ b/source/blender/modifiers/intern/MOD_fluidsim.c
@@ -41,9 +41,9 @@
#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"
@@ -68,12 +68,13 @@ static void copyData(ModifierData *md, ModifierData *target)
FluidsimModifierData *fluidmd = (FluidsimModifierData *) md;
FluidsimModifierData *tfluidmd = (FluidsimModifierData *) target;
- if (tfluidmd->fss)
- MEM_freeN(tfluidmd->fss);
-
- tfluidmd->fss = MEM_dupallocN(fluidmd->fss);
- if (tfluidmd->fss && (tfluidmd->fss->meshVelocities != NULL)) {
- tfluidmd->fss->meshVelocities = MEM_dupallocN(tfluidmd->fss->meshVelocities);
+ fluidsim_free(tfluidmd);
+
+ if (fluidmd->fss) {
+ tfluidmd->fss = MEM_dupallocN(fluidmd->fss);
+ if (tfluidmd->fss && (tfluidmd->fss->meshVelocities != NULL)) {
+ tfluidmd->fss->meshVelocities = MEM_dupallocN(tfluidmd->fss->meshVelocities);
+ }
}
}
@@ -100,33 +101,6 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
return result ? result : dm;
}
-static void updateDepgraph(
- ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain), Scene *scene,
- Object *ob, DagNode *obNode)
-{
- FluidsimModifierData *fluidmd = (FluidsimModifierData *) md;
- Base *base;
-
- if (fluidmd && fluidmd->fss) {
- if (fluidmd->fss->type == OB_FLUIDSIM_DOMAIN) {
- for (base = scene->base.first; base; base = base->next) {
- Object *ob1 = base->object;
- if (ob1 != ob) {
- 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(forest, ob1);
- dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Fluidsim Object");
- }
- }
- }
- }
- }
-}
-
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *scene,
@@ -136,9 +110,8 @@ static void updateDepsgraph(ModifierData *md,
FluidsimModifierData *fluidmd = (FluidsimModifierData *) md;
if (fluidmd && fluidmd->fss) {
if (fluidmd->fss->type == OB_FLUIDSIM_DOMAIN) {
- Base *base;
- for (base = scene->base.first; base; base = base->next) {
- Object *ob1 = base->object;
+ FOREACH_SCENE_OBJECT(scene, ob1)
+ {
if (ob1 != ob) {
FluidsimModifierData *fluidmdtmp =
(FluidsimModifierData *)modifiers_findByType(ob1, eModifierType_Fluidsim);
@@ -149,6 +122,7 @@ static void updateDepsgraph(ModifierData *md,
}
}
}
+ FOREACH_SCENE_OBJECT_END
}
}
}
@@ -180,7 +154,6 @@ ModifierTypeInfo modifierType_Fluidsim = {
/* 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 ffbbb1b0745..3684e947fe0 100644
--- a/source/blender/modifiers/intern/MOD_fluidsim_util.c
+++ b/source/blender/modifiers/intern/MOD_fluidsim_util.c
@@ -78,8 +78,8 @@ void fluidsim_init(FluidsimModifierData *fluidmd)
fss->resolutionxyz = 65;
fss->previewresxyz = 45;
fss->realsize = 0.5;
- fss->guiDisplayMode = 2; // preview
- fss->renderDisplayMode = 3; // render
+ fss->guiDisplayMode = OB_FSDOM_PREVIEW;
+ fss->renderDisplayMode = OB_FSDOM_FINAL;
fss->viscosityValue = 1.0;
fss->viscosityExponent = 6;
@@ -98,7 +98,7 @@ void fluidsim_init(FluidsimModifierData *fluidmd)
/* fluid/inflow settings
* fss->iniVel --> automatically set to 0 */
- modifier_path_init(fss->surfdataPath, sizeof(fss->surfdataPath), "cache_fluid");
+ modifier_path_init(fss->surfdataPath, sizeof(fss->surfdataPath), OB_FLUIDSIM_SURF_DIR_DEFAULT);
/* first init of bounding box */
/* no bounding box needed */
@@ -150,9 +150,8 @@ void fluidsim_free(FluidsimModifierData *fluidmd)
if (fluidmd && fluidmd->fss) {
if (fluidmd->fss->meshVelocities) {
MEM_freeN(fluidmd->fss->meshVelocities);
- fluidmd->fss->meshVelocities = NULL;
}
- MEM_freeN(fluidmd->fss);
+ MEM_SAFE_FREE(fluidmd->fss);
}
return;
@@ -423,8 +422,6 @@ static void fluidsim_read_vel_cache(FluidsimModifierData *fluidmd, DerivedMesh *
static DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm,
FluidsimModifierData *fluidmd, int framenr, int useRenderParams)
{
- int displaymode = 0;
-
int curFrame = framenr /* - 1 */ /*scene->r.sfra*/; /* start with 0 at start frame */
/* why start with 0 as start frame?? Animations + time are frozen for frame 0 anyway. (See physics_fluid.c for that. - DG */
/* If we start with frame 0, we need to remap all animation channels, too, because they will all be 1 frame late if using frame-1! - DG */
@@ -435,25 +432,23 @@ static DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm,
MPoly *mpoly;
MPoly mp_example = {0};
- if (!useRenderParams) {
- displaymode = fss->guiDisplayMode;
- }
- else {
- displaymode = fss->renderDisplayMode;
- }
+ const int displaymode = useRenderParams ? fss->renderDisplayMode : fss->guiDisplayMode;
switch (displaymode) {
- case 1:
+ case OB_FSDOM_GEOM:
/* just display original object */
return NULL;
- case 2:
+ case OB_FSDOM_PREVIEW:
/* use preview mesh */
BLI_join_dirfile(targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME);
break;
- default: /* 3 */
- /* 3. use final mesh */
+ case OB_FSDOM_FINAL:
+ /* use final mesh */
BLI_join_dirfile(targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME);
break;
+ default:
+ BLI_assert(!"Wrong fluidsim display type");
+ return NULL;
}
/* offset baked frame */
@@ -494,7 +489,7 @@ static DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm,
/* load vertex velocities, if they exist...
* TODO? use generate flag as loading flag as well?
* warning, needs original .bobj.gz mesh loading filename */
- if (displaymode == 3) {
+ if (displaymode == OB_FSDOM_FINAL) {
fluidsim_read_vel_cache(fluidmd, dm, targetFile);
}
else {
diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c
index 83c4ca7984c..08103292a8b 100644
--- a/source/blender/modifiers/intern/MOD_hook.c
+++ b/source/blender/modifiers/intern/MOD_hook.c
@@ -47,7 +47,6 @@
#include "BKE_colortools.h"
-#include "depsgraph_private.h"
#include "MEM_guardedalloc.h"
#include "MOD_util.h"
@@ -115,25 +114,7 @@ static void foreachObjectLink(
{
HookModifierData *hmd = (HookModifierData *) md;
- walk(userData, ob, &hmd->object, IDWALK_NOP);
-}
-
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- DagNode *obNode)
-{
- HookModifierData *hmd = (HookModifierData *) md;
-
- if (hmd->object) {
- DagNode *curNode = dag_get_node(forest, hmd->object);
-
- if (hmd->subtarget[0])
- dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA | DAG_RL_DATA_DATA, "Hook Modifier");
- else
- dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA, "Hook Modifier");
- }
+ walk(userData, ob, &hmd->object, IDWALK_CB_NOP);
}
static void updateDepsgraph(ModifierData *md,
@@ -145,12 +126,9 @@ static void updateDepsgraph(ModifierData *md,
HookModifierData *hmd = (HookModifierData *)md;
if (hmd->object != NULL) {
if (hmd->subtarget[0]) {
- DEG_add_bone_relation(node, hmd->object, hmd->subtarget, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
DEG_add_bone_relation(node, hmd->object, hmd->subtarget, DEG_OB_COMP_BONE, "Hook Modifier");
}
- else {
- DEG_add_object_relation(node, hmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
- }
+ DEG_add_object_relation(node, hmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
}
/* We need own transformation as well. */
DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
@@ -430,7 +408,6 @@ ModifierTypeInfo modifierType_Hook = {
/* 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 ce3fdc4bbe8..56a2e217a2a 100644
--- a/source/blender/modifiers/intern/MOD_laplaciandeform.c
+++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c
@@ -775,7 +775,6 @@ ModifierTypeInfo modifierType_LaplacianDeform = {
/* 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 f1216ff462a..1295a75d9e7 100644
--- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c
+++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
@@ -561,7 +561,6 @@ ModifierTypeInfo modifierType_LaplacianSmooth = {
/* 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 7d4701e3ef2..8c723f1c4be 100644
--- a/source/blender/modifiers/intern/MOD_lattice.c
+++ b/source/blender/modifiers/intern/MOD_lattice.c
@@ -44,8 +44,6 @@
#include "BKE_library_query.h"
#include "BKE_modifier.h"
-#include "depsgraph_private.h"
-
#include "MOD_util.h"
static void initData(ModifierData *md)
@@ -88,23 +86,7 @@ static void foreachObjectLink(
{
LatticeModifierData *lmd = (LatticeModifierData *) md;
- walk(userData, ob, &lmd->object, IDWALK_NOP);
-}
-
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- DagNode *obNode)
-{
- LatticeModifierData *lmd = (LatticeModifierData *) md;
-
- if (lmd->object) {
- DagNode *latNode = dag_get_node(forest, lmd->object);
-
- dag_add_relation(forest, latNode, obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Lattice Modifier");
- }
+ walk(userData, ob, &lmd->object, IDWALK_CB_NOP);
}
static void updateDepsgraph(ModifierData *md,
@@ -169,7 +151,6 @@ ModifierTypeInfo modifierType_Lattice = {
/* 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 5e01a20d93b..11c0fae9a75 100644
--- a/source/blender/modifiers/intern/MOD_mask.c
+++ b/source/blender/modifiers/intern/MOD_mask.c
@@ -50,7 +50,6 @@
#include "BKE_modifier.h"
#include "BKE_deform.h"
-#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
#include "BLI_strict_flags.h"
@@ -74,25 +73,7 @@ static void foreachObjectLink(
ObjectWalkFunc walk, void *userData)
{
MaskModifierData *mmd = (MaskModifierData *)md;
- walk(userData, ob, &mmd->ob_arm, IDWALK_NOP);
-}
-
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- DagNode *obNode)
-{
- MaskModifierData *mmd = (MaskModifierData *)md;
-
- if (mmd->ob_arm) {
- bArmature *arm = (bArmature *)mmd->ob_arm->data;
- DagNode *armNode = dag_get_node(forest, mmd->ob_arm);
-
- /* tag relationship in depsgraph, but also on the armature */
- dag_add_relation(forest, armNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Mask Modifier");
- arm->flag |= ARM_HAS_VIZ_DEPS;
- }
+ walk(userData, ob, &mmd->ob_arm, IDWALK_CB_NOP);
}
static void updateDepsgraph(ModifierData *md,
@@ -401,7 +382,6 @@ ModifierTypeInfo modifierType_Mask = {
/* 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 aa3e3ebcf7e..0d96032c515 100644
--- a/source/blender/modifiers/intern/MOD_meshcache.c
+++ b/source/blender/modifiers/intern/MOD_meshcache.c
@@ -313,7 +313,6 @@ ModifierTypeInfo modifierType_MeshCache = {
/* requiredDataMask */ NULL,
/* freeData */ NULL,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_meshcache_mdd.c b/source/blender/modifiers/intern/MOD_meshcache_mdd.c
index 90fc750de3b..3dd3a5fc598 100644
--- a/source/blender/modifiers/intern/MOD_meshcache_mdd.c
+++ b/source/blender/modifiers/intern/MOD_meshcache_mdd.c
@@ -35,6 +35,9 @@
#ifdef __LITTLE_ENDIAN__
# include "BLI_endian_switch.h"
#endif
+#ifdef WIN32
+# include "BLI_winstuff.h"
+#endif
#include "MOD_meshcache_util.h" /* own include */
@@ -157,7 +160,7 @@ bool MOD_meshcache_read_mdd_index(FILE *fp,
return false;
}
- if (fseek(fp, index * mdd_head.verts_tot * sizeof(float) * 3, SEEK_CUR) != 0) {
+ if (fseek(fp, sizeof(float) * 3 * index * mdd_head.verts_tot, SEEK_CUR) != 0) {
*err_str = "Failed to seek frame";
return false;
}
diff --git a/source/blender/modifiers/intern/MOD_meshcache_pc2.c b/source/blender/modifiers/intern/MOD_meshcache_pc2.c
index 219eae4ecca..8360c8ffda7 100644
--- a/source/blender/modifiers/intern/MOD_meshcache_pc2.c
+++ b/source/blender/modifiers/intern/MOD_meshcache_pc2.c
@@ -35,6 +35,10 @@
# include "BLI_endian_switch.h"
#endif
+#ifdef WIN32
+# include "BLI_winstuff.h"
+#endif
+
#include "MOD_meshcache_util.h" /* own include */
#include "DNA_modifier_types.h"
@@ -142,7 +146,7 @@ bool MOD_meshcache_read_pc2_index(FILE *fp,
return false;
}
- if (fseek(fp, index * pc2_head.verts_tot * sizeof(float) * 3, SEEK_CUR) != 0) {
+ if (fseek(fp, sizeof(float) * 3 * index * pc2_head.verts_tot , SEEK_CUR) != 0) {
*err_str = "Failed to seek frame";
return false;
}
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index 3f34319d25f..3c05f8266f0 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -47,8 +47,6 @@
#include "BKE_deform.h"
#include "BKE_editmesh.h"
-#include "depsgraph_private.h"
-
#include "MEM_guardedalloc.h"
#include "MOD_util.h"
@@ -83,7 +81,7 @@ static void copyData(ModifierData *md, ModifierData *target)
MeshDeformModifierData *mmd = (MeshDeformModifierData *) md;
MeshDeformModifierData *tmmd = (MeshDeformModifierData *) target;
- *tmmd = *mmd;
+ modifier_copyData_generic(md, target);
if (mmd->bindinfluences) tmmd->bindinfluences = MEM_dupallocN(mmd->bindinfluences);
if (mmd->bindoffsets) tmmd->bindoffsets = MEM_dupallocN(mmd->bindoffsets);
@@ -91,8 +89,8 @@ static void copyData(ModifierData *md, ModifierData *target)
if (mmd->dyngrid) tmmd->dyngrid = MEM_dupallocN(mmd->dyngrid);
if (mmd->dyninfluences) tmmd->dyninfluences = MEM_dupallocN(mmd->dyninfluences);
if (mmd->dynverts) tmmd->dynverts = MEM_dupallocN(mmd->dynverts);
- if (mmd->bindweights) tmmd->dynverts = MEM_dupallocN(mmd->bindweights); /* deprecated */
- if (mmd->bindcos) tmmd->dynverts = MEM_dupallocN(mmd->bindcos); /* deprecated */
+ if (mmd->bindweights) tmmd->bindweights = MEM_dupallocN(mmd->bindweights); /* deprecated */
+ if (mmd->bindcos) tmmd->bindcos = MEM_dupallocN(mmd->bindcos); /* deprecated */
}
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
@@ -119,24 +117,7 @@ static void foreachObjectLink(
{
MeshDeformModifierData *mmd = (MeshDeformModifierData *) md;
- walk(userData, ob, &mmd->object, IDWALK_NOP);
-}
-
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- DagNode *obNode)
-{
- MeshDeformModifierData *mmd = (MeshDeformModifierData *) md;
-
- if (mmd->object) {
- DagNode *curNode = dag_get_node(forest, mmd->object);
-
- dag_add_relation(forest, curNode, obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA | DAG_RL_DATA_OB | DAG_RL_OB_OB,
- "Mesh Deform Modifier");
- }
+ walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
}
static void updateDepsgraph(ModifierData *md,
@@ -534,7 +515,6 @@ ModifierTypeInfo modifierType_MeshDeform = {
/* 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 355ac9563dd..df13cadd184 100644
--- a/source/blender/modifiers/intern/MOD_meshsequencecache.c
+++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c
@@ -36,7 +36,6 @@
#include "BKE_library_query.h"
#include "BKE_scene.h"
-#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
#include "MOD_modifiertypes.h"
@@ -65,6 +64,7 @@ static void copyData(ModifierData *md, ModifierData *target)
if (tmcmd->cache_file) {
id_us_plus(&tmcmd->cache_file->id);
+ tmcmd->reader = NULL;
}
}
@@ -75,6 +75,13 @@ static void freeData(ModifierData *md)
if (mcmd->cache_file) {
id_us_min(&mcmd->cache_file->id);
}
+
+ if (mcmd->reader) {
+#ifdef WITH_ALEMBIC
+ CacheReader_free(mcmd->reader);
+#endif
+ mcmd->reader = NULL;
+ }
}
static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
@@ -102,10 +109,20 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
BKE_cachefile_ensure_handle(G.main, cache_file);
- DerivedMesh *result = ABC_read_mesh(cache_file->handle,
+ if (!mcmd->reader) {
+ mcmd->reader = CacheReader_open_alembic_object(cache_file->handle,
+ NULL,
+ ob,
+ mcmd->object_path);
+ if (!mcmd->reader) {
+ modifier_setError(md, "Could not create Alembic reader for file %s", cache_file->filepath);
+ return dm;
+ }
+ }
+
+ DerivedMesh *result = ABC_read_mesh(mcmd->reader,
ob,
dm,
- mcmd->object_path,
time,
&err_str,
mcmd->read_flag);
@@ -133,27 +150,10 @@ static void foreachIDLink(ModifierData *md, Object *ob,
{
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;
- walk(userData, ob, (ID **)&mcmd->cache_file, IDWALK_USER);
+ walk(userData, ob, (ID **)&mcmd->cache_file, IDWALK_CB_USER);
}
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *bmain,
- struct Scene *scene,
- Object *ob, DagNode *obNode)
-{
- MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;
-
- if (mcmd->cache_file != NULL) {
- DagNode *curNode = dag_get_node(forest, mcmd->cache_file);
-
- dag_add_relation(forest, curNode, obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Cache File Modifier");
- }
-
- UNUSED_VARS(bmain, scene, ob);
-}
-
static void updateDepsgraph(ModifierData *md,
struct Main *bmain,
struct Scene *scene,
@@ -187,7 +187,6 @@ ModifierTypeInfo modifierType_MeshSequenceCache = {
/* requiredDataMask */ NULL,
/* freeData */ freeData,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index 88facb22e0e..e0c37e8a0ce 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -45,7 +45,6 @@
#include "MEM_guardedalloc.h"
-#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
static void initData(ModifierData *md)
@@ -72,22 +71,7 @@ static void foreachObjectLink(
{
MirrorModifierData *mmd = (MirrorModifierData *) md;
- walk(userData, ob, &mmd->mirror_ob, IDWALK_NOP);
-}
-
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- DagNode *obNode)
-{
- MirrorModifierData *mmd = (MirrorModifierData *) md;
-
- if (mmd->mirror_ob) {
- DagNode *latNode = dag_get_node(forest, mmd->mirror_ob);
-
- dag_add_relation(forest, latNode, obNode, DAG_RL_OB_DATA, "Mirror Modifier");
- }
+ walk(userData, ob, &mmd->mirror_ob, IDWALK_CB_NOP);
}
static void updateDepsgraph(ModifierData *md,
@@ -274,8 +258,8 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
int j = maxLoops;
dmloopuv += j; /* second set of loops only */
for (; j-- > 0; dmloopuv++) {
- if (do_mirr_u) dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0];
- if (do_mirr_v) dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1];
+ if (do_mirr_u) dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0] + mmd->uv_offset[0];
+ if (do_mirr_v) dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1] + mmd->uv_offset[1];
}
}
}
@@ -375,7 +359,6 @@ ModifierTypeInfo modifierType_Mirror = {
/* 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 90ad1bdfdc2..aba184b7d40 100644
--- a/source/blender/modifiers/intern/MOD_multires.c
+++ b/source/blender/modifiers/intern/MOD_multires.c
@@ -161,7 +161,6 @@ ModifierTypeInfo modifierType_Multires = {
/* 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..3fb780f566d 100644
--- a/source/blender/modifiers/intern/MOD_none.c
+++ b/source/blender/modifiers/intern/MOD_none.c
@@ -67,7 +67,6 @@ ModifierTypeInfo modifierType_None = {
/* 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 ceb7dc02699..fa4d33f2e95 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.c
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -42,8 +42,6 @@
#include "BKE_mesh.h"
#include "BKE_deform.h"
-#include "depsgraph_private.h"
-
#include "MOD_util.h"
@@ -188,7 +186,7 @@ static bool polygons_check_flip(
}
static void normalEditModifier_do_radial(
- NormalEditModifierData *smd, Object *ob, DerivedMesh *dm,
+ NormalEditModifierData *enmd, Object *ob, DerivedMesh *dm,
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,
@@ -203,7 +201,7 @@ static void normalEditModifier_do_radial(
BLI_bitmap *done_verts = BLI_BITMAP_NEW((size_t)num_verts, __func__);
- generate_vert_coordinates(dm, ob, smd->target, smd->offset, num_verts, cos, size);
+ generate_vert_coordinates(dm, ob, enmd->target, enmd->offset, num_verts, cos, size);
/**
* size gives us our spheroid coefficients ``(A, B, C)``.
@@ -287,14 +285,14 @@ static void normalEditModifier_do_radial(
}
static void normalEditModifier_do_directional(
- NormalEditModifierData *smd, Object *ob, DerivedMesh *dm,
+ NormalEditModifierData *enmd, Object *ob, DerivedMesh *dm,
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,
MVert *mvert, const int num_verts, MEdge *medge, const int num_edges,
MLoop *mloop, const int num_loops, MPoly *mpoly, const int num_polys)
{
- const bool use_parallel_normals = (smd->flag & MOD_NORMALEDIT_USE_DIRECTION_PARALLEL) != 0;
+ const bool use_parallel_normals = (enmd->flag & MOD_NORMALEDIT_USE_DIRECTION_PARALLEL) != 0;
float (*cos)[3] = MEM_mallocN(sizeof(*cos) * num_verts, __func__);
float (*nos)[3] = MEM_mallocN(sizeof(*nos) * num_loops, __func__);
@@ -309,14 +307,14 @@ static void normalEditModifier_do_directional(
float mat[4][4];
invert_m4_m4(mat, ob->obmat);
- mul_m4_m4m4(mat, mat, smd->target->obmat);
+ mul_m4_m4m4(mat, mat, enmd->target->obmat);
copy_v3_v3(target_co, mat[3]);
}
if (use_parallel_normals) {
float no[3];
- sub_v3_v3v3(no, target_co, smd->offset);
+ sub_v3_v3v3(no, target_co, enmd->offset);
normalize_v3(no);
for (i = num_loops; i--; ) {
@@ -362,19 +360,19 @@ static void normalEditModifier_do_directional(
MEM_freeN(nos);
}
-static bool is_valid_target(NormalEditModifierData *smd)
+static bool is_valid_target(NormalEditModifierData *enmd)
{
- if (smd->mode == MOD_NORMALEDIT_MODE_RADIAL) {
+ if (enmd->mode == MOD_NORMALEDIT_MODE_RADIAL) {
return true;
}
- else if ((smd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) && smd->target) {
+ else if ((enmd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) && enmd->target) {
return true;
}
- modifier_setError((ModifierData *)smd, "Invalid target settings");
+ modifier_setError((ModifierData *)enmd, "Invalid target settings");
return false;
}
-static DerivedMesh *normalEditModifier_do(NormalEditModifierData *smd, Object *ob, DerivedMesh *dm)
+static DerivedMesh *normalEditModifier_do(NormalEditModifierData *enmd, Object *ob, DerivedMesh *dm)
{
Mesh *me = ob->data;
@@ -387,11 +385,11 @@ static DerivedMesh *normalEditModifier_do(NormalEditModifierData *smd, Object *o
MLoop *mloop;
MPoly *mpoly;
- const bool use_invert_vgroup = ((smd->flag & MOD_NORMALEDIT_INVERT_VGROUP) != 0);
- const bool use_current_clnors = !((smd->mix_mode == MOD_NORMALEDIT_MIX_COPY) &&
- (smd->mix_factor == 1.0f) &&
- (smd->defgrp_name[0] == '\0') &&
- (smd->mix_limit == (float)M_PI));
+ 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));
int defgrp_index;
MDeformVert *dvert;
@@ -403,12 +401,12 @@ static DerivedMesh *normalEditModifier_do(NormalEditModifierData *smd, Object *o
bool free_polynors = false;
/* Do not run that modifier at all if autosmooth is disabled! */
- if (!is_valid_target(smd) || !num_loops) {
+ if (!is_valid_target(enmd) || !num_loops) {
return dm;
}
if (!(me->flag & ME_AUTOSMOOTH)) {
- modifier_setError((ModifierData *)smd, "Enable 'Auto Smooth' option in mesh settings");
+ modifier_setError((ModifierData *)enmd, "Enable 'Auto Smooth' option in mesh settings");
return dm;
}
@@ -441,18 +439,18 @@ static DerivedMesh *normalEditModifier_do(NormalEditModifierData *smd, Object *o
free_polynors = true;
}
- modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index);
+ modifier_get_vgroup(ob, dm, enmd->defgrp_name, &dvert, &defgrp_index);
- if (smd->mode == MOD_NORMALEDIT_MODE_RADIAL) {
+ if (enmd->mode == MOD_NORMALEDIT_MODE_RADIAL) {
normalEditModifier_do_radial(
- smd, ob, dm, clnors, loopnors, polynors,
- smd->mix_mode, smd->mix_factor, smd->mix_limit, dvert, defgrp_index, use_invert_vgroup,
+ enmd, ob, dm, 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 (smd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) {
+ else if (enmd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) {
normalEditModifier_do_directional(
- smd, ob, dm, clnors, loopnors, polynors,
- smd->mix_mode, smd->mix_factor, smd->mix_limit, dvert, defgrp_index, use_invert_vgroup,
+ enmd, ob, dm, 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);
}
@@ -465,13 +463,13 @@ static DerivedMesh *normalEditModifier_do(NormalEditModifierData *smd, Object *o
static void initData(ModifierData *md)
{
- NormalEditModifierData *smd = (NormalEditModifierData *)md;
+ NormalEditModifierData *enmd = (NormalEditModifierData *)md;
- smd->mode = MOD_NORMALEDIT_MODE_RADIAL;
+ enmd->mode = MOD_NORMALEDIT_MODE_RADIAL;
- smd->mix_mode = MOD_NORMALEDIT_MIX_COPY;
- smd->mix_factor = 1.0f;
- smd->mix_limit = M_PI;
+ enmd->mix_mode = MOD_NORMALEDIT_MIX_COPY;
+ enmd->mix_factor = 1.0f;
+ enmd->mix_limit = M_PI;
}
static void copyData(ModifierData *md, ModifierData *target)
@@ -481,11 +479,11 @@ static void copyData(ModifierData *md, ModifierData *target)
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
{
- NormalEditModifierData *smd = (NormalEditModifierData *)md;
+ NormalEditModifierData *enmd = (NormalEditModifierData *)md;
CustomDataMask dataMask = CD_CUSTOMLOOPNORMAL;
/* Ask for vertexgroups if we need them. */
- if (smd->defgrp_name[0]) {
+ if (enmd->defgrp_name[0]) {
dataMask |= (CD_MASK_MDEFORMVERT);
}
@@ -499,30 +497,16 @@ static bool dependsOnNormals(ModifierData *UNUSED(md))
static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
{
- NormalEditModifierData *smd = (NormalEditModifierData *) md;
+ NormalEditModifierData *enmd = (NormalEditModifierData *) md;
- walk(userData, ob, &smd->target, IDWALK_NOP);
+ walk(userData, ob, &enmd->target, IDWALK_CB_NOP);
}
static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
{
- NormalEditModifierData *smd = (NormalEditModifierData *)md;
-
- return !is_valid_target(smd);
-}
+ NormalEditModifierData *enmd = (NormalEditModifierData *)md;
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob), DagNode *obNode)
-{
- NormalEditModifierData *smd = (NormalEditModifierData *) md;
-
- if (smd->target) {
- DagNode *Node = dag_get_node(forest, smd->target);
-
- dag_add_relation(forest, Node, obNode, DAG_RL_OB_DATA, "NormalEdit Modifier");
- }
+ return !is_valid_target(enmd);
}
static void updateDepsgraph(ModifierData *md,
@@ -531,9 +515,9 @@ static void updateDepsgraph(ModifierData *md,
Object *UNUSED(ob),
struct DepsNodeHandle *node)
{
- NormalEditModifierData *smd = (NormalEditModifierData *) md;
- if (smd->target) {
- DEG_add_object_relation(node, smd->target, DEG_OB_COMP_GEOMETRY, "NormalEdit Modifier");
+ NormalEditModifierData *enmd = (NormalEditModifierData *) md;
+ if (enmd->target) {
+ DEG_add_object_relation(node, enmd->target, DEG_OB_COMP_TRANSFORM, "NormalEdit Modifier");
}
}
@@ -562,7 +546,6 @@ ModifierTypeInfo modifierType_NormalEdit = {
/* 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 e77cc655c16..120337eb2ea 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -160,40 +160,19 @@ static void freeData(ModifierData *md)
static void copyData(ModifierData *md, ModifierData *target)
{
#ifdef WITH_OCEANSIM
+#if 0
OceanModifierData *omd = (OceanModifierData *) md;
+#endif
OceanModifierData *tomd = (OceanModifierData *) target;
- tomd->geometry_mode = omd->geometry_mode;
- tomd->resolution = omd->resolution;
- tomd->spatial_size = omd->spatial_size;
-
- tomd->wind_velocity = omd->wind_velocity;
-
- tomd->damp = omd->damp;
- tomd->smallest_wave = omd->smallest_wave;
- tomd->depth = omd->depth;
+ freeData(target);
- tomd->wave_alignment = omd->wave_alignment;
- tomd->wave_direction = omd->wave_direction;
- tomd->wave_scale = omd->wave_scale;
-
- tomd->chop_amount = omd->chop_amount;
- tomd->foam_coverage = omd->foam_coverage;
- tomd->time = omd->time;
-
- tomd->seed = omd->seed;
- tomd->flag = omd->flag;
+ modifier_copyData_generic(md, target);
tomd->refresh = 0;
- tomd->size = omd->size;
- tomd->repeat_x = omd->repeat_x;
- tomd->repeat_y = omd->repeat_y;
-
/* XXX todo: copy cache runtime too */
tomd->cached = 0;
- tomd->bakestart = omd->bakestart;
- tomd->bakeend = omd->bakeend;
tomd->oceancache = NULL;
tomd->ocean = BKE_ocean_add();
@@ -397,7 +376,6 @@ static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd)
/* 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 (gogd.mloopuvs) { /* unlikely to fail */
gogd.ix = 1.0 / gogd.rx;
@@ -597,7 +575,6 @@ ModifierTypeInfo modifierType_Ocean = {
/* 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 4e78e758dc3..316d51b9581 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -51,7 +51,6 @@
#include "BKE_particle.h"
#include "BKE_pointcache.h"
-#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
static void initData(ModifierData *md)
@@ -110,24 +109,6 @@ static bool isDisabled(ModifierData *md, int useRenderParams)
return false;
}
-
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- DagNode *obNode)
-{
- ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md;
-
- if (pimd->ob) {
- DagNode *curNode = dag_get_node(forest, pimd->ob);
-
- dag_add_relation(forest, curNode, obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA,
- "Particle Instance Modifier");
- }
-}
-
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
@@ -145,7 +126,7 @@ static void foreachObjectLink(ModifierData *md, Object *ob,
{
ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md;
- walk(userData, ob, &pimd->ob, IDWALK_NOP);
+ walk(userData, ob, &pimd->ob, IDWALK_CB_NOP);
}
static int particle_skip(ParticleInstanceModifierData *pimd, ParticleSystem *psys, int p)
@@ -460,7 +441,6 @@ ModifierTypeInfo modifierType_ParticleInstance = {
/* requiredDataMask */ NULL,
/* 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 d8cccca415c..a3b9d808b17 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.c
+++ b/source/blender/modifiers/intern/MOD_particlesystem.c
@@ -231,7 +231,6 @@ ModifierTypeInfo modifierType_ParticleSystem = {
/* 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 b85898c07e9..fb5c12399a4 100644
--- a/source/blender/modifiers/intern/MOD_remesh.c
+++ b/source/blender/modifiers/intern/MOD_remesh.c
@@ -231,7 +231,6 @@ ModifierTypeInfo modifierType_Remesh = {
/* 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 df94975e274..f62c68b56c9 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -46,7 +46,6 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_library_query.h"
-#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
#include "MOD_modifiertypes.h"
@@ -798,13 +797,11 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
if (ltmd->ob_axis) {
axis_angle_normalized_to_mat3(mat3, axis_vec, step_angle);
- copy_m4_m3(mat, mat3);
}
else {
- unit_m4(mat);
- rotate_m4(mat, axis_char, step_angle);
- copy_m3_m4(mat3, mat);
+ axis_angle_to_mat3_single(mat3, axis_char, step_angle);
}
+ copy_m4_m3(mat, mat3);
if (screw_ofs)
madd_v3_v3fl(mat[3], axis_vec, screw_ofs * ((float)step / (float)(step_tot - 1)));
@@ -1059,24 +1056,6 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
return result;
}
-
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- DagNode *obNode)
-{
- ScrewModifierData *ltmd = (ScrewModifierData *) md;
-
- if (ltmd->ob_axis) {
- DagNode *curNode = dag_get_node(forest, ltmd->ob_axis);
-
- dag_add_relation(forest, curNode, obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA,
- "Screw Modifier");
- }
-}
-
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
@@ -1095,7 +1074,7 @@ static void foreachObjectLink(
{
ScrewModifierData *ltmd = (ScrewModifierData *) md;
- walk(userData, ob, &ltmd->ob_axis, IDWALK_NOP);
+ walk(userData, ob, &ltmd->ob_axis, IDWALK_CB_NOP);
}
ModifierTypeInfo modifierType_Screw = {
@@ -1120,7 +1099,6 @@ ModifierTypeInfo modifierType_Screw = {
/* 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 97aae733532..6c8bd06c196 100644
--- a/source/blender/modifiers/intern/MOD_shapekey.c
+++ b/source/blender/modifiers/intern/MOD_shapekey.c
@@ -138,7 +138,6 @@ ModifierTypeInfo modifierType_ShapeKey = {
/* 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 633311c2b87..32241d8390a 100644
--- a/source/blender/modifiers/intern/MOD_shrinkwrap.c
+++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c
@@ -45,8 +45,6 @@
#include "BKE_modifier.h"
#include "BKE_shrinkwrap.h"
-#include "depsgraph_private.h"
-
#include "MOD_util.h"
static bool dependsOnNormals(ModifierData *md);
@@ -101,8 +99,8 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk,
{
ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *) md;
- walk(userData, ob, &smd->target, IDWALK_NOP);
- walk(userData, ob, &smd->auxTarget, IDWALK_NOP);
+ walk(userData, ob, &smd->target, IDWALK_CB_NOP);
+ walk(userData, ob, &smd->auxTarget, IDWALK_CB_NOP);
}
static void deformVerts(ModifierData *md, Object *ob,
@@ -143,23 +141,6 @@ static void deformVertsEM(ModifierData *md, Object *ob, struct BMEditMesh *editD
dm->release(dm);
}
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- DagNode *obNode)
-{
- ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *) md;
-
- if (smd->target)
- dag_add_relation(forest, dag_get_node(forest, smd->target), obNode,
- DAG_RL_OB_DATA | DAG_RL_DATA_DATA, "Shrinkwrap Modifier");
-
- if (smd->auxTarget)
- dag_add_relation(forest, dag_get_node(forest, smd->auxTarget), obNode,
- DAG_RL_OB_DATA | DAG_RL_DATA_DATA, "Shrinkwrap Modifier");
-}
-
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
@@ -209,7 +190,6 @@ ModifierTypeInfo modifierType_Shrinkwrap = {
/* 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 c68f2651191..4660afc0977 100644
--- a/source/blender/modifiers/intern/MOD_simpledeform.c
+++ b/source/blender/modifiers/intern/MOD_simpledeform.c
@@ -44,9 +44,6 @@
#include "BKE_modifier.h"
#include "BKE_deform.h"
-
-#include "depsgraph_private.h"
-
#include "MOD_util.h"
#define BEND_EPS 0.000001f
@@ -290,19 +287,7 @@ static void foreachObjectLink(
ObjectWalkFunc walk, void *userData)
{
SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md;
- walk(userData, ob, &smd->origin, IDWALK_NOP);
-}
-
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- DagNode *obNode)
-{
- SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md;
-
- if (smd->origin)
- dag_add_relation(forest, dag_get_node(forest, smd->origin), obNode, DAG_RL_OB_DATA, "SimpleDeform Modifier");
+ walk(userData, ob, &smd->origin, IDWALK_CB_NOP);
}
static void updateDepsgraph(ModifierData *md,
@@ -381,7 +366,6 @@ ModifierTypeInfo modifierType_SimpleDeform = {
/* 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 8ed623734be..4b84aeb335a 100644
--- a/source/blender/modifiers/intern/MOD_skin.c
+++ b/source/blender/modifiers/intern/MOD_skin.c
@@ -1950,7 +1950,6 @@ ModifierTypeInfo modifierType_Skin = {
/* 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 237d4cc6718..1b9e06bf0dc 100644
--- a/source/blender/modifiers/intern/MOD_smoke.c
+++ b/source/blender/modifiers/intern/MOD_smoke.c
@@ -47,13 +47,13 @@
#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_build.h"
static void initData(ModifierData *md)
@@ -109,7 +109,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
if (flag & MOD_APPLY_ORCO)
return dm;
- return smokeModifier_do(smd, md->scene, ob, dm);
+ return smokeModifier_do(smd, md->scene, BKE_scene_layer_context_active_PLACEHOLDER(md->scene), ob, dm);
}
static bool dependsOnTime(ModifierData *UNUSED(md))
@@ -117,219 +117,32 @@ static bool dependsOnTime(ModifierData *UNUSED(md))
return true;
}
-static void update_depsgraph_flow_coll_object(DagForest *forest,
- DagNode *obNode,
- Object *object2)
-{
- SmokeModifierData *smd;
- if ((object2->id.tag & LIB_TAG_DOIT) == 0) {
- return;
- }
- object2->id.tag &= ~LIB_TAG_DOIT;
- smd = (SmokeModifierData *)modifiers_findByType(object2, eModifierType_Smoke);
- if (smd && (((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) ||
- ((smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll)))
- {
- DagNode *curNode = dag_get_node(forest, object2);
- dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Smoke Flow/Coll");
- }
- if ((object2->transflag & OB_DUPLIGROUP) && object2->dup_group) {
- GroupObject *go;
- for (go = object2->dup_group->gobject.first;
- go != NULL;
- go = go->next)
- {
- if (go->ob == NULL) {
- continue;
- }
- update_depsgraph_flow_coll_object(forest, obNode, go->ob);
- }
- }
-}
-
-static void update_depsgraph_field_source_object(DagForest *forest,
- DagNode *obNode,
- Object *object,
- Object *object2)
-{
- if ((object2->id.tag & LIB_TAG_DOIT) == 0) {
- return;
- }
- object2->id.tag &= ~LIB_TAG_DOIT;
- if (object2->pd && object2->pd->forcefield == PFIELD_SMOKEFLOW && object2->pd->f_source == object) {
- DagNode *node2 = dag_get_node(forest, object2);
- dag_add_relation(forest, obNode, node2, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Field Source Object");
- }
- if ((object2->transflag & OB_DUPLIGROUP) && object2->dup_group) {
- GroupObject *go;
- for (go = object2->dup_group->gobject.first;
- go != NULL;
- go = go->next)
- {
- if (go->ob == NULL) {
- continue;
- }
- update_depsgraph_field_source_object(forest, obNode, object, go->ob);
- }
- }
-}
-
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *bmain,
- struct Scene *scene, struct Object *ob,
- DagNode *obNode)
+static bool is_flow_cb(Object *UNUSED(ob), ModifierData *md)
{
SmokeModifierData *smd = (SmokeModifierData *) md;
- Base *base;
-
- if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
- if (smd->domain->fluid_group || smd->domain->coll_group) {
- GroupObject *go = NULL;
-
- if (smd->domain->fluid_group)
- for (go = smd->domain->fluid_group->gobject.first; go; go = go->next) {
- if (go->ob) {
- SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(go->ob, eModifierType_Smoke);
-
- /* check for initialized smoke object */
- if (smd2 && (smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) {
- DagNode *curNode = dag_get_node(forest, go->ob);
- dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Smoke Flow");
- }
- }
- }
-
- if (smd->domain->coll_group)
- for (go = smd->domain->coll_group->gobject.first; go; go = go->next) {
- if (go->ob) {
- SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(go->ob, eModifierType_Smoke);
-
- /* check for initialized smoke object */
- if (smd2 && (smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll) {
- DagNode *curNode = dag_get_node(forest, go->ob);
- dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Smoke Coll");
- }
- }
- }
- }
- else {
- BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, true);
- base = scene->base.first;
- for (; base; base = base->next) {
- update_depsgraph_flow_coll_object(forest, obNode, base->object);
- }
- }
- /* add relation to all "smoke flow" force fields */
- base = scene->base.first;
- BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, true);
- for (; base; base = base->next) {
- update_depsgraph_field_source_object(forest, obNode, ob, base->object);
- }
- }
-}
-
-static void update_depsgraph_flow_coll_object_new(struct DepsNodeHandle *node,
- Object *object2)
-{
- SmokeModifierData *smd;
- if ((object2->id.tag & LIB_TAG_DOIT) == 0) {
- return;
- }
- object2->id.tag &= ~LIB_TAG_DOIT;
- smd = (SmokeModifierData *)modifiers_findByType(object2, eModifierType_Smoke);
- if (smd && (((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) ||
- ((smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll)))
- {
- DEG_add_object_relation(node, object2, DEG_OB_COMP_TRANSFORM, "Smoke Flow/Coll");
- DEG_add_object_relation(node, object2, DEG_OB_COMP_GEOMETRY, "Smoke Flow/Coll");
- }
- if ((object2->transflag & OB_DUPLIGROUP) && object2->dup_group) {
- GroupObject *go;
- for (go = object2->dup_group->gobject.first;
- go != NULL;
- go = go->next)
- {
- if (go->ob == NULL) {
- continue;
- }
- update_depsgraph_flow_coll_object_new(node, go->ob);
- }
- }
+ return (smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow;
}
-static void update_depsgraph_field_source_object_new(struct DepsNodeHandle *node,
- Object *object,
- Object *object2)
+static bool is_coll_cb(Object *UNUSED(ob), ModifierData *md)
{
- if ((object2->id.tag & LIB_TAG_DOIT) == 0) {
- return;
- }
- object2->id.tag &= ~LIB_TAG_DOIT;
- if (object2->pd && object2->pd->forcefield == PFIELD_SMOKEFLOW && object2->pd->f_source == object) {
- DEG_add_object_relation(node, object2, DEG_OB_COMP_TRANSFORM, "Field Source Object");
- DEG_add_object_relation(node, object2, DEG_OB_COMP_GEOMETRY, "Field Source Object");
- }
- if ((object2->transflag & OB_DUPLIGROUP) && object2->dup_group) {
- GroupObject *go;
- for (go = object2->dup_group->gobject.first;
- go != NULL;
- go = go->next)
- {
- if (go->ob == NULL) {
- continue;
- }
- update_depsgraph_field_source_object_new(node, object, go->ob);
- }
- }
+ SmokeModifierData *smd = (SmokeModifierData *) md;
+ return (smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll;
}
static void updateDepsgraph(ModifierData *md,
- struct Main *bmain,
+ struct Main *UNUSED(bmain),
struct Scene *scene,
Object *ob,
struct DepsNodeHandle *node)
{
SmokeModifierData *smd = (SmokeModifierData *)md;
- Base *base;
+
if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
- if (smd->domain->fluid_group || smd->domain->coll_group) {
- GroupObject *go = NULL;
- if (smd->domain->fluid_group != NULL) {
- for (go = smd->domain->fluid_group->gobject.first; go; go = go->next) {
- if (go->ob != NULL) {
- SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(go->ob, eModifierType_Smoke);
- /* Check for initialized smoke object. */
- if (smd2 && (smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) {
- DEG_add_object_relation(node, go->ob, DEG_OB_COMP_TRANSFORM, "Smoke Flow");
- }
- }
- }
- }
- if (smd->domain->coll_group != NULL) {
- for (go = smd->domain->coll_group->gobject.first; go; go = go->next) {
- if (go->ob != NULL) {
- SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(go->ob, eModifierType_Smoke);
- /* Check for initialized smoke object. */
- if (smd2 && (smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll) {
- DEG_add_object_relation(node, go->ob, DEG_OB_COMP_TRANSFORM, "Smoke Coll");
- }
- }
- }
- }
- }
- else {
- BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, true);
- base = scene->base.first;
- for (; base; base = base->next) {
- update_depsgraph_flow_coll_object_new(node, base->object);
- }
- }
- /* add relation to all "smoke flow" force fields */
- base = scene->base.first;
- BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, true);
- for (; base; base = base->next) {
- update_depsgraph_field_source_object_new(node, ob, base->object);
- }
+ /* Actual code uses get_collisionobjects */
+ DEG_add_collision_relations(node, scene, ob, smd->domain->fluid_group, eModifierType_Smoke, is_flow_cb, true, "Smoke Flow");
+ DEG_add_collision_relations(node, scene, ob, smd->domain->coll_group, eModifierType_Smoke, is_coll_cb, true, "Smoke Coll");
+
+ DEG_add_forcefield_relations(node, scene, ob, smd->domain->effector_weights, true, PFIELD_SMOKEFLOW, "Smoke Force Field");
}
}
@@ -339,17 +152,17 @@ static void foreachIDLink(ModifierData *md, Object *ob,
SmokeModifierData *smd = (SmokeModifierData *) md;
if (smd->type == MOD_SMOKE_TYPE_DOMAIN && smd->domain) {
- walk(userData, ob, (ID **)&smd->domain->coll_group, IDWALK_NOP);
- walk(userData, ob, (ID **)&smd->domain->fluid_group, IDWALK_NOP);
- walk(userData, ob, (ID **)&smd->domain->eff_group, IDWALK_NOP);
+ walk(userData, ob, (ID **)&smd->domain->coll_group, IDWALK_CB_NOP);
+ walk(userData, ob, (ID **)&smd->domain->fluid_group, IDWALK_CB_NOP);
+ walk(userData, ob, (ID **)&smd->domain->eff_group, IDWALK_CB_NOP);
if (smd->domain->effector_weights) {
- walk(userData, ob, (ID **)&smd->domain->effector_weights->group, IDWALK_NOP);
+ walk(userData, ob, (ID **)&smd->domain->effector_weights->group, IDWALK_CB_NOP);
}
}
if (smd->type == MOD_SMOKE_TYPE_FLOW && smd->flow) {
- walk(userData, ob, (ID **)&smd->flow->noise_texture, IDWALK_USER);
+ walk(userData, ob, (ID **)&smd->flow->noise_texture, IDWALK_CB_USER);
}
}
@@ -373,7 +186,6 @@ ModifierTypeInfo modifierType_Smoke = {
/* 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 d45c8528510..f0f20acb8ea 100644
--- a/source/blender/modifiers/intern/MOD_smooth.c
+++ b/source/blender/modifiers/intern/MOD_smooth.c
@@ -261,7 +261,6 @@ ModifierTypeInfo modifierType_Smooth = {
/* 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 98a1412d0c6..780a55aa631 100644
--- a/source/blender/modifiers/intern/MOD_softbody.c
+++ b/source/blender/modifiers/intern/MOD_softbody.c
@@ -35,13 +35,17 @@
#include <stdio.h>
#include "DNA_scene_types.h"
+#include "DNA_object_force.h"
#include "BLI_utildefines.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_layer.h"
#include "BKE_particle.h"
#include "BKE_softbody.h"
+#include "DEG_depsgraph_build.h"
+
#include "MOD_modifiertypes.h"
static void deformVerts(ModifierData *md, Object *ob,
@@ -50,7 +54,7 @@ static void deformVerts(ModifierData *md, Object *ob,
int numVerts,
ModifierApplyFlag UNUSED(flag))
{
- sbObjectStep(md->scene, ob, (float)md->scene->r.cfra, vertexCos, numVerts);
+ sbObjectStep(md->scene, BKE_scene_layer_context_active_PLACEHOLDER(md->scene), ob, (float)md->scene->r.cfra, vertexCos, numVerts);
}
static bool dependsOnTime(ModifierData *UNUSED(md))
@@ -58,6 +62,19 @@ static bool dependsOnTime(ModifierData *UNUSED(md))
return true;
}
+static void updateDepsgraph(ModifierData *UNUSED(md),
+ struct Main *UNUSED(bmain),
+ struct Scene *scene,
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ if (ob->soft) {
+ /* Actual code uses ccd_build_deflector_hash */
+ DEG_add_collision_relations(node, scene, ob, ob->soft->collision_group, eModifierType_Collision, NULL, false, "Softbody Collision");
+
+ DEG_add_forcefield_relations(node, scene, ob, ob->soft->effector_weights, true, 0, "Softbody Field");
+ }
+}
ModifierTypeInfo modifierType_Softbody = {
/* name */ "Softbody",
@@ -80,8 +97,7 @@ ModifierTypeInfo modifierType_Softbody = {
/* requiredDataMask */ NULL,
/* freeData */ NULL,
/* isDisabled */ NULL,
- /* updateDepgraph */ NULL,
- /* updateDepsgraph */ NULL,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index 911b6997058..e589cb7d713 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -973,7 +973,6 @@ ModifierTypeInfo modifierType_Solidify = {
/* 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 23ab61821f4..cee8dd301bf 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -46,10 +46,12 @@
#include "BKE_cdderivedmesh.h"
-#include "BKE_depsgraph.h"
#include "BKE_scene.h"
#include "BKE_subsurf.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "MOD_modifiertypes.h"
#include "intern/CCGSubSurf.h"
@@ -130,7 +132,11 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
if (U.opensubdiv_compute_type == USER_OPENSUBDIV_COMPUTE_NONE) {
modifier_setError(md, "OpenSubdiv is disabled in User Preferences");
}
- else if ((DAG_get_eval_flags_for_object(md->scene, ob) & DAG_EVAL_NEED_CPU) == 0) {
+ 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");
+ }
+ /* TODO(sergey): How do we get depsgraph here? */
+ else if ((DEG_get_eval_flags_for_id(md->scene->depsgraph_legacy, &ob->id) & DAG_EVAL_NEED_CPU) == 0) {
subsurf_flags |= SUBSURF_USE_GPU_BACKEND;
do_cddm_convert = false;
}
@@ -143,12 +149,16 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
result = subsurf_make_derived_from_derived(derivedData, smd, NULL, subsurf_flags);
result->cd_flag = derivedData->cd_flag;
- if (do_cddm_convert) {
+ {
DerivedMesh *cddm = CDDM_copy(result);
result->release(result);
result = cddm;
}
+#ifndef WITH_OPESUBDIV
+ (void) do_cddm_convert;
+#endif
+
return result;
}
@@ -208,7 +218,6 @@ ModifierTypeInfo modifierType_Subsurf = {
/* requiredDataMask */ NULL,
/* freeData */ freeData,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c
index 68987a1d28e..ea68f540236 100644
--- a/source/blender/modifiers/intern/MOD_surface.c
+++ b/source/blender/modifiers/intern/MOD_surface.c
@@ -172,6 +172,7 @@ ModifierTypeInfo modifierType_Surface = {
/* structSize */ sizeof(SurfaceModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsMesh |
+ eModifierTypeFlag_AcceptsCVs |
eModifierTypeFlag_NoUserAdd,
/* copyData */ NULL,
@@ -185,7 +186,6 @@ ModifierTypeInfo modifierType_Surface = {
/* 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
new file mode 100644
index 00000000000..9339d71524f
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_surfacedeform.c
@@ -0,0 +1,1213 @@
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_alloca.h"
+#include "BLI_math.h"
+#include "BLI_math_geom.h"
+#include "BLI_task.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_editmesh.h"
+#include "BKE_library_query.h"
+#include "BKE_modifier.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "MOD_util.h"
+
+typedef struct SDefAdjacency {
+ struct SDefAdjacency *next;
+ unsigned int index;
+} SDefAdjacency;
+
+typedef struct SDefAdjacencyArray {
+ SDefAdjacency *first;
+ unsigned int num; /* Careful, this is twice the number of polygons (avoids an extra loop) */
+} SDefAdjacencyArray;
+
+typedef struct SDefEdgePolys {
+ unsigned int polys[2], num;
+} SDefEdgePolys;
+
+typedef struct SDefBindCalcData {
+ BVHTreeFromMesh * const treeData;
+ const SDefAdjacencyArray * const vert_edges;
+ const SDefEdgePolys * const edge_polys;
+ SDefVert * const bind_verts;
+ const MLoopTri * const looptri;
+ const MPoly * const mpoly;
+ const MEdge * const medge;
+ const MLoop * const mloop;
+ float (* const targetCos)[3];
+ float (* const vertexCos)[3];
+ float imat[4][4];
+ const float falloff;
+ int success;
+} SDefBindCalcData;
+
+typedef struct SDefBindPoly {
+ float (*coords)[3];
+ float (*coords_v2)[2];
+ float point_v2[2];
+ float weight_angular;
+ float weight_dist_proj;
+ float weight_dist;
+ float weight;
+ float scales[2];
+ float centroid[3];
+ float centroid_v2[2];
+ float normal[3];
+ float cent_edgemid_vecs_v2[2][2];
+ float edgemid_angle;
+ float point_edgemid_angles[2];
+ float corner_edgemid_angles[2];
+ float dominant_angle_weight;
+ unsigned int index;
+ unsigned int numverts;
+ unsigned int loopstart;
+ unsigned int edge_inds[2];
+ unsigned int edge_vert_inds[2];
+ unsigned int corner_ind;
+ unsigned int dominant_edge;
+ bool inside;
+} SDefBindPoly;
+
+typedef struct SDefBindWeightData {
+ SDefBindPoly *bind_polys;
+ unsigned int numpoly;
+ unsigned int numbinds;
+} SDefBindWeightData;
+
+typedef struct SDefDeformData {
+ const SDefVert * const bind_verts;
+ float (* const targetCos)[3];
+ float (* const vertexCos)[3];
+} SDefDeformData;
+
+/* Bind result values */
+enum {
+ MOD_SDEF_BIND_RESULT_SUCCESS = 1,
+ MOD_SDEF_BIND_RESULT_GENERIC_ERR = 0,
+ MOD_SDEF_BIND_RESULT_MEM_ERR = -1,
+ MOD_SDEF_BIND_RESULT_NONMANY_ERR = -2,
+ MOD_SDEF_BIND_RESULT_CONCAVE_ERR = -3,
+ MOD_SDEF_BIND_RESULT_OVERLAP_ERR = -4,
+};
+
+/* Infinite weight flags */
+enum {
+ MOD_SDEF_INFINITE_WEIGHT_ANGULAR = (1 << 0),
+ MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ = (1 << 1),
+ MOD_SDEF_INFINITE_WEIGHT_DIST = (1 << 2),
+};
+
+static void initData(ModifierData *md)
+{
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
+ smd->target = NULL;
+ smd->verts = NULL;
+ smd->flags = 0;
+ smd->falloff = 4.0f;
+}
+
+static void freeData(ModifierData *md)
+{
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
+
+ if (smd->verts) {
+ for (int i = 0; i < smd->numverts; i++) {
+ if (smd->verts[i].binds) {
+ for (int j = 0; j < smd->verts[i].numbinds; j++) {
+ MEM_SAFE_FREE(smd->verts[i].binds[j].vert_inds);
+ MEM_SAFE_FREE(smd->verts[i].binds[j].vert_weights);
+ }
+
+ MEM_freeN(smd->verts[i].binds);
+ }
+ }
+
+ MEM_freeN(smd->verts);
+ smd->verts = NULL;
+ }
+}
+
+static void copyData(ModifierData *md, ModifierData *target)
+{
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
+ SurfaceDeformModifierData *tsmd = (SurfaceDeformModifierData *)target;
+
+ freeData(target);
+
+ modifier_copyData_generic(md, target);
+
+ if (smd->verts) {
+ tsmd->verts = MEM_dupallocN(smd->verts);
+
+ for (int i = 0; i < smd->numverts; i++) {
+ if (smd->verts[i].binds) {
+ tsmd->verts[i].binds = MEM_dupallocN(smd->verts[i].binds);
+
+ for (int j = 0; j < smd->verts[i].numbinds; j++) {
+ if (smd->verts[i].binds[j].vert_inds) {
+ tsmd->verts[i].binds[j].vert_inds = MEM_dupallocN(smd->verts[i].binds[j].vert_inds);
+ }
+
+ if (smd->verts[i].binds[j].vert_weights) {
+ tsmd->verts[i].binds[j].vert_weights = MEM_dupallocN(smd->verts[i].binds[j].vert_weights);
+ }
+ }
+ }
+ }
+ }
+}
+
+static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
+{
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
+
+ walk(userData, ob, &smd->target, IDWALK_NOP);
+}
+
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
+ if (smd->target != NULL) {
+ DEG_add_object_relation(node, smd->target, DEG_OB_COMP_GEOMETRY, "Surface Deform Modifier");
+ }
+}
+
+static void freeAdjacencyMap(SDefAdjacencyArray * const vert_edges, SDefAdjacency * const adj_ref, SDefEdgePolys * const edge_polys)
+{
+ MEM_freeN(edge_polys);
+
+ MEM_freeN(adj_ref);
+
+ MEM_freeN(vert_edges);
+}
+
+static int buildAdjacencyMap(const MPoly *poly, const MEdge *edge, const MLoop * const mloop, const unsigned int numpoly, const unsigned int numedges,
+ SDefAdjacencyArray * const vert_edges, SDefAdjacency *adj, SDefEdgePolys * const edge_polys)
+{
+ const MLoop *loop;
+
+ /* Fing polygons adjacent to edges */
+ for (int i = 0; i < numpoly; i++, poly++) {
+ loop = &mloop[poly->loopstart];
+
+ for (int j = 0; j < poly->totloop; j++, loop++) {
+ if (edge_polys[loop->e].num == 0) {
+ edge_polys[loop->e].polys[0] = i;
+ edge_polys[loop->e].polys[1] = -1;
+ edge_polys[loop->e].num++;
+ }
+ else if (edge_polys[loop->e].num == 1) {
+ edge_polys[loop->e].polys[1] = i;
+ edge_polys[loop->e].num++;
+ }
+ else {
+ return MOD_SDEF_BIND_RESULT_NONMANY_ERR;
+ }
+ }
+ }
+
+ /* Find edges adjacent to vertices */
+ for (int i = 0; i < numedges; i++, edge++) {
+ adj->next = vert_edges[edge->v1].first;
+ adj->index = i;
+ vert_edges[edge->v1].first = adj;
+ vert_edges[edge->v1].num += edge_polys[i].num;
+ adj++;
+
+ adj->next = vert_edges[edge->v2].first;
+ adj->index = i;
+ vert_edges[edge->v2].first = adj;
+ vert_edges[edge->v2].num += edge_polys[i].num;
+ adj++;
+ }
+
+ return MOD_SDEF_BIND_RESULT_SUCCESS;
+}
+
+BLI_INLINE void sortPolyVertsEdge(unsigned int *indices, const MLoop * const mloop, const unsigned int edge, const unsigned int num)
+{
+ bool found = false;
+
+ for (int i = 0; i < num; i++) {
+ if (mloop[i].e == edge) {
+ found = true;
+ }
+ if (found) {
+ *indices = mloop[i].v;
+ indices++;
+ }
+ }
+
+ /* Fill in remaining vertex indices that occur before the edge */
+ for (int i = 0; mloop[i].e != edge; i++) {
+ *indices = mloop[i].v;
+ indices++;
+ }
+}
+
+BLI_INLINE void sortPolyVertsTri(unsigned int *indices, const MLoop * const mloop, const unsigned int loopstart, const unsigned int num)
+{
+ for (int i = loopstart; i < num; i++) {
+ *indices = mloop[i].v;
+ indices++;
+ }
+
+ for (int i = 0; i < loopstart; i++) {
+ *indices = mloop[i].v;
+ indices++;
+ }
+}
+
+BLI_INLINE unsigned int nearestVert(SDefBindCalcData * const data, const float point_co[3])
+{
+ BVHTreeNearest nearest = {.dist_sq = FLT_MAX, .index = -1};
+ const MPoly *poly;
+ const MEdge *edge;
+ const MLoop *loop;
+ float t_point[3];
+ float max_dist = FLT_MAX;
+ float dist;
+ unsigned int index = 0;
+
+ mul_v3_m4v3(t_point, data->imat, point_co);
+
+ BLI_bvhtree_find_nearest(data->treeData->tree, t_point, &nearest, data->treeData->nearest_callback, data->treeData);
+
+ poly = &data->mpoly[data->looptri[nearest.index].poly];
+ loop = &data->mloop[poly->loopstart];
+
+ for (int i = 0; i < poly->totloop; i++, loop++) {
+ edge = &data->medge[loop->e];
+ dist = dist_squared_to_line_segment_v3(point_co, data->targetCos[edge->v1], data->targetCos[edge->v2]);
+
+ if (dist < max_dist) {
+ max_dist = dist;
+ index = loop->e;
+ }
+ }
+
+ edge = &data->medge[index];
+ if (len_squared_v3v3(point_co, data->targetCos[edge->v1]) < len_squared_v3v3(point_co, data->targetCos[edge->v2])) {
+ return edge->v1;
+ }
+ else {
+ return edge->v2;
+ }
+}
+
+BLI_INLINE int isPolyValid(const float coords[][2], const unsigned int nr)
+{
+ float prev_co[2];
+ float curr_vec[2], prev_vec[2];
+
+ if (!is_poly_convex_v2(coords, nr)) {
+ return MOD_SDEF_BIND_RESULT_CONCAVE_ERR;
+ }
+
+ copy_v2_v2(prev_co, coords[nr - 1]);
+ sub_v2_v2v2(prev_vec, prev_co, coords[nr - 2]);
+
+ for (int i = 0; i < nr; i++) {
+ sub_v2_v2v2(curr_vec, coords[i], prev_co);
+
+ if (len_squared_v2(curr_vec) < FLT_EPSILON) {
+ return MOD_SDEF_BIND_RESULT_OVERLAP_ERR;
+ }
+
+ if (1.0f - dot_v2v2(prev_vec, curr_vec) < FLT_EPSILON) {
+ return MOD_SDEF_BIND_RESULT_CONCAVE_ERR;
+ }
+
+ copy_v2_v2(prev_co, coords[i]);
+ copy_v2_v2(prev_vec, curr_vec);
+ }
+
+ return MOD_SDEF_BIND_RESULT_SUCCESS;
+}
+
+static void freeBindData(SDefBindWeightData * const bwdata)
+{
+ SDefBindPoly *bpoly = bwdata->bind_polys;
+
+ if (bwdata->bind_polys) {
+ for (int i = 0; i < bwdata->numpoly; bpoly++, i++) {
+ MEM_SAFE_FREE(bpoly->coords);
+ MEM_SAFE_FREE(bpoly->coords_v2);
+ }
+
+ MEM_freeN(bwdata->bind_polys);
+ }
+
+ MEM_freeN(bwdata);
+}
+
+BLI_INLINE float computeAngularWeight(const float point_angle, const float edgemid_angle)
+{
+ float weight;
+
+ weight = point_angle;
+ weight /= edgemid_angle;
+ weight *= M_PI_2;
+
+ return sinf(weight);
+}
+
+BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData * const data, const float point_co[3])
+{
+ const unsigned int nearest = nearestVert(data, point_co);
+ const SDefAdjacency * const vert_edges = data->vert_edges[nearest].first;
+ const SDefEdgePolys * const edge_polys = data->edge_polys;
+
+ const SDefAdjacency *vedge;
+ const MPoly *poly;
+ const MLoop *loop;
+
+ SDefBindWeightData *bwdata;
+ SDefBindPoly *bpoly;
+
+ float world[3] = {0.0f, 0.0f, 1.0f};
+ float avg_point_dist = 0.0f;
+ float tot_weight = 0.0f;
+ int inf_weight_flags = 0;
+
+ bwdata = MEM_callocN(sizeof(*bwdata), "SDefBindWeightData");
+ if (bwdata == NULL) {
+ data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
+ return NULL;
+ }
+
+ bwdata->numpoly = data->vert_edges[nearest].num / 2;
+
+ bpoly = MEM_callocN(sizeof(*bpoly) * bwdata->numpoly, "SDefBindPoly");
+ if (bpoly == NULL) {
+ freeBindData(bwdata);
+ data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
+ return NULL;
+ }
+
+ bwdata->bind_polys = bpoly;
+
+ /* Loop over all adjacent edges, and build the SDefBindPoly data for each poly adjacent to those */
+ for (vedge = vert_edges; vedge; vedge = vedge->next) {
+ unsigned int edge_ind = vedge->index;
+
+ for (int i = 0; i < edge_polys[edge_ind].num; i++) {
+ {
+ bpoly = bwdata->bind_polys;
+
+ for (int j = 0; j < bwdata->numpoly; bpoly++, j++) {
+ /* If coords isn't allocated, we have reached the first uninitialized bpoly */
+ if ((bpoly->index == edge_polys[edge_ind].polys[i]) || (!bpoly->coords)) {
+ break;
+ }
+ }
+ }
+
+ /* Check if poly was already created by another edge or still has to be initialized */
+ if (!bpoly->coords) {
+ float angle;
+ float axis[3];
+ float tmp_vec_v2[2];
+ int is_poly_valid;
+
+ bpoly->index = edge_polys[edge_ind].polys[i];
+ bpoly->coords = NULL;
+ bpoly->coords_v2 = NULL;
+
+ /* Copy poly data */
+ poly = &data->mpoly[bpoly->index];
+ loop = &data->mloop[poly->loopstart];
+
+ bpoly->numverts = poly->totloop;
+ bpoly->loopstart = poly->loopstart;
+
+ bpoly->coords = MEM_mallocN(sizeof(*bpoly->coords) * poly->totloop, "SDefBindPolyCoords");
+ if (bpoly->coords == NULL) {
+ freeBindData(bwdata);
+ data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
+ return NULL;
+ }
+
+ bpoly->coords_v2 = MEM_mallocN(sizeof(*bpoly->coords_v2) * poly->totloop, "SDefBindPolyCoords_v2");
+ if (bpoly->coords_v2 == NULL) {
+ freeBindData(bwdata);
+ data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
+ return NULL;
+ }
+
+ for (int j = 0; j < poly->totloop; j++, loop++) {
+ copy_v3_v3(bpoly->coords[j], data->targetCos[loop->v]);
+
+ /* Find corner and edge indices within poly loop array */
+ if (loop->v == nearest) {
+ bpoly->corner_ind = j;
+ bpoly->edge_vert_inds[0] = (j == 0) ? (poly->totloop - 1) : (j - 1);
+ bpoly->edge_vert_inds[1] = (j == poly->totloop - 1) ? (0) : (j + 1);
+
+ bpoly->edge_inds[0] = data->mloop[poly->loopstart + bpoly->edge_vert_inds[0]].e;
+ bpoly->edge_inds[1] = loop->e;
+ }
+ }
+
+ /* Compute poly's parametric data */
+ mid_v3_v3_array(bpoly->centroid, bpoly->coords, poly->totloop);
+ normal_poly_v3(bpoly->normal, bpoly->coords, poly->totloop);
+
+ /* Compute poly skew angle and axis */
+ angle = angle_normalized_v3v3(bpoly->normal, world);
+
+ cross_v3_v3v3(axis, bpoly->normal, world);
+ normalize_v3(axis);
+
+ /* Map coords onto 2d normal plane */
+ map_to_plane_axis_angle_v2_v3v3fl(bpoly->point_v2, point_co, axis, angle);
+
+ zero_v2(bpoly->centroid_v2);
+ for (int j = 0; j < poly->totloop; j++) {
+ map_to_plane_axis_angle_v2_v3v3fl(bpoly->coords_v2[j], bpoly->coords[j], axis, angle);
+ madd_v2_v2fl(bpoly->centroid_v2, bpoly->coords_v2[j], 1.0f / poly->totloop);
+ }
+
+ is_poly_valid = isPolyValid(bpoly->coords_v2, poly->totloop);
+
+ if (is_poly_valid != MOD_SDEF_BIND_RESULT_SUCCESS) {
+ freeBindData(bwdata);
+ data->success = is_poly_valid;
+ return NULL;
+ }
+
+ bpoly->inside = isect_point_poly_v2(bpoly->point_v2, bpoly->coords_v2, poly->totloop, false);
+
+ /* Initialize weight components */
+ bpoly->weight_angular = 1.0f;
+ bpoly->weight_dist_proj = len_v2v2(bpoly->centroid_v2, bpoly->point_v2);
+ bpoly->weight_dist = len_v3v3(bpoly->centroid, point_co);
+
+ avg_point_dist += bpoly->weight_dist;
+
+ /* Compute centroid to mid-edge vectors */
+ mid_v2_v2v2(bpoly->cent_edgemid_vecs_v2[0],
+ bpoly->coords_v2[bpoly->edge_vert_inds[0]],
+ bpoly->coords_v2[bpoly->corner_ind]);
+
+ mid_v2_v2v2(bpoly->cent_edgemid_vecs_v2[1],
+ bpoly->coords_v2[bpoly->edge_vert_inds[1]],
+ bpoly->coords_v2[bpoly->corner_ind]);
+
+ sub_v2_v2(bpoly->cent_edgemid_vecs_v2[0], bpoly->centroid_v2);
+ sub_v2_v2(bpoly->cent_edgemid_vecs_v2[1], bpoly->centroid_v2);
+
+ /* Compute poly scales with respect to mid-edges, and normalize the vectors */
+ bpoly->scales[0] = normalize_v2(bpoly->cent_edgemid_vecs_v2[0]);
+ bpoly->scales[1] = normalize_v2(bpoly->cent_edgemid_vecs_v2[1]);
+
+ /* Compute the required polygon angles */
+ bpoly->edgemid_angle = angle_normalized_v2v2(bpoly->cent_edgemid_vecs_v2[0], bpoly->cent_edgemid_vecs_v2[1]);
+
+ sub_v2_v2v2(tmp_vec_v2, bpoly->coords_v2[bpoly->corner_ind], bpoly->centroid_v2);
+ normalize_v2(tmp_vec_v2);
+
+ bpoly->corner_edgemid_angles[0] = angle_normalized_v2v2(tmp_vec_v2, bpoly->cent_edgemid_vecs_v2[0]);
+ bpoly->corner_edgemid_angles[1] = angle_normalized_v2v2(tmp_vec_v2, bpoly->cent_edgemid_vecs_v2[1]);
+
+ /* Check for inifnite weights, and compute angular data otherwise */
+ if (bpoly->weight_dist < FLT_EPSILON) {
+ inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ;
+ inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST;
+ }
+ else if (bpoly->weight_dist_proj < FLT_EPSILON) {
+ inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ;
+ }
+ else {
+ float cent_point_vec[2];
+
+ sub_v2_v2v2(cent_point_vec, bpoly->point_v2, bpoly->centroid_v2);
+ normalize_v2(cent_point_vec);
+
+ bpoly->point_edgemid_angles[0] = angle_normalized_v2v2(cent_point_vec, bpoly->cent_edgemid_vecs_v2[0]);
+ bpoly->point_edgemid_angles[1] = angle_normalized_v2v2(cent_point_vec, bpoly->cent_edgemid_vecs_v2[1]);
+ }
+ }
+ }
+ }
+
+ avg_point_dist /= bwdata->numpoly;
+
+ /* If weights 1 and 2 are not infinite, loop over all adjacent edges again,
+ * and build adjacency dependent angle data (depends on all polygons having been computed) */
+ if (!inf_weight_flags) {
+ for (vedge = vert_edges; vedge; vedge = vedge->next) {
+ SDefBindPoly *bpolys[2];
+ const SDefEdgePolys *epolys;
+ float ang_weights[2];
+ unsigned int edge_ind = vedge->index;
+ unsigned int edge_on_poly[2];
+
+ epolys = &edge_polys[edge_ind];
+
+ /* Find bind polys corresponding to the edge's adjacent polys */
+ bpoly = bwdata->bind_polys;
+
+ for (int i = 0, j = 0; (i < bwdata->numpoly) && (j < epolys->num); bpoly++, i++) {
+ if (ELEM(bpoly->index, epolys->polys[0], epolys->polys[1])) {
+ bpolys[j] = bpoly;
+
+ if (bpoly->edge_inds[0] == edge_ind) {
+ edge_on_poly[j] = 0;
+ }
+ else {
+ edge_on_poly[j] = 1;
+ }
+
+ j++;
+ }
+ }
+
+ /* Compute angular weight component */
+ if (epolys->num == 1) {
+ ang_weights[0] = computeAngularWeight(bpolys[0]->point_edgemid_angles[edge_on_poly[0]], bpolys[0]->edgemid_angle);
+ bpolys[0]->weight_angular *= ang_weights[0] * ang_weights[0];
+ }
+ else if (epolys->num == 2) {
+ ang_weights[0] = computeAngularWeight(bpolys[0]->point_edgemid_angles[edge_on_poly[0]], bpolys[0]->edgemid_angle);
+ ang_weights[1] = computeAngularWeight(bpolys[1]->point_edgemid_angles[edge_on_poly[1]], bpolys[1]->edgemid_angle);
+
+ bpolys[0]->weight_angular *= ang_weights[0] * ang_weights[1];
+ bpolys[1]->weight_angular *= ang_weights[0] * ang_weights[1];
+ }
+ }
+ }
+
+ /* Compute scalings and falloff.
+ * Scale all weights if no infinite weight is found,
+ * scale only unprojected weight if projected weight is infinite,
+ * scale none if both are infinite. */
+ if (!inf_weight_flags) {
+ bpoly = bwdata->bind_polys;
+
+ for (int i = 0; i < bwdata->numpoly; bpoly++, i++) {
+ float corner_angle_weights[2];
+ float scale_weight, sqr, inv_sqr;
+
+ corner_angle_weights[0] = bpoly->point_edgemid_angles[0] / bpoly->corner_edgemid_angles[0];
+ corner_angle_weights[1] = bpoly->point_edgemid_angles[1] / bpoly->corner_edgemid_angles[1];
+
+ if (isnan(corner_angle_weights[0]) || isnan(corner_angle_weights[1])) {
+ freeBindData(bwdata);
+ data->success = MOD_SDEF_BIND_RESULT_GENERIC_ERR;
+ return NULL;
+ }
+
+ /* Find which edge the point is closer to */
+ if (corner_angle_weights[0] < corner_angle_weights[1]) {
+ bpoly->dominant_edge = 0;
+ bpoly->dominant_angle_weight = corner_angle_weights[0];
+ }
+ else {
+ bpoly->dominant_edge = 1;
+ bpoly->dominant_angle_weight = corner_angle_weights[1];
+ }
+
+ bpoly->dominant_angle_weight = sinf(bpoly->dominant_angle_weight * M_PI_2);
+
+ /* Compute quadratic angular scale interpolation weight */
+ scale_weight = bpoly->point_edgemid_angles[bpoly->dominant_edge] / bpoly->edgemid_angle;
+ scale_weight /= scale_weight + (bpoly->point_edgemid_angles[!bpoly->dominant_edge] / bpoly->edgemid_angle);
+
+ sqr = scale_weight * scale_weight;
+ inv_sqr = 1.0f - scale_weight;
+ inv_sqr *= inv_sqr;
+ scale_weight = sqr / (sqr + inv_sqr);
+
+ /* Compute interpolated scale (no longer need the individual scales,
+ * so simply storing the result over the scale in index zero) */
+ bpoly->scales[0] = bpoly->scales[bpoly->dominant_edge] * (1.0f - scale_weight) +
+ bpoly->scales[!bpoly->dominant_edge] * scale_weight;
+
+ /* Scale the point distance weights, and introduce falloff */
+ bpoly->weight_dist_proj /= bpoly->scales[0];
+ bpoly->weight_dist_proj = powf(bpoly->weight_dist_proj, data->falloff);
+
+ bpoly->weight_dist /= avg_point_dist;
+ bpoly->weight_dist = powf(bpoly->weight_dist, data->falloff);
+
+ /* Re-check for infinite weights, now that all scalings and interpolations are computed */
+ if (bpoly->weight_dist < FLT_EPSILON) {
+ inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ;
+ inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST;
+ }
+ else if (bpoly->weight_dist_proj < FLT_EPSILON) {
+ inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ;
+ }
+ else if (bpoly->weight_angular < FLT_EPSILON) {
+ inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_ANGULAR;
+ }
+ }
+ }
+ else if (!(inf_weight_flags & MOD_SDEF_INFINITE_WEIGHT_DIST)) {
+ bpoly = bwdata->bind_polys;
+
+ for (int i = 0; i < bwdata->numpoly; bpoly++, i++) {
+ /* Scale the point distance weight by average point distance, and introduce falloff */
+ bpoly->weight_dist /= avg_point_dist;
+ bpoly->weight_dist = powf(bpoly->weight_dist, data->falloff);
+
+ /* Re-check for infinite weights, now that all scalings and interpolations are computed */
+ if (bpoly->weight_dist < FLT_EPSILON) {
+ inf_weight_flags |= MOD_SDEF_INFINITE_WEIGHT_DIST;
+ }
+ }
+ }
+
+ /* Final loop, to compute actual weights */
+ bpoly = bwdata->bind_polys;
+
+ for (int i = 0; i < bwdata->numpoly; bpoly++, i++) {
+ /* Weight computation from components */
+ if (inf_weight_flags & MOD_SDEF_INFINITE_WEIGHT_DIST) {
+ bpoly->weight = bpoly->weight_dist < FLT_EPSILON ? 1.0f : 0.0f;
+ }
+ else if (inf_weight_flags & MOD_SDEF_INFINITE_WEIGHT_DIST_PROJ) {
+ bpoly->weight = bpoly->weight_dist_proj < FLT_EPSILON ?
+ 1.0f / bpoly->weight_dist : 0.0f;
+ }
+ else if (inf_weight_flags & MOD_SDEF_INFINITE_WEIGHT_ANGULAR) {
+ bpoly->weight = bpoly->weight_angular < FLT_EPSILON ?
+ 1.0f / bpoly->weight_dist_proj / bpoly->weight_dist : 0.0f;
+ }
+ else {
+ bpoly->weight = 1.0f / bpoly->weight_angular /
+ bpoly->weight_dist_proj /
+ bpoly->weight_dist;
+ }
+
+ tot_weight += bpoly->weight;
+ }
+
+ bpoly = bwdata->bind_polys;
+
+ for (int i = 0; i < bwdata->numpoly; bpoly++, i++) {
+ bpoly->weight /= tot_weight;
+
+ /* Evaluate if this poly is relevant to bind */
+ /* Even though the weights should add up to 1.0,
+ * the losses of weights smaller than epsilon here
+ * should be negligible... */
+ if (bpoly->weight >= FLT_EPSILON) {
+ if (bpoly->inside) {
+ bwdata->numbinds += 1;
+ }
+ else {
+ if (bpoly->dominant_angle_weight < FLT_EPSILON || 1.0f - bpoly->dominant_angle_weight < FLT_EPSILON) {
+ bwdata->numbinds += 1;
+ }
+ else {
+ bwdata->numbinds += 2;
+ }
+ }
+ }
+ }
+
+ return bwdata;
+}
+
+BLI_INLINE float computeNormalDisplacement(const float point_co[3], const float point_co_proj[3], const float normal[3])
+{
+ float disp_vec[3];
+ float normal_dist;
+
+ sub_v3_v3v3(disp_vec, point_co, point_co_proj);
+ normal_dist = len_v3(disp_vec);
+
+ if (dot_v3v3(disp_vec, normal) < 0) {
+ normal_dist *= -1;
+ }
+
+ return normal_dist;
+}
+
+static void bindVert(void *userdata, void *UNUSED(userdata_chunk), const int index, const int UNUSED(threadid))
+{
+ SDefBindCalcData * const data = (SDefBindCalcData *)userdata;
+ float point_co[3];
+ float point_co_proj[3];
+
+ SDefBindWeightData *bwdata;
+ SDefVert *sdvert = data->bind_verts + index;
+ SDefBindPoly *bpoly;
+ SDefBind *sdbind;
+
+ if (data->success != MOD_SDEF_BIND_RESULT_SUCCESS) {
+ sdvert->binds = NULL;
+ sdvert->numbinds = 0;
+ return;
+ }
+
+ copy_v3_v3(point_co, data->vertexCos[index]);
+ bwdata = computeBindWeights(data, point_co);
+
+ if (bwdata == NULL) {
+ sdvert->binds = NULL;
+ sdvert->numbinds = 0;
+ return;
+ }
+
+ sdvert->binds = MEM_callocN(sizeof(*sdvert->binds) * bwdata->numbinds, "SDefVertBindData");
+ if (sdvert->binds == NULL) {
+ data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
+ sdvert->numbinds = 0;
+ return;
+ }
+
+ sdvert->numbinds = bwdata->numbinds;
+
+ sdbind = sdvert->binds;
+
+ bpoly = bwdata->bind_polys;
+
+ for (int i = 0; i < bwdata->numbinds; bpoly++) {
+ if (bpoly->weight >= FLT_EPSILON) {
+ if (bpoly->inside) {
+ const MLoop *loop = &data->mloop[bpoly->loopstart];
+
+ sdbind->influence = bpoly->weight;
+ sdbind->numverts = bpoly->numverts;
+
+ sdbind->mode = MOD_SDEF_MODE_NGON;
+ sdbind->vert_weights = MEM_mallocN(sizeof(*sdbind->vert_weights) * bpoly->numverts, "SDefNgonVertWeights");
+ if (sdbind->vert_weights == NULL) {
+ data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
+ return;
+ }
+
+ sdbind->vert_inds = MEM_mallocN(sizeof(*sdbind->vert_inds) * bpoly->numverts, "SDefNgonVertInds");
+ if (sdbind->vert_inds == NULL) {
+ data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
+ return;
+ }
+
+ interp_weights_poly_v2(sdbind->vert_weights, bpoly->coords_v2, bpoly->numverts, bpoly->point_v2);
+
+ /* Reproject vert based on weights and original poly verts, to reintroduce poly non-planarity */
+ zero_v3(point_co_proj);
+ for (int j = 0; j < bpoly->numverts; j++, loop++) {
+ madd_v3_v3fl(point_co_proj, bpoly->coords[j], sdbind->vert_weights[j]);
+ sdbind->vert_inds[j] = loop->v;
+ }
+
+ sdbind->normal_dist = computeNormalDisplacement(point_co, point_co_proj, bpoly->normal);
+
+ sdbind++;
+ i++;
+ }
+ else {
+ float tmp_vec[3];
+ float cent[3], norm[3];
+ float v1[3], v2[3], v3[3];
+
+ if (1.0f - bpoly->dominant_angle_weight >= FLT_EPSILON) {
+ sdbind->influence = bpoly->weight * (1.0f - bpoly->dominant_angle_weight);
+ sdbind->numverts = bpoly->numverts;
+
+ sdbind->mode = MOD_SDEF_MODE_CENTROID;
+ sdbind->vert_weights = MEM_mallocN(sizeof(*sdbind->vert_weights) * 3, "SDefCentVertWeights");
+ if (sdbind->vert_weights == NULL) {
+ data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
+ return;
+ }
+
+ sdbind->vert_inds = MEM_mallocN(sizeof(*sdbind->vert_inds) * bpoly->numverts, "SDefCentVertInds");
+ if (sdbind->vert_inds == NULL) {
+ data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
+ return;
+ }
+
+ sortPolyVertsEdge(sdbind->vert_inds, &data->mloop[bpoly->loopstart],
+ bpoly->edge_inds[bpoly->dominant_edge], bpoly->numverts);
+
+ copy_v3_v3(v1, data->targetCos[sdbind->vert_inds[0]]);
+ copy_v3_v3(v2, data->targetCos[sdbind->vert_inds[1]]);
+ copy_v3_v3(v3, bpoly->centroid);
+
+ mid_v3_v3v3v3(cent, v1, v2, v3);
+ normal_tri_v3(norm, v1, v2, v3);
+
+ add_v3_v3v3(tmp_vec, point_co, bpoly->normal);
+
+ /* We are sure the line is not parallel to the plane.
+ * Checking return value just to avoid warning... */
+ if (!isect_line_plane_v3(point_co_proj, point_co, tmp_vec, cent, norm)) {
+ BLI_assert(false);
+ }
+
+ interp_weights_tri_v3(sdbind->vert_weights, v1, v2, v3, point_co_proj);
+
+ sdbind->normal_dist = computeNormalDisplacement(point_co, point_co_proj, bpoly->normal);
+
+ sdbind++;
+ i++;
+ }
+
+ if (bpoly->dominant_angle_weight >= FLT_EPSILON) {
+ sdbind->influence = bpoly->weight * bpoly->dominant_angle_weight;
+ sdbind->numverts = bpoly->numverts;
+
+ sdbind->mode = MOD_SDEF_MODE_LOOPTRI;
+ sdbind->vert_weights = MEM_mallocN(sizeof(*sdbind->vert_weights) * 3, "SDefTriVertWeights");
+ if (sdbind->vert_weights == NULL) {
+ data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
+ return;
+ }
+
+ sdbind->vert_inds = MEM_mallocN(sizeof(*sdbind->vert_inds) * bpoly->numverts, "SDefTriVertInds");
+ if (sdbind->vert_inds == NULL) {
+ data->success = MOD_SDEF_BIND_RESULT_MEM_ERR;
+ return;
+ }
+
+ sortPolyVertsTri(sdbind->vert_inds, &data->mloop[bpoly->loopstart], bpoly->edge_vert_inds[0], bpoly->numverts);
+
+ copy_v3_v3(v1, data->targetCos[sdbind->vert_inds[0]]);
+ copy_v3_v3(v2, data->targetCos[sdbind->vert_inds[1]]);
+ copy_v3_v3(v3, data->targetCos[sdbind->vert_inds[2]]);
+
+ mid_v3_v3v3v3(cent, v1, v2, v3);
+ normal_tri_v3(norm, v1, v2, v3);
+
+ add_v3_v3v3(tmp_vec, point_co, bpoly->normal);
+
+ /* We are sure the line is not parallel to the plane.
+ * Checking return value just to avoid warning... */
+ if (!isect_line_plane_v3(point_co_proj, point_co, tmp_vec, cent, norm)) {
+ BLI_assert(false);
+ }
+
+ interp_weights_tri_v3(sdbind->vert_weights, v1, v2, v3, point_co_proj);
+
+ sdbind->normal_dist = computeNormalDisplacement(point_co, point_co_proj, bpoly->normal);
+
+ sdbind++;
+ i++;
+ }
+ }
+ }
+ }
+
+ freeBindData(bwdata);
+}
+
+static bool surfacedeformBind(SurfaceDeformModifierData *smd, float (*vertexCos)[3],
+ unsigned int numverts, unsigned int tnumpoly, unsigned int tnumverts, DerivedMesh *tdm)
+{
+ 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);
+ int adj_result;
+ SDefAdjacencyArray *vert_edges;
+ SDefAdjacency *adj_array;
+ SDefEdgePolys *edge_polys;
+
+ vert_edges = MEM_callocN(sizeof(*vert_edges) * tnumverts, "SDefVertEdgeMap");
+ if (vert_edges == NULL) {
+ modifier_setError((ModifierData *)smd, "Out of memory");
+ return false;
+ }
+
+ adj_array = MEM_mallocN(sizeof(*adj_array) * tnumedges * 2, "SDefVertEdge");
+ if (adj_array == NULL) {
+ modifier_setError((ModifierData *)smd, "Out of memory");
+ MEM_freeN(vert_edges);
+ return false;
+ }
+
+ edge_polys = MEM_callocN(sizeof(*edge_polys) * tnumedges, "SDefEdgeFaceMap");
+ if (edge_polys == NULL) {
+ modifier_setError((ModifierData *)smd, "Out of memory");
+ MEM_freeN(vert_edges);
+ MEM_freeN(adj_array);
+ return false;
+ }
+
+ smd->verts = MEM_mallocN(sizeof(*smd->verts) * numverts, "SDefBindVerts");
+ if (smd->verts == NULL) {
+ modifier_setError((ModifierData *)smd, "Out of memory");
+ freeAdjacencyMap(vert_edges, adj_array, edge_polys);
+ return false;
+ }
+
+ bvhtree_from_mesh_looptri(&treeData, tdm, 0.0, 2, 6);
+ if (treeData.tree == NULL) {
+ modifier_setError((ModifierData *)smd, "Out of memory");
+ freeAdjacencyMap(vert_edges, adj_array, edge_polys);
+ MEM_freeN(smd->verts);
+ smd->verts = NULL;
+ return false;
+ }
+
+ adj_result = buildAdjacencyMap(mpoly, medge, mloop, tnumpoly, tnumedges, vert_edges, adj_array, edge_polys);
+
+ if (adj_result == MOD_SDEF_BIND_RESULT_NONMANY_ERR) {
+ modifier_setError((ModifierData *)smd, "Target has edges with more than two polygons");
+ freeAdjacencyMap(vert_edges, adj_array, edge_polys);
+ free_bvhtree_from_mesh(&treeData);
+ MEM_freeN(smd->verts);
+ smd->verts = NULL;
+ return false;
+ }
+
+ smd->numverts = numverts;
+ smd->numpoly = tnumpoly;
+
+ SDefBindCalcData data = {.treeData = &treeData,
+ .vert_edges = vert_edges,
+ .edge_polys = edge_polys,
+ .mpoly = mpoly,
+ .medge = medge,
+ .mloop = mloop,
+ .looptri = tdm->getLoopTriArray(tdm),
+ .targetCos = MEM_mallocN(sizeof(float[3]) * tnumverts, "SDefTargetBindVertArray"),
+ .bind_verts = smd->verts,
+ .vertexCos = vertexCos,
+ .falloff = smd->falloff,
+ .success = MOD_SDEF_BIND_RESULT_SUCCESS};
+
+ if (data.targetCos == NULL) {
+ modifier_setError((ModifierData *)smd, "Out of memory");
+ freeData((ModifierData *)smd);
+ return false;
+ }
+
+ invert_m4_m4(data.imat, smd->mat);
+
+ for (int i = 0; i < tnumverts; i++) {
+ mul_v3_m4v3(data.targetCos[i], smd->mat, mvert[i].co);
+ }
+
+ BLI_task_parallel_range_ex(0, numverts, &data, NULL, 0, bindVert,
+ numverts > 10000, false);
+
+ MEM_freeN(data.targetCos);
+
+ if (data.success == MOD_SDEF_BIND_RESULT_MEM_ERR) {
+ modifier_setError((ModifierData *)smd, "Out of memory");
+ freeData((ModifierData *)smd);
+ }
+ else if (data.success == MOD_SDEF_BIND_RESULT_NONMANY_ERR) {
+ modifier_setError((ModifierData *)smd, "Target has edges with more than two polygons");
+ freeData((ModifierData *)smd);
+ }
+ else if (data.success == MOD_SDEF_BIND_RESULT_CONCAVE_ERR) {
+ modifier_setError((ModifierData *)smd, "Target contains concave polygons");
+ freeData((ModifierData *)smd);
+ }
+ else if (data.success == MOD_SDEF_BIND_RESULT_OVERLAP_ERR) {
+ modifier_setError((ModifierData *)smd, "Target contains overlapping verts");
+ freeData((ModifierData *)smd);
+ }
+ else if (data.success == MOD_SDEF_BIND_RESULT_GENERIC_ERR) {
+ /* I know this message is vague, but I could not think of a way
+ * to explain this whith a reasonably sized message.
+ * Though it shouldn't really matter all that much,
+ * because this is very unlikely to occur */
+ modifier_setError((ModifierData *)smd, "Target contains invalid polygons");
+ freeData((ModifierData *)smd);
+ }
+
+ freeAdjacencyMap(vert_edges, adj_array, edge_polys);
+ free_bvhtree_from_mesh(&treeData);
+
+ return data.success == 1;
+}
+
+static void deformVert(void *userdata, void *UNUSED(userdata_chunk), const int index, const int UNUSED(threadid))
+{
+ const SDefDeformData * const data = (SDefDeformData *)userdata;
+ const SDefBind *sdbind = data->bind_verts[index].binds;
+ float * const vertexCos = data->vertexCos[index];
+ float norm[3], temp[3];
+
+ zero_v3(vertexCos);
+
+ for (int j = 0; j < data->bind_verts[index].numbinds; j++, sdbind++) {
+ /* Mode-generic operations (allocate poly coordinates) */
+ float (*coords)[3] = MEM_mallocN(sizeof(*coords) * sdbind->numverts, "SDefDoPolyCoords");
+
+ for (int k = 0; k < sdbind->numverts; k++) {
+ copy_v3_v3(coords[k], data->targetCos[sdbind->vert_inds[k]]);
+ }
+
+ normal_poly_v3(norm, coords, sdbind->numverts);
+ zero_v3(temp);
+
+ /* ---------- looptri mode ---------- */
+ if (sdbind->mode == MOD_SDEF_MODE_LOOPTRI) {
+ madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[0]], sdbind->vert_weights[0]);
+ madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[1]], sdbind->vert_weights[1]);
+ madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[2]], sdbind->vert_weights[2]);
+ }
+ else {
+ /* ---------- ngon mode ---------- */
+ if (sdbind->mode == MOD_SDEF_MODE_NGON) {
+ for (int k = 0; k < sdbind->numverts; k++) {
+ madd_v3_v3fl(temp, coords[k], sdbind->vert_weights[k]);
+ }
+ }
+
+ /* ---------- centroid mode ---------- */
+ else if (sdbind->mode == MOD_SDEF_MODE_CENTROID) {
+ float cent[3];
+ mid_v3_v3_array(cent, coords, sdbind->numverts);
+
+ madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[0]], sdbind->vert_weights[0]);
+ madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[1]], sdbind->vert_weights[1]);
+ madd_v3_v3fl(temp, cent, sdbind->vert_weights[2]);
+ }
+ }
+
+ MEM_freeN(coords);
+
+ /* Apply normal offset (generic for all modes) */
+ madd_v3_v3fl(temp, norm, sdbind->normal_dist);
+
+ madd_v3_v3fl(vertexCos, temp, sdbind->influence);
+ }
+}
+
+static void surfacedeformModifier_do(ModifierData *md, float (*vertexCos)[3], unsigned int numverts, Object *ob)
+{
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
+ DerivedMesh *tdm;
+ unsigned int tnumverts, tnumpoly;
+
+ /* Exit function if bind flag is not set (free bind data if any) */
+ if (!(smd->flags & MOD_SDEF_BIND)) {
+ freeData(md);
+ 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) {
+ modifier_setError(md, "No valid target mesh");
+ return;
+ }
+
+ tnumverts = tdm->getNumVerts(tdm);
+ tnumpoly = tdm->getNumPolys(tdm);
+
+ /* If not bound, execute bind */
+ if (!(smd->verts)) {
+ float tmp_mat[4][4];
+
+ 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)) {
+ smd->flags &= ~MOD_SDEF_BIND;
+ return;
+ }
+ }
+
+ /* Poly count checks */
+ if (smd->numverts != numverts) {
+ modifier_setError(md, "Verts changed from %u to %u", smd->numverts, numverts);
+ return;
+ }
+ else if (smd->numpoly != tnumpoly) {
+ modifier_setError(md, "Target polygons changed from %u to %u", smd->numpoly, tnumpoly);
+ return;
+ }
+
+ /* Actual vertex location update starts here */
+ SDefDeformData data = {
+ .bind_verts = smd->verts,
+ .targetCos = MEM_mallocN(sizeof(float[3]) * tnumverts, "SDefTargetVertArray"),
+ .vertexCos = vertexCos,
+ };
+
+ if (data.targetCos != NULL) {
+ bool tdm_vert_alloc;
+ const MVert * const mvert = DM_get_vert_array(tdm, &tdm_vert_alloc);
+
+ for (int i = 0; i < tnumverts; i++) {
+ mul_v3_m4v3(data.targetCos[i], smd->mat, mvert[i].co);
+ }
+
+ BLI_task_parallel_range_ex(0, numverts, &data, NULL, 0, deformVert,
+ numverts > 10000, false);
+
+ if (tdm_vert_alloc) {
+ MEM_freeN((void *)mvert);
+ }
+
+ MEM_freeN(data.targetCos);
+ }
+}
+
+static void deformVerts(ModifierData *md, Object *ob,
+ DerivedMesh *UNUSED(derivedData),
+ float (*vertexCos)[3], int numVerts,
+ ModifierApplyFlag UNUSED(flag))
+{
+ surfacedeformModifier_do(md, vertexCos, numVerts, ob);
+}
+
+static void deformVertsEM(ModifierData *md, Object *ob,
+ struct BMEditMesh *UNUSED(editData),
+ DerivedMesh *UNUSED(derivedData),
+ float (*vertexCos)[3], int numVerts)
+{
+ surfacedeformModifier_do(md, vertexCos, numVerts, ob);
+}
+
+static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+{
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
+
+ return !smd->target && !(smd->verts && !(smd->flags & MOD_SDEF_BIND));
+}
+
+ModifierTypeInfo modifierType_SurfaceDeform = {
+ /* name */ "Surface Deform",
+ /* structName */ "SurfaceDeformModifierData",
+ /* structSize */ sizeof(SurfaceDeformModifierData),
+ /* type */ eModifierTypeType_OnlyDeform,
+ /* flags */ eModifierTypeFlag_AcceptsMesh |
+ eModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+ /* deformVerts */ deformVerts,
+ /* deformMatrices */ NULL,
+ /* deformVertsEM */ deformVertsEM,
+ /* deformMatricesEM */ NULL,
+ /* applyModifier */ NULL,
+ /* applyModifierEM */ NULL,
+ /* initData */ initData,
+ /* requiredDataMask */ NULL,
+ /* freeData */ freeData,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* dependsOnNormals */ NULL,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c
index 6fad2756f82..a5d826a69ba 100644
--- a/source/blender/modifiers/intern/MOD_triangulate.c
+++ b/source/blender/modifiers/intern/MOD_triangulate.c
@@ -118,7 +118,6 @@ ModifierTypeInfo modifierType_Triangulate = {
/* 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 93414562ccf..ded1f0b77e6 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -287,5 +287,6 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(NormalEdit);
INIT_TYPE(CorrectiveSmooth);
INIT_TYPE(MeshSequenceCache);
+ INIT_TYPE(SurfaceDeform);
#undef INIT_TYPE
}
diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c
index fb7668d16e0..cae83282238 100644
--- a/source/blender/modifiers/intern/MOD_uvproject.c
+++ b/source/blender/modifiers/intern/MOD_uvproject.c
@@ -45,7 +45,9 @@
#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"
@@ -53,14 +55,13 @@
#include "MEM_guardedalloc.h"
-#include "depsgraph_private.h"
#include "DEG_depsgraph_build.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;
@@ -70,9 +71,12 @@ static void copyData(ModifierData *md, ModifierData *target)
{
#if 0
UVProjectModifierData *umd = (UVProjectModifierData *) md;
- UVProjectModifierData *tumd = (UVProjectModifierData *) target;
#endif
+ UVProjectModifierData *tumd = (UVProjectModifierData *) target;
+
modifier_copyData_generic(md, target);
+
+ id_us_plus((ID *)tumd->image);
}
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(md))
@@ -80,7 +84,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,7 +96,7 @@ static void foreachObjectLink(ModifierData *md, Object *ob,
int i;
for (i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i)
- walk(userData, ob, &umd->projectors[i], IDWALK_NOP);
+ walk(userData, ob, &umd->projectors[i], IDWALK_CB_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob,
@@ -100,30 +104,11 @@ static void foreachIDLink(ModifierData *md, Object *ob,
{
UVProjectModifierData *umd = (UVProjectModifierData *) md;
- walk(userData, ob, (ID **)&umd->image, IDWALK_USER);
+ walk(userData, ob, (ID **)&umd->image, IDWALK_CB_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- DagNode *obNode)
-{
- UVProjectModifierData *umd = (UVProjectModifierData *) md;
- int i;
-
- for (i = 0; i < umd->num_projectors; ++i) {
- if (umd->projectors[i]) {
- DagNode *curNode = dag_get_node(forest, umd->projectors[i]);
-
- dag_add_relation(forest, curNode, obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "UV Project Modifier");
- }
- }
-}
-
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
@@ -151,12 +136,10 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
{
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];
@@ -241,10 +224,6 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
mloop_uv = CustomData_duplicate_referenced_layer_named(&dm->loopData,
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_mallocN(sizeof(*coords) * numVerts,
@@ -263,9 +242,14 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
mpoly = dm->getPolyArray(dm);
mloop = dm->getLoopArray(dm);
+ Image **ob_image_array = NULL;
+ if (image) {
+ ob_image_array = BKE_object_material_edit_image_get_array(ob);
+ }
+
/* 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)) {
+ for (i = 0, mp = mpoly; i < numPolys; ++i, ++mp) {
+ if (!image || (mp->mat_nr < ob->totcol ? ob_image_array[mp->mat_nr] : NULL) == image) {
if (num_projectors == 1) {
if (projectors[0].uci) {
unsigned int fidx = mp->totloop - 1;
@@ -328,13 +312,13 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
}
}
}
-
- if (override_image && mtexpoly) {
- mt->tpage = image;
- }
}
MEM_freeN(coords);
+
+ if (ob_image_array) {
+ MEM_freeN(ob_image_array);
+ }
if (free_uci) {
int j;
@@ -385,7 +369,6 @@ ModifierTypeInfo modifierType_UVProject = {
/* 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 89994c3ae22..7ee0a7e3108 100644
--- a/source/blender/modifiers/intern/MOD_uvwarp.c
+++ b/source/blender/modifiers/intern/MOD_uvwarp.c
@@ -40,8 +40,6 @@
#include "BKE_library_query.h"
#include "BKE_modifier.h"
-#include "depsgraph_private.h"
-
#include "MOD_util.h"
@@ -221,38 +219,13 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk,
{
UVWarpModifierData *umd = (UVWarpModifierData *) md;
- walk(userData, ob, &umd->object_dst, IDWALK_NOP);
- walk(userData, ob, &umd->object_src, IDWALK_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, DagForest *forest,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob),
- DagNode *obNode)
-{
- UVWarpModifierData *umd = (UVWarpModifierData *) md;
-
- uv_warp_deps_object_bone(forest, obNode, umd->object_src, umd->bone_src);
- uv_warp_deps_object_bone(forest, obNode, umd->object_dst, umd->bone_dst);
+ walk(userData, ob, &umd->object_dst, IDWALK_CB_NOP);
+ walk(userData, ob, &umd->object_src, IDWALK_CB_NOP);
}
-static void uv_warp_deps_object_bone_new(struct DepsNodeHandle *node,
- Object *object,
- const char *bonename)
+static void uv_warp_deps_object_bone(struct DepsNodeHandle *node,
+ Object *object,
+ const char *bonename)
{
if (object != NULL) {
if (bonename[0])
@@ -270,8 +243,8 @@ static void updateDepsgraph(ModifierData *md,
{
UVWarpModifierData *umd = (UVWarpModifierData *) md;
- uv_warp_deps_object_bone_new(node, umd->object_src, umd->bone_src);
- uv_warp_deps_object_bone_new(node, umd->object_dst, umd->bone_dst);
+ uv_warp_deps_object_bone(node, umd->object_src, umd->bone_src);
+ uv_warp_deps_object_bone(node, umd->object_dst, umd->bone_dst);
}
ModifierTypeInfo modifierType_UVWarp = {
@@ -293,7 +266,6 @@ ModifierTypeInfo modifierType_UVWarp = {
/* 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 b38de140a91..c9a9e20df23 100644
--- a/source/blender/modifiers/intern/MOD_warp.c
+++ b/source/blender/modifiers/intern/MOD_warp.c
@@ -42,8 +42,6 @@
#include "BKE_texture.h"
#include "BKE_colortools.h"
-#include "depsgraph_private.h"
-
#include "RE_shader_ext.h"
#include "MOD_util.h"
@@ -66,6 +64,10 @@ static void copyData(ModifierData *md, ModifierData *target)
WarpModifierData *wmd = (WarpModifierData *) md;
WarpModifierData *twmd = (WarpModifierData *) target;
+ if (twmd->curfalloff != NULL) {
+ curvemapping_free(twmd->curfalloff);
+ }
+
modifier_copyData_generic(md, target);
twmd->curfalloff = curvemapping_copy(wmd->curfalloff);
@@ -116,16 +118,16 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk,
{
WarpModifierData *wmd = (WarpModifierData *) md;
- walk(userData, ob, &wmd->object_from, IDWALK_NOP);
- walk(userData, ob, &wmd->object_to, IDWALK_NOP);
- walk(userData, ob, &wmd->map_object, IDWALK_NOP);
+ walk(userData, ob, &wmd->object_from, IDWALK_CB_NOP);
+ walk(userData, ob, &wmd->object_to, IDWALK_CB_NOP);
+ walk(userData, ob, &wmd->map_object, IDWALK_CB_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
WarpModifierData *wmd = (WarpModifierData *) md;
- walk(userData, ob, (ID **)&wmd->texture, IDWALK_USER);
+ walk(userData, ob, (ID **)&wmd->texture, IDWALK_CB_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
@@ -135,27 +137,6 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void
walk(userData, ob, md, "texture");
}
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob), DagNode *obNode)
-{
- WarpModifierData *wmd = (WarpModifierData *) md;
-
- if (wmd->object_from && wmd->object_to) {
- DagNode *fromNode = dag_get_node(forest, wmd->object_from);
- DagNode *toNode = dag_get_node(forest, wmd->object_to);
-
- dag_add_relation(forest, fromNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Warp Modifier1");
- dag_add_relation(forest, toNode, 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(forest, wmd->map_object);
- dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Warp Modifier3");
- }
-}
-
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
@@ -387,7 +368,6 @@ ModifierTypeInfo modifierType_Warp = {
/* 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 683649ed1c0..73e96f87c66 100644
--- a/source/blender/modifiers/intern/MOD_wave.c
+++ b/source/blender/modifiers/intern/MOD_wave.c
@@ -49,8 +49,6 @@
#include "BKE_scene.h"
#include "BKE_texture.h"
-#include "depsgraph_private.h"
-
#include "MEM_guardedalloc.h"
#include "RE_shader_ext.h"
@@ -111,8 +109,8 @@ static void foreachObjectLink(
{
WaveModifierData *wmd = (WaveModifierData *) md;
- walk(userData, ob, &wmd->objectcenter, IDWALK_NOP);
- walk(userData, ob, &wmd->map_object, IDWALK_NOP);
+ walk(userData, ob, &wmd->objectcenter, IDWALK_CB_NOP);
+ walk(userData, ob, &wmd->map_object, IDWALK_CB_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob,
@@ -120,7 +118,7 @@ static void foreachIDLink(ModifierData *md, Object *ob,
{
WaveModifierData *wmd = (WaveModifierData *) md;
- walk(userData, ob, (ID **)&wmd->texture, IDWALK_USER);
+ walk(userData, ob, (ID **)&wmd->texture, IDWALK_CB_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
@@ -131,29 +129,6 @@ static void foreachTexLink(ModifierData *md, Object *ob,
walk(userData, ob, md, "texture");
}
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- Scene *UNUSED(scene),
- Object *UNUSED(ob),
- DagNode *obNode)
-{
- WaveModifierData *wmd = (WaveModifierData *) md;
-
- if (wmd->objectcenter) {
- DagNode *curNode = dag_get_node(forest, wmd->objectcenter);
-
- dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA,
- "Wave Modifier");
- }
-
- if (wmd->map_object) {
- DagNode *curNode = dag_get_node(forest, wmd->map_object);
-
- dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA,
- "Wave Modifer");
- }
-}
-
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
@@ -397,7 +372,6 @@ ModifierTypeInfo modifierType_Wave = {
/* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
/* isDisabled */ NULL,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c
index 93567aed2c4..e6603b81bfd 100644
--- a/source/blender/modifiers/intern/MOD_weightvgedit.c
+++ b/source/blender/modifiers/intern/MOD_weightvgedit.c
@@ -46,7 +46,6 @@
#include "BKE_modifier.h"
#include "BKE_texture.h" /* Texture masking. */
-#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
#include "MEM_guardedalloc.h"
@@ -126,14 +125,14 @@ static bool dependsOnTime(ModifierData *md)
static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md;
- walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_NOP);
+ walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_CB_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md;
- walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_USER);
+ walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_CB_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
@@ -143,26 +142,6 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void
walk(userData, ob, md, "mask_texture");
}
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob), DagNode *obNode)
-{
- WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md;
- DagNode *curNode;
-
- if (wmd->mask_tex_map_obj && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
- curNode = dag_get_node(forest, wmd->mask_tex_map_obj);
-
- dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA,
- "WeightVGEdit Modifier");
- }
-
- if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL)
- dag_add_relation(forest, obNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA,
- "WeightVGEdit Modifier");
-}
-
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
@@ -226,8 +205,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
if (!do_add)
return dm;
/* Else, add a valid data layer! */
- dvert = CustomData_add_layer_named(&dm->vertData, CD_MDEFORMVERT, CD_CALLOC,
- NULL, numVerts, wmd->defgrp_name);
+ dvert = CustomData_add_layer(&dm->vertData, CD_MDEFORMVERT, CD_CALLOC, NULL, numVerts);
/* Ultimate security check. */
if (!dvert)
return dm;
@@ -307,7 +285,6 @@ ModifierTypeInfo modifierType_WeightVGEdit = {
/* 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 170fbbed7f1..df07cffe63f 100644
--- a/source/blender/modifiers/intern/MOD_weightvgmix.c
+++ b/source/blender/modifiers/intern/MOD_weightvgmix.c
@@ -43,7 +43,6 @@
#include "BKE_modifier.h"
#include "BKE_texture.h" /* Texture masking. */
-#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
#include "MEM_guardedalloc.h"
@@ -175,14 +174,14 @@ static bool dependsOnTime(ModifierData *md)
static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
- walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_NOP);
+ walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_CB_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
- walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_USER);
+ walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_CB_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
@@ -192,26 +191,6 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void
walk(userData, ob, md, "mask_texture");
}
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob), DagNode *obNode)
-{
- WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
- DagNode *curNode;
-
- if (wmd->mask_tex_map_obj && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
- curNode = dag_get_node(forest, wmd->mask_tex_map_obj);
-
- dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA,
- "WeightVGMix Modifier");
- }
-
- if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL)
- dag_add_relation(forest, obNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA,
- "WeightVGMix Modifier");
-}
-
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
@@ -282,8 +261,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
if (wmd->mix_set != MOD_WVG_SET_ALL)
return dm;
/* Else, add a valid data layer! */
- dvert = CustomData_add_layer_named(&dm->vertData, CD_MDEFORMVERT, CD_CALLOC,
- NULL, numVerts, wmd->defgrp_name_a);
+ dvert = CustomData_add_layer(&dm->vertData, CD_MDEFORMVERT, CD_CALLOC, NULL, numVerts);
/* Ultimate security check. */
if (!dvert)
return dm;
@@ -439,7 +417,6 @@ ModifierTypeInfo modifierType_WeightVGMix = {
/* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
/* 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 af59f11ba15..70b413ca685 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -47,7 +47,6 @@
#include "BKE_modifier.h"
#include "BKE_texture.h" /* Texture masking. */
-#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
#include "MEM_guardedalloc.h"
@@ -325,15 +324,15 @@ static bool dependsOnTime(ModifierData *md)
static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
- walk(userData, ob, &wmd->proximity_ob_target, IDWALK_NOP);
- walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_NOP);
+ walk(userData, ob, &wmd->proximity_ob_target, IDWALK_CB_NOP);
+ walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_CB_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
- walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_USER);
+ walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_CB_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
@@ -343,32 +342,6 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void
walk(userData, ob, md, "mask_texture");
}
-static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Main *UNUSED(bmain),
- struct Scene *UNUSED(scene),
- Object *UNUSED(ob), DagNode *obNode)
-{
- WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
- DagNode *curNode;
-
- if (wmd->proximity_ob_target) {
- curNode = dag_get_node(forest, wmd->proximity_ob_target);
- dag_add_relation(forest, curNode, 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(forest, wmd->mask_tex_map_obj);
-
- dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA,
- "WeightVGProximity Modifier");
- }
-
- if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL)
- dag_add_relation(forest, obNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA,
- "WeightVGProximity Modifier");
-}
-
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
@@ -617,7 +590,6 @@ ModifierTypeInfo modifierType_WeightVGProximity = {
/* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
/* 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 adadd4834d4..0c295f91012 100644
--- a/source/blender/modifiers/intern/MOD_wireframe.c
+++ b/source/blender/modifiers/intern/MOD_wireframe.c
@@ -132,7 +132,6 @@ ModifierTypeInfo modifierType_Wireframe = {
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index d20881df150..2c46791ae18 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -163,6 +163,7 @@ set(SRC
shader/nodes/node_shader_background.c
shader/nodes/node_shader_bsdf_anisotropic.c
shader/nodes/node_shader_bsdf_diffuse.c
+ shader/nodes/node_shader_bsdf_principled.c
shader/nodes/node_shader_bsdf_glass.c
shader/nodes/node_shader_bsdf_glossy.c
shader/nodes/node_shader_bsdf_toon.c
@@ -183,8 +184,11 @@ set(SRC
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_metallic.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_eevee_material.c
shader/nodes/node_shader_output_world.c
shader/nodes/node_shader_output_linestyle.c
shader/nodes/node_shader_particle_info.c
@@ -288,8 +292,4 @@ if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
-if(WITH_CYCLES AND WITH_CYCLES_DEBUG)
- add_definitions(-DWITH_CYCLES_DEBUG)
-endif()
-
blender_add_lib(bf_nodes "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h
index 0215db1dd55..a5c2e604f46 100644
--- a/source/blender/nodes/NOD_composite.h
+++ b/source/blender/nodes/NOD_composite.h
@@ -139,6 +139,8 @@ void register_node_type_cmp_trackpos(void);
void register_node_type_cmp_planetrackdeform(void);
void register_node_type_cmp_cornerpin(void);
-void node_cmp_rlayers_force_hidden_passes(struct bNode *node);
+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);
+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 4c0047f1d58..08c4924150e 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -106,6 +106,7 @@ void register_node_type_sh_bsdf_transparent(void);
void register_node_type_sh_bsdf_velvet(void);
void register_node_type_sh_bsdf_toon(void);
void register_node_type_sh_bsdf_anisotropic(void);
+void register_node_type_sh_bsdf_principled(void);
void register_node_type_sh_emission(void);
void register_node_type_sh_holdout(void);
void register_node_type_sh_volume_absorption(void);
@@ -116,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_static_types.h b/source/blender/nodes/NOD_static_types.h
index 171d5313c1d..d8944776cbb 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -67,6 +67,9 @@ DefNode( ShaderNode, SH_NODE_COMBRGB, 0, "COMBR
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_EEVEE_METALLIC, 0, "EEVEE_METALLIC", EeveeMetallic, "Metallic", "")
+DefNode( ShaderNode, SH_NODE_EEVEE_SPECULAR, 0, "EEVEE_SPECULAR", EeveeSpecular, "Specular", "")
+DefNode( ShaderNode, SH_NODE_OUTPUT_EEVEE_MATERIAL, def_sh_output, "OUTPUT_EEVEE_MATERIAL", OutputEeveeMaterial, "Material Output", "")
DefNode( ShaderNode, SH_NODE_OUTPUT_LAMP, def_sh_output, "OUTPUT_LAMP", OutputLamp, "Lamp 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", "" )
@@ -80,6 +83,7 @@ DefNode( ShaderNode, SH_NODE_BACKGROUND, 0, "BA
DefNode( ShaderNode, SH_NODE_HOLDOUT, 0, "HOLDOUT", Holdout, "Holdout", "" )
DefNode( ShaderNode, SH_NODE_BSDF_ANISOTROPIC, def_anisotropic, "BSDF_ANISOTROPIC", BsdfAnisotropic, "Anisotropic BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_DIFFUSE, 0, "BSDF_DIFFUSE", BsdfDiffuse, "Diffuse BSDF", "" )
+DefNode( ShaderNode, SH_NODE_BSDF_PRINCIPLED, def_principled, "BSDF_PRINCIPLED", BsdfPrincipled, "Principled BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_GLOSSY, def_glossy, "BSDF_GLOSSY", BsdfGlossy, "Glossy BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_GLASS, def_glass, "BSDF_GLASS", BsdfGlass, "Glass BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_REFRACTION, def_refraction, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "" )
@@ -145,7 +149,7 @@ DefNode( CompositorNode, CMP_NODE_VECBLUR, def_cmp_vector_blur, "VECBL
DefNode( CompositorNode, CMP_NODE_SEPRGBA, 0, "SEPRGBA", SepRGBA, "Separate RGBA", "" )
DefNode( CompositorNode, CMP_NODE_SEPHSVA, 0, "SEPHSVA", SepHSVA, "Separate HSVA", "" )
DefNode( CompositorNode, CMP_NODE_SETALPHA, 0, "SETALPHA", SetAlpha, "Set Alpha", "" )
-DefNode( CompositorNode, CMP_NODE_HUE_SAT, def_cmp_hue_saturation, "HUE_SAT", HueSat, "Hue Saturation Value","" )
+DefNode( CompositorNode, CMP_NODE_HUE_SAT, 0, "HUE_SAT", HueSat, "Hue Saturation Value","" )
DefNode( CompositorNode, CMP_NODE_IMAGE, def_cmp_image, "IMAGE", Image, "Image", "" )
DefNode( CompositorNode, CMP_NODE_R_LAYERS, def_cmp_render_layers, "R_LAYERS", RLayers, "Render Layers", "" )
DefNode( CompositorNode, CMP_NODE_COMPOSITE, def_cmp_composite, "COMPOSITE", Composite, "Composite", "" )
@@ -178,7 +182,7 @@ DefNode( CompositorNode, CMP_NODE_DISPLACE, 0, "DISPL
DefNode( CompositorNode, CMP_NODE_COMBHSVA, 0, "COMBHSVA", CombHSVA, "Combine HSVA", "" )
DefNode( CompositorNode, CMP_NODE_MATH, def_math, "MATH", Math, "Math", "" )
DefNode( CompositorNode, CMP_NODE_LUMA_MATTE, def_cmp_luma_matte, "LUMA_MATTE", LumaMatte, "Luminance Key", "" )
-DefNode( CompositorNode, CMP_NODE_BRIGHTCONTRAST, 0, "BRIGHTCONTRAST", BrightContrast, "Bright/Contrast", "" )
+DefNode( CompositorNode, CMP_NODE_BRIGHTCONTRAST, def_cmp_brightcontrast, "BRIGHTCONTRAST", BrightContrast, "Bright/Contrast", "" )
DefNode( CompositorNode, CMP_NODE_GAMMA, 0, "GAMMA", Gamma, "Gamma", "" )
DefNode( CompositorNode, CMP_NODE_INVERT, def_cmp_invert, "INVERT", Invert, "Invert", "" )
DefNode( CompositorNode, CMP_NODE_NORMALIZE, 0, "NORMALIZE", Normalize, "Normalize", "" )
diff --git a/source/blender/nodes/composite/node_composite_tree.c b/source/blender/nodes/composite/node_composite_tree.c
index cb565bd5491..36778a18f77 100644
--- a/source/blender/nodes/composite/node_composite_tree.c
+++ b/source/blender/nodes/composite/node_composite_tree.c
@@ -240,8 +240,15 @@ void ntreeCompositExecTree(Scene *scene, bNodeTree *ntree, RenderData *rd, int r
/* *********************************************** */
-/* based on rules, force sockets hidden always */
-void ntreeCompositForceHidden(bNodeTree *ntree)
+/* Update the outputs of the render layer nodes.
+ * Since the outputs depend on the render engine, this part is a bit complex:
+ * - ntreeCompositUpdateRLayers is called and loops over all render layer nodes
+ * - Each render layer node calls the update function of the render engine that's used for its scene
+ * - The render engine calls RE_engine_register_pass for each pass
+ * - RE_engine_register_pass calls ntreeCompositRegisterPass,
+ * which calls node_cmp_rlayers_register_pass for every render layer node
+ */
+void ntreeCompositUpdateRLayers(bNodeTree *ntree)
{
bNode *node;
@@ -249,16 +256,20 @@ void ntreeCompositForceHidden(bNodeTree *ntree)
for (node = ntree->nodes.first; node; node = node->next) {
if (node->type == CMP_NODE_R_LAYERS)
- node_cmp_rlayers_force_hidden_passes(node);
-
- /* XXX this stuff is called all the time, don't want that.
- * Updates should only happen when actually necessary.
- */
-#if 0
- else if (node->type == CMP_NODE_IMAGE) {
- nodeUpdate(ntree, node);
- }
-#endif
+ node_cmp_rlayers_outputs(ntree, node);
+ }
+
+}
+
+void ntreeCompositRegisterPass(bNodeTree *ntree, Scene *scene, SceneRenderLayer *srl, const char *name, int type)
+{
+ bNode *node;
+
+ if (ntree == NULL) return;
+
+ 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);
}
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_bilateralblur.c b/source/blender/nodes/composite/nodes/node_composite_bilateralblur.c
index 2ad097013ef..fde7dccb4ac 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bilateralblur.c
+++ b/source/blender/nodes/composite/nodes/node_composite_bilateralblur.c
@@ -47,6 +47,7 @@ static void node_composit_init_bilateralblur(bNodeTree *UNUSED(ntree), bNode *no
{
NodeBilateralBlurData *nbbd = MEM_callocN(sizeof(NodeBilateralBlurData), "node bilateral blur data");
node->storage = nbbd;
+ nbbd->iter = 1;
nbbd->sigma_color = 0.3;
nbbd->sigma_space = 5.0;
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_brightness.c b/source/blender/nodes/composite/nodes/node_composite_brightness.c
index 62f23f417b2..26e4d3a52c9 100644
--- a/source/blender/nodes/composite/nodes/node_composite_brightness.c
+++ b/source/blender/nodes/composite/nodes/node_composite_brightness.c
@@ -46,6 +46,10 @@ static bNodeSocketTemplate cmp_node_brightcontrast_out[] = {
{ -1, 0, "" }
};
+static void node_composit_init_brightcontrast(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->custom1 = 1;
+}
void register_node_type_cmp_brightcontrast(void)
{
@@ -53,6 +57,7 @@ void register_node_type_cmp_brightcontrast(void)
cmp_node_type_base(&ntype, CMP_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, cmp_node_brightcontrast_in, cmp_node_brightcontrast_out);
+ node_type_init(&ntype, node_composit_init_brightcontrast);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_directionalblur.c b/source/blender/nodes/composite/nodes/node_composite_directionalblur.c
index 6eb27a228ad..336eb3409ff 100644
--- a/source/blender/nodes/composite/nodes/node_composite_directionalblur.c
+++ b/source/blender/nodes/composite/nodes/node_composite_directionalblur.c
@@ -46,6 +46,7 @@ static void node_composit_init_dblur(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeDBlurData *ndbd = MEM_callocN(sizeof(NodeDBlurData), "node dblur data");
node->storage = ndbd;
+ ndbd->iter = 1;
ndbd->center_x = 0.5;
ndbd->center_y = 0.5;
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_glare.c b/source/blender/nodes/composite/nodes/node_composite_glare.c
index c512ea49586..76020e55463 100644
--- a/source/blender/nodes/composite/nodes/node_composite_glare.c
+++ b/source/blender/nodes/composite/nodes/node_composite_glare.c
@@ -50,7 +50,8 @@ static void node_composit_init_glare(bNodeTree *UNUSED(ntree), bNode *node)
ndg->colmod = 0.25;
ndg->mix = 0;
ndg->threshold = 1;
- ndg->angle = 4;
+ ndg->star_45 = true;
+ ndg->streaks = 4;
ndg->angle_ofs = 0.0f;
ndg->fade = 0.9;
ndg->size = 8;
diff --git a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c
index 1c31f4863ca..952ba78aff3 100644
--- a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c
+++ b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c
@@ -35,8 +35,11 @@
/* **************** Hue Saturation ******************** */
static bNodeSocketTemplate cmp_node_hue_sat_in[] = {
- { SOCK_FLOAT, 1, N_("Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_RGBA, 1, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
+ { SOCK_FLOAT, 1, N_("Hue"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Saturation"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Value"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ -1, 0, "" }
};
static bNodeSocketTemplate cmp_node_hue_sat_out[] = {
@@ -44,23 +47,12 @@ static bNodeSocketTemplate cmp_node_hue_sat_out[] = {
{ -1, 0, "" }
};
-static void node_composit_init_hue_sat(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeHueSat *nhs = MEM_callocN(sizeof(NodeHueSat), "node hue sat");
- node->storage = nhs;
- nhs->hue = 0.5f;
- nhs->sat = 1.0f;
- nhs->val = 1.0f;
-}
-
void register_node_type_cmp_hue_sat(void)
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, cmp_node_hue_sat_in, cmp_node_hue_sat_out);
- node_type_init(&ntype, node_composit_init_hue_sat);
- node_type_storage(&ntype, "NodeHueSat", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c
index 4f02c106569..8139e29bade 100644
--- a/source/blender/nodes/composite/nodes/node_composite_image.c
+++ b/source/blender/nodes/composite/nodes/node_composite_image.c
@@ -32,192 +32,108 @@
#include "node_composite_util.h"
#include "BLI_utildefines.h"
+#include "BLI_linklist.h"
#include "DNA_scene_types.h"
+#include "RE_engine.h"
+
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_main.h"
-#ifdef WITH_CYCLES_DEBUG
-# include "RE_pipeline.h"
-#endif
-
/* **************** IMAGE (and RenderResult, multilayer image) ******************** */
static bNodeSocketTemplate cmp_node_rlayers_out[] = {
- { SOCK_RGBA, 0, N_("Image"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_FLOAT, 0, N_("Alpha"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_FLOAT, 0, N_("Z"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_VECTOR, 0, N_("Normal"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_VECTOR, 0, N_("UV"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_VECTOR, 0, N_("Speed"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Diffuse"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Specular"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Shadow"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("AO"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Reflect"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Refract"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Indirect"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_FLOAT, 0, N_("IndexOB"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_FLOAT, 0, N_("IndexMA"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_FLOAT, 0, N_("Mist"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Emit"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Environment"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Diffuse Direct"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Diffuse Indirect"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Diffuse Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Glossy Direct"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Glossy Indirect"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Glossy Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Transmission Direct"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Transmission Indirect"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Transmission Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Subsurface Direct"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Subsurface Indirect"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 0, N_("Subsurface Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
-#ifdef WITH_CYCLES_DEBUG
- { SOCK_RGBA, 0, N_("Debug"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
-#endif
+ { SOCK_RGBA, 0, N_("Image"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, N_("Alpha"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, N_(RE_PASSNAME_Z), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 0, N_(RE_PASSNAME_NORMAL), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 0, N_(RE_PASSNAME_UV), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 0, N_(RE_PASSNAME_VECTOR), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_RGBA), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_DIFFUSE), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_SPEC), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_SHADOW), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_AO), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_REFLECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_REFRACT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_INDIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, N_(RE_PASSNAME_INDEXOB), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, N_(RE_PASSNAME_INDEXMA), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, N_(RE_PASSNAME_MIST), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_EMIT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_ENVIRONMENT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_DIFFUSE_DIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_DIFFUSE_INDIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_DIFFUSE_COLOR), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_GLOSSY_DIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_GLOSSY_INDIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_GLOSSY_COLOR), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_TRANSM_DIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_TRANSM_INDIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_TRANSM_COLOR), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_SUBSURFACE_DIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_SUBSURFACE_INDIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, N_(RE_PASSNAME_SUBSURFACE_COLOR), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ -1, 0, "" }
};
-static bNodeSocket *cmp_node_image_add_render_pass_output(bNodeTree *ntree, bNode *node, int pass, int rres_index)
+static void cmp_node_image_add_pass_output(bNodeTree *ntree, bNode *node,
+ const char *name, const char *passname,
+ int rres_index, int type, int is_rlayers,
+ LinkNodePair *available_sockets, int *prev_index)
{
bNodeSocket *sock;
- NodeImageLayer *sockdata;
-
- sock = node_add_socket_from_template(ntree, node, &cmp_node_rlayers_out[rres_index], SOCK_OUT);
- /* extra socket info */
- sockdata = MEM_callocN(sizeof(NodeImageLayer), "node image layer");
- sock->storage = sockdata;
-
- sockdata->pass_flag = pass;
-
- return sock;
-}
-
-static void cmp_node_image_add_render_pass_outputs(bNodeTree *ntree, bNode *node, int passflag)
-{
- if (passflag & SCE_PASS_COMBINED) {
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_COMBINED, RRES_OUT_IMAGE);
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_COMBINED, RRES_OUT_ALPHA);
- }
-
- if (passflag & SCE_PASS_Z)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_Z, RRES_OUT_Z);
- if (passflag & SCE_PASS_NORMAL)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_NORMAL, RRES_OUT_NORMAL);
- if (passflag & SCE_PASS_VECTOR)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_VECTOR, RRES_OUT_VEC);
- if (passflag & SCE_PASS_UV)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_UV, RRES_OUT_UV);
- if (passflag & SCE_PASS_RGBA)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_RGBA, RRES_OUT_RGBA);
- if (passflag & SCE_PASS_DIFFUSE)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_DIFFUSE, RRES_OUT_DIFF);
- if (passflag & SCE_PASS_SPEC)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_SPEC, RRES_OUT_SPEC);
- if (passflag & SCE_PASS_SHADOW)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_SHADOW, RRES_OUT_SHADOW);
- if (passflag & SCE_PASS_AO)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_AO, RRES_OUT_AO);
- if (passflag & SCE_PASS_REFLECT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_REFLECT, RRES_OUT_REFLECT);
- if (passflag & SCE_PASS_REFRACT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_REFRACT, RRES_OUT_REFRACT);
- if (passflag & SCE_PASS_INDIRECT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_INDIRECT, RRES_OUT_INDIRECT);
- if (passflag & SCE_PASS_INDEXOB)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_INDEXOB, RRES_OUT_INDEXOB);
- if (passflag & SCE_PASS_INDEXMA)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_INDEXMA, RRES_OUT_INDEXMA);
- if (passflag & SCE_PASS_MIST)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_MIST, RRES_OUT_MIST);
- if (passflag & SCE_PASS_EMIT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_EMIT, RRES_OUT_EMIT);
- if (passflag & SCE_PASS_ENVIRONMENT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_ENVIRONMENT, RRES_OUT_ENV);
-
- if (passflag & SCE_PASS_DIFFUSE_DIRECT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_DIFFUSE_DIRECT, RRES_OUT_DIFF_DIRECT);
- if (passflag & SCE_PASS_DIFFUSE_INDIRECT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_DIFFUSE_INDIRECT, RRES_OUT_DIFF_INDIRECT);
- if (passflag & SCE_PASS_DIFFUSE_COLOR)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_DIFFUSE_COLOR, RRES_OUT_DIFF_COLOR);
-
- if (passflag & SCE_PASS_GLOSSY_DIRECT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_GLOSSY_DIRECT, RRES_OUT_GLOSSY_DIRECT);
- if (passflag & SCE_PASS_GLOSSY_INDIRECT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_GLOSSY_INDIRECT, RRES_OUT_GLOSSY_INDIRECT);
- if (passflag & SCE_PASS_GLOSSY_COLOR)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_GLOSSY_COLOR, RRES_OUT_GLOSSY_COLOR);
-
- if (passflag & SCE_PASS_TRANSM_DIRECT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_TRANSM_DIRECT, RRES_OUT_TRANSM_DIRECT);
- if (passflag & SCE_PASS_TRANSM_INDIRECT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_TRANSM_INDIRECT, RRES_OUT_TRANSM_INDIRECT);
- if (passflag & SCE_PASS_TRANSM_COLOR)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_TRANSM_COLOR, RRES_OUT_TRANSM_COLOR);
-
- if (passflag & SCE_PASS_SUBSURFACE_DIRECT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_SUBSURFACE_DIRECT, RRES_OUT_SUBSURFACE_DIRECT);
- if (passflag & SCE_PASS_SUBSURFACE_INDIRECT)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_SUBSURFACE_INDIRECT, RRES_OUT_SUBSURFACE_INDIRECT);
- if (passflag & SCE_PASS_SUBSURFACE_COLOR)
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_SUBSURFACE_COLOR, RRES_OUT_SUBSURFACE_COLOR);
-
-#ifdef WITH_CYCLES_DEBUG
- cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_DEBUG, RRES_OUT_DEBUG);
-#endif
-}
-
-static void cmp_node_image_add_multilayer_outputs(bNodeTree *ntree, bNode *node, RenderLayer *rl)
-{
- bNodeSocket *sock;
- NodeImageLayer *sockdata;
- RenderPass *rpass;
- int index;
- int passflag = 0;
- for (rpass = rl->passes.first, index = 0; rpass; rpass = rpass->next, ++index) {
- int type;
- if (rpass->channels == 1)
- type = SOCK_FLOAT;
- else
- type = SOCK_RGBA;
-
- /* we only need one socket per type */
- if (passflag & rpass->passtype)
- continue;
-
- passflag |= rpass->passtype;
-
- sock = nodeAddStaticSocket(ntree, node, SOCK_OUT, type, PROP_NONE, rpass->internal_name, rpass->internal_name);
+ int sock_index = BLI_findstringindex(&node->outputs, name, offsetof(bNodeSocket, name));
+
+ if (sock_index < 0) {
+ /* The first 31 sockets always are the legacy hardcoded sockets.
+ * Any dynamically allocated sockets follow afterwards, and are sorted in the order in which they were stored in the RenderResult.
+ * Therefore, we remember the index of the last matched socket. New sockets are placed behind the previously traversed one, but always after the first 31. */
+ int after_index = *prev_index;
+ if (is_rlayers && after_index < 30)
+ after_index = 30;
+
+ if (rres_index >= 0) {
+ sock = node_add_socket_from_template(ntree, node, &cmp_node_rlayers_out[rres_index], SOCK_OUT);
+ }
+ else {
+ sock = nodeAddStaticSocket(ntree, node, SOCK_OUT, type, PROP_NONE, name, name);
+ }
/* extra socket info */
- sockdata = MEM_callocN(sizeof(NodeImageLayer), "node image layer");
+ NodeImageLayer *sockdata = MEM_callocN(sizeof(NodeImageLayer), "node image layer");
sock->storage = sockdata;
-
- sockdata->pass_index = index;
- sockdata->pass_flag = rpass->passtype;
-
- if (rpass->passtype == SCE_PASS_COMBINED) {
- sock = nodeAddStaticSocket(ntree, node, SOCK_OUT, SOCK_FLOAT, PROP_NONE, "Alpha", "Alpha");
- sockdata = MEM_callocN(sizeof(NodeImageLayer), "node image layer");
- sock->storage = sockdata;
- sockdata->pass_index = index;
- sockdata->pass_flag = rpass->passtype;
+
+ BLI_strncpy(sockdata->pass_name, passname, sizeof(sockdata->pass_name));
+
+ sock_index = BLI_listbase_count(&node->outputs) - 1;
+ if (sock_index != after_index + 1) {
+ bNodeSocket *after_sock = BLI_findlink(&node->outputs, after_index);
+ BLI_remlink(&node->outputs, sock);
+ BLI_insertlinkafter(&node->outputs, after_sock, sock);
+ }
+ }
+ else {
+ sock = BLI_findlink(&node->outputs, sock_index);
+ NodeImageLayer *sockdata = sock->storage;
+ if (sockdata) {
+ BLI_strncpy(sockdata->pass_name, passname, sizeof(sockdata->pass_name));
}
}
+
+ BLI_linklist_append(available_sockets, sock);
+ *prev_index = sock_index;
}
-static void cmp_node_image_create_outputs(bNodeTree *ntree, bNode *node)
+static void cmp_node_image_create_outputs(bNodeTree *ntree, bNode *node, LinkNodePair *available_sockets)
{
Image *ima = (Image *)node->id;
+ ImBuf *ibuf;
+ int prev_index = -1;
if (ima) {
ImageUser *iuser = node->storage;
ImageUser load_iuser = {NULL};
- ImBuf *ibuf;
int offset = BKE_image_sequence_guess_offset(ima);
/* It is possible that image user in this node is not
@@ -238,104 +154,144 @@ static void cmp_node_image_create_outputs(bNodeTree *ntree, bNode *node)
RenderLayer *rl = BLI_findlink(&ima->rr->layers, iuser->layer);
if (rl) {
- if (ima->type != IMA_TYPE_MULTILAYER)
- cmp_node_image_add_render_pass_outputs(ntree, node, rl->passflag);
- else
- cmp_node_image_add_multilayer_outputs(ntree, node, rl);
+ RenderPass *rpass;
+ for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
+ int type;
+ if (rpass->channels == 1)
+ type = SOCK_FLOAT;
+ else
+ type = SOCK_RGBA;
+
+ cmp_node_image_add_pass_output(ntree, node, rpass->name, rpass->name, -1, type, false, available_sockets, &prev_index);
+ /* Special handling for the Combined pass to ensure compatibility. */
+ if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) {
+ cmp_node_image_add_pass_output(ntree, node, "Alpha", rpass->name, -1, SOCK_FLOAT, false, available_sockets, &prev_index);
+ }
+ }
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ return;
}
- else
- cmp_node_image_add_render_pass_outputs(ntree, node, RRES_OUT_IMAGE | RRES_OUT_ALPHA);
}
- else
- cmp_node_image_add_render_pass_outputs(ntree, node, RRES_OUT_IMAGE | RRES_OUT_ALPHA | RRES_OUT_Z);
-
+ }
+
+ cmp_node_image_add_pass_output(ntree, node, "Image", RE_PASSNAME_COMBINED, -1, SOCK_RGBA, false, available_sockets, &prev_index);
+ cmp_node_image_add_pass_output(ntree, node, "Alpha", RE_PASSNAME_COMBINED, -1, SOCK_FLOAT, false, available_sockets, &prev_index);
+
+ if (ima) {
BKE_image_release_ibuf(ima, ibuf, NULL);
}
- else
- cmp_node_image_add_render_pass_outputs(ntree, node, RRES_OUT_IMAGE | RRES_OUT_ALPHA);
}
-static bNodeSocket *cmp_node_image_output_find_match(bNode *UNUSED(node), bNodeSocket *newsock, ListBase *oldsocklist)
-{
- bNodeSocket *sock;
-
- for (sock = oldsocklist->first; sock; sock = sock->next)
- if (STREQ(sock->name, newsock->name))
- return sock;
- return NULL;
-}
+typedef struct RLayerUpdateData {
+ LinkNodePair *available_sockets;
+ int prev_index;
+} RLayerUpdateData;
-static bNodeSocket *cmp_node_image_output_relink(bNode *node, bNodeSocket *oldsock, int oldindex)
+void node_cmp_rlayers_register_pass(bNodeTree *ntree, bNode *node, Scene *scene, SceneRenderLayer *srl, const char *name, int type)
{
- bNodeSocket *sock;
-
- /* first try to find matching socket name */
- for (sock = node->outputs.first; sock; sock = sock->next)
- if (STREQ(sock->name, oldsock->name))
- return sock;
-
- /* no matching name, simply link to same index */
- return BLI_findlink(&node->outputs, oldindex);
+ RLayerUpdateData *data = node->storage;
+
+ if (scene == NULL || srl == NULL || data == NULL || node->id != (ID *)scene) {
+ return;
+ }
+
+ SceneRenderLayer *node_srl = BLI_findlink(&scene->r.layers, node->custom1);
+ if (node_srl != srl) {
+ return;
+ }
+
+ /* Special handling for the Combined pass to ensure compatibility. */
+ if (STREQ(name, RE_PASSNAME_COMBINED)) {
+ cmp_node_image_add_pass_output(ntree, node, "Image", name, -1, type, true, data->available_sockets, &data->prev_index);
+ cmp_node_image_add_pass_output(ntree, node, "Alpha", name, -1, SOCK_FLOAT, true, data->available_sockets, &data->prev_index);
+ }
+ else {
+ cmp_node_image_add_pass_output(ntree, node, name, name, -1, type, true, data->available_sockets, &data->prev_index);
+ }
}
-static void cmp_node_image_sync_output(bNode *UNUSED(node), bNodeSocket *UNUSED(newsock), bNodeSocket *UNUSED(oldsock))
+static void cmp_node_rlayer_create_outputs(bNodeTree *ntree, bNode *node, LinkNodePair *available_sockets)
{
- /* pass */
+ Scene *scene = (Scene *)node->id;
+
+ 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) {
+ 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);
+ RE_engine_free(engine);
+
+ MEM_freeN(data);
+ node->storage = NULL;
+
+ return;
+ }
+ }
+ }
+
+ int prev_index = -1;
+ cmp_node_image_add_pass_output(ntree, node, "Image", RE_PASSNAME_COMBINED, RRES_OUT_IMAGE, SOCK_RGBA, true, available_sockets, &prev_index);
+ cmp_node_image_add_pass_output(ntree, node, "Alpha", RE_PASSNAME_COMBINED, RRES_OUT_ALPHA, SOCK_FLOAT, true, available_sockets, &prev_index);
}
/* XXX make this into a generic socket verification function for dynamic socket replacement (multilayer, groups, static templates) */
-static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node)
+static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node, bool rlayer)
{
- bNodeSocket *newsock, *oldsock, *oldsock_next;
- ListBase oldsocklist;
- int oldindex;
- bNodeLink *link;
-
- /* store current nodes in oldsocklist, then clear socket list */
- oldsocklist = node->outputs;
- BLI_listbase_clear(&node->outputs);
+ bNodeSocket *sock, *sock_next;
+ LinkNodePair available_sockets = {NULL, NULL};
+ int sock_index;
/* XXX make callback */
- cmp_node_image_create_outputs(ntree, node);
-
- for (newsock = node->outputs.first; newsock; newsock = newsock->next) {
- /* XXX make callback */
- oldsock = cmp_node_image_output_find_match(node, newsock, &oldsocklist);
- if (oldsock) {
- /* XXX make callback */
- cmp_node_image_sync_output(node, newsock, oldsock);
+ if (rlayer)
+ cmp_node_rlayer_create_outputs(ntree, node, &available_sockets);
+ else
+ cmp_node_image_create_outputs(ntree, node, &available_sockets);
+
+ /* Get rid of sockets whose passes are not available in the image.
+ * If sockets that are not available would be deleted, the connections to them would be lost
+ * when e.g. opening a file (since there's no render at all yet).
+ * Therefore, sockets with connected links will just be set as unavailable.
+ *
+ * Another important detail comes from compatibility with the older socket model, where there
+ * was a fixed socket per pass type that was just hidden or not. Therefore, older versions expect
+ * the first 31 passes to belong to a specific pass type.
+ * So, we keep those 31 always allocated before the others as well, even if they have no links attached. */
+ sock_index = 0;
+ for (sock = node->outputs.first; sock; sock = sock_next, sock_index++) {
+ sock_next = sock->next;
+ if (BLI_linklist_index(available_sockets.list, sock) >= 0) {
+ sock->flag &= ~(SOCK_UNAVAIL | SOCK_HIDDEN);
}
- }
-
- /* move links to new socket */
- for (oldsock = oldsocklist.first, oldindex = 0; oldsock; oldsock = oldsock->next, ++oldindex) {
- newsock = cmp_node_image_output_relink(node, oldsock, oldindex);
-
- if (newsock) {
+ else {
+ bNodeLink *link;
for (link = ntree->links.first; link; link = link->next) {
- if (link->fromsock == oldsock)
- link->fromsock = newsock;
+ if (link->fromsock == sock) break;
+ }
+ if (!link && (!rlayer || sock_index > 30)) {
+ MEM_freeN(sock->storage);
+ nodeRemoveSocket(ntree, node, sock);
+ }
+ else {
+ sock->flag |= SOCK_UNAVAIL;
}
}
}
-
- /* delete old sockets
- * XXX oldsock is not actually in the node->outputs list any more,
- * but the nodeRemoveSocket function works anyway. In future this
- * should become part of the core code, so can take care of this behavior.
- */
- for (oldsock = oldsocklist.first; oldsock; oldsock = oldsock_next) {
- oldsock_next = oldsock->next;
- MEM_freeN(oldsock->storage);
- nodeRemoveSocket(ntree, node, oldsock);
- }
+
+ BLI_linklist_free(available_sockets.list, NULL);
}
static void cmp_node_image_update(bNodeTree *ntree, bNode *node)
{
/* avoid unnecessary updates, only changes to the image/image user data are of interest */
if (node->update & NODE_UPDATE_ID)
- cmp_node_image_verify_outputs(ntree, node);
+ cmp_node_image_verify_outputs(ntree, node, false);
}
static void node_composit_init_image(bNodeTree *ntree, bNode *node)
@@ -348,7 +304,7 @@ static void node_composit_init_image(bNodeTree *ntree, bNode *node)
iuser->ok = 1;
/* setup initial outputs */
- cmp_node_image_verify_outputs(ntree, node);
+ cmp_node_image_verify_outputs(ntree, node, false);
}
static void node_composit_free_image(bNode *node)
@@ -388,87 +344,44 @@ void register_node_type_cmp_image(void)
/* **************** RENDER RESULT ******************** */
-static void set_output_visible(bNode *node, int passflag, int index, int pass)
+void node_cmp_rlayers_outputs(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *sock = BLI_findlink(&node->outputs, index);
- bool pass_enabled = ((passflag & pass) != 0);
-#ifdef WITH_CYCLES_DEBUG
- pass_enabled |= (pass == SCE_PASS_DEBUG);
-#endif
- /* clear the SOCK_HIDDEN flag as well, in case a socket was hidden before */
- if (pass_enabled)
- sock->flag &= ~(SOCK_HIDDEN | SOCK_UNAVAIL);
- else
- sock->flag |= SOCK_UNAVAIL;
+ cmp_node_image_verify_outputs(ntree, node, true);
}
-/* clumsy checking... should do dynamic outputs once */
-void node_cmp_rlayers_force_hidden_passes(bNode *node)
+const char *node_cmp_rlayers_sock_to_pass(int sock_index)
{
- Scene *scene = (Scene *)node->id;
- SceneRenderLayer *srl;
- int passflag;
- bNodeSocket *sock;
-
- /* must always have valid scene pointer */
- if (!scene)
- return;
-
- srl = BLI_findlink(&scene->r.layers, node->custom1);
- if (!srl)
- return;
-
- passflag = srl->passflag;
-
- for (sock = node->outputs.first; sock; sock = sock->next)
- sock->flag &= ~SOCK_UNAVAIL;
-
- set_output_visible(node, passflag, RRES_OUT_IMAGE, SCE_PASS_COMBINED);
- set_output_visible(node, passflag, RRES_OUT_ALPHA, SCE_PASS_COMBINED);
-
- set_output_visible(node, passflag, RRES_OUT_Z, SCE_PASS_Z);
- set_output_visible(node, passflag, RRES_OUT_NORMAL, SCE_PASS_NORMAL);
- set_output_visible(node, passflag, RRES_OUT_VEC, SCE_PASS_VECTOR);
- set_output_visible(node, passflag, RRES_OUT_UV, SCE_PASS_UV);
- set_output_visible(node, passflag, RRES_OUT_RGBA, SCE_PASS_RGBA);
- set_output_visible(node, passflag, RRES_OUT_DIFF, SCE_PASS_DIFFUSE);
- set_output_visible(node, passflag, RRES_OUT_SPEC, SCE_PASS_SPEC);
- set_output_visible(node, passflag, RRES_OUT_SHADOW, SCE_PASS_SHADOW);
- set_output_visible(node, passflag, RRES_OUT_AO, SCE_PASS_AO);
- set_output_visible(node, passflag, RRES_OUT_REFLECT, SCE_PASS_REFLECT);
- set_output_visible(node, passflag, RRES_OUT_REFRACT, SCE_PASS_REFRACT);
- set_output_visible(node, passflag, RRES_OUT_INDIRECT, SCE_PASS_INDIRECT);
- set_output_visible(node, passflag, RRES_OUT_INDEXOB, SCE_PASS_INDEXOB);
- set_output_visible(node, passflag, RRES_OUT_INDEXMA, SCE_PASS_INDEXMA);
- set_output_visible(node, passflag, RRES_OUT_MIST, SCE_PASS_MIST);
- set_output_visible(node, passflag, RRES_OUT_EMIT, SCE_PASS_EMIT);
- set_output_visible(node, passflag, RRES_OUT_ENV, SCE_PASS_ENVIRONMENT);
- set_output_visible(node, passflag, RRES_OUT_DIFF_DIRECT, SCE_PASS_DIFFUSE_DIRECT);
- set_output_visible(node, passflag, RRES_OUT_DIFF_INDIRECT, SCE_PASS_DIFFUSE_INDIRECT);
- set_output_visible(node, passflag, RRES_OUT_DIFF_COLOR, SCE_PASS_DIFFUSE_COLOR);
- set_output_visible(node, passflag, RRES_OUT_GLOSSY_DIRECT, SCE_PASS_GLOSSY_DIRECT);
- set_output_visible(node, passflag, RRES_OUT_GLOSSY_INDIRECT, SCE_PASS_GLOSSY_INDIRECT);
- set_output_visible(node, passflag, RRES_OUT_GLOSSY_COLOR, SCE_PASS_GLOSSY_COLOR);
- set_output_visible(node, passflag, RRES_OUT_TRANSM_DIRECT, SCE_PASS_TRANSM_DIRECT);
- set_output_visible(node, passflag, RRES_OUT_TRANSM_INDIRECT, SCE_PASS_TRANSM_INDIRECT);
- set_output_visible(node, passflag, RRES_OUT_TRANSM_COLOR, SCE_PASS_TRANSM_COLOR);
- set_output_visible(node, passflag, RRES_OUT_SUBSURFACE_DIRECT, SCE_PASS_SUBSURFACE_DIRECT);
- set_output_visible(node, passflag, RRES_OUT_SUBSURFACE_INDIRECT, SCE_PASS_SUBSURFACE_INDIRECT);
- set_output_visible(node, passflag, RRES_OUT_SUBSURFACE_COLOR, SCE_PASS_SUBSURFACE_COLOR);
-
-#ifdef WITH_CYCLES_DEBUG
- set_output_visible(node, passflag, RRES_OUT_DEBUG, SCE_PASS_DEBUG);
-#endif
+ const char *sock_to_passname[] = {
+ RE_PASSNAME_COMBINED, RE_PASSNAME_COMBINED,
+ RE_PASSNAME_Z, RE_PASSNAME_NORMAL, RE_PASSNAME_UV, RE_PASSNAME_VECTOR, RE_PASSNAME_RGBA,
+ RE_PASSNAME_DIFFUSE, RE_PASSNAME_SPEC, RE_PASSNAME_SHADOW, RE_PASSNAME_AO,
+ RE_PASSNAME_REFLECT, RE_PASSNAME_REFRACT, RE_PASSNAME_INDIRECT,
+ RE_PASSNAME_INDEXOB, RE_PASSNAME_INDEXMA, RE_PASSNAME_MIST, RE_PASSNAME_EMIT, RE_PASSNAME_ENVIRONMENT,
+ RE_PASSNAME_DIFFUSE_DIRECT, RE_PASSNAME_DIFFUSE_INDIRECT, RE_PASSNAME_DIFFUSE_COLOR,
+ RE_PASSNAME_GLOSSY_DIRECT, RE_PASSNAME_GLOSSY_INDIRECT, RE_PASSNAME_GLOSSY_COLOR,
+ RE_PASSNAME_TRANSM_DIRECT, RE_PASSNAME_TRANSM_INDIRECT, RE_PASSNAME_TRANSM_COLOR,
+ RE_PASSNAME_SUBSURFACE_DIRECT, RE_PASSNAME_SUBSURFACE_INDIRECT, RE_PASSNAME_SUBSURFACE_COLOR
+ };
+ if (sock_index > 30) {
+ return NULL;
+ }
+ return sock_to_passname[sock_index];
}
static void node_composit_init_rlayers(const bContext *C, PointerRNA *ptr)
{
Scene *scene = CTX_data_scene(C);
bNode *node = ptr->data;
-
+ int sock_index = 0;
+
node->id = &scene->id;
-
- node_cmp_rlayers_force_hidden_passes(node);
+
+ for (bNodeSocket *sock = node->outputs.first; sock; sock = sock->next, sock_index++) {
+ NodeImageLayer *sockdata = MEM_callocN(sizeof(NodeImageLayer), "node image layer");
+ sock->storage = sockdata;
+
+ BLI_strncpy(sockdata->pass_name, node_cmp_rlayers_sock_to_pass(sock_index), sizeof(sockdata->pass_name));
+ }
}
static int node_composit_poll_rlayers(bNodeType *UNUSED(ntype), bNodeTree *ntree)
@@ -489,6 +402,29 @@ static int node_composit_poll_rlayers(bNodeType *UNUSED(ntype), bNodeTree *ntree
return false;
}
+static void node_composit_free_rlayers(bNode *node)
+{
+ bNodeSocket *sock;
+
+ /* free extra socket info */
+ for (sock = node->outputs.first; sock; sock = sock->next)
+ MEM_freeN(sock->storage);
+}
+
+static void node_composit_copy_rlayers(bNodeTree *UNUSED(dest_ntree), bNode *UNUSED(dest_node), bNode *src_node)
+{
+ bNodeSocket *sock;
+
+ /* copy extra socket info */
+ for (sock = src_node->outputs.first; sock; sock = sock->next)
+ sock->new_sock->storage = MEM_dupallocN(sock->storage);
+}
+
+static void cmp_node_rlayers_update(bNodeTree *ntree, bNode *node)
+{
+ cmp_node_image_verify_outputs(ntree, node, true);
+}
+
void register_node_type_cmp_rlayers(void)
{
static bNodeType ntype;
@@ -497,6 +433,9 @@ void register_node_type_cmp_rlayers(void)
node_type_socket_templates(&ntype, NULL, cmp_node_rlayers_out);
ntype.initfunc_api = node_composit_init_rlayers;
ntype.poll = node_composit_poll_rlayers;
+ 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);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_outputFile.c b/source/blender/nodes/composite/nodes/node_composite_outputFile.c
index 7d1087435c2..6a96f1b30d8 100644
--- a/source/blender/nodes/composite/nodes/node_composite_outputFile.c
+++ b/source/blender/nodes/composite/nodes/node_composite_outputFile.c
@@ -32,7 +32,7 @@
#include <string.h>
#include "BLI_utildefines.h"
-#include "BLI_path_util.h"
+#include "BLI_string_utils.h"
#include "BKE_context.h"
diff --git a/source/blender/nodes/composite/nodes/node_composite_switchview.c b/source/blender/nodes/composite/nodes/node_composite_switchview.c
index d805cf4d87f..e0d9fa33f13 100644
--- a/source/blender/nodes/composite/nodes/node_composite_switchview.c
+++ b/source/blender/nodes/composite/nodes/node_composite_switchview.c
@@ -137,7 +137,6 @@ static void init_switch_view(const bContext *C, PointerRNA *ptr)
cmp_node_switch_view_sanitycheck(ntree, node);
}
-/* custom1 = mix type */
void register_node_type_cmp_switch_view(void)
{
static bNodeType ntype;
diff --git a/source/blender/nodes/intern/node_common.c b/source/blender/nodes/intern/node_common.c
index 12cd93e418b..736f17f1d70 100644
--- a/source/blender/nodes/intern/node_common.c
+++ b/source/blender/nodes/intern/node_common.c
@@ -78,7 +78,7 @@ bNodeSocket *node_group_find_output_socket(bNode *groupnode, const char *identif
/* groups display their internal tree name as label */
void node_group_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
{
- BLI_strncpy(label, (node->id) ? node->id->name + 2 : IFACE_("Missing Datablock"), maxlen);
+ BLI_strncpy(label, (node->id) ? node->id->name + 2 : IFACE_("Missing Data-Block"), maxlen);
}
int node_group_poll_instance(bNode *node, bNodeTree *nodetree)
@@ -178,9 +178,14 @@ void node_group_verify(struct bNodeTree *ntree, struct bNode *node, struct ID *i
{
/* check inputs and outputs, and remove or insert them */
if (id == node->id) {
- bNodeTree *ngroup = (bNodeTree *)node->id;
- group_verify_socket_list(ntree, node, &ngroup->inputs, &node->inputs, SOCK_IN);
- group_verify_socket_list(ntree, node, &ngroup->outputs, &node->outputs, SOCK_OUT);
+ if (id == NULL) {
+ nodeRemoveAllSockets(ntree, node);
+ }
+ else {
+ bNodeTree *ngroup = (bNodeTree *)node->id;
+ group_verify_socket_list(ntree, node, &ngroup->inputs, &node->inputs, SOCK_IN);
+ group_verify_socket_list(ntree, node, &ngroup->outputs, &node->outputs, SOCK_OUT);
+ }
}
}
diff --git a/source/blender/nodes/intern/node_exec.c b/source/blender/nodes/intern/node_exec.c
index 2347564c696..0cf131adbdc 100644
--- a/source/blender/nodes/intern/node_exec.c
+++ b/source/blender/nodes/intern/node_exec.c
@@ -78,7 +78,8 @@ void node_get_stack(bNode *node, bNodeStack *stack, bNodeStack **in, bNodeStack
static void node_init_input_index(bNodeSocket *sock, int *index)
{
- if (sock->link && sock->link->fromsock) {
+ /* Only consider existing link if from socket is valid! */
+ if (sock->link && sock->link->fromsock && sock->link->fromsock->stack_index >= 0) {
sock->stack_index = sock->link->fromsock->stack_index;
}
else {
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index 8523b7275bf..b5d77e99328 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -79,7 +79,8 @@ 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;
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *ob = OBACT_NEW;
if ((snode->shaderfrom == SNODE_SHADER_OBJECT) ||
(BKE_scene_use_new_shading_nodes(scene) == false))
@@ -327,7 +328,8 @@ static void ntree_shader_link_builtin_group_normal(
/* Need to update tree so all node instances nodes gets proper sockets. */
bNode *group_input_node = ntreeFindType(group_ntree, NODE_GROUP_INPUT);
node_group_verify(ntree, group_node, &group_ntree->id);
- node_group_input_verify(group_ntree, group_input_node, &group_ntree->id);
+ if (group_input_node)
+ node_group_input_verify(group_ntree, group_input_node, &group_ntree->id);
ntreeUpdateTree(G.main, group_ntree);
/* Assumes sockets are always added at the end. */
bNodeSocket *group_node_normal_socket = group_node->inputs.last;
@@ -370,7 +372,7 @@ static void ntree_shader_link_builtin_group_normal(
group_displacement_socket);
ntreeUpdateTree(G.main, group_ntree);
}
- else {
+ else if (group_input_node) {
/* Connect group node normal input. */
nodeAddLink(ntree,
node_from, socket_from,
diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c
index 9bd43f331fb..8559765e315 100644
--- a/source/blender/nodes/shader/node_shader_util.c
+++ b/source/blender/nodes/shader/node_shader_util.c
@@ -142,28 +142,40 @@ void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns)
{
memset(gs, 0, sizeof(*gs));
- nodestack_get_vec(gs->vec, type, ns);
- gs->link = ns->data;
-
- if (type == SOCK_FLOAT)
- gs->type = GPU_FLOAT;
- else if (type == SOCK_VECTOR)
- gs->type = GPU_VEC3;
- else if (type == SOCK_RGBA)
- gs->type = GPU_VEC4;
- else if (type == SOCK_SHADER)
- gs->type = GPU_VEC4;
- else
+ if (ns == NULL) {
+ /* node_get_stack() will generate NULL bNodeStack pointers for unknown/unsuported types of sockets... */
+ zero_v4(gs->vec);
+ gs->link = NULL;
gs->type = GPU_NONE;
+ gs->name = "";
+ gs->hasinput = false;
+ gs->hasoutput = false;
+ gs->sockettype = type;
+ }
+ else {
+ nodestack_get_vec(gs->vec, type, ns);
+ gs->link = ns->data;
- 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
- * further investigation.
- */
- gs->hasoutput = ns->hasoutput /*&& ns->data*/;
- gs->sockettype = ns->sockettype;
+ if (type == SOCK_FLOAT)
+ gs->type = GPU_FLOAT;
+ else if (type == SOCK_VECTOR)
+ gs->type = GPU_VEC3;
+ else if (type == SOCK_RGBA)
+ gs->type = GPU_VEC4;
+ else if (type == SOCK_SHADER)
+ 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
+ * further investigation.
+ */
+ gs->hasoutput = ns->hasoutput /*&& ns->data*/;
+ gs->sockettype = ns->sockettype;
+ }
}
void node_data_from_gpu_stack(bNodeStack *ns, GPUNodeStack *gs)
diff --git a/source/blender/nodes/shader/node_shader_util.h b/source/blender/nodes/shader/node_shader_util.h
index 4cb39e0f13b..148888f7693 100644
--- a/source/blender/nodes/shader/node_shader_util.h
+++ b/source/blender/nodes/shader/node_shader_util.h
@@ -76,7 +76,9 @@
#include "RE_pipeline.h"
#include "RE_shader_ext.h"
+#include "GPU_lamp.h"
#include "GPU_material.h"
+#include "GPU_uniformbuffer.h"
int sh_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree);
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..d3bb8fccf71 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 */
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 878f8562619..cb4335ca9a7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c
+++ b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c
@@ -39,9 +39,9 @@ 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));
+ return GPU_stack_link(mat, node, "node_ambient_occlusion", in, out, GPU_builtin(GPU_VIEW_NORMAL));
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_attribute.c b/source/blender/nodes/shader/nodes/node_shader_attribute.c
index 0a69593cf07..3c9b21a4198 100644
--- a/source/blender/nodes/shader/nodes/node_shader_attribute.c
+++ b/source/blender/nodes/shader/nodes/node_shader_attribute.c
@@ -47,7 +47,7 @@ static int node_shader_gpu_attribute(GPUMaterial *mat, bNode *node, bNodeExecDat
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);
+ return GPU_stack_link(mat, node, "node_attribute", in, out, cd_attr);
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_background.c b/source/blender/nodes/shader/nodes/node_shader_background.c
index b387529e456..4ea675f9e0c 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 */
diff --git a/source/blender/nodes/shader/nodes/node_shader_brightness.c b/source/blender/nodes/shader/nodes/node_shader_brightness.c
index e992c0773c2..457708405af 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)
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 01ca0bd6512..13e8ac67f63 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,12 @@ 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);
+ return GPU_stack_link(mat, node, "node_bsdf_anisotropic", in, out);
}
/* node type definition */
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..be7012712cc 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,12 @@ 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);
+ return GPU_stack_link(mat, node, "node_bsdf_diffuse", in, out);
}
/* node type definition */
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 5569fe85489..25f76ba9ecb 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,12 @@ 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);
+ return GPU_stack_link(mat, node, "node_bsdf_glass", in, out);
}
/* node type definition */
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 7e1bc971c73..456c000a39b 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,12 @@ 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);
+ return GPU_stack_link(mat, node, "node_bsdf_glossy", in, out);
}
/* node type definition */
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 25be59f091d..b8078ac60ac 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 */
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
new file mode 100644
index 00000000000..4ae0474d685
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.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) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../node_shader_util.h"
+
+/* **************** OUTPUT ******************** */
+
+static bNodeSocketTemplate sh_node_bsdf_principled_in[] = {
+ { SOCK_RGBA, 1, N_("Base Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 1, N_("Subsurface"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_VECTOR, 1, N_("Subsurface Radius"), 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 100.0f},
+ { SOCK_RGBA, 1, N_("Subsurface Color"), 0.7f, 0.1f, 0.1f, 1.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 1, N_("Metallic"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Specular"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Specular Tint"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Roughness"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Anisotropic"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Anisotropic Rotation"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Sheen"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Sheen Tint"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Clearcoat"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Clearcoat Roughness"), 0.03f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("IOR"), 1.45f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
+ { SOCK_FLOAT, 1, N_("Transmission"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Transmission Roughness"),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_VECTOR, 1, N_("Clearcoat Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ { SOCK_VECTOR, 1, N_("Tangent"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ { -1, 0, "" }
+};
+
+static bNodeSocketTemplate sh_node_bsdf_principled_out[] = {
+ { SOCK_SHADER, 0, N_("BSDF")},
+ { -1, 0, "" }
+};
+
+static void node_shader_init_principled(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->custom1 = SHD_GLOSSY_MULTI_GGX;
+}
+
+static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+{
+#if 0 /* Old 2.7 glsl viewport */
+ // 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);
+#endif
+
+ /* 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);
+ }
+
+ /* Only use complex versions when needed. */
+ if (!in[12].link && (in[12].vec[0] == 0.0f)) {
+ return GPU_stack_link(mat, node, "node_bsdf_principled_simple", in, out, GPU_builtin(GPU_VIEW_POSITION));
+ }
+ else {
+ return GPU_stack_link(mat, node, "node_bsdf_principled_clearcoat", in, out, GPU_builtin(GPU_VIEW_POSITION));
+ }
+}
+
+static void node_shader_update_principled(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sock;
+ int distribution = node->custom1;
+
+ for (sock = node->inputs.first; sock; sock = sock->next) {
+ if (STREQ(sock->name, "Transmission Roughness")) {
+ if (distribution == SHD_GLOSSY_GGX)
+ sock->flag &= ~SOCK_UNAVAIL;
+ else
+ sock->flag |= SOCK_UNAVAIL;
+
+ }
+ }
+}
+
+/* node type definition */
+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_MIDDLE);
+ node_type_init(&ntype, node_shader_init_principled);
+ node_type_storage(&ntype, "", NULL, NULL);
+ node_type_gpu(&ntype, node_shader_gpu_bsdf_principled);
+ node_type_update(&ntype, node_shader_update_principled, NULL);
+
+ nodeRegisterType(&ntype);
+}
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 c447f5de219..9dbe3361e8b 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,12 @@ 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);
+ return GPU_stack_link(mat, node, "node_bsdf_refraction", in, out);
}
/* node type definition */
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 c3510beb470..28941fbd662 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 */
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 3b88d609cdb..f6f6da524d5 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,12 @@ 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);
+ return GPU_stack_link(mat, node, "node_bsdf_translucent", in, out);
}
/* node type definition */
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 5cb50b00e1a..76afe935433 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 */
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 ef3d52ecbce..6d61f3f7473 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,12 @@ 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);
+ return GPU_stack_link(mat, node, "node_bsdf_velvet", in, out);
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.c b/source/blender/nodes/shader/nodes/node_shader_bump.c
index b39ca5d90ee..15a8c47db7a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bump.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bump.c
@@ -52,7 +52,7 @@ static int gpu_shader_bump(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(
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));
+ GPU_stack_link(mat, node, "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.
*
diff --git a/source/blender/nodes/shader/nodes/node_shader_camera.c b/source/blender/nodes/shader/nodes/node_shader_camera.c
index 3bdb5c36d69..ac0880d22ba 100644
--- a/source/blender/nodes/shader/nodes/node_shader_camera.c
+++ b/source/blender/nodes/shader/nodes/node_shader_camera.c
@@ -52,7 +52,7 @@ static void node_shader_exec_camera(void *data, int UNUSED(thread), bNode *UNUSE
}
}
-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;
@@ -62,7 +62,7 @@ static int gpu_shader_camera(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecDat
if (GPU_material_use_new_shading_nodes(mat))
GPU_link(mat, "invert_z", viewvec, &viewvec);
- return GPU_stack_link(mat, "camera", in, out, viewvec);
+ return GPU_stack_link(mat, node, "camera", in, out, viewvec);
}
void register_node_type_sh_camera(void)
diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.c b/source/blender/nodes/shader/nodes/node_shader_curves.c
index 5e067e6c630..ceba8fd1248 100644
--- a/source/blender/nodes/shader/nodes/node_shader_curves.c
+++ b/source/blender/nodes/shader/nodes/node_shader_curves.c
@@ -66,7 +66,7 @@ static int gpu_shader_curve_vec(GPUMaterial *mat, bNode *node, bNodeExecData *UN
int size;
curvemapping_table_RGBA(node->storage, &array, &size);
- return GPU_stack_link(mat, "curves_vec", in, out, GPU_texture(size, array));
+ return GPU_stack_link(mat, node, "curves_vec", in, out, GPU_texture(size, array));
}
void register_node_type_sh_curve_vec(void)
@@ -125,7 +125,7 @@ static int gpu_shader_curve_rgb(GPUMaterial *mat, bNode *node, bNodeExecData *UN
curvemapping_initialize(node->storage);
curvemapping_table_RGBA(node->storage, &array, &size);
- return GPU_stack_link(mat, "curves_rgb", in, out, GPU_texture(size, array));
+ return GPU_stack_link(mat, node, "curves_rgb", in, out, GPU_texture(size, array));
}
void register_node_type_sh_curve_rgb(void)
diff --git a/source/blender/nodes/shader/nodes/node_shader_eevee_metallic.c b/source/blender/nodes/shader/nodes/node_shader_eevee_metallic.c
new file mode 100644
index 00000000000..2a8a3a44f39
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_eevee_metallic.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_metallic_in[] = {
+ { SOCK_RGBA, 1, N_("Base Color"), 0.8f, 0.8f, 0.8f, 1.0f},
+ { SOCK_FLOAT, 1, N_("Metallic"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Specular"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { 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_metallic_out[] = {
+ { SOCK_SHADER, 0, N_("BSDF")},
+ { -1, 0, "" }
+};
+
+static int node_shader_gpu_eevee_metallic(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+{
+ static float one = 1.0f;
+
+ /* Normals */
+ if (!in[6].link) {
+ GPU_link(mat, "world_normals_get", &in[6].link);
+ }
+
+ /* Clearcoat Normals */
+ if (!in[9].link) {
+ GPU_link(mat, "world_normals_get", &in[9].link);
+ }
+
+ /* Occlusion */
+ if (!in[10].link) {
+ GPU_link(mat, "set_value", GPU_uniform(&one), &in[10].link);
+ }
+
+ return GPU_stack_link(mat, node, "node_eevee_metallic", in, out);
+}
+
+
+/* node type definition */
+void register_node_type_sh_eevee_metallic(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_EEVEE_METALLIC, "Metallic", NODE_CLASS_SHADER, 0);
+ node_type_compatibility(&ntype, NODE_NEW_SHADING);
+ node_type_socket_templates(&ntype, sh_node_eevee_metallic_in, sh_node_eevee_metallic_out);
+ node_type_init(&ntype, NULL);
+ node_type_storage(&ntype, "", NULL, NULL);
+ node_type_gpu(&ntype, node_shader_gpu_eevee_metallic);
+
+ nodeRegisterType(&ntype);
+}
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..954f9b3ee4a
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_eevee_specular.c
@@ -0,0 +1,87 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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_uniform(&one), &in[9].link);
+ }
+
+ return GPU_stack_link(mat, node, "node_eevee_specular", in, out);
+}
+
+
+/* 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_compatibility(&ntype, NODE_NEW_SHADING);
+ 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 51b3d5740a7..0901e8204f8 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 */
diff --git a/source/blender/nodes/shader/nodes/node_shader_fresnel.c b/source/blender/nodes/shader/nodes/node_shader_fresnel.c
index b50f722c71b..e78bb2b0b24 100644
--- a/source/blender/nodes/shader/nodes/node_shader_fresnel.c
+++ b/source/blender/nodes/shader/nodes/node_shader_fresnel.c
@@ -39,14 +39,36 @@ 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)
+ if (!in[1].link) {
in[1].link = GPU_builtin(GPU_VIEW_NORMAL);
- else
+ }
+ else if (GPU_material_use_world_space_shading(mat)) {
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 *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out)
+{
+ ShadeInput *shi = ((ShaderCallData *)data)->shi;
+ float eta = max_ff(in[0]->vec[0], 0.00001);
+
+ float n[3];
+ if (in[1]->hasinput) {
+ copy_v3_v3(n, in[1]->vec);
+ }
+ 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, shi->flippednor ? 1 / eta : eta);
}
/* node type definition */
@@ -55,11 +77,12 @@ 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_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);
node_type_gpu(&ntype, node_shader_gpu_fresnel);
+ node_type_exec(&ntype, NULL, NULL, node_shader_exec_fresnel);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_gamma.c b/source/blender/nodes/shader/nodes/node_shader_gamma.c
index 37439569f77..1aebfbe5888 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)
diff --git a/source/blender/nodes/shader/nodes/node_shader_geom.c b/source/blender/nodes/shader/nodes/node_shader_geom.c
index b289d66efc3..57bef4a6784 100644
--- a/source/blender/nodes/shader/nodes/node_shader_geom.c
+++ b/source/blender/nodes/shader/nodes/node_shader_geom.c
@@ -136,7 +136,7 @@ static int gpu_shader_geom(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(
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,
+ bool ret = GPU_stack_link(mat, node, "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)) {
diff --git a/source/blender/nodes/shader/nodes/node_shader_geometry.c b/source/blender/nodes/shader/nodes/node_shader_geometry.c
index 553ea65154f..6647f27e5c9 100644
--- a/source/blender/nodes/shader/nodes/node_shader_geometry.c
+++ b/source/blender/nodes/shader/nodes/node_shader_geometry.c
@@ -41,10 +41,11 @@ 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_attribute(CD_ORCO, ""), GPU_builtin(GPU_OBJECT_MATRIX),
GPU_builtin(GPU_INVERSE_VIEW_MATRIX));
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
index 6fe6a33010a..9eaa0c9f91c 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)
diff --git a/source/blender/nodes/shader/nodes/node_shader_invert.c b/source/blender/nodes/shader/nodes/node_shader_invert.c
index 27450ba0fe6..6a54733006d 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)
diff --git a/source/blender/nodes/shader/nodes/node_shader_lamp.c b/source/blender/nodes/shader/nodes/node_shader_lamp.c
index 2c96c91958e..3c41227ab8b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_lamp.c
+++ b/source/blender/nodes/shader/nodes/node_shader_lamp.c
@@ -68,7 +68,7 @@ static int gpu_shader_lamp(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(
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);
+ bool ret = GPU_stack_link(mat, node, "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;
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 8cbc587e339..e84d8e7241c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_layer_weight.c
+++ b/source/blender/nodes/shader/nodes/node_shader_layer_weight.c
@@ -41,14 +41,43 @@ 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)
in[1].link = GPU_builtin(GPU_VIEW_NORMAL);
- else
+ else if (GPU_material_use_world_space_shading(mat)) {
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 *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out)
+{
+ ShadeInput *shi = ((ShaderCallData *)data)->shi;
+ float blend = in[0]->vec[0];
+ float eta = max_ff(1 - blend, 0.00001);
+
+ float n[3];
+ if (in[1]->hasinput) {
+ copy_v3_v3(n, in[1]->vec);
+ }
+ 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, shi->flippednor ? eta : 1 / 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 */
@@ -57,11 +86,12 @@ 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_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);
node_type_gpu(&ntype, node_shader_gpu_layer_weight);
+ node_type_exec(&ntype, NULL, NULL, node_shader_exec_layer_weight);
nodeRegisterType(&ntype);
}
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 3aad476ea05..a51e4dc720f 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 */
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 b1001cd3937..be6db9c8269 100644
--- a/source/blender/nodes/shader/nodes/node_shader_light_path.c
+++ b/source/blender/nodes/shader/nodes/node_shader_light_path.c
@@ -39,14 +39,16 @@ static bNodeSocketTemplate sh_node_light_path_out[] = {
{ SOCK_FLOAT, 0, N_("Is Transmission Ray"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 0, N_("Ray Length"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 0, N_("Ray Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, N_("Diffuse Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, N_("Glossy Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 0, N_("Transparent Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 0, N_("Transmission Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ -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 */
diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.c b/source/blender/nodes/shader/nodes/node_shader_mapping.c
index 2044f5390cc..7f25b298cb2 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mapping.c
+++ b/source/blender/nodes/shader/nodes/node_shader_mapping.c
@@ -94,7 +94,7 @@ static int gpu_shader_mapping(GPUMaterial *mat, bNode *node, bNodeExecData *UNUS
GPUNodeLink *tdomin = GPU_uniform(&domin);
GPUNodeLink *tdomax = GPU_uniform(&domax);
- GPU_stack_link(mat, "mapping", in, out, tmat, tmin, tmax, tdomin, tdomax);
+ GPU_stack_link(mat, node, "mapping", in, out, tmat, tmin, tmax, tdomin, tdomax);
if (texmap->type == TEXMAP_TYPE_NORMAL)
GPU_link(mat, "texco_norm", out[0].link, &out[0].link);
diff --git a/source/blender/nodes/shader/nodes/node_shader_material.c b/source/blender/nodes/shader/nodes/node_shader_material.c
index 8b21b1ff33b..6850cdbf6ea 100644
--- a/source/blender/nodes/shader/nodes/node_shader_material.c
+++ b/source/blender/nodes/shader/nodes/node_shader_material.c
@@ -223,12 +223,27 @@ static void node_shader_init_material(bNodeTree *UNUSED(ntree), bNode *node)
/* 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(GPUNodeStack *in)
+static GPUNodeLink *gpu_get_input_link(GPUMaterial *mat, GPUNodeStack *in)
{
- if (in->link)
+ if (in->link) {
return in->link;
- else
- return GPU_uniform(in->vec);
+ }
+ 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)
@@ -251,18 +266,18 @@ static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNU
/* write values */
if (hasinput[MAT_IN_COLOR])
- shi.rgb = gpu_get_input_link(&in[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(&in[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(&in[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(&in[MAT_IN_NORMAL]);
+ 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);
@@ -276,15 +291,15 @@ static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNU
if (node->type == SH_NODE_MATERIAL_EXT) {
if (hasinput[MAT_IN_MIR])
- shi.mir = gpu_get_input_link(&in[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(&in[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(&in[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(&in[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(&in[MAT_IN_ALPHA]);
+ shi.alpha = gpu_get_input_link(mat, &in[MAT_IN_ALPHA]);
}
GPU_shaderesult_set(&shi, &shr); /* clears shr */
diff --git a/source/blender/nodes/shader/nodes/node_shader_math.c b/source/blender/nodes/shader/nodes/node_shader_math.c
index 2a1e936570d..6cd58d2fb85 100644
--- a/source/blender/nodes/shader/nodes/node_shader_math.c
+++ b/source/blender/nodes/shader/nodes/node_shader_math.c
@@ -249,7 +249,7 @@ static int gpu_shader_math(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(
case NODE_MATH_LESS:
case NODE_MATH_GREATER:
case NODE_MATH_MOD:
- 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:
@@ -264,14 +264,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:
diff --git a/source/blender/nodes/shader/nodes/node_shader_mixRgb.c b/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
index f911fa058dc..cca0a1e0561 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
@@ -71,7 +71,8 @@ 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};
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 7c5362a8969..5ac576004be 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 */
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal.c b/source/blender/nodes/shader/nodes/node_shader_normal.c
index 092fc201aa7..64f3ec94369 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal.c
@@ -58,14 +58,14 @@ 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);
+ return GPU_stack_link(mat, node, "normal_new_shading", in, out, vec);
}
else {
- return GPU_stack_link(mat, "normal", in, out, vec);
+ return GPU_stack_link(mat, node, "normal", in, out, vec);
}
}
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 48d1688c386..36d7522e3e6 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
@@ -46,8 +46,10 @@ static void node_shader_init_normal_map(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = attr;
}
-static void node_shader_exec_normal_map(void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out)
- {
+static void node_shader_exec_normal_map(
+ void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata),
+ bNodeStack **in, bNodeStack **out)
+{
if (data) {
ShadeInput *shi = ((ShaderCallData *)data)->shi;
@@ -63,7 +65,7 @@ static void node_shader_exec_normal_map(void *data, int UNUSED(thread), bNode *n
CLAMP_MIN(strength, 0.0f);
- float *N = shi->vno;
+ float *N = shi->nmapnorm;
int uv_index = 0;
switch (nm->space) {
case SHD_NORMAL_MAP_TANGENT:
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 d1905246fd4..471331beae3 100644
--- a/source/blender/nodes/shader/nodes/node_shader_object_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_object_info.c
@@ -37,9 +37,18 @@ 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);
+ 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)
+{
+ 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 */
@@ -53,6 +62,7 @@ void register_node_type_sh_object_info(void)
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
node_type_gpu(&ntype, node_shader_gpu_object_info);
+ node_type_exec(&ntype, NULL, NULL, node_shader_exec_object_info);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_output.c b/source/blender/nodes/shader/nodes/node_shader_output.c
index 789df09d898..dcf6fec41a4 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output.c
+++ b/source/blender/nodes/shader/nodes/node_shader_output.c
@@ -32,6 +32,8 @@
#include "node_shader_util.h"
+#include "BKE_scene.h"
+
/* **************** OUTPUT ******************** */
static bNodeSocketTemplate sh_node_output_in[] = {
{ SOCK_RGBA, 1, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f},
@@ -65,7 +67,7 @@ static void node_shader_exec_output(void *data, int UNUSED(thread), bNode *node,
}
}
-static int gpu_shader_output(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int gpu_shader_output(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
GPUNodeLink *outlink;
@@ -74,7 +76,11 @@ static int gpu_shader_output(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecDat
GPU_material_enable_alpha(mat);
#endif
- GPU_stack_link(mat, "output_node", in, out, &outlink);
+ if (BKE_scene_uses_blender_eevee(GPU_material_scene(mat))) {
+ return false;
+ }
+
+ GPU_stack_link(mat, node, "output_node", in, out, &outlink);
GPU_material_output_link(mat, outlink);
return 1;
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_eevee_material.c b/source/blender/nodes/shader/nodes/node_shader_output_eevee_material.c
new file mode 100644
index 00000000000..faf715f2b66
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_output_eevee_material.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) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../node_shader_util.h"
+
+#include "BKE_scene.h"
+
+/* **************** OUTPUT ******************** */
+
+static bNodeSocketTemplate sh_node_output_eevee_material_in[] = {
+ { SOCK_SHADER, 1, N_("Surface")},
+ { -1, 0, "" }
+};
+
+static int node_shader_gpu_output_eevee_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+{
+ GPUNodeLink *outlink;
+
+ GPU_stack_link(mat, node, "node_output_eevee_material", in, out, &outlink);
+ GPU_material_output_link(mat, outlink);
+
+ return true;
+}
+
+
+/* node type definition */
+void register_node_type_sh_output_eevee_material(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_OUTPUT_EEVEE_MATERIAL, "Material Output", NODE_CLASS_OUTPUT, 0);
+ node_type_compatibility(&ntype, NODE_NEW_SHADING);
+ node_type_socket_templates(&ntype, sh_node_output_eevee_material_in, NULL);
+ node_type_init(&ntype, NULL);
+ node_type_storage(&ntype, "", NULL, NULL);
+ node_type_gpu(&ntype, node_shader_gpu_output_eevee_material);
+
+ /* 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_material.c b/source/blender/nodes/shader/nodes/node_shader_output_material.c
index 336536b21ee..953999a0d48 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,15 @@ 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);
+ if (BKE_scene_uses_blender_eevee(GPU_material_scene(mat))) {
+ return false;
+ }
+
+ GPU_stack_link(mat, node, "node_output_material", in, out, &outlink);
GPU_material_output_link(mat, outlink);
return true;
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 f95cc842720..abab4fc351a 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;
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 5f0d81e98c9..8bdc88292e7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_particle_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_particle_info.c
@@ -48,10 +48,10 @@ static void node_shader_exec_particle_info(void *data, int UNUSED(thread), bNode
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);
}
-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),
diff --git a/source/blender/nodes/shader/nodes/node_shader_rgb.c b/source/blender/nodes/shader/nodes/node_shader_rgb.c
index 4f345bf2067..b9c051c0441 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)
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c b/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c
index b5b15397595..d031a2e412f 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)
@@ -94,9 +94,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)
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c
index 006ba34c3f3..682909edb0e 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)
@@ -98,9 +98,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)
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c
index 6375dcc8782..fce62f730b9 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)
@@ -75,9 +75,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)
diff --git a/source/blender/nodes/shader/nodes/node_shader_squeeze.c b/source/blender/nodes/shader/nodes/node_shader_squeeze.c
index a4c995748d9..2a1fbc2d02d 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)
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 7dfac32e85b..e34ff0aa420 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,12 @@ 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);
+ return GPU_stack_link(mat, node, "node_subsurface_scattering", in, out);
}
static void node_shader_update_subsurface_scattering(bNodeTree *UNUSED(ntree), bNode *node)
diff --git a/source/blender/nodes/shader/nodes/node_shader_tangent.c b/source/blender/nodes/shader/nodes/node_shader_tangent.c
index 7aa7fb43221..f2c59ec8fd8 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tangent.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tangent.c
@@ -41,6 +41,28 @@ 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)
{
@@ -51,6 +73,7 @@ void register_node_type_sh_tangent(void)
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 bb7f2166a8a..20ea162d98f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
@@ -36,6 +36,7 @@ static bNodeSocketTemplate sh_node_tex_brick_in[] = {
{ SOCK_RGBA, 1, N_("Mortar"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
{ SOCK_FLOAT, 1, N_("Scale"), 5.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
{ SOCK_FLOAT, 1, N_("Mortar Size"), 0.02f, 0.0f, 0.0f, 0.0f, 0.0f, 0.125f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
+ { SOCK_FLOAT, 1, N_("Mortar Smooth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
{ SOCK_FLOAT, 1, N_("Bias"), 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
{ SOCK_FLOAT, 1, N_("Brick Width"), 0.5f, 0.0f, 0.0f, 0.0f, 0.01f, 100.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
{ SOCK_FLOAT, 1, N_("Row Height"), 0.25f, 0.0f, 0.0f, 0.0f, 0.01f, 100.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
@@ -60,6 +61,12 @@ static void node_shader_init_tex_brick(bNodeTree *UNUSED(ntree), bNode *node)
tex->squash_freq = 2;
node->storage = tex;
+
+ for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) {
+ if (STREQ(sock->name, "Mortar Smooth")) {
+ ((bNodeSocketValueFloat *)sock->default_value)->value = 0.1f;
+ }
+ }
}
static int node_shader_gpu_tex_brick(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
@@ -73,7 +80,7 @@ static int node_shader_gpu_tex_brick(GPUMaterial *mat, bNode *node, bNodeExecDat
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));
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 77edd0e115e..3dbf98a929c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
@@ -61,7 +61,7 @@ static int node_shader_gpu_tex_checker(GPUMaterial *mat, bNode *node, bNodeExecD
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 */
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 be393582a42..99ab4ad2c20 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c
@@ -42,20 +42,20 @@ 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,
+ if (type == GPU_MATERIAL_TYPE_WORLD) {
+ return GPU_stack_link(mat, node, "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);
}
else {
- return GPU_stack_link(mat, "node_tex_coord_background", in, out,
+ 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);
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 2f8f95b0675..4d98b142f37 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
@@ -62,7 +62,7 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, bNode *node, bNodeE
int isdata = tex->color_space == SHD_COLORSPACE_NONE;
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);
@@ -76,9 +76,9 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, bNode *node, bNodeE
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));
+ GPU_stack_link(mat, node, "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));
+ GPU_stack_link(mat, node, "node_tex_environment_mirror_ball", in, out, GPU_image(ima, iuser, isdata));
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
if (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&
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 18a8065fb57..13d3438587c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c
@@ -61,7 +61,7 @@ static int node_shader_gpu_tex_gradient(GPUMaterial *mat, bNode *node, bNodeExec
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_uniform(&gradient_type));
}
/* node type definition */
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 71200dfe9d3..c86a502b666 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
@@ -66,7 +66,7 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecDat
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);
if (!in[0].link)
in[0].link = GPU_attribute(CD_MTFACE, "");
@@ -75,7 +75,7 @@ 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));
+ GPU_stack_link(mat, node, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
break;
case SHD_PROJ_BOX:
GPU_link(mat, "direction_transform_m4v3", GPU_builtin(GPU_VIEW_NORMAL),
@@ -94,12 +94,12 @@ 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));
+ GPU_stack_link(mat, node, "node_tex_image", 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));
+ GPU_stack_link(mat, node, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
break;
}
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 8700d7954e7..7cd79067693 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
@@ -64,7 +64,7 @@ static int node_shader_gpu_tex_magic(GPUMaterial *mat, bNode *node, bNodeExecDat
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_uniform(&depth));
}
/* node type definition */
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 51d6699fadd..e36b2d5b95b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
@@ -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_uniform(&type));
}
/* node type definition */
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 91015b3db25..38b208fc876 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
@@ -61,7 +61,7 @@ static int node_shader_gpu_tex_noise(GPUMaterial *mat, bNode *node, bNodeExecDat
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 */
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 495c78ca929..7df6d34b756 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 */
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 c994798e2da..30deb422e58 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
@@ -63,7 +63,7 @@ static int node_shader_gpu_tex_voronoi(GPUMaterial *mat, bNode *node, bNodeExecD
NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
float coloring = tex->coloring;
- 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_uniform(&coloring));
}
/* node type definition */
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 1194874e06c..356d2a78139 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
@@ -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_uniform(&wave_type), GPU_uniform(&wave_profile));
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_texture.c b/source/blender/nodes/shader/nodes/node_shader_texture.c
index b0b25a4878b..755ef106ade 100644
--- a/source/blender/nodes/shader/nodes/node_shader_texture.c
+++ b/source/blender/nodes/shader/nodes/node_shader_texture.c
@@ -126,7 +126,7 @@ static int gpu_shader_texture(GPUMaterial *mat, bNode *node, bNodeExecData *UNUS
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);
+ GPU_stack_link(mat, node, "texture_image", in, out, texlink);
}
else { /* TEX_ENVMAP */
if (!in[0].link)
diff --git a/source/blender/nodes/shader/nodes/node_shader_uvmap.c b/source/blender/nodes/shader/nodes/node_shader_uvmap.c
index 0f96cb45fe0..c47bb9022b6 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 */
diff --git a/source/blender/nodes/shader/nodes/node_shader_valToRgb.c b/source/blender/nodes/shader/nodes/node_shader_valToRgb.c
index 72942cce9c5..b5e32e294bf 100644
--- a/source/blender/nodes/shader/nodes/node_shader_valToRgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_valToRgb.c
@@ -69,7 +69,7 @@ static int gpu_shader_valtorgb(GPUMaterial *mat, bNode *node, bNodeExecData *UNU
int size;
colorband_table_RGBA(node->storage, &array, &size);
- return GPU_stack_link(mat, "valtorgb", in, out, GPU_texture(size, array));
+ return GPU_stack_link(mat, node, "valtorgb", in, out, GPU_texture(size, array));
}
void register_node_type_sh_valtorgb(void)
@@ -110,9 +110,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)
diff --git a/source/blender/nodes/shader/nodes/node_shader_value.c b/source/blender/nodes/shader/nodes/node_shader_value.c
index 3a9582a6a7c..1e5bd8c5bff 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)
diff --git a/source/blender/nodes/shader/nodes/node_shader_vectMath.c b/source/blender/nodes/shader/nodes/node_shader_vectMath.c
index 26045dfca04..f117adde98c 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:
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..518ab6587b2 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 */
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 0c5647b4ba8..bce4695af10 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 */
diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c
index 714665c303b..3b53d29d147 100644
--- a/source/blender/nodes/texture/node_texture_tree.c
+++ b/source/blender/nodes/texture/node_texture_tree.c
@@ -62,7 +62,8 @@ static void texture_get_from_context(const bContext *C, bNodeTreeType *UNUSED(tr
{
SpaceNode *snode = CTX_wm_space_node(C);
Scene *scene = CTX_data_scene(C);
- Object *ob = OBACT;
+ SceneLayer *sl = CTX_data_scene_layer(C);
+ Object *ob = OBACT_NEW;
Tex *tx = NULL;
if (snode->texfrom == SNODE_TEX_OBJECT) {
diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp
index 359395b63c4..b694b6e994d 100644
--- a/source/blender/physics/intern/BPH_mass_spring.cpp
+++ b/source/blender/physics/intern/BPH_mass_spring.cpp
@@ -333,19 +333,14 @@ static int UNUSED_FUNCTION(cloth_calc_helper_forces)(Object *UNUSED(ob), ClothMo
return 1;
}
-BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, float time)
+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;
- ClothVertex *verts = cloth->verts;
bool no_compress = parms->flags & CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS;
- zero_v3(s->f);
- zero_m3(s->dfdx);
- zero_m3(s->dfdv);
-
s->flags &= ~CLOTH_SPRING_FLAG_NEEDED;
// calculate force of structural + shear springs
@@ -361,31 +356,13 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s,
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, s->f, s->dfdx, s->dfdv);
+ BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, parms->max_sewing);
}
else {
- BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, 0.0f, s->f, s->dfdx, s->dfdv);
+ BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, 0.0f);
}
#endif
}
- else if (s->type & CLOTH_SPRING_TYPE_GOAL) {
-#ifdef CLOTH_FORCE_SPRING_GOAL
- float goal_x[3], goal_v[3];
- float k, scaling;
-
- s->flags |= CLOTH_SPRING_FLAG_NEEDED;
-
- // current_position = xold + t * (newposition - xold)
- /* divide by time_scale to prevent goal vertices' delta locations from being multiplied */
- interp_v3_v3v3(goal_x, verts[s->ij].xold, verts[s->ij].xconst, time / parms->time_scale);
- sub_v3_v3v3(goal_v, verts[s->ij].xconst, verts[s->ij].xold); // distance covered over dt==1
-
- scaling = parms->goalspring + s->stiffness * fabsf(parms->max_struct - parms->goalspring);
- k = verts[s->ij].goal * scaling / (parms->avg_spring_len + FLT_EPSILON);
-
- BPH_mass_spring_force_spring_goal(data, s->ij, goal_x, goal_v, k, parms->goalfrict * 0.01f, s->f, s->dfdx, s->dfdv);
-#endif
- }
else if (s->type & CLOTH_SPRING_TYPE_BENDING) { /* calculate force of bending springs */
#ifdef CLOTH_FORCE_SPRING_BEND
float kb, cb, scaling;
@@ -398,7 +375,7 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s,
// Fix for [#45084] for cloth stiffness must have cb proportional to kb
cb = kb * parms->bending_damping;
- BPH_mass_spring_force_spring_bending(data, s->ij, s->kl, s->restlen, kb, cb, s->f, s->dfdx, s->dfdv);
+ 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) {
@@ -474,9 +451,24 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB
/* scale gravity force */
mul_v3_v3fl(gravity, clmd->scene->physics_settings.gravity, 0.001f * clmd->sim_parms->effector_weights->global_gravity);
}
+
vert = cloth->verts;
for (i = 0; i < cloth->mvert_num; i++, vert++) {
BPH_mass_spring_force_gravity(data, i, vert->mass, gravity);
+
+ /* Vertex goal springs */
+ if ((!(vert->flags & CLOTH_VERT_FLAG_PINNED)) && (vert->goal > FLT_EPSILON)) {
+ float goal_x[3], goal_v[3];
+ float k;
+
+ /* divide by time_scale to prevent goal vertices' delta locations from being multiplied */
+ interp_v3_v3v3(goal_x, vert->xold, vert->xconst, time / clmd->sim_parms->time_scale);
+ sub_v3_v3v3(goal_v, vert->xconst, vert->xold); /* distance covered over dt==1 */
+
+ k = vert->goal * clmd->sim_parms->goalspring / (clmd->sim_parms->avg_spring_len + FLT_EPSILON);
+
+ BPH_mass_spring_force_spring_goal(data, i, goal_x, goal_v, k, clmd->sim_parms->goalfrict * 0.01f);
+ }
}
#endif
@@ -544,8 +536,9 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB
for (LinkNode *link = cloth->springs; link; link = link->next) {
ClothSpring *spring = (ClothSpring *)link->link;
// only handle active springs
- if (!(spring->flags & CLOTH_SPRING_FLAG_DEACTIVATE))
- cloth_calc_spring_force(clmd, spring, time);
+ if (!(spring->flags & CLOTH_SPRING_FLAG_DEACTIVATE)) {
+ cloth_calc_spring_force(clmd, spring);
+ }
}
}
diff --git a/source/blender/physics/intern/hair_volume.cpp b/source/blender/physics/intern/hair_volume.cpp
index d79cf7d8c31..5cc1231e6cb 100644
--- a/source/blender/physics/intern/hair_volume.cpp
+++ b/source/blender/physics/intern/hair_volume.cpp
@@ -710,7 +710,7 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target
* div(grad(p)) = div(v)
*
* The finite difference approximation yields the linear equation system described here:
- * http://en.wikipedia.org/wiki/Discrete_Poisson_equation
+ * https://en.wikipedia.org/wiki/Discrete_Poisson_equation
*/
lMatrix A(num_cellsA, num_cellsA);
/* Reserve space for the base equation system (without boundary conditions).
@@ -888,7 +888,7 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target
#if 0 /* XXX weighting is incorrect, disabled for now */
/* Velocity filter kernel
- * See http://en.wikipedia.org/wiki/Filter_%28large_eddy_simulation%29
+ * See https://en.wikipedia.org/wiki/Filter_%28large_eddy_simulation%29
*/
BLI_INLINE void hair_volume_filter_box_convolute(HairVertexGrid *grid, float invD, const int kernel_size[3], int i, int j, int k)
diff --git a/source/blender/physics/intern/implicit.h b/source/blender/physics/intern/implicit.h
index 40af180ac9d..d632ce267a1 100644
--- a/source/blender/physics/intern/implicit.h
+++ b/source/blender/physics/intern/implicit.h
@@ -109,19 +109,15 @@ 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 r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]);
+ float stiffness, float damping, bool no_compress, float clamp_force);
/* 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,
- float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]);
+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,
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],
- float stiffness, float damping,
- float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]);
+ float stiffness, float damping);
/* ======== Hair Volumetric Forces ======== */
diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c
index a697852e803..bfc78f140b0 100644
--- a/source/blender/physics/intern/implicit_blender.c
+++ b/source/blender/physics/intern/implicit_blender.c
@@ -1579,8 +1579,7 @@ 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 r_f[3], float r_dfdx[3][3], float r_dfdv[3][3])
+ float stiffness, float damping, bool no_compress, float clamp_force)
{
float extent[3], length, dir[3], vel[3];
@@ -1608,25 +1607,15 @@ bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, int i, int j, floa
apply_spring(data, i, j, f, dfdx, dfdv);
- if (r_f) copy_v3_v3(r_f, f);
- if (r_dfdx) copy_m3_m3(r_dfdx, dfdx);
- if (r_dfdv) copy_m3_m3(r_dfdv, dfdv);
-
return true;
}
else {
- if (r_f) zero_v3(r_f);
- if (r_dfdx) zero_m3(r_dfdx);
- if (r_dfdv) zero_m3(r_dfdv);
-
return false;
}
}
/* See "Stable but Responsive Cloth" (Choi, Ko 2005) */
-bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, float restlen,
- float kb, float cb,
- float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3])
+bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, float restlen, float kb, float cb)
{
float extent[3], length, dir[3], vel[3];
@@ -1646,17 +1635,9 @@ bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, flo
apply_spring(data, i, j, f, dfdx, dfdv);
- if (r_f) copy_v3_v3(r_f, f);
- if (r_dfdx) copy_m3_m3(r_dfdx, dfdx);
- if (r_dfdv) copy_m3_m3(r_dfdv, dfdv);
-
return true;
}
else {
- if (r_f) zero_v3(r_f);
- if (r_dfdx) zero_m3(r_dfdx);
- if (r_dfdv) zero_m3(r_dfdv);
-
return false;
}
}
@@ -1945,8 +1926,7 @@ bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, in
}
bool BPH_mass_spring_force_spring_goal(Implicit_Data *data, int i, const float goal_x[3], const float goal_v[3],
- float stiffness, float damping,
- float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3])
+ float stiffness, float damping)
{
float root_goal_x[3], root_goal_v[3], extent[3], length, dir[3], vel[3];
float f[3], dfdx[3][3], dfdv[3][3];
@@ -1973,17 +1953,9 @@ bool BPH_mass_spring_force_spring_goal(Implicit_Data *data, int i, const float g
add_m3_m3m3(data->dFdX[i].m, data->dFdX[i].m, dfdx);
add_m3_m3m3(data->dFdV[i].m, data->dFdV[i].m, dfdv);
- if (r_f) copy_v3_v3(r_f, f);
- if (r_dfdx) copy_m3_m3(r_dfdx, dfdx);
- if (r_dfdv) copy_m3_m3(r_dfdv, dfdv);
-
return true;
}
else {
- if (r_f) zero_v3(r_f);
- if (r_dfdx) zero_m3(r_dfdx);
- if (r_dfdv) zero_m3(r_dfdv);
-
return false;
}
}
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
index 3148dab3c50..b4c36a7c516 100644
--- a/source/blender/python/BPY_extern.h
+++ b/source/blender/python/BPY_extern.h
@@ -75,7 +75,8 @@ void BPY_thread_restore(BPy_ThreadStatePtr tstate);
bool BPY_execute_filepath(struct bContext *C, const char *filepath, struct ReportList *reports);
bool BPY_execute_text(struct bContext *C, struct Text *text, struct ReportList *reports, const bool do_jump);
-bool BPY_execute_string_as_number(struct bContext *C, const char *expr, double *value, const bool verbose);
+bool BPY_execute_string_as_number(struct bContext *C, const char *expr, const bool verbose, double *r_value);
+bool BPY_execute_string_as_string(struct bContext *C, const char *expr, const bool verbose, char **r_value);
bool BPY_execute_string_ex(struct bContext *C, const char *expr, bool use_eval);
bool BPY_execute_string(struct bContext *C, const char *expr);
diff --git a/source/blender/python/bmesh/CMakeLists.txt b/source/blender/python/bmesh/CMakeLists.txt
index c7b86acc8f9..4d3230fa3e9 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 d5973baeadb..d6189f7c1eb 100644
--- a/source/blender/python/bmesh/bmesh_py_api.c
+++ b/source/blender/python/bmesh/bmesh_py_api.c
@@ -156,11 +156,6 @@ 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);
}
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index 1d951bae48b..88445cfd62b 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -34,10 +34,11 @@
#include "DNA_object_types.h"
#include "DNA_material_types.h"
-#include "BKE_depsgraph.h"
#include "BKE_customdata.h"
#include "BKE_DerivedMesh.h"
+#include "DEG_depsgraph.h"
+
#include "bmesh.h"
#include <Python.h>
@@ -913,14 +914,11 @@ 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);
-
BM_mesh_bm_to_me(bm, me, (&(struct BMeshToMeshParams){0}));
/* 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;
}
@@ -2233,7 +2231,7 @@ static PyObject *bpy_bmfaceseq_new(BPy_BMElemSeq *self, PyObject *args)
}
/* check if the face exists */
- if (BM_face_exists(vert_array, vert_seq_len, NULL)) {
+ if (BM_face_exists(vert_array, vert_seq_len) != NULL) {
PyErr_SetString(PyExc_ValueError,
"faces.new(verts): face already exists");
goto cleanup;
@@ -2426,7 +2424,8 @@ static PyObject *bpy_bmfaceseq_get__method(BPy_BMElemSeq *self, PyObject *args)
return NULL;
}
- if (BM_face_exists(vert_array, vert_seq_len, &f)) {
+ f = BM_face_exists(vert_array, vert_seq_len);
+ if (f != NULL) {
ret = BPy_BMFace_CreatePyObject(bm, f);
}
else {
diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c
index 908f6b5a734..47dead028a4 100644
--- a/source/blender/python/bmesh/bmesh_py_types_customdata.c
+++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c
@@ -104,9 +104,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`"
);
@@ -222,8 +219,6 @@ static PyGetSetDef bpy_bmlayeraccess_face_getseters[] = {
{(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},
-
#ifdef WITH_FREESTYLE
{(char *)"freestyle", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__freestyle_face_doc, (void *)CD_FREESTYLE_FACE},
#endif
@@ -998,11 +993,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);
@@ -1101,11 +1091,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 92c11a03433..f6926e8437d 100644
--- a/source/blender/python/bmesh/bmesh_py_types_meshdata.c
+++ b/source/blender/python/bmesh/bmesh_py_types_meshdata.c
@@ -47,96 +47,6 @@
#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
* ************ */
@@ -798,7 +708,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 3ea10228ad4..ed4726e2ab7 100644
--- a/source/blender/python/generic/bgl.c
+++ b/source/blender/python/generic/bgl.c
@@ -185,11 +185,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 +229,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"
@@ -1015,358 +1019,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 */
@@ -1378,7 +1095,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))
@@ -1386,42 +1102,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))
@@ -1587,44 +1267,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) */
/** \} */
@@ -1634,26 +1277,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 */
@@ -1687,9 +1316,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;
@@ -1764,268 +1390,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 */
{
@@ -2043,27 +1407,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 */
{
@@ -2073,7 +1416,6 @@ PyObject *BPyInit_bgl(void)
PY_MOD_ADD_METHOD(TexSubImage3D);
}
-
/* GL_VERSION_1_3 */
{
PY_MOD_ADD_METHOD(ActiveTexture);
@@ -2086,47 +1428,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 */
{
@@ -2134,7 +1435,6 @@ PyObject *BPyInit_bgl(void)
PY_MOD_ADD_METHOD(BlendEquation);
}
-
/* GL_VERSION_1_5 */
{
PY_MOD_ADD_METHOD(BeginQuery);
@@ -2158,7 +1458,6 @@ PyObject *BPyInit_bgl(void)
PY_MOD_ADD_METHOD(UnmapBuffer);
}
-
/* GL_VERSION_2_0 */
{
PY_MOD_ADD_METHOD(AttachShader);
@@ -2256,7 +1555,6 @@ PyObject *BPyInit_bgl(void)
PY_MOD_ADD_METHOD(VertexAttribPointer);
}
-
/* GL_VERSION_2_1 */
{
PY_MOD_ADD_METHOD(UniformMatrix2x3fv);
@@ -2267,7 +1565,6 @@ PyObject *BPyInit_bgl(void)
PY_MOD_ADD_METHOD(UniformMatrix4x3fv);
}
-
/* GL_VERSION_3_0 */
{
PY_MOD_ADD_METHOD(BindVertexArray);
@@ -2276,7 +1573,6 @@ PyObject *BPyInit_bgl(void)
PY_MOD_ADD_METHOD(IsVertexArray);
}
-
/* GL_VERSION_3_1 */
{
PY_MOD_ADD_METHOD(BindBufferBase);
@@ -2291,7 +1587,6 @@ PyObject *BPyInit_bgl(void)
PY_MOD_ADD_METHOD(UniformBlockBinding);
}
-
/* GL_VERSION_3_2 */
{
PY_MOD_ADD_METHOD(FramebufferTexture);
@@ -2303,39 +1598,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)
@@ -2453,8 +1717,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);
@@ -2544,338 +1806,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 */
{
@@ -2916,15 +1846,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 */
{
@@ -2988,47 +1909,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 */
{
@@ -3058,33 +1938,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 */
{
@@ -3107,7 +1960,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);
@@ -3117,32 +1969,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 */
{
@@ -3227,14 +2053,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 */
{
@@ -3255,16 +2073,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 */
{
@@ -3505,14 +2313,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 */
{
@@ -3579,7 +2379,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);
@@ -3685,4 +2484,4 @@ static PyObject *Method_ShaderSource(PyObject *UNUSED(self), PyObject *args)
}
-/** \} */ \ No newline at end of file
+/** \} */
diff --git a/source/blender/python/generic/blf_py_api.c b/source/blender/python/generic/blf_py_api.c
index 69f1e297b43..02bd1fdbe39 100644
--- a/source/blender/python/generic/blf_py_api.c
+++ b/source/blender/python/generic/blf_py_api.c
@@ -114,6 +114,7 @@ static PyObject *py_blf_aspect(PyObject *UNUSED(self), PyObject *args)
}
+#if BLF_BLUR_ENABLE
PyDoc_STRVAR(py_blf_blur_doc,
".. function:: blur(fontid, radius)\n"
"\n"
@@ -135,6 +136,7 @@ static PyObject *py_blf_blur(PyObject *UNUSED(self), PyObject *args)
Py_RETURN_NONE;
}
+#endif
PyDoc_STRVAR(py_blf_draw_doc,
@@ -418,7 +420,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},
diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c
index 2e15b7b1413..5d6a7c578a2 100644
--- a/source/blender/python/generic/idprop_py_api.c
+++ b/source/blender/python/generic/idprop_py_api.c
@@ -43,6 +43,9 @@
#include "python_utildefines.h"
+extern bool pyrna_id_FromPyObject(PyObject *obj, ID **id);
+extern PyObject *pyrna_id_CreatePyObject(ID *id);
+extern bool pyrna_id_CheckPyObject(PyObject *obj);
/*********************** ID Property Main Wrapper Stuff ***************/
@@ -88,6 +91,11 @@ static PyObject *idprop_py_from_idp_group(ID *id, IDProperty *prop, IDProperty *
return (PyObject *)group;
}
+static PyObject *idprop_py_from_idp_id(IDProperty *prop)
+{
+ return pyrna_id_CreatePyObject(prop->data.pointer);
+}
+
static PyObject *idprop_py_from_idp_array(ID *id, IDProperty *prop)
{
BPy_IDProperty *array = PyObject_New(BPy_IDProperty, &BPy_IDArray_Type);
@@ -148,6 +156,7 @@ PyObject *BPy_IDGroup_WrapData(ID *id, IDProperty *prop, IDProperty *parent)
case IDP_GROUP: return idprop_py_from_idp_group(id, prop, parent);
case IDP_ARRAY: return idprop_py_from_idp_array(id, prop);
case IDP_IDPARRAY: return idprop_py_from_idp_idparray(id, prop); /* this could be better a internal type */
+ case IDP_ID: return idprop_py_from_idp_id(prop);
default: Py_RETURN_NONE;
}
}
@@ -335,19 +344,9 @@ static char idp_sequence_type(PyObject *seq_fast)
return type;
}
-/**
- * \note group can be a pointer array or a group.
- * assume we already checked key is a string.
- *
- * \return success.
- */
-bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group, PyObject *ob)
+static const char *idp_try_read_name(PyObject *name_obj)
{
- IDProperty *prop = NULL;
- IDPropertyTemplate val = {0};
-
- const char *name;
-
+ const char *name = NULL;
if (name_obj) {
Py_ssize_t name_size;
name = _PyUnicode_AsStringAndSize(name_obj, &name_size);
@@ -356,168 +355,307 @@ bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group,
PyErr_Format(PyExc_KeyError,
"invalid id-property key, expected a string, not a %.200s",
Py_TYPE(name_obj)->tp_name);
- return false;
+ return NULL;
}
if (name_size > MAX_IDPROP_NAME) {
PyErr_SetString(PyExc_KeyError, "the length of IDProperty names is limited to 63 characters");
- return false;
+ return NULL;
}
}
else {
name = "";
}
+ return name;
+}
- if (PyFloat_Check(ob)) {
- val.d = PyFloat_AsDouble(ob);
- prop = IDP_New(IDP_DOUBLE, &val, name);
- }
- else if (PyLong_Check(ob)) {
- val.i = _PyLong_AsInt(ob);
- if (val.i == -1 && PyErr_Occurred()) {
- return false;
- }
- prop = IDP_New(IDP_INT, &val, name);
+/* -------------------------------------------------------------------------- */
+
+/**
+ * The 'idp_from_Py*' functions expect that the input type has been checked before
+ * and return NULL if the IDProperty can't be created.
+ */
+
+static IDProperty *idp_from_PyFloat(const char *name, PyObject *ob)
+{
+ IDPropertyTemplate val = {0};
+ val.d = PyFloat_AsDouble(ob);
+ return IDP_New(IDP_DOUBLE, &val, name);
+}
+
+static IDProperty *idp_from_PyLong(const char *name, PyObject *ob)
+{
+ IDPropertyTemplate val = {0};
+ val.i = _PyLong_AsInt(ob);
+ if (val.i == -1 && PyErr_Occurred()) {
+ return NULL;
}
- else if (PyUnicode_Check(ob)) {
+ return IDP_New(IDP_INT, &val, name);
+}
+
+static IDProperty *idp_from_PyUnicode(const char *name, PyObject *ob)
+{
+ IDProperty *prop;
+ IDPropertyTemplate val = {0};
#ifdef USE_STRING_COERCE
- Py_ssize_t value_size;
- PyObject *value_coerce = NULL;
- val.string.str = PyC_UnicodeAsByteAndSize(ob, &value_size, &value_coerce);
- val.string.len = (int)value_size + 1;
- val.string.subtype = IDP_STRING_SUB_UTF8;
- prop = IDP_New(IDP_STRING, &val, name);
- Py_XDECREF(value_coerce);
+ Py_ssize_t value_size;
+ PyObject *value_coerce = NULL;
+ val.string.str = PyC_UnicodeAsByteAndSize(ob, &value_size, &value_coerce);
+ val.string.len = (int)value_size + 1;
+ val.string.subtype = IDP_STRING_SUB_UTF8;
+ prop = IDP_New(IDP_STRING, &val, name);
+ Py_XDECREF(value_coerce);
#else
- val.str = _PyUnicode_AsString(ob);
- prop = IDP_New(IDP_STRING, val, name);
+ val.str = _PyUnicode_AsString(ob);
+ prop = IDP_New(IDP_STRING, val, name);
#endif
- }
- else if (PyBytes_Check(ob)) {
- val.string.str = PyBytes_AS_STRING(ob);
- val.string.len = PyBytes_GET_SIZE(ob);
- val.string.subtype = IDP_STRING_SUB_BYTE;
+ return prop;
+}
+
+static IDProperty *idp_from_PyBytes(const char *name, PyObject *ob)
+{
+ IDPropertyTemplate val = {0};
+ val.string.str = PyBytes_AS_STRING(ob);
+ val.string.len = PyBytes_GET_SIZE(ob);
+ val.string.subtype = IDP_STRING_SUB_BYTE;
+ return IDP_New(IDP_STRING, &val, name);
+}
- prop = IDP_New(IDP_STRING, &val, name);
- //prop = IDP_NewString(PyBytes_AS_STRING(ob), name, PyBytes_GET_SIZE(ob));
- //prop->subtype = IDP_STRING_SUB_BYTE;
+static int idp_array_type_from_format_char(char format)
+{
+ if (format == 'i') return IDP_INT;
+ if (format == 'f') return IDP_FLOAT;
+ if (format == 'd') return IDP_DOUBLE;
+ return -1;
+}
+
+static const char *idp_format_from_array_type(int type)
+{
+ if (type == IDP_INT) return "i";
+ if (type == IDP_FLOAT) return "f";
+ if (type == IDP_DOUBLE) return "d";
+ return NULL;
+}
+
+static IDProperty *idp_from_PySequence_Buffer(const char *name, Py_buffer *buffer)
+{
+ IDProperty *prop;
+ IDPropertyTemplate val = {0};
+
+ int format = idp_array_type_from_format_char(*buffer->format);
+ if (format == -1) {
+ /* should never happen as the type has been checked before */
+ return NULL;
}
- else if (PySequence_Check(ob)) {
- PyObject *ob_seq_fast;
- PyObject **ob_seq_fast_items;
- PyObject *item;
- int i;
+ else {
+ val.array.type = format;
+ val.array.len = buffer->len / buffer->itemsize;
+ }
+ prop = IDP_New(IDP_ARRAY, &val, name);
+ memcpy(IDP_Array(prop), buffer->buf, buffer->len);
+ return prop;
+}
- if (!(ob_seq_fast = PySequence_Fast(ob, "py -> idprop"))) {
- return false;
- }
+static IDProperty *idp_from_PySequence_Fast(const char *name, PyObject *ob)
+{
+ IDProperty *prop;
+ IDPropertyTemplate val = {0};
- ob_seq_fast_items = PySequence_Fast_ITEMS(ob_seq_fast);
+ PyObject **ob_seq_fast_items;
+ PyObject *item;
+ int i;
- if ((val.array.type = idp_sequence_type(ob_seq_fast)) == (char)-1) {
- Py_DECREF(ob_seq_fast);
- PyErr_SetString(PyExc_TypeError, "only floats, ints and dicts are allowed in ID property arrays");
- return false;
- }
+ ob_seq_fast_items = PySequence_Fast_ITEMS(ob);
- /* validate sequence and derive type.
- * we assume IDP_INT unless we hit a float
- * number; then we assume it's */
+ if ((val.array.type = idp_sequence_type(ob)) == (char)-1) {
+ PyErr_SetString(PyExc_TypeError, "only floats, ints and dicts are allowed in ID property arrays");
+ return NULL;
+ }
- val.array.len = PySequence_Fast_GET_SIZE(ob_seq_fast);
+ /* validate sequence and derive type.
+ * we assume IDP_INT unless we hit a float
+ * number; then we assume it's */
- switch (val.array.type) {
- case IDP_DOUBLE:
- {
- double *prop_data;
-
- prop = IDP_New(IDP_ARRAY, &val, name);
- prop_data = IDP_Array(prop);
- for (i = 0; i < val.array.len; i++) {
- item = ob_seq_fast_items[i];
- if (((prop_data[i] = PyFloat_AsDouble(item)) == -1.0) && PyErr_Occurred()) {
- Py_DECREF(ob_seq_fast);
- return false;
- }
+ val.array.len = PySequence_Fast_GET_SIZE(ob);
+
+ switch (val.array.type) {
+ case IDP_DOUBLE:
+ {
+ double *prop_data;
+ prop = IDP_New(IDP_ARRAY, &val, name);
+ prop_data = IDP_Array(prop);
+ for (i = 0; i < val.array.len; i++) {
+ item = ob_seq_fast_items[i];
+ if (((prop_data[i] = PyFloat_AsDouble(item)) == -1.0) && PyErr_Occurred()) {
+ return NULL;
}
- break;
}
- case IDP_INT:
- {
- int *prop_data;
- prop = IDP_New(IDP_ARRAY, &val, name);
- prop_data = IDP_Array(prop);
- for (i = 0; i < val.array.len; i++) {
- item = ob_seq_fast_items[i];
- if (((prop_data[i] = _PyLong_AsInt(item)) == -1) && PyErr_Occurred()) {
- Py_DECREF(ob_seq_fast);
- return false;
- }
+ break;
+ }
+ case IDP_INT:
+ {
+ int *prop_data;
+ prop = IDP_New(IDP_ARRAY, &val, name);
+ prop_data = IDP_Array(prop);
+ for (i = 0; i < val.array.len; i++) {
+ item = ob_seq_fast_items[i];
+ if (((prop_data[i] = _PyLong_AsInt(item)) == -1) && PyErr_Occurred()) {
+ return NULL;
}
- break;
}
- case IDP_IDPARRAY:
- {
- prop = IDP_NewIDPArray(name);
- for (i = 0; i < val.array.len; i++) {
- item = ob_seq_fast_items[i];
-
- if (BPy_IDProperty_Map_ValidateAndCreate(NULL, prop, item) == false) {
- Py_DECREF(ob_seq_fast);
- return false;
- }
+ break;
+ }
+ case IDP_IDPARRAY:
+ {
+ prop = IDP_NewIDPArray(name);
+ for (i = 0; i < val.array.len; i++) {
+ item = ob_seq_fast_items[i];
+ if (BPy_IDProperty_Map_ValidateAndCreate(NULL, prop, item) == false) {
+ return NULL;
}
- break;
}
- default:
- /* should never happen */
- Py_DECREF(ob_seq_fast);
- PyErr_SetString(PyExc_RuntimeError, "internal error with idp array.type");
- return false;
+ break;
}
+ default:
+ /* should never happen */
+ PyErr_SetString(PyExc_RuntimeError, "internal error with idp array.type");
+ return NULL;
+ }
+ return prop;
+}
- Py_DECREF(ob_seq_fast);
+
+static IDProperty *idp_from_PySequence(const char *name, PyObject *ob)
+{
+ Py_buffer buffer;
+ bool use_buffer = false;
+
+ if (PyObject_CheckBuffer(ob)) {
+ PyObject_GetBuffer(ob, &buffer, PyBUF_SIMPLE | PyBUF_FORMAT);
+ char format = *buffer.format;
+ if (ELEM(format, 'i', 'f', 'd')) {
+ use_buffer = true;
+ }
+ else {
+ PyBuffer_Release(&buffer);
+ }
}
- else if (PyMapping_Check(ob)) {
- PyObject *keys, *vals, *key, *pval;
- int i, len;
- /*yay! we get into recursive stuff now!*/
- keys = PyMapping_Keys(ob);
- vals = PyMapping_Values(ob);
-
- /* we allocate the group first; if we hit any invalid data,
- * we can delete it easily enough.*/
- prop = IDP_New(IDP_GROUP, &val, name);
- len = PyMapping_Length(ob);
- for (i = 0; i < len; i++) {
- key = PySequence_GetItem(keys, i);
- pval = PySequence_GetItem(vals, i);
- if (BPy_IDProperty_Map_ValidateAndCreate(key, prop, pval) == false) {
- IDP_FreeProperty(prop);
- MEM_freeN(prop);
- Py_XDECREF(keys);
- Py_XDECREF(vals);
- Py_XDECREF(key);
- Py_XDECREF(pval);
- /* error is already set */
- return false;
- }
+
+ if (use_buffer) {
+ IDProperty *prop = idp_from_PySequence_Buffer(name, &buffer);
+ PyBuffer_Release(&buffer);
+ return prop;
+ }
+ else {
+ PyObject *ob_seq_fast = PySequence_Fast(ob, "py -> idprop");
+ if (ob_seq_fast != NULL) {
+ IDProperty *prop = idp_from_PySequence_Fast(name, ob_seq_fast);
+ Py_DECREF(ob_seq_fast);
+ return prop;
+ }
+ else {
+ return NULL;
+ }
+ }
+}
+
+static IDProperty *idp_from_PyMapping(const char *name, PyObject *ob)
+{
+ IDProperty *prop;
+ IDPropertyTemplate val = {0};
+
+ PyObject *keys, *vals, *key, *pval;
+ int i, len;
+ /* yay! we get into recursive stuff now! */
+ keys = PyMapping_Keys(ob);
+ vals = PyMapping_Values(ob);
+
+ /* we allocate the group first; if we hit any invalid data,
+ * we can delete it easily enough.*/
+ prop = IDP_New(IDP_GROUP, &val, name);
+ len = PyMapping_Length(ob);
+ for (i = 0; i < len; i++) {
+ key = PySequence_GetItem(keys, i);
+ pval = PySequence_GetItem(vals, i);
+ if (BPy_IDProperty_Map_ValidateAndCreate(key, prop, pval) == false) {
+ IDP_FreeProperty(prop);
+ MEM_freeN(prop);
+ Py_XDECREF(keys);
+ Py_XDECREF(vals);
Py_XDECREF(key);
Py_XDECREF(pval);
+ /* error is already set */
+ return NULL;
}
- Py_XDECREF(keys);
- Py_XDECREF(vals);
+ Py_XDECREF(key);
+ Py_XDECREF(pval);
+ }
+ Py_XDECREF(keys);
+ Py_XDECREF(vals);
+ return prop;
+}
+
+static IDProperty *idp_from_DatablockPointer(const char *name, PyObject *ob, IDPropertyTemplate *val)
+{
+ pyrna_id_FromPyObject(ob, &val->id);
+ return IDP_New(IDP_ID, val, name);
+}
+
+static IDProperty *idp_from_PyObject(PyObject *name_obj, PyObject *ob)
+{
+ IDPropertyTemplate val = {0};
+ const char *name = idp_try_read_name(name_obj);
+ if (name == NULL) {
+ return NULL;
+ }
+
+ if (PyFloat_Check(ob)) {
+ return idp_from_PyFloat(name, ob);
+ }
+ else if (PyLong_Check(ob)) {
+ return idp_from_PyLong(name, ob);
+ }
+ else if (PyUnicode_Check(ob)) {
+ return idp_from_PyUnicode(name, ob);
+ }
+ else if (PyBytes_Check(ob)) {
+ return idp_from_PyBytes(name, ob);
+ }
+ else if (PySequence_Check(ob)) {
+ return idp_from_PySequence(name, ob);
+ }
+ else if (ob == Py_None || pyrna_id_CheckPyObject(ob)) {
+ return idp_from_DatablockPointer(name, ob, &val);
+ }
+ else if (PyMapping_Check(ob)) {
+ return idp_from_PyMapping(name, ob);
}
else {
PyErr_Format(PyExc_TypeError,
"invalid id-property type %.200s not supported",
Py_TYPE(ob)->tp_name);
+ return NULL;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * \note group can be a pointer array or a group.
+ * assume we already checked key is a string.
+ *
+ * \return success.
+ */
+bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group, PyObject *ob)
+{
+ IDProperty *prop = idp_from_PyObject(name_obj, ob);
+ if (prop == NULL) {
return false;
}
if (group->type == IDP_IDPARRAY) {
IDP_AppendArray(group, prop);
- // IDP_FreeProperty(item); /* IDP_AppendArray does a shallow copy (memcpy), only free memory */
+ /* IDP_AppendArray does a shallow copy (memcpy), only free memory */
MEM_freeN(prop);
}
else {
@@ -613,6 +751,8 @@ static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
return idprop_py_from_idp_float(prop);
case IDP_DOUBLE:
return idprop_py_from_idp_double(prop);
+ case IDP_ID:
+ return idprop_py_from_idp_id(prop);
case IDP_ARRAY:
{
PyObject *seq = PyList_New(prop->len);
@@ -1371,6 +1511,44 @@ static PyMappingMethods BPy_IDArray_AsMapping = {
(objobjargproc)BPy_IDArray_ass_subscript
};
+static int itemsize_by_idarray_type(int array_type)
+{
+ if (array_type == IDP_INT) return sizeof(int);
+ if (array_type == IDP_FLOAT) return sizeof(float);
+ if (array_type == IDP_DOUBLE) return sizeof(double);
+ return -1; /* should never happen */
+}
+
+static int BPy_IDArray_getbuffer(BPy_IDArray *self, Py_buffer *view, int flags)
+{
+ IDProperty *prop = self->prop;
+ int itemsize = itemsize_by_idarray_type(prop->subtype);
+ int length = itemsize * prop->len;
+
+ if (PyBuffer_FillInfo(view, (PyObject *)self, IDP_Array(prop), length, false, flags) == -1) {
+ return -1;
+ }
+
+ view->itemsize = itemsize;
+ view->format = (char *)idp_format_from_array_type(prop->subtype);
+
+ Py_ssize_t *shape = MEM_mallocN(sizeof(Py_ssize_t), __func__);
+ shape[0] = prop->len;
+ view->shape = shape;
+
+ return 0;
+}
+
+static void BPy_IDArray_releasebuffer(BPy_IDArray *UNUSED(self), Py_buffer *view)
+{
+ MEM_freeN(view->shape);
+}
+
+static PyBufferProcs BPy_IDArray_Buffer = {
+ (getbufferproc)BPy_IDArray_getbuffer,
+ (releasebufferproc)BPy_IDArray_releasebuffer,
+};
+
PyTypeObject BPy_IDArray_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
@@ -1403,7 +1581,7 @@ PyTypeObject BPy_IDArray_Type = {
NULL, /* setattrofunc tp_setattro; */
/* Functions to access object as input/output buffer */
- NULL, /* PyBufferProcs *tp_as_buffer; */
+ &BPy_IDArray_Buffer, /* PyBufferProcs *tp_as_buffer; */
/*** Flags to define presence of optional/expanded features ***/
Py_TPFLAGS_DEFAULT, /* long tp_flags; */
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index 7b2d58a1268..2e789d6d4b3 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -918,11 +918,11 @@ char *PyC_FlagSet_AsString(PyC_FlagSet *item)
return cstring;
}
-int PyC_FlagSet_ValueFromID_int(PyC_FlagSet *item, const char *identifier, int *value)
+int PyC_FlagSet_ValueFromID_int(PyC_FlagSet *item, const char *identifier, int *r_value)
{
for ( ; item->identifier; item++) {
if (STREQ(item->identifier, identifier)) {
- *value = item->value;
+ *r_value = item->value;
return 1;
}
}
@@ -930,9 +930,9 @@ int PyC_FlagSet_ValueFromID_int(PyC_FlagSet *item, const char *identifier, int *
return 0;
}
-int PyC_FlagSet_ValueFromID(PyC_FlagSet *item, const char *identifier, int *value, const char *error_prefix)
+int PyC_FlagSet_ValueFromID(PyC_FlagSet *item, const char *identifier, int *r_value, const char *error_prefix)
{
- if (PyC_FlagSet_ValueFromID_int(item, identifier, value) == 0) {
+ if (PyC_FlagSet_ValueFromID_int(item, identifier, r_value) == 0) {
const char *enum_str = PyC_FlagSet_AsString(item);
PyErr_Format(PyExc_ValueError,
"%s: '%.200s' not found in (%s)",
@@ -1006,7 +1006,7 @@ PyObject *PyC_FlagSet_FromBitfield(PyC_FlagSet *items, int flag)
*
* \note it is caller's responsibility to acquire & release GIL!
*/
-bool PyC_RunString_AsNumber(const char *expr, double *value, const char *filename)
+bool PyC_RunString_AsNumber(const char *expr, const char *filename, double *r_value)
{
PyObject *py_dict, *mod, *retval;
bool ok = true;
@@ -1058,10 +1058,10 @@ bool PyC_RunString_AsNumber(const char *expr, double *value, const char *filenam
ok = false;
}
else if (!isfinite(val)) {
- *value = 0.0;
+ *r_value = 0.0;
}
else {
- *value = val;
+ *r_value = val;
}
}
@@ -1070,4 +1070,41 @@ bool PyC_RunString_AsNumber(const char *expr, double *value, const char *filenam
return ok;
}
+bool PyC_RunString_AsString(const char *expr, const char *filename, char **r_value)
+{
+ PyObject *py_dict, *retval;
+ bool ok = true;
+ PyObject *main_mod = NULL;
+
+ PyC_MainModule_Backup(&main_mod);
+
+ py_dict = PyC_DefaultNameSpace(filename);
+
+ retval = PyRun_String(expr, Py_eval_input, py_dict, py_dict);
+
+ if (retval == NULL) {
+ ok = false;
+ }
+ else {
+ const char *val;
+ Py_ssize_t val_len;
+
+ val = _PyUnicode_AsStringAndSize(retval, &val_len);
+ if (val == NULL && PyErr_Occurred()) {
+ ok = false;
+ }
+ else {
+ char *val_alloc = MEM_mallocN(val_len + 1, __func__);
+ memcpy(val_alloc, val, val_len + 1);
+ *r_value = val_alloc;
+ }
+
+ Py_DECREF(retval);
+ }
+
+ PyC_MainModule_Restore(main_mod);
+
+ return ok;
+}
+
#endif /* #ifndef MATH_STANDALONE */
diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h
index 04cfc8801eb..3f89e1d82a0 100644
--- a/source/blender/python/generic/py_capi_utils.h
+++ b/source/blender/python/generic/py_capi_utils.h
@@ -75,12 +75,13 @@ typedef struct PyC_FlagSet {
} PyC_FlagSet;
char *PyC_FlagSet_AsString(PyC_FlagSet *item);
-int PyC_FlagSet_ValueFromID_int(PyC_FlagSet *item, const char *identifier, int *value);
-int PyC_FlagSet_ValueFromID(PyC_FlagSet *item, const char *identifier, int *value, const char *error_prefix);
+int PyC_FlagSet_ValueFromID_int(PyC_FlagSet *item, const char *identifier, int *r_value);
+int PyC_FlagSet_ValueFromID(PyC_FlagSet *item, const char *identifier, int *r_value, const char *error_prefix);
int PyC_FlagSet_ToBitfield(PyC_FlagSet *items, PyObject *value, int *r_value, const char *error_prefix);
PyObject *PyC_FlagSet_FromBitfield(PyC_FlagSet *items, int flag);
-bool PyC_RunString_AsNumber(const char *expr, double *value, const char *filename);
+bool PyC_RunString_AsNumber(const char *expr, const char *filename, double *r_value);
+bool PyC_RunString_AsString(const char *expr, const char *filename, char **r_value);
int PyC_ParseBool(PyObject *o, void *p);
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 038c1e7eb10..967e90d22cb 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -55,6 +55,7 @@ set(SRC
bpy_app_handlers.c
bpy_app_ocio.c
bpy_app_oiio.c
+ bpy_app_opensubdiv.c
bpy_app_openvdb.c
bpy_app_sdl.c
bpy_app_translations.c
@@ -64,6 +65,7 @@ set(SRC
bpy_intern_string.c
bpy_library_load.c
bpy_library_write.c
+ bpy_manipulator_wrap.c
bpy_operator.c
bpy_operator_wrap.c
bpy_path.c
@@ -74,6 +76,7 @@ set(SRC
bpy_rna_callback.c
bpy_rna_driver.c
bpy_rna_id_collection.c
+ bpy_rna_manipulator.c
bpy_traceback.c
bpy_util.c
bpy_utils_previews.c
@@ -89,12 +92,14 @@ set(SRC
bpy_app_handlers.h
bpy_app_ocio.h
bpy_app_oiio.h
+ bpy_app_opensubdiv.h
bpy_app_openvdb.h
bpy_app_sdl.h
bpy_app_translations.h
bpy_driver.h
bpy_intern_string.h
bpy_library.h
+ bpy_manipulator_wrap.h
bpy_operator.h
bpy_operator_wrap.h
bpy_path.h
@@ -104,6 +109,7 @@ set(SRC
bpy_rna_callback.h
bpy_rna_driver.h
bpy_rna_id_collection.h
+ bpy_rna_manipulator.h
bpy_traceback.h
bpy_util.h
bpy_utils_previews.h
@@ -295,6 +301,13 @@ if(WITH_OPENIMAGEIO)
)
endif()
+if(WITH_OPENSUBDIV)
+ add_definitions(-DWITH_OPENSUBDIV)
+ list(APPEND INC
+ ../../../../intern/opensubdiv
+ )
+endif()
+
if(WITH_PLAYER)
add_definitions(-DWITH_PLAYER)
endif()
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index 5bbfb4912e6..4a29d4f8da1 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_manipulator.h"
#include "bpy_props.h"
#include "bpy_library.h"
#include "bpy_operator.h"
@@ -327,6 +328,8 @@ void BPy_init_modules(void)
BPY_rna_id_collection_module(mod);
+ BPY_rna_manipulator_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");
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index 78cb537cccd..8b3464173d2 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -37,6 +37,7 @@
#include "bpy_app_ffmpeg.h"
#include "bpy_app_ocio.h"
#include "bpy_app_oiio.h"
+#include "bpy_app_opensubdiv.h"
#include "bpy_app_openvdb.h"
#include "bpy_app_sdl.h"
#include "bpy_app_build_options.h"
@@ -109,6 +110,7 @@ static PyStructSequence_Field app_info_fields[] = {
{(char *)"ffmpeg", (char *)"FFmpeg library information backend"},
{(char *)"ocio", (char *)"OpenColorIO library information backend"},
{(char *)"oiio", (char *)"OpenImageIO library information backend"},
+ {(char *)"opensubdiv", (char *)"OpenSubdiv library information backend"},
{(char *)"openvdb", (char *)"OpenVDB library information backend"},
{(char *)"sdl", (char *)"SDL library information backend"},
{(char *)"build_options", (char *)"A set containing most important enabled optional build features"},
@@ -117,9 +119,21 @@ static PyStructSequence_Field app_info_fields[] = {
{NULL},
};
+PyDoc_STRVAR(bpy_app_doc,
+"This module contains application values that remain unchanged during runtime.\n"
+"\n"
+"Submodules:\n"
+"\n"
+".. toctree::\n"
+" :maxdepth: 1\n"
+"\n"
+" bpy.app.handlers.rst\n"
+" bpy.app.translations.rst\n"
+);
+
static PyStructSequence_Desc app_info_desc = {
(char *)"bpy.app", /* name */
- (char *)"This module contains application values that remain unchanged during runtime.", /* doc */
+ bpy_app_doc, /* doc */
app_info_fields, /* fields */
ARRAY_SIZE(app_info_fields) - 1
};
@@ -188,6 +202,7 @@ static PyObject *make_app_info(void)
SetObjItem(BPY_app_ffmpeg_struct());
SetObjItem(BPY_app_ocio_struct());
SetObjItem(BPY_app_oiio_struct());
+ SetObjItem(BPY_app_opensubdiv_struct());
SetObjItem(BPY_app_openvdb_struct());
SetObjItem(BPY_app_sdl_struct());
SetObjItem(BPY_app_build_options_struct());
@@ -234,7 +249,7 @@ static int bpy_app_debug_set(PyObject *UNUSED(self), PyObject *value, void *clos
return 0;
}
-
+#define BROKEN_BINARY_PATH_PYTHON_HACK
PyDoc_STRVAR(bpy_app_binary_path_python_doc,
"String, the path to the python executable (read-only)"
@@ -251,14 +266,18 @@ static PyObject *bpy_app_binary_path_python_get(PyObject *self, void *UNUSED(clo
fullpath, sizeof(fullpath),
PY_MAJOR_VERSION, PY_MINOR_VERSION);
ret = PyC_UnicodeFromByte(fullpath);
- PyDict_SetItem(BlenderAppType.tp_dict, PyDescr_NAME(self), ret);
+#ifdef BROKEN_BINARY_PATH_PYTHON_HACK
+ Py_INCREF(ret);
+ UNUSED_VARS(self);
+#else
+ PyDict_SetItem(BlenderAppType.tp_dict, /* XXX BAAAADDDDDD! self is not a PyDescr at all! it's bpy.app!!! */ PyDescr_NAME(self), ret);
+#endif
}
else {
Py_INCREF(ret);
}
return ret;
-
}
PyDoc_STRVAR(bpy_app_debug_value_doc,
diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c
index 6a8b0b065c2..5a309339e17 100644
--- a/source/blender/python/intern/bpy_app_handlers.c
+++ b/source/blender/python/intern/bpy_app_handlers.c
@@ -59,8 +59,6 @@ static PyStructSequence_Field app_cb_info_fields[] = {
{(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 *)"scene_update_pre", (char *)"on updating the scenes data (before)"},
- {(char *)"scene_update_post", (char *)"on updating the scenes data (after)"},
{(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"},
@@ -126,7 +124,7 @@ static PyObject *bpy_app_handlers_persistent_new(PyTypeObject *UNUSED(type), PyO
/* dummy type because decorators can't be PyCFunctions */
static PyTypeObject BPyPersistent_Type = {
-#if defined(_MSC_VER) || defined(FREE_WINDOWS)
+#if defined(_MSC_VER)
PyVarObject_HEAD_INIT(NULL, 0)
#else
PyVarObject_HEAD_INIT(&PyType_Type, 0)
@@ -206,7 +204,7 @@ PyObject *BPY_app_handlers_struct(void)
{
PyObject *ret;
-#if defined(_MSC_VER) || defined(FREE_WINDOWS)
+#if defined(_MSC_VER)
BPyPersistent_Type.ob_base.ob_base.ob_type = &PyType_Type;
#endif
@@ -317,7 +315,13 @@ void bpy_app_generic_callback(struct Main *UNUSED(main), struct ID *id, void *ar
func = PyList_GET_ITEM(cb_list, pos);
ret = PyObject_Call(func, args, NULL);
if (ret == NULL) {
- PyErr_Print();
+ /* Don't set last system variables because they might cause some
+ * dangling pointers to external render engines (when exception
+ * happens during rendering) which will break logic of render pipeline
+ * which expects to be the only user of render engine when rendering
+ * is finished.
+ */
+ PyErr_PrintEx(0);
PyErr_Clear();
}
else {
diff --git a/source/blender/python/intern/bpy_app_opensubdiv.c b/source/blender/python/intern/bpy_app_opensubdiv.c
new file mode 100644
index 00000000000..7f269baf2b0
--- /dev/null
+++ b/source/blender/python/intern/bpy_app_opensubdiv.c
@@ -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.
+ *
+ * Contributor(s): Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_app_opensubdiv.c
+ * \ingroup pythonintern
+ */
+
+#include <Python.h>
+#include "BLI_utildefines.h"
+
+#include "bpy_app_opensubdiv.h"
+
+#ifdef WITH_OPENSUBDIV
+# include "opensubdiv_capi.h"
+#endif
+
+static PyTypeObject BlenderAppOpenSubdivType;
+
+static PyStructSequence_Field app_opensubdiv_info_fields[] = {
+ {(char *)"supported", (char *)("Boolean, True when Blender is built with OpenSubdiv support")},
+ {(char *)("version"), (char *)("The OpenSubdiv version as a tuple of 3 numbers")},
+ {(char *)("version_string"), (char *)("The OpenSubdiv version formatted as a string")},
+ {NULL}
+};
+
+static PyStructSequence_Desc app_opensubdiv_info_desc = {
+ (char *)"bpy.app.opensubdiv", /* name */
+ (char *)"This module contains information about OpenSubdiv blender is linked against", /* doc */
+ app_opensubdiv_info_fields, /* fields */
+ ARRAY_SIZE(app_opensubdiv_info_fields) - 1
+};
+
+static PyObject *make_opensubdiv_info(void)
+{
+ PyObject *opensubdiv_info;
+ int pos = 0;
+
+ opensubdiv_info = PyStructSequence_New(&BlenderAppOpenSubdivType);
+ if (opensubdiv_info == NULL) {
+ return NULL;
+ }
+
+#ifndef WITH_OPENSUBDIV
+#define SetStrItem(str) \
+ PyStructSequence_SET_ITEM(opensubdiv_info, pos++, PyUnicode_FromString(str))
+#endif
+
+#define SetObjItem(obj) \
+ PyStructSequence_SET_ITEM(opensubdiv_info, pos++, obj)
+
+#ifdef WITH_OPENSUBDIV
+ int curversion = openSubdiv_getVersionHex();
+ SetObjItem(PyBool_FromLong(1));
+ SetObjItem(Py_BuildValue("(iii)",
+ curversion / 10000, (curversion / 100) % 100, curversion % 100));
+ SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d",
+ curversion / 10000, (curversion / 100) % 100, curversion % 100));
+#else
+ SetObjItem(PyBool_FromLong(0));
+ SetObjItem(Py_BuildValue("(iii)", 0, 0, 0));
+ SetStrItem("Unknown");
+#endif
+
+ if (PyErr_Occurred()) {
+ Py_CLEAR(opensubdiv_info);
+ return NULL;
+ }
+
+#undef SetStrItem
+#undef SetObjItem
+
+ return opensubdiv_info;
+}
+
+PyObject *BPY_app_opensubdiv_struct(void)
+{
+ PyObject *ret;
+
+ PyStructSequence_InitType(&BlenderAppOpenSubdivType, &app_opensubdiv_info_desc);
+
+ ret = make_opensubdiv_info();
+
+ /* prevent user from creating new instances */
+ BlenderAppOpenSubdivType.tp_init = NULL;
+ BlenderAppOpenSubdivType.tp_new = NULL;
+ /* without this we can't do set(sys.modules) [#29635] */
+ BlenderAppOpenSubdivType.tp_hash = (hashfunc)_Py_HashPointer;
+
+ return ret;
+}
diff --git a/source/blender/depsgraph/util/deg_util_hash.h b/source/blender/python/intern/bpy_app_opensubdiv.h
index e490be1a7a1..b1da218b168 100644
--- a/source/blender/depsgraph/util/deg_util_hash.h
+++ b/source/blender/python/intern/bpy_app_opensubdiv.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) 2014 Blender Foundation.
- * All rights reserved.
- *
- * Original Author: Brecht van Lommel
- * Contributor(s): Lukas Toenne
+ * Contributor(s): Sergey Sharybin
*
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/deg_util_hash.h
- * \ingroup depsgraph
+/** \file blender/python/intern/bpy_app_opensubdiv.h
+ * \ingroup pythonintern
*/
-#pragma once
-
-#include "BLI_utildefines.h"
+#ifndef __BPY_APP_OPENSUBDIV_H__
+#define __BPY_APP_OPENSUBDIV_H__
-#include "BLI_ghash.h"
+PyObject *BPY_app_opensubdiv_struct(void);
-/* XXX this might require 2 different variants for sizeof(size_t) (32 vs 64 bit) */
-BLI_INLINE size_t hash_combine(size_t hash_a, size_t hash_b)
-{
- return hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2));
-}
+#endif /* __BPY_APP_OPENSUBDIV_H__ */
diff --git a/source/blender/python/intern/bpy_app_sdl.c b/source/blender/python/intern/bpy_app_sdl.c
index 2f4d8e6c325..76dab775953 100644
--- a/source/blender/python/intern/bpy_app_sdl.c
+++ b/source/blender/python/intern/bpy_app_sdl.c
@@ -56,7 +56,7 @@ static PyStructSequence_Field app_sdl_info_fields[] = {
{(char *)"available", (char *)("Boolean, True when SDL is available. This is False when "
"either *supported* is False, or *dynload* is True and "
"Blender cannot find the correct library.")},
- {NULL}
+ {NULL}
};
static PyStructSequence_Desc app_sdl_info_desc = {
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 311f621e13b..cd4d2f7a1c2 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -480,11 +480,20 @@ static bool python_script_exec(
* object, but as written in the Python/C API Ref Manual, chapter 2,
* 'FILE structs for different C libraries can be different and
* incompatible'.
- * So now we load the script file data to a buffer */
+ * So now we load the script file data to a buffer.
+ *
+ * Note on use of 'globals()', it's important not copy the dictionary because
+ * tools may inspect 'sys.modules["__main__"]' for variables defined in the code
+ * where using a copy of 'globals()' causes code execution
+ * to leave the main namespace untouched. see: T51444
+ *
+ * This leaves us with the problem of variables being included,
+ * currently this is worked around using 'dict.__del__' it's ugly but works.
+ */
{
const char *pystring =
- "ns = globals().copy()\n"
- "with open(__file__, 'rb') as f: exec(compile(f.read(), __file__, 'exec'), ns)";
+ "with open(__file__, 'rb') as f:"
+ "exec(compile(f.read(), __file__, 'exec'), globals().__delitem__('f') or globals())";
fclose(fp);
@@ -521,7 +530,8 @@ static bool python_script_exec(
if (py_dict) {
#ifdef PYMODULE_CLEAR_WORKAROUND
- PyModuleObject *mmod = (PyModuleObject *)PyDict_GetItemString(PyThreadState_GET()->interp->modules, "__main__");
+ PyModuleObject *mmod = (PyModuleObject *)PyDict_GetItem(
+ PyThreadState_GET()->interp->modules, 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. */
@@ -572,21 +582,58 @@ void BPY_DECREF_RNA_INVALIDATE(void *pyob_ptr)
/**
* \return success
*/
-bool BPY_execute_string_as_number(bContext *C, const char *expr, double *value, const bool verbose)
+bool BPY_execute_string_as_number(bContext *C, const char *expr, const bool verbose, double *r_value)
{
PyGILState_STATE gilstate;
bool ok = true;
- if (!value || !expr) return -1;
+ if (!r_value || !expr) {
+ return -1;
+ }
+
+ if (expr[0] == '\0') {
+ *r_value = 0.0;
+ return ok;
+ }
+
+ bpy_context_set(C, &gilstate);
+
+ ok = PyC_RunString_AsNumber(expr, "<blender button>", r_value);
+
+ if (ok == false) {
+ if (verbose) {
+ BPy_errors_to_report_ex(CTX_wm_reports(C), false, false);
+ }
+ else {
+ PyErr_Clear();
+ }
+ }
+
+ bpy_context_clear(C, &gilstate);
+
+ return ok;
+}
+
+/**
+ * \return success
+ */
+bool BPY_execute_string_as_string(bContext *C, const char *expr, const bool verbose, char **r_value)
+{
+ PyGILState_STATE gilstate;
+ bool ok = true;
+
+ if (!r_value || !expr) {
+ return -1;
+ }
if (expr[0] == '\0') {
- *value = 0.0;
+ *r_value = NULL;
return ok;
}
bpy_context_set(C, &gilstate);
- ok = PyC_RunString_AsNumber(expr, value, "<blender button>");
+ ok = PyC_RunString_AsString(expr, "<blender button>", r_value);
if (ok == false) {
if (verbose) {
@@ -602,6 +649,7 @@ bool BPY_execute_string_as_number(bContext *C, const char *expr, double *value,
return ok;
}
+
bool BPY_execute_string_ex(bContext *C, const char *expr, bool use_eval)
{
PyGILState_STATE gilstate;
diff --git a/source/blender/python/intern/bpy_intern_string.c b/source/blender/python/intern/bpy_intern_string.c
index ac0100fa75d..6911e985e93 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___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_frame;
PyObject *bpy_intern_str_order;
-PyObject *bpy_intern_str_attr;
+PyObject *bpy_intern_str_properties;
+PyObject *bpy_intern_str_register;
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_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___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_frame, "frame");
BPY_INTERN_STR(bpy_intern_str_order, "order");
- BPY_INTERN_STR(bpy_intern_str_attr, "attr");
+ 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_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_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..998c312c321 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___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_frame;
extern PyObject *bpy_intern_str_order;
-extern PyObject *bpy_intern_str_attr;
+extern PyObject *bpy_intern_str_properties;
+extern PyObject *bpy_intern_str_register;
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_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 ec69abbb1df..73265d28a93 100644
--- a/source/blender/python/intern/bpy_library_load.c
+++ b/source/blender/python/intern/bpy_library_load.c
@@ -33,6 +33,7 @@
#include <stddef.h>
#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
#include "BLI_string.h"
#include "BLI_linklist.h"
#include "BLI_path_util.h"
@@ -331,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);
@@ -340,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);
@@ -405,14 +407,16 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
BLO_blendhandle_close(self->blo_handle);
self->blo_handle = NULL;
+ GHash *old_to_new_ids = BLI_ghash_ptr_new(__func__);
+
/* copied from wm_operator.c */
{
/* mark all library linked objects to be updated */
BKE_main_lib_objects_recalc_all(bmain);
/* append, rather than linking */
- if ((self->flag & FILE_LINK) == 0) {
- BKE_library_make_local(bmain, lib, true, false);
+ if (do_append) {
+ BKE_library_make_local(bmain, lib, old_to_new_ids, true, false);
}
}
@@ -424,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)) {
@@ -439,6 +443,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
ID *id;
id = PyCapsule_GetPointer(item, NULL);
+ id = BLI_ghash_lookup_default(old_to_new_ids, id, id);
Py_DECREF(item);
RNA_id_pointer_create(id, &id_ptr);
@@ -452,6 +457,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
}
#endif /* USE_RNA_DATABLOCKS */
+ BLI_ghash_free(old_to_new_ids, NULL, NULL);
Py_RETURN_NONE;
}
}
diff --git a/source/blender/python/intern/bpy_library_write.c b/source/blender/python/intern/bpy_library_write.c
index f582cebb260..bf91253141a 100644
--- a/source/blender/python/intern/bpy_library_write.c
+++ b/source/blender/python/intern/bpy_library_write.c
@@ -50,7 +50,7 @@
PyDoc_STRVAR(bpy_lib_write_doc,
-".. method:: write(filepath, datablocks, relative_remap=False, fake_user=False)\n"
+".. method:: write(filepath, datablocks, relative_remap=False, fake_user=False, compress=False)\n"
"\n"
" Write data-blocks into a blend file.\n"
"\n"
diff --git a/source/blender/python/intern/bpy_manipulator_wrap.c b/source/blender/python/intern/bpy_manipulator_wrap.c
new file mode 100644
index 00000000000..7d02c2963d7
--- /dev/null
+++ b/source/blender/python/intern/bpy_manipulator_wrap.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/intern/bpy_manipulator_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_manipulator_wrap.h" /* own include */
+
+/* we may want to add, but not now */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Manipulator
+ * \{ */
+
+
+static bool bpy_manipulatortype_target_property_def(
+ wmManipulatorType *wt, 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};
+#define KW_FMT "|$ssi:register_class"
+#if PY_VERSION_HEX >= 0x03060000
+ static _PyArg_Parser _parser = {KW_FMT, _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ empty_tuple, item,
+ &_parser,
+ &params.id,
+ &params.type_id,
+ &params.array_length))
+#else
+ if (!PyArg_ParseTupleAndKeywords(
+ empty_tuple, item,
+ KW_FMT, (char **)_keywords,
+ &params.id,
+ &params.type_id,
+ &params.array_length))
+#endif
+ {
+ goto fail;
+ }
+#undef KW_FMT
+
+ 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_manipulatortype_target_property_def(wt, params.id, params.type, params.array_length);
+ Py_DECREF(empty_tuple);
+ return true;
+
+fail:
+ Py_DECREF(empty_tuple);
+ return false;
+}
+
+static void manipulator_properties_init(wmManipulatorType *wt)
+{
+ PyTypeObject *py_class = wt->ext.data;
+ RNA_struct_blender_type_set(wt->ext.srna, wt);
+
+ /* 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(wt->srna, wt->idname);
+
+ if (pyrna_deferred_register_class(wt->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);
+ 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_manipulatortype_target_property_def(wt, items[i])) {
+ PyErr_Print();
+ PyErr_Clear();
+ break;
+ }
+ }
+
+ Py_DECREF(bl_target_properties_fast);
+ }
+}
+
+void BPY_RNA_manipulator_wrapper(wmManipulatorType *wt, void *userdata)
+{
+ /* take care not to overwrite anything set in
+ * WM_manipulatormaptype_group_link_ptr before opfunc() is called */
+ StructRNA *srna = wt->srna;
+ *wt = *((wmManipulatorType *)userdata);
+ wt->srna = srna; /* restore */
+
+ /* don't do translations here yet */
+#if 0
+ /* Use i18n context from ext.srna if possible (py manipulatorgroups). */
+ if (wt->ext.srna) {
+ RNA_def_struct_translation_context(wt->srna, RNA_struct_translation_context(wt->ext.srna));
+ }
+#endif
+
+ wt->struct_size = sizeof(wmManipulator);
+
+ manipulator_properties_init(wt);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Manipulator Group
+ * \{ */
+
+static void manipulatorgroup_properties_init(wmManipulatorGroupType *wgt)
+{
+#ifdef USE_SRNA
+ PyTypeObject *py_class = wgt->ext.data;
+#endif
+ RNA_struct_blender_type_set(wgt->ext.srna, wgt);
+
+#ifdef USE_SRNA
+ /* 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(wgt->srna, wgt->idname);
+
+ if (pyrna_deferred_register_class(wgt->srna, py_class) != 0) {
+ PyErr_Print(); /* failed to register operator props */
+ PyErr_Clear();
+ }
+#endif
+}
+
+void BPY_RNA_manipulatorgroup_wrapper(wmManipulatorGroupType *wgt, void *userdata)
+{
+ /* take care not to overwrite anything set in
+ * WM_manipulatormaptype_group_link_ptr before opfunc() is called */
+#ifdef USE_SRNA
+ StructRNA *srna = wgt->srna;
+#endif
+ *wgt = *((wmManipulatorGroupType *)userdata);
+#ifdef USE_SRNA
+ wgt->srna = srna; /* restore */
+#endif
+
+#ifdef USE_SRNA
+ /* Use i18n context from ext.srna if possible (py manipulatorgroups). */
+ if (wgt->ext.srna) {
+ RNA_def_struct_translation_context(wgt->srna, RNA_struct_translation_context(wgt->ext.srna));
+ }
+#endif
+
+ manipulatorgroup_properties_init(wgt);
+}
+
+/** \} */
+
diff --git a/source/blender/python/intern/bpy_manipulator_wrap.h b/source/blender/python/intern/bpy_manipulator_wrap.h
new file mode 100644
index 00000000000..3f739e26059
--- /dev/null
+++ b/source/blender/python/intern/bpy_manipulator_wrap.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 *****
+ */
+
+/** \file blender/python/intern/bpy_manipulator_wrap.h
+ * \ingroup pythonintern
+ */
+
+#ifndef __BPY_MANIPULATOR_WRAP_H__
+#define __BPY_MANIPULATOR_WRAP_H__
+
+struct wmManipulatorType;
+struct wmManipulatorGroupType;
+
+/* exposed to rna/wm api */
+void BPY_RNA_manipulator_wrapper(struct wmManipulatorType *wt, void *userdata);
+void BPY_RNA_manipulatorgroup_wrapper(struct wmManipulatorGroupType *wgt, void *userdata);
+
+#endif /* __BPY_MANIPULATOR_WRAP_H__ */
+
diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c
index 11e27ca3e3c..90719905a79 100644
--- a/source/blender/python/intern/bpy_operator_wrap.c
+++ b/source/blender/python/intern/bpy_operator_wrap.c
@@ -118,7 +118,7 @@ static void operator_properties_init(wmOperatorType *ot)
}
-void operator_wrapper(wmOperatorType *ot, void *userdata)
+void BPY_RNA_operator_wrapper(wmOperatorType *ot, void *userdata)
{
/* take care not to overwrite anything set in
* WM_operatortype_append_ptr before opfunc() is called */
@@ -134,7 +134,7 @@ void operator_wrapper(wmOperatorType *ot, void *userdata)
operator_properties_init(ot);
}
-void macro_wrapper(wmOperatorType *ot, void *userdata)
+void BPY_RNA_operator_macro_wrapper(wmOperatorType *ot, void *userdata)
{
wmOperatorType *data = (wmOperatorType *)userdata;
diff --git a/source/blender/python/intern/bpy_operator_wrap.h b/source/blender/python/intern/bpy_operator_wrap.h
index 05a566a1485..0828c58e2bd 100644
--- a/source/blender/python/intern/bpy_operator_wrap.h
+++ b/source/blender/python/intern/bpy_operator_wrap.h
@@ -33,7 +33,7 @@ struct wmOperatorType;
PyObject *PYOP_wrap_macro_define(PyObject *self, PyObject *args);
/* exposed to rna/wm api */
-void operator_wrapper(struct wmOperatorType *ot, void *userdata);
-void macro_wrapper(struct wmOperatorType *ot, void *userdata);
+void BPY_RNA_operator_wrapper(struct wmOperatorType *ot, void *userdata);
+void BPY_RNA_operator_macro_wrapper(struct wmOperatorType *ot, void *userdata);
#endif
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index 3baeae0384a..c7787ba9682 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -50,11 +50,13 @@
#include "../generic/py_capi_utils.h"
/* initial definition of callback slots we'll probably have more than 1 */
-#define BPY_DATA_CB_SLOT_SIZE 3
-
-#define BPY_DATA_CB_SLOT_UPDATE 0
-#define BPY_DATA_CB_SLOT_GET 1
-#define BPY_DATA_CB_SLOT_SET 2
+enum {
+ BPY_DATA_CB_SLOT_UPDATE = 0,
+ BPY_DATA_CB_SLOT_GET = 1,
+ BPY_DATA_CB_SLOT_SET = 2,
+ BPY_DATA_CB_SLOT_POLL = 3,
+ BPY_DATA_CB_SLOT_SIZE = 4,
+};
extern BPy_StructRNA *bpy_context_module;
@@ -71,6 +73,9 @@ static EnumPropertyItem property_flag_items[] = {
" :arg options: Enumerator in ['HIDDEN', 'SKIP_SAVE', 'ANIMATABLE', 'LIBRARY_EDITABLE', 'PROPORTIONAL'," \
"'TEXTEDIT_UPDATE'].\n" \
" :type options: set\n" \
+" :arg poll: function to be called to determine whether an item is valid for this property.\n" \
+" The function must take 2 values (self,object) and return Bool.\n" \
+" :type poll: function\n" \
static EnumPropertyItem property_flag_enum_items[] = {
{PROP_HIDDEN, "HIDDEN", 0, "Hidden", ""},
@@ -230,7 +235,7 @@ static PyObject *bpy_prop_deferred_return(PyObject *func, PyObject *kw)
static void bpy_prop_update_cb(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop)
{
PyGILState_STATE gilstate;
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -279,7 +284,7 @@ static void bpy_prop_update_cb(struct bContext *C, struct PointerRNA *ptr, struc
static int bpy_prop_boolean_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -337,7 +342,7 @@ static int bpy_prop_boolean_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
static void bpy_prop_boolean_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int value)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -389,9 +394,54 @@ static void bpy_prop_boolean_set_cb(struct PointerRNA *ptr, struct PropertyRNA *
}
}
+static int bpy_prop_poll_cb(struct PointerRNA *self, PointerRNA candidate, struct PropertyRNA *prop)
+{
+ PyObject *py_self;
+ PyObject *py_candidate;
+ PyObject *py_func;
+ PyObject **py_data = RNA_property_py_data_get(prop);
+ PyObject *args;
+ PyObject *ret;
+ bool result;
+ const int is_write_ok = pyrna_write_check();
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
+ BLI_assert(self != NULL);
+
+ py_self = pyrna_struct_as_instance(self);
+ py_candidate = pyrna_struct_as_instance(&candidate);
+ py_func = py_data[BPY_DATA_CB_SLOT_POLL];
+
+ if (!is_write_ok)
+ pyrna_write_set(true);
+
+ args = PyTuple_New(2);
+ PyTuple_SET_ITEM(args, 0, py_self);
+ PyTuple_SET_ITEM(args, 1, py_candidate);
+
+ ret = PyObject_CallObject(py_func, args);
+
+ Py_DECREF(args);
+
+ if (ret == NULL) {
+ printf_func_error(py_func);
+ result = false;
+ }
+ else {
+ result = PyObject_IsTrue(ret);
+ Py_DECREF(ret);
+ }
+
+ PyGILState_Release(gilstate);
+ if (!is_write_ok)
+ pyrna_write_set(false);
+
+ return result;
+}
+
static void bpy_prop_boolean_array_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int *values)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -452,7 +502,7 @@ static void bpy_prop_boolean_array_get_cb(struct PointerRNA *ptr, struct Propert
static void bpy_prop_boolean_array_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, const int *values)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -513,7 +563,7 @@ static void bpy_prop_boolean_array_set_cb(struct PointerRNA *ptr, struct Propert
static int bpy_prop_int_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -571,7 +621,7 @@ static int bpy_prop_int_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
static void bpy_prop_int_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int value)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -625,7 +675,7 @@ static void bpy_prop_int_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop
static void bpy_prop_int_array_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int *values)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -686,7 +736,7 @@ static void bpy_prop_int_array_get_cb(struct PointerRNA *ptr, struct PropertyRNA
static void bpy_prop_int_array_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, const int *values)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -747,7 +797,7 @@ static void bpy_prop_int_array_set_cb(struct PointerRNA *ptr, struct PropertyRNA
static float bpy_prop_float_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -805,7 +855,7 @@ static float bpy_prop_float_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
static void bpy_prop_float_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, float value)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -859,7 +909,7 @@ static void bpy_prop_float_set_cb(struct PointerRNA *ptr, struct PropertyRNA *pr
static void bpy_prop_float_array_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, float *values)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -920,7 +970,7 @@ static void bpy_prop_float_array_get_cb(struct PointerRNA *ptr, struct PropertyR
static void bpy_prop_float_array_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, const float *values)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -981,7 +1031,7 @@ static void bpy_prop_float_array_set_cb(struct PointerRNA *ptr, struct PropertyR
static void bpy_prop_string_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, char *value)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1040,7 +1090,7 @@ static void bpy_prop_string_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
static int bpy_prop_string_length_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1102,7 +1152,7 @@ static int bpy_prop_string_length_cb(struct PointerRNA *ptr, struct PropertyRNA
static void bpy_prop_string_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, const char *value)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1163,7 +1213,7 @@ static void bpy_prop_string_set_cb(struct PointerRNA *ptr, struct PropertyRNA *p
static int bpy_prop_enum_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1221,7 +1271,7 @@ static int bpy_prop_enum_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop
static void bpy_prop_enum_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int value)
{
- PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
+ PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1598,6 +1648,16 @@ static void bpy_prop_callback_assign_update(struct PropertyRNA *prop, PyObject *
}
}
+static void bpy_prop_callback_assign_pointer(struct PropertyRNA *prop, PyObject *poll_cb)
+{
+ if (poll_cb && poll_cb != Py_None) {
+ PyObject **py_data = bpy_prop_py_data_get(prop);
+
+ RNA_def_property_poll_runtime(prop, (void *) bpy_prop_poll_cb);
+ py_data[BPY_DATA_CB_SLOT_POLL] = poll_cb;
+ }
+}
+
static void bpy_prop_callback_assign_boolean(struct PropertyRNA *prop, PyObject *get_cb, PyObject *set_cb)
{
BooleanPropertyGetFunc rna_get_cb = NULL;
@@ -1904,7 +1964,7 @@ static void bpy_prop_callback_assign_enum(struct PropertyRNA *prop, PyObject *ge
" :type set: function\n" \
#define BPY_PROPDEF_TYPE_DOC \
-" :arg type: A subclass of :class:`bpy.types.PropertyGroup`.\n" \
+" :arg type: A subclass of :class:`bpy.types.PropertyGroup` or :class:`bpy.types.ID`.\n" \
" :type type: class\n" \
#if 0
@@ -2648,7 +2708,8 @@ PyDoc_STRVAR(BPy_EnumProperty_doc,
" .. warning::\n"
"\n"
" There is a known bug with using a callback,\n"
-" Python must keep a reference to the strings returned or Blender will crash.\n"
+" Python must keep a reference to the strings returned or Blender will misbehave\n"
+" or even crash."
"\n"
" :type items: sequence of string tuples or a function\n"
BPY_PROPDEF_NAME_DOC
@@ -2771,7 +2832,7 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
Py_RETURN_NONE;
}
-static StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix)
+StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix)
{
StructRNA *srna;
@@ -2781,25 +2842,18 @@ static StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix
PyObject *msg = PyC_ExceptionBuffer();
const char *msg_char = _PyUnicode_AsString(msg);
PyErr_Format(PyExc_TypeError,
- "%.200s expected an RNA type derived from PropertyGroup, failed with: %s",
+ "%.200s expected an RNA type, failed with: %s",
error_prefix, msg_char);
Py_DECREF(msg);
}
else {
PyErr_Format(PyExc_TypeError,
- "%.200s expected an RNA type derived from PropertyGroup, failed with type '%s'",
+ "%.200s expected an RNA type, failed with type '%s'",
error_prefix, Py_TYPE(value)->tp_name);
}
return NULL;
}
- if (!RNA_struct_is_a(srna, &RNA_PropertyGroup)) {
- PyErr_Format(PyExc_TypeError,
- "%.200s expected an RNA type derived from PropertyGroup",
- error_prefix);
- return NULL;
- }
-
return srna;
}
@@ -2808,6 +2862,7 @@ PyDoc_STRVAR(BPy_PointerProperty_doc,
"name=\"\", "
"description=\"\", "
"options={'ANIMATABLE'}, "
+ "poll=None, "
"update=None)\n"
"\n"
" Returns a new pointer property definition.\n"
@@ -2818,14 +2873,14 @@ BPY_PROPDEF_DESC_DOC
BPY_PROPDEF_OPTIONS_DOC
BPY_PROPDEF_UPDATE_DOC
);
-static PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
+PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
BPY_PROPDEF_HEAD(PointerProperty);
if (srna) {
- static const char *kwlist[] = {"attr", "type", "name", "description", "options", "update", NULL};
+ static const char *kwlist[] = {"attr", "type", "name", "description", "options", "poll", "update", NULL};
const char *id = NULL, *name = NULL, *description = "";
int id_len;
PropertyRNA *prop;
@@ -2833,33 +2888,47 @@ static PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *k
PyObject *type = Py_None;
PyObject *pyopts = NULL;
int opts = 0;
- PyObject *update_cb = NULL;
+ PyObject *update_cb = NULL, *poll_cb = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kw,
- "s#O|ssO!O:PointerProperty",
+ "s#O|ssO!OOO:PointerProperty",
(char **)kwlist, &id, &id_len,
&type, &name, &description,
&PySet_Type, &pyopts,
- &update_cb))
+ &poll_cb, &update_cb))
{
return NULL;
}
BPY_PROPDEF_CHECK(PointerProperty, property_flag_items);
- ptype = pointer_type_from_py(type, "PointerProperty(...):");
+ ptype = pointer_type_from_py(type, "PointerProperty(...)");
if (!ptype)
return NULL;
-
+ if (!RNA_struct_is_a(ptype, &RNA_PropertyGroup) && !RNA_struct_is_ID(ptype)) {
+ PyErr_Format(PyExc_TypeError,
+ "PointerProperty(...) expected an RNA type derived from %.200s or %.200s",
+ RNA_struct_ui_name(&RNA_ID), RNA_struct_ui_name(&RNA_PropertyGroup));
+ return NULL;
+ }
if (bpy_prop_callback_check(update_cb, "update", 2) == -1) {
return NULL;
}
-
+ if (bpy_prop_callback_check(poll_cb, "poll", 2) == -1) {
+ return NULL;
+ }
prop = RNA_def_pointer_runtime(srna, id, ptype, name ? name : id, description);
if (pyopts) {
bpy_prop_assign_flag(prop, opts);
}
+
+ if (RNA_struct_idprops_contains_datablock(ptype)) {
+ if (RNA_struct_is_a(srna, &RNA_PropertyGroup)) {
+ RNA_def_struct_flag(srna, STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES);
+ }
+ }
bpy_prop_callback_assign_update(prop, update_cb);
+ bpy_prop_callback_assign_pointer(prop, poll_cb);
RNA_def_property_duplicate_pointers(srna, prop);
}
Py_RETURN_NONE;
@@ -2878,7 +2947,7 @@ BPY_PROPDEF_NAME_DOC
BPY_PROPDEF_DESC_DOC
BPY_PROPDEF_OPTIONS_DOC
);
-static PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
+PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -2909,17 +2978,30 @@ static PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject
if (!ptype)
return NULL;
+ if (!RNA_struct_is_a(ptype, &RNA_PropertyGroup)) {
+ PyErr_Format(PyExc_TypeError,
+ "CollectionProperty(...) expected an RNA type derived from %.200s",
+ RNA_struct_ui_name(&RNA_ID), RNA_struct_ui_name(&RNA_PropertyGroup));
+ return NULL;
+ }
+
prop = RNA_def_collection_runtime(srna, id, ptype, name ? name : id, description);
if (pyopts) {
bpy_prop_assign_flag(prop, opts);
}
+
+ if (RNA_struct_idprops_contains_datablock(ptype)) {
+ if (RNA_struct_is_a(srna, &RNA_PropertyGroup)) {
+ RNA_def_struct_flag(srna, STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES);
+ }
+ }
RNA_def_property_duplicate_pointers(srna, prop);
}
Py_RETURN_NONE;
}
PyDoc_STRVAR(BPy_RemoveProperty_doc,
-".. function:: RemoveProperty(cls, attr="")\n"
+".. function:: RemoveProperty(cls, attr)\n"
"\n"
" Removes a dynamically defined property.\n"
"\n"
diff --git a/source/blender/python/intern/bpy_props.h b/source/blender/python/intern/bpy_props.h
index c9934ca0cf3..614c1b4b708 100644
--- a/source/blender/python/intern/bpy_props.h
+++ b/source/blender/python/intern/bpy_props.h
@@ -30,6 +30,10 @@
PyObject *BPY_rna_props(void);
+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
#endif
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index ab523e03f4d..51e179fb317 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -310,7 +310,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);
@@ -806,7 +806,7 @@ static PyObject *pyrna_struct_richcmp(PyObject *a, PyObject *b, int op)
switch (op) {
case Py_NE:
ok = !ok;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case Py_EQ:
res = ok ? Py_False : Py_True;
break;
@@ -836,7 +836,7 @@ static PyObject *pyrna_prop_richcmp(PyObject *a, PyObject *b, int op)
switch (op) {
case Py_NE:
ok = !ok;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case Py_EQ:
res = ok ? Py_False : Py_True;
break;
@@ -1636,7 +1636,7 @@ static int pyrna_py_to_prop(
/* prefer not to have an exception here
* however so many poll functions return None or a valid Object.
* its a hassle to convert these into a bool before returning, */
- if (RNA_property_flag(prop) & PROP_OUTPUT) {
+ if (RNA_parameter_flag(prop) & PARM_OUTPUT) {
param = PyObject_IsTrue(value);
}
else {
@@ -1824,6 +1824,7 @@ static int pyrna_py_to_prop(
StructRNA *ptr_type = RNA_property_pointer_type(ptr, prop);
int flag = RNA_property_flag(prop);
+ int flag_parameter = RNA_parameter_flag(prop);
/* this is really nasty!, so we can fake the operator having direct properties eg:
* layout.prop(self, "filepath")
@@ -1838,19 +1839,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_Manipulator)) {
+ 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/ManipulatorProperties 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_ManipulatorProperties) {
+ 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 */
@@ -1900,7 +1910,7 @@ static int pyrna_py_to_prop(
bool raise_error = false;
if (data) {
- if (flag & PROP_RNAPTR) {
+ if (flag_parameter & PARM_RNAPTR) {
if (flag & PROP_THICK_WRAP) {
if (value == Py_None)
memset(data, 0, sizeof(PointerRNA));
@@ -1933,16 +1943,10 @@ static int pyrna_py_to_prop(
}
else {
/* data == NULL, assign to RNA */
- if (value == Py_None) {
- PointerRNA valueptr = {{NULL}};
- RNA_property_pointer_set(ptr, prop, valueptr);
- }
- else if (RNA_struct_is_a(param->ptr.type, ptr_type)) {
- RNA_property_pointer_set(ptr, prop, param->ptr);
- }
- else {
+ if (value == Py_None || RNA_struct_is_a(param->ptr.type, ptr_type))
+ RNA_property_pointer_set(ptr, prop, value == Py_None ? PointerRNA_NULL : param->ptr);
+ else
raise_error = true;
- }
}
if (raise_error) {
@@ -3276,6 +3280,20 @@ static int pyrna_struct_ass_subscript(BPy_StructRNA *self, PyObject *key, PyObje
return -1;
}
+ if (value && BPy_StructRNA_Check(value)) {
+ BPy_StructRNA *val = (BPy_StructRNA *)value;
+ if (val && self->ptr.type && val->ptr.type) {
+ if (!RNA_struct_idprops_datablock_allowed(self->ptr.type) &&
+ RNA_struct_idprops_contains_datablock(val->ptr.type))
+ {
+ PyErr_SetString(
+ PyExc_TypeError,
+ "bpy_struct[key] = val: datablock id properties not supported for this type");
+ return -1;
+ }
+ }
+ }
+
return BPy_Wrap_SetMapItem(group, key, value);
}
@@ -5116,6 +5134,7 @@ static PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *dat
PyObject *ret;
const int type = RNA_property_type(prop);
const int flag = RNA_property_flag(prop);
+ const int flag_parameter = RNA_parameter_flag(prop);
if (RNA_property_array_check(prop)) {
int a, len;
@@ -5158,7 +5177,7 @@ static PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *dat
ret = Matrix_CreatePyObject(data, 3, 3, NULL);
break;
}
- /* fall-through */
+ ATTR_FALLTHROUGH;
#endif
default:
ret = PyTuple_New(len);
@@ -5233,7 +5252,7 @@ static PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *dat
PointerRNA newptr;
StructRNA *ptype = RNA_property_pointer_type(ptr, prop);
- if (flag & PROP_RNAPTR) {
+ if (flag_parameter & PARM_RNAPTR) {
/* in this case we get the full ptr */
newptr = *(PointerRNA *)data;
}
@@ -5315,7 +5334,7 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject
ParameterIterator iter;
PropertyRNA *parm;
PyObject *ret, *item;
- int i, pyargs_len, pykw_len, parms_len, ret_len, flag, err = 0, kw_tot = 0;
+ int i, pyargs_len, pykw_len, parms_len, ret_len, flag_parameter, err = 0, kw_tot = 0;
bool kw_arg;
PropertyRNA *pret_single = NULL;
@@ -5380,10 +5399,10 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject
/* parse function parameters */
for (i = 0; iter.valid && err == 0; RNA_parameter_list_next(&iter)) {
parm = iter.parm;
- flag = RNA_property_flag(parm);
+ flag_parameter = RNA_parameter_flag(parm);
/* only useful for single argument returns, we'll need another list loop for multiple */
- if (flag & PROP_OUTPUT) {
+ if (flag_parameter & PARM_OUTPUT) {
ret_len++;
if (pret_single == NULL) {
pret_single = parm;
@@ -5414,7 +5433,7 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject
i++; /* current argument */
if (item == NULL) {
- if (flag & PROP_REQUIRED) {
+ if (flag_parameter & PARM_REQUIRED) {
PyErr_Format(PyExc_TypeError,
"%.200s.%.200s(): required parameter \"%.200s\" not specified",
RNA_struct_identifier(self_ptr->type),
@@ -5514,7 +5533,7 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject
RNA_parameter_list_begin(&parms, &iter);
for (; iter.valid; RNA_parameter_list_next(&iter)) {
parm = iter.parm;
- if (RNA_property_flag(parm) & PROP_OUTPUT)
+ if (RNA_parameter_flag(parm) & PARM_OUTPUT)
continue;
BLI_dynstr_appendf(good_args, first ? "%s" : ", %s", RNA_property_identifier(parm));
@@ -5561,9 +5580,8 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject
for (; iter.valid; RNA_parameter_list_next(&iter)) {
parm = iter.parm;
- flag = RNA_property_flag(parm);
- if (flag & PROP_OUTPUT)
+ if (RNA_parameter_flag(parm) & PARM_OUTPUT)
PyTuple_SET_ITEM(ret, i++, pyrna_param_to_py(&funcptr, parm, iter.data));
}
@@ -5683,7 +5701,7 @@ PyTypeObject pyrna_struct_meta_idprop_Type = {
NULL, /* struct PyMethodDef *tp_methods; */
NULL, /* struct PyMemberDef *tp_members; */
NULL, /* struct PyGetSetDef *tp_getset; */
-#if defined(_MSC_VER) || defined(FREE_WINDOWS)
+#if defined(_MSC_VER)
NULL, /* defer assignment */
#else
&PyType_Type, /* struct _typeobject *tp_base; */
@@ -6258,7 +6276,7 @@ static PyTypeObject pyrna_prop_collection_iter_Type = {
NULL, /* reprfunc tp_str; */
/* will only use these if this is a subtype of a py class */
-#if defined(_MSC_VER) || defined(FREE_WINDOWS)
+#if defined(_MSC_VER)
NULL, /* defer assignment */
#else
PyObject_GenericGetAttr, /* getattrofunc tp_getattro; */
@@ -6291,7 +6309,7 @@ static PyTypeObject pyrna_prop_collection_iter_Type = {
#endif
/*** Added in release 2.2 ***/
/* Iterators */
-#if defined(_MSC_VER) || defined(FREE_WINDOWS)
+#if defined(_MSC_VER)
NULL, /* defer assignment */
#else
PyObject_SelfIter, /* getiterfunc tp_iter; */
@@ -6744,7 +6762,7 @@ PyObject *pyrna_id_CreatePyObject(ID *id)
bool pyrna_id_FromPyObject(PyObject *obj, ID **id)
{
- if (BPy_StructRNA_Check(obj) && (RNA_struct_is_ID(((BPy_StructRNA *)obj)->ptr.type))) {
+ if (pyrna_id_CheckPyObject(obj)) {
*id = ((BPy_StructRNA *)obj)->ptr.id.data;
return true;
}
@@ -6754,6 +6772,11 @@ bool pyrna_id_FromPyObject(PyObject *obj, ID **id)
}
}
+bool pyrna_id_CheckPyObject(PyObject *obj)
+{
+ return BPy_StructRNA_Check(obj) && (RNA_struct_is_ID(((BPy_StructRNA *) obj)->ptr.type));
+}
+
void BPY_rna_init(void)
{
#ifdef USE_MATHUTILS /* register mathutils callbacks, ok to run more than once. */
@@ -6762,7 +6785,7 @@ void BPY_rna_init(void)
#endif
/* for some reason MSVC complains of these */
-#if defined(_MSC_VER) || defined(FREE_WINDOWS)
+#if defined(_MSC_VER)
pyrna_struct_meta_idprop_Type.tp_base = &PyType_Type;
pyrna_prop_collection_iter_Type.tp_iter = PyObject_SelfIter;
@@ -6912,7 +6935,7 @@ static PyObject *pyrna_basetype_dir(BPy_BaseTypeRNA *self)
StructRNA *srna = itemptr.data;
StructRNA *srna_base = RNA_struct_base(itemptr.data);
/* skip own operators, these double up [#29666] */
- if (srna_base == &RNA_Operator) {
+ if (ELEM(srna_base, &RNA_Operator, &RNA_Manipulator)) {
/* do nothing */
}
else {
@@ -7088,6 +7111,21 @@ static int deferred_register_prop(StructRNA *srna, PyObject *key, PyObject *item
args_fake = PyTuple_New(1);
PyTuple_SET_ITEM(args_fake, 0, py_srna_cobject);
+ PyObject *type = PyDict_GetItemString(py_kw, "type");
+ StructRNA *type_srna = srna_from_self(type, "");
+ if (type_srna) {
+ if (!RNA_struct_idprops_datablock_allowed(srna) &&
+ (*(PyCFunctionWithKeywords)PyCFunction_GET_FUNCTION(py_func) == BPy_PointerProperty ||
+ *(PyCFunctionWithKeywords)PyCFunction_GET_FUNCTION(py_func) == BPy_CollectionProperty) &&
+ RNA_struct_idprops_contains_datablock(type_srna))
+ {
+ PyErr_Format(PyExc_ValueError,
+ "bpy_struct \"%.200s\" doesn't support datablock properties \n",
+ RNA_struct_identifier(srna));
+ return -1;
+ }
+ }
+
py_ret = PyObject_Call(py_func, args_fake, py_kw);
if (py_ret) {
@@ -7216,8 +7254,8 @@ static int rna_function_arg_count(FunctionRNA *func, int *min_count)
for (link = lb->first; link; link = link->next) {
parm = (PropertyRNA *)link;
- if (!(RNA_property_flag(parm) & PROP_OUTPUT)) {
- if (!done_min_count && (RNA_property_flag(parm) & PROP_PYFUNC_OPTIONAL)) {
+ if (!(RNA_parameter_flag(parm) & PARM_OUTPUT)) {
+ if (!done_min_count && (RNA_parameter_flag(parm) & PARM_PYFUNC_OPTIONAL)) {
/* From now on, following parameters are optional in py func */
if (min_count)
*min_count = count;
@@ -7236,15 +7274,12 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v
{
const ListBase *lb;
Link *link;
- FunctionRNA *func;
- PropertyRNA *prop;
const char *class_type = RNA_struct_identifier(srna);
StructRNA *srna_base = RNA_struct_base(srna);
PyObject *py_class = (PyObject *)py_data;
PyObject *base_class = RNA_struct_py_type_get(srna);
PyObject *item;
- int i, flag, arg_count, func_arg_count, func_arg_min_count = 0;
- bool is_staticmethod;
+ int i, arg_count, func_arg_count, func_arg_min_count = 0;
const char *py_class_name = ((PyTypeObject *)py_class)->tp_name; /* __name__ */
if (srna_base) {
@@ -7265,9 +7300,12 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v
lb = RNA_struct_type_functions(srna);
i = 0;
for (link = lb->first; link; link = link->next) {
- func = (FunctionRNA *)link;
- flag = RNA_function_flag(func);
- is_staticmethod = (flag & FUNC_NO_SELF) && !(flag & FUNC_USE_SELF_TYPE);
+ FunctionRNA *func = (FunctionRNA *)link;
+ const int flag = RNA_function_flag(func);
+ /* TODO(campbell): this is used for classmethod's too,
+ * even though class methods should have 'FUNC_USE_SELF_TYPE' set, see Operator.poll for eg.
+ * Keep this as-is since its working but we should be using 'FUNC_USE_SELF_TYPE' for many functions. */
+ const bool is_staticmethod = (flag & FUNC_NO_SELF) && !(flag & FUNC_USE_SELF_TYPE);
if (!(flag & FUNC_REGISTER))
continue;
@@ -7293,7 +7331,8 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v
if (is_staticmethod) {
if (PyMethod_Check(item) == 0) {
PyErr_Format(PyExc_TypeError,
- "expected %.200s, %.200s class \"%.200s\" attribute to be a method, not a %.200s",
+ "expected %.200s, %.200s class \"%.200s\" "
+ "attribute to be a static/class method, not a %.200s",
class_type, py_class_name, RNA_function_identifier(func), Py_TYPE(item)->tp_name);
return -1;
}
@@ -7302,7 +7341,8 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v
else {
if (PyFunction_Check(item) == 0) {
PyErr_Format(PyExc_TypeError,
- "expected %.200s, %.200s class \"%.200s\" attribute to be a function, not a %.200s",
+ "expected %.200s, %.200s class \"%.200s\" "
+ "attribute to be a function, not a %.200s",
class_type, py_class_name, RNA_function_identifier(func), Py_TYPE(item)->tp_name);
return -1;
}
@@ -7314,7 +7354,7 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v
arg_count = ((PyCodeObject *)PyFunction_GET_CODE(item))->co_argcount;
/* note, the number of args we check for and the number of args we give to
- * @staticmethods are different (quirk of python),
+ * '@staticmethods' are different (quirk of python),
* this is why rna_function_arg_count() doesn't return the value -1*/
if (is_staticmethod) {
func_arg_count++;
@@ -7345,8 +7385,8 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v
lb = RNA_struct_type_properties(srna);
for (link = lb->first; link; link = link->next) {
const char *identifier;
- prop = (PropertyRNA *)link;
- flag = RNA_property_flag(prop);
+ PropertyRNA *prop = (PropertyRNA *)link;
+ const int flag = RNA_property_flag(prop);
if (!(flag & PROP_REGISTER))
continue;
@@ -7425,7 +7465,8 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
PyGILState_STATE gilstate;
#ifdef USE_PEDANTIC_WRITE
- const bool is_operator = 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_Manipulator));
// 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);
@@ -7490,7 +7531,7 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
if (py_class->tp_init) {
#ifdef USE_PEDANTIC_WRITE
const int prev_write = rna_disallow_writes;
- rna_disallow_writes = is_operator ? false : true; /* only operators can write on __init__ */
+ rna_disallow_writes = is_readonly_init ? false : true; /* only operators can write on __init__ */
#endif
/* true in most cases even when the class its self doesn't define an __init__ function. */
@@ -7575,10 +7616,9 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
/* parse function parameters */
for (; iter.valid; RNA_parameter_list_next(&iter)) {
parm = iter.parm;
- flag = RNA_property_flag(parm);
/* only useful for single argument returns, we'll need another list loop for multiple */
- if (flag & PROP_OUTPUT) {
+ if (RNA_parameter_flag(parm) & PARM_OUTPUT) {
ret_len++;
if (pret_single == NULL) {
pret_single = parm;
@@ -7678,10 +7718,9 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
/* parse function parameters */
for (i = 0; iter.valid; RNA_parameter_list_next(&iter)) {
parm = iter.parm;
- flag = RNA_property_flag(parm);
/* only useful for single argument returns, we'll need another list loop for multiple */
- if (flag & PROP_OUTPUT) {
+ if (RNA_parameter_flag(parm) & PARM_OUTPUT) {
err = pyrna_py_to_prop(&funcptr, parm, iter.data,
PyTuple_GET_ITEM(ret, i++),
"calling class function:");
@@ -7967,7 +8006,7 @@ static int pyrna_srna_contains_pointer_prop_srna(
for (link = lb->first; link; link = link->next) {
prop = (PropertyRNA *)link;
- if (RNA_property_type(prop) == PROP_POINTER && !(RNA_property_flag(prop) & PROP_BUILTIN)) {
+ if (RNA_property_type(prop) == PROP_POINTER && !RNA_property_builtin(prop)) {
PointerRNA tptr;
RNA_pointer_create(NULL, &RNA_Struct, srna_props, &tptr);
diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h
index e38d4f095d6..605f79b1ad8 100644
--- a/source/blender/python/intern/bpy_rna.h
+++ b/source/blender/python/intern/bpy_rna.h
@@ -179,6 +179,7 @@ PyObject *pyrna_prop_CreatePyObject(PointerRNA *ptr, PropertyRNA *prop);
/* extern'd by other modules which don't deal closely with RNA */
PyObject *pyrna_id_CreatePyObject(struct ID *id);
bool pyrna_id_FromPyObject(PyObject *obj, struct ID **id);
+bool pyrna_id_CheckPyObject(PyObject *obj);
/* operators also need this to set args */
int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const bool all_args, const char *error_prefix);
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index 92931eb8090..8a0130babd5 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -36,12 +36,15 @@
#include "DNA_scene_types.h"
#include "DNA_anim_types.h"
+
#include "ED_keyframing.h"
+#include "ED_keyframes_edit.h"
#include "BKE_report.h"
#include "BKE_context.h"
#include "BKE_animsys.h"
#include "BKE_fcurve.h"
+#include "BKE_idcode.h"
#include "RNA_access.h"
#include "RNA_enum_types.h"
@@ -223,9 +226,47 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb
{
return NULL;
}
+ else if (self->ptr.type == &RNA_NlaStrip) {
+ /* Handle special properties for NLA Strips, whose F-Curves are stored on the
+ * strips themselves. These are stored separately or else the properties will
+ * not have any effect.
+ */
+ ReportList reports;
+ short result = 0;
+
+ PointerRNA ptr = self->ptr;
+ PropertyRNA *prop = NULL;
+ const char *prop_name;
+
+ BKE_reports_init(&reports, RPT_STORE);
+
+ /* Retrieve the property identifier from the full path, since we can't get it any other way */
+ prop_name = strrchr(path_full, '.');
+ if ((prop_name >= path_full) &&
+ (prop_name + 1 < path_full + strlen(path_full)))
+ {
+ prop = RNA_struct_find_property(&ptr, prop_name + 1);
+ }
+
+ if (prop) {
+ 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);
+ }
+ else {
+ BKE_reportf(&reports, RPT_ERROR, "Could not resolve path (%s)", path_full);
+ }
+ MEM_freeN((void *)path_full);
+
+ if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1)
+ return NULL;
+
+ return PyBool_FromLong(result);
+ }
else {
- short result;
ReportList reports;
+ short result;
BKE_reports_init(&reports, RPT_STORE);
@@ -272,6 +313,67 @@ PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyOb
{
return NULL;
}
+ else if (self->ptr.type == &RNA_NlaStrip) {
+ /* Handle special properties for NLA Strips, whose F-Curves are stored on the
+ * strips themselves. These are stored separately or else the properties will
+ * not have any effect.
+ */
+ ReportList reports;
+ short result = 0;
+
+ PointerRNA ptr = self->ptr;
+ PropertyRNA *prop = NULL;
+ const char *prop_name;
+
+ BKE_reports_init(&reports, RPT_STORE);
+
+ /* Retrieve the property identifier from the full path, since we can't get it any other way */
+ prop_name = strrchr(path_full, '.');
+ if ((prop_name >= path_full) &&
+ (prop_name + 1 < path_full + strlen(path_full)))
+ {
+ prop = RNA_struct_find_property(&ptr, prop_name + 1);
+ }
+
+ if (prop) {
+ ID *id = ptr.id.data;
+ NlaStrip *strip = (NlaStrip *)ptr.data;
+ FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index);
+
+ BLI_assert(fcu != NULL); /* NOTE: This should be true, or else we wouldn't be able to get here */
+
+ if (BKE_fcurve_is_protected(fcu)) {
+ BKE_reportf(&reports, RPT_WARNING,
+ "Not deleting keyframe for locked F-Curve for NLA Strip influence on %s - %s '%s'",
+ strip->name, BKE_idcode_to_name(GS(id->name)), id->name + 2);
+ }
+ else {
+ /* remove the keyframe directly
+ * NOTE: cannot use delete_keyframe_fcurve(), as that will free the curve,
+ * and delete_keyframe() expects the FCurve to be part of an action
+ */
+ bool found = false;
+ int i;
+
+ /* try to find index of beztriple to get rid of */
+ i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found);
+ if (found) {
+ /* delete the key at the index (will sanity check + do recalc afterwards) */
+ delete_fcurve_key(fcu, i, 1);
+ result = true;
+ }
+ }
+ }
+ else {
+ BKE_reportf(&reports, RPT_ERROR, "Could not resolve path (%s)", path_full);
+ }
+ MEM_freeN((void *)path_full);
+
+ if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1)
+ return NULL;
+
+ return PyBool_FromLong(result);
+ }
else {
short result;
ReportList reports;
diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c
index 31189ba4dee..72705ffb3fb 100644
--- a/source/blender/python/intern/bpy_rna_id_collection.c
+++ b/source/blender/python/intern/bpy_rna_id_collection.c
@@ -40,6 +40,9 @@
#include "BKE_library_query.h"
#include "DNA_ID.h"
+/* Those folowing are only to support hack of not listing some internal 'backward' pointers in generated user_map... */
+#include "DNA_object_types.h"
+#include "DNA_key_types.h"
#include "bpy_util.h"
#include "bpy_rna_id_collection.h"
@@ -81,7 +84,7 @@ static bool id_check_type(const ID *id, const BLI_bitmap *types_bitmap)
}
static int foreach_libblock_id_user_map_callback(
- void *user_data, ID *UNUSED(self_id), ID **id_p, int UNUSED(cb_flag))
+ void *user_data, ID *self_id, ID **id_p, int UNUSED(cb_flag))
{
IDUserMapData *data = user_data;
@@ -93,6 +96,15 @@ static int foreach_libblock_id_user_map_callback(
}
}
+ if ((GS(self_id->name) == ID_OB) && (id_p == (ID **)&((Object *)self_id)->proxy_from)) {
+ /* We skip proxy_from here, since it some internal pointer which is not irrelevant info for py/API level. */
+ return IDWALK_RET_NOP;
+ }
+ else if ((GS(self_id->name) == ID_KE) && (id_p == (ID **)&((Key *)self_id)->from)) {
+ /* We skip from here, since it some internal pointer which is not irrelevant info for py/API level. */
+ return IDWALK_RET_NOP;
+ }
+
/* pyrna_struct_hash() uses ptr.data only,
* but pyrna_struct_richcmp() uses also ptr.type,
* so we need to create a valid PointerRNA here...
@@ -233,8 +245,26 @@ static PyObject *bpy_user_map(PyObject *UNUSED(self), PyObject *args, PyObject *
data_cb.py_id_key_lookup_only = pyrna_id_CreatePyObject(id);
}
+ if (!data_cb.is_subset) {
+ PyObject *key = data_cb.py_id_key_lookup_only;
+ PyObject *set;
+
+ RNA_id_pointer_create(id, &((BPy_StructRNA *)key)->ptr);
+
+ /* We have to insert the key now, otherwise ID unused would be missing from final dict... */
+ if ((set = PyDict_GetItem(data_cb.user_map, key)) == NULL) {
+ /* Cannot use our placeholder key here! */
+ key = pyrna_id_CreatePyObject(id);
+ set = PySet_New(NULL);
+ PyDict_SetItem(data_cb.user_map, key, set);
+ Py_DECREF(set);
+ Py_DECREF(key);
+ }
+ }
+
data_cb.id_curr = id;
- BKE_library_foreach_ID_link(id, foreach_libblock_id_user_map_callback, &data_cb, IDWALK_NOP);
+ BKE_library_foreach_ID_link(NULL, id, foreach_libblock_id_user_map_callback, &data_cb, IDWALK_CB_NOP);
+
if (data_cb.py_id_curr) {
Py_DECREF(data_cb.py_id_curr);
data_cb.py_id_curr = NULL;
diff --git a/source/blender/python/intern/bpy_rna_manipulator.c b/source/blender/python/intern/bpy_rna_manipulator.c
new file mode 100644
index 00000000000..d4f9a52db8d
--- /dev/null
+++ b/source/blender/python/intern/bpy_rna_manipulator.c
@@ -0,0 +1,353 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_manipulator.c
+ * \ingroup pythonintern
+ *
+ * .
+ */
+
+#include <Python.h>
+#include <stddef.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_main.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "bpy_util.h"
+#include "bpy_rna_manipulator.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"
+
+enum {
+ BPY_MANIPULATOR_FN_SLOT_GET = 0,
+ BPY_MANIPULATOR_FN_SLOT_SET,
+ BPY_MANIPULATOR_FN_SLOT_RANGE_GET,
+};
+#define BPY_MANIPULATOR_FN_SLOT_LEN (BPY_MANIPULATOR_FN_SLOT_RANGE_GET + 1)
+
+struct BPyManipulatorHandlerUserData {
+
+ PyObject *fn_slots[BPY_MANIPULATOR_FN_SLOT_LEN];
+};
+
+static void py_rna_manipulator_handler_get_cb(
+ const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop,
+ void *value_p)
+{
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
+ struct BPyManipulatorHandlerUserData *data = mpr_prop->custom_func.user_data;
+ PyObject *ret = PyObject_CallObject(data->fn_slots[BPY_MANIPULATOR_FN_SLOT_GET], NULL);
+ if (ret == NULL) {
+ goto fail;
+ }
+
+ if (mpr_prop->type->data_type == PROP_FLOAT) {
+ float *value = value_p;
+ if (mpr_prop->type->array_length == 1) {
+ if (((*value = PyFloat_AsDouble(ret)) == -1.0f && PyErr_Occurred()) == 0) {
+ goto fail;
+ }
+ }
+ else {
+ if (PyC_AsArray(value, ret, mpr_prop->type->array_length, &PyFloat_Type, false,
+ "Manipulator 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_manipulator_handler_set_cb(
+ const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop,
+ const void *value_p)
+{
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
+ struct BPyManipulatorHandlerUserData *data = mpr_prop->custom_func.user_data;
+
+ PyObject *args = PyTuple_New(1);
+
+ if (mpr_prop->type->data_type == PROP_FLOAT) {
+ const float *value = value_p;
+ PyObject *py_value;
+ if (mpr_prop->type->array_length == 1) {
+ py_value = PyFloat_FromDouble(*value);
+ }
+ else {
+ py_value = PyC_FromArray((void *)value, mpr_prop->type->array_length, &PyFloat_Type, false,
+ "Manipulator set callback: ");
+ }
+ 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_MANIPULATOR_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_manipulator_handler_range_get_cb(
+ const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop,
+ void *value_p)
+{
+ struct BPyManipulatorHandlerUserData *data = mpr_prop->custom_func.user_data;
+
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
+ PyObject *ret = PyObject_CallObject(data->fn_slots[BPY_MANIPULATOR_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 (mpr_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_manipulator_handler_free_cb(
+ const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop)
+{
+ struct BPyManipulatorHandlerUserData *data = mpr_prop->custom_func.user_data;
+
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ for (int i = 0; i < BPY_MANIPULATOR_FN_SLOT_LEN; i++) {
+ Py_XDECREF(data->fn_slots[i]);
+ }
+ PyGILState_Release(gilstate);
+
+ MEM_freeN(data);
+
+}
+
+PyDoc_STRVAR(bpy_manipulator_target_set_handler_doc,
+".. method:: target_set_handler(target, get, set, range=None):\n"
+"\n"
+" Assigns callbacks to a manipulators 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 manipulators that use a range.\n"
+" :type range: callable\n"
+);
+static PyObject *bpy_manipulator_target_set_handler(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
+{
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
+ struct {
+ PyObject *self;
+ char *target;
+ PyObject *py_fn_slots[BPY_MANIPULATOR_FN_SLOT_LEN];
+ } params = {
+ .self = NULL,
+ .target = NULL,
+ .py_fn_slots = {NULL},
+ };
+
+ /* Note: this is a counter-part to functions:
+ * 'Manipulator.target_set_prop & target_set_operator'
+ * (see: rna_wm_manipulator_api.c). conventions should match. */
+ static const char * const _keywords[] = {"self", "target", "get", "set", "range", NULL};
+#define KW_FMT "Os|$OOO:target_set_handler"
+#if PY_VERSION_HEX >= 0x03070000
+ static _PyArg_Parser _parser = {KW_FMT, _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kwds,
+ &_parser,
+ &params.self,
+ &params.target,
+ &params.py_fn_slots[BPY_MANIPULATOR_FN_SLOT_GET],
+ &params.py_fn_slots[BPY_MANIPULATOR_FN_SLOT_SET],
+ &params.py_fn_slots[BPY_MANIPULATOR_FN_SLOT_RANGE_GET]))
+#else
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwds,
+ KW_FMT, (char **)_keywords,
+ &params.self,
+ &params.target,
+ &params.py_fn_slots[BPY_MANIPULATOR_FN_SLOT_GET],
+ &params.py_fn_slots[BPY_MANIPULATOR_FN_SLOT_SET],
+ &params.py_fn_slots[BPY_MANIPULATOR_FN_SLOT_RANGE_GET]))
+#endif
+ {
+ goto fail;
+ }
+#undef KW_FMT
+
+ wmManipulator *mpr = ((BPy_StructRNA *)params.self)->ptr.data;
+
+ const wmManipulatorPropertyType *mpr_prop_type =
+ WM_manipulatortype_target_property_find(mpr->type, params.target);
+ if (mpr_prop_type == NULL) {
+ PyErr_Format(PyExc_ValueError,
+ "Manipulator target property '%s.%s' not found",
+ mpr->type->idname, params.target);
+ goto fail;
+ }
+
+ {
+ const int slots_required = 2;
+ const int slots_start = 2;
+ for (int i = 0; i < BPY_MANIPULATOR_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 BPyManipulatorHandlerUserData *data = MEM_callocN(sizeof(*data), __func__);
+
+ for (int i = 0; i < BPY_MANIPULATOR_FN_SLOT_LEN; i++) {
+ data->fn_slots[i] = params.py_fn_slots[i];
+ Py_XINCREF(params.py_fn_slots[i]);
+ }
+
+ WM_manipulator_target_property_def_func_ptr(
+ mpr, mpr_prop_type,
+ &(const struct wmManipulatorPropertyFnParams) {
+ .value_get_fn = py_rna_manipulator_handler_get_cb,
+ .value_set_fn = py_rna_manipulator_handler_set_cb,
+ .range_get_fn = py_rna_manipulator_handler_range_get_cb,
+ .free_fn = py_rna_manipulator_handler_free_cb,
+ .user_data = data,
+ });
+
+ PyGILState_Release(gilstate);
+
+ Py_RETURN_NONE;
+
+fail:
+ PyGILState_Release(gilstate);
+ return NULL;
+}
+
+int BPY_rna_manipulator_module(PyObject *mod_par)
+{
+ static PyMethodDef method_def = {
+ "target_set_handler", (PyCFunction)bpy_manipulator_target_set_handler, METH_VARARGS | METH_KEYWORDS,
+ bpy_manipulator_target_set_handler_doc};
+
+ PyObject *func = PyCFunction_New(&method_def, NULL);
+ PyObject *func_inst = PyInstanceMethod_New(func);
+
+
+ /* TODO, return a type that binds nearly to a method. */
+ PyModule_AddObject(mod_par, "_rna_manipulator_target_set_handler", func_inst);
+
+ return 0;
+}
+
+
diff --git a/source/blender/python/intern/bpy_rna_manipulator.h b/source/blender/python/intern/bpy_rna_manipulator.h
new file mode 100644
index 00000000000..b6f3a2e651d
--- /dev/null
+++ b/source/blender/python/intern/bpy_rna_manipulator.h
@@ -0,0 +1,32 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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): Bastien Montagne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_rna_manipulator.h
+ * \ingroup pythonintern
+ */
+
+#ifndef __BPY_RNA_MANIPULATOR_H__
+#define __BPY_RNA_MANIPULATOR_H__
+
+int BPY_rna_manipulator_module(PyObject *);
+
+#endif /* __BPY_RNA_MANIPULATOR_H__ */
diff --git a/source/blender/python/intern/bpy_utils_units.c b/source/blender/python/intern/bpy_utils_units.c
index 974d7c5549c..e0c70483e3c 100644
--- a/source/blender/python/intern/bpy_utils_units.c
+++ b/source/blender/python/intern/bpy_utils_units.c
@@ -201,7 +201,7 @@ static PyObject *bpyunits_to_value(PyObject *UNUSED(self), PyObject *args, PyObj
bUnit_ReplaceString(str, (int)str_len, uref, scale, usys, ucat);
- if (!PyC_RunString_AsNumber(str, &result, "<bpy_units_api>")) {
+ if (!PyC_RunString_AsNumber(str, "<bpy_units_api>", &result)) {
if (PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
diff --git a/source/blender/python/intern/gpu.c b/source/blender/python/intern/gpu.c
index 50dd4618166..48230a723d2 100644
--- a/source/blender/python/intern/gpu.c
+++ b/source/blender/python/intern/gpu.c
@@ -138,6 +138,7 @@ static PyObject *PyInit_gpu(void)
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);
/* -------------------------------------------------------------------- */
diff --git a/source/blender/python/intern/gpu_offscreen.c b/source/blender/python/intern/gpu_offscreen.c
index c4863b2a92f..c7350ad2e3f 100644
--- a/source/blender/python/intern/gpu_offscreen.c
+++ b/source/blender/python/intern/gpu_offscreen.c
@@ -192,26 +192,28 @@ PyDoc_STRVAR(pygpu_offscreen_draw_view3d_doc,
);
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};
+ static const char *kwlist[] = {"scene", "render_layer", "view3d", "region", "projection_matrix", "modelview_matrix", NULL};
MatrixObject *py_mat_modelview, *py_mat_projection;
- PyObject *py_scene, *py_region, *py_view3d;
+ PyObject *py_scene, *py_scene_layer, *py_region, *py_view3d;
Scene *scene;
+ SceneLayer *sl;
View3D *v3d;
ARegion *ar;
GPUFX *fx;
GPUFXSettings fx_settings;
- void *rv3d_mats;
+ 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,
+ args, kwds, "OOOOO&O&:draw_view3d", (char **)(kwlist),
+ &py_scene, &py_scene_layer, &py_view3d, &py_region,
pygpu_offscreen_check_matrix, &py_mat_projection,
pygpu_offscreen_check_matrix, &py_mat_modelview) ||
(!(scene = PyC_RNA_AsPointer(py_scene, "Scene")) ||
+ !(sl = PyC_RNA_AsPointer(py_scene_layer, "SceneLayer")) ||
!(v3d = PyC_RNA_AsPointer(py_view3d, "SpaceView3D")) ||
!(ar = PyC_RNA_AsPointer(py_region, "Region"))))
{
@@ -222,14 +224,14 @@ static PyObject *pygpu_offscreen_draw_view3d(BPy_GPUOffScreen *self, PyObject *a
fx_settings = v3d->fx_settings; /* full copy */
- ED_view3d_draw_offscreen_init(scene, v3d);
+ ED_view3d_draw_offscreen_init(scene, sl, v3d);
rv3d_mats = ED_view3d_mats_rv3d_backup(ar->regiondata);
GPU_offscreen_bind(self->ofs, true); /* bind */
ED_view3d_draw_offscreen(
- scene, v3d, ar, GPU_offscreen_width(self->ofs), GPU_offscreen_height(self->ofs),
+ scene, sl, 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,
diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c
index 5c505247a97..1afb1d7be90 100644
--- a/source/blender/python/mathutils/mathutils.c
+++ b/source/blender/python/mathutils/mathutils.c
@@ -1,4 +1,4 @@
-/*
+/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
@@ -38,18 +38,31 @@
#endif
PyDoc_STRVAR(M_Mathutils_doc,
-"This module provides access to the math classes:\n"
+"This module provides access to math operations.\n"
+"\n"
+".. note::\n"
+"\n"
+" Classes, methods and attributes that accept vectors also accept other numeric sequences,\n"
+" such as tuples, lists."
+"\n\n"
+"Submodules:\n"
+"\n"
+".. toctree::\n"
+" :maxdepth: 1\n"
+"\n"
+" mathutils.geometry.rst\n"
+" mathutils.bvhtree.rst\n"
+" mathutils.kdtree.rst\n"
+" mathutils.interpolate.rst\n"
+" mathutils.noise.rst\n"
+"\n"
+"The :mod:`mathutils` module provides the following classes:\n"
"\n"
"- :class:`Color`,\n"
"- :class:`Euler`,\n"
"- :class:`Matrix`,\n"
"- :class:`Quaternion`,\n"
"- :class:`Vector`,\n"
-"\n"
-".. note::\n"
-"\n"
-" Classes, methods and attributes that accept vectors also accept other numeric sequences,\n"
-" such as tuples, lists."
);
static int mathutils_array_parse_fast(float *array,
int size,
@@ -219,7 +232,7 @@ int mathutils_array_parse_alloc(float **array, int array_min, PyObject *value, c
error_prefix, size, array_min);
return -1;
}
-
+
*array = PyMem_Malloc(size * sizeof(float));
memcpy(*array, ((BaseMathObject *)value)->data, size * sizeof(float));
return size;
@@ -422,7 +435,7 @@ static Mathutils_Callback *mathutils_callbacks[MATHUTILS_TOT_CB] = {NULL};
unsigned char Mathutils_RegisterCallback(Mathutils_Callback *cb)
{
unsigned char i;
-
+
/* find the first free slot */
for (i = 0; mathutils_callbacks[i]; i++) {
if (mathutils_callbacks[i] == cb) /* already registered? */
@@ -625,14 +638,14 @@ PyMODINIT_FUNC PyInit_mathutils(void)
return NULL;
mod = PyModule_Create(&M_Mathutils_module_def);
-
+
/* each type has its own new() function */
PyModule_AddObject(mod, vector_Type.tp_name, (PyObject *)&vector_Type);
PyModule_AddObject(mod, matrix_Type.tp_name, (PyObject *)&matrix_Type);
PyModule_AddObject(mod, euler_Type.tp_name, (PyObject *)&euler_Type);
PyModule_AddObject(mod, quaternion_Type.tp_name, (PyObject *)&quaternion_Type);
PyModule_AddObject(mod, color_Type.tp_name, (PyObject *)&color_Type);
-
+
/* submodule */
PyModule_AddObject(mod, "geometry", (submodule = PyInit_mathutils_geometry()));
/* XXX, python doesnt do imports with this usefully yet
diff --git a/source/blender/python/mathutils/mathutils_Color.c b/source/blender/python/mathutils/mathutils_Color.c
index add8c2451ff..9997cd9c1f5 100644
--- a/source/blender/python/mathutils/mathutils_Color.c
+++ b/source/blender/python/mathutils/mathutils_Color.c
@@ -173,7 +173,7 @@ static PyObject *Color_richcmpr(PyObject *a, PyObject *b, int op)
switch (op) {
case Py_NE:
ok = !ok;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case Py_EQ:
res = ok ? Py_False : Py_True;
break;
diff --git a/source/blender/python/mathutils/mathutils_Euler.c b/source/blender/python/mathutils/mathutils_Euler.c
index 54adc826af7..9492b6d67f3 100644
--- a/source/blender/python/mathutils/mathutils_Euler.c
+++ b/source/blender/python/mathutils/mathutils_Euler.c
@@ -65,7 +65,7 @@ static PyObject *Euler_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
case 2:
if ((order = euler_order_from_string(order_str, "mathutils.Euler()")) == -1)
return NULL;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case 1:
if (mathutils_array_parse(eul, EULER_SIZE, EULER_SIZE, seq, "mathutils.Euler()") == -1)
return NULL;
@@ -370,7 +370,7 @@ static PyObject *Euler_richcmpr(PyObject *a, PyObject *b, int op)
switch (op) {
case Py_NE:
ok = !ok;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case Py_EQ:
res = ok ? Py_False : Py_True;
break;
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index 71288871104..e368e8871f3 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -1301,7 +1301,7 @@ PyDoc_STRVAR(Matrix_to_scale_doc,
" :return: Return the scale of a matrix.\n"
" :rtype: :class:`Vector`\n"
"\n"
-" .. note:: This method does not return negative a scale on any axis because it is not possible to obtain this data from the matrix alone.\n"
+" .. note:: This method does not return a negative scale on any axis because it is not possible to obtain this data from the matrix alone.\n"
);
static PyObject *Matrix_to_scale(MatrixObject *self)
{
@@ -1390,11 +1390,11 @@ PyDoc_STRVAR(Matrix_invert_doc,
"\n"
" Set the matrix to its inverse.\n"
"\n"
-" :arg fallback: Set the matrix to this value when the inverse can't be calculated\n"
+" :arg fallback: Set the matrix to this value when the inverse cannot be calculated\n"
" (instead of raising a :exc:`ValueError` exception).\n"
" :type fallback: :class:`Matrix`\n"
"\n"
-" .. seealso:: <http://en.wikipedia.org/wiki/Inverse_matrix>\n"
+" .. seealso:: `Inverse matrix <https://en.wikipedia.org/wiki/Inverse_matrix>` on Wikipedia.\n"
);
static PyObject *Matrix_invert(MatrixObject *self, PyObject *args)
{
@@ -1505,7 +1505,7 @@ PyDoc_STRVAR(Matrix_invert_safe_doc,
" If degenerated (e.g. zero scale on an axis), add some epsilon to its diagonal, to get an invertible one.\n"
" If tweaked matrix is still degenerated, set to the identity matrix instead.\n"
"\n"
-" .. seealso:: <http://en.wikipedia.org/wiki/Inverse_matrix>\n"
+" .. seealso:: `Inverse Matrix <https://en.wikipedia.org/wiki/Inverse_matrix>` on Wikipedia.\n"
);
static PyObject *Matrix_invert_safe(MatrixObject *self)
{
@@ -1554,9 +1554,9 @@ PyDoc_STRVAR(Matrix_adjugate_doc,
"\n"
" Set the matrix to its adjugate.\n"
"\n"
-" .. note:: When the matrix cant be adjugated a :exc:`ValueError` exception is raised.\n"
+" .. note:: When the matrix cannot be adjugated a :exc:`ValueError` exception is raised.\n"
"\n"
-" .. seealso:: <http://en.wikipedia.org/wiki/Adjugate_matrix>\n"
+" .. seealso:: `Adjugate matrix <https://en.wikipedia.org/wiki/Adjugate_matrix>` on Wikipedia.\n"
);
static PyObject *Matrix_adjugate(MatrixObject *self)
{
@@ -1641,9 +1641,9 @@ static PyObject *Matrix_rotate(MatrixObject *self, PyObject *value)
PyDoc_STRVAR(Matrix_decompose_doc,
".. method:: decompose()\n"
"\n"
-" Return the location, rotation and scale components of this matrix.\n"
+" Return the translation, rotation and scale components of this matrix.\n"
"\n"
-" :return: loc, rot, scale triple.\n"
+" :return: trans, rot, scale triple.\n"
" :rtype: (:class:`Vector`, :class:`Quaternion`, :class:`Vector`)"
);
static PyObject *Matrix_decompose(MatrixObject *self)
@@ -1709,10 +1709,10 @@ static PyObject *Matrix_lerp(MatrixObject *self, PyObject *args)
/* TODO, different sized matrix */
if (self->num_col == 4 && self->num_row == 4) {
- blend_m4_m4m4((float (*)[4])mat, (float (*)[4])self->matrix, (float (*)[4])mat2->matrix, fac);
+ interp_m4_m4m4((float (*)[4])mat, (float (*)[4])self->matrix, (float (*)[4])mat2->matrix, fac);
}
else if (self->num_col == 3 && self->num_row == 3) {
- blend_m3_m3m3((float (*)[3])mat, (float (*)[3])self->matrix, (float (*)[3])mat2->matrix, fac);
+ interp_m3_m3m3((float (*)[3])mat, (float (*)[3])self->matrix, (float (*)[3])mat2->matrix, fac);
}
else {
PyErr_SetString(PyExc_ValueError,
@@ -1733,7 +1733,7 @@ PyDoc_STRVAR(Matrix_determinant_doc,
" :return: Return the determinant of a matrix.\n"
" :rtype: float\n"
"\n"
-" .. seealso:: <http://en.wikipedia.org/wiki/Determinant>\n"
+" .. seealso:: `Determinant <https://en.wikipedia.org/wiki/Determinant>` on Wikipedia.\n"
);
static PyObject *Matrix_determinant(MatrixObject *self)
{
@@ -1755,7 +1755,7 @@ PyDoc_STRVAR(Matrix_transpose_doc,
"\n"
" Set the matrix to its transpose.\n"
"\n"
-" .. seealso:: <http://en.wikipedia.org/wiki/Transpose>\n"
+" .. seealso:: `Transpose <https://en.wikipedia.org/wiki/Transpose>` on Wikipedia.\n"
);
static PyObject *Matrix_transpose(MatrixObject *self)
{
@@ -1887,10 +1887,10 @@ PyDoc_STRVAR(Matrix_identity_doc,
"\n"
" Set the matrix to the identity matrix.\n"
"\n"
-" .. note:: An object with zero location and rotation, a scale of one,\n"
+" .. note:: An object with a location and rotation of zero, and a scale of one\n"
" will have an identity matrix.\n"
"\n"
-" .. seealso:: <http://en.wikipedia.org/wiki/Identity_matrix>\n"
+" .. seealso:: `Identity matrix <https://en.wikipedia.org/wiki/Identity_matrix>` on Wikipedia.\n"
);
static PyObject *Matrix_identity(MatrixObject *self)
{
@@ -2034,7 +2034,7 @@ static PyObject *Matrix_richcmpr(PyObject *a, PyObject *b, int op)
switch (op) {
case Py_NE:
ok = !ok;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case Py_EQ:
res = ok ? Py_False : Py_True;
break;
diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c
index 71b3cf8ddac..d283c717a46 100644
--- a/source/blender/python/mathutils/mathutils_Quaternion.c
+++ b/source/blender/python/mathutils/mathutils_Quaternion.c
@@ -552,7 +552,7 @@ static PyObject *Quaternion_richcmpr(PyObject *a, PyObject *b, int op)
switch (op) {
case Py_NE:
ok = !ok;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case Py_EQ:
res = ok ? Py_False : Py_True;
break;
diff --git a/source/blender/python/mathutils/mathutils_bvhtree.c b/source/blender/python/mathutils/mathutils_bvhtree.c
index ff1761eb6d7..1eb8644a9a6 100644
--- a/source/blender/python/mathutils/mathutils_bvhtree.c
+++ b/source/blender/python/mathutils/mathutils_bvhtree.c
@@ -817,13 +817,14 @@ static PyObject *C_BVHTree_FromPolygons(PyObject *UNUSED(cls), PyObject *args, P
PyErr_Format(PyExc_ValueError,
"%s: index %d must be less than %d",
error_prefix, plink->poly[j], coords_len);
-
- Py_DECREF(py_tricoords_fast);
+ /* decref below */
valid = false;
break;
}
}
+ Py_DECREF(py_tricoords_fast);
+
if (py_tricoords_len >= 3) {
tris_len += (py_tricoords_len - 2);
}
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt
index 9e40ab02ee4..282942709f0 100644
--- a/source/blender/render/CMakeLists.txt
+++ b/source/blender/render/CMakeLists.txt
@@ -34,7 +34,10 @@ set(INC
../depsgraph
../makesdna
../makesrna
+ ../nodes
../physics
+ ../draw
+ ../../../intern/atomic
../../../intern/guardedalloc
../../../intern/mikktspace
../../../intern/smoke/extern
@@ -164,10 +167,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
-if(WITH_CYCLES AND WITH_CYCLES_DEBUG)
- add_definitions(-DWITH_CYCLES_DEBUG)
-endif()
-
if(APPLE)
# SSE math is enabled by default on x86_64
if(CMAKE_OSX_ARCHITECTURES MATCHES "i386")
diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h
index f83a210275f..3086c9d4fad 100644
--- a/source/blender/render/extern/include/RE_engine.h
+++ b/source/blender/render/extern/include/RE_engine.h
@@ -39,6 +39,9 @@
struct bNode;
struct bNodeTree;
+struct Depsgraph;
+struct IDProperty;
+struct Main;
struct Object;
struct Render;
struct RenderData;
@@ -63,6 +66,7 @@ struct BakePixel;
#define RE_USE_TEXTURE_PREVIEW 128
#define RE_USE_SHADING_NODES_CUSTOM 256
#define RE_USE_SPHERICAL_STEREO 512
+#define RE_USE_LEGACY_PIPELINE 1024 /* XXX Temporary flag, to be removed once draw manager is finished. */
/* RenderEngine.flag */
#define RE_ENGINE_ANIMATION 1
@@ -88,14 +92,22 @@ 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, struct Scene *scene);
+ void (*render_to_image)(struct RenderEngine *engine, struct Depsgraph *depsgraph);
+ 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 (*view_update)(struct RenderEngine *engine, const struct bContext *context);
- void (*view_draw)(struct RenderEngine *engine, const struct bContext *context);
+ void (*render_to_view)(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 (*collection_settings_create)(struct RenderEngine *engine, struct IDProperty *props);
+ void (*render_settings_create)(struct RenderEngine *engine, struct IDProperty *props);
+
+ struct DrawEngineType *draw_engine;
/* RNA integration */
ExtensionRNA ext;
@@ -139,7 +151,8 @@ void RE_result_load_from_file(struct RenderResult *result, struct ReportList *re
struct RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername, const char *viewname);
void RE_engine_update_result(RenderEngine *engine, struct RenderResult *result);
-void RE_engine_end_result(RenderEngine *engine, struct RenderResult *result, int cancel, int merge_results);
+void RE_engine_add_pass(RenderEngine *engine, const char *name, int channels, const char *chan_id, const char *layername);
+void RE_engine_end_result(RenderEngine *engine, struct RenderResult *result, int cancel, int highlight, int merge_results);
const char *RE_engine_active_view_get(RenderEngine *engine);
void RE_engine_active_view_set(RenderEngine *engine, const char *viewname);
@@ -160,16 +173,21 @@ 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,
+ 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(struct Main *bmain, 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 Depsgraph *graph, struct Scene *scene);
#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 c1c5fc4a04d..901c1c1d05d 100644
--- a/source/blender/render/extern/include/RE_multires_bake.h
+++ b/source/blender/render/extern/include/RE_multires_bake.h
@@ -43,6 +43,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 509ad6f3515..145186548e6 100644
--- a/source/blender/render/extern/include/RE_pipeline.h
+++ b/source/blender/render/extern/include/RE_pipeline.h
@@ -37,6 +37,7 @@
struct bMovieHandle;
struct bNodeTree;
+struct Depsgraph;
struct Image;
struct ImageFormatData;
struct Main;
@@ -48,7 +49,6 @@ struct ReportList;
struct Scene;
struct SceneRenderLayer;
struct EnvMap;
-struct RenderResult;
struct StampData;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
@@ -84,24 +84,19 @@ typedef struct RenderView {
typedef struct RenderPass {
struct RenderPass *next, *prev;
- int passtype, channels;
+ int channels;
char name[64]; /* amount defined in openexr_multi.h */
char chan_id[8]; /* amount defined in openexr_multi.h */
float *rect;
int rectx, recty;
- char internal_name[64]; /* EXR_PASS_MAXNAME */
+ char fullname[64]; /* EXR_PASS_MAXNAME */
char view[64]; /* EXR_VIEW_MAXNAME */
int view_id; /* quick lookup */
- int debug_type;
+ int pad;
} RenderPass;
-enum {
- RENDER_PASS_DEBUG_BVH_TRAVERSAL_STEPS = 0,
- RENDER_PASS_DEBUG_BVH_TRAVERSED_INSTANCES = 1,
- RENDER_PASS_DEBUG_RAY_BOUNCES = 2,
-};
/* a renderlayer is a full image, but with all passes and samples */
/* size of the rects is defined in RenderResult */
@@ -236,7 +231,7 @@ void RE_render_result_rect_from_ibuf(
struct ImBuf *ibuf, const int view_id);
struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name);
-float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, int passtype, const char *viewname);
+float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, const char *name, const char *viewname);
/* add passes for grease pencil */
struct RenderPass *RE_create_gp_pass(struct RenderResult *rr, const char *layername, const char *viewname);
@@ -252,6 +247,7 @@ 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_SetDepsgraph(struct Render *re, struct Depsgraph *graph);
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);
@@ -345,6 +341,7 @@ int RE_seq_render_active(struct Scene *scene, struct RenderData *rd);
bool RE_layers_have_name(struct RenderResult *result);
+struct RenderPass *RE_pass_find_by_name(volatile struct RenderLayer *rl, const char *name, const char *viewname);
struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl, int passtype, const char *viewname);
/* shaded view or baking options */
@@ -381,7 +378,7 @@ 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),
+ RE_OBJECT_INSTANCES_UPDATE_OBMAT = (1 << 1)
};
void RE_updateRenderInstances(Render *re, int flag);
@@ -392,13 +389,7 @@ bool RE_RenderResult_is_stereo(RenderResult *res);
struct RenderView *RE_RenderViewGetById(struct RenderResult *res, const int view_id);
struct RenderView *RE_RenderViewGetByName(struct RenderResult *res, const char *viewname);
-/******* Debug pass helper functions *********/
-
-#ifdef WITH_CYCLES_DEBUG
-int RE_debug_pass_num_channels_get(int pass_type);
-const char *RE_debug_pass_name_get(int pass_type);
-int RE_debug_pass_type_get(struct Render *re);
-#endif
+RenderResult *RE_DuplicateRenderResult(RenderResult *rr);
#endif /* __RE_PIPELINE_H__ */
diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h
index 73867de6b2e..b64c0c8fc52 100644
--- a/source/blender/render/extern/include/RE_shader_ext.h
+++ b/source/blender/render/extern/include/RE_shader_ext.h
@@ -178,6 +178,7 @@ typedef struct ShadeInput {
unsigned int lay;
int layflag, passflag, combinedflag;
+ short object_pass_index;
struct Group *light_override;
struct Material *mat_override;
@@ -218,6 +219,8 @@ int multitex_nodes(struct Tex *tex, float texvec[3], float dxt[3], float dyt[3],
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 *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;
@@ -239,6 +242,9 @@ enum {
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,
diff --git a/source/blender/render/intern/include/render_result.h b/source/blender/render/intern/include/render_result.h
index 0c4f4e20325..4057d8c1052 100644
--- a/source/blender/render/intern/include/render_result.h
+++ b/source/blender/render/intern/include/render_result.h
@@ -67,6 +67,11 @@ void render_result_views_new(struct RenderResult *rr, struct RenderData *rd);
void render_result_merge(struct RenderResult *rr, struct RenderResult *rrpart);
+/* Add Passes */
+
+void render_result_clone_passes(struct Render *re, struct RenderResult *rr, const char *viewname);
+void render_result_add_pass(struct RenderResult *rr, const char *name, int channels, const char *chan_id, const char *layername, const char *viewname);
+
/* Free */
void render_result_free(struct RenderResult *rr);
@@ -84,7 +89,7 @@ void render_result_exr_file_begin(struct Render *re);
void render_result_exr_file_end(struct Render *re);
/* render pass wrapper for gpencil */
-struct RenderPass *gp_add_pass(struct RenderResult *rr, struct RenderLayer *rl, int channels, int passtype, const char *viewname);
+struct RenderPass *gp_add_pass(struct RenderResult *rr, struct RenderLayer *rl, int channels, const char *name, const char *viewname);
void render_result_exr_file_merge(struct RenderResult *rr, struct RenderResult *rrpart, const char *viewname);
diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h
index b3a5ccdae17..1de1f23f351 100644
--- a/source/blender/render/intern/include/render_types.h
+++ b/source/blender/render/intern/include/render_types.h
@@ -185,6 +185,8 @@ struct Render {
/* shadow counter, detect shadow-reuse for shaders */
int shadowsamplenr[BLENDER_MAX_THREADS];
+ struct Depsgraph *depsgraph;
+
/* main, scene, and its full copy of renderdata and world */
struct Main *main;
Scene *scene;
@@ -335,7 +337,7 @@ typedef struct ObjectRen {
char (*mcol)[MAX_CUSTOMDATA_LAYER_NAME];
int actmtface, actmcol, bakemtface;
- char tangent_mask; /* which tangent layer should be calculated */
+ short tangent_mask; /* which tangent layer should be calculated */
float obmat[4][4]; /* only used in convertblender.c, for instancing */
@@ -382,6 +384,8 @@ typedef struct ObjectInstanceRen {
float part_co[3];
float part_vel[3];
float part_avel[3];
+
+ unsigned int random_id;
} ObjectInstanceRen;
/* ------------------------------------------------------------------------- */
diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h
index 7254fd25ee6..f4c4a50ac27 100644
--- a/source/blender/render/intern/include/rendercore.h
+++ b/source/blender/render/intern/include/rendercore.h
@@ -34,6 +34,12 @@
#include "render_types.h"
+#include "RE_engine.h"
+
+#include "DNA_node_types.h"
+
+#include "NOD_composite.h"
+
struct ShadeInput;
struct ShadeResult;
struct World;
@@ -77,6 +83,8 @@ 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 ------- */
diff --git a/source/blender/render/intern/include/shading.h b/source/blender/render/intern/include/shading.h
index 27867eadbb4..13f16ce0bd7 100644
--- a/source/blender/render/intern/include/shading.h
+++ b/source/blender/render/intern/include/shading.h
@@ -99,7 +99,7 @@ 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);
+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/raytrace/rayobject.cpp b/source/blender/render/intern/raytrace/rayobject.cpp
index 2104315dc00..c16ef5500df 100644
--- a/source/blender/render/intern/raytrace/rayobject.cpp
+++ b/source/blender/render/intern/raytrace/rayobject.cpp
@@ -138,16 +138,81 @@ MALWAYS_INLINE int vlr_check_bake(Isect *is, ObjectInstanceRen *obi, VlakRen *UN
/* Ray Triangle/Quad Intersection */
-MALWAYS_INLINE int isec_tri_quad(float start[3], const struct IsectRayPrecalc *isect_precalc, RayFace *face, float r_uv[2], float *lambda)
+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 < *lambda) {
+ if (l > -RE_RAYTRACE_EPSILON && l < *r_lambda) {
r_uv[0] = -uv[0];
r_uv[1] = -uv[1];
- *lambda = l;
+ *r_lambda = l;
return 1;
}
}
@@ -156,10 +221,10 @@ MALWAYS_INLINE int isec_tri_quad(float start[3], const struct IsectRayPrecalc *i
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 < *lambda) {
+ if (l > -RE_RAYTRACE_EPSILON && l < *r_lambda) {
r_uv[0] = -uv[0];
r_uv[1] = -uv[1];
- *lambda = l;
+ *r_lambda = l;
return 2;
}
}
@@ -170,24 +235,25 @@ MALWAYS_INLINE int isec_tri_quad(float start[3], const struct IsectRayPrecalc *i
/* Simpler yes/no Ray Triangle/Quad Intersection */
-MALWAYS_INLINE int isec_tri_quad_neighbour(float start[3], float dir[3], RayFace *face)
+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_v3(start, &isect_precalc, face->v1, face->v2, face->v3, &l, uv)) {
+ 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_v3(start, &isect_precalc, face->v1, face->v3, face->v4, &l, uv)) {
+ if (isect_ray_tri_watertight_no_sign_check_v3(start, &isect_precalc, face->v1, face->v3, face->v4, &l, uv)) {
return 2;
}
}
diff --git a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
index 724a809077e..81e41a20f2e 100644
--- a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
+++ b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
@@ -31,10 +31,16 @@
#include <assert.h>
-#include <math.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"
@@ -42,10 +48,6 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#if __cplusplus >= 201103L
-using std::isfinite;
-#endif
-
static bool selected_node(RTBuilder::Object *node)
{
return node->selected;
diff --git a/source/blender/render/intern/source/bake.c b/source/blender/render/intern/source/bake.c
index 31e461b4536..71a595d6a8b 100644
--- a/source/blender/render/intern/source/bake.c
+++ b/source/blender/render/intern/source/bake.c
@@ -669,11 +669,12 @@ static int get_next_bake_face(BakeShade *bs)
const float disp_solid[4] = {0.5f, 0.5f, 0.5f, 1.0f};
tface = RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0);
+ /* should use 'BKE_object_material_edit_image_get' but in this case simpler not to */
+ ima = vlr->mat ? vlr->mat->edit_image : NULL;
- if (!tface || !tface->tpage)
+ if (!tface || !ima)
continue;
- ima = tface->tpage;
ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
if (ibuf == NULL)
@@ -814,7 +815,7 @@ static void shade_tface(BakeShade *bs)
ObjectInstanceRen *obi = bs->obi;
ObjectRen *obr = obi->obr;
MTFace *tface = RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0);
- Image *ima = tface->tpage;
+ Image *ima = vlr->mat->edit_image;
float vec[4][2];
int a, i1, i2, i3;
diff --git a/source/blender/render/intern/source/bake_api.c b/source/blender/render/intern/source/bake_api.c
index 1a0ef4e64d4..588c327ab91 100644
--- a/source/blender/render/intern/source/bake_api.c
+++ b/source/blender/render/intern/source/bake_api.c
@@ -298,20 +298,16 @@ static bool cast_ray_highpoly(
}
if (hits[i].index != -1) {
- /* cull backface */
- const float dot = dot_v3v3(dir_high, hits[i].no);
- if (dot < 0.0f) {
- float distance;
- float hit_world[3];
-
- /* distance comparison in world space */
- mul_v3_m4v3(hit_world, highpoly[i].obmat, hits[i].co);
- distance = len_squared_v3v3(hit_world, co);
-
- if (distance < hit_distance) {
- hit_mesh = i;
- hit_distance = distance;
- }
+ float distance;
+ float hit_world[3];
+
+ /* distance comparison in world space */
+ mul_v3_m4v3(hit_world, highpoly[i].obmat, hits[i].co);
+ distance = len_squared_v3v3(hit_world, co);
+
+ if (distance < hit_distance) {
+ hit_mesh = i;
+ hit_distance = distance;
}
}
}
@@ -688,6 +684,10 @@ void RE_bake_pixels_populate(
int mat_nr = mp->mat_nr;
int image_id = bake_images->lookup[mat_nr];
+ if (image_id < 0) {
+ continue;
+ }
+
bd.bk_image = &bake_images->data[image_id];
bd.primitive_id = ++p_id;
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index 86961cdd169..42cef07205c 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -66,7 +66,6 @@
#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"
@@ -82,6 +81,8 @@
#include "BKE_particle.h"
#include "BKE_scene.h"
+#include "DEG_depsgraph.h"
+
#include "PIL_time.h"
#include "envmap.h"
@@ -3153,11 +3154,11 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
/* normalmaps, test if tangents needed, separated from shading */
if (ma->mode_l & MA_TANGENT_V) {
need_tangent= 1;
- if (me->mtpoly==NULL)
+ if (me->mloopuv==NULL)
need_orco= 1;
}
if (ma->mode_l & MA_NORMAP_TANG) {
- if (me->mtpoly==NULL) {
+ if (me->mloopuv==NULL) {
need_orco= 1;
}
need_tangent= 1;
@@ -3170,7 +3171,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
if (re->flag & R_NEED_TANGENT) {
/* exception for tangent space baking */
- if (me->mtpoly==NULL) {
+ if (me->mloopuv==NULL) {
need_orco= 1;
}
need_tangent= 1;
@@ -3439,10 +3440,9 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
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);
- BLI_assert(uv_start >= 0 && uv_index >= 0);
- if ((uv_start < 0 || uv_index < 0))
- continue;
- int n = uv_index - uv_start;
+
+ /* 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);
@@ -4658,14 +4658,22 @@ static void add_render_object(Render *re, Object *ob, Object *par, DupliObject *
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))
+ 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 */
@@ -4712,8 +4720,9 @@ static void add_render_object(Render *re, Object *ob, Object *par, DupliObject *
if (dob)
psys->flag |= PSYS_USE_IMAT;
init_render_object_data(re, obr, timeoffset);
- if (!(re->r.scemode & R_VIEWPORT_PREVIEW))
+ 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 */
@@ -4975,14 +4984,13 @@ static void add_group_render_dupli_obs(Render *re, Group *group, int nolamps, in
}
}
-static void database_init_objects(Render *re, unsigned int renderlay, int nolamps, int onlyselected, Object *actob, int timeoffset)
+static void database_init_objects(Render *re, unsigned int UNUSED(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
@@ -5010,14 +5018,18 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
for (SETLOOPER(re->scene, sce_iter, base)) {
ob= base->object;
+#if 0
+ TODO_LAYER; /* investigate if this is an issue*/
/* 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;
+#endif
- /* if the object has been restricted from rendering in the outliner, ignore it */
- if (is_object_restricted(re, ob)) continue;
+ /* if the object is not visible, ignore it */
+ if ((base->flag & BASE_VISIBLED) == 0) {
+ continue;
+ }
/* OB_DONE means the object itself got duplicated, so was already converted */
if (ob->flag & OB_DONE) {
@@ -5030,7 +5042,7 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
}
}
}
- else if ((base->lay & lay) || (ob->type==OB_LAMP && (base->lay & re->lay)) ) {
+ else if (((base->flag & BASE_VISIBLED) != 0) || (ob->type==OB_LAMP)) {
if ((ob->transflag & OB_DUPLI) && (ob->type!=OB_MBALL)) {
DupliObject *dob;
ListBase *duplilist;
@@ -5203,7 +5215,7 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l
/* 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);
+ BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene);
render_update_anim_renderdata(re, &re->scene->r);
}
@@ -5218,7 +5230,7 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l
RE_SetView(re, mat);
/* force correct matrix for scaled cameras */
- DAG_id_tag_update_ex(re->main, &camera->id, OB_RECALC_OB);
+ DEG_id_tag_update_ex(re->main, &camera->id, OB_RECALC_OB);
}
/* store for incremental render, viewmat rotates dbase */
@@ -5373,13 +5385,9 @@ static void database_fromscene_vectors(Render *re, Scene *scene, unsigned int la
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);
+ BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene);
/* if no camera, viewmat should have been set! */
if (camera) {
@@ -5569,12 +5577,17 @@ static void calculate_speedvectors(Render *re, ObjectInstanceRen *obi, float *ve
/* 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]];
- co4= (face[3])? mesh->co[face[3]]: NULL;
+ co1 = mesh->co[face[0]];
+ co2 = mesh->co[face[1]];
+ co3 = mesh->co[face[2]];
- interp_weights_face_v3(w, co1, co2, co3, co4, strand->vert->co);
+ 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]);
diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c
index d97e18d6511..7bd8c6decf0 100644
--- a/source/blender/render/intern/source/envmap.c
+++ b/source/blender/render/intern/source/envmap.c
@@ -51,6 +51,7 @@
#include "BKE_main.h"
#include "BKE_image.h" /* BKE_imbuf_write */
+#include "BKE_layer.h"
#include "BKE_texture.h"
#include "BKE_scene.h"
@@ -61,6 +62,7 @@
#include "renderpipeline.h"
#include "texture.h"
#include "zbuf.h"
+#include "render_result.h"
/* ------------------------------------------------------------------------- */
@@ -142,8 +144,8 @@ static Render *envmap_render_copy(Render *re, EnvMap *env)
/* set up renderdata */
render_copy_renderdata(&envre->r, &re->r);
envre->r.mode &= ~(R_BORDER | R_PANORAMA | R_ORTHO | R_MBLUR);
- BLI_listbase_clear(&envre->r.layers);
- BLI_listbase_clear(&envre->r.views);
+ 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;
@@ -247,17 +249,14 @@ static void envmap_transmatrix(float mat[4][4], int part)
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;
+
+ FOREACH_SCENE_OBJECT(re->scene, ob)
+ {
+ mul_m4_m4m4(mat, re->viewmat, ob->obmat);
+ invert_m4_m4(ob->imat, mat);
}
-
+ FOREACH_SCENE_OBJECT_END
}
/* ------------------------------------------------------------------------- */
@@ -493,13 +492,20 @@ static void render_envmap(Render *re, EnvMap *env)
env_rotate_scene(envre, tmat, 0);
if (re->test_break(re->tbh) == 0) {
- RenderLayer *rl = envre->result->layers.first;
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, SCE_PASS_COMBINED, "");
+ 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));
diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c
index fd9d95c63b6..be6d6459b2f 100644
--- a/source/blender/render/intern/source/external_engine.c
+++ b/source/blender/render/intern/source/external_engine.c
@@ -45,9 +45,12 @@
#include "BKE_camera.h"
#include "BKE_global.h"
#include "BKE_colortools.h"
+#include "BKE_layer.h"
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#ifdef WITH_PYTHON
@@ -58,17 +61,20 @@
#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,
+ "BLENDER_RENDER", N_("Blender Render"), RE_INTERNAL | RE_USE_LEGACY_PIPELINE,
+ NULL, NULL, NULL, NULL, NULL, NULL, render_internal_update_passes, NULL, NULL, NULL,
{NULL, NULL, NULL}
};
@@ -76,8 +82,8 @@ static RenderEngineType internal_render_type = {
static RenderEngineType internal_game_type = {
NULL, NULL,
- "BLENDER_GAME", N_("Blender Game"), RE_INTERNAL | RE_GAME,
- NULL, NULL, NULL, NULL, NULL, NULL,
+ "BLENDER_GAME", N_("Blender Game"), RE_INTERNAL | RE_GAME | RE_USE_LEGACY_PIPELINE,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
{NULL, NULL, NULL}
};
@@ -87,16 +93,22 @@ ListBase R_engines = {NULL, NULL};
void RE_engines_init(void)
{
- BLI_addtail(&R_engines, &internal_render_type);
+ RE_engines_register(NULL, &internal_render_type);
#ifdef WITH_GAMEENGINE
- BLI_addtail(&R_engines, &internal_game_type);
+ RE_engines_register(NULL, &internal_game_type);
#endif
+ DRW_engines_register();
}
void RE_engines_exit(void)
{
RenderEngineType *type, *next;
+ DRW_engines_free();
+
+ BKE_layer_collection_engine_settings_callback_free();
+ BKE_scene_layer_engine_settings_callback_free();
+
for (type = R_engines.first; type; type = next) {
next = type->next;
@@ -111,6 +123,22 @@ void RE_engines_exit(void)
}
}
+void RE_engines_register(Main *bmain, RenderEngineType *render_type)
+{
+ if (render_type->draw_engine) {
+ DRW_engine_register(render_type->draw_engine);
+ }
+ if (render_type->collection_settings_create) {
+ BKE_layer_collection_engine_settings_callback_register(
+ bmain, render_type->idname, render_type->collection_settings_create);
+ }
+ if (render_type->render_settings_create) {
+ BKE_scene_layer_engine_settings_callback_register(
+ bmain, render_type->idname, render_type->render_settings_create);
+ }
+ BLI_addtail(&R_engines, render_type);
+}
+
RenderEngineType *RE_engines_find(const char *idname)
{
RenderEngineType *type;
@@ -125,7 +153,7 @@ RenderEngineType *RE_engines_find(const char *idname)
bool RE_engine_is_external(Render *re)
{
RenderEngineType *type = RE_engines_find(re->r.engine);
- return (type && type->render);
+ return (type && type->render_to_image);
}
/* Create, Free */
@@ -183,7 +211,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;
@@ -212,6 +241,8 @@ RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w,
/* can be NULL if we CLAMP the width or height to 0 */
if (result) {
+ render_result_clone_passes(re, result, viewname);
+
RenderPart *pa;
/* Copy EXR tile settings, so pipeline knows whether this is a result
@@ -245,7 +276,18 @@ void RE_engine_update_result(RenderEngine *engine, RenderResult *result)
}
}
-void RE_engine_end_result(RenderEngine *engine, RenderResult *result, int cancel, int merge_results)
+void RE_engine_add_pass(RenderEngine *engine, const char *name, int channels, const char *chan_id, const char *layername)
+{
+ Render *re = engine->re;
+
+ if (!re || !re->result) {
+ return;
+ }
+
+ render_result_add_pass(re->result, name, channels, chan_id, layername, NULL);
+}
+
+void RE_engine_end_result(RenderEngine *engine, RenderResult *result, int cancel, int highlight, int merge_results)
{
Render *re = engine->re;
@@ -254,7 +296,7 @@ void RE_engine_end_result(RenderEngine *engine, RenderResult *result, int cancel
}
/* merge. on break, don't merge in result for preview renders, looks nicer */
- if (!cancel) {
+ if (!highlight) {
/* for exr tile render, detect tiles that are done */
RenderPart *pa = get_part_from_result(re, result);
@@ -395,7 +437,8 @@ float RE_engine_get_camera_shift_x(RenderEngine *engine, Object *camera, int use
return BKE_camera_multiview_shift_x(re ? &re->r : NULL, camera, re->viewname);
}
-void RE_engine_get_camera_model_matrix(RenderEngine *engine, Object *camera, int use_spherical_stereo, float *r_modelmat)
+void RE_engine_get_camera_model_matrix(
+ RenderEngine *engine, Object *camera, int use_spherical_stereo, float *r_modelmat)
{
Render *re = engine->re;
@@ -472,8 +515,9 @@ RenderData *RE_engine_get_render_data(Render *re)
}
/* Bake */
-void RE_bake_engine_set_engine_parameters(Render *re, Main *bmain, Scene *scene)
+void RE_bake_engine_set_engine_parameters(Render *re, Main *bmain, Depsgraph *graph, Scene *scene)
{
+ re->depsgraph = graph;
re->scene = scene;
re->main = bmain;
render_copy_renderdata(&re->r, &scene->r);
@@ -523,10 +567,21 @@ bool RE_bake_engine(
/* 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);
+ type->update(engine, re->main, re->depsgraph, re->scene);
+
+ if (type->bake) {
+ type->bake(
+ engine,
+ re->scene,
+ object,
+ pass_type,
+ pass_filter,
+ object_id,
+ pixel_array,
+ num_pixels,
+ depth,
+ result);
+ }
engine->tile_x = 0;
engine->tile_y = 0;
@@ -562,8 +617,7 @@ void RE_engine_frame_set(RenderEngine *engine, int frame, float subframe)
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);
+ BKE_scene_update_for_newframe(re->eval_ctx, re->main, scene);
#ifdef WITH_PYTHON
BPy_END_ALLOW_THREADS;
@@ -574,17 +628,6 @@ void RE_engine_frame_set(RenderEngine *engine, int frame, float subframe)
/* 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);
@@ -592,7 +635,7 @@ int RE_engine_render(Render *re, int do_all)
bool persistent_data = (re->r.mode & R_PERSISTENT_DATA) != 0;
/* verify if we can render */
- if (!type->render)
+ if (!type->render_to_image)
return 0;
if ((re->r.scemode & R_BUTS_PREVIEW) && !(type->flag & RE_USE_PREVIEW))
return 0;
@@ -609,40 +652,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);
+ BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene);
render_update_anim_renderdata(re, &re->scene->r);
}
@@ -708,16 +718,18 @@ int RE_engine_render(Render *re, int do_all)
if (re->result->do_exr_tile)
render_result_exr_file_begin(re);
- if (type->update)
- type->update(engine, re->main, re->scene);
+ if (type->update) {
+ type->update(engine, re->main, re->depsgraph, 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_to_image) {
+ type->render_to_image(engine, re->depsgraph);
+ }
engine->tile_x = 0;
engine->tile_y = 0;
@@ -760,3 +772,22 @@ 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,
+ 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)) {
+ return;
+ }
+
+ /* Register the pass in all scenes that have a render layer node for this layer.
+ * Since multiple scenes can be used in the compositor, the code must loop over all scenes
+ * and check whether their nodetree has a node that needs to be updated. */
+ Scene *sce;
+ for (sce = G.main->scene.first; sce; sce = sce->id.next) {
+ if (sce->nodetree) {
+ ntreeCompositRegisterPass(sce->nodetree, scene, srl, name, type);
+ }
+ }
+}
diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c
index 970a3937657..4ac44671871 100644
--- a/source/blender/render/intern/source/initrender.c
+++ b/source/blender/render/intern/source/initrender.c
@@ -48,6 +48,8 @@
#include "BKE_camera.h"
+#include "DEG_depsgraph.h"
+
#ifdef WITH_QUICKTIME
#include "quicktime_export.h"
#endif
@@ -503,6 +505,11 @@ void RE_SetCamera(Render *re, Object *cam_ob)
re_camera_params_get(re, &params, cam_ob);
}
+void RE_SetDepsgraph(Render *re, Depsgraph *graph)
+{
+ re->depsgraph = graph;
+}
+
void RE_SetPixelSize(Render *re, float pixsize)
{
re->viewdx = pixsize;
diff --git a/source/blender/render/intern/source/multires_bake.c b/source/blender/render/intern/source/multires_bake.c
index fba5836ac32..4c0355ef604 100644
--- a/source/blender/render/intern/source/multires_bake.c
+++ b/source/blender/render/intern/source/multires_bake.c
@@ -42,14 +42,16 @@
#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"
@@ -78,7 +80,6 @@ typedef struct {
MLoop *mloop;
MLoopUV *mloopuv;
const MLoopTri *mlooptri;
- MTexPoly *mtpoly;
float *pvtangent;
const float *precomputed_normals;
int w, h;
@@ -89,6 +90,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);
@@ -373,13 +376,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 +450,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 +493,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 */
@@ -1178,30 +1181,34 @@ static void apply_ao_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, void
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)
@@ -1283,7 +1290,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
index b3d31e3b93a..cd93898d846 100644
--- a/source/blender/render/intern/source/occlusion.c
+++ b/source/blender/render/intern/source/occlusion.c
@@ -329,7 +329,7 @@ static void occ_face(const OccFace *face, float co[3], float normal[3], float *a
if (vlr->v4)
mid_v3_v3v3(co, vlr->v1->co, vlr->v3->co);
else
- cent_tri_v3(co, vlr->v1->co, vlr->v2->co, vlr->v3->co);
+ mid_v3_v3v3v3(co, vlr->v1->co, vlr->v2->co, vlr->v3->co);
if (obi->flag & R_TRANSFORMED)
mul_m4_v3(obi->mat, co);
@@ -1190,9 +1190,14 @@ static void sample_occ_surface(ShadeInput *shi)
co1 = mesh->co[face[0]];
co2 = mesh->co[face[1]];
co3 = mesh->co[face[2]];
- co4 = (face[3]) ? mesh->co[face[3]] : NULL;
- interp_weights_face_v3(w, co1, co2, co3, co4, strand->vert->co);
+ 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);
@@ -1245,7 +1250,7 @@ static void *exec_strandsurface_sample(void *data)
normal_quad_v3(n, co1, co2, co3, co4);
}
else {
- cent_tri_v3(co, co1, co2, co3);
+ mid_v3_v3v3v3(co, co1, co2, co3);
normal_tri_v3(n, co1, co2, co3);
}
negate_v3(n);
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index ec629aa2863..7219630f519 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -62,9 +62,9 @@
#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_global.h"
#include "BKE_image.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_library_remap.h"
#include "BKE_main.h"
@@ -74,9 +74,12 @@
#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 "PIL_time.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
@@ -238,9 +241,9 @@ void RE_FreeRenderResult(RenderResult *res)
render_result_free(res);
}
-float *RE_RenderLayerGetPass(volatile RenderLayer *rl, int passtype, const char *viewname)
+float *RE_RenderLayerGetPass(volatile RenderLayer *rl, const char *name, const char *viewname)
{
- RenderPass *rpass = RE_pass_find_by_type(rl, passtype, viewname);
+ RenderPass *rpass = RE_pass_find_by_name(rl, name, viewname);
return rpass ? rpass->rect : NULL;
}
@@ -381,13 +384,13 @@ void RE_AcquireResultImageViews(Render *re, RenderResult *rr)
if (rl) {
if (rv->rectf == NULL) {
for (rview = (RenderView *)rr->views.first; rview; rview = rview->next) {
- rview->rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, rview->name);
+ rview->rectf = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, rview->name);
}
}
if (rv->rectz == NULL) {
for (rview = (RenderView *)rr->views.first; rview; rview = rview->next) {
- rview->rectz = RE_RenderLayerGetPass(rl, SCE_PASS_Z, rview->name);
+ rview->rectz = RE_RenderLayerGetPass(rl, RE_PASSNAME_Z, rview->name);
}
}
}
@@ -441,10 +444,10 @@ void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id)
if (rl) {
if (rv->rectf == NULL)
- rr->rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, rv->name);
+ rr->rectf = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, rv->name);
if (rv->rectz == NULL)
- rr->rectz = RE_RenderLayerGetPass(rl, SCE_PASS_Z, rv->name);
+ rr->rectz = RE_RenderLayerGetPass(rl, RE_PASSNAME_Z, rv->name);
}
rr->have_combined = (rv->rectf != NULL);
@@ -549,6 +552,7 @@ void RE_FreeRender(Render *re)
/* main dbase can already be invalid now, some database-free code checks it */
re->main = NULL;
re->scene = NULL;
+ re->depsgraph = NULL;
RE_Database_Free(re); /* view render can still have full database */
free_sample_tables(re);
@@ -722,6 +726,8 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
re->r.size = source->r.size;
}
+ re_init_resolution(re, source, winx, winy, disprect);
+
/* disable border if it's a full render anyway */
if (re->r.border.xmin == 0.0f && re->r.border.xmax == 1.0f &&
re->r.border.ymin == 0.0f && re->r.border.ymax == 1.0f)
@@ -729,8 +735,6 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
re->r.mode &= ~R_BORDER;
}
- re_init_resolution(re, source, winx, winy, disprect);
-
if (re->rectx < 1 || re->recty < 1 || (BKE_imtype_is_movie(rd->im_format.imtype) &&
(re->rectx < 16 || re->recty < 16) ))
{
@@ -841,7 +845,7 @@ static void render_result_rescale(Render *re)
if (src_rectf == NULL) {
RenderLayer *rl = render_get_active_layer(re, re->result);
if (rl != NULL) {
- src_rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, NULL);
+ src_rectf = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, NULL);
}
}
@@ -860,7 +864,7 @@ static void render_result_rescale(Render *re)
RenderLayer *rl;
rl = render_get_active_layer(re, re->result);
if (rl != NULL) {
- dst_rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, NULL);
+ dst_rectf = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, NULL);
}
}
@@ -1654,7 +1658,7 @@ static void merge_renderresult_blur(RenderResult *rr, RenderResult *brr, float b
/* passes are allocated in sync */
rpass1 = rl1->passes.first;
for (rpass = rl->passes.first; rpass && rpass1; rpass = rpass->next, rpass1 = rpass1->next) {
- if ((rpass->passtype & SCE_PASS_COMBINED) && key_alpha)
+ 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);
@@ -1697,7 +1701,7 @@ static void do_render_blur_3d(Render *re)
/* 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);
+ BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene);
}
/* weak... the display callback wants an active renderlayer pointer... */
@@ -1854,6 +1858,8 @@ static void render_result_uncrop(Render *re)
rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
+ render_result_clone_passes(re, rres, NULL);
+
render_result_merge(rres, re->result);
render_result_free(re->result);
re->result = rres;
@@ -1931,6 +1937,7 @@ static void render_scene(Render *re, Scene *sce, int cfra)
/* still unsure entity this... */
resc->main = re->main;
+ resc->depsgraph = re->depsgraph;
resc->scene = sce;
resc->lay = sce->lay;
resc->scene_color_manage = BKE_scene_check_color_management_enabled(sce);
@@ -2011,14 +2018,14 @@ bool RE_allow_render_generic_object(Object *ob)
#define DEPSGRAPH_WORKAROUND_HACK
#ifdef DEPSGRAPH_WORKAROUND_HACK
-static void tag_dependend_objects_for_render(Scene *scene, int renderlay)
+static void tag_dependend_objects_for_render(Scene *scene, int UNUSED(renderlay))
{
Scene *sce_iter;
Base *base;
for (SETLOOPER(scene, sce_iter, base)) {
Object *object = base->object;
- if ((base->lay & renderlay) == 0) {
+ if ((base->flag & BASE_VISIBLED) == 0) {
continue;
}
@@ -2038,22 +2045,22 @@ static void tag_dependend_objects_for_render(Scene *scene, int renderlay)
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);
+ DEG_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);
+ DEG_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);
+ DEG_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);
+ DEG_id_tag_update(&smd->target->id, OB_RECALC_DATA);
}
}
}
@@ -2587,7 +2594,7 @@ static void do_render_composite_fields_blur_3d(Render *re)
R.i.cfra = re->i.cfra;
if (update_newframe)
- BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, re->lay);
+ BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene);
if (re->r.scemode & R_FULL_SAMPLE)
do_merge_fullsample(re, ntree);
@@ -3059,6 +3066,13 @@ bool RE_is_rendering_allowed(Scene *scene, Object *camera_override, ReportList *
}
#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");
+ return false;
+ }
+ }
+
/* layer flag tests */
if (!render_scene_has_layers_to_render(scene)) {
BKE_report(reports, RPT_ERROR, "All render layers are disabled");
@@ -3432,7 +3446,7 @@ bool RE_WriteRenderViewsMovie(
ok = mh->append_movie(movie_ctx_arr[0], rd, preview ? scene->r.psfra : scene->r.sfra, scene->r.cfra, (int *) ibuf_arr[2]->rect,
ibuf_arr[2]->x, ibuf_arr[2]->y, "", reports);
- for (i = 0; i < 2; i++) {
+ for (i = 0; i < 3; i++) {
/* imbuf knows which rects are not part of ibuf */
IMB_freeImBuf(ibuf_arr[i]);
}
@@ -3632,19 +3646,8 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
render_initialize_from_main(re, &rd, bmain, scene, NULL, camera_override, lay_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 update for physics and particles system. */
+ BKE_scene_update_for_newframe(re->eval_ctx, bmain, scene);
continue;
}
else
@@ -3784,6 +3787,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
re->flag &= ~R_ANIMATION;
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);
/* UGLY WARNING */
G.is_rendering = false;
@@ -3792,6 +3796,8 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
void RE_PreviewRender(Render *re, Main *bmain, Scene *sce)
{
Object *camera;
+ /* TODO(sergey): Get proper scene layer here. */
+ SceneLayer *scene_layer = BKE_scene_layer_context_active_ex_PLACEHOLDER(bmain, sce);
int winx, winy;
winx = (sce->r.size * sce->r.xsch) / 100;
@@ -3805,6 +3811,7 @@ void RE_PreviewRender(Render *re, Main *bmain, Scene *sce)
re->scene = sce;
re->scene_color_manage = BKE_scene_check_color_management_enabled(sce);
re->lay = sce->lay;
+ re->depsgraph = BKE_scene_get_depsgraph(sce, scene_layer);
camera = RE_GetCamera(re);
RE_SetCamera(re, camera);
@@ -3878,7 +3885,7 @@ void RE_layer_load_from_file(RenderLayer *layer, ReportList *reports, const char
/* multiview: since the API takes no 'view', we use the first combined pass found */
for (rpass = layer->passes.first; rpass; rpass = rpass->next)
- if (rpass->passtype == SCE_PASS_COMBINED)
+ if (STREQ(rpass->name, RE_PASSNAME_COMBINED))
break;
if (rpass == NULL)
@@ -4004,13 +4011,12 @@ bool RE_layers_have_name(struct RenderResult *rr)
return false;
}
-RenderPass *RE_pass_find_by_type(volatile RenderLayer *rl, int passtype, const char *viewname)
+RenderPass *RE_pass_find_by_name(volatile RenderLayer *rl, const char *name, const char *viewname)
{
RenderPass *rp = NULL;
for (rp = rl->passes.last; rp; rp = rp->prev) {
- if (rp->passtype == passtype) {
-
+ if (STREQ(rp->name, name)) {
if (viewname == NULL || viewname[0] == '\0')
break;
else if (STREQ(rp->view, viewname))
@@ -4020,6 +4026,50 @@ RenderPass *RE_pass_find_by_type(volatile RenderLayer *rl, int passtype, const c
return rp;
}
+/* Only provided for API compatibility, don't use this in new code! */
+RenderPass *RE_pass_find_by_type(volatile RenderLayer *rl, int passtype, const char *viewname)
+{
+#define CHECK_PASS(NAME) \
+ if (passtype == SCE_PASS_ ## NAME) \
+ return RE_pass_find_by_name(rl, RE_PASSNAME_ ## NAME, viewname);
+
+ CHECK_PASS(COMBINED);
+ CHECK_PASS(Z);
+ CHECK_PASS(VECTOR);
+ CHECK_PASS(NORMAL);
+ CHECK_PASS(UV);
+ CHECK_PASS(RGBA);
+ CHECK_PASS(EMIT);
+ CHECK_PASS(DIFFUSE);
+ CHECK_PASS(SPEC);
+ CHECK_PASS(SHADOW);
+ CHECK_PASS(AO);
+ CHECK_PASS(ENVIRONMENT);
+ CHECK_PASS(INDIRECT);
+ CHECK_PASS(REFLECT);
+ CHECK_PASS(REFRACT);
+ CHECK_PASS(INDEXOB);
+ CHECK_PASS(INDEXMA);
+ CHECK_PASS(MIST);
+ CHECK_PASS(RAYHITS);
+ CHECK_PASS(DIFFUSE_DIRECT);
+ CHECK_PASS(DIFFUSE_INDIRECT);
+ CHECK_PASS(DIFFUSE_COLOR);
+ CHECK_PASS(GLOSSY_DIRECT);
+ CHECK_PASS(GLOSSY_INDIRECT);
+ CHECK_PASS(GLOSSY_COLOR);
+ CHECK_PASS(TRANSM_DIRECT);
+ CHECK_PASS(TRANSM_INDIRECT);
+ CHECK_PASS(TRANSM_COLOR);
+ CHECK_PASS(SUBSURFACE_DIRECT);
+ CHECK_PASS(SUBSURFACE_INDIRECT);
+ CHECK_PASS(SUBSURFACE_COLOR);
+
+#undef CHECK_PASS
+
+ return NULL;
+}
+
/* create a renderlayer and renderpass for grease pencil layer */
RenderPass *RE_create_gp_pass(RenderResult *rr, const char *layername, const char *viewname)
{
@@ -4037,7 +4087,7 @@ RenderPass *RE_create_gp_pass(RenderResult *rr, const char *layername, const cha
}
/* clear previous pass if exist or the new image will be over previous one*/
- RenderPass *rp = RE_pass_find_by_type(rl, SCE_PASS_COMBINED, viewname);
+ RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname);
if (rp) {
if (rp->rect) {
MEM_freeN(rp->rect);
@@ -4045,5 +4095,5 @@ RenderPass *RE_create_gp_pass(RenderResult *rr, const char *layername, const cha
BLI_freelinkN(&rl->passes, rp);
}
/* create a totally new pass */
- return gp_add_pass(rr, rl, 4, SCE_PASS_COMBINED, viewname);
+ return gp_add_pass(rr, rl, 4, RE_PASSNAME_COMBINED, viewname);
}
diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c
index e4da4302efe..fb047aad897 100644
--- a/source/blender/render/intern/source/pointdensity.c
+++ b/source/blender/render/intern/source/pointdensity.c
@@ -333,7 +333,16 @@ static void pointdensity_cache_vertex_color(PointDensity *pd, Object *UNUSED(ob)
for (i = 0; i < totloop; i++) {
int v = mloop[i].v;
- rgb_uchar_to_float(&data_color[v*3], &mcol[i].r);
+
+ if (mcorners[v] == 0) {
+ rgb_uchar_to_float(&data_color[v * 3], &mcol[i].r);
+ }
+ else {
+ float col[3];
+ rgb_uchar_to_float(col, &mcol[i].r);
+ add_v3_v3(&data_color[v * 3], col);
+ }
+
++mcorners[v];
}
@@ -974,11 +983,12 @@ void RE_point_density_minmax(
}
else {
float radius[3] = {pd->radius, pd->radius, pd->radius};
- float *loc, *size;
+ BoundBox *bb = BKE_object_boundbox_get(object);
- if (BKE_object_obdata_texspace_get(pd->object, NULL, &loc, &size, NULL)) {
- sub_v3_v3v3(r_min, loc, size);
- add_v3_v3v3(r_max, loc, size);
+ if (bb != NULL) {
+ BLI_assert((bb->flag & BOUNDBOX_DIRTY) == 0);
+ copy_v3_v3(r_min, bb->vec[0]);
+ copy_v3_v3(r_max, bb->vec[6]);
/* Adjust texture space to include density points on the boundaries. */
sub_v3_v3(r_min, radius);
add_v3_v3(r_max, radius);
diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c
index 6ea46af6f7e..8e6e6c9bb7d 100644
--- a/source/blender/render/intern/source/render_result.c
+++ b/source/blender/render/intern/source/render_result.c
@@ -173,363 +173,72 @@ void render_result_views_shallowdelete(RenderResult *rr)
}
}
-static const char *name_from_passtype(int passtype, int channel)
-{
- if (passtype == SCE_PASS_COMBINED) {
- if (channel == -1) return "Combined";
- if (channel == 0) return "Combined.R";
- if (channel == 1) return "Combined.G";
- if (channel == 2) return "Combined.B";
- return "Combined.A";
- }
- if (passtype == SCE_PASS_Z) {
- if (channel == -1) return "Depth";
- return "Depth.Z";
- }
- if (passtype == SCE_PASS_VECTOR) {
- if (channel == -1) return "Vector";
- if (channel == 0) return "Vector.X";
- if (channel == 1) return "Vector.Y";
- if (channel == 2) return "Vector.Z";
- return "Vector.W";
- }
- if (passtype == SCE_PASS_NORMAL) {
- if (channel == -1) return "Normal";
- if (channel == 0) return "Normal.X";
- if (channel == 1) return "Normal.Y";
- return "Normal.Z";
- }
- if (passtype == SCE_PASS_UV) {
- if (channel == -1) return "UV";
- if (channel == 0) return "UV.U";
- if (channel == 1) return "UV.V";
- return "UV.A";
- }
- if (passtype == SCE_PASS_RGBA) {
- if (channel == -1) return "Color";
- if (channel == 0) return "Color.R";
- if (channel == 1) return "Color.G";
- if (channel == 2) return "Color.B";
- return "Color.A";
- }
- if (passtype == SCE_PASS_EMIT) {
- if (channel == -1) return "Emit";
- if (channel == 0) return "Emit.R";
- if (channel == 1) return "Emit.G";
- return "Emit.B";
- }
- if (passtype == SCE_PASS_DIFFUSE) {
- if (channel == -1) return "Diffuse";
- if (channel == 0) return "Diffuse.R";
- if (channel == 1) return "Diffuse.G";
- return "Diffuse.B";
- }
- if (passtype == SCE_PASS_SPEC) {
- if (channel == -1) return "Spec";
- if (channel == 0) return "Spec.R";
- if (channel == 1) return "Spec.G";
- return "Spec.B";
- }
- if (passtype == SCE_PASS_SHADOW) {
- if (channel == -1) return "Shadow";
- if (channel == 0) return "Shadow.R";
- if (channel == 1) return "Shadow.G";
- return "Shadow.B";
- }
- if (passtype == SCE_PASS_AO) {
- if (channel == -1) return "AO";
- if (channel == 0) return "AO.R";
- if (channel == 1) return "AO.G";
- return "AO.B";
- }
- if (passtype == SCE_PASS_ENVIRONMENT) {
- if (channel == -1) return "Env";
- if (channel == 0) return "Env.R";
- if (channel == 1) return "Env.G";
- return "Env.B";
- }
- if (passtype == SCE_PASS_INDIRECT) {
- if (channel == -1) return "Indirect";
- if (channel == 0) return "Indirect.R";
- if (channel == 1) return "Indirect.G";
- return "Indirect.B";
- }
- if (passtype == SCE_PASS_REFLECT) {
- if (channel == -1) return "Reflect";
- if (channel == 0) return "Reflect.R";
- if (channel == 1) return "Reflect.G";
- return "Reflect.B";
- }
- if (passtype == SCE_PASS_REFRACT) {
- if (channel == -1) return "Refract";
- if (channel == 0) return "Refract.R";
- if (channel == 1) return "Refract.G";
- return "Refract.B";
- }
- if (passtype == SCE_PASS_INDEXOB) {
- if (channel == -1) return "IndexOB";
- return "IndexOB.X";
- }
- if (passtype == SCE_PASS_INDEXMA) {
- if (channel == -1) return "IndexMA";
- return "IndexMA.X";
- }
- if (passtype == SCE_PASS_MIST) {
- if (channel == -1) return "Mist";
- return "Mist.Z";
- }
- if (passtype == SCE_PASS_RAYHITS) {
- if (channel == -1) return "Rayhits";
- if (channel == 0) return "Rayhits.R";
- if (channel == 1) return "Rayhits.G";
- return "Rayhits.B";
- }
- if (passtype == SCE_PASS_DIFFUSE_DIRECT) {
- if (channel == -1) return "DiffDir";
- if (channel == 0) return "DiffDir.R";
- if (channel == 1) return "DiffDir.G";
- return "DiffDir.B";
- }
- if (passtype == SCE_PASS_DIFFUSE_INDIRECT) {
- if (channel == -1) return "DiffInd";
- if (channel == 0) return "DiffInd.R";
- if (channel == 1) return "DiffInd.G";
- return "DiffInd.B";
- }
- if (passtype == SCE_PASS_DIFFUSE_COLOR) {
- if (channel == -1) return "DiffCol";
- if (channel == 0) return "DiffCol.R";
- if (channel == 1) return "DiffCol.G";
- return "DiffCol.B";
- }
- if (passtype == SCE_PASS_GLOSSY_DIRECT) {
- if (channel == -1) return "GlossDir";
- if (channel == 0) return "GlossDir.R";
- if (channel == 1) return "GlossDir.G";
- return "GlossDir.B";
- }
- if (passtype == SCE_PASS_GLOSSY_INDIRECT) {
- if (channel == -1) return "GlossInd";
- if (channel == 0) return "GlossInd.R";
- if (channel == 1) return "GlossInd.G";
- return "GlossInd.B";
- }
- if (passtype == SCE_PASS_GLOSSY_COLOR) {
- if (channel == -1) return "GlossCol";
- if (channel == 0) return "GlossCol.R";
- if (channel == 1) return "GlossCol.G";
- return "GlossCol.B";
- }
- if (passtype == SCE_PASS_TRANSM_DIRECT) {
- if (channel == -1) return "TransDir";
- if (channel == 0) return "TransDir.R";
- if (channel == 1) return "TransDir.G";
- return "TransDir.B";
- }
- if (passtype == SCE_PASS_TRANSM_INDIRECT) {
- if (channel == -1) return "TransInd";
- if (channel == 0) return "TransInd.R";
- if (channel == 1) return "TransInd.G";
- return "TransInd.B";
- }
- if (passtype == SCE_PASS_TRANSM_COLOR) {
- if (channel == -1) return "TransCol";
- if (channel == 0) return "TransCol.R";
- if (channel == 1) return "TransCol.G";
- return "TransCol.B";
- }
- if (passtype == SCE_PASS_SUBSURFACE_DIRECT) {
- if (channel == -1) return "SubsurfaceDir";
- if (channel == 0) return "SubsurfaceDir.R";
- if (channel == 1) return "SubsurfaceDir.G";
- return "SubsurfaceDir.B";
- }
- if (passtype == SCE_PASS_SUBSURFACE_INDIRECT) {
- if (channel == -1) return "SubsurfaceInd";
- if (channel == 0) return "SubsurfaceInd.R";
- if (channel == 1) return "SubsurfaceInd.G";
- return "SubsurfaceInd.B";
- }
- if (passtype == SCE_PASS_SUBSURFACE_COLOR) {
- if (channel == -1) return "SubsurfaceCol";
- if (channel == 0) return "SubsurfaceCol.R";
- if (channel == 1) return "SubsurfaceCol.G";
- return "SubsurfaceCol.B";
- }
- return "Unknown";
-}
-static int passtype_from_name(const char *str, int passflag)
+static char* set_pass_name(char *outname, const char *name, int channel, const char *chan_id)
{
- /* We do not really support several pass of the same types, so in case we are opening an EXR file with several pass
- * names detected as same pass type, only return that pass type the first time, and return 'uknown' for the others.
- * See T48466. */
-#define RETURN_PASS(_passtype) return (passflag & (_passtype)) ? 0 : (_passtype)
-
- if (STRPREFIX(str, "Combined"))
- RETURN_PASS(SCE_PASS_COMBINED);
-
- if (STRPREFIX(str, "Depth"))
- RETURN_PASS(SCE_PASS_Z);
-
- if (STRPREFIX(str, "Vector"))
- RETURN_PASS(SCE_PASS_VECTOR);
-
- if (STRPREFIX(str, "Normal"))
- RETURN_PASS(SCE_PASS_NORMAL);
-
- if (STRPREFIX(str, "UV"))
- RETURN_PASS(SCE_PASS_UV);
-
- if (STRPREFIX(str, "Color"))
- RETURN_PASS(SCE_PASS_RGBA);
-
- if (STRPREFIX(str, "Emit"))
- RETURN_PASS(SCE_PASS_EMIT);
-
- if (STRPREFIX(str, "Diffuse"))
- RETURN_PASS(SCE_PASS_DIFFUSE);
-
- if (STRPREFIX(str, "Spec"))
- RETURN_PASS(SCE_PASS_SPEC);
-
- if (STRPREFIX(str, "Shadow"))
- RETURN_PASS(SCE_PASS_SHADOW);
-
- if (STRPREFIX(str, "AO"))
- RETURN_PASS(SCE_PASS_AO);
-
- if (STRPREFIX(str, "Env"))
- RETURN_PASS(SCE_PASS_ENVIRONMENT);
-
- if (STRPREFIX(str, "Indirect"))
- RETURN_PASS(SCE_PASS_INDIRECT);
-
- if (STRPREFIX(str, "Reflect"))
- RETURN_PASS(SCE_PASS_REFLECT);
-
- if (STRPREFIX(str, "Refract"))
- RETURN_PASS(SCE_PASS_REFRACT);
-
- if (STRPREFIX(str, "IndexOB"))
- RETURN_PASS(SCE_PASS_INDEXOB);
-
- if (STRPREFIX(str, "IndexMA"))
- RETURN_PASS(SCE_PASS_INDEXMA);
-
- if (STRPREFIX(str, "Mist"))
- RETURN_PASS(SCE_PASS_MIST);
-
- if (STRPREFIX(str, "RayHits"))
- RETURN_PASS(SCE_PASS_RAYHITS);
-
- if (STRPREFIX(str, "DiffDir"))
- RETURN_PASS(SCE_PASS_DIFFUSE_DIRECT);
-
- if (STRPREFIX(str, "DiffInd"))
- RETURN_PASS(SCE_PASS_DIFFUSE_INDIRECT);
-
- if (STRPREFIX(str, "DiffCol"))
- RETURN_PASS(SCE_PASS_DIFFUSE_COLOR);
-
- if (STRPREFIX(str, "GlossDir"))
- RETURN_PASS(SCE_PASS_GLOSSY_DIRECT);
-
- if (STRPREFIX(str, "GlossInd"))
- RETURN_PASS(SCE_PASS_GLOSSY_INDIRECT);
-
- if (STRPREFIX(str, "GlossCol"))
- RETURN_PASS(SCE_PASS_GLOSSY_COLOR);
-
- if (STRPREFIX(str, "TransDir"))
- RETURN_PASS(SCE_PASS_TRANSM_DIRECT);
-
- if (STRPREFIX(str, "TransInd"))
- RETURN_PASS(SCE_PASS_TRANSM_INDIRECT);
-
- if (STRPREFIX(str, "TransCol"))
- RETURN_PASS(SCE_PASS_TRANSM_COLOR);
-
- if (STRPREFIX(str, "SubsurfaceDir"))
- RETURN_PASS(SCE_PASS_SUBSURFACE_DIRECT);
-
- if (STRPREFIX(str, "SubsurfaceInd"))
- RETURN_PASS(SCE_PASS_SUBSURFACE_INDIRECT);
-
- if (STRPREFIX(str, "SubsurfaceCol"))
- RETURN_PASS(SCE_PASS_SUBSURFACE_COLOR);
-
- return 0;
-
-#undef RETURN_PASS
+ BLI_strncpy(outname, name, EXR_PASS_MAXNAME);
+ if (channel >= 0) {
+ char token[3] = {'.', chan_id[channel], '\0'};
+ strncat(outname, token, EXR_PASS_MAXNAME);
+ }
+ return outname;
}
-
-static void set_pass_name(char *passname, int passtype, int channel, const char *view)
+static void set_pass_full_name(char *fullname, const char *name, int channel, const char *view, const char *chan_id)
{
- const char delims[] = {'.', '\0'};
- const char *sep;
- const char *token;
- size_t len;
-
- const char *passtype_name = name_from_passtype(passtype, channel);
-
- if (view == NULL || view[0] == '\0') {
- BLI_strncpy(passname, passtype_name, EXR_PASS_MAXNAME);
- return;
- }
-
- len = BLI_str_rpartition(passtype_name, delims, &sep, &token);
-
- if (sep) {
- BLI_snprintf(passname, EXR_PASS_MAXNAME, "%.*s.%s.%s", (int)len, passtype_name, view, token);
+ BLI_strncpy(fullname, name, EXR_PASS_MAXNAME);
+ if (view && view[0]) {
+ strncat(fullname, ".", EXR_PASS_MAXNAME);
+ strncat(fullname, view, EXR_PASS_MAXNAME);
}
- else {
- BLI_snprintf(passname, EXR_PASS_MAXNAME, "%s.%s", passtype_name, view);
+ if (channel >= 0) {
+ char token[3] = {'.', chan_id[channel], '\0'};
+ strncat(fullname, token, EXR_PASS_MAXNAME);
}
}
/********************************** New **************************************/
-static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype, const char *viewname)
+static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, const char *name, const char *viewname, const char *chan_id)
{
const int view_id = BLI_findstringindex(&rr->views, viewname, offsetof(RenderView, name));
- const char *typestr = name_from_passtype(passtype, -1);
- RenderPass *rpass = MEM_callocN(sizeof(RenderPass), typestr);
+ RenderPass *rpass = MEM_callocN(sizeof(RenderPass), name);
size_t rectsize = ((size_t)rr->rectx) * rr->recty * channels;
- rpass->passtype = passtype;
rpass->channels = channels;
rpass->rectx = rl->rectx;
rpass->recty = rl->recty;
rpass->view_id = view_id;
- set_pass_name(rpass->name, rpass->passtype, -1, viewname);
- BLI_strncpy(rpass->internal_name, typestr, sizeof(rpass->internal_name));
+ BLI_strncpy(rpass->name, name, sizeof(rpass->name));
+ BLI_strncpy(rpass->chan_id, chan_id, sizeof(rpass->chan_id));
BLI_strncpy(rpass->view, viewname, sizeof(rpass->view));
+ set_pass_full_name(rpass->fullname, rpass->name, -1, rpass->view, rpass->chan_id);
if (rl->exrhandle) {
int a;
- for (a = 0; a < channels; a++)
- IMB_exr_add_channel(rl->exrhandle, rl->name, name_from_passtype(passtype, a), viewname, 0, 0, NULL, false);
+ for (a = 0; a < channels; a++) {
+ char passname[EXR_PASS_MAXNAME];
+ IMB_exr_add_channel(rl->exrhandle, rl->name, set_pass_name(passname, rpass->name, a, rpass->chan_id), viewname, 0, 0, NULL, false);
+ }
}
else {
float *rect;
int x;
- rpass->rect = MEM_mapallocN(sizeof(float) * rectsize, typestr);
+ rpass->rect = MEM_mapallocN(sizeof(float) * rectsize, name);
if (rpass->rect == NULL) {
MEM_freeN(rpass);
return NULL;
}
- if (passtype == SCE_PASS_VECTOR) {
+ if (STREQ(rpass->name, RE_PASSNAME_VECTOR)) {
/* initialize to max speed */
rect = rpass->rect;
for (x = rectsize - 1; x >= 0; x--)
rect[x] = PASS_VECTOR_MAX;
}
- else if (passtype == SCE_PASS_Z) {
+ else if (STREQ(rpass->name, RE_PASSNAME_Z)) {
rect = rpass->rect;
for (x = rectsize - 1; x >= 0; x--)
rect[x] = 10e10;
@@ -541,57 +250,11 @@ static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int
return rpass;
}
/* wrapper called from render_opengl */
-RenderPass *gp_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype, const char *viewname)
+RenderPass *gp_add_pass(RenderResult *rr, RenderLayer *rl, int channels, const char *name, const char *viewname)
{
- return render_layer_add_pass(rr, rl, channels, passtype, viewname);
+ return render_layer_add_pass(rr, rl, channels, name, viewname, "RGBA");
}
-#ifdef WITH_CYCLES_DEBUG
-const char *RE_debug_pass_name_get(int debug_type)
-{
- switch (debug_type) {
- case RENDER_PASS_DEBUG_BVH_TRAVERSAL_STEPS:
- return "BVH Traversal Steps";
- case RENDER_PASS_DEBUG_BVH_TRAVERSED_INSTANCES:
- return "BVH Traversed Instances";
- case RENDER_PASS_DEBUG_RAY_BOUNCES:
- return "Ray Bounces";
- }
- return "Unknown";
-}
-
-int RE_debug_pass_num_channels_get(int UNUSED(debug_type))
-{
- /* Only single case currently, might be handy for further debug passes. */
- return 1;
-}
-
-static RenderPass *render_layer_add_debug_pass(RenderResult *rr,
- RenderLayer *rl,
- int pass_type,
- int debug_type,
- const char *view)
-{
- const char *name = RE_debug_pass_name_get(debug_type);
- int channels = RE_debug_pass_num_channels_get(debug_type);
- RenderPass *rpass = render_layer_add_pass(rr, rl, channels, pass_type, view);
- if (rpass == NULL) {
- return NULL;
- }
- rpass->debug_type = debug_type;
- BLI_strncpy(rpass->name,
- name,
- sizeof(rpass->name));
- BLI_strncpy(rpass->internal_name, rpass->name, sizeof(rpass->internal_name));
- return rpass;
-}
-
-int RE_debug_pass_type_get(Render *re)
-{
- return re->r.debug_pass_type;
-}
-#endif
-
/* called by main render as well for parts */
/* will read info from Render *re to define layers */
/* called in threads */
@@ -681,89 +344,77 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
if (rr->do_exr_tile)
IMB_exr_add_view(rl->exrhandle, view);
-#define RENDER_LAYER_ADD_PASS_SAFE(rr, rl, channels, passtype, viewname) \
+#define RENDER_LAYER_ADD_PASS_SAFE(rr, rl, channels, name, viewname, chan_id) \
do { \
- if (render_layer_add_pass(rr, rl, channels, passtype, viewname) == NULL) { \
+ if (render_layer_add_pass(rr, rl, channels, name, viewname, chan_id) == NULL) { \
render_result_free(rr); \
return NULL; \
} \
} while (false)
/* a renderlayer should always have a Combined pass*/
- render_layer_add_pass(rr, rl, 4, SCE_PASS_COMBINED, view);
+ render_layer_add_pass(rr, rl, 4, "Combined", view, "RGBA");
if (srl->passflag & SCE_PASS_Z)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, SCE_PASS_Z, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_Z, view, "Z");
if (srl->passflag & SCE_PASS_VECTOR)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 4, SCE_PASS_VECTOR, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 4, RE_PASSNAME_VECTOR, view, "XYZW");
if (srl->passflag & SCE_PASS_NORMAL)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_NORMAL, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_NORMAL, view, "XYZ");
if (srl->passflag & SCE_PASS_UV)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_UV, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_UV, view, "UVA");
if (srl->passflag & SCE_PASS_RGBA)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 4, SCE_PASS_RGBA, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 4, RE_PASSNAME_RGBA, view, "RGBA");
if (srl->passflag & SCE_PASS_EMIT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_EMIT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_EMIT, view, "RGB");
if (srl->passflag & SCE_PASS_DIFFUSE)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_DIFFUSE, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_DIFFUSE, view, "RGB");
if (srl->passflag & SCE_PASS_SPEC)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_SPEC, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SPEC, view, "RGB");
if (srl->passflag & SCE_PASS_AO)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_AO, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_AO, view, "RGB");
if (srl->passflag & SCE_PASS_ENVIRONMENT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_ENVIRONMENT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_ENVIRONMENT, view, "RGB");
if (srl->passflag & SCE_PASS_INDIRECT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_INDIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_INDIRECT, view, "RGB");
if (srl->passflag & SCE_PASS_SHADOW)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_SHADOW, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SHADOW, view, "RGB");
if (srl->passflag & SCE_PASS_REFLECT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_REFLECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_REFLECT, view, "RGB");
if (srl->passflag & SCE_PASS_REFRACT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_REFRACT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_REFRACT, view, "RGB");
if (srl->passflag & SCE_PASS_INDEXOB)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, SCE_PASS_INDEXOB, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_INDEXOB, view, "X");
if (srl->passflag & SCE_PASS_INDEXMA)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, SCE_PASS_INDEXMA, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_INDEXMA, view, "X");
if (srl->passflag & SCE_PASS_MIST)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, SCE_PASS_MIST, view);
+ 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, SCE_PASS_RAYHITS, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 4, RE_PASSNAME_RAYHITS, view, "RGB");
if (srl->passflag & SCE_PASS_DIFFUSE_DIRECT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_DIFFUSE_DIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_DIFFUSE_DIRECT, view, "RGB");
if (srl->passflag & SCE_PASS_DIFFUSE_INDIRECT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_DIFFUSE_INDIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_DIFFUSE_INDIRECT, view, "RGB");
if (srl->passflag & SCE_PASS_DIFFUSE_COLOR)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_DIFFUSE_COLOR, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_DIFFUSE_COLOR, view, "RGB");
if (srl->passflag & SCE_PASS_GLOSSY_DIRECT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_GLOSSY_DIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_GLOSSY_DIRECT, view, "RGB");
if (srl->passflag & SCE_PASS_GLOSSY_INDIRECT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_GLOSSY_INDIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_GLOSSY_INDIRECT, view, "RGB");
if (srl->passflag & SCE_PASS_GLOSSY_COLOR)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_GLOSSY_COLOR, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_GLOSSY_COLOR, view, "RGB");
if (srl->passflag & SCE_PASS_TRANSM_DIRECT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_TRANSM_DIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_TRANSM_DIRECT, view, "RGB");
if (srl->passflag & SCE_PASS_TRANSM_INDIRECT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_TRANSM_INDIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_TRANSM_INDIRECT, view, "RGB");
if (srl->passflag & SCE_PASS_TRANSM_COLOR)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_TRANSM_COLOR, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_TRANSM_COLOR, view, "RGB");
if (srl->passflag & SCE_PASS_SUBSURFACE_DIRECT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_SUBSURFACE_DIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SUBSURFACE_DIRECT, view, "RGB");
if (srl->passflag & SCE_PASS_SUBSURFACE_INDIRECT)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_SUBSURFACE_INDIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SUBSURFACE_INDIRECT, view, "RGB");
if (srl->passflag & SCE_PASS_SUBSURFACE_COLOR)
- RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_SUBSURFACE_COLOR, view);
-
-#ifdef WITH_CYCLES_DEBUG
- if (BKE_scene_use_new_shading_nodes(re->scene)) {
- if (render_layer_add_debug_pass(rr, rl, SCE_PASS_DEBUG,
- re->r.debug_pass_type, view) == NULL)
- {
- render_result_free(rr);
- return NULL;
- }
- }
-#endif
-
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SUBSURFACE_COLOR, view, "RGB");
#undef RENDER_LAYER_ADD_PASS_SAFE
}
}
@@ -792,7 +443,7 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
IMB_exr_add_view(rl->exrhandle, view);
/* a renderlayer should always have a Combined pass */
- render_layer_add_pass(rr, rl, 4, SCE_PASS_COMBINED, view);
+ render_layer_add_pass(rr, rl, 4, RE_PASSNAME_COMBINED, view, "RGBA");
}
/* note, this has to be in sync with scene.c */
@@ -811,6 +462,60 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
return rr;
}
+void render_result_clone_passes(Render *re, RenderResult *rr, const char *viewname)
+{
+ RenderLayer *rl;
+ RenderPass *main_rp;
+
+ for (rl = rr->layers.first; rl; rl = rl->next) {
+ RenderLayer *main_rl = BLI_findstring(&re->result->layers, rl->name, offsetof(RenderLayer, name));
+ if (!main_rl) {
+ continue;
+ }
+
+ for (main_rp = main_rl->passes.first; main_rp; main_rp = main_rp->next) {
+ if (viewname && viewname[0] && !STREQ(main_rp->view, viewname)) {
+ continue;
+ }
+
+ /* Compare fullname to make sure that the view also is equal. */
+ RenderPass *rp = BLI_findstring(&rl->passes, main_rp->fullname, offsetof(RenderPass, fullname));
+ if (!rp) {
+ render_layer_add_pass(rr, rl, main_rp->channels, main_rp->name, main_rp->view, main_rp->chan_id);
+ }
+ }
+ }
+}
+
+void render_result_add_pass(RenderResult *rr, const char *name, int channels, const char *chan_id, const char *layername, const char *viewname)
+{
+ RenderLayer *rl;
+ RenderPass *rp;
+ RenderView *rv;
+
+ for (rl = rr->layers.first; rl; rl = rl->next) {
+ if (layername && layername[0] && !STREQ(rl->name, layername)) {
+ continue;
+ }
+
+ for (rv = rr->views.first; rv; rv = rv->next) {
+ const char *view = rv->name;
+
+ if (viewname && viewname[0] && !STREQ(view, viewname)) continue;
+
+ /* Ensure that the pass doesn't exist yet. */
+ for (rp = rl->passes.first; rp; rp = rp->next) {
+ if (!STREQ(rp->name, name)) continue;
+ if (!STREQ(rp->view, view)) continue;
+ }
+
+ if (!rp) {
+ render_layer_add_pass(rr, rl, channels, name, view, chan_id);
+ }
+ }
+ }
+}
+
/* 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)
{
@@ -828,6 +533,50 @@ RenderResult *render_result_new_full_sample(Render *re, ListBase *lb, rcti *part
return lb->first;
}
+static int passtype_from_name(const char *name)
+{
+ const char delim[] = {'.', '\0'};
+ const char *sep, *suf;
+ int len = BLI_str_partition(name, delim, &sep, &suf);
+
+#define CHECK_PASS(NAME) if (STREQLEN(name, RE_PASSNAME_ ## NAME, len)) return SCE_PASS_ ## NAME
+
+ CHECK_PASS(COMBINED);
+ CHECK_PASS(Z);
+ CHECK_PASS(VECTOR);
+ CHECK_PASS(NORMAL);
+ CHECK_PASS(UV);
+ CHECK_PASS(RGBA);
+ CHECK_PASS(EMIT);
+ CHECK_PASS(DIFFUSE);
+ CHECK_PASS(SPEC);
+ CHECK_PASS(SHADOW);
+ CHECK_PASS(AO);
+ CHECK_PASS(ENVIRONMENT);
+ CHECK_PASS(INDIRECT);
+ CHECK_PASS(REFLECT);
+ CHECK_PASS(REFRACT);
+ CHECK_PASS(INDEXOB);
+ CHECK_PASS(INDEXMA);
+ CHECK_PASS(MIST);
+ CHECK_PASS(RAYHITS);
+ CHECK_PASS(DIFFUSE_DIRECT);
+ CHECK_PASS(DIFFUSE_INDIRECT);
+ CHECK_PASS(DIFFUSE_COLOR);
+ CHECK_PASS(GLOSSY_DIRECT);
+ CHECK_PASS(GLOSSY_INDIRECT);
+ CHECK_PASS(GLOSSY_COLOR);
+ CHECK_PASS(TRANSM_DIRECT);
+ CHECK_PASS(TRANSM_INDIRECT);
+ CHECK_PASS(TRANSM_COLOR);
+ CHECK_PASS(SUBSURFACE_DIRECT);
+ CHECK_PASS(SUBSURFACE_INDIRECT);
+ CHECK_PASS(SUBSURFACE_COLOR);
+
+#undef CHECK_PASS
+ return 0;
+}
+
/* callbacks for render_result_new_from_exr */
static void *ml_addlayer_cb(void *base, const char *str)
{
@@ -841,36 +590,30 @@ static void *ml_addlayer_cb(void *base, const char *str)
return rl;
}
-static void ml_addpass_cb(void *base, void *lay, const char *str, float *rect, int totchan, const char *chan_id, const char *view)
+static void ml_addpass_cb(void *base, void *lay, const char *name, float *rect, int totchan, const char *chan_id, const char *view)
{
RenderResult *rr = base;
RenderLayer *rl = lay;
RenderPass *rpass = MEM_callocN(sizeof(RenderPass), "loaded pass");
- int a;
-
+
BLI_addtail(&rl->passes, rpass);
rpass->channels = totchan;
- rpass->passtype = passtype_from_name(str, rl->passflag);
- if (rpass->passtype == 0)
- printf("unknown pass %s\n", str);
- rl->passflag |= rpass->passtype;
-
+ rl->passflag |= passtype_from_name(name);
+
/* channel id chars */
- for (a = 0; a < totchan; a++)
- rpass->chan_id[a] = chan_id[a];
+ BLI_strncpy(rpass->chan_id, chan_id, sizeof(rpass->chan_id));
rpass->rect = rect;
+ BLI_strncpy(rpass->name, name, EXR_PASS_MAXNAME);
+ BLI_strncpy(rpass->view, view, sizeof(rpass->view));
+ set_pass_full_name(rpass->fullname, name, -1, view, rpass->chan_id);
+
if (view[0] != '\0') {
- BLI_snprintf(rpass->name, sizeof(rpass->name), "%s.%s", str, view);
rpass->view_id = BLI_findstringindex(&rr->views, view, offsetof(RenderView, name));
}
else {
- BLI_strncpy(rpass->name, str, sizeof(rpass->name));
rpass->view_id = 0;
}
-
- BLI_strncpy(rpass->view, view, sizeof(rpass->view));
- BLI_strncpy(rpass->internal_name, str, sizeof(rpass->internal_name));
}
static void *ml_addview_cb(void *base, const char *str)
@@ -910,12 +653,30 @@ static int order_render_passes(const void *a, const void *b)
// 1 if a is after b
RenderPass *rpa = (RenderPass *) a;
RenderPass *rpb = (RenderPass *) b;
+ unsigned int passtype_a = passtype_from_name(rpa->name);
+ unsigned int passtype_b = passtype_from_name(rpb->name);
- if (rpa->passtype > rpb->passtype)
+ /* Render passes with default type always go first. */
+ if (passtype_b && !passtype_a)
return 1;
- else if (rpa->passtype < rpb->passtype)
+ if (passtype_a && !passtype_b)
return 0;
+ if (passtype_a && passtype_b) {
+ if (passtype_a > passtype_b)
+ return 1;
+ else if (passtype_a < passtype_b)
+ return 0;
+ }
+ else {
+ int cmp = strncmp(rpa->name, rpb->name, EXR_PASS_MAXNAME);
+ if (cmp > 0)
+ return 1;
+ if (cmp < 0)
+ return 0;
+ }
+
+
/* they have the same type */
/* left first */
if (STREQ(rpa->view, STEREO_LEFT_NAME))
@@ -1047,7 +808,7 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart)
rpass = rpass->next)
{
/* renderresult have all passes, renderpart only the active view's passes */
- if (strcmp(rpassp->name, rpass->name) != 0)
+ if (strcmp(rpassp->fullname, rpass->fullname) != 0)
continue;
do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, rpass->channels);
@@ -1059,21 +820,6 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart)
}
}
-/* for passes read from files, these have names stored */
-static char *make_pass_name(RenderPass *rpass, int chan)
-{
- static char name[EXR_PASS_MAXNAME];
- int len;
-
- BLI_strncpy(name, rpass->name, EXR_PASS_MAXNAME);
- len = strlen(name);
- name[len] = '.';
- name[len + 1] = rpass->chan_id[chan];
- name[len + 2] = 0;
-
- return name;
-}
-
/* called from within UI and render pipeline, saves both rendered result as a file-read result
* if multiview is true saves all views in a multiview exr
* else if view is not NULL saves single view
@@ -1134,8 +880,10 @@ bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *fil
IMB_exr_add_view(exrhandle, rview->name);
if (rview->rectf) {
+ char passname[EXR_PASS_MAXNAME];
for (a = 0; a < 4; a++) {
- IMB_exr_add_channel(exrhandle, "Composite", name_from_passtype(SCE_PASS_COMBINED, a),
+ set_pass_name(passname, RE_PASSNAME_COMBINED, a, "RGBA");
+ IMB_exr_add_channel(exrhandle, RE_PASSNAME_COMBINED, passname,
chan_view, 4, 4 * width, rview->rectf + a,
use_half_float);
}
@@ -1148,6 +896,7 @@ bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *fil
/* passes are allocated in sync */
for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
const int xstride = rpass->channels;
+ char passname[EXR_PASS_MAXNAME];
if (is_mono) {
if (!STREQ(view, rpass->view)) {
@@ -1161,16 +910,10 @@ bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *fil
}
for (a = 0; a < xstride; a++) {
- if (rpass->passtype) {
- IMB_exr_add_channel(exrhandle, rl->name, name_from_passtype(rpass->passtype, a), chan_view,
- xstride, xstride * width, rpass->rect + a,
- rpass->passtype == SCE_PASS_Z ? false : use_half_float);
- }
- else {
- IMB_exr_add_channel(exrhandle, rl->name, make_pass_name(rpass, a), chan_view,
- xstride, xstride * width, rpass->rect + a,
- use_half_float);
- }
+ set_pass_name(passname, rpass->name, a, rpass->chan_id);
+ IMB_exr_add_channel(exrhandle, rl->name, passname, chan_view,
+ xstride, xstride * width, rpass->rect + a,
+ STREQ(rpass->name, RE_PASSNAME_Z) ? false : use_half_float);
}
}
}
@@ -1279,12 +1022,12 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart, cons
for (rpassp = rlp->passes.first; rpassp; rpassp = rpassp->next) {
const int xstride = rpassp->channels;
int a;
- char passname[EXR_PASS_MAXNAME];
+ char fullname[EXR_PASS_MAXNAME];
for (a = 0; a < xstride; a++) {
- set_pass_name(passname, rpassp->passtype, a, rpassp->view);
+ set_pass_full_name(fullname, rpassp->name, a, viewname, rpassp->chan_id);
- IMB_exr_set_channel(rl->exrhandle, rlp->name, passname,
+ IMB_exr_set_channel(rl->exrhandle, rlp->name, fullname,
xstride, xstride * rrpart->rectx, rpassp->rect + a + xstride * offs);
}
}
@@ -1447,15 +1190,15 @@ int render_result_exr_file_read_path(RenderResult *rr, RenderLayer *rl_single, c
for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
const int xstride = rpass->channels;
int a;
- char passname[EXR_PASS_MAXNAME];
+ char fullname[EXR_PASS_MAXNAME];
for (a = 0; a < xstride; a++) {
- set_pass_name(passname, rpass->passtype, a, rpass->view);
- IMB_exr_set_channel(exrhandle, rl->name, passname,
+ set_pass_full_name(fullname, rpass->name, a, rpass->view, rpass->chan_id);
+ IMB_exr_set_channel(exrhandle, rl->name, fullname,
xstride, xstride * rectx, rpass->rect + a);
}
- set_pass_name(rpass->name, rpass->passtype, -1, rpass->view);
+ set_pass_full_name(rpass->fullname, rpass->name, -1, rpass->view, rpass->chan_id);
}
}
@@ -1665,3 +1408,84 @@ RenderView *RE_RenderViewGetByName(RenderResult *res, const char *viewname)
BLI_assert(res->views.first);
return rv ? rv : res->views.first;
}
+
+static RenderPass *duplicate_render_pass(RenderPass *rpass)
+{
+ RenderPass *new_rpass = MEM_mallocN(sizeof(RenderPass), "new render pass");
+ *new_rpass = *rpass;
+ new_rpass->next = new_rpass->prev = NULL;
+ if (new_rpass->rect != NULL) {
+ new_rpass->rect = MEM_dupallocN(new_rpass->rect);
+ }
+ return new_rpass;
+}
+
+static RenderLayer *duplicate_render_layer(RenderLayer *rl)
+{
+ RenderLayer *new_rl = MEM_mallocN(sizeof(RenderLayer), "new render layer");
+ *new_rl = *rl;
+ new_rl->next = new_rl->prev = NULL;
+ new_rl->passes.first = new_rl->passes.last = NULL;
+ new_rl->exrhandle = NULL;
+ if (new_rl->acolrect != NULL) {
+ new_rl->acolrect = MEM_dupallocN(new_rl->acolrect);
+ }
+ if (new_rl->scolrect != NULL) {
+ new_rl->scolrect = MEM_dupallocN(new_rl->scolrect);
+ }
+ if (new_rl->display_buffer != NULL) {
+ new_rl->display_buffer = MEM_dupallocN(new_rl->display_buffer);
+ }
+ for (RenderPass *rpass = rl->passes.first; rpass != NULL; rpass = rpass->next) {
+ RenderPass *new_rpass = duplicate_render_pass(rpass);
+ BLI_addtail(&new_rl->passes, new_rpass);
+ }
+ return new_rl;
+}
+
+static RenderView *duplicate_render_view(RenderView *rview)
+{
+ RenderView *new_rview = MEM_mallocN(sizeof(RenderView), "new render view");
+ *new_rview = *rview;
+ if (new_rview->rectf != NULL) {
+ new_rview->rectf = MEM_dupallocN(new_rview->rectf);
+ }
+ if (new_rview->rectf != NULL) {
+ new_rview->rectf = MEM_dupallocN(new_rview->rectf);
+ }
+ if (new_rview->rectz != NULL) {
+ new_rview->rectz = MEM_dupallocN(new_rview->rectz);
+ }
+ if (new_rview->rect32 != NULL) {
+ new_rview->rect32 = MEM_dupallocN(new_rview->rect32);
+ }
+ return new_rview;
+}
+
+RenderResult *RE_DuplicateRenderResult(RenderResult *rr)
+{
+ RenderResult *new_rr = MEM_mallocN(sizeof(RenderResult), "new duplicated render result");
+ *new_rr = *rr;
+ new_rr->next = new_rr->prev = NULL;
+ new_rr->layers.first = new_rr->layers.last = NULL;
+ new_rr->views.first = new_rr->views.last = NULL;
+ for (RenderLayer *rl = rr->layers.first; rl != NULL; rl = rl->next) {
+ RenderLayer *new_rl = duplicate_render_layer(rl);
+ BLI_addtail(&new_rr->layers, new_rl);
+ }
+ for (RenderView *rview = rr->views.first; rview != NULL; rview = rview->next) {
+ RenderView *new_rview = duplicate_render_view(rview);
+ BLI_addtail(&new_rr->views, new_rview);
+ }
+ if (new_rr->rect32 != NULL) {
+ new_rr->rect32 = MEM_dupallocN(new_rr->rect32);
+ }
+ if (new_rr->rectf != NULL) {
+ new_rr->rectf = MEM_dupallocN(new_rr->rectf);
+ }
+ if (new_rr->rectz != NULL) {
+ new_rr->rectz = MEM_dupallocN(new_rr->rectz);
+ }
+ new_rr->stamp_data = MEM_dupallocN(new_rr->stamp_data);
+ return new_rr;
+}
diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c
index b4a14f5337d..22dc2b28900 100644
--- a/source/blender/render/intern/source/render_texture.c
+++ b/source/blender/render/intern/source/render_texture.c
@@ -1112,14 +1112,15 @@ static int multitex(Tex *tex,
const short which_output,
struct ImagePool *pool,
const bool skip_load_image,
- const bool texnode_preview)
+ const bool texnode_preview,
+ const bool use_nodes)
{
float tmpvec[3];
int retval = 0; /* return value, int:0, col:1, nor:2, everything:3 */
texres->talpha = false; /* is set when image texture returns alpha (considered premul) */
- if (tex->use_nodes && tex->nodetree) {
+ if (use_nodes && tex->use_nodes && tex->nodetree) {
retval = ntreeTexExecTree(tex->nodetree, texres, texvec, dxt, dyt, osatex, thread,
tex, which_output, R.r.cfra, texnode_preview, NULL, NULL);
}
@@ -1239,7 +1240,8 @@ static int multitex_nodes_intern(Tex *tex,
ImagePool *pool,
const bool scene_color_manage,
const bool skip_load_image,
- const bool texnode_preview)
+ const bool texnode_preview,
+ const bool use_nodes)
{
if (tex==NULL) {
memset(texres, 0, sizeof(TexResult));
@@ -1264,7 +1266,8 @@ static int multitex_nodes_intern(Tex *tex,
which_output,
pool,
skip_load_image,
- texnode_preview);
+ texnode_preview,
+ use_nodes);
if (mtex->mapto & (MAP_COL+MAP_COLSPEC+MAP_COLMIR)) {
ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool);
@@ -1311,7 +1314,8 @@ static int multitex_nodes_intern(Tex *tex,
which_output,
pool,
skip_load_image,
- texnode_preview);
+ texnode_preview,
+ use_nodes);
{
ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool);
@@ -1341,7 +1345,8 @@ static int multitex_nodes_intern(Tex *tex,
which_output,
pool,
skip_load_image,
- texnode_preview);
+ texnode_preview,
+ use_nodes);
}
}
@@ -1354,7 +1359,8 @@ int multitex_nodes(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int os
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);
+ (R.r.scemode & R_TEXNODE_PREVIEW) != 0,
+ true);
}
/* this is called for surface shading */
@@ -1378,7 +1384,8 @@ static int multitex_mtex(ShadeInput *shi, MTex *mtex, float texvec[3], float dxt
mtex->which_output,
pool,
skip_load_image,
- (R.r.scemode & R_TEXNODE_PREVIEW) != 0);
+ (R.r.scemode & R_TEXNODE_PREVIEW) != 0,
+ true);
}
}
@@ -1408,7 +1415,8 @@ int multitex_ext(Tex *tex,
pool,
scene_color_manage,
skip_load_image,
- false);
+ false,
+ true);
}
/* extern-tex doesn't support nodes (ntreeBeginExec() can't be called when rendering is going on)\
@@ -1417,13 +1425,19 @@ int multitex_ext(Tex *tex,
*/
int multitex_ext_safe(Tex *tex, float texvec[3], TexResult *texres, struct ImagePool *pool, bool scene_color_manage, const bool skip_load_image)
{
- int use_nodes= tex->use_nodes, retval;
-
- tex->use_nodes = false;
- retval= multitex_nodes_intern(tex, texvec, NULL, NULL, 0, texres, 0, 0, NULL, NULL, pool, scene_color_manage, skip_load_image, false);
- tex->use_nodes= use_nodes;
-
- return retval;
+ return multitex_nodes_intern(tex,
+ texvec,
+ NULL, NULL,
+ 0,
+ texres,
+ 0,
+ 0,
+ NULL, NULL,
+ pool,
+ scene_color_manage,
+ skip_load_image,
+ false,
+ false);
}
@@ -1481,6 +1495,7 @@ void texture_rgb_blend(float in[3], const float tex[3], const float out[3], floa
case MTEX_SUB:
fact= -fact;
+ ATTR_FALLTHROUGH;
case MTEX_ADD:
fact*= facg;
in[0]= (fact*tex[0] + out[0]);
@@ -1595,6 +1610,7 @@ float texture_value_blend(float tex, float out, float fact, float facg, int blen
case MTEX_SUB:
fact= -fact;
+ ATTR_FALLTHROUGH;
case MTEX_ADD:
in= fact*tex + out;
break;
@@ -2873,7 +2889,8 @@ void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_
mtex->which_output,
re->pool,
skip_load_image,
- texnode_preview); /* NULL = dxt/dyt, 0 = shi->osatex - not supported */
+ texnode_preview,
+ true); /* NULL = dxt/dyt, 0 = shi->osatex - not supported */
/* texture output */
@@ -3051,7 +3068,8 @@ void do_halo_tex(HaloRen *har, float xn, float yn, float col_r[4])
mtex->which_output,
har->pool,
skip_load_image,
- texnode_preview);
+ texnode_preview,
+ true);
/* texture output */
if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
@@ -3274,7 +3292,8 @@ void do_sky_tex(
mtex->which_output,
R.pool,
skip_load_image,
- texnode_preview);
+ texnode_preview,
+ true);
/* texture output */
if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
@@ -3500,7 +3519,8 @@ void do_lamp_tex(LampRen *la, const float lavec[3], ShadeInput *shi, float col_r
mtex->which_output,
R.pool,
skip_load_image,
- texnode_preview);
+ texnode_preview,
+ true);
/* texture output */
if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
@@ -3614,7 +3634,8 @@ int externtex(MTex *mtex,
mtex->which_output,
pool,
skip_load_image,
- texnode_preview);
+ texnode_preview,
+ true);
if (rgb) {
texr.tin = IMB_colormanagement_get_luminance(&texr.tr);
diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c
index 910ea16607e..77f399d08d1 100644
--- a/source/blender/render/intern/source/rendercore.c
+++ b/source/blender/render/intern/source/rendercore.c
@@ -180,11 +180,12 @@ static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, in
flarec= 0;
if (fullsample) {
- for (sample=0; sample<totsample; sample++)
+ for (sample=0; sample<totsample; sample++) {
if (ps->mask & (1 << sample)) {
- float *pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ 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;
@@ -215,11 +216,12 @@ static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, in
}
if (fullsample) {
- for (sample=0; sample<totsample; sample++)
+ for (sample=0; sample<totsample; sample++) {
if (!(mask & (1 << sample))) {
- float *pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ float *pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
addalphaAddfacFloat(pass + od*4, col, har->add);
}
+ }
}
else {
col[0]= accol[0];
@@ -228,7 +230,7 @@ static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, in
col[3]= accol[3];
for (sample=0; sample<totsample; sample++) {
- float *pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ float *pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
addalphaAddfacFloat(pass + od*4, col, har->add);
}
}
@@ -312,7 +314,7 @@ static void halo_tile(RenderPart *pa, RenderLayer *rl)
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], SCE_PASS_COMBINED, R.viewname);
+ float * rect= RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
addalphaAddfacFloat(rect + od*4, col, har->add);
}
}
@@ -367,7 +369,7 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
if (fullsample) {
for (sample=0; sample<totsample; sample++) {
if (ps->mask & (1 << sample)) {
- pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
pass += od * 4;
pass[0]+= col[0];
pass[1]+= col[1];
@@ -379,7 +381,7 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
}
else {
fac= ((float)count)/(float)R.osa;
- pass = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname);
+ pass = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
pass += od * 4;
pass[0]+= fac*col[0];
pass[1]+= fac*col[1];
@@ -401,7 +403,7 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
for (sample=0; sample<totsample; sample++) {
if (!(mask & (1 << sample))) {
- pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
pass += od * 4;
pass[0]+= col[0];
pass[1]+= col[1];
@@ -413,7 +415,7 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
}
else {
fac= ((float)R.osa-totsamp)/(float)R.osa;
- pass = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname);
+ pass = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
pass += od * 4;
pass[0]+= fac*col[0];
pass[1]+= fac*col[1];
@@ -433,7 +435,7 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
renderspothalo(&shi, col, 1.0f);
for (sample=0; sample<totsample; sample++) {
- pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
pass += od * 4;
pass[0]+= col[0];
pass[1]+= col[1];
@@ -462,101 +464,96 @@ static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset,
float *fp, *col= NULL;
int pixsize= 3;
- switch (rpass->passtype) {
- case SCE_PASS_COMBINED:
- add_filt_fmask(curmask, shr->combined, rpass->rect + 4*offset, rectx);
- break;
- case SCE_PASS_Z:
- fp= rpass->rect + offset;
- *fp= shr->z;
- break;
- case SCE_PASS_RGBA:
- col= shr->col;
- pixsize= 4;
- break;
- case SCE_PASS_EMIT:
- col= shr->emit;
- break;
- case SCE_PASS_DIFFUSE:
- col= shr->diff;
- break;
- case SCE_PASS_SPEC:
- col= shr->spec;
- break;
- case SCE_PASS_SHADOW:
- col= shr->shad;
- break;
- case SCE_PASS_AO:
- col= shr->ao;
- break;
- case SCE_PASS_ENVIRONMENT:
- col= shr->env;
- break;
- case SCE_PASS_INDIRECT:
- col= shr->indirect;
- break;
- case SCE_PASS_REFLECT:
- col= shr->refl;
- break;
- case SCE_PASS_REFRACT:
- col= shr->refr;
- break;
- case SCE_PASS_NORMAL:
- col= shr->nor;
- break;
- case SCE_PASS_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;
- }
- break;
- case SCE_PASS_INDEXOB:
- /* no filter */
- if (shi->vlr) {
- fp= rpass->rect + offset;
+ 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->obr->ob->index;
- }
- break;
- case SCE_PASS_INDEXMA:
- /* no filter */
- if (shi->vlr) {
- fp= rpass->rect + offset;
- if (*fp==0.0f)
- *fp= (float)shi->mat->index;
- }
- break;
- case SCE_PASS_MIST:
- /* */
- col= &shr->mist;
- pixsize= 1;
- break;
-
- case SCE_PASS_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];
- }
-
- break;
+ *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];
}
- case SCE_PASS_RAYHITS:
- /* */
- col= shr->rayhits;
- pixsize= 4;
- break;
}
+ 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);
@@ -574,86 +571,85 @@ static void add_passes(RenderLayer *rl, int offset, ShadeInput *shi, ShadeResult
float *col= NULL, uvcol[3];
int a, pixsize= 3;
- switch (rpass->passtype) {
- case SCE_PASS_COMBINED:
- /* copy combined to use for preview */
- copy_v4_v4(rpass->rect + 4*offset, shr->combined);
- break;
- case SCE_PASS_Z:
- fp= rpass->rect + offset;
- *fp= shr->z;
- break;
- case SCE_PASS_RGBA:
- col= shr->col;
- pixsize= 4;
- break;
- case SCE_PASS_EMIT:
- col= shr->emit;
- break;
- case SCE_PASS_DIFFUSE:
- col= shr->diff;
- break;
- case SCE_PASS_SPEC:
- col= shr->spec;
- break;
- case SCE_PASS_SHADOW:
- col= shr->shad;
- break;
- case SCE_PASS_AO:
- col= shr->ao;
- break;
- case SCE_PASS_ENVIRONMENT:
- col= shr->env;
- break;
- case SCE_PASS_INDIRECT:
- col= shr->indirect;
- break;
- case SCE_PASS_REFLECT:
- col= shr->refl;
- break;
- case SCE_PASS_REFRACT:
- col= shr->refr;
- break;
- case SCE_PASS_NORMAL:
- col= shr->nor;
- break;
- case SCE_PASS_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;
- }
- break;
- case SCE_PASS_VECTOR:
- col= shr->winspeed;
- pixsize= 4;
- break;
- case SCE_PASS_INDEXOB:
- if (shi->vlr) {
- fp= rpass->rect + offset;
- *fp= (float)shi->obr->ob->index;
- }
- break;
- case SCE_PASS_INDEXMA:
- if (shi->vlr) {
- fp= rpass->rect + offset;
- *fp= (float)shi->mat->index;
- }
- break;
- case SCE_PASS_MIST:
- fp= rpass->rect + offset;
- *fp= shr->mist;
- break;
- case SCE_PASS_RAYHITS:
- col= shr->rayhits;
- pixsize= 4;
- break;
+ 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;
+ fp = rpass->rect + pixsize*offset;
for (a=0; a<pixsize; a++)
- fp[a]= col[a];
+ fp[a] = col[a];
}
}
}
@@ -696,7 +692,7 @@ static void sky_tile(RenderPart *pa, RenderLayer *rl)
bool done = false;
for (sample= 0; sample<totsample; sample++) {
- float *pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ float *pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
pass += od;
if (pass[3]<1.0f) {
@@ -737,7 +733,7 @@ static void atm_tile(RenderPart *pa, RenderLayer *rl)
/* check that z pass is enabled */
if (pa->rectz==NULL) return;
for (zpass= rl->passes.first; zpass; zpass= zpass->next)
- if (zpass->passtype==SCE_PASS_Z)
+ if (STREQ(zpass->name, RE_PASSNAME_Z))
break;
if (zpass==NULL) return;
@@ -758,8 +754,8 @@ static void atm_tile(RenderPart *pa, RenderLayer *rl)
int sample;
for (sample=0; sample<totsample; sample++) {
- const float *zrect = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_Z, R.viewname) + od;
- float *rgbrect = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname) + 4*od;
+ 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;
@@ -994,7 +990,7 @@ static void clamp_alpha_rgb_range(RenderPart *pa, RenderLayer *rl)
return;
for (sample= 0; sample<totsample; sample++) {
- float *rectf = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ 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);
@@ -1076,7 +1072,7 @@ static void reset_sky_speed(RenderPart *pa, RenderLayer *rl)
totsample= get_sample_layers(pa, rl, rlpp);
for (sample= 0; sample<totsample; sample++) {
- fp= RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_VECTOR, R.viewname);
+ 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--)
@@ -1187,7 +1183,7 @@ void zbufshadeDA_tile(RenderPart *pa)
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, SCE_PASS_COMBINED, R.viewname);
+ 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");
@@ -1339,7 +1335,7 @@ void zbufshade_tile(RenderPart *pa)
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, SCE_PASS_COMBINED, R.viewname);
+ 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");
@@ -1676,7 +1672,7 @@ void zbufshade_sss_tile(RenderPart *pa)
return;
}
- fcol= RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname);
+ 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");
@@ -1969,7 +1965,7 @@ void add_halo_flare(Render *re)
if ((rl->layflag & SCE_LAY_HALO) == 0)
continue;
- rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, re->viewname);
+ rect = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, re->viewname);
if (rect==NULL)
continue;
@@ -1998,3 +1994,37 @@ void add_halo_flare(Render *re)
}
}
+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
index 76e6ca8d467..199322795f3 100644
--- a/source/blender/render/intern/source/renderdatabase.c
+++ b/source/blender/render/intern/source/renderdatabase.c
@@ -66,6 +66,7 @@
#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"
@@ -1458,6 +1459,14 @@ ObjectInstanceRen *RE_addRenderInstance(
}
}
+ /* 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) {
diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c
index 20602314526..597a2338fe7 100644
--- a/source/blender/render/intern/source/shadeinput.c
+++ b/source/blender/render/intern/source/shadeinput.c
@@ -442,7 +442,7 @@ void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert
}
}
- if ((texco & TEXCO_UV) || (mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE))) {
+ if ((texco & TEXCO_UV) || (mode & (MA_VERTEXCOL | MA_VERTEXCOLP))) {
MCol *mcol;
const float *uv;
char *name;
@@ -504,15 +504,6 @@ void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert
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) {
@@ -521,14 +512,6 @@ void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert
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;
- }
}
}
@@ -570,7 +553,7 @@ void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert
}
if (shi->do_manage) {
- if (mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE)) {
+ if (mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) {
srgb_to_linearrgb_v3_v3(shi->vcol, shi->vcol);
}
}
@@ -1076,7 +1059,7 @@ void shade_input_set_shade_texco(ShadeInput *shi)
}
}
- if ((texco & TEXCO_UV) || (mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE)) || (R.flag & R_NEED_VCOL)) {
+ if ((texco & TEXCO_UV) || (mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) || (R.flag & R_NEED_VCOL)) {
VlakRen *vlr = shi->vlr;
MTFace *tface;
MCol *mcol;
@@ -1231,18 +1214,6 @@ void shade_input_set_shade_texco(ShadeInput *shi)
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);
- }
- }
}
}
@@ -1256,14 +1227,6 @@ void shade_input_set_shade_texco(ShadeInput *shi)
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;
- }
}
}
@@ -1319,7 +1282,7 @@ void shade_input_set_shade_texco(ShadeInput *shi)
* else un-initialized values are used
*/
if (shi->do_manage) {
- if ((mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE)) || (R.flag & R_NEED_VCOL)) {
+ if ((mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) || (R.flag & R_NEED_VCOL)) {
srgb_to_linearrgb_v3_v3(shi->vcol, shi->vcol);
}
}
diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c
index 9dec2698720..c5a666d52c9 100644
--- a/source/blender/render/intern/source/shadeoutput.c
+++ b/source/blender/render/intern/source/shadeoutput.c
@@ -899,14 +899,7 @@ 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)) {
+ 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];
@@ -1764,12 +1757,8 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
/* 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];
+ if (false) {
+ /* pass */
}
#ifdef WITH_FREESTYLE
else if (ma->vcol_alpha) {
@@ -2064,11 +2053,13 @@ static float lamp_get_data_internal(ShadeInput *shi, GroupObject *go, float col[
if (lar->mode & LA_SHAD_TEX)
do_lamp_tex(lar, lv, shi, shadow, LA_SHAD_TEX);
- lamp_get_shadow(lar, shi, inp, shadfac, shi->depth);
+ 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]));
+ 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;
@@ -2139,9 +2130,19 @@ const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int m
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) {
+ switch (matrix_id) {
case RE_VIEW_MATRIX:
return (const float(*)[4])R.viewmat;
case RE_VIEWINV_MATRIX:
@@ -2149,3 +2150,24 @@ const float (*RE_render_current_get_matrix(int matrix_id))[4]
}
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/sunsky.c b/source/blender/render/intern/source/sunsky.c
index d4e53eb7305..f0cf29e98ca 100644
--- a/source/blender/render/intern/source/sunsky.c
+++ b/source/blender/render/intern/source/sunsky.c
@@ -398,7 +398,7 @@ void InitAtmosphere(struct SunSky *sunSky, float sun_intens, float mief, float r
vLambda2[0] = fLambda2[0];
vLambda2[1] = fLambda2[1];
vLambda2[2] = fLambda2[2];
-
+
vLambda4[0] = fLambda4[0];
vLambda4[1] = fLambda4[1];
vLambda4[2] = fLambda4[2];
diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c
index 5377d0eba00..752a9df0b79 100644
--- a/source/blender/render/intern/source/volume_precache.c
+++ b/source/blender/render/intern/source/volume_precache.c
@@ -60,6 +60,8 @@
#include "volumetric.h"
#include "volume_precache.h"
+#include "atomic_ops.h"
+
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
@@ -509,7 +511,8 @@ static void *vol_precache_part_test(void *data)
*/
typedef struct VolPrecacheState {
double lasttime;
- int totparts;
+ unsigned int doneparts;
+ unsigned int totparts;
} VolPrecacheState;
static void vol_precache_part(TaskPool * __restrict pool, void *taskdata, int UNUSED(threadid))
@@ -574,13 +577,15 @@ static void vol_precache_part(TaskPool * __restrict pool, void *taskdata, int UN
}
}
+ 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)BLI_task_pool_tasks_done(pool)/(float)state->totparts;
+ 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);
@@ -631,6 +636,7 @@ static void precache_launch_parts(Render *re, RayObject *tree, ShadeInput *shi,
/* 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();
diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c
index 610e86caa13..7fe52328781 100644
--- a/source/blender/render/intern/source/volumetric.c
+++ b/source/blender/render/intern/source/volumetric.c
@@ -275,10 +275,12 @@ static float metadensity(Object *ob, const float co[3])
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 */
+ /* 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 */
+ /* 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);
}
diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c
index 9f777631e52..68707f163af 100644
--- a/source/blender/render/intern/source/zbuf.c
+++ b/source/blender/render/intern/source/zbuf.c
@@ -1601,7 +1601,6 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float *
* Note: uses globals.
* \param v1 start coordinate s
* \param v2 target coordinate t
- * \param b1
* \param b2
* \param b3
* \param a index for coordinate (x, y, or z)
@@ -3494,7 +3493,7 @@ static void add_transp_speed(RenderLayer *rl, int offset, float speed[4], float
RenderPass *rpass;
for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
- if (rpass->passtype==SCE_PASS_VECTOR) {
+ if (STREQ(rpass->name, RE_PASSNAME_VECTOR)) {
float *fp= rpass->rect + 4*offset;
if (speed==NULL) {
@@ -3528,7 +3527,7 @@ static void add_transp_obindex(RenderLayer *rl, int offset, Object *ob)
RenderPass *rpass;
for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
- if (rpass->passtype == SCE_PASS_INDEXOB) {
+ if (STREQ(rpass->name, RE_PASSNAME_INDEXOB)) {
float *fp= rpass->rect + offset;
*fp= (float)ob->index;
break;
@@ -3541,7 +3540,7 @@ static void add_transp_material_index(RenderLayer *rl, int offset, Material *mat
RenderPass *rpass;
for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
- if (rpass->passtype == SCE_PASS_INDEXMA) {
+ if (STREQ(rpass->name, RE_PASSNAME_INDEXMA)) {
float *fp= rpass->rect + offset;
*fp= (float)mat->index;
break;
@@ -3558,78 +3557,74 @@ static void merge_transp_passes(RenderLayer *rl, ShadeResult *shr)
int delta= sizeof(ShadeResult)/4;
for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
- float *col= NULL;
- int pixsize= 3;
+ float *col = NULL;
+ int pixsize = 3;
- switch (rpass->passtype) {
- case SCE_PASS_RGBA:
- col= shr->col;
- pixsize= 4;
- break;
- case SCE_PASS_EMIT:
- col= shr->emit;
- break;
- case SCE_PASS_DIFFUSE:
- col= shr->diff;
- break;
- case SCE_PASS_SPEC:
- col= shr->spec;
- break;
- case SCE_PASS_SHADOW:
- col= shr->shad;
- break;
- case SCE_PASS_AO:
- col= shr->ao;
- break;
- case SCE_PASS_ENVIRONMENT:
- col= shr->env;
- break;
- case SCE_PASS_INDIRECT:
- col= shr->indirect;
- break;
- case SCE_PASS_REFLECT:
- col= shr->refl;
- break;
- case SCE_PASS_REFRACT:
- col= shr->refr;
- break;
- case SCE_PASS_NORMAL:
- col= shr->nor;
- break;
- case SCE_PASS_MIST:
- col= &shr->mist;
- pixsize= 1;
- break;
- case SCE_PASS_Z:
- col= &shr->z;
- pixsize= 1;
- break;
- case SCE_PASS_VECTOR:
+ 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++) {
- {
- ShadeResult *shr_t= shr+1;
- float *fp= shr->winspeed; /* was initialized */
- int samp;
+ if (shr_t->combined[3] > 0.0f) {
+ const float *speed = shr_t->winspeed;
- /* 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 ( (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;
+ }
}
+
if (col) {
const float *fp= col+delta;
int samp;
@@ -3661,53 +3656,51 @@ static void add_transp_passes(RenderLayer *rl, int offset, ShadeResult *shr, flo
float *fp, *col= NULL;
int pixsize= 3;
- switch (rpass->passtype) {
- case SCE_PASS_Z:
- fp= rpass->rect + offset;
- if (shr->z < *fp)
- *fp= shr->z;
- break;
- case SCE_PASS_RGBA:
- fp= rpass->rect + 4*offset;
- addAlphaOverFloat(fp, shr->col);
- break;
- case SCE_PASS_EMIT:
- col= shr->emit;
- break;
- case SCE_PASS_DIFFUSE:
- col= shr->diff;
- break;
- case SCE_PASS_SPEC:
- col= shr->spec;
- break;
- case SCE_PASS_SHADOW:
- col= shr->shad;
- break;
- case SCE_PASS_AO:
- col= shr->ao;
- break;
- case SCE_PASS_ENVIRONMENT:
- col= shr->env;
- break;
- case SCE_PASS_INDIRECT:
- col= shr->indirect;
- break;
- case SCE_PASS_REFLECT:
- col= shr->refl;
- break;
- case SCE_PASS_REFRACT:
- col= shr->refr;
- break;
- case SCE_PASS_NORMAL:
- col= shr->nor;
- break;
- case SCE_PASS_MIST:
- col= &shr->mist;
- pixsize= 1;
- break;
+ 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) {
+ if (col) {
fp= rpass->rect + pixsize*offset;
fp[0]= col[0] + (1.0f-alpha)*fp[0];
if (pixsize==3) {
@@ -3964,7 +3957,7 @@ static void reset_sky_speedvectors(RenderPart *pa, RenderLayer *rl, float *rectf
float *fp, *col;
int a;
- fp = RE_RenderLayerGetPass(rl, SCE_PASS_VECTOR, R.viewname);
+ fp = RE_RenderLayerGetPass(rl, RE_PASSNAME_VECTOR, R.viewname);
if (fp==NULL) return;
col= rectf+3;
@@ -4058,7 +4051,7 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas
/* zero alpha pixels get speed vector max again */
if (addpassflag & SCE_PASS_VECTOR)
if (rl->layflag & SCE_LAY_SOLID) {
- float *rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname);
+ 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 */
@@ -4246,7 +4239,7 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas
if (alpha != 0.0f) {
RenderLayer *rl_other = ssamp.rlpp[a];
- float *rect = RE_RenderLayerGetPass(rl_other , SCE_PASS_COMBINED, R.viewname);
+ 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);
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index 01188cb7f65..cfa97a9e177 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -25,12 +25,15 @@
set(INC
.
+ manipulators
+ manipulators/intern
../blenfont
../blenkernel
../blenlib
../blenloader
../blentranslation
../compositor
+ ../depsgraph
../editors/include
../gpu
../imbuf
@@ -68,6 +71,12 @@ set(SRC
intern/wm_subwindow.c
intern/wm_window.c
intern/wm_stereo.c
+ manipulators/intern/wm_manipulator.c
+ manipulators/intern/wm_manipulator_group.c
+ manipulators/intern/wm_manipulator_group_type.c
+ manipulators/intern/wm_manipulator_map.c
+ manipulators/intern/wm_manipulator_target_props.c
+ manipulators/intern/wm_manipulator_type.c
WM_api.h
WM_keymap.h
@@ -80,6 +89,11 @@ set(SRC
wm_files.h
wm_subwindow.h
wm_window.h
+ manipulators/WM_manipulator_api.h
+ manipulators/WM_manipulator_types.h
+ manipulators/wm_manipulator_fn.h
+ manipulators/wm_manipulator_wmapi.h
+ manipulators/intern/wm_manipulator_intern.h
)
if(WITH_AUDASPACE)
@@ -128,10 +142,6 @@ if(WITH_PYTHON)
../python
)
add_definitions(-DWITH_PYTHON)
-
- if(WITH_PYTHON_SECURITY)
- add_definitions(-DWITH_PYTHON_SECURITY)
- endif()
endif()
if(WITH_GAMEENGINE)
@@ -146,6 +156,10 @@ if(WITH_OPENSUBDIV)
add_definitions(-DWITH_OPENSUBDIV)
endif()
+if(WITH_INPUT_NDOF)
+ add_definitions(-DWITH_INPUT_NDOF)
+endif()
+
if(WIN32)
if(WITH_INPUT_IME)
add_definitions(-DWITH_INPUT_IME)
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 69905fc296b..a8c67a296af 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -42,6 +42,9 @@
#include "WM_keymap.h"
#include "BLI_compiler_attrs.h"
+/* Include external manipulator API's */
+#include "manipulators/WM_manipulator_api.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -64,9 +67,16 @@ struct wmDrag;
struct ImBuf;
struct ImageFormatData;
struct ARegion;
+struct ScrArea;
+
+#ifdef WITH_INPUT_NDOF
struct wmNDOFMotionData;
+#endif
typedef struct wmJob wmJob;
+typedef struct wmManipulator wmManipulator;
+typedef struct wmManipulatorMap wmManipulatorMap;
+typedef struct wmManipulatorMapType wmManipulatorMapType;
/* general API */
void WM_init_state_size_set (int stax, int stay, int sizx, int sizy);
@@ -91,6 +101,21 @@ int WM_window_pixels_x (struct wmWindow *win);
int WM_window_pixels_y (struct wmWindow *win);
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 Scene *WM_window_get_active_scene(const struct wmWindow *win) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+void WM_window_change_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 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);
+bool WM_window_is_temp_screen(const struct wmWindow *win) ATTR_WARN_UNUSED_RESULT;
+
/* defines for 'type' WM_window_open_temp */
enum {
WM_WINDOW_RENDER = 1,
@@ -99,7 +124,8 @@ enum {
};
struct wmWindow *WM_window_open(struct bContext *C, const struct rcti *rect);
-struct wmWindow *WM_window_open_temp(struct bContext *C, const struct rcti *rect_init, int type);
+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);
@@ -168,6 +194,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 */
@@ -186,9 +215,10 @@ void WM_event_add_mousemove(struct bContext *C);
bool WM_modal_tweak_exit(const struct wmEvent *event, int tweak_event);
bool WM_event_is_absolute(const struct wmEvent *event);
+#ifdef WITH_INPUT_NDOF
/* 3D mouse */
void WM_ndof_deadzone_set(float deadzone);
-
+#endif
/* notifiers */
void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference);
void WM_main_add_notifier(unsigned int type, void *reference);
@@ -224,6 +254,7 @@ void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op
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);
+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);
@@ -248,6 +279,7 @@ int WM_operator_confirm_message(struct bContext *C, struct wmOperator *o
/* operator api */
void WM_operator_free (struct wmOperator *op);
+void WM_operator_free_all_after(wmWindowManager *wm, struct wmOperator *op);
void WM_operator_type_set(struct wmOperator *op, struct wmOperatorType *ot);
void WM_operator_stack_clear(struct wmWindowManager *wm);
void WM_operator_handlers_clear(wmWindowManager *wm, struct wmOperatorType *ot);
@@ -272,6 +304,7 @@ int WM_operator_call (struct bContext *C, struct wmOperator *op);
int WM_operator_call_notest(struct bContext *C, struct wmOperator *op);
int WM_operator_repeat (struct bContext *C, struct wmOperator *op);
bool WM_operator_repeat_check(const struct bContext *C, struct wmOperator *op);
+bool WM_operator_is_repeat(const struct bContext *C, const struct wmOperator *op);
int WM_operator_name_call_ptr(struct bContext *C, struct wmOperatorType *ot, short context, struct PointerRNA *properties);
int WM_operator_name_call(struct bContext *C, const char *opstring, short context, struct PointerRNA *properties);
int WM_operator_call_py(struct bContext *C, struct wmOperatorType *ot, short context, struct PointerRNA *properties, struct ReportList *reports, const bool is_undo);
@@ -405,9 +438,7 @@ ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid);
void wmSubWindowSet (struct wmWindow *win, int swinid);
void wmSubWindowScissorSet (struct wmWindow *win, int swinid, const struct rcti *srct, bool srct_pad);
- /* 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);
@@ -498,11 +529,13 @@ bool write_crash_blend(void);
/* Lock the interface for any communication */
void WM_set_locked_interface(struct wmWindowManager *wm, bool lock);
+#ifdef WITH_INPUT_NDOF
void WM_event_ndof_pan_get(const struct wmNDOFMotionData *ndof, float r_pan[3], const bool use_zoom);
void WM_event_ndof_rotate_get(const struct wmNDOFMotionData *ndof, float r_rot[3]);
float WM_event_ndof_to_axis_angle(const struct wmNDOFMotionData *ndof, float axis[3]);
void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4]);
+#endif /* WITH_INPUT_NDOF */
float WM_event_tablet_data(const struct wmEvent *event, int *pen_flip, float tilt[2]);
bool WM_event_is_tablet(const struct wmEvent *event);
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 99303f8e061..02601cbbcea 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -119,6 +119,7 @@ struct ImBuf;
/* exported types for WM */
#include "wm_cursors.h"
#include "wm_event_types.h"
+#include "manipulators/WM_manipulator_types.h"
/* ************** wmOperatorType ************************ */
@@ -138,6 +139,7 @@ enum {
OPTYPE_INTERNAL = (1 << 6),
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 */
};
/* context to call operator in for WM_operator_name_call */
@@ -222,7 +224,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)
@@ -256,15 +258,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_SCREENCAST (3<<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)
/* NC_SCENE Scene */
#define ND_SCENEBROWSE (1<<16)
@@ -486,6 +489,7 @@ typedef enum { /* motion progress, for modal handlers */
P_FINISHED
} wmProgress;
+#ifdef WITH_INPUT_NDOF
typedef struct wmNDOFMotionData {
/* awfully similar to GHOST_TEventNDOFMotionData... */
/* Each component normally ranges from -1 to +1, but can exceed that.
@@ -497,6 +501,7 @@ typedef struct wmNDOFMotionData {
float dt; /* time since previous NDOF Motion event */
wmProgress progress; /* is this the first event, the last, or one of many in between? */
} wmNDOFMotionData;
+#endif /* WITH_INPUT_NDOF */
typedef struct wmTimer {
struct wmTimer *next, *prev;
@@ -521,6 +526,7 @@ typedef struct wmOperatorType {
const char *idname; /* unique identifier */
const char *translation_context;
const char *description; /* tooltips and python docs */
+ const char *undo_group; /* identifier to group operators together */
/* this callback executes the operator without any interactive input,
* parameters may be provided through operator properties. cannot use
@@ -539,7 +545,15 @@ typedef struct wmOperatorType {
* canceled due to some external reason, cancel is called
* - see defines below for return values */
int (*invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT;
+
+ /* Called when a modal operator is canceled (not used often).
+ * Internal cleanup can be done here if needed. */
void (*cancel)(struct bContext *, struct wmOperator *);
+
+ /* Modal is used for operators which continuously run, eg:
+ * fly mode, knife tool, circle select are all examples of modal operators.
+ * Modal operators can handle events which would normally access other operators,
+ * they keep running until they don't return `OPERATOR_RUNNING_MODAL`. */
int (*modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT;
/* verify if the operator can be executed in the current context, note
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index b76a1f1d422..da1b5feea3d 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -107,6 +107,17 @@ void WM_operator_free(wmOperator *op)
MEM_freeN(op);
}
+void WM_operator_free_all_after(wmWindowManager *wm, struct wmOperator *op)
+{
+ op = op->next;
+ while (op != NULL) {
+ wmOperator *op_next = op->next;
+ BLI_remlink(&wm->operators, op);
+ WM_operator_free(op);
+ op = op_next;
+ }
+}
+
/**
* Use with extreme care!,
* properties, customdata etc - must be compatible.
@@ -149,18 +160,23 @@ static void wm_reports_free(wmWindowManager *wm)
void wm_operator_register(bContext *C, wmOperator *op)
{
wmWindowManager *wm = CTX_wm_manager(C);
- int tot;
+ int tot = 0;
BLI_addtail(&wm->operators, op);
- tot = BLI_listbase_count(&wm->operators);
-
- while (tot > MAX_OP_REGISTERED) {
- wmOperator *opt = wm->operators.first;
- BLI_remlink(&wm->operators, opt);
- WM_operator_free(opt);
- tot--;
+
+ /* only count registered operators */
+ while (op) {
+ wmOperator *op_prev = op->prev;
+ if (op->type->flag & OPTYPE_REGISTER) {
+ tot += 1;
+ }
+ if (tot > MAX_OP_REGISTERED) {
+ BLI_remlink(&wm->operators, op);
+ WM_operator_free(op);
+ }
+ op = op_prev;
}
-
+
/* so the console is redrawn */
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
WM_event_add_notifier(C, NC_WM | ND_HISTORY, NULL);
@@ -417,10 +433,12 @@ void wm_add_default(bContext *C)
wmWindowManager *wm = BKE_libblock_alloc(CTX_data_main(C), ID_WM, "WinMan");
wmWindow *win;
bScreen *screen = CTX_wm_screen(C); /* XXX from file read hrmf */
-
+ struct WorkSpace *workspace = G.main->workspaces.last;
+
CTX_wm_manager_set(C, wm);
win = wm_window_new(C);
- win->screen = screen;
+ WM_window_set_active_workspace(win, workspace);
+ WM_window_set_active_screen(win, workspace, screen);
screen->winid = win->winid;
BLI_strncpy(win->screenname, screen->id.name + 2, sizeof(win->screenname));
@@ -441,7 +459,7 @@ 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_window_set_active_workspace(win, NULL); /* prevent draw clear to use screen */
wm_draw_window_clear(win);
wm_window_free(C, wm, win);
}
@@ -467,13 +485,12 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm)
void wm_close_and_free_all(bContext *C, ListBase *wmlist)
{
- Main *bmain = CTX_data_main(C);
wmWindowManager *wm;
-
+
while ((wm = wmlist->first)) {
wm_close_and_free(C, wm);
BLI_remlink(wmlist, wm);
- BKE_libblock_free_data(bmain, &wm->id);
+ BKE_libblock_free_data(&wm->id, true);
MEM_freeN(wm);
}
}
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index 3a53906a8e8..40a2bf42a28 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -46,6 +46,8 @@
#include "BKE_context.h"
+#include "GPU_shader.h"
+
#include "IMB_imbuf_types.h"
#include "UI_interface.h"
@@ -268,10 +270,10 @@ void wm_drags_check_ops(bContext *C, wmEvent *event)
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)
@@ -332,8 +334,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 {
@@ -361,8 +365,8 @@ 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));
+ const unsigned char col[] = {255, 255, 255, 255};
+ UI_fontstyle_draw_simple(fstyle, x, y, wm_drag_name(drag), col);
}
/* operator name with roundbox */
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 3825db14e93..7cff598e6ad 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -57,8 +57,7 @@
#include "GPU_draw.h"
#include "GPU_extensions.h"
-#include "GPU_glew.h"
-#include "GPU_basic_shader.h"
+#include "GPU_immediate.h"
#include "RE_engine.h"
@@ -88,7 +87,7 @@ static void wm_paintcursor_draw(bContext *C, ARegion *ar)
if (wm->paintcursors.first) {
wmWindow *win = CTX_wm_window(C);
- bScreen *screen = win->screen;
+ bScreen *screen = WM_window_get_active_screen(win);
wmPaintCursor *pc;
if (ar->swinid && screen->subwinactive == ar->swinid) {
@@ -128,10 +127,10 @@ static bool wm_area_test_invalid_backbuf(ScrArea *sa)
if (sa->spacetype == SPACE_VIEW3D)
return (((View3D *)sa->spacedata.first)->flag & V3D_INVALID_BACKBUF) != 0;
else
- return 1;
+ return true;
}
-static void wm_region_test_render_do_draw(bScreen *screen, ScrArea *sa, ARegion *ar)
+static void wm_region_test_render_do_draw(const Scene *scene, ScrArea *sa, ARegion *ar)
{
/* tag region for redraw from render engine preview running inside of it */
if (sa->spacetype == SPACE_VIEW3D) {
@@ -139,7 +138,6 @@ static void wm_region_test_render_do_draw(bScreen *screen, ScrArea *sa, ARegion
RenderEngine *engine = (rv3d) ? rv3d->render_engine : NULL;
if (engine && (engine->flag & RE_ENGINE_DO_DRAW)) {
- Scene *scene = screen->scene;
View3D *v3d = sa->spacedata.first;
rcti border_rect;
@@ -159,7 +157,7 @@ static void wm_region_test_render_do_draw(bScreen *screen, ScrArea *sa, ARegion
static void wm_method_draw_full(bContext *C, wmWindow *win)
{
- bScreen *screen = win->screen;
+ bScreen *screen = WM_window_get_active_screen(win);
ScrArea *sa;
ARegion *ar;
@@ -182,7 +180,7 @@ static void wm_method_draw_full(bContext *C, wmWindow *win)
}
ED_screen_draw(win);
- win->screen->do_draw = false;
+ screen->do_draw = false;
/* draw overlapping regions */
for (ar = screen->regionbase.first; ar; ar = ar->next) {
@@ -238,7 +236,7 @@ static void wm_flush_regions_up(bScreen *screen, rcti *dirty)
static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
{
wmWindowManager *wm = CTX_wm_manager(C);
- bScreen *screen = win->screen;
+ bScreen *screen = WM_window_get_active_screen(win);
ScrArea *sa;
ARegion *ar;
static rcti rect = {0, 0, 0, 0};
@@ -319,7 +317,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
/* after area regions so we can do area 'overlay' drawing */
if (screen->do_draw) {
ED_screen_draw(win);
- win->screen->do_draw = false;
+ screen->do_draw = false;
if (exchange)
screen->swap = WIN_FRONT_OK;
@@ -327,7 +325,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
else if (exchange) {
if (screen->swap == WIN_FRONT_OK) {
ED_screen_draw(win);
- win->screen->do_draw = false;
+ screen->do_draw = false;
screen->swap = WIN_BOTH_OK;
}
else if (screen->swap == WIN_BACK_OK)
@@ -372,62 +370,55 @@ static void wm_draw_triple_fail(bContext *C, wmWindow *win)
{
wm_draw_window_clear(win);
- win->drawfail = 1;
+ win->drawfail = true;
wm_method_draw_overlap_all(C, win, 0);
}
-static int wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple)
+static bool wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple)
{
- const int winsize_x = WM_window_pixels_x(win);
- const int winsize_y = WM_window_pixels_y(win);
-
- GLint maxsize;
-
/* compute texture sizes */
- if (GLEW_ARB_texture_rectangle || GLEW_NV_texture_rectangle || GLEW_EXT_texture_rectangle) {
- triple->target = GL_TEXTURE_RECTANGLE_ARB;
- }
- else {
- triple->target = GL_TEXTURE_2D;
- }
-
- triple->x = winsize_x;
- triple->y = winsize_y;
+ triple->x = WM_window_pixels_x(win);
+ triple->y = WM_window_pixels_y(win);
+
+#if USE_TEXTURE_RECTANGLE
+ /* GL_TEXTURE_RECTANGLE is part of GL 3.1 so we can use it soon without runtime checks */
+ triple->target = GL_TEXTURE_RECTANGLE;
+#else
+ triple->target = GL_TEXTURE_2D;
+#endif
/* 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;
- }
-
/* 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();
+ const GLint 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;
+ "(texture too large for graphics card).\n");
+ return false;
}
/* 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);
+
+ /* no mipmaps */
+#if USE_TEXTURE_RECTANGLE
+ /* already has no mipmaps */
+#else
+ glTexParameteri(triple->target, GL_TEXTURE_MAX_LEVEL, 0);
+ /* GL_TEXTURE_BASE_LEVEL = 0 by default */
+#endif
+
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;
- }
+ glTexImage2D(triple->target, 0, GL_RGB8, triple->x, triple->y, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
+
+ glBindTexture(triple->target, 0);
- return 1;
+ return true;
}
void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha)
@@ -435,44 +426,60 @@ void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha)
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;
+ float ratiox = sizex;
+ float ratioy = sizey;
+ float halfx = GLA_PIXEL_OFS;
+ float halfy = GLA_PIXEL_OFS;
+#if USE_TEXTURE_RECTANGLE
/* texture rectangle has unnormalized coordinates */
- if (triple->target == GL_TEXTURE_2D) {
- ratiox /= triple->x;
- ratioy /= triple->y;
- halfx /= triple->x;
- halfy /= triple->y;
- }
+#else
+ ratiox /= triple->x;
+ ratioy /= triple->y;
+ halfx /= triple->x;
+ halfy /= triple->y;
+#endif
- GPU_basic_shader_bind((triple->target == GL_TEXTURE_2D) ? GPU_SHADER_TEXTURE_2D : GPU_SHADER_TEXTURE_RECT);
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int texcoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ const int activeTex = 7; /* arbitrary */
+ glActiveTexture(GL_TEXTURE0 + activeTex);
glBindTexture(triple->target, triple->bind);
- glColor4f(1.0f, 1.0f, 1.0f, alpha);
- glBegin(GL_QUADS);
- glTexCoord2f(halfx, halfy);
- glVertex2f(0, 0);
+#if USE_TEXTURE_RECTANGLE
+ immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_RECT_MODULATE_ALPHA);
+#else
+ immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_MODULATE_ALPHA);
+ /* TODO: make pure 2D version
+ * and a 2D_IMAGE (replace, not modulate) version for when alpha = 1.0
+ */
+#endif
+ immUniform1f("alpha", alpha);
+ immUniform1i("image", activeTex);
- glTexCoord2f(ratiox + halfx, halfy);
- glVertex2f(sizex, 0);
+ immBegin(GWN_PRIM_TRI_FAN, 4);
- glTexCoord2f(ratiox + halfx, ratioy + halfy);
- glVertex2f(sizex, sizey);
+ immAttrib2f(texcoord, halfx, halfy);
+ immVertex2f(pos, 0.0f, 0.0f);
- glTexCoord2f(halfx, ratioy + halfy);
- glVertex2f(0, sizey);
- glEnd();
+ immAttrib2f(texcoord, ratiox + halfx, halfy);
+ immVertex2f(pos, sizex, 0.0f);
- glBindTexture(triple->target, 0);
+ immAttrib2f(texcoord, ratiox + halfx, ratioy + halfy);
+ immVertex2f(pos, sizex, sizey);
+
+ immAttrib2f(texcoord, halfx, ratioy + halfy);
+ immVertex2f(pos, 0.0f, sizey);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ immEnd();
+ immUnbindProgram();
+
+ glBindTexture(triple->target, 0);
+ if (activeTex != 0)
+ glActiveTexture(GL_TEXTURE0);
}
static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple)
@@ -481,8 +488,8 @@ static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple)
const int sizey = WM_window_pixels_y(win);
glBindTexture(triple->target, triple->bind);
+ /* what is GL_READ_BUFFER right now? */
glCopyTexSubImage2D(triple->target, 0, 0, 0, 0, 0, sizex, sizey);
-
glBindTexture(triple->target, 0);
}
@@ -492,7 +499,9 @@ static void wm_draw_region_blend(wmWindow *win, ARegion *ar, wmDrawTriple *tripl
/* region blend always is 1, except when blend timer is running */
if (fac < 1.0f) {
- wmSubWindowScissorSet(win, win->screen->mainwin, &ar->winrct, true);
+ bScreen *screen = WM_window_get_active_screen(win);
+
+ wmSubWindowScissorSet(win, screen->mainwin, &ar->winrct, true);
glEnable(GL_BLEND);
wm_triple_draw_textures(win, triple, 1.0f - fac);
@@ -503,16 +512,17 @@ static void wm_draw_region_blend(wmWindow *win, ARegion *ar, wmDrawTriple *tripl
static void wm_method_draw_triple(bContext *C, wmWindow *win)
{
wmWindowManager *wm = CTX_wm_manager(C);
- wmDrawTriple *triple;
wmDrawData *dd, *dd_next, *drawdata = win->drawdata.first;
- bScreen *screen = win->screen;
+ bScreen *screen = WM_window_get_active_screen(win);
ScrArea *sa;
ARegion *ar;
- int copytex = false;
+ bool copytex = false;
if (drawdata && drawdata->triple) {
- glClearColor(0, 0, 0, 0);
+#if 0 /* why do we need to clear before overwriting? */
+ glClearColor(1, 1, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+#endif
wmSubWindowSet(win, screen->mainwin);
@@ -543,7 +553,7 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
MEM_freeN(dd);
}
- triple = drawdata->triple;
+ wmDrawTriple *triple = drawdata->triple;
/* draw marked area regions */
for (sa = screen->areabase.first; sa; sa = sa->next) {
@@ -551,7 +561,6 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
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);
@@ -612,7 +621,7 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
/* after area regions so we can do area 'overlay' drawing */
ED_screen_draw(win);
- win->screen->do_draw = false;
+ WM_window_get_active_screen(win)->do_draw = false;
/* draw floating regions (menus) */
for (ar = screen->regionbase.first; ar; ar = ar->next) {
@@ -639,7 +648,7 @@ static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, StereoVi
wmWindowManager *wm = CTX_wm_manager(C);
wmDrawData *drawdata;
wmDrawTriple *triple_data, *triple_all;
- bScreen *screen = win->screen;
+ bScreen *screen = WM_window_get_active_screen(win);
ScrArea *sa;
ARegion *ar;
int copytex = false;
@@ -651,8 +660,10 @@ static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, StereoVi
if (drawdata && drawdata->triple) {
if (id == 0) {
+#if 0 /* why do we need to clear before overwriting? */
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+#endif
wmSubWindowSet(win, screen->mainwin);
@@ -783,7 +794,7 @@ static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, StereoVi
/* after area regions so we can do area 'overlay' drawing */
ED_screen_draw(win);
if (sview == STEREO_RIGHT_ID)
- win->screen->do_draw = false;
+ screen->do_draw = false;
/* draw floating regions (menus) */
for (ar = screen->regionbase.first; ar; ar = ar->next) {
@@ -815,11 +826,13 @@ static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, StereoVi
/* quick test to prevent changing window drawable */
static bool wm_draw_update_test_window(wmWindow *win)
{
+ const Scene *scene = WM_window_get_active_scene(win);
+ const bScreen *screen = WM_window_get_active_screen(win);
ScrArea *sa;
ARegion *ar;
bool do_draw = false;
- for (ar = win->screen->regionbase.first; ar; ar = ar->next) {
+ for (ar = screen->regionbase.first; ar; ar = ar->next) {
if (ar->do_draw_overlay) {
wm_tag_redraw_overlay(win, ar);
ar->do_draw_overlay = false;
@@ -828,9 +841,9 @@ static bool wm_draw_update_test_window(wmWindow *win)
do_draw = true;
}
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
for (ar = sa->regionbase.first; ar; ar = ar->next) {
- wm_region_test_render_do_draw(win->screen, sa, ar);
+ wm_region_test_render_do_draw(scene, sa, ar);
if (ar->swinid && ar->do_draw)
do_draw = true;
@@ -838,20 +851,20 @@ static bool wm_draw_update_test_window(wmWindow *win)
}
if (do_draw)
- return 1;
+ return true;
- if (win->screen->do_refresh)
- return 1;
- if (win->screen->do_draw)
- return 1;
- if (win->screen->do_draw_gesture)
- return 1;
- if (win->screen->do_draw_paintcursor)
- return 1;
- if (win->screen->do_draw_drag)
- return 1;
+ if (screen->do_refresh)
+ return true;
+ if (screen->do_draw)
+ return true;
+ if (screen->do_draw_gesture)
+ return true;
+ if (screen->do_draw_paintcursor)
+ return true;
+ if (screen->do_draw_drag)
+ return true;
- return 0;
+ return false;
}
static int wm_automatic_draw_method(wmWindow *win)
@@ -889,15 +902,18 @@ void wm_tag_redraw_overlay(wmWindow *win, ARegion *ar)
{
/* for draw triple gestures, paint cursors don't need region redraw */
if (ar && win) {
+ bScreen *screen = WM_window_get_active_screen(win);
+
if (wm_automatic_draw_method(win) != USER_DRAW_TRIPLE)
ED_region_tag_redraw(ar);
- win->screen->do_draw_paintcursor = true;
+ screen->do_draw_paintcursor = true;
}
}
void WM_paint_cursor_tag_redraw(wmWindow *win, ARegion *ar)
{
- win->screen->do_draw_paintcursor = true;
+ bScreen *screen = WM_window_get_active_screen(win);
+ screen->do_draw_paintcursor = true;
wm_tag_redraw_overlay(win, ar);
}
@@ -905,7 +921,6 @@ void wm_draw_update(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win;
- int drawmethod;
#ifdef WITH_OPENSUBDIV
BKE_subsurf_free_unused_buffers();
@@ -915,15 +930,14 @@ void wm_draw_update(bContext *C)
for (win = wm->windows.first; win; win = win->next) {
#ifdef WIN32
- if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
- GHOST_TWindowState state = GHOST_GetWindowState(win->ghostwin);
-
- if (state == GHOST_kWindowStateMinimized) {
- /* do not update minimized windows, it gives issues on intel drivers (see [#33223])
- * anyway, it seems logical to skip update for invisible windows
- */
- continue;
- }
+ GHOST_TWindowState state = GHOST_GetWindowState(win->ghostwin);
+
+ if (state == GHOST_kWindowStateMinimized) {
+ /* do not update minimized windows, gives issues on Intel (see T33223)
+ * and AMD (see T50856). it seems logical to skip update for invisible
+ * window anyway.
+ */
+ continue;
}
#endif
if (win->drawmethod != U.wmdrawmethod) {
@@ -932,16 +946,18 @@ void wm_draw_update(bContext *C)
}
if (wm_draw_update_test_window(win)) {
+ bScreen *screen = WM_window_get_active_screen(win);
+
CTX_wm_window_set(C, win);
/* sets context window+screen */
wm_window_make_drawable(wm, win);
/* notifiers for screen redraw */
- if (win->screen->do_refresh)
+ if (screen->do_refresh)
ED_screen_refresh(wm, win);
- drawmethod = wm_automatic_draw_method(win);
+ int drawmethod = wm_automatic_draw_method(win);
if (win->drawfail)
wm_method_draw_overlap_all(C, win, 0);
@@ -962,9 +978,9 @@ void wm_draw_update(bContext *C)
}
}
- win->screen->do_draw_gesture = false;
- win->screen->do_draw_paintcursor = false;
- win->screen->do_draw_drag = false;
+ screen->do_draw_gesture = false;
+ screen->do_draw_paintcursor = false;
+ screen->do_draw_drag = false;
wm_window_swap_buffers(win);
@@ -985,7 +1001,7 @@ void wm_draw_data_free(wmWindow *win)
void wm_draw_window_clear(wmWindow *win)
{
- bScreen *screen = win->screen;
+ bScreen *screen = WM_window_get_active_screen(win);
ScrArea *sa;
ARegion *ar;
@@ -1003,12 +1019,13 @@ void wm_draw_window_clear(wmWindow *win)
void wm_draw_region_clear(wmWindow *win, ARegion *ar)
{
+ bScreen *screen = WM_window_get_active_screen(win);
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);
+ wm_flush_regions_down(screen, &ar->winrct);
- win->screen->do_draw = true;
+ screen->do_draw = true;
}
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 01dc77127d2..6a1be832918 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -39,6 +39,7 @@
#include "DNA_screen_types.h"
#include "DNA_scene_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "DNA_userdef_types.h"
#include "MEM_guardedalloc.h"
@@ -53,10 +54,12 @@
#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"
@@ -68,8 +71,6 @@
#include "RNA_access.h"
-#include "GPU_debug.h"
-
#include "UI_interface.h"
#include "PIL_time.h"
@@ -276,6 +277,7 @@ void wm_event_do_notifiers(bContext *C)
/* 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);
@@ -293,17 +295,31 @@ 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);
+
+ ED_workspace_change(ref_ws, C, wm, win);
+ if (G.debug & G_DEBUG_EVENTS)
+ printf("%s: Workspace set %p\n", __func__, note->reference);
+ }
+ 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!
+ 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!
+ 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);
}
@@ -311,7 +327,7 @@ void wm_event_do_notifiers(bContext *C)
}
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)
@@ -319,7 +335,8 @@ 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);
+ SceneLayer *sl = BKE_scene_layer_context_active_PLACEHOLDER(scene);
+ ED_info_stats_clear(sl);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, NULL);
}
}
@@ -331,7 +348,7 @@ void wm_event_do_notifiers(bContext *C)
if (G.is_rendering == false) {
/* depsgraph gets called, might send more notifiers */
- ED_update_for_newframe(CTX_data_main(C), win->screen->scene, 1);
+ ED_update_for_newframe(CTX_data_main(C), scene, 1);
}
}
}
@@ -339,12 +356,19 @@ 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);
+
/* 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 != WM_window_get_active_workspace(win) &&
+ 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 {
@@ -357,14 +381,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(screen, NULL, ar, note, scene);
}
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
- ED_area_do_listen(win->screen, sa, note);
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ ED_area_do_listen(screen, 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(screen, sa, ar, note, scene);
}
}
}
@@ -372,18 +396,23 @@ void wm_event_do_notifiers(bContext *C)
MEM_freeN(note);
}
-
+
/* combine datamasks so 1 win doesn't disable UV's in another [#26448] */
for (win = wm->windows.first; win; win = win->next) {
- win_combine_v3d_datamask |= ED_view3d_screen_datamask(win->screen);
+ const Scene *scene = WM_window_get_active_scene(win);
+ const bScreen *screen = WM_window_get_active_screen(win);
+
+ win_combine_v3d_datamask |= ED_view3d_screen_datamask(scene, screen);
}
/* cached: editor refresh callbacks now, they get context */
for (win = wm->windows.first; win; win = win->next) {
+ const bScreen *screen = WM_window_get_active_screen(win);
+ Scene *scene = WM_window_get_active_scene(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);
@@ -396,12 +425,12 @@ void wm_event_do_notifiers(bContext *C)
Main *bmain = CTX_data_main(C);
/* copied to set's in scene_update_tagged_recursive() */
- win->screen->scene->customdata_mask = win_combine_v3d_datamask;
+ 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;
+ scene->customdata_mask |= scene->customdata_mask_modal;
- BKE_scene_update_tagged(bmain->eval_ctx, bmain, win->screen->scene);
+ BKE_scene_update_tagged(bmain->eval_ctx, bmain, scene);
}
}
@@ -567,6 +596,7 @@ void WM_event_print(const wmEvent *event)
BLI_str_utf8_size(event->utf8_buf), event->utf8_buf,
event->keymap_idname, (const void *)event);
+#ifdef WITH_INPUT_NDOF
if (ISNDOF(event->type)) {
const wmNDOFMotionData *ndof = event->customdata;
if (event->type == NDOF_MOTION) {
@@ -577,6 +607,7 @@ void WM_event_print(const wmEvent *event)
/* ndof buttons printed already */
}
}
+#endif /* WITH_INPUT_NDOF */
if (event->tablet_data) {
const wmTabletData *wmtab = event->tablet_data;
@@ -613,10 +644,12 @@ bool WM_event_is_absolute(const wmEvent *event)
return (event->tablet_data != NULL);
}
+#ifdef WITH_INPUT_NDOF
void WM_ndof_deadzone_set(float deadzone)
{
GHOST_setNDOFDeadZone(deadzone);
}
+#endif
static void wm_add_reports(ReportList *reports)
{
@@ -711,7 +744,9 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca
*/
static bool wm_operator_register_check(wmWindowManager *wm, wmOperatorType *ot)
{
- return wm && (wm->op_undo_depth == 0) && (ot->flag & OPTYPE_REGISTER);
+ /* Check undo flag here since undo operators are also added to the list,
+ * to support checking if the same operator is run twice. */
+ return wm && (wm->op_undo_depth == 0) && (ot->flag & (OPTYPE_REGISTER | OPTYPE_UNDO));
}
static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat)
@@ -723,10 +758,13 @@ static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat)
/* we don't want to do undo pushes for operators that are being
* 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 (wm->op_undo_depth == 0) {
if (op->type->flag & OPTYPE_UNDO)
ED_undo_push_op(C, op);
-
+ else if (op->type->flag & OPTYPE_UNDO_GROUPED)
+ ED_undo_grouped_push_op(C, op);
+ }
+
if (repeat == 0) {
if (G.debug & G_DEBUG_WM) {
char *buf = WM_operator_pystring(C, op, false, true);
@@ -871,6 +909,20 @@ bool WM_operator_repeat_check(const bContext *UNUSED(C), wmOperator *op)
return false;
}
+bool WM_operator_is_repeat(const bContext *C, const wmOperator *op)
+{
+ /* may be in the operators list or not */
+ wmOperator *op_prev;
+ if (op->prev == NULL && op->next == NULL) {
+ wmWindowManager *wm = CTX_wm_manager(C);
+ op_prev = wm->operators.last;
+ }
+ else {
+ op_prev = op->prev;
+ }
+ return (op_prev && (op->type == op_prev->type));
+}
+
static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot,
PointerRNA *properties, ReportList *reports)
{
@@ -1670,7 +1722,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
wm_handler_op_context(C, handler, event);
wm_region_mouse_co(C, event);
wm_event_modalkeymap(C, op, event, &dbl_click_disabled);
-
+
if (ot->flag & OPTYPE_UNDO)
wm->op_undo_depth++;
@@ -1719,6 +1771,9 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
CTX_wm_region_set(C, NULL);
}
+ /* update manipulators during modal handlers */
+ wm_manipulatormaps_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);
@@ -1850,9 +1905,12 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand
wm->op_undo_depth--;
/* XXX check this carefully, CTX_wm_manager(C) == wm is a bit hackish */
- if (CTX_wm_manager(C) == wm && wm->op_undo_depth == 0)
+ if (CTX_wm_manager(C) == wm && wm->op_undo_depth == 0) {
if (handler->op->type->flag & OPTYPE_UNDO)
ED_undo_push_op(C, handler->op);
+ else if (handler->op->type->flag & OPTYPE_UNDO_GROUPED)
+ ED_undo_grouped_push_op(C, handler->op);
+ }
if (handler->op->reports->list.first) {
@@ -2028,11 +2086,13 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
break;
}
else {
- if (action & WM_HANDLER_HANDLED)
+ 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);
-
- PRINT("%s: un-handled '%s'...", __func__, kmi->idname);
+ }
+ else {
+ PRINT("%s: un-handled '%s'\n", __func__, kmi->idname);
+ }
}
}
}
@@ -2086,6 +2146,71 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
}
}
}
+ else if (handler->manipulator_map) {
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = CTX_wm_region(C);
+ wmManipulatorMap *mmap = handler->manipulator_map;
+ wmManipulator *mpr = wm_manipulatormap_highlight_get(mmap);
+
+ wm_manipulatormap_handler_context(C, handler);
+ wm_region_mouse_co(C, event);
+
+ /* handle manipulator highlighting */
+ if (event->type == MOUSEMOVE && !wm_manipulatormap_active_get(mmap)) {
+ int part;
+ mpr = wm_manipulatormap_highlight_find(mmap, C, event, &part);
+ wm_manipulatormap_highlight_set(mmap, C, mpr, part);
+ }
+ /* handle user configurable manipulator-map keymap */
+ else if (mpr) {
+ /* get user customized keymap from default one */
+ const wmManipulatorGroup *highlightgroup = mpr->parent_mgroup;
+ const wmKeyMap *keymap = WM_keymap_active(wm, highlightgroup->type->keymap);
+ wmKeyMapItem *kmi;
+
+ PRINT("%s: checking '%s' ...", __func__, keymap->idname);
+
+ if (!keymap->poll || keymap->poll(C)) {
+ PRINT("pass\n");
+ for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ if (wm_eventmatch(event, kmi)) {
+ 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;
+
+ /* 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;
+
+ if (action & WM_HANDLER_BREAK) {
+ 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");
+ }
+ }
+
+ /* 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);
@@ -2259,17 +2384,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;
@@ -2285,16 +2412,16 @@ 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 (screen->do_draw_drag)
if (win->drawmethod == USER_DRAW_OVERLAP)
- win->screen->do_draw = true;
+ screen->do_draw = true;
}
@@ -2324,22 +2451,28 @@ void wm_event_do_handlers(bContext *C)
/* update key configuration before handling events */
WM_keyconfig_update(wm);
+ WM_manipulatorconfig_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 safty 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);
@@ -2372,6 +2505,9 @@ 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);
@@ -2423,16 +2559,18 @@ void wm_event_do_handlers(bContext *C)
/* for regions having custom cursors */
wm_paintcursor_test(C, event);
}
+#ifdef WITH_INPUT_NDOF
else if (event->type == NDOF_MOTION) {
win->addmousemove = true;
}
+#endif
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
/* 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;
}
@@ -2526,8 +2664,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_manipulatorconfig_update(CTX_data_main(C));
}
/* ********** filesector handling ************ */
@@ -2564,7 +2701,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
wmWindow *win = CTX_wm_window(C);
/* only allow 1 file selector open per window */
- for (handler = win->modalhandlers.first; handler; handler = handlernext) {
+ for (handler = win->handlers.first; handler; handler = handlernext) {
handlernext = handler->next;
if (handler->type == WM_HANDLER_FILESELECT) {
@@ -2578,7 +2715,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
if (sfile->op == handler->op) {
CTX_wm_area_set(C, sa);
- wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_CANCEL);
+ wm_handler_fileselect_do(C, &win->handlers, handler, EVT_FILESELECT_CANCEL);
break;
}
}
@@ -2586,7 +2723,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
/* if not found we stop the handler without changing the screen */
if (!sa)
- wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_EXTERNAL_CANCEL);
+ wm_handler_fileselect_do(C, &win->handlers, handler, EVT_FILESELECT_EXTERNAL_CANCEL);
}
}
@@ -2597,7 +2734,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
handler->op_area = CTX_wm_area(C);
handler->op_region = CTX_wm_region(C);
- BLI_addhead(&win->modalhandlers, handler);
+ BLI_addhead(&win->handlers, handler);
/* check props once before invoking if check is available
* ensures initial properties are valid */
@@ -2640,6 +2777,33 @@ wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op)
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) {
+ if (handler->op_area == old_area) {
+ 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;
@@ -3026,6 +3190,7 @@ static void update_tablet_data(wmWindow *win, wmEvent *event)
}
}
+#ifdef WITH_INPUT_NDOF
/* adds customdata to event */
static void attach_ndof_data(wmEvent *event, const GHOST_TEventNDOFMotionData *ghost)
{
@@ -3052,6 +3217,7 @@ static void attach_ndof_data(wmEvent *event, const GHOST_TEventNDOFMotionData *g
event->customdata = data;
event->customdatafree = 1;
}
+#endif /* WITH_INPUT_NDOF */
/* imperfect but probably usable... draw/enable drags to other windows */
static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *win, wmEvent *event)
@@ -3163,6 +3329,8 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
GHOST_TEventCursorData *cd = customdata;
copy_v2_v2_int(&event.x, &cd->x);
+ wm_stereo3d_mouse_offset_apply(win, &event.x);
+
event.type = MOUSEMOVE;
wm_event_add_mousemove(win, &event);
copy_v2_v2_int(&evt->x, &event.x);
@@ -3439,6 +3607,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
break;
}
+#ifdef WITH_INPUT_NDOF
case GHOST_kEventNDOFMotion:
{
event.type = NDOF_MOTION;
@@ -3474,6 +3643,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
break;
}
+#endif /* WITH_INPUT_NDOF */
case GHOST_kEventUnknown:
case GHOST_kNumEventTypes:
@@ -3545,6 +3715,7 @@ void WM_set_locked_interface(wmWindowManager *wm, bool lock)
}
+#ifdef WITH_INPUT_NDOF
/* -------------------------------------------------------------------- */
/* NDOF */
@@ -3587,6 +3758,7 @@ void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4])
angle = WM_event_ndof_to_axis_angle(ndof, axis);
axis_angle_to_quat(q, axis, angle);
}
+#endif /* WITH_INPUT_NDOF */
/* if this is a tablet event, return tablet pressure and set *pen_flip
* to 1 if the eraser tool is being used, 0 otherwise */
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index fe257cc4c41..5631a0108fd 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -69,6 +69,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_utildefines.h"
@@ -77,7 +78,6 @@
#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"
@@ -86,6 +86,7 @@
#include "BKE_sound.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "BLO_readfile.h"
#include "BLO_writefile.h"
@@ -119,6 +120,8 @@
#include "BPY_extern.h"
#endif
+#include "DEG_depsgraph.h"
+
#include "WM_api.h"
#include "WM_types.h"
#include "wm.h"
@@ -159,7 +162,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));
}
}
@@ -248,16 +251,23 @@ static void wm_window_match_do(bContext *C, ListBase *oldwmlist)
/* match oldwm to new dbase, only old files */
for (wm = oldwmlist->first; wm; wm = wm->id.next) {
-
for (win = wm->windows.first; win; win = win->next) {
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+
/* all windows get active screen from file */
- if (screen->winid == 0)
- win->screen = screen;
- else
- win->screen = ED_screen_duplicate(win, screen);
-
- BLI_strncpy(win->screenname, win->screen->id.name + 2, sizeof(win->screenname));
- win->screen->winid = win->winid;
+ 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(workspace, layout_old, win);
+
+ WM_window_set_active_layout(win, workspace, layout_new);
+ }
+
+ bScreen *win_screen = WM_window_get_active_screen(win);
+ BLI_strncpy(win->screenname, win_screen->id.name + 2, sizeof(win->screenname));
+ win_screen->winid = win->winid;
}
}
}
@@ -316,10 +326,8 @@ static void wm_window_match_do(bContext *C, ListBase *oldwmlist)
}
/* in case UserDef was read, we re-initialize all, and do versioning */
-static void wm_init_userdef(bContext *C, const bool from_memory)
+static void wm_init_userdef(Main *bmain, const bool read_userdef_from_memory)
{
- Main *bmain = CTX_data_main(C);
-
/* versioning is here */
UI_init_userdef();
@@ -336,14 +344,12 @@ static void wm_init_userdef(bContext *C, const bool from_memory)
}
/* avoid re-saving for every small change to our prefs, allow overrides */
- if (from_memory) {
+ if (read_userdef_from_memory) {
BLO_update_defaults_userpref_blend();
}
/* update tempdir from user preferences */
BKE_tempdir_init(U.tempdir);
-
- BKE_blender_userdef_refresh();
}
@@ -464,12 +470,16 @@ static void wm_file_read_post(bContext *C, bool is_startup_file)
CTX_wm_window_set(C, wm->windows.first);
ED_editors_init(C);
- DAG_on_visible_update(CTX_data_main(C), true);
+ DEG_on_visible_update(CTX_data_main(C), true);
#ifdef WITH_PYTHON
if (is_startup_file) {
/* possible python hasn't been initialized */
if (CTX_py_init_get(C)) {
+ /* Only run when we have a template path found. */
+ if (BKE_appdir_app_template_any()) {
+ BPY_execute_string(C, "__import__('bl_app_template_utils').reset()");
+ }
/* sync addons, these may have changed from the defaults */
BPY_execute_string(C, "__import__('addon_utils').reset_all()");
@@ -554,7 +564,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
/* confusing this global... */
G.relbase_valid = 1;
- retval = BKE_blendfile_read(C, filepath, reports);
+ retval = BKE_blendfile_read(C, filepath, reports, 0);
/* when loading startup.blend's, we can be left with a blank path */
if (G.main->name[0]) {
G.save_over = 1;
@@ -577,7 +587,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
if (retval == BKE_BLENDFILE_READ_OK_USERPREFS) {
/* in case a userdef is read from regular .blend */
- wm_init_userdef(C, false);
+ wm_init_userdef(G.main, false);
}
if (retval != BKE_BLENDFILE_READ_FAIL) {
@@ -629,32 +639,45 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
/**
- * called on startup, (context entirely filled with NULLs)
- * or called for 'New File'
- * both startup.blend and userpref.blend are checked
- * the optional parameter custom_file points to an alternative startup page
- * custom_file can be NULL
+ * Called on startup, (context entirely filled with NULLs)
+ * or called for 'New File' both startup.blend and userpref.blend are checked.
+ *
+ * \param use_factory_settings: Ignore on-disk startup file, use bundled ``datatoc_startup_blend`` instead.
+ * Used for "Restore Factory Settings".
+ * \param filepath_startup_override: Optional path pointing to an alternative blend file (may be NULL).
+ * \param app_template_override: Template to use instead of the template defined in user-preferences.
+ * When not-null, this is written into the user preferences.
*/
-int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const char *custom_file)
+int wm_homefile_read(
+ bContext *C, ReportList *reports,
+ bool use_factory_settings, bool use_empty_data,
+ const char *filepath_startup_override, const char *app_template_override)
{
ListBase wmbase;
- char startstr[FILE_MAX];
- char prefstr[FILE_MAX];
- int success = 0;
+ bool success = false;
+
+ char filepath_startup[FILE_MAX];
+ char filepath_userdef[FILE_MAX];
+
+ /* When 'app_template' is set: '{BLENDER_USER_CONFIG}/{app_template}' */
+ char app_template_system[FILE_MAX];
+ /* When 'app_template' is set: '{BLENDER_SYSTEM_SCRIPTS}/startup/bl_app_templates_system/{app_template}' */
+ char app_template_config[FILE_MAX];
/* Indicates whether user preferences were really load from memory.
*
- * This is used for versioning code, and for this we can not rely on from_memory
+ * This is used for versioning code, and for this we can not rely on use_factory_settings
* passed via argument. This is because there might be configuration folder
* exists but it might not have userpref.blend and in this case we fallback to
* reading home file from memory.
*
* And in this case versioning code is to be run.
*/
- bool read_userdef_from_memory = true;
+ bool read_userdef_from_memory = false;
+ eBLOReadSkip skip_flags = 0;
/* options exclude eachother */
- BLI_assert((from_memory && custom_file) == 0);
+ BLI_assert((use_factory_settings && filepath_startup_override) == 0);
if ((G.f & G_SCRIPT_OVERRIDE_PREF) == 0) {
BKE_BIT_TEST_SET(G.f, (U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0, G_SCRIPT_AUTOEXEC);
@@ -665,77 +688,155 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c
UI_view2d_zoom_cache_reset();
G.relbase_valid = 0;
- if (!from_memory) {
- const char * const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL);
- if (custom_file) {
- BLI_strncpy(startstr, custom_file, FILE_MAX);
- if (cfgdir) {
- BLI_make_file_string(G.main->name, prefstr, cfgdir, BLENDER_USERPREF_FILE);
- }
- else {
- prefstr[0] = '\0';
- }
+ /* put aside screens to match with persistent windows later */
+ wm_window_match_init(C, &wmbase);
+
+ filepath_startup[0] = '\0';
+ filepath_userdef[0] = '\0';
+ app_template_system[0] = '\0';
+ app_template_config[0] = '\0';
+
+ const char * const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL);
+ if (!use_factory_settings) {
+ if (cfgdir) {
+ BLI_path_join(filepath_startup, sizeof(filepath_startup), cfgdir, BLENDER_STARTUP_FILE, NULL);
+ BLI_path_join(filepath_userdef, sizeof(filepath_startup), cfgdir, BLENDER_USERPREF_FILE, NULL);
+ }
+ else {
+ use_factory_settings = true;
+ }
+
+ if (filepath_startup_override) {
+ BLI_strncpy(filepath_startup, filepath_startup_override, FILE_MAX);
+ }
+ }
+
+ /* load preferences before startup.blend */
+ if (!use_factory_settings && BLI_exists(filepath_userdef)) {
+ UserDef *userdef = BKE_blendfile_userdef_read(filepath_userdef, NULL);
+ if (userdef != NULL) {
+ BKE_blender_userdef_set_data(userdef);
+ MEM_freeN(userdef);
+
+ skip_flags |= BLO_READ_SKIP_USERDEF;
+ printf("Read prefs: %s\n", filepath_userdef);
}
- else if (cfgdir) {
- BLI_make_file_string(G.main->name, startstr, cfgdir, BLENDER_STARTUP_FILE);
- BLI_make_file_string(G.main->name, prefstr, cfgdir, BLENDER_USERPREF_FILE);
+ }
+
+ const char *app_template = NULL;
+
+ if (filepath_startup_override != NULL) {
+ /* pass */
+ }
+ else if (app_template_override && app_template_override[0]) {
+ app_template = app_template_override;
+ }
+ else if (!use_factory_settings && U.app_template[0]) {
+ app_template = U.app_template;
+ }
+
+ if (app_template != NULL) {
+ BKE_appdir_app_template_id_search(app_template, app_template_system, sizeof(app_template_system));
+ BLI_path_join(app_template_config, sizeof(app_template_config), cfgdir, app_template, NULL);
+ }
+
+ /* insert template name into startup file */
+ if (app_template != NULL) {
+ /* note that the path is being set even when 'use_factory_settings == true'
+ * this is done so we can load a templates factory-settings */
+ if (!use_factory_settings) {
+ BLI_path_join(filepath_startup, sizeof(filepath_startup), app_template_config, BLENDER_STARTUP_FILE, NULL);
+ if (BLI_access(filepath_startup, R_OK) != 0) {
+ filepath_startup[0] = '\0';
+ }
}
else {
- startstr[0] = '\0';
- prefstr[0] = '\0';
- from_memory = 1;
+ filepath_startup[0] = '\0';
+ }
+
+ if (filepath_startup[0] == '\0') {
+ BLI_path_join(filepath_startup, sizeof(filepath_startup), app_template_system, BLENDER_STARTUP_FILE, NULL);
}
}
-
- /* put aside screens to match with persistent windows later */
- wm_window_match_init(C, &wmbase);
-
- if (!from_memory) {
- if (BLI_access(startstr, R_OK) == 0) {
- success = (BKE_blendfile_read(C, startstr, NULL) != BKE_BLENDFILE_READ_FAIL);
+
+ if (!use_factory_settings || (filepath_startup[0] != '\0')) {
+ if (BLI_access(filepath_startup, R_OK) == 0) {
+ success = (BKE_blendfile_read(C, filepath_startup, NULL, skip_flags) != BKE_BLENDFILE_READ_FAIL);
}
if (BLI_listbase_is_empty(&U.themes)) {
if (G.debug & G_DEBUG)
- printf("\nNote: No (valid) '%s' found, fall back to built-in default.\n\n", startstr);
- success = 0;
+ printf("\nNote: No (valid) '%s' found, fall back to built-in default.\n\n", filepath_startup);
+ success = false;
}
}
- if (success == 0 && custom_file && reports) {
- BKE_reportf(reports, RPT_ERROR, "Could not read '%s'", custom_file);
- /*We can not return from here because wm is already reset*/
+ if (success == false && filepath_startup_override && reports) {
+ /* We can not return from here because wm is already reset */
+ BKE_reportf(reports, RPT_ERROR, "Could not read '%s'", filepath_startup_override);
}
- if (success == 0) {
- success = BKE_blendfile_read_from_memory(C, datatoc_startup_blend, datatoc_startup_blend_size, NULL, true);
+ if (success == false) {
+ success = BKE_blendfile_read_from_memory(
+ C, datatoc_startup_blend, datatoc_startup_blend_size,
+ NULL, skip_flags, true);
+ if (success && !(skip_flags & BLO_READ_SKIP_USERDEF)) {
+ read_userdef_from_memory = true;
+ }
if (BLI_listbase_is_empty(&wmbase)) {
wm_clear_default_size(C);
}
- BKE_tempdir_init(U.tempdir);
+ }
-#ifdef WITH_PYTHON_SECURITY
- /* use alternative setting for security nuts
- * otherwise we'd need to patch the binary blob - startup.blend.c */
- U.flag |= USER_SCRIPT_AUTOEXEC_DISABLE;
-#endif
+ if (use_empty_data) {
+ BKE_blendfile_read_make_empty(C);
}
-
- /* check new prefs only after startup.blend was finished */
- if (!from_memory && BLI_exists(prefstr)) {
- int done = BKE_blendfile_read_userdef(prefstr, NULL);
- if (done != BKE_BLENDFILE_READ_FAIL) {
- read_userdef_from_memory = false;
- printf("Read new prefs: %s\n", prefstr);
+
+ /* Load template preferences,
+ * unlike regular preferences we only use some of the settings,
+ * see: BKE_blender_userdef_set_app_template */
+ if (app_template_system[0] != '\0') {
+ char temp_path[FILE_MAX];
+ temp_path[0] = '\0';
+ if (!use_factory_settings) {
+ BLI_path_join(temp_path, sizeof(temp_path), app_template_config, BLENDER_USERPREF_FILE, NULL);
+ if (BLI_access(temp_path, R_OK) != 0) {
+ temp_path[0] = '\0';
+ }
+ }
+
+ if (temp_path[0] == '\0') {
+ BLI_path_join(temp_path, sizeof(temp_path), app_template_system, BLENDER_USERPREF_FILE, NULL);
+ }
+
+ UserDef *userdef_template = NULL;
+ /* just avoids missing file warning */
+ if (BLI_exists(temp_path)) {
+ userdef_template = BKE_blendfile_userdef_read(temp_path, NULL);
+ }
+ if (userdef_template == NULL) {
+ /* we need to have preferences load to overwrite preferences from previous template */
+ userdef_template = BKE_blendfile_userdef_read_from_memory(
+ datatoc_startup_blend, datatoc_startup_blend_size, NULL);
+ read_userdef_from_memory = true;
+ }
+ if (userdef_template) {
+ BKE_blender_userdef_set_app_template(userdef_template);
+ BKE_blender_userdef_free_data(userdef_template);
+ MEM_freeN(userdef_template);
}
}
-
+
+ if (app_template_override) {
+ BLI_strncpy(U.app_template, app_template_override, sizeof(U.app_template));
+ }
+
/* prevent buggy files that had G_FILE_RELATIVE_REMAP written out by mistake. Screws up autosaves otherwise
* can remove this eventually, only in a 2.53 and older, now its not written */
G.fileflags &= ~G_FILE_RELATIVE_REMAP;
/* check userdef before open window, keymaps etc */
- wm_init_userdef(C, read_userdef_from_memory);
+ wm_init_userdef(CTX_data_main(C), read_userdef_from_memory);
/* match the read WM with current WM */
wm_window_match_do(C, &wmbase);
@@ -744,11 +845,14 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c
G.main->name[0] = '\0';
/* When loading factory settings, the reset solid OpenGL lights need to be applied. */
- if (!G.background) GPU_default_lights();
-
- /* XXX */
- G.save_over = 0; // start with save preference untitled.blend
- G.fileflags &= ~G_FILE_AUTOPLAY; /* disable autoplay in startup.blend... */
+ 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);
@@ -879,7 +983,7 @@ static void wm_history_file_update(void)
/* screen can be NULL */
-static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, BlendThumbnail **thumb_pt)
+static ImBuf *blend_file_thumb(Scene *scene, SceneLayer *sl, bScreen *screen, BlendThumbnail **thumb_pt)
{
/* will be scaled down, but gives some nice oversampling */
ImBuf *ibuf;
@@ -916,14 +1020,14 @@ static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, BlendThumbnail **t
/* gets scaled to BLEN_THUMB_SIZE */
if (scene->camera) {
ibuf = ED_view3d_draw_offscreen_imbuf_simple(
- scene, scene->camera,
+ scene, sl, scene->camera,
BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
IB_rect, OB_SOLID, false, false, false, R_ALPHAPREMUL, 0, false, NULL,
NULL, NULL, err_out);
}
else {
ibuf = ED_view3d_draw_offscreen_imbuf(
- scene, v3d, ar,
+ scene, sl, v3d, ar,
BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
IB_rect, false, R_ALPHAPREMUL, 0, false, NULL,
NULL, NULL, err_out);
@@ -998,7 +1102,7 @@ static int wm_file_write(bContext *C, const char *filepath, int fileflags, Repor
BKE_reportf(reports, RPT_ERROR, "Cannot save blend file, path '%s' is not writable", filepath);
return ret;
}
-
+
/* note: used to replace the file extension (to ensure '.blend'),
* no need to now because the operator ensures,
* its handy for scripts to save to a predefined name without blender editing it */
@@ -1019,7 +1123,7 @@ static int wm_file_write(bContext *C, const char *filepath, int fileflags, Repor
/* Main now can store a .blend thumbnail, usefull for background mode or thumbnail customization. */
main_thumb = thumb = CTX_data_main(C)->blen_thumb;
if ((U.flag & USER_SAVE_PREVIEWS) && BLI_thread_is_main()) {
- ibuf_thumb = blend_file_thumb(CTX_data_scene(C), CTX_wm_screen(C), &thumb);
+ ibuf_thumb = blend_file_thumb(CTX_data_scene(C), CTX_data_scene_layer(C), CTX_wm_screen(C), &thumb);
}
/* operator now handles overwrite checks */
@@ -1144,6 +1248,9 @@ void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(w
for (handler = win->modalhandlers.first; handler; handler = handler->next) {
if (handler->op) {
wm->autosavetimer = WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, 10.0);
+ if (G.debug) {
+ printf("Skipping auto-save, modal operator running, retrying in ten seconds...\n");
+ }
return;
}
}
@@ -1161,7 +1268,7 @@ void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(w
ED_editors_flush_edits(C, false);
- /* no error reporting to console */
+ /* Error reporting into console */
BLO_write_file(CTX_data_main(C), filepath, fileflags, NULL, NULL);
}
/* do timer after file write, just in case file write takes a long time */
@@ -1261,16 +1368,24 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
char filepath[FILE_MAX];
int fileflags;
+ const char *app_template = U.app_template[0] ? U.app_template : NULL;
+ const char * const cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, app_template);
+ if (cfgdir == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Unable to create user config path");
+ return OPERATOR_CANCELLED;
+ }
+
BLI_callback_exec(G.main, 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 */
WM_keyconfig_update(wm);
- BLI_make_file_string("/", filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_STARTUP_FILE);
+ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_STARTUP_FILE, NULL);
+
printf("trying to save homefile at %s ", filepath);
ED_editors_flush_edits(C, false);
@@ -1348,21 +1463,44 @@ static int wm_userpref_write_exec(bContext *C, wmOperator *op)
{
wmWindowManager *wm = CTX_wm_manager(C);
char filepath[FILE_MAX];
+ const char *cfgdir;
+ bool ok = false;
/* update keymaps in user preferences */
WM_keyconfig_update(wm);
- BLI_make_file_string("/", filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_USERPREF_FILE);
- printf("trying to save userpref at %s ", filepath);
-
- if (BKE_blendfile_write_userdef(filepath, op->reports) == 0) {
- printf("fail\n");
- return OPERATOR_CANCELLED;
+ if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL))) {
+ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL);
+ printf("trying to save userpref at %s ", filepath);
+ if (BKE_blendfile_userdef_write(filepath, op->reports) != 0) {
+ printf("ok\n");
+ ok = true;
+ }
+ else {
+ printf("fail\n");
+ }
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "Unable to create userpref path");
}
- printf("ok\n");
+ if (U.app_template[0] && (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);
+ if (BKE_blendfile_userdef_write(filepath, op->reports) == 0) {
+ printf("fail\n");
+ ok = true;
+ }
+ else {
+ printf("ok\n");
+ }
+ }
+ else if (U.app_template[0]) {
+ BKE_report(op->reports, RPT_ERROR, "Unable to create app-template userpref path");
+ }
- return OPERATOR_FINISHED;
+ return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void WM_OT_save_userpref(wmOperatorType *ot)
@@ -1375,6 +1513,42 @@ void WM_OT_save_userpref(wmOperatorType *ot)
ot->exec = wm_userpref_write_exec;
}
+static int wm_workspace_configuration_file_write_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ char filepath[FILE_MAX];
+
+ const char *app_template = U.app_template[0] ? U.app_template : NULL;
+ const char * const cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, app_template);
+ if (cfgdir == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Unable to create workspace configuration file path");
+ return OPERATOR_CANCELLED;
+ }
+
+ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_WORKSPACES_FILE, NULL);
+ printf("trying to save workspace configuration file at %s ", filepath);
+
+ if (BKE_blendfile_workspace_config_write(bmain, filepath, op->reports) != 0) {
+ printf("ok\n");
+ return OPERATOR_FINISHED;
+ }
+ else {
+ printf("fail\n");
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void WM_OT_save_workspace_file(wmOperatorType *ot)
+{
+ ot->name = "Save Workspace Configuration";
+ ot->idname = "WM_OT_save_workspace_file";
+ ot->description = "Save workspaces of the current file as part of the user configuration";
+
+ ot->invoke = WM_operator_confirm;
+ ot->exec = wm_workspace_configuration_file_write_exec;
+}
+
static int wm_history_file_read_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
{
ED_file_read_bookmarks();
@@ -1397,11 +1571,11 @@ void WM_OT_read_history(wmOperatorType *ot)
static int wm_homefile_read_exec(bContext *C, wmOperator *op)
{
- const bool from_memory = (STREQ(op->type->idname, "WM_OT_read_factory_settings"));
+ const bool use_factory_settings = (STREQ(op->type->idname, "WM_OT_read_factory_settings"));
char filepath_buf[FILE_MAX];
const char *filepath = NULL;
- if (!from_memory) {
+ if (!use_factory_settings) {
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "filepath");
/* This can be used when loading of a start-up file should only change
@@ -1423,7 +1597,34 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op)
G.fileflags &= ~G_FILE_NO_UI;
}
- return wm_homefile_read(C, op->reports, from_memory, filepath) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ char app_template_buf[sizeof(U.app_template)];
+ const char *app_template;
+ PropertyRNA *prop_app_template = RNA_struct_find_property(op->ptr, "app_template");
+ const bool use_splash = !use_factory_settings && RNA_boolean_get(op->ptr, "use_splash");
+ const bool use_empty_data = RNA_boolean_get(op->ptr, "use_empty");
+
+ if (prop_app_template && RNA_property_is_set(op->ptr, prop_app_template)) {
+ RNA_property_string_get(op->ptr, prop_app_template, app_template_buf);
+ app_template = app_template_buf;
+ }
+ else if (!use_factory_settings) {
+ /* TODO: dont reset prefs on 'New File' */
+ BLI_strncpy(app_template_buf, U.app_template, sizeof(app_template_buf));
+ app_template = app_template_buf;
+ }
+ else {
+ app_template = NULL;
+ }
+
+ if (wm_homefile_read(C, op->reports, use_factory_settings, use_empty_data, filepath, app_template)) {
+ if (use_splash) {
+ WM_init_splash(C);
+ }
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
void WM_OT_read_homefile(wmOperatorType *ot)
@@ -1446,17 +1647,36 @@ void WM_OT_read_homefile(wmOperatorType *ot)
"Load user interface setup from the .blend file");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "use_empty", false, "Empty", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ /* So the splash can be kept open after loading a file (for templates). */
+ prop = RNA_def_boolean(ot->srna, "use_splash", false, "Splash", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ prop = RNA_def_string(ot->srna, "app_template", "Template", sizeof(U.app_template), "", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
/* omit poll to run in background mode */
}
void WM_OT_read_factory_settings(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
ot->name = "Load Factory Settings";
ot->idname = "WM_OT_read_factory_settings";
ot->description = "Load default file and user preferences";
ot->invoke = WM_operator_confirm;
ot->exec = wm_homefile_read_exec;
+
+ prop = RNA_def_string(ot->srna, "app_template", "Template", sizeof(U.app_template), "", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(ot->srna, "use_empty", false, "Empty", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
/* omit poll to run in background mode */
}
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index 3405537a09c..af0d2be8097 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -59,7 +59,7 @@
#include "BLO_readfile.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_library_remap.h"
#include "BKE_global.h"
@@ -69,6 +69,8 @@
#include "BKE_idcode.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "IMB_colormanagement.h"
@@ -131,8 +133,8 @@ 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"))
@@ -212,7 +214,7 @@ static WMLinkAppendDataItem *wm_link_append_data_item_add(
}
static void wm_link_do(
- WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, View3D *v3d,
+ WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, SceneLayer *sl,
const bool use_placeholders, const bool force_indirect)
{
Main *mainl;
@@ -261,7 +263,7 @@ static void wm_link_do(
}
new_id = BLO_library_link_named_part_ex(
- mainl, &bh, item->idcode, item->name, flag, scene, v3d, use_placeholders, force_indirect);
+ mainl, &bh, item->idcode, item->name, flag, scene, sl, use_placeholders, force_indirect);
if (new_id) {
/* If the link is successful, clear item's libs 'todo' flags.
@@ -271,21 +273,58 @@ static void wm_link_do(
}
}
- BLO_library_link_end(mainl, &bh, flag, scene, v3d);
+ BLO_library_link_end(mainl, &bh, flag, scene, sl);
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);
+ SceneLayer *sl = CTX_data_scene_layer(C);
PropertyRNA *prop;
WMLinkAppendData *lapp_data;
char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX];
char *group, *name;
int totfiles = 0;
short flag;
+ bool has_item = false;
+ bool do_append;
RNA_string_get(op->ptr, "filename", relname);
RNA_string_get(op->ptr, "directory", root);
@@ -323,6 +362,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
}
flag = wm_link_append_flag(op);
+ do_append = (flag & FILE_LINK) == 0;
/* sanity checks for flag */
if (scene && scene->id.lib) {
@@ -334,8 +374,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 (sl && RNA_boolean_get(op->ptr, "autoselect")) {
+ BKE_scene_layer_base_deselect_all(sl);
}
/* tag everything, all untagged data can be made local
@@ -358,7 +398,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;
}
@@ -366,6 +406,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
BLI_ghash_insert(libraries, BLI_strdup(libname), SET_INT_IN_POINTER(lib_idx));
lib_idx++;
wm_link_append_data_library_add(lapp_data, libname);
+ has_item = true;
}
}
}
@@ -379,8 +420,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;
}
@@ -388,6 +429,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
item = wm_link_append_data_item_add(lapp_data, name, BKE_idcode_from_name(group), NULL);
BLI_BITMAP_ENABLE(item->libraries, lib_idx);
+ has_item = true;
}
}
RNA_END;
@@ -400,12 +442,18 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
wm_link_append_data_library_add(lapp_data, libname);
item = wm_link_append_data_item_add(lapp_data, name, BKE_idcode_from_name(group), NULL);
BLI_BITMAP_ENABLE(item->libraries, 0);
+ has_item = true;
+ }
+
+ if (!has_item) {
+ wm_link_append_data_free(lapp_data);
+ return OPERATOR_CANCELLED;
}
/* 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), false, false);
+ wm_link_do(lapp_data, op->reports, bmain, scene, sl, false, false);
/* BKE_main_unlock(bmain); */
@@ -414,12 +462,12 @@ 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");
if (use_recursive) {
- BKE_library_make_local(bmain, NULL, true, set_fake);
+ BKE_library_make_local(bmain, NULL, NULL, true, set_fake);
}
else {
LinkNode *itemlink;
@@ -430,7 +478,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
ID *new_id = ((WMLinkAppendDataItem *)(itemlink->link))->new_id;
if (new_id && !BLI_gset_haskey(done_libraries, new_id->lib)) {
- BKE_library_make_local(bmain, new_id->lib, true, set_fake);
+ BKE_library_make_local(bmain, new_id->lib, NULL, true, set_fake);
BLI_gset_insert(done_libraries, new_id->lib);
}
}
@@ -445,11 +493,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);
+ /* 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);
+
/* 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();
+ DEG_scene_relations_rebuild(bmain, scene);
/* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */
BLI_strncpy(G.lib, root, FILE_MAX);
@@ -466,13 +520,13 @@ static void wm_link_append_properties_common(wmOperatorType *ot, bool is_link)
/* better not save _any_ settings for this operator */
/* properties */
prop = RNA_def_boolean(ot->srna, "link", is_link,
- "Link", "Link the objects or datablocks rather than appending");
+ "Link", "Link the objects or data-blocks rather than appending");
RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
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");
@@ -560,6 +614,7 @@ static void lib_relocate_do(
LinkNode *itemlink;
int item_idx;
+ bool has_item = false;
/* Remove all IDs to be reloaded from Main. */
lba_idx = set_listbasepointers(bmain, lbarray);
@@ -581,6 +636,7 @@ static void lib_relocate_do(
BLI_remlink(lbarray[lba_idx], id);
item = wm_link_append_data_item_add(lapp_data, id->name + 2, idcode, id);
BLI_BITMAP_SET_ALL(item->libraries, true, lapp_data->num_libraries);
+ has_item = true;
#ifdef PRINT_DEBUG
printf("\tdatablock to seek for: %s\n", id->name);
@@ -589,6 +645,11 @@ static void lib_relocate_do(
}
}
+ if (!has_item) {
+ /* nothing to relocate */
+ return;
+ }
+
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
/* We do not want any instanciation here! */
@@ -608,7 +669,8 @@ static void lib_relocate_do(
}
/* Note that in reload case, we also want to replace indirect usages. */
- const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE);
+ const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE |
+ (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE);
for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; item_idx++, itemlink = itemlink->next) {
WMLinkAppendDataItem *item = itemlink->link;
ID *old_id = item->customdata;
@@ -675,7 +737,7 @@ static void lib_relocate_do(
id_sort_by_name(which_libbase(bmain, GS(old_id->name)), old_id);
BKE_reportf(reports, RPT_WARNING,
- "Lib Reload: Replacing all references to old datablock '%s' by reloaded one failed, "
+ "Lib Reload: Replacing all references to old data-block '%s' by reloaded one failed, "
"old one (%d remaining users) had to be kept and was renamed to '%s'",
new_id->name, old_id->us, old_id->name);
}
@@ -736,10 +798,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();
+ DEG_scene_relations_rebuild(bmain, scene);
}
void WM_lib_reload(Library *lib, bContext *C, ReportList *reports)
diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c
index 1357729e898..73694295fef 100644
--- a/source/blender/windowmanager/intern/wm_gesture.c
+++ b/source/blender/windowmanager/intern/wm_gesture.c
@@ -37,6 +37,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_bitmap_draw_2d.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -44,15 +45,15 @@
#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"
@@ -167,69 +168,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);
-
- 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);
+
+ uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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("num_colors", 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(GWN_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);
-
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
-
+
+ uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
+
+ glEnable(GL_BLEND);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.05f);
+
+ immRecti(shdr_pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
+
+ immUnbindProgram();
+
+ glDisable(GL_BLEND);
+
+ shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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("num_colors", 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_line_box(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 = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.05f);
+ imm_draw_circle_fill(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);
-
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- glTranslatef(-rect->xmin, -rect->ymin, 0.0f);
-
+
+ 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("num_colors", 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(shdr_pos, (float)rect->xmin, (float)rect->ymin, (float)rect->xmax, 40);
+
+ immUnbindProgram();
}
struct LassoFillData {
@@ -252,6 +283,7 @@ static void draw_filled_lasso(wmWindow *win, wmGesture *gt)
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];
@@ -272,33 +304,33 @@ static void draw_filled_lasso(wmWindow *win, wmGesture *gt)
unsigned char *pixel_buf = MEM_callocN(sizeof(*pixel_buf) * w * h, __func__);
struct LassoFillData lasso_fill_data = {pixel_buf, w};
- fill_poly_v2i_n(
+ BLI_bitmap_draw_2d_poly_v2i_n(
rect.xmin, rect.ymin, rect.xmax, rect.ymax,
(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);
}
MEM_freeN(moves);
@@ -314,29 +346,34 @@ static void wm_gesture_draw_lasso(wmWindow *win, wmGesture *gt, bool filled)
draw_filled_lasso(win, gt);
}
- // 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);
-
+ const int numverts = gt->points;
+
+ /* Nothing to draw, do early output. */
+ if (numverts < 2) {
+ return;
+ }
+
+ const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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("num_colors", 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) ? GWN_PRIM_LINE_LOOP : GWN_PRIM_LINE_STRIP, numverts);
+
+ for (i = 0; i < gt->points; i++, lasso += 2) {
+ immVertex2f(shdr_pos, (float)lasso[0], (float)lasso[1]);
+ }
+
+ immEnd();
+
+ immUnbindProgram();
}
static void wm_gesture_draw_cross(wmWindow *win, wmGesture *gt)
@@ -345,25 +382,49 @@ 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 = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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("num_colors", 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(GWN_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 */
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);
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 3022d865460..a96ddb7368a 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -119,10 +119,11 @@
#include "GPU_draw.h"
#include "GPU_init_exit.h"
-#include "BKE_depsgraph.h"
#include "BKE_sound.h"
#include "COM_compositor.h"
+#include "DEG_depsgraph.h"
+
#ifdef WITH_OPENSUBDIV
# include "BKE_subsurf.h"
#endif
@@ -164,24 +165,27 @@ void WM_init(bContext *C, int argc, const char **argv)
wm_operatortype_init();
WM_menutype_init();
WM_uilisttype_init();
+ wm_manipulatortype_init();
+ wm_manipulatorgrouptype_init();
BKE_undo_callback_wm_kill_jobs_set(wm_undo_kill_callback);
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_manipulatormap_set(wm_manipulatormap_remove); /* screen.c */
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_render_scene_update_pre);
ED_spacetypes_init(); /* editors/space_api/spacetype.c */
ED_file_init(); /* for fsmenu */
ED_node_init_butfuncs();
- BLF_init(11, U.dpi); /* Please update source/gamengine/GamePlayer/GPG_ghost.cpp if you change this */
+ BLF_init(); /* Please update source/gamengine/GamePlayer/GPG_ghost.cpp if you change this */
BLT_lang_init();
/* Enforce loading the UI for the initial homefile */
@@ -192,14 +196,17 @@ void WM_init(bContext *C, int argc, const char **argv)
wm_init_reports(C);
/* get the default database, plus a wm */
- wm_homefile_read(C, NULL, G.factory_startup, NULL);
+ wm_homefile_read(C, NULL, G.factory_startup, false, NULL, NULL);
BLT_lang_set(NULL);
if (!G.background) {
+
+#ifdef WITH_INPUT_NDOF
/* sets 3D mouse deadzone */
WM_ndof_deadzone_set(U.ndof_deadzone);
+#endif
GPU_init();
@@ -441,8 +448,6 @@ void WM_exit_ext(bContext *C, const bool do_python)
{
wmWindowManager *wm = C ? CTX_wm_manager(C) : NULL;
- BKE_sound_exit();
-
/* first wrap up running stuff, we assume only the active WM is running */
/* modal handlers are on window level freed, others too? */
/* note; same code copied in wm_files.c */
@@ -475,7 +480,7 @@ 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));
}
}
@@ -524,9 +529,13 @@ void WM_exit_ext(bContext *C, const bool do_python)
ANIM_fmodifiers_copybuf_free();
ED_gpencil_anim_copybuf_free();
ED_gpencil_strokes_copybuf_free();
- ED_clipboard_posebuf_free();
BKE_node_clipboard_clear();
+ /* free manipulator-maps after freeing blender, so no deleted data get accessed during cleaning up of areas */
+ wm_manipulatormaptypes_free();
+ wm_manipulatorgrouptype_free();
+ wm_manipulatortype_free();
+
BLF_exit();
#ifdef WITH_INTERNATIONAL
@@ -572,7 +581,7 @@ void WM_exit_ext(bContext *C, const bool do_python)
ED_file_exit(); /* for fsmenu */
UI_exit();
- BKE_blender_userdef_free();
+ BKE_blender_userdef_free_data(&U);
RNA_exit(); /* should be after BPY_python_end so struct python slots are cleared */
@@ -589,6 +598,10 @@ void WM_exit_ext(bContext *C, const bool do_python)
BLI_threadapi_exit();
+ /* No need to call this early, rather do it late so that other pieces of Blender using sound may exit cleanly,
+ * see also T50676. */
+ BKE_sound_exit();
+
BKE_blender_atexit();
if (MEM_get_memory_blocks_in_use() != 0) {
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index a11733c060b..db5fc23146f 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -77,6 +77,10 @@ static wmKeyMapItem *wm_keymap_item_copy(wmKeyMapItem *kmi)
kmin->properties = IDP_CopyProperty(kmin->properties);
kmin->ptr->data = kmin->properties;
}
+ else {
+ kmin->properties = NULL;
+ kmin->ptr = NULL;
+ }
return kmin;
}
@@ -87,6 +91,8 @@ static void wm_keymap_item_free(wmKeyMapItem *kmi)
if (kmi->ptr) {
WM_operator_properties_free(kmi->ptr);
MEM_freeN(kmi->ptr);
+ kmi->ptr = NULL;
+ kmi->properties = NULL;
}
}
@@ -115,12 +121,19 @@ static void wm_keymap_item_properties_update_ot(wmKeyMapItem *kmi)
if (ot->srna != kmi->ptr->type) {
/* matches wm_keymap_item_properties_set but doesnt alloc new ptr */
WM_operator_properties_create_ptr(kmi->ptr, ot);
+ /* 'kmi->ptr->data' NULL'd above, keep using existing properties.
+ * Note: the operators property types may have changed,
+ * we will need a more comprehensive sanitize function to support this properly.
+ */
+ if (kmi->properties) {
+ kmi->ptr->data = kmi->properties;
+ }
WM_operator_properties_sanitize(kmi->ptr, 1);
}
}
else {
/* zombie keymap item */
- MEM_SAFE_FREE(kmi->ptr);
+ wm_keymap_item_free(kmi);
}
}
}
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 78273615602..5001fc7817f 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -70,7 +70,6 @@
#include "BKE_blender_version.h"
#include "BKE_brush.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_icons.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
@@ -86,9 +85,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"
@@ -97,8 +99,6 @@
#include "ED_util.h"
#include "ED_view3d.h"
-#include "GPU_basic_shader.h"
-
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -158,18 +158,20 @@ void WM_operatortype_iter(GHashIterator *ghi)
BLI_ghashIterator_init(ghi, global_ops_hash);
}
-/* all ops in 1 list (for time being... needs evaluation later) */
-void WM_operatortype_append(void (*opfunc)(wmOperatorType *))
+/** \name Operator Type Append
+ * \{ */
+
+static wmOperatorType *wm_operatortype_append__begin(void)
{
- wmOperatorType *ot;
-
- ot = MEM_callocN(sizeof(wmOperatorType), "operatortype");
+ wmOperatorType *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;
- opfunc(ot);
-
+ return ot;
+}
+static void wm_operatortype_append__end(wmOperatorType *ot)
+{
if (ot->name == NULL) {
fprintf(stderr, "ERROR: Operator %s has no name property!\n", ot->idname);
ot->name = N_("Dummy Name");
@@ -182,22 +184,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);
- RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP);
- RNA_def_struct_identifier(ot->srna, ot->idname);
-
- BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
+ wm_operatortype_append__end(ot);
}
+/** \} */
+
/* ********************* macro operator ******************** */
typedef struct {
@@ -900,7 +903,7 @@ void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
void WM_operator_properties_create(PointerRNA *ptr, const char *opstring)
{
- wmOperatorType *ot = WM_operatortype_find(opstring, 0);
+ wmOperatorType *ot = WM_operatortype_find(opstring, false);
if (ot)
WM_operator_properties_create_ptr(ptr, ot);
@@ -1104,45 +1107,70 @@ 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);
+ 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;
}
@@ -1369,12 +1397,13 @@ typedef struct wmOpPopUp {
/* Only invoked by OK button in popups created with wm_block_dialog_create() */
static void dialog_exec_cb(bContext *C, void *arg1, void *arg2)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- wmWindow *win = CTX_wm_window(C);
-
wmOpPopUp *data = arg1;
uiBlock *block = arg2;
+ /* Explicitly set UI_RETURN_OK flag, otherwise the menu might be cancelled
+ * in case WM_operator_call_ex exits/reloads the current file (T49199). */
+ UI_popup_menu_retval_set(block, UI_RETURN_OK, true);
+
WM_operator_call_ex(C, data->op, true);
/* let execute handle freeing it */
@@ -1384,27 +1413,23 @@ static void dialog_exec_cb(bContext *C, void *arg1, void *arg2)
/* in this case, wm_operator_ui_popup_cancel wont run */
MEM_freeN(data);
+ /* get context data *after* WM_operator_call_ex which might have closed the current file and changed context */
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
+
/* check window before 'block->handle' incase the
- * popup execution closed the window and freed the block. see T44688. */
+ * popup execution closed the window and freed the block. see T44688.
+ */
+ /* Post 2.78 TODO: Check if this fix and others related to T44688 are still
+ * needed or can be improved now that requesting context data has been corrected
+ * (see above). We're close to release so not a good time for experiments.
+ * -- Julian
+ */
if (BLI_findindex(&wm->windows, win) != -1) {
UI_popup_block_close(C, win, block);
}
}
-static void popup_check_cb(bContext *C, void *op_ptr, void *UNUSED(arg))
-{
- wmOperator *op = op_ptr;
- if (op->type->check) {
- if (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);
- }
- }
- }
-}
-
/* Dialogs are popups that require user verification (click OK) before exec */
static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData)
{
@@ -1423,8 +1448,6 @@ 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);
- UI_block_func_set(block, popup_check_cb, op, NULL);
-
uiLayoutOperatorButs(C, layout, op, NULL, 'H', UI_LAYOUT_OP_SHOW_TITLE);
/* clear so the OK button is left alone */
@@ -1463,8 +1486,6 @@ 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);
- UI_block_func_set(block, popup_check_cb, op, NULL);
-
/* since ui is defined the auto-layout args are not used */
uiLayoutOperatorButs(C, layout, op, NULL, 'V', 0);
@@ -1511,7 +1532,7 @@ int WM_operator_ui_popup(bContext *C, wmOperator *op, int width, int height)
data->width = width;
data->height = height;
data->free_op = true; /* if this runs and gets registered we may want not to free it */
- UI_popup_block_ex(C, wm_operator_ui_create, NULL, wm_operator_ui_popup_cancel, data);
+ UI_popup_block_ex(C, wm_operator_ui_create, NULL, wm_operator_ui_popup_cancel, data, op);
return OPERATOR_RUNNING_MODAL;
}
@@ -1541,7 +1562,7 @@ static int wm_operator_props_popup_ex(bContext *C, wmOperator *op,
if (!do_redo || !(U.uiflag & USER_GLOBALUNDO))
return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, UI_UNIT_Y);
- UI_popup_block_ex(C, wm_block_create_redo, NULL, wm_block_redo_cancel_cb, op);
+ UI_popup_block_ex(C, wm_block_create_redo, NULL, wm_block_redo_cancel_cb, op, op);
if (do_call)
wm_block_redo_cb(C, op, 0);
@@ -1583,7 +1604,7 @@ int WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width, int h
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 */
- UI_popup_block_ex(C, wm_block_dialog_create, wm_operator_ui_popup_ok, wm_operator_ui_popup_cancel, data);
+ UI_popup_block_ex(C, wm_block_dialog_create, wm_operator_ui_popup_ok, wm_operator_ui_popup_cancel, data, op);
return OPERATOR_RUNNING_MODAL;
}
@@ -1750,6 +1771,36 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
ibuf = IMB_ibImageFromMemory((unsigned char *)datatoc_splash_png,
datatoc_splash_png_size, IB_rect, NULL, "<splash screen>");
}
+
+ /* overwrite splash with template image */
+ if (U.app_template[0] != '\0') {
+ ImBuf *ibuf_template = NULL;
+ char splash_filepath[FILE_MAX];
+ char template_directory[FILE_MAX];
+
+ if (BKE_appdir_app_template_id_search(
+ U.app_template,
+ template_directory, sizeof(template_directory)))
+ {
+ BLI_join_dirfile(
+ splash_filepath, sizeof(splash_filepath), template_directory,
+ (U.pixelsize == 2) ? "splash_2x.png" : "splash.png");
+ 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;
+ /* 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]));
+ }
+ else {
+ printf("Splash expected %dx%d found %dx%d, ignoring: %s\n",
+ x_expect, y_expect, ibuf_template->x, ibuf_template->y, splash_filepath);
+ }
+ IMB_freeImBuf(ibuf_template);
+ }
+ }
+ }
#endif
block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
@@ -1775,13 +1826,13 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
if (version_suffix != NULL && version_suffix[0]) {
/* placed after the version number in the image,
* placing y is tricky to match baseline */
- int x = 260 - (2 * UI_DPI_WINDOW_FAC);
- int y = 242 + (4 * UI_DPI_WINDOW_FAC);
- int w = 240;
+ 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 * U.pixelsize, y * U.pixelsize, w * U.pixelsize, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
+ but = uiDefBut(block, UI_BTYPE_LABEL, 0, version_suffix, 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);
@@ -1835,7 +1886,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
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",
- "http://www.blender.org/manual");
+ "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), "http://www.blender.org/documentation/blender_python_api_%d_%d"
@@ -2046,8 +2097,11 @@ static void WM_OT_call_menu_pie(wmOperatorType *ot)
static int 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;
@@ -2064,14 +2118,22 @@ static void WM_OT_window_close(wmOperatorType *ot)
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->exec = wm_window_duplicate_exec;
+ PropertyRNA *prop;
+
+ ot->name = "New Window";
+ ot->idname = "WM_OT_window_new";
+ ot->description = "Create a new Blender window";
+
+ ot->exec = wm_window_new_exec;
+ ot->invoke = wm_window_new_invoke;
ot->poll = wm_operator_winactive_normal;
+
+ prop = RNA_def_enum(ot->srna, "screen", DummyRNA_NULL_items, 0, "Screen", "");
+ RNA_def_enum_funcs(prop, wm_window_new_screen_itemf);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
+ ot->prop = prop;
}
static void WM_OT_window_fullscreen_toggle(wmOperatorType *ot)
@@ -2288,6 +2350,11 @@ int WM_border_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
+#ifdef WITH_INPUT_NDOF
+ else if (event->type == NDOF_MOTION) {
+ return OPERATOR_PASS_THROUGH;
+ }
+#endif
// /* Allow view navigation??? */
// else {
// return OPERATOR_PASS_THROUGH;
@@ -2402,6 +2469,11 @@ int WM_gesture_circle_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_FINISHED; /* use finish or we don't get an undo */
}
}
+#ifdef WITH_INPUT_NDOF
+ else if (event->type == NDOF_MOTION) {
+ return OPERATOR_PASS_THROUGH;
+ }
+#endif
/* Allow view navigation??? */
/* note, this gives issues: 1) other modal ops run on top (border select), 2) middlemouse is used now 3) tablet/trackpad? */
// else {
@@ -2851,8 +2923,8 @@ void WM_OT_straightline_gesture(wmOperatorType *ot)
/* *********************** radial control ****************** */
-#define WM_RADIAL_CONTROL_DISPLAY_SIZE (200)
-#define WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE (35)
+#define WM_RADIAL_CONTROL_DISPLAY_SIZE (200 * UI_DPI_FAC)
+#define WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE (35 * UI_DPI_FAC)
#define WM_RADIAL_CONTROL_DISPLAY_WIDTH (WM_RADIAL_CONTROL_DISPLAY_SIZE - WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE)
#define WM_RADIAL_MAX_STR 10
@@ -2964,8 +3036,8 @@ 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);
MEM_freeN(ibuf->rect_float);
MEM_freeN(ibuf);
}
@@ -2998,43 +3070,63 @@ 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);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
if (rc->gltex) {
+
+ unsigned int texCoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
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", GL_TEXTURE0);
/* 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);
+ gpuPushMatrix();
+ gpuRotate2D(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(GWN_PRIM_TRI_FAN, 4);
+
+ immAttrib2f(texCoord, 0, 0);
+ immVertex2f(pos, -radius, -radius);
+
+ immAttrib2f(texCoord, 1, 0);
+ immVertex2f(pos, radius, -radius);
+
+ immAttrib2f(texCoord, 1, 1);
+ immVertex2f(pos, radius, radius);
+
+ immAttrib2f(texCoord, 0, 1);
+ immVertex2f(pos, -radius, radius);
+
+ immEnd();
/* undo rotation */
if (rc->rot_prop)
- glPopMatrix();
+ gpuPopMatrix();
}
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(pos, 0.0f, 0.0f, radius, 40);
}
+
+ immUnbindProgram();
}
static void radial_control_paint_cursor(bContext *C, int x, int y, void *customdata)
@@ -3093,7 +3185,7 @@ 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);
+ gpuTranslate2f((float)x, (float)y);
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
@@ -3101,7 +3193,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);
+ gpuScale2fv(zoom);
}
/* draw rotated texture */
@@ -3110,26 +3202,41 @@ 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);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3fvAlpha(col, 0.5f);
if (rc->subtype == PROP_ANGLE) {
- glPushMatrix();
+ gpuPushMatrix();
+
/* 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);
+ gpuRotate2D(RAD2DEGF(rc->initial_value));
+ immBegin(GWN_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();
+ gpuRotate2D(RAD2DEGF(rc->current_value - rc->initial_value));
+ immBegin(GWN_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();
+
+ gpuPopMatrix();
}
/* 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(pos, 0.0f, 0.0f, r1, 40);
+ imm_draw_circle_wire(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(pos, 0.0, 0.0f, rmin, 40);
+ immUnbindProgram();
- BLF_size(fontid, 1.5 * fstyle_points, 1.0f / U.dpi);
+ BLF_size(fontid, 1.5 * fstyle_points * U.pixelsize, U.dpi);
BLF_enable(fontid, BLF_SHADOW);
BLF_shadow(fontid, 3, (const float[4]){0.0f, 0.0f, 0.0f, 0.5f});
BLF_shadow_offset(fontid, 1, -1);
@@ -3143,6 +3250,7 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
+
}
typedef enum {
@@ -3721,11 +3829,12 @@ 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);
@@ -3748,7 +3857,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_update_for_newframe(bmain->eval_ctx, bmain, scene);
}
else if (type == eRTAnimationPlay) {
/* play anim, return on same frame as started with */
@@ -3760,7 +3869,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_update_for_newframe(bmain->eval_ctx, bmain, scene);
redraw_timer_window_swap(C);
}
}
@@ -3848,28 +3957,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 {
@@ -3889,8 +3976,12 @@ static void previews_id_ensure(bContext *C, Scene *scene, ID *id)
}
}
-static int previews_id_ensure_callback(void *userdata, ID *UNUSED(self_id), ID **idptr, int UNUSED(cd_flag))
+static int previews_id_ensure_callback(void *userdata, ID *UNUSED(self_id), ID **idptr, int cb_flag)
{
+ if (cb_flag & IDWALK_CB_PRIVATE) {
+ return IDWALK_RET_NOP;
+ }
+
PreviewsIDEnsureData *data = userdata;
ID *id = *idptr;
@@ -3923,7 +4014,7 @@ static int previews_ensure_exec(bContext *C, wmOperator *UNUSED(op))
preview_id_data.scene = scene;
id = (ID *)scene;
- BKE_library_foreach_ID_link(id, previews_id_ensure_callback, &preview_id_data, IDWALK_RECURSE);
+ BKE_library_foreach_ID_link(NULL, id, previews_id_ensure_callback, &preview_id_data, IDWALK_RECURSE);
}
/* Check a last time for ID not used (fake users only, in theory), and
@@ -3942,9 +4033,9 @@ static int previews_ensure_exec(bContext *C, wmOperator *UNUSED(op))
static void WM_OT_previews_ensure(wmOperatorType *ot)
{
- ot->name = "Refresh DataBlock Previews";
+ ot->name = "Refresh Data-Block Previews";
ot->idname = "WM_OT_previews_ensure";
- ot->description = "Ensure datablock previews are available and up-to-date "
+ ot->description = "Ensure data-block previews are available and up-to-date "
"(to be saved in .blend file, only for some types like materials, textures, etc.)";
ot->exec = previews_ensure_exec;
@@ -4001,9 +4092,9 @@ static int previews_clear_exec(bContext *C, wmOperator *op)
static void WM_OT_previews_clear(wmOperatorType *ot)
{
- ot->name = "Clear DataBlock Previews";
+ ot->name = "Clear Data-Block Previews";
ot->idname = "WM_OT_previews_clear";
- ot->description = "Clear datablock previews (only for some types like objects, materials, textures, etc.)";
+ ot->description = "Clear data-block previews (only for some types like objects, materials, textures, etc.)";
ot->exec = previews_clear_exec;
ot->invoke = WM_menu_invoke;
@@ -4011,7 +4102,7 @@ static void WM_OT_previews_clear(wmOperatorType *ot)
ot->prop = RNA_def_enum_flag(ot->srna, "id_type", preview_id_type_items,
FILTER_ID_SCE | FILTER_ID_OB | FILTER_ID_GR |
FILTER_ID_MA | FILTER_ID_LA | FILTER_ID_WO | FILTER_ID_TE | FILTER_ID_IM,
- "DataBlock Type", "Which datablock previews to clear");
+ "Data-Block Type", "Which data-block previews to clear");
}
/* *************************** Doc from UI ************* */
@@ -4112,12 +4203,13 @@ void wm_operatortype_init(void)
global_ops_hash = BLI_ghash_str_new_ex("wm_operatortype_init gh", 2048);
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_read_history);
WM_operatortype_append(WM_OT_read_homefile);
WM_operatortype_append(WM_OT_read_factory_settings);
WM_operatortype_append(WM_OT_save_homefile);
WM_operatortype_append(WM_OT_save_userpref);
+ WM_operatortype_append(WM_OT_save_workspace_file);
WM_operatortype_append(WM_OT_userpref_autoexec_path_add);
WM_operatortype_append(WM_OT_userpref_autoexec_path_remove);
WM_operatortype_append(WM_OT_window_fullscreen_toggle);
@@ -4134,7 +4226,6 @@ void wm_operatortype_init(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);
@@ -4149,6 +4240,10 @@ void wm_operatortype_init(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);
+
+ /* manipulators */
+ WM_operatortype_append(MANIPULATORGROUP_OT_manipulator_select);
+ WM_operatortype_append(MANIPULATORGROUP_OT_manipulator_tweak);
}
/* circleselect-like modal operators */
@@ -4348,10 +4443,9 @@ void wm_window_keymap(wmKeyConfig *keyconf)
{
wmKeyMap *keymap = WM_keymap_find(keyconf, "Window", 0, 0);
wmKeyMapItem *kmi;
- const char *data_path;
/* 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);
+ WM_keymap_verify_item(keymap, "WM_OT_window_new", 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);
@@ -4386,7 +4480,9 @@ void wm_window_keymap(wmKeyConfig *keyconf)
/* 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 */
@@ -4433,8 +4529,9 @@ void wm_window_keymap(wmKeyConfig *keyconf)
RNA_string_set(kmi->ptr, "data_path", "area.type");
RNA_string_set(kmi->ptr, "value", "DOPESHEET_EDITOR");
+#ifdef WITH_INPUT_NDOF
/* ndof speed */
- data_path = "user_preferences.inputs.ndof_sensitivity";
+ 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);
@@ -4450,10 +4547,9 @@ void wm_window_keymap(wmKeyConfig *keyconf)
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);
- data_path = NULL;
- (void)data_path;
-
+#endif /* WITH_INPUT_NDOF */
+ wm_manipulators_keymap(keyconf);
gesture_circle_modal_keymap(keyconf);
gesture_border_modal_keymap(keyconf);
gesture_zoom_border_modal_keymap(keyconf);
@@ -4537,4 +4633,3 @@ EnumPropertyItem *RNA_mask_local_itemf(bContext *C, PointerRNA *ptr, PropertyRNA
{
return rna_id_itemf(C, ptr, r_free, C ? (ID *)CTX_data_main(C)->mask.first : NULL, true);
}
-
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index 6bf7bcc2934..fdcded8e50a 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -58,17 +58,22 @@
#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 "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
@@ -190,10 +195,7 @@ 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);
+ gpuOrtho2D(0.0f, 1.0f, 0.0f, 1.0f);
}
/* implementation */
@@ -308,42 +310,45 @@ 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);
-
+
/* checkerboard for case alpha */
if (ibuf->planes == 32) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- fdrawcheckerboard(offs_x, offs_y, offs_x + span_x, offs_y + span_y);
+ imm_draw_checker_box(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));
-
- glPixelZoom(ps->zoom * (ps->draw_flip[0] ? -1.0f : 1.0f),
- ps->zoom * (ps->draw_flip[1] ? -1.0f : 1.0f));
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- 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);
-
+
pupdate_time();
if (picture && (g_WS.qual & (WS_QUAL_SHIFT | WS_QUAL_LMOUSE)) && (fontid != -1)) {
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);
@@ -354,24 +359,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);
+ gpuPushProjectionMatrix();
+ gpuLoadIdentityProjectionMatrix();
+ gpuPushMatrix();
+ gpuLoadIdentity();
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3ub(0, 255, 0);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2f(pos, fac, -1.0f);
+ immVertex2f(pos, fac, 1.0f);
+ immEnd();
+
+ immUnbindProgram();
+
+ gpuPopMatrix();
+ gpuPopProjectionMatrix();
}
GHOST_SwapWindowBuffers(g_WS.ghost_window);
@@ -1255,8 +1261,11 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
//GHOST_ActivateWindowDrawingContext(g_WS.ghost_window);
+ /* initialize OpenGL immediate mode */
+ immInit();
+
/* initialize the font */
- BLF_init(11, 72);
+ BLF_init();
ps.fontid = BLF_load_mem("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
BLF_size(ps.fontid, 11, 72);
@@ -1428,8 +1437,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
ps.next_frame = ps.direction;
-
- while ((hasevent = GHOST_ProcessEvents(g_WS.ghost_system, 0)) || ps.wait2) {
+ while ((hasevent = GHOST_ProcessEvents(g_WS.ghost_system, ps.wait2))) {
if (hasevent) {
GHOST_DispatchEvents(g_WS.ghost_system);
}
@@ -1525,7 +1533,11 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
#endif
/* we still miss freeing a lot!,
* but many areas could skip initialization too for anim play */
-
+
+ GPU_shader_free_builtin_shaders();
+
+ immDestroy();
+
BLF_exit();
GHOST_DisposeWindow(g_WS.ghost_system, g_WS.ghost_window);
@@ -1538,7 +1550,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 5576a104123..1e63a0e4483 100644
--- a/source/blender/windowmanager/intern/wm_stereo.c
+++ b/source/blender/windowmanager/intern/wm_stereo.c
@@ -52,8 +52,7 @@
#include "ED_screen.h"
-#include "GPU_glew.h"
-#include "GPU_basic_shader.h"
+#include "GPU_immediate.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -83,48 +82,76 @@ static void wm_method_draw_stereo3d_pageflip(wmWindow *win)
glDrawBuffer(GL_BACK);
}
-static enum eStereo3dInterlaceType interlace_prev_type = -1;
-static char interlace_prev_swap = -1;
+static GPUInterlaceShader interlace_gpu_id_from_type(eStereo3dInterlaceType interlace_type)
+{
+ 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;
+ }
+}
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;
- 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;
- }
+ wmDrawData *drawdata[2];
+ for (int eye = 0; eye < 2; eye++) {
+ int view = swap ? !eye : eye;
+ drawdata[eye] = BLI_findlink(&win->drawdata, (view * 2) + 1);
+ }
- wm_triple_draw_textures(win, drawdata->triple, 1.0f);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ const int sizex = WM_window_pixels_x(win);
+ const int sizey = WM_window_pixels_y(win);
+
+ /* wmOrtho for the screen has this same offset */
+ float ratiox = sizex;
+ float ratioy = sizey;
+ float halfx = GLA_PIXEL_OFS;
+ float halfy = GLA_PIXEL_OFS;
+
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int texcoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_INTERLACE);
+
+ /* leave GL_TEXTURE0 as the latest bind texture */
+ for (int eye = 1; eye >= 0; eye--) {
+ glActiveTexture(GL_TEXTURE0 + eye);
+ glBindTexture(drawdata[eye]->triple->target, drawdata[eye]->triple->bind);
+ }
+
+ immUniform1i("image_a", 0);
+ immUniform1i("image_b", 1);
+
+ immUniform1i("interlace_id", interlace_gpu_id_from_type(interlace_type));
+
+ immBegin(GWN_PRIM_TRI_FAN, 4);
+
+ immAttrib2f(texcoord, halfx, halfy);
+ immVertex2f(pos, 0.0f, 0.0f);
+
+ immAttrib2f(texcoord, ratiox + halfx, halfy);
+ immVertex2f(pos, sizex, 0.0f);
+
+ immAttrib2f(texcoord, ratiox + halfx, ratioy + halfy);
+ immVertex2f(pos, sizex, sizey);
+
+ immAttrib2f(texcoord, halfx, ratioy + halfy);
+ immVertex2f(pos, 0.0f, sizey);
+
+ immEnd();
+ immUnbindProgram();
+
+ for (int eye = 0; eye < 2; eye++) {
+ glBindTexture(drawdata[eye]->triple->target, 0);
}
- interlace_prev_type = interlace_type;
- interlace_prev_swap = swap;
}
static void wm_method_draw_stereo3d_anaglyph(wmWindow *win)
@@ -168,11 +195,14 @@ static void wm_method_draw_stereo3d_sidebyside(wmWindow *win)
wmDrawData *drawdata;
wmDrawTriple *triple;
float halfx, halfy, ratiox, ratioy;
- float alpha = 1.0f;
int view;
int soffx;
bool cross_eyed = (win->stereo3d_format->flag & S3D_SIDEBYSIDE_CROSSEYED) != 0;
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int texcoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
for (view = 0; view < 2; view ++) {
drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1);
triple = drawdata->triple;
@@ -187,8 +217,6 @@ static void wm_method_draw_stereo3d_sidebyside(wmWindow *win)
soffx = 0;
}
- glEnable(triple->target);
-
const int sizex = triple->x;
const int sizey = triple->y;
@@ -206,26 +234,33 @@ static void wm_method_draw_stereo3d_sidebyside(wmWindow *win)
halfy /= triple->y;
}
+ /* TODO: if target is always same for both eyes, bind program & set uniform before loop */
+ immBindBuiltinProgram((triple->target == GL_TEXTURE_2D) ? GPU_SHADER_3D_IMAGE_MODULATE_ALPHA : GPU_SHADER_3D_IMAGE_RECT_MODULATE_ALPHA);
+
glBindTexture(triple->target, triple->bind);
- glColor4f(1.0f, 1.0f, 1.0f, alpha);
- glBegin(GL_QUADS);
- glTexCoord2f(halfx, halfy);
- glVertex2f(soffx, 0);
+ immUniform1f("alpha", 1.0f);
+ immUniform1i("image", 0); /* default GL_TEXTURE0 unit */
+
+ immBegin(GWN_PRIM_TRI_FAN, 4);
- glTexCoord2f(ratiox + halfx, halfy);
- glVertex2f(soffx + (sizex * 0.5f), 0);
+ immAttrib2f(texcoord, halfx, halfy);
+ immVertex2f(pos, soffx, 0.0f);
- glTexCoord2f(ratiox + halfx, ratioy + halfy);
- glVertex2f(soffx + (sizex * 0.5f), sizey);
+ immAttrib2f(texcoord, ratiox + halfx, halfy);
+ immVertex2f(pos, soffx + (sizex * 0.5f), 0.0f);
- glTexCoord2f(halfx, ratioy + halfy);
- glVertex2f(soffx, sizey);
- glEnd();
+ immAttrib2f(texcoord, ratiox + halfx, ratioy + halfy);
+ immVertex2f(pos, soffx + (sizex * 0.5f), sizey);
+ immAttrib2f(texcoord, halfx, ratioy + halfy);
+ immVertex2f(pos, soffx, sizey);
+
+ immEnd();
+
+ /* TODO: if target is always same for both eyes, unbind program & texture target after loop */
glBindTexture(triple->target, 0);
- glDisable(triple->target);
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ immUnbindProgram();
}
}
@@ -234,10 +269,13 @@ static void wm_method_draw_stereo3d_topbottom(wmWindow *win)
wmDrawData *drawdata;
wmDrawTriple *triple;
float halfx, halfy, ratiox, ratioy;
- float alpha = 1.0f;
int view;
int soffy;
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int texcoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
for (view = 0; view < 2; view ++) {
drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1);
triple = drawdata->triple;
@@ -249,8 +287,6 @@ static void wm_method_draw_stereo3d_topbottom(wmWindow *win)
soffy = 0;
}
- glEnable(triple->target);
-
const int sizex = triple->x;
const int sizey = triple->y;
@@ -268,26 +304,33 @@ static void wm_method_draw_stereo3d_topbottom(wmWindow *win)
halfy /= triple->y;
}
+ /* TODO: if target is always same for both eyes, bind program & set uniforms before loop */
+ immBindBuiltinProgram((triple->target == GL_TEXTURE_2D) ? GPU_SHADER_3D_IMAGE_MODULATE_ALPHA : GPU_SHADER_3D_IMAGE_RECT_MODULATE_ALPHA);
+
glBindTexture(triple->target, triple->bind);
- glColor4f(1.0f, 1.0f, 1.0f, alpha);
- glBegin(GL_QUADS);
- glTexCoord2f(halfx, halfy);
- glVertex2f(0, soffy);
+ immUniform1f("alpha", 1.0f);
+ immUniform1i("image", 0); /* default GL_TEXTURE0 unit */
- glTexCoord2f(ratiox + halfx, halfy);
- glVertex2f(sizex, soffy);
+ immBegin(GWN_PRIM_TRI_FAN, 4);
- glTexCoord2f(ratiox + halfx, ratioy + halfy);
- glVertex2f(sizex, soffy + (sizey * 0.5f));
+ immAttrib2f(texcoord, halfx, halfy);
+ immVertex2f(pos, 0.0f, soffy);
- glTexCoord2f(halfx, ratioy + halfy);
- glVertex2f(0, soffy + (sizey * 0.5f));
- glEnd();
+ immAttrib2f(texcoord, ratiox + halfx, halfy);
+ immVertex2f(pos, sizex, soffy);
+ immAttrib2f(texcoord, ratiox + halfx, ratioy + halfy);
+ immVertex2f(pos, sizex, soffy + (sizey * 0.5f));
+
+ immAttrib2f(texcoord, halfx, ratioy + halfy);
+ immVertex2f(pos, 0.0f, soffy + (sizey * 0.5f));
+
+ immEnd();
+
+ /* TODO: if target is always same for both eyes, unbind program & texture target after loop */
+ immUnbindProgram();
glBindTexture(triple->target, 0);
- glDisable(triple->target);
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
}
@@ -316,9 +359,9 @@ void wm_method_draw_stereo3d(const bContext *UNUSED(C), wmWindow *win)
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)
@@ -330,7 +373,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 */
@@ -338,7 +382,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;
}
@@ -351,6 +395,32 @@ bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check)
return true;
}
+/**
+ * If needed, this adjusts \a r_mouse_xy so that drawn cursor and handled mouse position are matching visually.
+*/
+void wm_stereo3d_mouse_offset_apply(wmWindow *win, int *r_mouse_xy)
+{
+ if (!WM_stereo3d_enabled(win, false))
+ return;
+
+ if (win->stereo3d_format->display_mode == S3D_DISPLAY_SIDEBYSIDE) {
+ const int half_x = win->sizex / 2;
+ /* right half of the screen */
+ if (r_mouse_xy[0] > half_x) {
+ r_mouse_xy[0] -= half_x;
+ }
+ r_mouse_xy[0] *= 2;
+ }
+ else if (win->stereo3d_format->display_mode == S3D_DISPLAY_TOPBOTTOM) {
+ const int half_y = win->sizey / 2;
+ /* upper half of the screen */
+ if (r_mouse_xy[1] > half_y) {
+ r_mouse_xy[1] -= half_y;
+ }
+ r_mouse_xy[1] *= 2;
+ }
+}
+
/************************** Stereo 3D operator **********************************/
typedef struct Stereo3dData {
Stereo3dFormat stereo3d_format;
@@ -439,7 +509,7 @@ int wm_stereo3d_set_exec(bContext *C, wmOperator *op)
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))) {
+ if ((win_dst = wm_window_copy_test(C, win_src, false))) {
/* pass */
}
else {
@@ -449,14 +519,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))) {
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 458ac4a121a..1a8f71891c0 100644
--- a/source/blender/windowmanager/intern/wm_subwindow.c
+++ b/source/blender/windowmanager/intern/wm_subwindow.c
@@ -47,8 +47,7 @@
#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"
@@ -142,15 +141,17 @@ void wm_subwindow_origin_get(wmWindow *win, int swinid, int *x, int *y)
static void wm_swin_matrix_get(wmWindow *win, wmSubWindow *swin, float mat[4][4])
{
+ const bScreen *screen = WM_window_get_active_screen(win);
+
/* used by UI, should find a better way to get the matrix there */
- if (swin->swinid == win->screen->mainwin) {
+ if (swin->swinid == 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);
+ gpuGetProjectionMatrix(mat);
}
}
void wm_subwindow_matrix_get(wmWindow *win, int swinid, float mat[4][4])
@@ -216,7 +217,7 @@ int wm_subwindow_open(wmWindow *win, const rcti *winrct, bool activate)
/* extra service */
wm_swin_size_get(swin, &width, &height);
wmOrtho2_pixelspace(width, height);
- glLoadIdentity();
+ gpuLoadIdentity();
}
return swin->swinid;
@@ -322,7 +323,7 @@ void wmSubWindowScissorSet(wmWindow *win, int swinid, const rcti *srct, bool src
glScissor(_curswin->winrct.xmin, _curswin->winrct.ymin, width, height);
wmOrtho2_pixelspace(width, height);
- glLoadIdentity();
+ gpuLoadIdentity();
glFlush();
}
@@ -333,31 +334,13 @@ void wmSubWindowSet(wmWindow *win, int swinid)
wmSubWindowScissorSet(win, swinid, NULL, true);
}
-void wmFrustum(float x1, float x2, float y1, float y2, float n, float f)
-{
- 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();
-
- glOrtho(x1, x2, y1, y2, n, f);
-
- glMatrixMode(GL_MODELVIEW);
-}
-
void wmOrtho2(float x1, float x2, float y1, float y2)
{
/* prevent opengl from generating errors */
if (x1 == x2) x2 += 1.0f;
if (y1 == y2) y2 += 1.0f;
- wmOrtho(x1, x2, y1, y2, -100, 100);
+ gpuOrtho(x1, x2, y1, y2, -100, 100);
}
static void wmOrtho2_offset(const float x, const float y, const float ofs)
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 425287993d9..8068b048d10 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,12 +52,16 @@
#include "BKE_blender.h"
#include "BKE_context.h"
+#include "BKE_icons.h"
#include "BKE_library.h"
#include "BKE_global.h"
#include "BKE_main.h"
+#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "RNA_access.h"
+#include "RNA_define.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -66,17 +71,22 @@
#include "wm_subwindow.h"
#include "wm_event_system.h"
+#include "ED_scene.h"
#include "ED_screen.h"
#include "ED_fileselect.h"
#include "UI_interface.h"
+#include "UI_interface_icons.h"
#include "PIL_time.h"
#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_init_exit.h"
-#include "GPU_glew.h"
+#include "GPU_immediate.h"
+#include "BLF_api.h"
+
+#include "UI_resources.h"
/* for assert */
#ifndef NDEBUG
@@ -212,6 +222,7 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
wm_ghostwindow_destroy(win);
+ BKE_workspace_instance_hook_free(G.main, win->workspace_hook);
MEM_freeN(win->stereo3d_format);
MEM_freeN(win);
@@ -232,35 +243,60 @@ static int find_free_winid(wmWindowManager *wm)
/* don't change context itself */
wmWindow *wm_window_new(bContext *C)
{
+ 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->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Stereo 3D Format (window)");
+ win->workspace_hook = BKE_workspace_instance_hook_create(bmain);
return win;
}
+/**
+ * A higher level version of copy that tests the new window can be added.
+ */
+static wmWindow *wm_window_new_test(bContext *C)
+{
+ wmWindow *win = wm_window_new(C);
+
+ WM_check(C);
+
+ if (win->ghostwin) {
+ WM_event_add_notifier(C, NC_WINDOW | NA_ADDED, NULL);
+ return win;
+ }
+ else {
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wm_window_close(C, wm, win);
+ return NULL;
+ }
+}
/* 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)
{
wmWindow *win_dst = wm_window_new(C);
-
+ WorkSpace *workspace = WM_window_get_active_workspace(win_src);
+ WorkSpaceLayout *layout_old = WM_window_get_active_layout(win_src);
+ Scene *scene = WM_window_get_active_scene(win_src);
+ WorkSpaceLayout *layout_new;
+ bScreen *new_screen;
+
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(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->scene = scene;
+ WM_window_set_active_workspace(win_dst, workspace);
+ layout_new = duplicate_layout ? ED_workspace_layout_duplicate(workspace, layout_old, win_dst) : layout_old;
+ WM_window_set_active_layout(win_dst, workspace, layout_new);
+ new_screen = WM_window_get_active_screen(win_dst);
+ BLI_strncpy(win_dst->screenname, new_screen->id.name + 2, sizeof(win_dst->screenname));
win_dst->drawmethod = U.wmdrawmethod;
@@ -275,12 +311,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)
{
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);
WM_check(C);
@@ -304,14 +340,14 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
for (tmpwin = wm->windows.first; tmpwin; tmpwin = tmpwin->next) {
if (tmpwin == win)
continue;
- if (tmpwin->screen->temp == 0)
+ if (WM_window_is_temp_screen(tmpwin) == false)
break;
}
if (tmpwin == NULL)
do_exit = 1;
- if ((U.uiflag & USER_QUIT_PROMPT) && !wm->file_saved) {
+ if ((U.uiflag & USER_QUIT_PROMPT) && !wm->file_saved && !G.background) {
if (do_exit) {
if (!GHOST_confirmQuit(win->ghostwin))
return;
@@ -323,8 +359,10 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
WM_exit(C);
}
else {
- bScreen *screen = win->screen;
-
+ 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);
+
BLI_remlink(&wm->windows, win);
wm_draw_window_clear(win);
@@ -335,8 +373,8 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *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);
+ if (screen) {
+ ED_screen_exit(C, win, screen);
}
wm_window_free(C, wm, win);
@@ -344,14 +382,16 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *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);
+
+ 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 */
}
@@ -374,14 +414,41 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win)
}
}
-static float wm_window_get_virtual_pixelsize(void)
+void WM_window_set_dpi(wmWindow *win)
{
- return ((U.virtual_pixel == VIRTUAL_PIXEL_NATIVE) ? 1.0f : 2.0f);
-}
+ int auto_dpi = GHOST_GetDPIHint(win->ghostwin);
-float wm_window_pixelsize(wmWindow *win)
-{
- return (GHOST_GetNativePixelSize(win->ghostwin) * wm_window_get_virtual_pixelsize());
+ /* Lazily init UI scale size, preserving backwards compatibility by
+ * computing UI scale from ratio of previous DPI and auto DPI */
+ if (U.ui_scale == 0) {
+ int virtual_pixel = (U.virtual_pixel == VIRTUAL_PIXEL_NATIVE) ? 1 : 2;
+
+ if (U.dpi == 0) {
+ U.ui_scale = virtual_pixel;
+ }
+ else {
+ U.ui_scale = (virtual_pixel * U.dpi * 96.0f) / (auto_dpi * 72.0f);
+ }
+
+ CLAMP(U.ui_scale, 0.25f, 4.0f);
+ }
+
+ /* Blender's UI drawing assumes DPI 72 as a good default following macOS
+ * while Windows and Linux use DPI 96. GHOST assumes a default 96 so we
+ * remap the DPI to Blender's convention. */
+ int dpi = auto_dpi * U.ui_scale * (72.0 / 96.0f);
+
+ /* Automatically set larger pixel size for high DPI. */
+ int pixelsize = MAX2(1, dpi / 54);
+
+ /* Set user preferences globals for drawing, and for forward compatibility. */
+ U.pixelsize = GHOST_GetNativePixelSize(win->ghostwin) * pixelsize;
+ 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;
+
+ /* update font drawing */
+ BLF_default_dpi(U.pixelsize * U.dpi);
}
/* belongs to below */
@@ -456,10 +523,8 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
glClear(GL_COLOR_BUFFER_BIT);
}
- /* displays with larger native pixels, like Macbook. Used to scale dpi with */
/* needed here, because it's used before it reads userdef */
- U.pixelsize = wm_window_pixelsize(win);
- BKE_blender_userdef_refresh();
+ WM_window_set_dpi(win);
wm_window_swap_buffers(win);
@@ -618,22 +683,36 @@ wmWindow *WM_window_open(bContext *C, const rcti *rect)
* \param type: WM_WINDOW_RENDER, WM_WINDOW_USERPREFS...
* \return the window or NULL.
*/
-wmWindow *WM_window_open_temp(bContext *C, const rcti *rect_init, int type)
+wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, int type)
{
+ 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);
const char *title;
- rcti rect = *rect_init;
- const short px_virtual = (short)wm_window_get_virtual_pixelsize();
+
+ /* convert to native OS window coordinates */
+ const float native_pixel_size = GHOST_GetNativePixelSize(win_prev->ghostwin);
+ x /= native_pixel_size;
+ y /= native_pixel_size;
+ sizex /= native_pixel_size;
+ sizey /= native_pixel_size;
+
+ /* calculate postition */
+ rcti rect;
+ rect.xmin = x + win_prev->posx - sizex / 2;
+ rect.ymin = y + win_prev->posy - sizey / 2;
+ rect.xmax = rect.xmin + sizex;
+ rect.ymax = rect.ymin + sizey;
/* changes rect to fit within desktop */
wm_window_check_position(&rect);
/* 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? */
@@ -644,27 +723,36 @@ wmWindow *WM_window_open_temp(bContext *C, const rcti *rect_init, int type)
win->posy = rect.ymin;
}
- /* multiply with virtual pixelsize, ghost handles native one (e.g. for retina) */
- win->sizex = BLI_rcti_size_x(&rect) * px_virtual;
- win->sizey = BLI_rcti_size_y(&rect) * px_virtual;
+ screen = WM_window_get_active_screen(win);
+
+ win->sizex = BLI_rcti_size_x(&rect);
+ win->sizey = BLI_rcti_size_y(&rect);
if (win->ghostwin) {
wm_window_set_size(win, win->sizex, win->sizey);
wm_window_raise(win);
}
-
- if (win->screen == NULL) {
- /* add new screen */
- win->screen = ED_screen_add(win, scene, "temp");
+
+ if (WM_window_get_active_workspace(win) == NULL) {
+ WorkSpace *workspace = WM_window_get_active_workspace(win_prev);
+ WM_window_set_active_workspace(win, 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(workspace, win, "temp");
+
+ screen = BKE_workspace_layout_screen_get(layout);
+ WM_window_set_active_layout(win, workspace, layout);
}
- win->screen->temp = 1;
-
+ if (WM_window_get_active_scene(win) != scene) {
+ WM_window_change_active_scene(bmain, C, win, scene);
+ }
+
+ screen->temp = 1;
+
/* make window active, and validate/resize */
CTX_wm_window_set(C, win);
WM_check(C);
@@ -676,7 +764,7 @@ wmWindow *WM_window_open_temp(bContext *C, const rcti *rect_init, int type)
*/
/* 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) {
@@ -686,7 +774,7 @@ wmWindow *WM_window_open_temp(bContext *C, const rcti *rect_init, int type)
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 */
if (sa->spacetype == SPACE_IMAGE)
@@ -722,17 +810,104 @@ 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))
+static WorkSpaceLayout *wm_window_new_find_layout(wmOperator *op, WorkSpace *workspace)
+{
+ ListBase *listbase = BKE_workspace_layouts_get(workspace);
+ const int layout_id = RNA_enum_get(op->ptr, "screen");
+ int i = 0;
+
+ for (WorkSpaceLayout *layout = listbase->first; layout; layout = layout->next) {
+ if (i++ == layout_id) {
+ return layout;
+ }
+ }
+
+ BLI_assert(0);
+ return NULL;
+}
+
+/* new window operator callback */
+int wm_window_new_exec(bContext *C, wmOperator *op)
{
wmWindow *win_src = CTX_wm_window(C);
- bool ok;
+ WorkSpace *workspace = WM_window_get_active_workspace(win_src);
+ WorkSpaceLayout *layout_new = wm_window_new_find_layout(op, workspace);
+ bScreen *screen_new = BKE_workspace_layout_screen_get(layout_new);
+ wmWindow *win_dst;
- ok = (wm_window_copy_test(C, win_src) != NULL);
+ if ((win_dst = wm_window_new_test(C))) {
+ if (screen_new->winid) {
+ /* layout/screen is already used, duplicate it */
+ layout_new = ED_workspace_layout_duplicate(workspace, layout_new, win_dst);
+ screen_new = BKE_workspace_layout_screen_get(layout_new);
+ }
+ /* New window with a different screen but same workspace */
+ WM_window_set_active_workspace(win_dst, workspace);
+ WM_window_set_active_screen(win_dst, workspace, screen_new);
+ win_dst->scene = win_src->scene;
+ screen_new->winid = win_dst->winid;
+ CTX_wm_window_set(C, win_dst);
+ ED_screen_refresh(CTX_wm_manager(C), win_dst);
+ }
- return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ return (win_dst != NULL) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
+int wm_window_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ wmWindow *win = CTX_wm_window(C);
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ ListBase *listbase = BKE_workspace_layouts_get(workspace);
+
+ if (BLI_listbase_count_ex(listbase, 2) == 1) {
+ RNA_enum_set(op->ptr, "screen", 0);
+ return wm_window_new_exec(C, op);
+ }
+ else {
+ return WM_enum_search_invoke_previews(C, op, 6, 2);
+ }
+}
+
+struct EnumPropertyItem *wm_window_new_screen_itemf(
+ bContext *C, struct PointerRNA *UNUSED(ptr), struct PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ wmWindow *win = CTX_wm_window(C);
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ ListBase *listbase = BKE_workspace_layouts_get(workspace);
+ EnumPropertyItem *item = NULL;
+ EnumPropertyItem tmp = {0, "", 0, "", ""};
+ int value = 0, totitem = 0;
+ int count_act_screens = 0;
+ /* XXX setting max number of windows to 20. We'd need support
+ * for dynamic strings in EnumPropertyItem.name to avoid this. */
+ static char active_screens[20][MAX_NAME + 12];
+
+ for (WorkSpaceLayout *layout = listbase->first; layout; layout = layout->next) {
+ bScreen *screen = BKE_workspace_layout_screen_get(layout);
+ const char *layout_name = BKE_workspace_layout_name_get(layout);
+
+ if (screen->winid) {
+ BLI_snprintf(active_screens[count_act_screens], sizeof(*active_screens), "%s (Duplicate)", layout_name);
+ tmp.name = active_screens[count_act_screens++];
+ }
+ else {
+ tmp.name = layout_name;
+ }
+
+ tmp.value = value;
+ tmp.identifier = layout_name;
+ UI_id_icon_render(C, CTX_data_scene(C), &screen->id, true, false);
+ tmp.icon = BKE_icon_id_ensure(&screen->id);
+
+ RNA_enum_item_add(&item, &totitem, &tmp);
+ value++;
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
/* fullscreen operator callback */
int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op))
@@ -832,11 +1007,13 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
if (G.debug & G_DEBUG_EVENTS) {
printf("%s: set drawable %d\n", __func__, win->winid);
}
+
+ immDeactivate();
GHOST_ActivateWindowDrawingContext(win->ghostwin);
-
+ immActivate();
+
/* this can change per window */
- U.pixelsize = wm_window_pixelsize(win);
- BKE_blender_userdef_refresh();
+ WM_window_set_dpi(win);
}
}
@@ -1033,8 +1210,10 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
/* stop screencast if resize */
if (type == GHOST_kEventWindowSize) {
- WM_jobs_stop(wm, win->screen, NULL);
+ WM_jobs_stop(wm, WM_window_get_active_screen(win), NULL);
}
+
+ WM_window_set_dpi(win);
/* win32: gives undefined window size when minimized */
if (state != GHOST_kWindowStateMinimized) {
@@ -1066,6 +1245,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;
@@ -1102,6 +1283,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);
@@ -1118,7 +1300,18 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
}
break;
}
-
+
+ case GHOST_kEventWindowDPIHintChanged:
+ {
+ WM_window_set_dpi(win);
+ /* font's are stored at each DPI level, without this we can easy load 100's of fonts */
+ BLF_cache_clear();
+
+ WM_main_add_notifier(NC_WINDOW, NULL); /* full redraw */
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); /* refresh region sizes */
+ break;
+ }
+
case GHOST_kEventOpenMainFile:
{
PointerRNA props_ptr;
@@ -1197,23 +1390,26 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
}
case GHOST_kEventNativeResolutionChange:
{
- // printf("change, pixel size %f\n", GHOST_GetNativePixelSize(win->ghostwin));
-
- U.pixelsize = wm_window_pixelsize(win);
- BKE_blender_userdef_refresh();
+ // only update if the actual pixel size changes
+ float prev_pixelsize = U.pixelsize;
+ WM_window_set_dpi(win);
- // close all popups since they are positioned with the pixel
- // size baked in and it's difficult to correct them
- wmWindow *oldWindow = CTX_wm_window(C);
- CTX_wm_window_set(C, win);
- UI_popup_handlers_remove_all(C, &win->modalhandlers);
- CTX_wm_window_set(C, oldWindow);
+ if (U.pixelsize != prev_pixelsize) {
+ BKE_icon_changed(WM_window_get_active_screen(win)->id.icon_id);
- wm_window_make_drawable(wm, win);
- wm_draw_window_clear(win);
+ // close all popups since they are positioned with the pixel
+ // size baked in and it's difficult to correct them
+ wmWindow *oldWindow = CTX_wm_window(C);
+ CTX_wm_window_set(C, win);
+ UI_popup_handlers_remove_all(C, &win->modalhandlers);
+ CTX_wm_window_set(C, oldWindow);
- WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
- WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL);
+ wm_window_make_drawable(wm, win);
+ wm_draw_window_clear(win);
+
+ WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL);
+ }
break;
}
@@ -1706,6 +1902,86 @@ 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;
+}
+
+Scene *WM_window_get_active_scene(const wmWindow *win)
+{
+ return win->scene;
+}
+
+/**
+ * \warning Only call outside of area/region loops
+ */
+void WM_window_change_active_scene(Main *bmain, bContext *C, wmWindow *win, Scene *scene_new)
+{
+ const bScreen *screen = WM_window_get_active_screen(win);
+
+ ED_scene_exit(C);
+ win->scene = scene_new;
+ ED_scene_changed_update(bmain, C, scene_new, screen);
+}
+
+WorkSpace *WM_window_get_active_workspace(const wmWindow *win)
+{
+ return BKE_workspace_active_get(win->workspace_hook);
+}
+void WM_window_set_active_workspace(wmWindow *win, WorkSpace *workspace)
+{
+ BKE_workspace_active_set(win->workspace_hook, workspace);
+}
+
+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 */
diff --git a/source/blender/windowmanager/manipulators/WM_manipulator_api.h b/source/blender/windowmanager/manipulators/WM_manipulator_api.h
new file mode 100644
index 00000000000..d6774333ba4
--- /dev/null
+++ b/source/blender/windowmanager/manipulators/WM_manipulator_api.h
@@ -0,0 +1,264 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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/manipulators/WM_manipulator_api.h
+ * \ingroup wm
+ *
+ * \name Manipulator API
+ * \brief API for external use of wmManipulator types.
+ *
+ * Only included in WM_api.h
+ */
+
+
+#ifndef __WM_MANIPULATOR_API_H__
+#define __WM_MANIPULATOR_API_H__
+
+struct ARegion;
+struct GHashIterator;
+struct IDProperty;
+struct Main;
+struct PropertyRNA;
+struct wmKeyConfig;
+struct wmManipulator;
+struct wmManipulatorProperty;
+struct wmManipulatorPropertyType;
+struct wmManipulatorType;
+struct wmManipulatorGroup;
+struct wmManipulatorGroupType;
+struct wmManipulatorMap;
+struct wmManipulatorMapType;
+struct wmManipulatorMapType_Params;
+
+#include "wm_manipulator_fn.h"
+
+/* -------------------------------------------------------------------- */
+/* wmManipulator */
+
+struct wmManipulator *WM_manipulator_new_ptr(
+ const struct wmManipulatorType *wt, struct wmManipulatorGroup *mgroup,
+ const char *name, struct PointerRNA *properties);
+struct wmManipulator *WM_manipulator_new(
+ const char *idname, struct wmManipulatorGroup *mgroup,
+ const char *name, struct PointerRNA *properties);
+void WM_manipulator_free(
+ ListBase *manipulatorlist, struct wmManipulatorMap *mmap, struct wmManipulator *mpr,
+ struct bContext *C);
+
+void WM_manipulator_name_set(struct wmManipulatorGroup *mgroup, struct wmManipulator *mpr, const char *name);
+
+struct PointerRNA *WM_manipulator_set_operator(
+ struct wmManipulator *, struct wmOperatorType *ot, struct IDProperty *properties);
+
+/* callbacks */
+void WM_manipulator_set_fn_custom_modal(struct wmManipulator *mpr, wmManipulatorFnModal fn);
+
+void WM_manipulator_set_matrix_location(
+ struct wmManipulator *mpr, const float origin[3]);
+void WM_manipulator_set_matrix_rotation_from_z_axis(
+ struct wmManipulator *mpr, const float z_axis[3]);
+void WM_manipulator_set_matrix_rotation_from_yz_axis(
+ struct wmManipulator *mpr, const float y_axis[3], const float z_axis[3]);
+
+void WM_manipulator_set_matrix_offset_location(
+ struct wmManipulator *mpr, const float origin[3]);
+void WM_manipulator_set_matrix_offset_rotation_from_z_axis(
+ struct wmManipulator *mpr, const float z_axis[3]);
+void WM_manipulator_set_matrix_offset_rotation_from_yz_axis(
+ struct wmManipulator *mpr, const float y_axis[3], const float z_axis[3]);
+
+void WM_manipulator_set_flag(struct wmManipulator *mpr, const int flag, const bool enable);
+void WM_manipulator_set_scale(struct wmManipulator *mpr, float scale);
+void WM_manipulator_set_line_width(struct wmManipulator *mpr, const float line_width);
+
+void WM_manipulator_get_color(const struct wmManipulator *mpr, float col[4]);
+void WM_manipulator_set_color(struct wmManipulator *mpr, const float col[4]);
+void WM_manipulator_get_color_highlight(const struct wmManipulator *mpr, float col_hi[4]);
+void WM_manipulator_set_color_highlight(struct wmManipulator *mpr, const float col[4]);
+
+/* properties */
+void WM_manipulator_properties_create_ptr(struct PointerRNA *ptr, struct wmManipulatorType *wt);
+void WM_manipulator_properties_create(struct PointerRNA *ptr, const char *opstring);
+void WM_manipulator_properties_alloc(struct PointerRNA **ptr, struct IDProperty **properties, const char *wtstring);
+void WM_manipulator_properties_sanitize(struct PointerRNA *ptr, const bool no_context);
+bool WM_manipulator_properties_default(struct PointerRNA *ptr, const bool do_update);
+void WM_manipulator_properties_reset(struct wmManipulator *op);
+void WM_manipulator_properties_clear(struct PointerRNA *ptr);
+void WM_manipulator_properties_free(struct PointerRNA *ptr);
+
+
+/* wm_manipulator_type.c */
+const struct wmManipulatorType *WM_manipulatortype_find(const char *idname, bool quiet);
+void WM_manipulatortype_append(void (*wtfunc)(struct wmManipulatorType *));
+void WM_manipulatortype_append_ptr(void (*mnpfunc)(struct wmManipulatorType *, void *), void *userdata);
+bool WM_manipulatortype_remove(const char *idname);
+void WM_manipulatortype_remove_ptr(struct wmManipulatorType *wt);
+void WM_manipulatortype_iter(struct GHashIterator *ghi);
+
+/* wm_manipulator_group_type.c */
+struct wmManipulatorGroupType *WM_manipulatorgrouptype_find(const char *idname, bool quiet);
+struct wmManipulatorGroupType *WM_manipulatorgrouptype_append(void (*wtfunc)(struct wmManipulatorGroupType *));
+struct wmManipulatorGroupType *WM_manipulatorgrouptype_append_ptr(void (*mnpfunc)(struct wmManipulatorGroupType *, void *), void *userdata);
+bool WM_manipulatorgrouptype_remove(const char *idname);
+void WM_manipulatorgrouptype_remove_ptr(struct wmManipulatorGroupType *wt);
+void WM_manipulatorgrouptype_iter(struct GHashIterator *ghi);
+
+struct wmManipulatorGroupTypeRef *WM_manipulatorgrouptype_append_and_link(
+ struct wmManipulatorMapType *mmap_type,
+ void (*wtfunc)(struct wmManipulatorGroupType *));
+
+/* wm_manipulator_map.c */
+
+/* Dynamic Updates (for RNA runtime registration) */
+void WM_manipulatorconfig_update_tag_init(struct wmManipulatorMapType *mmap_type, struct wmManipulatorGroupType *wgt);
+void WM_manipulatorconfig_update_tag_remove(struct wmManipulatorMapType *mmap_type, struct wmManipulatorGroupType *wgt);
+void WM_manipulatorconfig_update(struct Main *bmain);
+
+
+/* wm_maniulator_target_props.c */
+struct wmManipulatorProperty *WM_manipulator_target_property_array(struct wmManipulator *mpr);
+struct wmManipulatorProperty *WM_manipulator_target_property_at_index(
+ struct wmManipulator *mpr, int index);
+struct wmManipulatorProperty *WM_manipulator_target_property_find(
+ struct wmManipulator *mpr, const char *idname);
+
+void WM_manipulator_target_property_def_rna_ptr(
+ struct wmManipulator *mpr, const struct wmManipulatorPropertyType *mpr_prop_type,
+ struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
+void WM_manipulator_target_property_def_rna(
+ struct wmManipulator *mpr, const char *idname,
+ struct PointerRNA *ptr, const char *propname, int index);
+
+void WM_manipulator_target_property_def_func_ptr(
+ struct wmManipulator *mpr, const struct wmManipulatorPropertyType *mpr_prop_type,
+ const struct wmManipulatorPropertyFnParams *params);
+void WM_manipulator_target_property_def_func(
+ struct wmManipulator *mpr, const char *idname,
+ const struct wmManipulatorPropertyFnParams *params);
+
+bool WM_manipulator_target_property_is_valid_any(struct wmManipulator *mpr);
+bool WM_manipulator_target_property_is_valid(
+ const struct wmManipulatorProperty *mpr_prop);
+float WM_manipulator_target_property_value_get(
+ const struct wmManipulator *mpr, struct wmManipulatorProperty *mpr_prop);
+void WM_manipulator_target_property_value_set(
+ struct bContext *C, const struct wmManipulator *mpr, struct wmManipulatorProperty *mpr_prop,
+ const float value);
+
+void WM_manipulator_target_property_value_get_array(
+ const struct wmManipulator *mpr, struct wmManipulatorProperty *mpr_prop,
+ float *value);
+void WM_manipulator_target_property_value_set_array(
+ struct bContext *C, const struct wmManipulator *mpr, struct wmManipulatorProperty *mpr_prop,
+ const float *value);
+
+void WM_manipulator_target_property_range_get(
+ const struct wmManipulator *mpr, struct wmManipulatorProperty *mpr_prop,
+ float range[2]);
+
+/* definitions */
+const struct wmManipulatorPropertyType *WM_manipulatortype_target_property_find(
+ const struct wmManipulatorType *wt, const char *idname);
+void WM_manipulatortype_target_property_def(
+ struct wmManipulatorType *wt, const char *idname, int data_type, int array_length);
+
+
+/* -------------------------------------------------------------------- */
+/* wmManipulatorGroup */
+
+/* Callbacks for 'wmManipulatorGroupType.setup_keymap' */
+struct wmKeyMap *WM_manipulatorgroup_keymap_common(
+ const struct wmManipulatorGroupType *wgt, struct wmKeyConfig *config);
+struct wmKeyMap *WM_manipulatorgroup_keymap_common_select(
+ const struct wmManipulatorGroupType *wgt, struct wmKeyConfig *config);
+
+
+/* -------------------------------------------------------------------- */
+/* wmManipulatorMap */
+
+struct wmManipulatorMap *WM_manipulatormap_new_from_type(
+ const struct wmManipulatorMapType_Params *mmap_params);
+const struct ListBase *WM_manipulatormap_group_list(struct wmManipulatorMap *mmap);
+void WM_manipulatormap_tag_refresh(struct wmManipulatorMap *mmap);
+void WM_manipulatormap_draw(struct wmManipulatorMap *mmap, const struct bContext *C, const int drawstep);
+void WM_manipulatormap_add_handlers(struct ARegion *ar, struct wmManipulatorMap *mmap);
+bool WM_manipulatormap_select_all(struct bContext *C, struct wmManipulatorMap *mmap, const int action);
+bool WM_manipulatormap_cursor_set(const struct wmManipulatorMap *mmap, struct wmWindow *win);
+
+/* -------------------------------------------------------------------- */
+/* wmManipulatorMapType */
+
+struct wmManipulatorMapType *WM_manipulatormaptype_find(
+ const struct wmManipulatorMapType_Params *mmap_params);
+struct wmManipulatorMapType *WM_manipulatormaptype_ensure(
+ const struct wmManipulatorMapType_Params *mmap_params);
+
+struct wmManipulatorGroupTypeRef *WM_manipulatormaptype_group_find(
+ struct wmManipulatorMapType *mmap_type,
+ const char *idname);
+struct wmManipulatorGroupTypeRef *WM_manipulatormaptype_group_find_ptr(
+ struct wmManipulatorMapType *mmap_type,
+ const struct wmManipulatorGroupType *wgt);
+struct wmManipulatorGroupTypeRef *WM_manipulatormaptype_group_link(
+ struct wmManipulatorMapType *mmap_type,
+ const char *idname);
+struct wmManipulatorGroupTypeRef *WM_manipulatormaptype_group_link_ptr(
+ struct wmManipulatorMapType *mmap_type,
+ struct wmManipulatorGroupType *wgt);
+
+void WM_manipulatormaptype_group_init_runtime(
+ const struct Main *bmain, struct wmManipulatorMapType *mmap_type,
+ struct wmManipulatorGroupType *wgt);
+void WM_manipulatormaptype_group_unlink(
+ struct bContext *C, struct Main *bmain, struct wmManipulatorMapType *mmap_type,
+ const struct wmManipulatorGroupType *wgt);
+
+void WM_manipulatormaptype_group_free(struct wmManipulatorGroupTypeRef *wgt);
+
+/* -------------------------------------------------------------------- */
+/* Manipulator Add/Remove (High level API) */
+
+void WM_manipulator_group_add_ptr_ex(
+ struct wmManipulatorGroupType *wgt,
+ struct wmManipulatorMapType *mmap_type);
+void WM_manipulator_group_add_ptr(
+ struct wmManipulatorGroupType *wgt);
+void WM_manipulator_group_add(const char *idname);
+
+void WM_manipulator_group_remove_ptr_ex(
+ struct Main *bmain, struct wmManipulatorGroupType *wgt,
+ struct wmManipulatorMapType *mmap_type);
+void WM_manipulator_group_remove_ptr(
+ struct Main *bmain, struct wmManipulatorGroupType *wgt);
+void WM_manipulator_group_remove(struct Main *bmain, const char *idname);
+
+void WM_manipulator_group_remove_ptr_delayed_ex(
+ struct wmManipulatorGroupType *wgt,
+ struct wmManipulatorMapType *mmap_type);
+void WM_manipulator_group_remove_ptr_delayed(
+ struct wmManipulatorGroupType *wgt);
+void WM_manipulator_group_remove_delayed(const char *idname);
+
+#endif /* __WM_MANIPULATOR_API_H__ */
diff --git a/source/blender/windowmanager/manipulators/WM_manipulator_types.h b/source/blender/windowmanager/manipulators/WM_manipulator_types.h
new file mode 100644
index 00000000000..b1b6c5b1c0f
--- /dev/null
+++ b/source/blender/windowmanager/manipulators/WM_manipulator_types.h
@@ -0,0 +1,367 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/manipulators/WM_manipulator_types.h
+ * \ingroup wm
+ *
+ * \name Manipulator Types
+ * \brief Manipulator defines for external use.
+ *
+ * Only included in WM_types.h and lower level files.
+ */
+
+
+#ifndef __WM_MANIPULATOR_TYPES_H__
+#define __WM_MANIPULATOR_TYPES_H__
+
+#include "BLI_compiler_attrs.h"
+
+struct wmManipulatorMapType;
+struct wmManipulatorGroupType;
+struct wmManipulatorGroup;
+struct wmManipulator;
+struct wmManipulatorProperty;
+struct wmKeyConfig;
+
+#include "wm_manipulator_fn.h"
+
+#include "DNA_listBase.h"
+
+/* -------------------------------------------------------------------- */
+/* wmManipulator */
+
+/* manipulators are set per region by registering them on manipulator-maps */
+struct wmManipulator {
+ struct wmManipulator *next, *prev;
+
+ char name[64 + 4]; /* MAX_NAME + 4 for unique '.001', '.002', etc suffix */
+
+ /* While we don't have a real type, use this to put type-like vars. */
+ const struct wmManipulatorType *type;
+
+ /* Overrides 'type->modal' when set.
+ * Note that this is a workaround, remove if we can. */
+ wmManipulatorFnModal custom_modal;
+
+ /* pointer back to group this manipulator is in (just for quick access) */
+ struct wmManipulatorGroup *parent_mgroup;
+
+ void *py_instance;
+
+ /* rna pointer to access properties */
+ struct PointerRNA *ptr;
+
+ int flag; /* flags that influence the behavior or how the manipulators are drawn */
+ short state; /* state flags (active, highlighted, selected) */
+
+ /* Optional ID for highlighting different parts of this manipulator. */
+ int highlight_part;
+
+ /* Transformation of the manipulator 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 manipulator.
+ * - Typically the +Z is the primary axis for manipulators to use.
+ * - 'matrix[3]' must be used for location,
+ * besides this it's up to the manipulators internal code how the
+ * rotation components are used for drawing and interaction.
+ */
+ 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;
+ /* manipulator colors (uses default fallbacks if not defined) */
+ float color[4], color_hi[4];
+
+ /* data used during interaction */
+ void *interaction_data;
+
+ /* name of operator to spawn when activating the manipulator */
+ struct {
+ struct wmOperatorType *type;
+ /* operator properties if manipulator spawns and controls an operator,
+ * or owner pointer if manipulator spawns and controls a property */
+ PointerRNA ptr;
+ } op_data;
+
+ struct IDProperty *properties;
+
+ /* over alloc target_properties after 'wmManipulatorType.struct_size' */
+};
+
+typedef void (*wmManipulatorGroupFnInit)(
+ const struct bContext *, struct wmManipulatorGroup *);
+
+/* Similar to PropertyElemRNA, but has an identifier. */
+typedef struct wmManipulatorProperty {
+ const struct wmManipulatorPropertyType *type;
+
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+
+
+ /* Optional functions for converting to/from RNA */
+ struct {
+ wmManipulatorPropertyFnGet value_get_fn;
+ wmManipulatorPropertyFnSet value_set_fn;
+ wmManipulatorPropertyFnRangeGet range_get_fn;
+ wmManipulatorPropertyFnFree free_fn;
+ const struct bContext *context;
+ void *user_data;
+ } custom_func;
+} wmManipulatorProperty;
+
+typedef struct wmManipulatorPropertyType {
+ struct wmManipulatorPropertyType *next, *prev;
+ /* PropertyType, typically 'PROP_FLOAT' */
+ int data_type;
+ int array_length;
+
+ /* index within 'wmManipulatorType' */
+ int index_in_type;
+
+ /* over alloc */
+ char idname[0];
+} wmManipulatorPropertyType;
+
+
+
+/**
+ * Simple utility wrapper for storing a single manipulator as wmManipulatorGroup.customdata (which gets freed).
+ */
+typedef struct wmManipulatorWrapper {
+ struct wmManipulator *manipulator;
+} wmManipulatorWrapper;
+
+struct wmManipulatorMapType_Params {
+ short spaceid;
+ short regionid;
+};
+
+
+/* wmManipulator.flag
+ * Flags for individual manipulators. */
+enum {
+ WM_MANIPULATOR_DRAW_HOVER = (1 << 0), /* draw *only* while hovering */
+ WM_MANIPULATOR_DRAW_ACTIVE = (1 << 1), /* draw while dragging */
+ WM_MANIPULATOR_DRAW_VALUE = (1 << 2), /* draw an indicator for the current value while dragging */
+ WM_MANIPULATOR_HIDDEN = (1 << 3),
+};
+
+/* wmManipulator.state */
+enum {
+ WM_MANIPULATOR_STATE_HIGHLIGHT = (1 << 0), /* while hovered */
+ WM_MANIPULATOR_STATE_ACTIVE = (1 << 1), /* while dragging */
+ WM_MANIPULATOR_STATE_SELECT = (1 << 2),
+};
+
+/**
+ * \brief Manipulator tweak flag.
+ * Bitflag passed to manipulator while tweaking.
+ *
+ * \note Manipulators are responsible for handling this #wmManipulator.modal callback!.
+ */
+enum {
+ /* Drag with extra precision (Shift). */
+ WM_MANIPULATOR_TWEAK_PRECISE = (1 << 0),
+ /* Drag with snap enabled (Ctrl). */
+ WM_MANIPULATOR_TWEAK_SNAP = (1 << 1),
+};
+
+typedef struct wmManipulatorType {
+
+ const char *idname; /* MAX_NAME */
+
+ /* Set to 'sizeof(wmManipulator)' 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). */
+ wmManipulatorFnSetup setup;
+
+ /* draw manipulator */
+ wmManipulatorFnDraw draw;
+
+ /* determines 3d intersection by rendering the manipulator in a selection routine. */
+ wmManipulatorFnDrawSelect draw_select;
+
+ /* determine if the mouse intersects with the manipulator. The calculation should be done in the callback itself */
+ wmManipulatorFnTestSelect test_select;
+
+ /* handler used by the manipulator. Usually handles interaction tied to a manipulator type */
+ wmManipulatorFnModal modal;
+
+ /* manipulator-specific handler to update manipulator attributes based on the property value */
+ wmManipulatorFnPropertyUpdate property_update;
+
+ /* Returns the final transformation which may be different from the 'matrix',
+ * depending on the manipulator.
+ * Notes:
+ * - Scale isn't applied (wmManipulator.scale/user_scale).
+ * - Offset isn't applied (wmManipulator.matrix_offset).
+ */
+ wmManipulatorFnMatrixWorldGet matrix_world_get;
+
+ /* activate a manipulator state when the user clicks on it */
+ wmManipulatorFnInvoke invoke;
+
+ /* called when manipulator tweaking is done - used to free data and reset property when cancelling */
+ wmManipulatorFnExit exit;
+
+ wmManipulatorFnCursorGet cursor_get;
+
+ /* called when manipulator selection state changes */
+ wmManipulatorFnSelect select;
+
+ /* RNA for properties */
+ struct StructRNA *srna;
+
+ /* RNA integration */
+ ExtensionRNA ext;
+
+ ListBase target_property_defs;
+ int target_property_defs_len;
+
+} wmManipulatorType;
+
+
+/* -------------------------------------------------------------------- */
+/* wmManipulatorGroup */
+
+/* factory class for a manipulator-group type, gets called every time a new area is spawned */
+typedef struct wmManipulatorGroupTypeRef {
+ struct wmManipulatorGroupTypeRef *next, *prev;
+ struct wmManipulatorGroupType *type;
+} wmManipulatorGroupTypeRef;
+
+/* factory class for a manipulator-group type, gets called every time a new area is spawned */
+typedef struct wmManipulatorGroupType {
+ const char *idname; /* MAX_NAME */
+ const char *name; /* manipulator-group name - displayed in UI (keymap editor) */
+
+ /* poll if manipulator-map should be visible */
+ wmManipulatorGroupFnPoll poll;
+ /* initially create manipulators and set permanent data - stuff you only need to do once */
+ wmManipulatorGroupFnInit setup;
+ /* refresh data, only called if recreate flag is set (WM_manipulatormap_tag_refresh) */
+ wmManipulatorGroupFnRefresh refresh;
+ /* refresh data for drawing, called before each redraw */
+ wmManipulatorGroupFnDrawPrepare draw_prepare;
+
+ /* Keymap init callback for this manipulator-group (optional),
+ * will fall back to default tweak keymap when left NULL. */
+ wmManipulatorGroupFnSetupKeymap setup_keymap;
+
+ /* keymap created with callback from above */
+ struct wmKeyMap *keymap;
+ /* Only for convenient removal. */
+ struct wmKeyConfig *keyconf;
+
+ /* Disable for now, maybe some day we want properties. */
+#if 0
+ /* rna for properties */
+ struct StructRNA *srna;
+#endif
+
+ /* RNA integration */
+ ExtensionRNA ext;
+
+ int flag;
+
+ /* eManipulatorMapTypeUpdateFlags (so we know which group type to update) */
+ uchar type_update_flag;
+
+ /* same as manipulator-maps, so registering/unregistering goes to the correct region */
+ struct wmManipulatorMapType_Params mmap_params;
+
+} wmManipulatorGroupType;
+
+typedef struct wmManipulatorGroup {
+ struct wmManipulatorGroup *next, *prev;
+
+ struct wmManipulatorGroupType *type;
+ ListBase manipulators;
+
+ struct wmManipulatorMap *parent_mmap;
+
+ 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 */
+ int flag; /* private */
+ int pad;
+} wmManipulatorGroup;
+
+/**
+ * Manipulator-map type update flag: `wmManipulatorMapType.type_update_flag`
+ */
+enum eManipulatorMapTypeUpdateFlags {
+ /* A new type has been added, needs to be initialized for all views. */
+ WM_MANIPULATORMAPTYPE_UPDATE_INIT = (1 << 0),
+ WM_MANIPULATORMAPTYPE_UPDATE_REMOVE = (1 << 1),
+};
+
+/**
+ * wmManipulatorGroupType.flag
+ * Flags that influence the behavior of all manipulators in the group.
+ */
+enum {
+ /* Mark manipulator-group as being 3D */
+ WM_MANIPULATORGROUPTYPE_3D = (1 << 0),
+ /* Scale manipulators as 3D object that respects zoom (otherwise zoom independent draw size).
+ * note: currently only for 3D views, 2D support needs adding. */
+ WM_MANIPULATORGROUPTYPE_SCALE = (1 << 1),
+ /* Manipulators can be depth culled with scene objects (covered by other geometry - TODO) */
+ WM_MANIPULATORGROUPTYPE_DEPTH_3D = (1 << 2),
+ /* Manipulators can be selected */
+ WM_MANIPULATORGROUPTYPE_SELECT = (1 << 3),
+ /* The manipulator group is to be kept (not removed on loading a new file for eg). */
+ WM_MANIPULATORGROUPTYPE_PERSISTENT = (1 << 4),
+};
+
+
+/* -------------------------------------------------------------------- */
+/* wmManipulatorMap */
+
+/**
+ * Pass a value of this enum to #WM_manipulatormap_draw to tell it what to draw.
+ */
+enum {
+ /* Draw 2D manipulator-groups (ManipulatorGroupType.is_3d == false) */
+ WM_MANIPULATORMAP_DRAWSTEP_2D = 0,
+ /* Draw 3D manipulator-groups (ManipulatorGroupType.is_3d == true) */
+ WM_MANIPULATORMAP_DRAWSTEP_3D,
+ /* Draw only depth culled manipulators (WM_MANIPULATOR_SCENE_DEPTH flag).
+ * Note that these are expected to be 3D manipulators too. */
+ WM_MANIPULATORMAP_DRAWSTEP_IN_SCENE,
+};
+
+#endif /* __WM_MANIPULATOR_TYPES_H__ */
diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator.c
new file mode 100644
index 00000000000..d8d530a4db9
--- /dev/null
+++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator.c
@@ -0,0 +1,675 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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/manipulators/intern/wm_manipulator.c
+ * \ingroup wm
+ */
+
+#include "BKE_context.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "GPU_batch.h"
+#include "GPU_glew.h"
+#include "GPU_immediate.h"
+
+#include "MEM_guardedalloc.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"
+
+#ifdef WITH_PYTHON
+#include "BPY_extern.h"
+#endif
+
+/* only for own init/exit calls (wm_manipulatortype_init/wm_manipulatortype_free) */
+#include "wm.h"
+
+/* own includes */
+#include "wm_manipulator_wmapi.h"
+#include "wm_manipulator_intern.h"
+
+static void wm_manipulator_register(
+ wmManipulatorGroup *mgroup, wmManipulator *mpr, const char *name);
+
+/**
+ * \note Follow #wm_operator_create convention.
+ */
+static wmManipulator *wm_manipulator_create(
+ const wmManipulatorType *wt,
+ PointerRNA *properties)
+{
+ BLI_assert(wt != NULL);
+ BLI_assert(wt->struct_size >= sizeof(wmManipulator));
+
+ wmManipulator *mpr = MEM_callocN(
+ wt->struct_size + (sizeof(wmManipulatorProperty) * wt->target_property_defs_len), __func__);
+ mpr->type = wt;
+
+ /* initialize properties, either copy or create */
+ mpr->ptr = MEM_callocN(sizeof(PointerRNA), "wmManipulatorPtrRNA");
+ if (properties && properties->data) {
+ mpr->properties = IDP_CopyProperty(properties->data);
+ }
+ else {
+ IDPropertyTemplate val = {0};
+ mpr->properties = IDP_New(IDP_GROUP, &val, "wmManipulatorProperties");
+ }
+ RNA_pointer_create(G.main->wm.first, wt->srna, mpr->properties, mpr->ptr);
+
+ WM_manipulator_properties_sanitize(mpr->ptr, 0);
+
+ unit_m4(mpr->matrix_basis);
+ unit_m4(mpr->matrix_offset);
+
+ return mpr;
+}
+
+wmManipulator *WM_manipulator_new_ptr(
+ const wmManipulatorType *wt, wmManipulatorGroup *mgroup,
+ const char *name, PointerRNA *properties)
+{
+ wmManipulator *mpr = wm_manipulator_create(wt, properties);
+
+ wm_manipulator_register(mgroup, mpr, name);
+
+ if (mpr->type->setup != NULL) {
+ mpr->type->setup(mpr);
+ }
+
+ return mpr;
+}
+
+/**
+ * \param wt: Must be valid,
+ * if you need to check it exists use #WM_manipulator_new_ptr
+ * because callers of this function don't NULL check the return value.
+ */
+wmManipulator *WM_manipulator_new(
+ const char *idname, wmManipulatorGroup *mgroup,
+ const char *name, PointerRNA *properties)
+{
+ const wmManipulatorType *wt = WM_manipulatortype_find(idname, false);
+ return WM_manipulator_new_ptr(wt, mgroup, name, properties);
+}
+
+/**
+ * Assign an idname that is unique in \a mgroup to \a manipulator.
+ *
+ * \param rawname: Name used as basis to define final unique idname.
+ */
+static void manipulator_unique_idname_set(wmManipulatorGroup *mgroup, wmManipulator *mpr, const char *rawname)
+{
+ BLI_snprintf(mpr->name, sizeof(mpr->name), "%s_%s", mgroup->type->idname, rawname);
+
+ /* ensure name is unique, append '.001', '.002', etc if not */
+ BLI_uniquename(&mgroup->manipulators, mpr, "Manipulator", '.',
+ offsetof(wmManipulator, name), sizeof(mpr->name));
+}
+
+void WM_manipulator_name_set(wmManipulatorGroup *mgroup, wmManipulator *mpr, const char *name)
+{
+ BLI_strncpy(mpr->name, name, sizeof(mpr->name));
+
+ /* ensure name is unique, append '.001', '.002', etc if not */
+ BLI_uniquename(&mgroup->manipulators, mpr, "Manipulator", '.',
+ offsetof(wmManipulator, name), sizeof(mpr->name));
+}
+
+/**
+ * Initialize default values and allocate needed memory for members.
+ */
+static void manipulator_init(wmManipulator *mpr)
+{
+ const float color_default[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+
+ mpr->scale_basis = 1.0f;
+ mpr->line_width = 1.0f;
+
+ /* defaults */
+ copy_v4_v4(mpr->color, color_default);
+ copy_v4_v4(mpr->color_hi, color_default);
+}
+
+/**
+ * Register \a manipulator.
+ *
+ * \param name: name used to create a unique idname for \a manipulator in \a mgroup
+ *
+ * \note Not to be confused with type registration from RNA.
+ */
+static void wm_manipulator_register(wmManipulatorGroup *mgroup, wmManipulator *mpr, const char *name)
+{
+ manipulator_init(mpr);
+ manipulator_unique_idname_set(mgroup, mpr, name);
+ wm_manipulatorgroup_manipulator_register(mgroup, mpr);
+}
+
+/**
+ * Free \a manipulator and unlink from \a manipulatorlist.
+ * \a manipulatorlist is allowed to be NULL.
+ */
+void WM_manipulator_free(ListBase *manipulatorlist, wmManipulatorMap *mmap, wmManipulator *mpr, bContext *C)
+{
+#ifdef WITH_PYTHON
+ if (mpr->py_instance) {
+ /* do this first in case there are any __del__ functions or
+ * similar that use properties */
+ BPY_DECREF_RNA_INVALIDATE(mpr->py_instance);
+ }
+#endif
+
+ if (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) {
+ wm_manipulatormap_highlight_set(mmap, C, NULL, 0);
+ }
+ if (mpr->state & WM_MANIPULATOR_STATE_ACTIVE) {
+ wm_manipulatormap_active_set(mmap, C, NULL, NULL);
+ }
+ if (mpr->state & WM_MANIPULATOR_STATE_SELECT) {
+ wm_manipulator_deselect(mmap, mpr);
+ }
+
+ if (mpr->op_data.ptr.data) {
+ WM_operator_properties_free(&mpr->op_data.ptr);
+ }
+
+ if (mpr->ptr != NULL) {
+ WM_manipulator_properties_free(mpr->ptr);
+ MEM_freeN(mpr->ptr);
+ }
+
+ if (mpr->type->target_property_defs_len != 0) {
+ wmManipulatorProperty *mpr_prop_array = WM_manipulator_target_property_array(mpr);
+ for (int i = 0; i < mpr->type->target_property_defs_len; i++) {
+ wmManipulatorProperty *mpr_prop = &mpr_prop_array[i];
+ if (mpr_prop->custom_func.free_fn) {
+ mpr_prop->custom_func.free_fn(mpr, mpr_prop);
+ }
+ }
+ }
+
+ if (manipulatorlist) {
+ BLI_remlink(manipulatorlist, mpr);
+ }
+
+ BLI_assert(mmap->mmap_context.highlight != mpr);
+ BLI_assert(mmap->mmap_context.active != mpr);
+
+ MEM_freeN(mpr);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Manipulator Creation API
+ *
+ * API for defining data on manipulator creation.
+ *
+ * \{ */
+
+
+PointerRNA *WM_manipulator_set_operator(
+ wmManipulator *mpr, wmOperatorType *ot, IDProperty *properties)
+{
+ mpr->op_data.type = ot;
+
+ if (mpr->op_data.ptr.data) {
+ WM_operator_properties_free(&mpr->op_data.ptr);
+ }
+ WM_operator_properties_create_ptr(&mpr->op_data.ptr, ot);
+
+ if (properties) {
+ mpr->op_data.ptr.data = properties;
+ }
+
+ return &mpr->op_data.ptr;
+}
+
+static void wm_manipulator_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_manipulator_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]);
+}
+
+/**
+ * wmManipulator.matrix utils.
+ */
+void WM_manipulator_set_matrix_rotation_from_z_axis(
+ wmManipulator *mpr, const float z_axis[3])
+{
+ wm_manipulator_set_matrix_rotation_from_z_axis__internal(mpr->matrix_basis, z_axis);
+}
+void WM_manipulator_set_matrix_rotation_from_yz_axis(
+ wmManipulator *mpr, const float y_axis[3], const float z_axis[3])
+{
+ wm_manipulator_set_matrix_rotation_from_yz_axis__internal(mpr->matrix_basis, y_axis, z_axis);
+}
+void WM_manipulator_set_matrix_location(wmManipulator *mpr, const float origin[3])
+{
+ copy_v3_v3(mpr->matrix_basis[3], origin);
+}
+
+/**
+ * wmManipulator.matrix_offset utils.
+ */
+void WM_manipulator_set_matrix_offset_rotation_from_z_axis(
+ wmManipulator *mpr, const float z_axis[3])
+{
+ wm_manipulator_set_matrix_rotation_from_z_axis__internal(mpr->matrix_offset, z_axis);
+}
+void WM_manipulator_set_matrix_offset_rotation_from_yz_axis(
+ wmManipulator *mpr, const float y_axis[3], const float z_axis[3])
+{
+ wm_manipulator_set_matrix_rotation_from_yz_axis__internal(mpr->matrix_offset, y_axis, z_axis);
+}
+void WM_manipulator_set_matrix_offset_location(wmManipulator *mpr, const float offset[3])
+{
+ copy_v3_v3(mpr->matrix_offset[3], offset);
+}
+
+void WM_manipulator_set_flag(wmManipulator *mpr, const int flag, const bool enable)
+{
+ if (enable) {
+ mpr->flag |= flag;
+ }
+ else {
+ mpr->flag &= ~flag;
+ }
+}
+
+void WM_manipulator_set_scale(wmManipulator *mpr, const float scale)
+{
+ mpr->scale_basis = scale;
+}
+
+void WM_manipulator_set_line_width(wmManipulator *mpr, const float line_width)
+{
+ mpr->line_width = line_width;
+}
+
+/**
+ * Set manipulator rgba colors.
+ *
+ * \param col Normal state color.
+ * \param col_hi Highlighted state color.
+ */
+void WM_manipulator_get_color(const wmManipulator *mpr, float col[4])
+{
+ copy_v4_v4(col, mpr->color);
+}
+void WM_manipulator_set_color(wmManipulator *mpr, const float col[4])
+{
+ copy_v4_v4(mpr->color, col);
+}
+
+void WM_manipulator_get_color_highlight(const wmManipulator *mpr, float color_hi[4])
+{
+ copy_v4_v4(color_hi, mpr->color_hi);
+}
+void WM_manipulator_set_color_highlight(wmManipulator *mpr, const float color_hi[4])
+{
+ copy_v4_v4(mpr->color_hi, color_hi);
+}
+
+
+/** \} */ // Manipulator Creation API
+
+
+/* -------------------------------------------------------------------- */
+/** \name Manipulator Callback Assignment
+ *
+ * \{ */
+
+void WM_manipulator_set_fn_custom_modal(struct wmManipulator *mpr, wmManipulatorFnModal fn)
+{
+ mpr->custom_modal = fn;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/**
+ * Remove \a manipulator from selection.
+ * Reallocates memory for selected manipulators so better not call for selecting multiple ones.
+ *
+ * \return if the selection has changed.
+ */
+bool wm_manipulator_deselect(wmManipulatorMap *mmap, wmManipulator *mpr)
+{
+ if (!mmap->mmap_context.selected)
+ return false;
+
+ wmManipulator ***sel = &mmap->mmap_context.selected;
+ int *selected_len = &mmap->mmap_context.selected_len;
+ bool changed = false;
+
+ /* caller should check! */
+ BLI_assert(mpr->state & WM_MANIPULATOR_STATE_SELECT);
+
+ /* remove manipulator from selected_manipulators array */
+ for (int i = 0; i < (*selected_len); i++) {
+ if ((*sel)[i] == mpr) {
+ for (int j = i; j < ((*selected_len) - 1); j++) {
+ (*sel)[j] = (*sel)[j + 1];
+ }
+ changed = true;
+ break;
+ }
+ }
+
+ /* update array data */
+ if ((*selected_len) <= 1) {
+ wm_manipulatormap_selected_clear(mmap);
+ }
+ else {
+ *sel = MEM_reallocN(*sel, sizeof(**sel) * (*selected_len));
+ (*selected_len)--;
+ }
+
+ mpr->state &= ~WM_MANIPULATOR_STATE_SELECT;
+ return changed;
+}
+
+/**
+ * Add \a manipulator to selection.
+ * Reallocates memory for selected manipulators so better not call for selecting multiple ones.
+ *
+ * \return if the selection has changed.
+ */
+bool wm_manipulator_select(bContext *C, wmManipulatorMap *mmap, wmManipulator *mpr)
+{
+ wmManipulator ***sel = &mmap->mmap_context.selected;
+ int *selected_len = &mmap->mmap_context.selected_len;
+
+ if (!mpr || (mpr->state & WM_MANIPULATOR_STATE_SELECT))
+ return false;
+
+ (*selected_len)++;
+
+ *sel = MEM_reallocN(*sel, sizeof(wmManipulator *) * (*selected_len));
+ (*sel)[(*selected_len) - 1] = mpr;
+
+ mpr->state |= WM_MANIPULATOR_STATE_SELECT;
+ if (mpr->type->select) {
+ mpr->type->select(C, mpr, SEL_SELECT);
+ }
+ wm_manipulatormap_highlight_set(mmap, C, mpr, mpr->highlight_part);
+
+ return true;
+}
+
+void wm_manipulator_calculate_scale(wmManipulator *mpr, const bContext *C)
+{
+ const RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ float scale = U.ui_scale;
+
+ if ((mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_SCALE) == 0) {
+ scale *= U.manipulator_size;
+ if (rv3d) {
+ /* 'ED_view3d_pixel_size' includes 'U.pixelsize', remove it. */
+ if (mpr->type->matrix_world_get) {
+ float matrix_world[4][4];
+
+ mpr->type->matrix_world_get(mpr, matrix_world);
+ scale *= ED_view3d_pixel_size(rv3d, matrix_world[3]) / U.pixelsize;
+ }
+ else {
+ scale *= ED_view3d_pixel_size(rv3d, mpr->matrix_basis[3]) / U.pixelsize;
+ }
+ }
+ else {
+ scale *= 0.02f;
+ }
+ }
+
+ mpr->scale_final = mpr->scale_basis * scale;
+}
+
+static void manipulator_update_prop_data(wmManipulator *mpr)
+{
+ /* manipulator property might have been changed, so update manipulator */
+ if (mpr->type->property_update) {
+ wmManipulatorProperty *mpr_prop_array = WM_manipulator_target_property_array(mpr);
+ for (int i = 0; i < mpr->type->target_property_defs_len; i++) {
+ wmManipulatorProperty *mpr_prop = &mpr_prop_array[i];
+ if (WM_manipulator_target_property_is_valid(mpr_prop)) {
+ mpr->type->property_update(mpr, mpr_prop);
+ }
+ }
+ }
+}
+
+void wm_manipulator_update(wmManipulator *mpr, const bContext *C, const bool refresh_map)
+{
+ if (refresh_map) {
+ manipulator_update_prop_data(mpr);
+ }
+ wm_manipulator_calculate_scale(mpr, C);
+}
+
+int wm_manipulator_is_visible(wmManipulator *mpr)
+{
+ if (mpr->flag & WM_MANIPULATOR_HIDDEN) {
+ return 0;
+ }
+ if ((mpr->state & WM_MANIPULATOR_STATE_ACTIVE) &&
+ !(mpr->flag & (WM_MANIPULATOR_DRAW_ACTIVE | WM_MANIPULATOR_DRAW_VALUE)))
+ {
+ /* don't draw while active (while dragging) */
+ return 0;
+ }
+ if ((mpr->flag & WM_MANIPULATOR_DRAW_HOVER) &&
+ !(mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) &&
+ !(mpr->state & WM_MANIPULATOR_STATE_SELECT)) /* still draw selected manipulators */
+ {
+ /* update but don't draw */
+ return WM_MANIPULATOR_IS_VISIBLE_UPDATE;
+ }
+
+ return WM_MANIPULATOR_IS_VISIBLE_UPDATE | WM_MANIPULATOR_IS_VISIBLE_DRAW;
+}
+
+
+/** \name Manipulator Propery Access
+ *
+ * Matches `WM_operator_properties` conventions.
+ *
+ * \{ */
+
+
+void WM_manipulator_properties_create_ptr(PointerRNA *ptr, wmManipulatorType *wt)
+{
+ RNA_pointer_create(NULL, wt->srna, NULL, ptr);
+}
+
+void WM_manipulator_properties_create(PointerRNA *ptr, const char *wtstring)
+{
+ const wmManipulatorType *wt = WM_manipulatortype_find(wtstring, false);
+
+ if (wt)
+ WM_manipulator_properties_create_ptr(ptr, (wmManipulatorType *)wt);
+ else
+ RNA_pointer_create(NULL, &RNA_ManipulatorProperties, NULL, ptr);
+}
+
+/* similar to the function above except its uses ID properties
+ * used for keymaps and macros */
+void WM_manipulator_properties_alloc(PointerRNA **ptr, IDProperty **properties, const char *wtstring)
+{
+ if (*properties == NULL) {
+ IDPropertyTemplate val = {0};
+ *properties = IDP_New(IDP_GROUP, &val, "wmOpItemProp");
+ }
+
+ if (*ptr == NULL) {
+ *ptr = MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr");
+ WM_manipulator_properties_create(*ptr, wtstring);
+ }
+
+ (*ptr)->data = *properties;
+
+}
+
+void WM_manipulator_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 manipulator properties */
+ if (RNA_struct_is_a(ptype, &RNA_ManipulatorProperties)) {
+ PointerRNA opptr = RNA_property_pointer_get(ptr, prop);
+ WM_manipulator_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, theres nothing specific to manipulators here.
+ * this could be made a general function.
+ */
+bool WM_manipulator_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_manipulator_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_manipulator_properties_reset(wmManipulator *mpr)
+{
+ if (mpr->ptr->data) {
+ PropertyRNA *iterprop;
+ iterprop = RNA_struct_iterator_property(mpr->type->srna);
+
+ RNA_PROP_BEGIN (mpr->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(mpr->ptr, identifier);
+ }
+ }
+ RNA_PROP_END;
+ }
+}
+
+void WM_manipulator_properties_clear(PointerRNA *ptr)
+{
+ IDProperty *properties = ptr->data;
+
+ if (properties) {
+ IDP_ClearProperty(properties);
+ }
+}
+
+void WM_manipulator_properties_free(PointerRNA *ptr)
+{
+ IDProperty *properties = ptr->data;
+
+ if (properties) {
+ IDP_FreeProperty(properties);
+ MEM_freeN(properties);
+ ptr->data = NULL; /* just in case */
+ }
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c
new file mode 100644
index 00000000000..126c866d600
--- /dev/null
+++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c
@@ -0,0 +1,723 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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/manipulators/intern/wm_manipulator_group.c
+ * \ingroup wm
+ *
+ * \name Manipulator-Group
+ *
+ * Manipulator-groups store and manage groups of manipulators. They can be
+ * attached to modal handlers and have own keymaps.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "ED_screen.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "wm_event_system.h"
+
+/* own includes */
+#include "wm_manipulator_wmapi.h"
+#include "wm_manipulator_intern.h"
+
+#ifdef WITH_PYTHON
+# include "BPY_extern.h"
+#endif
+
+/* -------------------------------------------------------------------- */
+/** \name wmManipulatorGroup
+ *
+ * \{ */
+
+/* wmManipulatorGroup.flag */
+enum {
+ WM_MANIPULATORGROUP_INITIALIZED = (1 << 2), /* mgroup has been initialized */
+};
+
+/**
+ * Create a new manipulator-group from \a wgt.
+ */
+wmManipulatorGroup *wm_manipulatorgroup_new_from_type(
+ wmManipulatorMap *mmap, wmManipulatorGroupType *wgt)
+{
+ wmManipulatorGroup *mgroup = MEM_callocN(sizeof(*mgroup), "manipulator-group");
+ mgroup->type = wgt;
+
+ /* keep back-link */
+ mgroup->parent_mmap = mmap;
+
+ BLI_addtail(&mmap->groups, mgroup);
+
+ return mgroup;
+}
+
+void wm_manipulatorgroup_free(bContext *C, wmManipulatorGroup *mgroup)
+{
+ wmManipulatorMap *mmap = mgroup->parent_mmap;
+ for (wmManipulator *mpr = mgroup->manipulators.first, *mpr_next; mpr; mpr = mpr_next) {
+ mpr_next = mpr->next;
+ WM_manipulator_free(&mgroup->manipulators, mmap, mpr, C);
+ }
+ BLI_assert(BLI_listbase_is_empty(&mgroup->manipulators));
+
+#ifdef WITH_PYTHON
+ if (mgroup->py_instance) {
+ /* do this first in case there are any __del__ functions or
+ * similar that use properties */
+ BPY_DECREF_RNA_INVALIDATE(mgroup->py_instance);
+ }
+#endif
+
+ if (mgroup->reports && (mgroup->reports->flag & RPT_FREE)) {
+ BKE_reports_clear(mgroup->reports);
+ MEM_freeN(mgroup->reports);
+ }
+
+ if (mgroup->customdata_free) {
+ mgroup->customdata_free(mgroup->customdata);
+ }
+ else {
+ MEM_SAFE_FREE(mgroup->customdata);
+ }
+
+ BLI_remlink(&mmap->groups, mgroup);
+
+ MEM_freeN(mgroup);
+}
+
+/**
+ * Add \a manipulator to \a mgroup and make sure its name is unique within the group.
+ */
+void wm_manipulatorgroup_manipulator_register(wmManipulatorGroup *mgroup, wmManipulator *mpr)
+{
+ BLI_assert(!BLI_findstring(&mgroup->manipulators, mpr->name, offsetof(wmManipulator, name)));
+ BLI_addtail(&mgroup->manipulators, mpr);
+ mpr->parent_mgroup = mgroup;
+}
+
+wmManipulator *wm_manipulatorgroup_find_intersected_mainpulator(
+ const wmManipulatorGroup *mgroup, bContext *C, const wmEvent *event,
+ int *r_part)
+{
+ for (wmManipulator *mpr = mgroup->manipulators.first; mpr; mpr = mpr->next) {
+ if (mpr->type->test_select && (mpr->flag & WM_MANIPULATOR_HIDDEN) == 0) {
+ if ((*r_part = mpr->type->test_select(C, mpr, event))) {
+ return mpr;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Adds all manipulators of \a mgroup that can be selected to the head of \a listbase. Added items need freeing!
+ */
+void wm_manipulatorgroup_intersectable_manipulators_to_list(const wmManipulatorGroup *mgroup, ListBase *listbase)
+{
+ for (wmManipulator *mpr = mgroup->manipulators.first; mpr; mpr = mpr->next) {
+ if ((mpr->flag & WM_MANIPULATOR_HIDDEN) == 0) {
+ if (((mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) && mpr->type->draw_select) ||
+ ((mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) == 0 && mpr->type->test_select))
+ {
+ BLI_addhead(listbase, BLI_genericNodeN(mpr));
+ }
+ }
+ }
+}
+
+void wm_manipulatorgroup_ensure_initialized(wmManipulatorGroup *mgroup, const bContext *C)
+{
+ /* prepare for first draw */
+ if (UNLIKELY((mgroup->flag & WM_MANIPULATORGROUP_INITIALIZED) == 0)) {
+ mgroup->type->setup(C, mgroup);
+
+ /* Not ideal, initialize keymap here, needed for RNA runtime generated manipulators. */
+ wmManipulatorGroupType *wgt = mgroup->type;
+ if (wgt->keymap == NULL) {
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wm_manipulatorgrouptype_setup_keymap(wgt, wm->defaultconf);
+ BLI_assert(wgt->keymap != NULL);
+ }
+
+ mgroup->flag |= WM_MANIPULATORGROUP_INITIALIZED;
+ }
+}
+
+bool wm_manipulatorgroup_is_visible(const wmManipulatorGroup *mgroup, const bContext *C)
+{
+ /* Check for poll function, if manipulator-group belongs to an operator, also check if the operator is running. */
+ return (!mgroup->type->poll || mgroup->type->poll(C, mgroup->type));
+}
+
+bool wm_manipulatorgroup_is_visible_in_drawstep(const wmManipulatorGroup *mgroup, const int drawstep)
+{
+ switch (drawstep) {
+ case WM_MANIPULATORMAP_DRAWSTEP_2D:
+ return (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) == 0;
+ case WM_MANIPULATORMAP_DRAWSTEP_3D:
+ return (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D);
+ case WM_MANIPULATORMAP_DRAWSTEP_IN_SCENE:
+ return (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_DEPTH_3D);
+ default:
+ BLI_assert(0);
+ return false;
+ }
+}
+
+/** \name Manipulator operators
+ *
+ * Basic operators for manipulator interaction with user configurable keymaps.
+ *
+ * \{ */
+
+static int manipulator_select_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ ARegion *ar = CTX_wm_region(C);
+ wmManipulatorMap *mmap = ar->manipulator_map;
+ wmManipulator ***sel = &mmap->mmap_context.selected;
+ wmManipulator *highlight = mmap->mmap_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_manipulatormap_deselect_all(mmap, sel);
+ BLI_assert(*sel == NULL && mmap->mmap_context.selected_len == 0);
+ }
+
+ if (highlight) {
+ const bool is_selected = (highlight->state & WM_MANIPULATOR_STATE_SELECT);
+ bool redraw = false;
+
+ if (toggle) {
+ /* toggle: deselect if already selected, else select */
+ deselect = is_selected;
+ }
+
+ if (deselect) {
+ if (is_selected && wm_manipulator_deselect(mmap, highlight)) {
+ redraw = true;
+ }
+ }
+ else if (wm_manipulator_select(C, mmap, highlight)) {
+ redraw = true;
+ }
+
+ if (redraw) {
+ ED_region_tag_redraw(ar);
+ }
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ BLI_assert(0);
+ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
+ }
+
+ return OPERATOR_PASS_THROUGH;
+}
+
+void MANIPULATORGROUP_OT_manipulator_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Manipulator Select";
+ ot->description = "Select the currently highlighted manipulator";
+ ot->idname = "MANIPULATORGROUP_OT_manipulator_select";
+
+ /* api callbacks */
+ ot->invoke = manipulator_select_invoke;
+
+ ot->flag = OPTYPE_UNDO;
+
+ WM_operator_properties_mouse_select(ot);
+}
+
+typedef struct ManipulatorTweakData {
+ wmManipulatorMap *mmap;
+ wmManipulator *active;
+
+ int init_event; /* initial event type */
+ int flag; /* tweak flags */
+} ManipulatorTweakData;
+
+static void manipulator_tweak_finish(bContext *C, wmOperator *op, const bool cancel)
+{
+ ManipulatorTweakData *mtweak = op->customdata;
+ if (mtweak->active->type->exit) {
+ mtweak->active->type->exit(C, mtweak->active, cancel);
+ }
+ wm_manipulatormap_active_set(mtweak->mmap, C, NULL, NULL);
+ MEM_freeN(mtweak);
+}
+
+static int manipulator_tweak_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ManipulatorTweakData *mtweak = op->customdata;
+ wmManipulator *mpr = mtweak->active;
+
+ if (mpr == NULL) {
+ BLI_assert(0);
+ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
+ }
+
+ if (event->type == mtweak->init_event && event->val == KM_RELEASE) {
+ manipulator_tweak_finish(C, op, false);
+ return OPERATOR_FINISHED;
+ }
+
+
+ if (event->type == EVT_MODAL_MAP) {
+ switch (event->val) {
+ case TWEAK_MODAL_CANCEL:
+ manipulator_tweak_finish(C, op, true);
+ return OPERATOR_CANCELLED;
+ case TWEAK_MODAL_CONFIRM:
+ manipulator_tweak_finish(C, op, false);
+ return OPERATOR_FINISHED;
+
+ case TWEAK_MODAL_PRECISION_ON:
+ mtweak->flag |= WM_MANIPULATOR_TWEAK_PRECISE;
+ break;
+ case TWEAK_MODAL_PRECISION_OFF:
+ mtweak->flag &= ~WM_MANIPULATOR_TWEAK_PRECISE;
+ break;
+
+ case TWEAK_MODAL_SNAP_ON:
+ mtweak->flag |= WM_MANIPULATOR_TWEAK_SNAP;
+ break;
+ case TWEAK_MODAL_SNAP_OFF:
+ mtweak->flag &= ~WM_MANIPULATOR_TWEAK_SNAP;
+ break;
+ }
+ }
+
+ /* handle manipulator */
+ if (mpr->custom_modal) {
+ mpr->custom_modal(C, mpr, event, mtweak->flag);
+ }
+ else if (mpr->type->modal) {
+ mpr->type->modal(C, mpr, event, mtweak->flag);
+ }
+
+ /* Ugly hack to send manipulator events */
+ ((wmEvent *)event)->type = EVT_MANIPULATOR_UPDATE;
+
+ /* always return PASS_THROUGH so modal handlers
+ * with manipulators attached can update */
+ return OPERATOR_PASS_THROUGH;
+}
+
+static int manipulator_tweak_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ wmManipulatorMap *mmap = ar->manipulator_map;
+ wmManipulator *mpr = mmap->mmap_context.highlight;
+
+ if (!mpr) {
+ /* wm_handlers_do_intern shouldn't let this happen */
+ BLI_assert(0);
+ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
+ }
+
+
+ /* activate highlighted manipulator */
+ wm_manipulatormap_active_set(mmap, C, event, mpr);
+
+ /* XXX temporary workaround for modal manipulator operator
+ * conflicting with modal operator attached to manipulator */
+ if (mpr->op_data.type) {
+ if (mpr->op_data.type->modal) {
+ return OPERATOR_FINISHED;
+ }
+ }
+
+
+ ManipulatorTweakData *mtweak = MEM_mallocN(sizeof(ManipulatorTweakData), __func__);
+
+ mtweak->init_event = event->type;
+ mtweak->active = mmap->mmap_context.highlight;
+ mtweak->mmap = mmap;
+ mtweak->flag = 0;
+
+ op->customdata = mtweak;
+
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void MANIPULATORGROUP_OT_manipulator_tweak(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Manipulator Tweak";
+ ot->description = "Tweak the active manipulator";
+ ot->idname = "MANIPULATORGROUP_OT_manipulator_tweak";
+
+ /* api callbacks */
+ ot->invoke = manipulator_tweak_invoke;
+ ot->modal = manipulator_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
+}
+
+/** \} */ // Manipulator operators
+
+
+static wmKeyMap *manipulatorgroup_tweak_modal_keymap(wmKeyConfig *keyconf, const char *mgroupname)
+{
+ 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", mgroupname);
+ 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, "MANIPULATORGROUP_OT_manipulator_tweak");
+
+ return keymap;
+}
+
+/**
+ * Common default keymap for manipulator groups
+ */
+wmKeyMap *WM_manipulatorgroup_keymap_common(
+ const wmManipulatorGroupType *wgt, wmKeyConfig *config)
+{
+ /* Use area and region id since we might have multiple manipulators with the same name in different areas/regions */
+ wmKeyMap *km = WM_keymap_find(config, wgt->name, wgt->mmap_params.spaceid, wgt->mmap_params.regionid);
+
+ WM_keymap_add_item(km, "MANIPULATORGROUP_OT_manipulator_tweak", LEFTMOUSE, KM_PRESS, KM_ANY, 0);
+ manipulatorgroup_tweak_modal_keymap(config, wgt->name);
+
+ return km;
+}
+
+/**
+ * Variation of #WM_manipulatorgroup_keymap_common but with keymap items for selection
+ */
+wmKeyMap *WM_manipulatorgroup_keymap_common_select(
+ const wmManipulatorGroupType *wgt, wmKeyConfig *config)
+{
+ /* Use area and region id since we might have multiple manipulators with the same name in different areas/regions */
+ wmKeyMap *km = WM_keymap_find(config, wgt->name, wgt->mmap_params.spaceid, wgt->mmap_params.regionid);
+
+ WM_keymap_add_item(km, "MANIPULATORGROUP_OT_manipulator_tweak", ACTIONMOUSE, KM_PRESS, KM_ANY, 0);
+ manipulatorgroup_tweak_modal_keymap(config, wgt->name);
+
+ wmKeyMapItem *kmi = WM_keymap_add_item(km, "MANIPULATORGROUP_OT_manipulator_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(km, "MANIPULATORGROUP_OT_manipulator_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);
+
+ return km;
+}
+
+/** \} */ /* wmManipulatorGroup */
+
+/* -------------------------------------------------------------------- */
+/** \name wmManipulatorGroupType
+ *
+ * \{ */
+
+struct wmManipulatorGroupTypeRef *WM_manipulatormaptype_group_find_ptr(
+ struct wmManipulatorMapType *mmap_type,
+ const wmManipulatorGroupType *wgt)
+{
+ /* could use hash lookups as operator types do, for now simple search. */
+ for (wmManipulatorGroupTypeRef *wgt_ref = mmap_type->grouptype_refs.first;
+ wgt_ref;
+ wgt_ref = wgt_ref->next)
+ {
+ if (wgt_ref->type == wgt) {
+ return wgt_ref;
+ }
+ }
+ return NULL;
+}
+
+struct wmManipulatorGroupTypeRef *WM_manipulatormaptype_group_find(
+ struct wmManipulatorMapType *mmap_type,
+ const char *idname)
+{
+ /* could use hash lookups as operator types do, for now simple search. */
+ for (wmManipulatorGroupTypeRef *wgt_ref = mmap_type->grouptype_refs.first;
+ wgt_ref;
+ wgt_ref = wgt_ref->next)
+ {
+ if (STREQ(idname, wgt_ref->type->idname)) {
+ return wgt_ref;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Use this for registering manipulators on startup. For runtime, use #WM_manipulatormaptype_group_link_runtime.
+ */
+wmManipulatorGroupTypeRef *WM_manipulatormaptype_group_link(
+ wmManipulatorMapType *mmap_type, const char *idname)
+{
+ wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(idname, false);
+ BLI_assert(wgt != NULL);
+ return WM_manipulatormaptype_group_link_ptr(mmap_type, wgt);
+}
+
+wmManipulatorGroupTypeRef *WM_manipulatormaptype_group_link_ptr(
+ wmManipulatorMapType *mmap_type, wmManipulatorGroupType *wgt)
+{
+ wmManipulatorGroupTypeRef *wgt_ref = MEM_callocN(sizeof(wmManipulatorGroupTypeRef), "manipulator-group-ref");
+ wgt_ref->type = wgt;
+ BLI_addtail(&mmap_type->grouptype_refs, wgt_ref);
+ return wgt_ref;
+}
+
+void WM_manipulatormaptype_group_init_runtime(
+ const Main *bmain, wmManipulatorMapType *mmap_type,
+ wmManipulatorGroupType *wgt)
+{
+ /* init keymap - on startup there's an extra call to init keymaps for 'permanent' manipulator-groups */
+ wm_manipulatorgrouptype_setup_keymap(wgt, ((wmWindowManager *)bmain->wm.first)->defaultconf);
+
+ /* now create a manipulator 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) {
+ wmManipulatorMap *mmap = ar->manipulator_map;
+ if (mmap && mmap->type == mmap_type) {
+ wm_manipulatorgroup_new_from_type(mmap, wgt);
+
+ /* just add here, drawing will occur on next update */
+ wm_manipulatormap_highlight_set(mmap, NULL, NULL, 0);
+ ED_region_tag_redraw(ar);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+/**
+ * Unlike #WM_manipulatormaptype_group_unlink this doesn't maintain correct state, simply free.
+ */
+void WM_manipulatormaptype_group_free(wmManipulatorGroupTypeRef *wgt_ref)
+{
+ MEM_freeN(wgt_ref);
+}
+
+void WM_manipulatormaptype_group_unlink(
+ bContext *C, Main *bmain, wmManipulatorMapType *mmap_type,
+ const wmManipulatorGroupType *wgt)
+{
+ /* 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) {
+ wmManipulatorMap *mmap = ar->manipulator_map;
+ if (mmap && mmap->type == mmap_type) {
+ wmManipulatorGroup *mgroup, *mgroup_next;
+ for (mgroup = mmap->groups.first; mgroup; mgroup = mgroup_next) {
+ mgroup_next = mgroup->next;
+ if (mgroup->type == wgt) {
+ BLI_assert(mgroup->parent_mmap == mmap);
+ wm_manipulatorgroup_free(C, mgroup);
+ ED_region_tag_redraw(ar);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Free types. */
+ wmManipulatorGroupTypeRef *wgt_ref = WM_manipulatormaptype_group_find_ptr(mmap_type, wgt);
+ if (wgt_ref) {
+ BLI_remlink(&mmap_type->grouptype_refs, wgt_ref);
+ WM_manipulatormaptype_group_free(wgt_ref);
+ }
+
+ /* Note, we may want to keep this keymap for editing */
+ WM_keymap_remove(wgt->keyconf, wgt->keymap);
+
+ BLI_assert(WM_manipulatormaptype_group_find_ptr(mmap_type, wgt) == NULL);
+}
+
+void wm_manipulatorgrouptype_setup_keymap(
+ wmManipulatorGroupType *wgt, wmKeyConfig *keyconf)
+{
+ wgt->keymap = wgt->setup_keymap(wgt, keyconf);
+ wgt->keyconf = keyconf;
+}
+
+/** \} */ /* wmManipulatorGroupType */
+
+/* -------------------------------------------------------------------- */
+/** \name High Level Add/Remove API
+ *
+ * For use directly from operators & RNA registration.
+ *
+ * \note In context of manipulator API these names are a bit misleading,
+ * but for general use terms its OK.
+ * `WM_manipulator_group_add` would be more correctly called:
+ * `WM_manipulatormaptype_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_manipulator_group_add_ptr_ex(
+ wmManipulatorGroupType *wgt,
+ wmManipulatorMapType *mmap_type)
+{
+ WM_manipulatormaptype_group_link_ptr(mmap_type, wgt);
+
+ WM_manipulatorconfig_update_tag_init(mmap_type, wgt);
+}
+
+void WM_manipulator_group_add_ptr(
+ wmManipulatorGroupType *wgt)
+{
+ wmManipulatorMapType *mmap_type = WM_manipulatormaptype_ensure(&wgt->mmap_params);
+ WM_manipulator_group_add_ptr_ex(wgt, mmap_type);
+}
+
+void WM_manipulator_group_add(const char *idname)
+{
+ wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(idname, false);
+ BLI_assert(wgt != NULL);
+ WM_manipulator_group_add_ptr(wgt);
+}
+
+void WM_manipulator_group_remove_ptr_ex(
+ struct Main *bmain, wmManipulatorGroupType *wgt,
+ wmManipulatorMapType *mmap_type)
+{
+ WM_manipulatormaptype_group_unlink(NULL, bmain, mmap_type, wgt);
+}
+
+void WM_manipulator_group_remove_ptr(
+ struct Main *bmain, wmManipulatorGroupType *wgt)
+{
+ wmManipulatorMapType *mmap_type = WM_manipulatormaptype_ensure(&wgt->mmap_params);
+ WM_manipulator_group_remove_ptr_ex(bmain, wgt, mmap_type);
+}
+
+void WM_manipulator_group_remove(struct Main *bmain, const char *idname)
+{
+ wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(idname, false);
+ BLI_assert(wgt != NULL);
+ WM_manipulator_group_remove_ptr(bmain, wgt);
+}
+
+/* delayed versions */
+
+void WM_manipulator_group_remove_ptr_delayed_ex(
+ wmManipulatorGroupType *wgt,
+ wmManipulatorMapType *mmap_type)
+{
+ WM_manipulatorconfig_update_tag_remove(mmap_type, wgt);
+}
+
+void WM_manipulator_group_remove_ptr_delayed(
+ wmManipulatorGroupType *wgt)
+{
+ wmManipulatorMapType *mmap_type = WM_manipulatormaptype_ensure(&wgt->mmap_params);
+ WM_manipulator_group_remove_ptr_delayed_ex(wgt, mmap_type);
+}
+
+void WM_manipulator_group_remove_delayed(const char *idname)
+{
+ wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(idname, false);
+ BLI_assert(wgt != NULL);
+ WM_manipulator_group_remove_ptr_delayed(wgt);
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_group_type.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_group_type.c
new file mode 100644
index 00000000000..0f21a7448b5
--- /dev/null
+++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_group_type.c
@@ -0,0 +1,186 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/manipulators/intern/wm_manipulator_group_type.c
+ * \ingroup wm
+ */
+
+#include "BKE_context.h"
+
+#include "BLI_ghash.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+/* only for own init/exit calls (wm_manipulatorgrouptype_init/wm_manipulatorgrouptype_free) */
+#include "wm.h"
+
+/* own includes */
+#include "wm_manipulator_wmapi.h"
+#include "wm_manipulator_intern.h"
+
+
+/** \name ManipulatorGroup Type Append
+ *
+ * \note This follows conventions from #WM_operatortype_find #WM_operatortype_append & friends.
+ * \{ */
+
+static GHash *global_manipulatorgrouptype_hash = NULL;
+
+wmManipulatorGroupType *WM_manipulatorgrouptype_find(const char *idname, bool quiet)
+{
+ if (idname[0]) {
+ wmManipulatorGroupType *wgt;
+
+ wgt = BLI_ghash_lookup(global_manipulatorgrouptype_hash, idname);
+ if (wgt) {
+ return wgt;
+ }
+
+ if (!quiet) {
+ printf("search for unknown manipulator group '%s'\n", idname);
+ }
+ }
+ else {
+ if (!quiet) {
+ printf("search for empty manipulator group\n");
+ }
+ }
+
+ return NULL;
+}
+
+/* caller must free */
+void WM_manipulatorgrouptype_iter(GHashIterator *ghi)
+{
+ BLI_ghashIterator_init(ghi, global_manipulatorgrouptype_hash);
+}
+
+static wmManipulatorGroupType *wm_manipulatorgrouptype_append__begin(void)
+{
+ wmManipulatorGroupType *wgt = MEM_callocN(sizeof(wmManipulatorGroupType), "manipulatorgrouptype");
+
+ return wgt;
+}
+static void wm_manipulatorgrouptype_append__end(wmManipulatorGroupType *wgt)
+{
+ BLI_assert(wgt->name != NULL);
+ BLI_assert(wgt->idname != NULL);
+
+ /* if not set, use default */
+ if (wgt->setup_keymap == NULL) {
+ wgt->setup_keymap = WM_manipulatorgroup_keymap_common;
+ }
+
+ BLI_ghash_insert(global_manipulatorgrouptype_hash, (void *)wgt->idname, wgt);
+}
+
+wmManipulatorGroupType *WM_manipulatorgrouptype_append(
+ void (*wtfunc)(struct wmManipulatorGroupType *))
+{
+ wmManipulatorGroupType *wgt = wm_manipulatorgrouptype_append__begin();
+ wtfunc(wgt);
+ wm_manipulatorgrouptype_append__end(wgt);
+ return wgt;
+}
+
+wmManipulatorGroupType *WM_manipulatorgrouptype_append_ptr(
+ void (*wtfunc)(struct wmManipulatorGroupType *, void *), void *userdata)
+{
+ wmManipulatorGroupType *wgt = wm_manipulatorgrouptype_append__begin();
+ wtfunc(wgt, userdata);
+ wm_manipulatorgrouptype_append__end(wgt);
+ return wgt;
+}
+
+/**
+ * Append and insert into a manipulator typemap.
+ * This is most common for C manipulators which are enabled by default.
+ */
+wmManipulatorGroupTypeRef *WM_manipulatorgrouptype_append_and_link(
+ wmManipulatorMapType *mmap_type,
+ void (*wtfunc)(struct wmManipulatorGroupType *))
+{
+ wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_append(wtfunc);
+
+ wgt->mmap_params.spaceid = mmap_type->spaceid;
+ wgt->mmap_params.regionid = mmap_type->regionid;
+
+ return WM_manipulatormaptype_group_link_ptr(mmap_type, wgt);
+}
+
+/**
+ * Free but don't remove from ghash.
+ */
+static void manipulatorgrouptype_free(wmManipulatorGroupType *wgt)
+{
+ MEM_freeN(wgt);
+}
+
+void WM_manipulatorgrouptype_remove_ptr(wmManipulatorGroupType *wgt)
+{
+ BLI_assert(wgt == WM_manipulatorgrouptype_find(wgt->idname, false));
+
+ BLI_ghash_remove(global_manipulatorgrouptype_hash, wgt->idname, NULL, NULL);
+
+ manipulatorgrouptype_free(wgt);
+
+ /* XXX, TODO, update the world! */
+}
+
+bool WM_manipulatorgrouptype_remove(const char *idname)
+{
+ wmManipulatorGroupType *wgt = BLI_ghash_lookup(global_manipulatorgrouptype_hash, idname);
+
+ if (wgt == NULL) {
+ return false;
+ }
+
+ WM_manipulatorgrouptype_remove_ptr(wgt);
+
+ return true;
+}
+
+static void wm_manipulatorgrouptype_ghash_free_cb(wmManipulatorGroupType *mt)
+{
+ manipulatorgrouptype_free(mt);
+}
+
+void wm_manipulatorgrouptype_free(void)
+{
+ BLI_ghash_free(global_manipulatorgrouptype_hash, NULL, (GHashValFreeFP)wm_manipulatorgrouptype_ghash_free_cb);
+ global_manipulatorgrouptype_hash = NULL;
+}
+
+/* called on initialize WM_init() */
+void wm_manipulatorgrouptype_init(void)
+{
+ /* reserve size is set based on blender default setup */
+ global_manipulatorgrouptype_hash = BLI_ghash_str_new_ex("wm_manipulatorgrouptype_init gh", 128);
+}
+
+/** \} */
+
diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h b/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h
new file mode 100644
index 00000000000..6ddde1df9de
--- /dev/null
+++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.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.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/manipulators/intern/wm_manipulator_intern.h
+ * \ingroup wm
+ */
+
+
+#ifndef __WM_MANIPULATOR_INTERN_H__
+#define __WM_MANIPULATOR_INTERN_H__
+
+struct wmKeyConfig;
+struct wmManipulatorMap;
+struct ManipulatorGeomInfo;
+struct GHashIterator;
+
+#include "wm_manipulator_fn.h"
+
+/* -------------------------------------------------------------------- */
+/* wmManipulator */
+
+bool wm_manipulator_deselect(struct wmManipulatorMap *mmap, struct wmManipulator *mpr);
+bool wm_manipulator_select(bContext *C, struct wmManipulatorMap *mmap, struct wmManipulator *mpr);
+
+void wm_manipulator_calculate_scale(struct wmManipulator *mpr, const bContext *C);
+void wm_manipulator_update(struct wmManipulator *mpr, const bContext *C, const bool refresh_map);
+
+int wm_manipulator_is_visible(struct wmManipulator *mpr);
+enum {
+ WM_MANIPULATOR_IS_VISIBLE_UPDATE = (1 << 0),
+ WM_MANIPULATOR_IS_VISIBLE_DRAW = (1 << 1),
+};
+
+/* -------------------------------------------------------------------- */
+/* wmManipulatorGroup */
+
+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 wmManipulatorGroup *wm_manipulatorgroup_new_from_type(
+ struct wmManipulatorMap *mmap, struct wmManipulatorGroupType *wgt);
+void wm_manipulatorgroup_free(bContext *C, struct wmManipulatorGroup *mgroup);
+void wm_manipulatorgroup_manipulator_register(struct wmManipulatorGroup *mgroup, struct wmManipulator *mpr);
+struct wmManipulator *wm_manipulatorgroup_find_intersected_mainpulator(
+ const struct wmManipulatorGroup *mgroup, struct bContext *C, const struct wmEvent *event,
+ int *r_part);
+void wm_manipulatorgroup_intersectable_manipulators_to_list(
+ const struct wmManipulatorGroup *mgroup, struct ListBase *listbase);
+void wm_manipulatorgroup_ensure_initialized(struct wmManipulatorGroup *mgroup, const struct bContext *C);
+bool wm_manipulatorgroup_is_visible(const struct wmManipulatorGroup *mgroup, const struct bContext *C);
+bool wm_manipulatorgroup_is_visible_in_drawstep(const struct wmManipulatorGroup *mgroup, const int drawstep);
+
+void wm_manipulatorgrouptype_setup_keymap(
+ struct wmManipulatorGroupType *wgt, struct wmKeyConfig *keyconf);
+
+
+/* -------------------------------------------------------------------- */
+/* wmManipulatorMap */
+
+struct wmManipulatorMap {
+ struct wmManipulatorMap *next, *prev;
+
+ struct wmManipulatorMapType *type;
+ ListBase groups; /* wmManipulatorGroup */
+
+ char update_flag; /* private, update tagging */
+
+ /**
+ * \brief Manipulator map runtime context
+ *
+ * Contains information about this manipulator-map. Currently
+ * highlighted manipulator, currently selected manipulators, ...
+ */
+ struct {
+ /* we redraw the manipulator-map when this changes */
+ struct wmManipulator *highlight;
+ /* user has clicked this manipulator and it gets all input */
+ struct wmManipulator *active;
+ /* array for all selected manipulators
+ * TODO check on using BLI_array */
+ struct wmManipulator **selected;
+ int selected_len;
+ } mmap_context;
+};
+
+/**
+ * This is a container for all manipulator 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 wmManipulatorMapType {
+ struct wmManipulatorMapType *next, *prev;
+ short spaceid, regionid;
+ /* types of manipulator-groups for this manipulator-map type */
+ ListBase grouptype_refs;
+
+ /* eManipulatorMapTypeUpdateFlags */
+ uchar type_update_flag;
+};
+
+void wm_manipulatormap_selected_clear(struct wmManipulatorMap *mmap);
+bool wm_manipulatormap_deselect_all(struct wmManipulatorMap *mmap, struct wmManipulator ***sel);
+
+#endif \ No newline at end of file
diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c
new file mode 100644
index 00000000000..f5ef5572fd4
--- /dev/null
+++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c
@@ -0,0 +1,909 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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/manipulators/intern/wm_manipulator_map.c
+ * \ingroup wm
+ */
+
+#include <string.h>
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+#include "BLI_ghash.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+
+#include "ED_screen.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"
+
+/* own includes */
+#include "wm_manipulator_wmapi.h"
+#include "wm_manipulator_intern.h"
+
+/**
+ * Store all manipulator-maps here. Anyone who wants to register a manipulator for a certain
+ * area type can query the manipulator-map to do so.
+ */
+static ListBase manipulatormaptypes = {NULL, NULL};
+
+/**
+ * Update when manipulator-map types change.
+ */
+/* so operator removal can trigger update */
+enum {
+ WM_MANIPULATORMAPTYPE_GLOBAL_UPDATE_INIT = (1 << 0),
+ WM_MANIPULATORMAPTYPE_GLOBAL_UPDATE_REMOVE = (1 << 1),
+};
+
+static char wm_mmap_type_update_flag = 0;
+
+/**
+ * Manipulator-map update tagging.
+ */
+enum eManipulatorMapUpdateFlags {
+ /* Tag manipulator-map for refresh. */
+ MANIPULATORMAP_REFRESH = (1 << 0),
+};
+
+
+/* -------------------------------------------------------------------- */
+/** \name wmManipulatorMap
+ *
+ * \{ */
+
+/**
+ * Creates a manipulator-map with all registered manipulators for that type
+ */
+wmManipulatorMap *WM_manipulatormap_new_from_type(
+ const struct wmManipulatorMapType_Params *mmap_params)
+{
+ wmManipulatorMapType *mmap_type = WM_manipulatormaptype_ensure(mmap_params);
+ wmManipulatorMap *mmap;
+
+ mmap = MEM_callocN(sizeof(wmManipulatorMap), "ManipulatorMap");
+ mmap->type = mmap_type;
+ mmap->update_flag = MANIPULATORMAP_REFRESH;
+
+ /* create all manipulator-groups for this manipulator-map. We may create an empty one
+ * too in anticipation of manipulators from operators etc */
+ for (wmManipulatorGroupTypeRef *wgt_ref = mmap_type->grouptype_refs.first; wgt_ref; wgt_ref = wgt_ref->next) {
+ wm_manipulatorgroup_new_from_type(mmap, wgt_ref->type);
+ }
+
+ return mmap;
+}
+
+void wm_manipulatormap_selected_clear(wmManipulatorMap *mmap)
+{
+ MEM_SAFE_FREE(mmap->mmap_context.selected);
+ mmap->mmap_context.selected_len = 0;
+}
+
+void wm_manipulatormap_remove(wmManipulatorMap *mmap)
+{
+ if (!mmap)
+ return;
+
+ for (wmManipulatorGroup *mgroup = mmap->groups.first, *mgroup_next; mgroup; mgroup = mgroup_next) {
+ mgroup_next = mgroup->next;
+ BLI_assert(mgroup->parent_mmap == mmap);
+ wm_manipulatorgroup_free(NULL, mgroup);
+ }
+ BLI_assert(BLI_listbase_is_empty(&mmap->groups));
+
+ wm_manipulatormap_selected_clear(mmap);
+
+ MEM_freeN(mmap);
+}
+
+const ListBase *WM_manipulatormap_group_list(wmManipulatorMap *mmap)
+{
+ return &mmap->groups;
+}
+
+/**
+ * Creates and returns idname hash table for (visible) manipulators in \a mmap
+ *
+ * \param poll Polling function for excluding manipulators.
+ * \param data Custom data passed to \a poll
+ */
+static GHash *WM_manipulatormap_manipulator_hash_new(
+ const bContext *C, wmManipulatorMap *mmap,
+ bool (*poll)(const wmManipulator *, void *),
+ void *data, const bool include_hidden)
+{
+ GHash *hash = BLI_ghash_str_new(__func__);
+
+ /* collect manipulators */
+ for (wmManipulatorGroup *mgroup = mmap->groups.first; mgroup; mgroup = mgroup->next) {
+ if (!mgroup->type->poll || mgroup->type->poll(C, mgroup->type)) {
+ for (wmManipulator *mpr = mgroup->manipulators.first; mpr; mpr = mpr->next) {
+ if ((include_hidden || (mpr->flag & WM_MANIPULATOR_HIDDEN) == 0) &&
+ (!poll || poll(mpr, data)))
+ {
+ BLI_ghash_insert(hash, mpr->name, mpr);
+ }
+ }
+ }
+ }
+
+ return hash;
+}
+
+void WM_manipulatormap_tag_refresh(wmManipulatorMap *mmap)
+{
+ if (mmap) {
+ mmap->update_flag |= MANIPULATORMAP_REFRESH;
+ }
+}
+
+static void manipulatormap_tag_updated(wmManipulatorMap *mmap)
+{
+ mmap->update_flag = 0;
+}
+
+static bool manipulator_prepare_drawing(
+ wmManipulatorMap *mmap, wmManipulator *mpr,
+ const bContext *C, ListBase *draw_manipulators)
+{
+ int do_draw = wm_manipulator_is_visible(mpr);
+ if (do_draw == 0) {
+ /* skip */
+ }
+ else {
+ if (do_draw & WM_MANIPULATOR_IS_VISIBLE_UPDATE) {
+ /* hover manipulators need updating, even if we don't draw them */
+ wm_manipulator_update(mpr, C, (mmap->update_flag & MANIPULATORMAP_REFRESH) != 0);
+ }
+ if (do_draw & WM_MANIPULATOR_IS_VISIBLE_DRAW) {
+ BLI_addhead(draw_manipulators, BLI_genericNodeN(mpr));
+ }
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Update manipulators of \a mmap to prepare for drawing. Adds all manipulators that
+ * should be drawn to list \a draw_manipulators, note that added items need freeing.
+ */
+static void manipulatormap_prepare_drawing(
+ wmManipulatorMap *mmap, const bContext *C, ListBase *draw_manipulators, const int drawstep)
+{
+ if (!mmap || BLI_listbase_is_empty(&mmap->groups))
+ return;
+ wmManipulator *active_manipulator = mmap->mmap_context.active;
+
+ /* only active manipulator needs updating */
+ if (active_manipulator) {
+ if (manipulator_prepare_drawing(mmap, active_manipulator, C, draw_manipulators)) {
+ manipulatormap_tag_updated(mmap);
+ }
+ /* don't draw any other manipulators */
+ return;
+ }
+
+ for (wmManipulatorGroup *mgroup = mmap->groups.first; mgroup; mgroup = mgroup->next) {
+ /* check group visibility - drawstep first to avoid unnecessary call of group poll callback */
+ if (!wm_manipulatorgroup_is_visible_in_drawstep(mgroup, drawstep) ||
+ !wm_manipulatorgroup_is_visible(mgroup, C))
+ {
+ continue;
+ }
+
+ /* needs to be initialized on first draw */
+ wm_manipulatorgroup_ensure_initialized(mgroup, C);
+ /* update data if needed */
+ /* XXX weak: Manipulator-group may skip refreshing if it's invisible (map gets untagged nevertheless) */
+ if (mmap->update_flag & MANIPULATORMAP_REFRESH && mgroup->type->refresh) {
+ mgroup->type->refresh(C, mgroup);
+ }
+ /* prepare drawing */
+ if (mgroup->type->draw_prepare) {
+ mgroup->type->draw_prepare(C, mgroup);
+ }
+
+ for (wmManipulator *mpr = mgroup->manipulators.first; mpr; mpr = mpr->next) {
+ manipulator_prepare_drawing(mmap, mpr, C, draw_manipulators);
+ }
+ }
+
+ manipulatormap_tag_updated(mmap);
+}
+
+/**
+ * Draw all visible manipulators in \a mmap.
+ * Uses global draw_manipulators listbase.
+ */
+static void manipulators_draw_list(const wmManipulatorMap *mmap, const bContext *C, ListBase *draw_manipulators)
+{
+ /* Can be empty if we're dynamically added and removed. */
+ if ((mmap == NULL) || BLI_listbase_is_empty(&mmap->groups)) {
+ return;
+ }
+
+ const bool draw_multisample = (U.ogl_multisamples != USER_MULTISAMPLE_NONE);
+
+ /* TODO this will need it own shader probably? don't think it can be handled from that point though. */
+/* const bool use_lighting = (U.manipulator_flag & V3D_MANIPULATOR_SHADED) != 0; */
+
+ /* enable multisampling */
+ if (draw_multisample) {
+ glEnable(GL_MULTISAMPLE);
+ }
+
+ bool is_depth_prev = false;
+
+ /* draw_manipulators contains all visible manipulators - draw them */
+ for (LinkData *link = draw_manipulators->first, *link_next; link; link = link_next) {
+ wmManipulator *mpr = link->data;
+ link_next = link->next;
+
+ bool is_depth = (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_DEPTH_3D) != 0;
+
+ /* Weak! since we don't 100% support depth yet (select ignores depth) always show highlighted */
+ if (is_depth && (mpr->state & WM_MANIPULATOR_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;
+ }
+
+ mpr->type->draw(C, mpr);
+ /* free/remove manipulator link after drawing */
+ BLI_freelinkN(draw_manipulators, link);
+ }
+
+ if (is_depth_prev) {
+ glDisable(GL_DEPTH_TEST);
+ }
+
+ if (draw_multisample) {
+ glDisable(GL_MULTISAMPLE);
+ }
+}
+
+void WM_manipulatormap_draw(wmManipulatorMap *mmap, const bContext *C, const int drawstep)
+{
+ ListBase draw_manipulators = {NULL};
+
+ manipulatormap_prepare_drawing(mmap, C, &draw_manipulators, drawstep);
+ manipulators_draw_list(mmap, C, &draw_manipulators);
+ BLI_assert(BLI_listbase_is_empty(&draw_manipulators));
+}
+
+static void manipulator_find_active_3D_loop(const bContext *C, ListBase *visible_manipulators)
+{
+ int selectionbase = 0;
+ wmManipulator *mpr;
+
+ /* TODO(campbell): this depends on depth buffer being written to, currently broken for the 3D view. */
+ bool is_depth_prev = false;
+
+ for (LinkData *link = visible_manipulators->first; link; link = link->next) {
+ mpr = link->data;
+
+ bool is_depth = (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_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;
+ }
+
+ /* pass the selection id shifted by 8 bits. Last 8 bits are used for selected manipulator part id */
+
+ mpr->type->draw_select(C, mpr, selectionbase << 8);
+
+
+ selectionbase++;
+ }
+
+ if (is_depth_prev) {
+ glDisable(GL_DEPTH_TEST);
+ }
+}
+
+static int manipulator_find_intersected_3d_intern(
+ ListBase *visible_manipulators, const bContext *C, const int co[2],
+ const float hotspot)
+{
+ 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 manipulators. */
+ GLuint buffer[MAXPICKBUF];
+ short hits;
+ const bool do_passes = GPU_select_query_check_active();
+
+ rect.xmin = co[0] - hotspot;
+ rect.xmax = co[0] + hotspot;
+ rect.ymin = co[1] - hotspot;
+ rect.ymax = co[1] + hotspot;
+
+ ED_view3d_draw_setup_view(CTX_wm_window(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 */
+ manipulator_find_active_3D_loop(C, visible_manipulators);
+
+ hits = GPU_select_end();
+
+ if (do_passes && (hits > 0)) {
+ GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
+ manipulator_find_active_3D_loop(C, visible_manipulators);
+ GPU_select_end();
+ }
+
+ ED_view3d_draw_setup_view(CTX_wm_window(C), CTX_data_scene(C), ar, v3d, NULL, NULL, NULL);
+
+ return hits > 0 ? buffer[3] : -1;
+}
+
+/**
+ * Try to find a 3D manipulator at screen-space coordinate \a co. Uses OpenGL picking.
+ */
+static wmManipulator *manipulator_find_intersected_3d(
+ bContext *C, const int co[2], ListBase *visible_manipulators,
+ int *r_part)
+{
+ wmManipulator *result = NULL;
+ const float hotspot = 14.0f;
+ int ret;
+
+ *r_part = 0;
+ /* set up view matrices */
+ view3d_operator_needs_opengl(C);
+
+ ret = manipulator_find_intersected_3d_intern(visible_manipulators, C, co, 0.5f * hotspot);
+
+ if (ret != -1) {
+ LinkData *link;
+ int retsec;
+ retsec = manipulator_find_intersected_3d_intern(visible_manipulators, C, co, 0.2f * hotspot);
+
+ if (retsec != -1)
+ ret = retsec;
+
+ link = BLI_findlink(visible_manipulators, ret >> 8);
+ *r_part = ret & 255;
+ result = link->data;
+ }
+
+ return result;
+}
+
+/**
+ * Try to find a manipulator under the mouse position. 2D intersections have priority over
+ * 3D ones (could check for smallest screen-space distance but not needed right now).
+ */
+wmManipulator *wm_manipulatormap_highlight_find(
+ wmManipulatorMap *mmap, bContext *C, const wmEvent *event,
+ int *r_part)
+{
+ wmManipulator *mpr = NULL;
+ ListBase visible_3d_manipulators = {NULL};
+
+ for (wmManipulatorGroup *mgroup = mmap->groups.first; mgroup; mgroup = mgroup->next) {
+ if (wm_manipulatorgroup_is_visible(mgroup, C)) {
+ if (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) {
+ wm_manipulatorgroup_intersectable_manipulators_to_list(mgroup, &visible_3d_manipulators);
+ }
+ else if ((mpr = wm_manipulatorgroup_find_intersected_mainpulator(mgroup, C, event, r_part))) {
+ break;
+ }
+ }
+ }
+
+ if (!BLI_listbase_is_empty(&visible_3d_manipulators)) {
+ mpr = manipulator_find_intersected_3d(C, event->mval, &visible_3d_manipulators, r_part);
+ BLI_freelistN(&visible_3d_manipulators);
+ }
+
+ return mpr;
+}
+
+void WM_manipulatormap_add_handlers(ARegion *ar, wmManipulatorMap *mmap)
+{
+ wmEventHandler *handler = MEM_callocN(sizeof(wmEventHandler), "manipulator handler");
+
+ BLI_assert(mmap == ar->manipulator_map);
+ handler->manipulator_map = mmap;
+ BLI_addtail(&ar->handlers, handler);
+}
+
+void wm_manipulatormaps_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->manipulator_map) {
+ return;
+ }
+
+ wmManipulatorMap *mmap = handler->op_region->manipulator_map;
+ wmManipulator *mpr = wm_manipulatormap_active_get(mmap);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = CTX_wm_region(C);
+
+ wm_manipulatormap_handler_context(C, handler);
+
+ /* regular update for running operator */
+ if (modal_running) {
+ if (mpr && (mpr->op_data.type != NULL) &&
+ (mpr->op_data.type == handler->op->type))
+ {
+ if (mpr->custom_modal) {
+ mpr->custom_modal(C, mpr, event, 0);
+ }
+ else if (mpr->type->modal) {
+ mpr->type->modal(C, mpr, event, 0);
+ }
+ }
+ }
+ /* operator not running anymore */
+ else {
+ wm_manipulatormap_highlight_set(mmap, C, NULL, 0);
+ wm_manipulatormap_active_set(mmap, C, event, NULL);
+ }
+
+ /* restore the area */
+ CTX_wm_area_set(C, area);
+ CTX_wm_region_set(C, region);
+}
+
+/**
+ * Deselect all selected manipulators in \a mmap.
+ * \return if selection has changed.
+ */
+bool wm_manipulatormap_deselect_all(wmManipulatorMap *mmap, wmManipulator ***sel)
+{
+ if (*sel == NULL || mmap->mmap_context.selected_len == 0)
+ return false;
+
+ for (int i = 0; i < mmap->mmap_context.selected_len; i++) {
+ (*sel)[i]->state &= ~WM_MANIPULATOR_STATE_SELECT;
+ (*sel)[i] = NULL;
+ }
+ wm_manipulatormap_selected_clear(mmap);
+
+ /* always return true, we already checked
+ * if there's anything to deselect */
+ return true;
+}
+
+BLI_INLINE bool manipulator_selectable_poll(const wmManipulator *mpr, void *UNUSED(data))
+{
+ return (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_SELECT);
+}
+
+/**
+ * Select all selectable manipulators in \a mmap.
+ * \return if selection has changed.
+ */
+static bool wm_manipulatormap_select_all_intern(
+ bContext *C, wmManipulatorMap *mmap, wmManipulator ***sel,
+ const int action)
+{
+ /* GHash is used here to avoid having to loop over all manipulators twice (once to
+ * get tot_sel for allocating, once for actually selecting). Instead we collect
+ * selectable manipulators in hash table and use this to get tot_sel and do selection */
+
+ GHash *hash = WM_manipulatormap_manipulator_hash_new(C, mmap, manipulator_selectable_poll, NULL, true);
+ GHashIterator gh_iter;
+ int i, *selected_len = &mmap->mmap_context.selected_len;
+ bool changed = false;
+
+ *selected_len = BLI_ghash_size(hash);
+ *sel = MEM_reallocN(*sel, sizeof(**sel) * (*selected_len));
+
+ GHASH_ITER_INDEX (gh_iter, hash, i) {
+ wmManipulator *mpr_iter = BLI_ghashIterator_getValue(&gh_iter);
+
+ if ((mpr_iter->state & WM_MANIPULATOR_STATE_SELECT) == 0) {
+ changed = true;
+ }
+ mpr_iter->state |= WM_MANIPULATOR_STATE_SELECT;
+ if (mpr_iter->type->select) {
+ mpr_iter->type->select(C, mpr_iter, action);
+ }
+ (*sel)[i] = mpr_iter;
+ BLI_assert(i < (*selected_len));
+ }
+ /* highlight first manipulator */
+ wm_manipulatormap_highlight_set(mmap, C, (*sel)[0], (*sel)[0]->highlight_part);
+
+ BLI_ghash_free(hash, NULL, NULL);
+ return changed;
+}
+
+/**
+ * Select/Deselect all selectable manipulators in \a mmap.
+ * \return if selection has changed.
+ *
+ * TODO select all by type
+ */
+bool WM_manipulatormap_select_all(bContext *C, wmManipulatorMap *mmap, const int action)
+{
+ wmManipulator ***sel = &mmap->mmap_context.selected;
+ bool changed = false;
+
+ switch (action) {
+ case SEL_SELECT:
+ changed = wm_manipulatormap_select_all_intern(C, mmap, sel, action);
+ break;
+ case SEL_DESELECT:
+ changed = wm_manipulatormap_deselect_all(mmap, sel);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+
+ if (changed)
+ WM_event_add_mousemove(C);
+
+ return changed;
+}
+
+/**
+ * Prepare context for manipulator handling (but only if area/region is
+ * part of screen). Version of #wm_handler_op_context for manipulators.
+ */
+void wm_manipulatormap_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->manipulator_map == NULL)
+ printf("internal error: modal manipulator-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_manipulatormap_cursor_set(const wmManipulatorMap *mmap, wmWindow *win)
+{
+ for (; mmap; mmap = mmap->next) {
+ wmManipulator *mpr = mmap->mmap_context.highlight;
+ if (mpr && mpr->type->cursor_get) {
+ WM_cursor_set(win, mpr->type->cursor_get(mpr));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void wm_manipulatormap_highlight_set(
+ wmManipulatorMap *mmap, const bContext *C, wmManipulator *mpr, int part)
+{
+ if ((mpr != mmap->mmap_context.highlight) ||
+ (mpr && part != mpr->highlight_part))
+ {
+ if (mmap->mmap_context.highlight) {
+ mmap->mmap_context.highlight->state &= ~WM_MANIPULATOR_STATE_HIGHLIGHT;
+ mmap->mmap_context.highlight->highlight_part = 0;
+ }
+
+ mmap->mmap_context.highlight = mpr;
+
+ if (mpr) {
+ mpr->state |= WM_MANIPULATOR_STATE_HIGHLIGHT;
+ mpr->highlight_part = part;
+
+ if (C && mpr->type->cursor_get) {
+ wmWindow *win = CTX_wm_window(C);
+ WM_cursor_set(win, mpr->type->cursor_get(mpr));
+ }
+ }
+ else {
+ if (C) {
+ wmWindow *win = CTX_wm_window(C);
+ WM_cursor_set(win, CURSOR_STD);
+ }
+ }
+
+ /* tag the region for redraw */
+ if (C) {
+ ARegion *ar = CTX_wm_region(C);
+ ED_region_tag_redraw(ar);
+ }
+ }
+}
+
+wmManipulator *wm_manipulatormap_highlight_get(wmManipulatorMap *mmap)
+{
+ return mmap->mmap_context.highlight;
+}
+
+void wm_manipulatormap_active_set(
+ wmManipulatorMap *mmap, bContext *C, const wmEvent *event, wmManipulator *mpr)
+{
+ if (mpr && C) {
+ mpr->state |= WM_MANIPULATOR_STATE_ACTIVE;
+ mmap->mmap_context.active = mpr;
+
+ if (mpr->op_data.type) {
+ /* first activate the manipulator itself */
+ if (mpr->type->invoke &&
+ (mpr->type->modal || mpr->custom_modal))
+ {
+ mpr->type->invoke(C, mpr, event);
+ }
+
+ WM_operator_name_call_ptr(C, mpr->op_data.type, WM_OP_INVOKE_DEFAULT, &mpr->op_data.ptr);
+
+ /* we failed to hook the manipulator to the operator handler or operator was cancelled, return */
+ if (!mmap->mmap_context.active) {
+ mpr->state &= ~WM_MANIPULATOR_STATE_ACTIVE;
+ /* first activate the manipulator itself */
+ MEM_SAFE_FREE(mpr->interaction_data);
+ }
+ return;
+ }
+ else {
+ if (mpr->type->invoke &&
+ (mpr->type->modal || mpr->custom_modal))
+ {
+ mpr->type->invoke(C, mpr, event);
+ }
+ }
+ WM_cursor_grab_enable(CTX_wm_window(C), true, true, NULL);
+ }
+ else {
+ mpr = mmap->mmap_context.active;
+
+ /* deactivate, manipulator but first take care of some stuff */
+ if (mpr) {
+ mpr->state &= ~WM_MANIPULATOR_STATE_ACTIVE;
+ /* first activate the manipulator itself */
+ MEM_SAFE_FREE(mpr->interaction_data);
+ }
+ mmap->mmap_context.active = NULL;
+
+ if (C) {
+ WM_cursor_grab_disable(CTX_wm_window(C), NULL);
+ ED_region_tag_redraw(CTX_wm_region(C));
+ WM_event_add_mousemove(C);
+ }
+ }
+}
+
+wmManipulator *wm_manipulatormap_active_get(wmManipulatorMap *mmap)
+{
+ return mmap->mmap_context.active;
+}
+
+/** \} */ /* wmManipulatorMap */
+
+
+/* -------------------------------------------------------------------- */
+/** \name wmManipulatorMapType
+ *
+ * \{ */
+
+wmManipulatorMapType *WM_manipulatormaptype_find(
+ const struct wmManipulatorMapType_Params *mmap_params)
+{
+ for (wmManipulatorMapType *mmap_type = manipulatormaptypes.first; mmap_type; mmap_type = mmap_type->next) {
+ if (mmap_type->spaceid == mmap_params->spaceid &&
+ mmap_type->regionid == mmap_params->regionid)
+ {
+ return mmap_type;
+ }
+ }
+
+ return NULL;
+}
+
+wmManipulatorMapType *WM_manipulatormaptype_ensure(
+ const struct wmManipulatorMapType_Params *mmap_params)
+{
+ wmManipulatorMapType *mmap_type = WM_manipulatormaptype_find(mmap_params);
+
+ if (mmap_type) {
+ return mmap_type;
+ }
+
+ mmap_type = MEM_callocN(sizeof(wmManipulatorMapType), "manipulatortype list");
+ mmap_type->spaceid = mmap_params->spaceid;
+ mmap_type->regionid = mmap_params->regionid;
+ BLI_addhead(&manipulatormaptypes, mmap_type);
+
+ return mmap_type;
+}
+
+void wm_manipulatormaptypes_free(void)
+{
+ for (wmManipulatorMapType *mmap_type = manipulatormaptypes.first, *mmap_type_next;
+ mmap_type;
+ mmap_type = mmap_type_next)
+ {
+ mmap_type_next = mmap_type->next;
+ for (wmManipulatorGroupTypeRef *wgt_ref = mmap_type->grouptype_refs.first, *wgt_next;
+ wgt_ref;
+ wgt_ref = wgt_next)
+ {
+ wgt_next = wgt_ref->next;
+ WM_manipulatormaptype_group_free(wgt_ref);
+ }
+ MEM_freeN(mmap_type);
+ }
+}
+
+/**
+ * Initialize keymaps for all existing manipulator-groups
+ */
+void wm_manipulators_keymap(wmKeyConfig *keyconf)
+{
+ /* we add this item-less keymap once and use it to group manipulator-group keymaps into it */
+ WM_keymap_find(keyconf, "Manipulators", 0, 0);
+
+ for (wmManipulatorMapType *mmap_type = manipulatormaptypes.first; mmap_type; mmap_type = mmap_type->next) {
+ for (wmManipulatorGroupTypeRef *wgt_ref = mmap_type->grouptype_refs.first; wgt_ref; wgt_ref = wgt_ref->next) {
+ wm_manipulatorgrouptype_setup_keymap(wgt_ref->type, keyconf);
+ }
+ }
+}
+
+/** \} */ /* wmManipulatorMapType */
+
+/* -------------------------------------------------------------------- */
+/** \name Updates for Dynamic Type Registraion
+ *
+ * \{ */
+
+
+void WM_manipulatorconfig_update_tag_init(
+ wmManipulatorMapType *mmap_type, wmManipulatorGroupType *wgt)
+{
+ /* tag for update on next use */
+ mmap_type->type_update_flag |= WM_MANIPULATORMAPTYPE_UPDATE_INIT;
+ wgt->type_update_flag |= WM_MANIPULATORMAPTYPE_UPDATE_INIT;
+
+ wm_mmap_type_update_flag |= WM_MANIPULATORMAPTYPE_GLOBAL_UPDATE_INIT;
+}
+
+void WM_manipulatorconfig_update_tag_remove(
+ wmManipulatorMapType *mmap_type, wmManipulatorGroupType *wgt)
+{
+ /* tag for update on next use */
+ mmap_type->type_update_flag |= WM_MANIPULATORMAPTYPE_UPDATE_REMOVE;
+ wgt->type_update_flag |= WM_MANIPULATORMAPTYPE_UPDATE_REMOVE;
+
+ wm_mmap_type_update_flag |= WM_MANIPULATORMAPTYPE_GLOBAL_UPDATE_REMOVE;
+}
+
+/**
+ * Run incase new types have been added (runs often, early exit where possible).
+ * Follows #WM_keyconfig_update concentions.
+ */
+void WM_manipulatorconfig_update(struct Main *bmain)
+{
+ if (G.background)
+ return;
+
+ if (wm_mmap_type_update_flag == 0)
+ return;
+
+ if (wm_mmap_type_update_flag & WM_MANIPULATORMAPTYPE_GLOBAL_UPDATE_REMOVE) {
+ for (wmManipulatorMapType *mmap_type = manipulatormaptypes.first;
+ mmap_type;
+ mmap_type = mmap_type->next)
+ {
+ if (mmap_type->type_update_flag & WM_MANIPULATORMAPTYPE_GLOBAL_UPDATE_REMOVE) {
+ mmap_type->type_update_flag &= ~WM_MANIPULATORMAPTYPE_UPDATE_REMOVE;
+ for (wmManipulatorGroupTypeRef *wgt_ref = mmap_type->grouptype_refs.first, *wgt_ref_next;
+ wgt_ref;
+ wgt_ref = wgt_ref_next)
+ {
+ wgt_ref_next = wgt_ref->next;
+ WM_manipulatormaptype_group_unlink(NULL, bmain, mmap_type, wgt_ref->type);
+ }
+ }
+ }
+
+ wm_mmap_type_update_flag &= ~WM_MANIPULATORMAPTYPE_GLOBAL_UPDATE_REMOVE;
+ }
+
+ if (wm_mmap_type_update_flag & WM_MANIPULATORMAPTYPE_GLOBAL_UPDATE_INIT) {
+ for (wmManipulatorMapType *mmap_type = manipulatormaptypes.first;
+ mmap_type;
+ mmap_type = mmap_type->next)
+ {
+ if (mmap_type->type_update_flag & WM_MANIPULATORMAPTYPE_UPDATE_INIT) {
+ mmap_type->type_update_flag &= ~WM_MANIPULATORMAPTYPE_UPDATE_INIT;
+ for (wmManipulatorGroupTypeRef *wgt_ref = mmap_type->grouptype_refs.first;
+ wgt_ref;
+ wgt_ref = wgt_ref->next)
+ {
+ wgt_ref->type->type_update_flag &= ~WM_MANIPULATORMAPTYPE_UPDATE_INIT;
+ WM_manipulatormaptype_group_init_runtime(bmain, mmap_type, wgt_ref->type);
+ }
+ }
+ }
+
+ wm_mmap_type_update_flag &= ~WM_MANIPULATORMAPTYPE_GLOBAL_UPDATE_INIT;
+ }
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_target_props.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_target_props.c
new file mode 100644
index 00000000000..fcf7b2c986f
--- /dev/null
+++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_target_props.c
@@ -0,0 +1,274 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/manipulators/intern/wm_manipulator_target_props.c
+ * \ingroup wm
+ */
+
+#include "BKE_context.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "wm.h"
+
+/* own includes */
+#include "wm_manipulator_wmapi.h"
+#include "wm_manipulator_intern.h"
+
+/* -------------------------------------------------------------------- */
+
+/** \name Property Definition
+ * \{ */
+
+BLI_INLINE wmManipulatorProperty *wm_manipulator_target_property_array(wmManipulator *mpr)
+{
+ return (wmManipulatorProperty *)(POINTER_OFFSET(mpr, mpr->type->struct_size));
+}
+
+wmManipulatorProperty *WM_manipulator_target_property_array(wmManipulator *mpr)
+{
+ return wm_manipulator_target_property_array(mpr);
+}
+
+wmManipulatorProperty *WM_manipulator_target_property_at_index(wmManipulator *mpr, int index)
+{
+ BLI_assert(index < mpr->type->target_property_defs_len);
+ BLI_assert(index != -1);
+ wmManipulatorProperty *mpr_prop_array = wm_manipulator_target_property_array(mpr);
+ return &mpr_prop_array[index];
+}
+
+wmManipulatorProperty *WM_manipulator_target_property_find(wmManipulator *mpr, const char *idname)
+{
+ int index = BLI_findstringindex(
+ &mpr->type->target_property_defs, idname, offsetof(wmManipulatorPropertyType, idname));
+ if (index != -1) {
+ return WM_manipulator_target_property_at_index(mpr, index);
+ }
+ else {
+ return NULL;
+ }
+}
+
+void WM_manipulator_target_property_def_rna_ptr(
+ wmManipulator *mpr, const wmManipulatorPropertyType *mpr_prop_type,
+ PointerRNA *ptr, PropertyRNA *prop, int index)
+{
+ wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_at_index(mpr, mpr_prop_type->index_in_type);
+
+ /* if manipulator evokes an operator we cannot use it for property manipulation */
+ mpr->op_data.type = NULL;
+
+ mpr_prop->type = mpr_prop_type;
+
+ mpr_prop->ptr = *ptr;
+ mpr_prop->prop = prop;
+ mpr_prop->index = index;
+
+ if (mpr->type->property_update) {
+ mpr->type->property_update(mpr, mpr_prop);
+ }
+}
+
+void WM_manipulator_target_property_def_rna(
+ wmManipulator *mpr, const char *idname,
+ PointerRNA *ptr, const char *propname, int index)
+{
+ const wmManipulatorPropertyType *mpr_prop_type = WM_manipulatortype_target_property_find(mpr->type, idname);
+ PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
+ WM_manipulator_target_property_def_rna_ptr(mpr, mpr_prop_type, ptr, prop, index);
+}
+
+void WM_manipulator_target_property_def_func_ptr(
+ wmManipulator *mpr, const wmManipulatorPropertyType *mpr_prop_type,
+ const wmManipulatorPropertyFnParams *params)
+{
+ wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_at_index(mpr, mpr_prop_type->index_in_type);
+
+ /* if manipulator evokes an operator we cannot use it for property manipulation */
+ mpr->op_data.type = NULL;
+
+ mpr_prop->type = mpr_prop_type;
+
+ mpr_prop->custom_func.value_get_fn = params->value_get_fn;
+ mpr_prop->custom_func.value_set_fn = params->value_set_fn;
+ mpr_prop->custom_func.range_get_fn = params->range_get_fn;
+ mpr_prop->custom_func.free_fn = params->free_fn;
+ mpr_prop->custom_func.user_data = params->user_data;
+
+ if (mpr->type->property_update) {
+ mpr->type->property_update(mpr, mpr_prop);
+ }
+}
+
+void WM_manipulator_target_property_def_func(
+ wmManipulator *mpr, const char *idname,
+ const wmManipulatorPropertyFnParams *params)
+{
+ const wmManipulatorPropertyType *mpr_prop_type = WM_manipulatortype_target_property_find(mpr->type, idname);
+ WM_manipulator_target_property_def_func_ptr(mpr, mpr_prop_type, params);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Property Access
+ * \{ */
+
+bool WM_manipulator_target_property_is_valid_any(wmManipulator *mpr)
+{
+ wmManipulatorProperty *mpr_prop_array = wm_manipulator_target_property_array(mpr);
+ for (int i = 0; i < mpr->type->target_property_defs_len; i++) {
+ wmManipulatorProperty *mpr_prop = &mpr_prop_array[i];
+ if (WM_manipulator_target_property_is_valid(mpr_prop)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool WM_manipulator_target_property_is_valid(const wmManipulatorProperty *mpr_prop)
+{
+ return ((mpr_prop->prop != NULL) ||
+ (mpr_prop->custom_func.value_get_fn && mpr_prop->custom_func.value_set_fn));
+}
+
+float WM_manipulator_target_property_value_get(
+ const wmManipulator *mpr, wmManipulatorProperty *mpr_prop)
+{
+ if (mpr_prop->custom_func.value_get_fn) {
+ float value = 0.0f;
+ BLI_assert(mpr_prop->type->array_length == 1);
+ mpr_prop->custom_func.value_get_fn(mpr, mpr_prop, &value);
+ return value;
+ }
+
+ if (mpr_prop->index == -1) {
+ return RNA_property_float_get(&mpr_prop->ptr, mpr_prop->prop);
+ }
+ else {
+ return RNA_property_float_get_index(&mpr_prop->ptr, mpr_prop->prop, mpr_prop->index);
+ }
+}
+
+void WM_manipulator_target_property_value_set(
+ bContext *C, const wmManipulator *mpr,
+ wmManipulatorProperty *mpr_prop, const float value)
+{
+ if (mpr_prop->custom_func.value_set_fn) {
+ BLI_assert(mpr_prop->type->array_length == 1);
+ mpr_prop->custom_func.value_set_fn(mpr, mpr_prop, &value);
+ return;
+ }
+
+ /* reset property */
+ if (mpr_prop->index == -1) {
+ RNA_property_float_set(&mpr_prop->ptr, mpr_prop->prop, value);
+ }
+ else {
+ RNA_property_float_set_index(&mpr_prop->ptr, mpr_prop->prop, mpr_prop->index, value);
+ }
+ RNA_property_update(C, &mpr_prop->ptr, mpr_prop->prop);
+}
+
+void WM_manipulator_target_property_value_get_array(
+ const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
+ float *value)
+{
+ if (mpr_prop->custom_func.value_get_fn) {
+ mpr_prop->custom_func.value_get_fn(mpr, mpr_prop, value);
+ return;
+ }
+ return RNA_property_float_get_array(&mpr_prop->ptr, mpr_prop->prop, value);
+}
+
+void WM_manipulator_target_property_value_set_array(
+ bContext *C, const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
+ const float *value)
+{
+ if (mpr_prop->custom_func.value_set_fn) {
+ mpr_prop->custom_func.value_set_fn(mpr, mpr_prop, value);
+ return;
+ }
+ RNA_property_float_set_array(&mpr_prop->ptr, mpr_prop->prop, value);
+
+ RNA_property_update(C, &mpr_prop->ptr, mpr_prop->prop);
+}
+
+void WM_manipulator_target_property_range_get(
+ const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
+ float range[2])
+{
+ if (mpr_prop->custom_func.range_get_fn) {
+ mpr_prop->custom_func.range_get_fn(mpr, mpr_prop, range);
+ return;
+ }
+
+ float step, precision;
+ RNA_property_float_ui_range(&mpr_prop->ptr, mpr_prop->prop, &range[0], &range[1], &step, &precision);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Property Define
+ * \{ */
+
+const wmManipulatorPropertyType *WM_manipulatortype_target_property_find(
+ const wmManipulatorType *wt, const char *idname)
+{
+ return BLI_findstring(&wt->target_property_defs, idname, offsetof(wmManipulatorPropertyType, idname));
+}
+
+void WM_manipulatortype_target_property_def(
+ wmManipulatorType *wt, const char *idname, int data_type, int array_length)
+{
+ wmManipulatorPropertyType *mpt;
+
+ BLI_assert(WM_manipulatortype_target_property_find(wt, idname) == NULL);
+
+ const uint idname_size = strlen(idname) + 1;
+ mpt = MEM_callocN(sizeof(wmManipulatorPropertyType) + idname_size, __func__);
+ memcpy(mpt->idname, idname, idname_size);
+ mpt->data_type = data_type;
+ mpt->array_length = array_length;
+ mpt->index_in_type = wt->target_property_defs_len;
+ wt->target_property_defs_len += 1;
+ BLI_addtail(&wt->target_property_defs, mpt);
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_type.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_type.c
new file mode 100644
index 00000000000..7dabc70d69d
--- /dev/null
+++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_type.c
@@ -0,0 +1,166 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/manipulators/intern/wm_manipulator_type.c
+ * \ingroup wm
+ */
+
+#include "BKE_context.h"
+
+#include "BLI_ghash.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.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_manipulatortype_init/wm_manipulatortype_free) */
+#include "wm.h"
+
+/* own includes */
+#include "wm_manipulator_wmapi.h"
+#include "wm_manipulator_intern.h"
+
+
+/** \name Manipulator Type Append
+ *
+ * \note This follows conventions from #WM_operatortype_find #WM_operatortype_append & friends.
+ * \{ */
+
+static GHash *global_manipulatortype_hash = NULL;
+
+const wmManipulatorType *WM_manipulatortype_find(const char *idname, bool quiet)
+{
+ if (idname[0]) {
+ wmManipulatorType *wt;
+
+ wt = BLI_ghash_lookup(global_manipulatortype_hash, idname);
+ if (wt) {
+ return wt;
+ }
+
+ if (!quiet) {
+ printf("search for unknown manipulator '%s'\n", idname);
+ }
+ }
+ else {
+ if (!quiet) {
+ printf("search for empty manipulator\n");
+ }
+ }
+
+ return NULL;
+}
+
+/* caller must free */
+void WM_manipulatortype_iter(GHashIterator *ghi)
+{
+ BLI_ghashIterator_init(ghi, global_manipulatortype_hash);
+}
+
+static wmManipulatorType *wm_manipulatortype_append__begin(void)
+{
+ wmManipulatorType *wt = MEM_callocN(sizeof(wmManipulatorType), "manipulatortype");
+ wt->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_ManipulatorProperties);
+#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 wt;
+}
+static void wm_manipulatortype_append__end(wmManipulatorType *wt)
+{
+ BLI_assert(wt->struct_size >= sizeof(wmManipulator));
+
+ RNA_def_struct_identifier(wt->srna, wt->idname);
+
+ BLI_ghash_insert(global_manipulatortype_hash, (void *)wt->idname, wt);
+}
+
+void WM_manipulatortype_append(void (*wtfunc)(struct wmManipulatorType *))
+{
+ wmManipulatorType *wt = wm_manipulatortype_append__begin();
+ wtfunc(wt);
+ wm_manipulatortype_append__end(wt);
+}
+
+void WM_manipulatortype_append_ptr(void (*wtfunc)(struct wmManipulatorType *, void *), void *userdata)
+{
+ wmManipulatorType *mt = wm_manipulatortype_append__begin();
+ wtfunc(mt, userdata);
+ wm_manipulatortype_append__end(mt);
+}
+
+/**
+ * Free but don't remove from ghash.
+ */
+static void manipulatortype_free(wmManipulatorType *wt)
+{
+ BLI_freelistN(&wt->target_property_defs);
+ MEM_freeN(wt);
+}
+
+void WM_manipulatortype_remove_ptr(wmManipulatorType *wt)
+{
+ BLI_assert(wt == WM_manipulatortype_find(wt->idname, false));
+
+ BLI_ghash_remove(global_manipulatortype_hash, wt->idname, NULL, NULL);
+
+ manipulatortype_free(wt);
+}
+
+bool WM_manipulatortype_remove(const char *idname)
+{
+ wmManipulatorType *wt = BLI_ghash_lookup(global_manipulatortype_hash, idname);
+
+ if (wt == NULL) {
+ return false;
+ }
+
+ WM_manipulatortype_remove_ptr(wt);
+
+ return true;
+}
+
+static void wm_manipulatortype_ghash_free_cb(wmManipulatorType *mt)
+{
+ manipulatortype_free(mt);
+}
+
+void wm_manipulatortype_free(void)
+{
+ BLI_ghash_free(global_manipulatortype_hash, NULL, (GHashValFreeFP)wm_manipulatortype_ghash_free_cb);
+ global_manipulatortype_hash = NULL;
+}
+
+/* called on initialize WM_init() */
+void wm_manipulatortype_init(void)
+{
+ /* reserve size is set based on blender default setup */
+ global_manipulatortype_hash = BLI_ghash_str_new_ex("wm_manipulatortype_init gh", 128);
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/manipulators/wm_manipulator_fn.h b/source/blender/windowmanager/manipulators/wm_manipulator_fn.h
new file mode 100644
index 00000000000..ae72e04e1c3
--- /dev/null
+++ b/source/blender/windowmanager/manipulators/wm_manipulator_fn.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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/manipulators/wm_manipulator_fn.h
+ * \ingroup wm
+ *
+ * Callback function definitions, needed for both Types & API headers.
+ */
+
+#ifndef __WM_MANIPULATOR_FN_H__
+#define __WM_MANIPULATOR_FN_H__
+
+#include "BLI_compiler_attrs.h"
+
+/* wmManipulatorGroup */
+typedef bool (*wmManipulatorGroupFnPoll)(
+ const struct bContext *, struct wmManipulatorGroupType *)
+ ATTR_WARN_UNUSED_RESULT;
+typedef void (*wmManipulatorGroupFnInit)(
+ const struct bContext *, struct wmManipulatorGroup *);
+typedef void (*wmManipulatorGroupFnRefresh)(
+ const struct bContext *, struct wmManipulatorGroup *);
+typedef void (*wmManipulatorGroupFnDrawPrepare)(
+ const struct bContext *, struct wmManipulatorGroup *);
+typedef struct wmKeyMap *(*wmManipulatorGroupFnSetupKeymap)(
+ const struct wmManipulatorGroupType *, struct wmKeyConfig *)
+ ATTR_WARN_UNUSED_RESULT;
+
+/* wmManipulator */
+/* See: wmManipulatorType for docs on each type. */
+
+typedef void (*wmManipulatorFnSetup)(struct wmManipulator *);
+typedef void (*wmManipulatorFnDraw)(const struct bContext *, struct wmManipulator *);
+typedef void (*wmManipulatorFnDrawSelect)(const struct bContext *, struct wmManipulator *, int);
+typedef int (*wmManipulatorFnTestSelect)(struct bContext *, struct wmManipulator *, const struct wmEvent *);
+typedef void (*wmManipulatorFnModal)(struct bContext *, struct wmManipulator *, const struct wmEvent *, const int);
+typedef void (*wmManipulatorFnPropertyUpdate)(struct wmManipulator *, struct wmManipulatorProperty *);
+typedef void (*wmManipulatorFnMatrixWorldGet)(struct wmManipulator *, float[4][4]);
+typedef void (*wmManipulatorFnInvoke)(struct bContext *, struct wmManipulator *, const struct wmEvent *);
+typedef void (*wmManipulatorFnExit)(struct bContext *, struct wmManipulator *, const bool);
+typedef int (*wmManipulatorFnCursorGet)(struct wmManipulator *);
+typedef void (*wmManipulatorFnSelect)(struct bContext *, struct wmManipulator *, const int);
+
+/* wmManipulatorProperty ('value' type defined by 'wmManipulatorProperty.data_type') */
+typedef void (*wmManipulatorPropertyFnGet)(
+ const struct wmManipulator *, struct wmManipulatorProperty *,
+ /* typically 'float *' */
+ void *value);
+typedef void (*wmManipulatorPropertyFnSet)(
+ const struct wmManipulator *, struct wmManipulatorProperty *,
+ /* typically 'const float *' */
+ const void *value);
+typedef void (*wmManipulatorPropertyFnRangeGet)(
+ const struct wmManipulator *, struct wmManipulatorProperty *,
+ /* typically 'float[2]' */
+ void *range);
+typedef void (*wmManipulatorPropertyFnFree)(
+ const struct wmManipulator *, struct wmManipulatorProperty *);
+
+typedef struct wmManipulatorPropertyFnParams {
+ wmManipulatorPropertyFnGet value_get_fn;
+ wmManipulatorPropertyFnSet value_set_fn;
+ wmManipulatorPropertyFnRangeGet range_get_fn;
+ wmManipulatorPropertyFnFree free_fn;
+ void *user_data;
+} wmManipulatorPropertyFnParams;
+
+#endif /* __WM_MANIPULATOR_FN_H__ */
diff --git a/source/blender/windowmanager/manipulators/wm_manipulator_wmapi.h b/source/blender/windowmanager/manipulators/wm_manipulator_wmapi.h
new file mode 100644
index 00000000000..61489b6a730
--- /dev/null
+++ b/source/blender/windowmanager/manipulators/wm_manipulator_wmapi.h
@@ -0,0 +1,93 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/manipulators/wm_manipulator_wmapi.h
+ * \ingroup wm
+ *
+ * \name Manipulators Window Manager API
+ * API for usage in window manager code only. It should contain all functionality
+ * needed to hook up the manipulator system with Blender's window manager. It's
+ * mostly the event system that needs to communicate with manipulator code.
+ *
+ * Only included in wm.h and lower level files.
+ */
+
+
+#ifndef __WM_MANIPULATOR_WMAPI_H__
+#define __WM_MANIPULATOR_WMAPI_H__
+
+struct wmEventHandler;
+struct wmManipulatorMap;
+struct wmOperatorType;
+struct wmOperator;
+
+
+/* -------------------------------------------------------------------- */
+/* wmManipulator */
+
+/* wm_manipulator_type.c, for init/exit */
+void wm_manipulatortype_free(void);
+void wm_manipulatortype_init(void);
+
+/* wm_manipulatorgroup_type.c, for init/exit */
+void wm_manipulatorgrouptype_free(void);
+void wm_manipulatorgrouptype_init(void);
+
+/* -------------------------------------------------------------------- */
+/* wmManipulatorGroup */
+
+void MANIPULATORGROUP_OT_manipulator_select(struct wmOperatorType *ot);
+void MANIPULATORGROUP_OT_manipulator_tweak(struct wmOperatorType *ot);
+
+/* -------------------------------------------------------------------- */
+/* wmManipulatorMap */
+
+void wm_manipulatormap_remove(struct wmManipulatorMap *mmap);
+
+void wm_manipulators_keymap(struct wmKeyConfig *keyconf);
+
+void wm_manipulatormaps_handled_modal_update(
+ bContext *C, struct wmEvent *event, struct wmEventHandler *handler);
+void wm_manipulatormap_handler_context(bContext *C, struct wmEventHandler *handler);
+
+struct wmManipulator *wm_manipulatormap_highlight_find(
+ struct wmManipulatorMap *mmap, bContext *C, const struct wmEvent *event,
+ int *r_part);
+void wm_manipulatormap_highlight_set(
+ struct wmManipulatorMap *mmap, const bContext *C,
+ struct wmManipulator *mpr, int part);
+struct wmManipulator *wm_manipulatormap_highlight_get(struct wmManipulatorMap *mmap);
+void wm_manipulatormap_active_set(
+ struct wmManipulatorMap *mmap, bContext *C,
+ const struct wmEvent *event, struct wmManipulator *mpr);
+struct wmManipulator *wm_manipulatormap_active_get(struct wmManipulatorMap *mmap);
+
+/* -------------------------------------------------------------------- */
+/* wmManipulatorMapType */
+
+void wm_manipulatormaptypes_free(void);
+
+#endif /* __WM_MANIPULATOR_WMAPI_H__ */
+
diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h
index 2f06ddab1e8..f63246580ea 100644
--- a/source/blender/windowmanager/wm.h
+++ b/source/blender/windowmanager/wm.h
@@ -34,6 +34,8 @@
struct wmWindow;
struct ReportList;
+#include "manipulators/wm_manipulator_wmapi.h"
+
typedef struct wmPaintCursor {
struct wmPaintCursor *next, *prev;
@@ -78,6 +80,7 @@ void wm_autosave_location(char *filepath);
/* wm_stereo.c */
void wm_method_draw_stereo3d(const bContext *C, wmWindow *win);
+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);
void wm_stereo3d_set_draw(bContext *C, wmOperator *op);
diff --git a/source/blender/windowmanager/wm_draw.h b/source/blender/windowmanager/wm_draw.h
index 0f125309045..56dff304719 100644
--- a/source/blender/windowmanager/wm_draw.h
+++ b/source/blender/windowmanager/wm_draw.h
@@ -34,6 +34,8 @@
#include "GPU_glew.h"
+#define USE_TEXTURE_RECTANGLE 1
+
typedef struct wmDrawTriple {
GLuint bind;
int x, y;
diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h
index efc01b1f8a8..2f7ebbc1def 100644
--- a/source/blender/windowmanager/wm_event_system.h
+++ b/source/blender/windowmanager/wm_event_system.h
@@ -52,7 +52,7 @@ typedef struct wmEventHandler {
wmKeyMap *keymap; /* pointer to builtin/custom keymaps */
const rcti *bblocal, *bbwin; /* optional local and windowspace bb */
- /* modal operator handler */
+ /* modal operator handler and WM_HANDLER_FILESELECT */
wmOperator *op; /* for derived/modal handlers */
struct ScrArea *op_area; /* for derived/modal handlers */
struct ARegion *op_region; /* for derived/modal handlers */
@@ -68,7 +68,8 @@ typedef struct wmEventHandler {
/* drop box handler */
ListBase *dropboxes;
-
+ /* manipulator handler */
+ struct wmManipulatorMap *manipulator_map;
} wmEventHandler;
/* custom types for handlers, for signalling, freeing */
diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h
index 3085f138846..9d34bc24e6c 100644
--- a/source/blender/windowmanager/wm_event_types.h
+++ b/source/blender/windowmanager/wm_event_types.h
@@ -339,6 +339,8 @@ enum {
EVT_DROP = 0x5023,
EVT_BUT_CANCEL = 0x5024,
+ /* could become manipulator callback */
+ EVT_MANIPULATOR_UPDATE = 0x5025,
/* ********** End of Blender internal events. ********** */
};
diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h
index 396907a3f6d..4fbbe3d2879 100644
--- a/source/blender/windowmanager/wm_files.h
+++ b/source/blender/windowmanager/wm_files.h
@@ -35,13 +35,17 @@ struct wmOperatorType;
/* wm_files.c */
void wm_history_file_read(void);
-int wm_homefile_read(struct bContext *C, struct ReportList *reports, bool from_memory, const char *filepath);
+int wm_homefile_read(
+ struct bContext *C, struct ReportList *reports,
+ bool use_factory_settings, bool use_empty_data,
+ const char *filepath_startup_override, const char *app_template_override);
void wm_file_read_report(bContext *C);
void WM_OT_save_homefile(struct wmOperatorType *ot);
void WM_OT_userpref_autoexec_path_add(struct wmOperatorType *ot);
void WM_OT_userpref_autoexec_path_remove(struct wmOperatorType *ot);
void WM_OT_save_userpref(struct wmOperatorType *ot);
+void WM_OT_save_workspace_file(struct wmOperatorType *ot);
void WM_OT_read_history(struct wmOperatorType *ot);
void WM_OT_read_homefile(struct wmOperatorType *ot);
void WM_OT_read_factory_settings(struct wmOperatorType *ot);
diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h
index c106f9d7851..c8f89a5bf62 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);
@@ -42,8 +46,8 @@ 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_copy (bContext *C, wmWindow *win_src, const bool duplicate_layout);
+wmWindow *wm_window_copy_test (bContext *C, wmWindow *win_src, const bool duplicate_layout);
void wm_window_free (bContext *C, wmWindowManager *wm, wmWindow *win);
void wm_window_close (bContext *C, wmWindowManager *wm, wmWindow *win);
@@ -63,8 +67,6 @@ void wm_window_swap_buffers (wmWindow *win);
void wm_window_set_swap_interval(wmWindow *win, int interval);
bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut);
-float wm_window_pixelsize(wmWindow *win);
-
void wm_get_cursor_position (wmWindow *win, int *x, int *y);
void wm_cursor_position_from_ghost (wmWindow *win, int *x, int *y);
void wm_cursor_position_to_ghost (wmWindow *win, int *x, int *y);
@@ -78,9 +80,12 @@ 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);
+struct EnumPropertyItem *wm_window_new_screen_itemf(bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
+int wm_window_new_exec(bContext *C, struct wmOperator *op);
+int wm_window_new_invoke(bContext *C, struct wmOperator *op, const struct wmEvent *event);
+
/* Initial (unmaximized) size to start with for
* systems that can't find it for themselves (X11).
* Clamped by real desktop limits */
diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt
index 2748de0e7dd..4f0e64b0955 100644
--- a/source/blenderplayer/CMakeLists.txt
+++ b/source/blenderplayer/CMakeLists.txt
@@ -35,30 +35,19 @@ if(WIN32 AND NOT UNIX)
string(SUBSTRING ${BLENDER_VERSION} 0 1 bver1)
string(SUBSTRING ${BLENDER_VERSION} 2 1 bver2)
string(SUBSTRING ${BLENDER_VERSION} 3 1 bver3)
- if(MINGW)
- add_definitions(
- -DWINDRES
- -DBLEN_VER_RC_STR_M=${BLENDER_VERSION}
- -DBLEN_VER_RC_1=${bver1}
- -DBLEN_VER_RC_2=${bver2}
- -DBLEN_VER_RC_3=${bver3}
- -DBLEN_VER_RC_4=0
- )
- else()
- add_definitions(
- -DBLEN_VER_RC_STR=${BLENDER_VERSION}
- -DBLEN_VER_RC_1=${bver1}
- -DBLEN_VER_RC_2=${bver2}
- -DBLEN_VER_RC_3=${bver3}
- -DBLEN_VER_RC_4=0
- )
- endif()
+ add_definitions(
+ -DBLEN_VER_RC_STR=${BLENDER_VERSION}
+ -DBLEN_VER_RC_1=${bver1}
+ -DBLEN_VER_RC_2=${bver2}
+ -DBLEN_VER_RC_3=${bver3}
+ -DBLEN_VER_RC_4=0
+ )
add_executable(
blenderplayer ${EXETYPE}
bad_level_call_stubs/stubs.c
${CMAKE_SOURCE_DIR}/release/windows/icons/winblender.rc)
-
+ WINDOWS_SIGN_TARGET(blenderplayer)
install(TARGETS blenderplayer
COMPONENT Blenderplayer
DESTINATION ".")
@@ -138,6 +127,7 @@ endif()
bf_intern_moto
bf_nodes
bf_gpu
+ bf_intern_gawain
bf_imbuf
bf_avi
ge_logic_network
@@ -176,11 +166,17 @@ endif()
extern_rangetree
extern_wcwidth
bf_intern_libmv
- extern_glog
- extern_gflags
extern_sdlew
)
+ if(NOT WITH_SYSTEM_GLOG)
+ list(APPEND BLENDER_SORTED_LIBS extern_glog)
+ endif()
+
+ if(NOT WITH_SYSTEM_GFLAGS)
+ list(APPEND BLENDER_SORTED_LIBS extern_gflags)
+ endif()
+
if(WITH_MOD_CLOTH_ELTOPO)
list(APPEND BLENDER_SORTED_LIBS extern_eltopo)
endif()
diff --git a/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt b/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt
index 1d681d28589..d2c2129532a 100644
--- a/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt
+++ b/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt
@@ -35,11 +35,12 @@ set(INC
../../blender/blenloader
../../blender/makesdna
../../blender/makesrna
+ ../../../intern/glew-mx
../../../intern/guardedalloc
)
set(INC_SYS
-
+ ${GLEW_INCLUDE_PATH}
)
set(SRC
@@ -70,4 +71,8 @@ if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
+if(WITH_INPUT_NDOF)
+ add_definitions(-DWITH_INPUT_NDOF)
+endif()
+
blender_add_lib_nolist(blenkernel_blc "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c
index cdfd326d986..13f567762b5 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -43,8 +43,10 @@
struct ARegion;
struct ARegionType;
+struct bFaceMap;
struct BMEditMesh;
struct Base;
+struct BaseLegacy;
struct bContext;
struct BoundBox;
struct Brush;
@@ -113,6 +115,7 @@ struct bConstraintOb;
struct bConstraintTarget;
struct bContextDataResult;
struct bGPDlayer;
+struct bFaceMap;
struct bNode;
struct bNodeType;
struct bNodeSocket;
@@ -130,6 +133,8 @@ struct wmOperator;
struct wmOperatorType;
struct wmWindow;
struct wmWindowManager;
+struct wmManipulatorGroupType;
+struct wmManipulatorMap;
/* -------------------------------------------------------------------- */
@@ -142,7 +147,6 @@ struct wmWindowManager;
# pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
-#include "../../intern/cycles/blender/CCL_api.h"
#include "../../intern/dualcon/dualcon.h"
#include "../../intern/elbeem/extern/elbeem.h"
#include "../blender/blenkernel/BKE_modifier.h"
@@ -161,12 +165,14 @@ struct wmWindowManager;
#include "../blender/editors/include/ED_keyframes_edit.h"
#include "../blender/editors/include/ED_keyframing.h"
#include "../blender/editors/include/ED_lattice.h"
+#include "../blender/editors/include/ED_manipulator_library.h"
#include "../blender/editors/include/ED_mball.h"
#include "../blender/editors/include/ED_mesh.h"
#include "../blender/editors/include/ED_node.h"
#include "../blender/editors/include/ED_object.h"
#include "../blender/editors/include/ED_particle.h"
#include "../blender/editors/include/ED_render.h"
+#include "../blender/editors/include/ED_scene.h"
#include "../blender/editors/include/ED_screen.h"
#include "../blender/editors/include/ED_space_api.h"
#include "../blender/editors/include/ED_text.h"
@@ -179,11 +185,15 @@ struct wmWindowManager;
#include "../blender/editors/include/UI_resources.h"
#include "../blender/editors/include/UI_view2d.h"
#include "../blender/freestyle/FRS_freestyle.h"
+#include "../blender/gpu/GPU_immediate.h"
+#include "../blender/gpu/GPU_matrix.h"
#include "../blender/python/BPY_extern.h"
+#include "../blender/python/intern/bpy_manipulator_wrap.h"
#include "../blender/render/extern/include/RE_engine.h"
#include "../blender/render/extern/include/RE_pipeline.h"
#include "../blender/render/extern/include/RE_render_ext.h"
#include "../blender/render/extern/include/RE_shader_ext.h"
+#include "../blender/draw/DRW_engine.h"
#include "../blender/windowmanager/WM_api.h"
@@ -194,12 +204,17 @@ struct wmWindowManager;
/* bpy_operator_wrap.h */
extern void macro_wrapper(struct wmOperatorType *ot, void *userdata);
-extern void operator_wrapper(struct wmOperatorType *ot, void *userdata);
+extern void operator_wrapper(struct wmManipulatorGroupType *wgt, void *userdata);
+
+/* bpy_widgetgroup_wrap.h */
+extern void widgetgroup_wrapper(struct wmOperatorType *ot, void *userdata);
+
/* bpy_rna.h */
extern bool pyrna_id_FromPyObject(struct PyObject *obj, struct ID **id);
extern const char *BPY_app_translations_py_pgettext(const char *msgctxt, const char *msgid);
extern const char *BPY_app_translations_py_pgettext(const char *msgctxt, const char *msgid);
extern struct PyObject *pyrna_id_CreatePyObject(struct ID *id);
+extern bool pyrna_id_CheckPyObject(struct PyObject *obj);
/* bpy_interface.c */
bool BPY_string_is_keyword(const char *str) { return false; }
@@ -228,22 +243,23 @@ void EDBM_mesh_load(struct Object *ob) RET_NONE
void EDBM_mesh_make(struct ToolSettings *ts, struct Object *ob, const bool use_key_index) RET_NONE
void EDBM_mesh_normals_update(struct BMEditMesh *em) RET_NONE
void *g_system;
-bool EDBM_mtexpoly_check(struct BMEditMesh *em) RET_ZERO
+bool EDBM_uv_check(struct BMEditMesh *em) RET_ZERO
-float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, int passtype, const char *viewname) RET_NULL
+float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, const char *name, const char *viewname) RET_NULL
float RE_filter_value(int type, float x) RET_ZERO
struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name) RET_NULL
void RE_texture_rng_init() RET_NONE
void RE_texture_rng_exit() RET_NONE
-bool RE_layers_have_name(struct RenderResult *result) {STUB_ASSERT(0); return 0;}
+bool RE_layers_have_name(struct RenderResult *result) RET_ZERO
const char *RE_engine_active_view_get(struct RenderEngine *engine) RET_NULL
-void RE_engine_active_view_set(struct RenderEngine *engine, const char *viewname) {STUB_ASSERT(0);}
-void RE_engine_get_camera_model_matrix(struct RenderEngine *engine, struct Object *camera, int use_spherical_stereo, float *r_modelmat) {STUB_ASSERT(0);}
+void RE_engine_active_view_set(struct RenderEngine *engine, const char *viewname) RET_NONE
+void RE_engine_get_camera_model_matrix(struct RenderEngine *engine, struct Object *camera, int use_spherical_stereo, float *r_modelmat) RET_NONE
float RE_engine_get_camera_shift_x(struct RenderEngine *engine, struct Object *camera, int use_spherical_stereo) RET_ZERO
int RE_engine_get_spherical_stereo(struct RenderEngine *engine, struct Object *camera) RET_ZERO
-void RE_SetActiveRenderView(struct Render *re, const char *viewname) {STUB_ASSERT(0);}
+void RE_SetActiveRenderView(struct Render *re, const char *viewname) RET_NONE
+struct RenderPass *RE_pass_find_by_name(volatile struct RenderLayer *rl, const char *name, const char *viewname) RET_NULL
struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl, int passtype, const char *viewname) RET_NULL
bool RE_HasFakeLayer(RenderResult *res) RET_ZERO
@@ -259,7 +275,7 @@ bool ED_texture_context_check_linestyle(const struct bContext *C) RET_ZERO
void FRS_free_view_map_cache(void) RET_NONE
/* texture.c */
-int multitex_ext(struct Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, short thread, struct ImagePool *pool, bool scene_color_manage, const bool skip_load_image) RET_ZERO
+int multitex_ext(struct Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, const short thread, struct ImagePool *pool, bool scene_color_manage, const bool skip_load_image) RET_ZERO
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) RET_ZERO
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) RET_ZERO
@@ -274,6 +290,8 @@ struct Object *RE_GetCamera(struct Render *re) RET_NULL
float RE_lamp_get_data(struct ShadeInput *shi, struct Object *lamp_obj, float col[4], float lv[3], float *dist, float shadow[4]) RET_ZERO
const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int matrix_id))[4] RET_NULL
const float (*RE_render_current_get_matrix(int matrix_id))[4] RET_NULL
+float RE_object_instance_get_object_pass_index(struct ObjectInstanceRen *obi) RET_ZERO
+float RE_object_instance_get_random_id(struct ObjectInstanceRen *obi) RET_ZERO
/* blenkernel */
bool BKE_paint_proj_mesh_data_check(struct Scene *scene, struct Object *ob, bool *uvs, bool *mat, bool *tex, bool *stencil) RET_ZERO
@@ -307,6 +325,13 @@ int WM_operator_confirm(struct bContext *C, struct wmOperator *op, const struct
struct MenuType *WM_menutype_find(const char *idname, bool quiet) RET_NULL
void WM_operator_stack_clear(struct wmWindowManager *wm) RET_NONE
void WM_operator_handlers_clear(wmWindowManager *wm, struct wmOperatorType *ot) RET_NONE
+bool WM_operator_is_repeat(const struct bContext *C, const struct wmOperator *op) RET_ZERO;
+void WM_windows_scene_data_sync(const struct ListBase *win_lb, struct Scene *scene) RET_NONE
+struct Scene *WM_windows_scene_get_from_screen(const struct wmWindowManager *wm, const struct bScreen *screen) RET_NULL
+struct bScreen *WM_window_get_active_screen(const struct wmWindow *win) RET_NULL
+struct Scene *WM_window_get_active_scene(const struct wmWindow *win) RET_NULL
+void WM_window_change_active_scene(struct Main *bmain, struct bContext *C, struct wmWindow *win, struct Scene *scene_new) RET_NONE
+bool WM_window_is_temp_screen(const struct wmWindow *win) RET_ZERO
void WM_autosave_init(wmWindowManager *wm) RET_NONE
void WM_jobs_kill_all_except(struct wmWindowManager *wm, void *owner) RET_NONE
@@ -336,7 +361,41 @@ void WM_jobs_callbacks(struct wmJob *job,
void WM_jobs_start(struct wmWindowManager *wm, struct wmJob *job) RET_NONE
void WM_report(ReportType type, const char *message) RET_NONE
-void WM_ndof_deadzone_set(float deadzone) RET_NONE
+void BPY_RNA_manipulatorgroup_wrapper(struct wmManipulatorGroupType *wgt, void *userdata) RET_NONE
+void BPY_RNA_manipulator_wrapper(struct wmManipulatorType *wgt, void *userdata) RET_NONE
+
+PointerRNA *WM_manipulator_set_operator(struct wmManipulator *mpr, struct wmOperatorType *ot, struct IDProperty *properties) RET_NULL
+const struct wmManipulatorPropertyType *WM_manipulatortype_target_property_find(const struct wmManipulatorType *wt, const char *idname) RET_NULL
+const struct wmManipulatorType *WM_manipulatortype_find(const char *idname, bool quiet) RET_NULL
+struct wmManipulator *WM_manipulator_new_ptr(const struct wmManipulatorType *wt, struct wmManipulatorGroup *mgroup, const char *name, struct PointerRNA *properties) RET_NULL
+struct wmManipulatorGroupType *WM_manipulatorgrouptype_append_ptr(void (*mnpfunc)(struct wmManipulatorGroupType *, void *), void *userdata) RET_NULL
+struct wmManipulatorGroupType *WM_manipulatorgrouptype_find(const char *idname, bool quiet) RET_NULL
+void WM_manipulator_free(ListBase *manipulatorlist, struct wmManipulatorMap *mmap, struct wmManipulator *mpr, struct bContext *C) RET_NONE
+void WM_manipulator_group_add_ptr(struct wmManipulatorGroupType *wgt) RET_NONE
+void WM_manipulator_group_add_ptr_ex(struct wmManipulatorGroupType *wgt, struct wmManipulatorMapType *mmap_type) RET_NONE
+void WM_manipulator_group_remove_ptr(struct Main *bmain, struct wmManipulatorGroupType *wgt) RET_NONE
+void WM_manipulator_name_set(struct wmManipulatorGroup *mgroup, struct wmManipulator *mpr, const char *name) RET_NONE
+void WM_manipulator_target_property_def_rna_ptr(struct wmManipulator *mpr, const struct wmManipulatorPropertyType *mpr_prop_type, struct PointerRNA *ptr, struct PropertyRNA *prop, int index) RET_NONE
+void WM_manipulatorgrouptype_remove_ptr(struct wmManipulatorGroupType *wt) RET_NONE
+void WM_manipulatormaptype_group_unlink(struct bContext *C, struct Main *bmain, struct wmManipulatorMapType *mmap_type, const struct wmManipulatorGroupType *wgt) RET_NONE
+void WM_manipulatortype_append_ptr(void (*mnpfunc)(struct wmManipulatorType *, void *), void *userdata) RET_NONE
+void WM_manipulatortype_remove_ptr(struct wmManipulatorType *wt) RET_NONE
+
+void ED_manipulator_draw_preset_box(const struct wmManipulator *mpr, float mat[4][4], int select_id) RET_NONE
+void ED_manipulator_draw_preset_arrow(const struct wmManipulator *mpr, float mat[4][4], int axis, int select_id) RET_NONE
+void ED_manipulator_draw_preset_circle(const struct wmManipulator *mpr, float mat[4][4], int axis, int select_id) RET_NONE
+void ED_manipulator_draw_preset_facemap(const struct wmManipulator *mpr, struct Scene *scene, struct Object *ob, const int facemap, int select_id) RET_NONE
+
+struct wmManipulatorMapType *WM_manipulatormaptype_find(const struct wmManipulatorMapType_Params *wmap_params) RET_NULL
+struct wmManipulatorMapType *WM_manipulatormaptype_ensure(const struct wmManipulatorMapType_Params *wmap_params) RET_NULL
+struct wmManipulatorMap *WM_manipulatormap_new_from_type(const struct wmManipulatorMapType_Params *wmap_params) RET_NULL
+void WM_manipulatormaptype_group_init_runtime(
+ const struct Main *bmain, struct wmManipulatorMapType *mmap_type, struct wmManipulatorGroupType *wgt) RET_NONE
+const struct ListBase *WM_manipulatormap_group_list(struct wmManipulatorMap *mmap) RET_NULL
+
+#ifdef WITH_INPUT_NDOF
+ void WM_ndof_deadzone_set(float deadzone) RET_NONE
+#endif
void WM_uilisttype_init(void) RET_NONE
struct uiListType *WM_uilisttype_find(const char *idname, bool quiet) RET_NULL
@@ -359,8 +418,10 @@ void ED_armature_edit_bone_remove(struct bArmature *arm, struct EditBone *exBone
void object_test_constraints(struct Object *owner) RET_NONE
void ED_armature_ebone_to_mat4(struct EditBone *ebone, float mat[4][4]) RET_NONE
void ED_armature_ebone_from_mat4(EditBone *ebone, float mat[4][4]) RET_NONE
-void ED_object_parent(struct Object *ob, struct Object *par, int type, const char *substr) RET_NONE
+void ED_object_parent(struct Object *ob, struct Object *par, const int type, const char *substr) RET_NONE
void ED_object_constraint_set_active(struct Object *ob, struct bConstraint *con) RET_NONE
+void ED_object_facemap_face_add(struct Object *ob, struct bFaceMap *fmap, int facenum) RET_NONE
+void ED_object_facemap_face_remove(struct Object *ob, struct bFaceMap *fmap, int facenum) RET_NONE
void ED_node_composit_default(const struct bContext *C, struct Scene *scene) RET_NONE
void *ED_region_draw_cb_activate(struct ARegionType *art, void(*draw)(const struct bContext *, struct ARegion *, void *), void *custumdata, int type) RET_ZERO /* XXX this one looks weird */
void *ED_region_draw_cb_customdata(void *handle) RET_ZERO /* XXX This one looks wrong also */
@@ -387,7 +448,6 @@ void ED_space_image_scopes_update(const struct bContext *C, struct SpaceImage *s
void ED_uvedit_get_aspect(struct Scene *scene, struct Object *ob, struct BMesh *em, float *aspx, float *aspy) RET_NONE
-void ED_screen_set_scene(struct bContext *C, struct bScreen *screen, struct Scene *scene) RET_NONE
struct MovieClip *ED_space_clip_get_clip(struct SpaceClip *sc) RET_NULL
void ED_space_clip_set_clip(struct bContext *C, struct bScreen *screen, struct SpaceClip *sc, struct MovieClip *clip) RET_NONE
void ED_space_clip_set_mask(struct bContext *C, struct SpaceClip *sc, struct Mask *mask) RET_NONE
@@ -408,7 +468,7 @@ void ED_fsmenu_entry_set_path(struct FSMenuEntry *fsentry, const char *name) RET
char *ED_fsmenu_entry_get_name(struct FSMenuEntry *fsentry) RET_NULL
void ED_fsmenu_entry_set_name(struct FSMenuEntry *fsentry, const char *name) RET_NONE
-struct PTCacheEdit *PE_get_current(struct Scene *scene, struct Object *ob) RET_NULL
+struct PTCacheEdit *PE_get_current(struct Scene *scene, struct SceneLayer *sl, struct Object *ob) RET_NULL
void PE_current_changed(struct Scene *scene, struct Object *ob) RET_NONE
/* rna keymap */
@@ -448,7 +508,7 @@ bool ANIM_remove_driver(struct ReportList *reports, struct ID *id, const char rn
void ED_space_image_release_buffer(struct SpaceImage *sima, struct ImBuf *ibuf, void *lock) RET_NONE
struct ImBuf *ED_space_image_acquire_buffer(struct SpaceImage *sima, void **r_lock) RET_NULL
void ED_space_image_get_zoom(struct SpaceImage *sima, struct ARegion *ar, float *zoomx, float *zoomy) RET_NONE
-const char *ED_info_stats_string(struct Scene *scene) RET_NULL
+const char *ED_info_stats_string(struct Scene *scene, struct SceneLayer *sl) RET_NULL
void ED_area_tag_redraw(struct ScrArea *sa) RET_NONE
void ED_area_tag_refresh(struct ScrArea *sa) RET_NONE
void ED_area_newspace(struct bContext *C, struct ScrArea *sa, int type, const bool skip_ar_exit) RET_NONE
@@ -459,30 +519,33 @@ void ED_node_texture_default(const struct bContext *C, struct Tex *tex) RET_NONE
void ED_node_tag_update_id(struct ID *id) RET_NONE
void ED_node_tag_update_nodetree(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node) RET_NONE
void ED_node_tree_update(const struct bContext *C) RET_NONE
-void ED_node_set_tree_type(struct SpaceNode *snode, struct bNodeTreeType *typeinfo){}
-void ED_init_custom_node_type(struct bNodeType *ntype){}
-void ED_init_custom_node_socket_type(struct bNodeSocketType *stype){}
+void ED_node_set_tree_type(struct SpaceNode *snode, struct bNodeTreeType *typeinfo) RET_NONE
+void ED_init_custom_node_type(struct bNodeType *ntype) RET_NONE
+void ED_init_custom_node_socket_type(struct bNodeSocketType *stype) RET_NONE
void ED_init_standard_node_socket_type(struct bNodeSocketType *stype) RET_NONE
void ED_init_node_socket_type_virtual(struct bNodeSocketType *stype) RET_NONE
-int ED_node_tree_path_length(struct SpaceNode *snode){return 0;}
-void ED_node_tree_path_get(struct SpaceNode *snode, char *value){}
-void ED_node_tree_path_get_fixedbuf(struct SpaceNode *snode, char *value, int max_length){}
-void ED_node_tree_start(struct SpaceNode *snode, struct bNodeTree *ntree, struct ID *id, struct ID *from){}
-void ED_node_tree_push(struct SpaceNode *snode, struct bNodeTree *ntree, struct bNode *gnode){}
-void ED_node_tree_pop(struct SpaceNode *snode){}
+int ED_node_tree_path_length(struct SpaceNode *snode) RET_ZERO
+void ED_node_tree_path_get(struct SpaceNode *snode, char *value) RET_NONE
+void ED_node_tree_path_get_fixedbuf(struct SpaceNode *snode, char *value, int max_length) RET_NONE
+void ED_node_tree_start(struct SpaceNode *snode, struct bNodeTree *ntree, struct ID *id, struct ID *from) RET_NONE
+void ED_node_tree_push(struct SpaceNode *snode, struct bNodeTree *ntree, struct bNode *gnode) RET_NONE
+void ED_node_tree_pop(struct SpaceNode *snode) RET_NONE
int ED_view3d_scene_layer_set(int lay, const int *values, int *active) RET_ZERO
void ED_view3d_quadview_update(struct ScrArea *sa, struct ARegion *ar, bool do_clip) RET_NONE
void ED_view3d_from_m4(float mat[4][4], float ofs[3], float quat[4], float *dist) RET_NONE
struct BGpic *ED_view3D_background_image_new(struct View3D *v3d) RET_NULL
void ED_view3D_background_image_remove(struct View3D *v3d, struct BGpic *bgpic) RET_NONE
void ED_view3D_background_image_clear(struct View3D *v3d) RET_NONE
-void ED_view3d_update_viewmat(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, float viewmat[4][4], float winmat[4][4]) RET_NONE
+void ED_view3d_update_viewmat(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, float viewmat[4][4], float winmat[4][4], const struct rcti *rect) RET_NONE
float ED_view3d_grid_scale(struct Scene *scene, struct View3D *v3d, const char **grid_unit) RET_ZERO
void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View3D *v3d, struct ScrArea *sa) RET_NONE
void ED_node_shader_default(const struct bContext *C, struct ID *id) RET_NONE
void ED_screen_animation_timer_update(struct bScreen *screen, int redraws, int refresh) RET_NONE
struct bScreen *ED_screen_animation_playing(const struct wmWindowManager *wm) RET_NULL
-void ED_base_object_select(struct Base *base, short mode) RET_NONE
+struct Scene *ED_screen_scene_find(const struct bScreen *screen, const struct wmWindowManager *wm) RET_NULL
+bool ED_scene_render_layer_delete(struct Main *bmain, Scene *scene, SceneLayer *layer, ReportList *reports) RET_ZERO
+void ED_base_object_select(struct BaseLegacy *base, short mode) RET_NONE
+void ED_object_base_select(struct Base *base, short mode) RET_NONE
bool ED_object_modifier_remove(struct ReportList *reports, struct Main *bmain, struct Object *ob, struct ModifierData *md) RET_ZERO
struct ModifierData *ED_object_modifier_add(struct ReportList *reports, struct Main *bmain, struct Scene *scene, struct Object *ob, const char *name, int type) RET_ZERO
void ED_object_modifier_clear(struct Main *bmain, struct Object *ob) RET_NONE
@@ -503,7 +566,7 @@ void uiLayoutSetAlignment(uiLayout *layout, char alignment) RET_NONE
void uiLayoutSetScaleX(struct uiLayout *layout, float scale) RET_NONE
void uiLayoutSetScaleY(struct uiLayout *layout, float scale) RET_NONE
void uiTemplateIconView(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname, int show_labels, float icon_scale) RET_NONE
-void ED_base_object_free_and_unlink(struct Main *bmain, struct Scene *scene, struct Base *base) RET_NONE
+void ED_base_object_free_and_unlink(struct Main *bmain, struct Scene *scene, struct Object *base) RET_NONE
void ED_mesh_update(struct Mesh *mesh, struct bContext *C, int calc_edges, int calc_tessface) RET_NONE
void ED_mesh_vertices_add(struct Mesh *mesh, struct ReportList *reports, int count) RET_NONE
void ED_mesh_edges_add(struct Mesh *mesh, struct ReportList *reports, int count) RET_NONE
@@ -529,7 +592,7 @@ int ED_mesh_mirror_spatial_table(struct Object *ob, struct BMEditMesh *em, struc
float ED_rollBoneToVector(EditBone *bone, const float new_up_axis[3], const bool axis_only) RET_ZERO
void ED_space_image_get_size(struct SpaceImage *sima, int *width, int *height) RET_NONE
-bool ED_space_image_check_show_maskedit(struct Scene *scene, struct SpaceImage *sima) RET_ZERO
+bool ED_space_image_check_show_maskedit(struct SceneLayer *sl, struct SpaceImage *sima) RET_ZERO
bool ED_texture_context_check_world(const struct bContext *C) RET_ZERO
bool ED_texture_context_check_material(const struct bContext *C) RET_ZERO
@@ -540,19 +603,19 @@ bool ED_texture_context_check_others(const struct bContext *C) RET_ZERO
bool ED_text_region_location_from_cursor(SpaceText *st, ARegion *ar, const int cursor_co[2], int r_pixel_co[2]) RET_ZERO
SnapObjectContext *ED_transform_snap_object_context_create(
- struct Main *bmain, struct Scene *scene, int flag) RET_NULL
+ struct Main *bmain, struct Scene *scene, struct SceneLayer *sl, int flag) RET_NULL
SnapObjectContext *ED_transform_snap_object_context_create_view3d(
- struct Main *bmain, struct Scene *scene, int flag,
+ struct Main *bmain, struct Scene *scene, struct SceneLayer *sl, int flag,
const struct ARegion *ar, const struct View3D *v3d) RET_NULL
void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx) RET_NONE
bool ED_transform_snap_object_project_ray_ex(
struct SnapObjectContext *sctx,
- const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3], float *ray_depth,
/* return args */
float r_loc[3], float r_no[3], int *r_index,
struct Object **r_ob, float r_obmat[4][4]) RET_ZERO
+void BIF_selectTransformOrientationValue(struct View3D *v3d, int orientation) RET_NONE
void ED_lattice_editlatt_make(struct Object *obedit) RET_NONE
void ED_lattice_editlatt_load(struct Object *obedit) RET_NONE
@@ -593,6 +656,14 @@ const char *uiLayoutIntrospect(uiLayout *layout) RET_NULL
void UI_reinit_font(void) RET_NONE
int UI_rnaptr_icon_get(struct bContext *C, struct PointerRNA *ptr, int rnaicon, const bool big) RET_ZERO
struct bTheme *UI_GetTheme(void) RET_NULL
+void UI_GetThemeColor3fv(int colorid, float col[4]) RET_NONE
+void UI_GetThemeColor4fv(int colorid, float col[4]) RET_NONE
+void UI_GetThemeColorShade4fv(int colorid, int offset, float col[4]) RET_NONE
+void UI_GetThemeColorShadeAlpha4fv(int colorid, int coloffset, int alphaoffset, float col[4]) RET_NONE
+void UI_GetThemeColorBlendShade3fv(int colorid1, int colorid2, float fac, int offset, float col[3]) RET_NONE
+void UI_GetThemeColorBlendShade4fv(int colorid1, int colorid2, float fac, int offset, float col[4]) RET_NONE
+void UI_GetThemeColorBlend3ubv(int colorid1, int colorid2, float fac, unsigned char col[3]) RET_NONE
+void UI_GetThemeColorShadeAlpha4ubv(int colorid, int coloffset, int alphaoffset, unsigned char col[4]) RET_NONE
/* rna template */
void uiTemplateAnyID(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *proptypename, const char *text) RET_NONE
@@ -604,6 +675,17 @@ struct uiLayout *uiTemplateConstraint(struct uiLayout *layout, struct PointerRNA
void uiTemplatePreview(struct uiLayout *layout, struct bContext *C, struct ID *id, int show_buttons, struct ID *parent,
struct MTex *slot, const char *preview_id) RET_NONE
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) RET_NONE
+void uiTemplateSearch(
+ uiLayout *layout, struct bContext *C,
+ PointerRNA *ptr, const char *propname,
+ PointerRNA *searchptr, const char *searchpropname,
+ const char *newop, const char *unlinkop) RET_NONE
+void uiTemplateSearchPreview(
+ uiLayout *layout, struct bContext *C,
+ PointerRNA *ptr, const char *propname,
+ PointerRNA *searchptr, const char *searchpropname,
+ const char *newop, const char *unlinkop,
+ const int rows, const int cols) RET_NONE
void uiTemplateCurveMapping(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int type, int levels, int brush, int neg_slope) RET_NONE
void uiTemplateColorRamp(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int expand) RET_NONE
void uiTemplateLayers(uiLayout *layout, struct PointerRNA *ptr, const char *propname, PointerRNA *used_ptr, const char *used_propname, int active_layer) RET_NONE
@@ -626,6 +708,7 @@ void uiTemplateNodeView(struct uiLayout *layout, struct bContext *C, struct bNod
void uiTemplateTextureUser(struct uiLayout *layout, struct bContext *C) RET_NONE
void uiTemplateTextureShow(struct uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop) RET_NONE
void uiTemplateKeymapItemProperties(struct uiLayout *layout, struct PointerRNA *ptr) RET_NONE
+void uiTemplateOverrideProperty(struct uiLayout *layout, struct PointerRNA *collection_props_ptr, struct PointerRNA *scene_props_ptr, const char *propname, const char *name, const char *text_ctxt, int translate, int icon, const char *custom_template) RET_NONE
void uiTemplateMovieClip(struct uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, int compact) RET_NONE
void uiTemplateMovieclipInformation(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *userptr) RET_NONE
void uiTemplateTrack(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname) RET_NONE
@@ -648,7 +731,8 @@ struct RenderData *RE_engine_get_render_data(struct Render *re) RET_NULL
void RE_engine_update_result(struct RenderEngine *engine, struct RenderResult *result) RET_NONE
void RE_engine_update_progress(struct RenderEngine *engine, float progress) RET_NONE
void RE_engine_set_error_message(RenderEngine *engine, const char *msg) RET_NONE
-void RE_engine_end_result(RenderEngine *engine, struct RenderResult *result, int cancel, int merge_results) RET_NONE
+void RE_engine_add_pass(RenderEngine *engine, const char *name, int channels, const char *chan_id, const char *layername) RET_NONE
+void RE_engine_end_result(RenderEngine *engine, struct RenderResult *result, int cancel, int highlight, int merge_results) RET_NONE
void RE_engine_update_stats(RenderEngine *engine, const char *stats, const char *info) RET_NONE
void RE_layer_load_from_file(struct RenderLayer *layer, struct ReportList *reports, const char *filename, int x, int y) RET_NONE
void RE_result_load_from_file(struct RenderResult *result, struct ReportList *reports, const char *filename) RET_NONE
@@ -658,6 +742,7 @@ void RE_ReleaseResultImage(struct Render *re) RET_NONE
int RE_engine_test_break(struct RenderEngine *engine) RET_ZERO
void RE_engines_init() RET_NONE
void RE_engines_exit() RET_NONE
+void RE_engines_register(struct Main *bmain, RenderEngineType *render_type) RET_NONE
void RE_engine_report(struct RenderEngine *engine, int type, const char *msg) RET_NONE
ListBase R_engines = {NULL, NULL};
void RE_engine_free(struct RenderEngine *engine) RET_NONE
@@ -667,11 +752,20 @@ struct RenderEngine *RE_engine_create(struct RenderEngineType *type) RET_NULL
void RE_engine_frame_set(struct RenderEngine *engine, int frame, float subframe) RET_NONE
void RE_FreePersistentData(void) RET_NONE
void RE_point_density_cache(struct Scene *scene, struct PointDensity *pd, const bool use_render_params) RET_NONE
-void RE_point_density_minmax(struct Scene *scene, struct PointDensity *pd, const bool use_render_params, float r_min[3], float r_max[3]) RET_NONE;
-void RE_point_density_sample(struct Scene *scene, struct PointDensity *pd, int resolution, const bool use_render_params, float *values) RET_NONE;
-void RE_point_density_free(struct PointDensity *pd) RET_NONE;
+void RE_point_density_minmax(struct Scene *scene, struct PointDensity *pd, const bool use_render_params, float r_min[3], float r_max[3]) RET_NONE
+void RE_point_density_sample(struct Scene *scene, struct PointDensity *pd, const int resolution, const bool use_render_params, float *values) RET_NONE
+void RE_point_density_free(struct PointDensity *pd) RET_NONE
void RE_instance_get_particle_info(struct ObjectInstanceRen *obi, float *index, float *age, float *lifetime, float co[3], float *size, float vel[3], float angvel[3]) RET_NONE
void RE_FreeAllPersistentData(void) RET_NONE
+float RE_fresnel_dielectric(float incoming[3], float normal[3], float eta) RET_ZERO
+void RE_engine_register_pass(struct RenderEngine *engine, struct Scene *scene, struct SceneRenderLayer *srl, const char *name, int channels, const char *chanid, int type) RET_NONE
+
+/* Draw */
+void OBJECT_collection_settings_create(struct IDProperty *properties) RET_NONE
+void EDIT_MESH_collection_settings_create(struct IDProperty *properties) RET_NONE
+void EDIT_ARMATURE_collection_settings_create(struct IDProperty *properties) RET_NONE
+void PAINT_WEIGHT_collection_settings_create(struct IDProperty *properties) RET_NONE
+void PAINT_VERTEX_collection_settings_create(struct IDProperty *properties) RET_NONE
/* python */
struct wmOperatorType *WM_operatortype_find(const char *idname, bool quiet) RET_NULL
@@ -714,6 +808,7 @@ int UI_pie_menu_invoke_from_operator_enum(struct bContext *C, const char *title,
/* RNA COLLADA dependency */
int collada_export(struct Scene *sce,
+ struct SceneLayer *scene_layer,
const char *filepath,
int apply_modifiers,
BC_export_mesh_type export_mesh_type,
@@ -725,7 +820,6 @@ int collada_export(struct Scene *sce,
int deform_bones_only,
int active_uv_only,
- int include_uv_textures,
int include_material_textures,
int use_texture_copies,
@@ -734,12 +828,17 @@ int collada_export(struct Scene *sce,
int use_blender_profile,
int sort_by_name,
BC_export_transformation_type export_transformation_type,
- int open_sim) RET_ZERO
+ int open_sim,
+ int limit_precision,
+ int keep_bind_info) RET_ZERO
void ED_mesh_calc_tessface(struct Mesh *mesh, bool free_mpoly) RET_NONE
/* bpy/python internal api */
-void operator_wrapper(struct wmOperatorType *ot, void *userdata) RET_NONE
+extern void BPY_RNA_operator_wrapper(struct wmOperatorType *ot, void *userdata);
+extern void BPY_RNA_operator_macro_wrapper(struct wmOperatorType *ot, void *userdata);
+void BPY_RNA_operator_wrapper(struct wmOperatorType *ot, void *userdata) RET_NONE
+void BPY_RNA_operator_macro_wrapper(struct wmOperatorType *ot, void *userdata) RET_NONE
void BPY_text_free_code(struct Text *text) RET_NONE
void BPY_id_release(struct ID *id) RET_NONE
int BPY_context_member_get(struct bContext *C, const char *member, struct bContextDataResult *result) RET_ZERO
@@ -747,10 +846,10 @@ void BPY_pyconstraint_target(struct bPythonConstraint *con, struct bConstraintTa
float BPY_driver_exec(PathResolvedRNA *anim_rna, struct ChannelDriver *driver, const float evaltime) RET_ZERO /* might need this one! */
void BPY_DECREF(void *pyob_ptr) RET_NONE
void BPY_pyconstraint_exec(struct bPythonConstraint *con, struct bConstraintOb *cob, struct ListBase *targets) RET_NONE
-void macro_wrapper(struct wmOperatorType *ot, void *userdata) RET_NONE
bool pyrna_id_FromPyObject(struct PyObject *obj, struct ID **id) RET_ZERO
struct PyObject *pyrna_id_CreatePyObject(struct ID *id) RET_NULL
-void BPY_context_update(struct bContext *C) RET_NONE;
+bool pyrna_id_CheckPyObject(struct PyObject *obj) RET_ZERO
+void BPY_context_update(struct bContext *C) RET_NONE
const char *BPY_app_translations_py_pgettext(const char *msgctxt, const char *msgid) RET_ARG(msgid)
/* intern/dualcon */
@@ -768,10 +867,6 @@ void *dualcon(const DualConInput *input_mesh,
float scale,
int depth) RET_ZERO
-/* intern/cycles */
-struct CCLDeviceInfo;
-struct CCLDeviceInfo *CCL_compute_device_list(int opencl) RET_NULL
-
/* compositor */
void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rendering,
const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings,
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index 7acea43d1f5..11e22fffa4d 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -113,24 +113,13 @@ if(WIN32 AND NOT UNIX)
string(SUBSTRING ${BLENDER_VERSION} 0 1 bver1)
string(SUBSTRING ${BLENDER_VERSION} 2 1 bver2)
string(SUBSTRING ${BLENDER_VERSION} 3 1 bver3)
- if(MINGW)
- add_definitions(
- -DWINDRES
- -DBLEN_VER_RC_STR_M=${BLENDER_VERSION}
- -DBLEN_VER_RC_1=${bver1}
- -DBLEN_VER_RC_2=${bver2}
- -DBLEN_VER_RC_3=${bver3}
- -DBLEN_VER_RC_4=0
- )
- else()
- add_definitions(
- -DBLEN_VER_RC_STR=${BLENDER_VERSION}
- -DBLEN_VER_RC_1=${bver1}
- -DBLEN_VER_RC_2=${bver2}
- -DBLEN_VER_RC_3=${bver3}
- -DBLEN_VER_RC_4=0
- )
- endif()
+ add_definitions(
+ -DBLEN_VER_RC_STR=${BLENDER_VERSION}
+ -DBLEN_VER_RC_1=${bver1}
+ -DBLEN_VER_RC_2=${bver2}
+ -DBLEN_VER_RC_3=${bver3}
+ -DBLEN_VER_RC_4=0
+ )
list(APPEND SRC
@@ -263,6 +252,7 @@ if(WITH_PYTHON_MODULE)
else()
add_executable(blender ${EXETYPE} ${SRC})
+ WINDOWS_SIGN_TARGET(blender)
endif()
if(WITH_BUILDINFO)
@@ -337,7 +327,8 @@ if(WITH_PYTHON)
# install(CODE "message(\"copying blender scripts...\")")
# exclude addons_contrib if release
- if("${BLENDER_VERSION_CYCLE}" STREQUAL "release")
+ if("${BLENDER_VERSION_CYCLE}" STREQUAL "release" OR
+ "${BLENDER_VERSION_CYCLE}" STREQUAL "rc")
set(ADDON_EXCLUDE_CONDITIONAL "addons_contrib/*")
else()
set(ADDON_EXCLUDE_CONDITIONAL "_addons_contrib/*") # dummy, wont do anything
@@ -421,6 +412,12 @@ if(WITH_OPENCOLORIO)
)
endif()
+# Add default workspaces.blend to build (under [version]/datafiles
+install(
+ FILES ${CMAKE_SOURCE_DIR}/release/datafiles/workspaces.blend
+ DESTINATION ${TARGETDIR_VER}/datafiles
+)
+
# helpful tip when using make
if("${CMAKE_GENERATOR}" MATCHES ".*Makefiles.*")
# message after building.
@@ -650,7 +647,6 @@ elseif(WIN32)
if(WITH_PYTHON)
string(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION})
- # MinGW TODO: This bit of Python configuration diverges from MSVC
if(NOT CMAKE_COMPILER_IS_GNUCC)
install(
FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}.dll
@@ -711,10 +707,7 @@ elseif(WIN32)
)
if(WITH_PYTHON_INSTALL_NUMPY)
- set(PYTHON_NUMPY_VERSION 1.9)
- if(MSVC_VERSION EQUAL 1900)
- set(PYTHON_NUMPY_VERSION 1.11)
- endif()
+ set(PYTHON_NUMPY_VERSION 1.10)
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages
COMMAND ${CMAKE_COMMAND} -E
make_directory ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages)
@@ -722,9 +715,9 @@ elseif(WIN32)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages/numpy
COMMAND ${CMAKE_COMMAND} -E
- tar xzvf "${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_numpy_${PYTHON_NUMPY_VERSION}.tar.gz"
+ tar xzvf "${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_numpy_${PYTHON_NUMPY_VERSION}$<$<CONFIG:Debug>:d>.tar.gz"
DEPENDS
- ${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_numpy_${PYTHON_NUMPY_VERSION}.tar.gz
+ ${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_numpy_${PYTHON_NUMPY_VERSION}$<$<CONFIG:Debug>:d>.tar.gz
${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages
)
@@ -750,20 +743,6 @@ elseif(WIN32)
DESTINATION ${BLENDER_VERSION}/python/bin
CONFIGURATIONS Debug
)
-
- # MinGW needs Python DLL
- if(MINGW)
- install(
- FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}.dll
- DESTINATION "."
- CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel
- )
- install(
- FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}_d.dll
- DESTINATION "."
- CONFIGURATIONS Debug
- )
- endif()
endif()
unset(_PYTHON_VERSION_NO_DOTS)
@@ -786,56 +765,19 @@ elseif(WIN32)
FILES ${LIBDIR}/pthreads/lib/pthreadVC2.dll
DESTINATION "."
)
- else()
- #MinGW64 comes with own version. For portable builds it will probaly have to be copied to work
- if(NOT WITH_MINGW64)
- install(
- FILES ${LIBDIR}/pthreads/lib/pthreadGC2.dll
- DESTINATION "."
- )
- elseif(WITH_MINGW64)
- install(
- FILES
- ${LIBDIR}/binaries/libgcc_s_sjlj-1.dll
- ${LIBDIR}/binaries/libwinpthread-1.dll
- ${LIBDIR}/binaries/libstdc++-6.dll
- DESTINATION "."
- )
-
- if(WITH_OPENMP)
- install(
- FILES
- ${LIBDIR}/binaries/libgomp-1.dll
- DESTINATION "."
- )
- endif()
- endif()
endif()
if(WITH_CODEC_FFMPEG)
- if(WITH_MINGW64)
- install(
- FILES
- ${LIBDIR}/ffmpeg/lib/avcodec-53.dll
- ${LIBDIR}/ffmpeg/lib/avformat-53.dll
- ${LIBDIR}/ffmpeg/lib/avdevice-53.dll
- ${LIBDIR}/ffmpeg/lib/avutil-51.dll
- ${LIBDIR}/ffmpeg/lib/swscale-2.dll
- ${LIBDIR}/ffmpeg/lib/swresample-0.dll
- ${LIBDIR}/ffmpeg/lib/xvidcore.dll
- DESTINATION "."
- )
- else()
- install(
- FILES
- ${LIBDIR}/ffmpeg/lib/avcodec-55.dll
- ${LIBDIR}/ffmpeg/lib/avformat-55.dll
- ${LIBDIR}/ffmpeg/lib/avdevice-55.dll
- ${LIBDIR}/ffmpeg/lib/avutil-52.dll
- ${LIBDIR}/ffmpeg/lib/swscale-2.dll
- DESTINATION "."
- )
- endif()
+ install(
+ FILES
+ ${LIBDIR}/ffmpeg/lib/avcodec-57.dll
+ ${LIBDIR}/ffmpeg/lib/avformat-57.dll
+ ${LIBDIR}/ffmpeg/lib/avdevice-57.dll
+ ${LIBDIR}/ffmpeg/lib/avutil-55.dll
+ ${LIBDIR}/ffmpeg/lib/swscale-4.dll
+ ${LIBDIR}/ffmpeg/lib/swresample-2.dll
+ DESTINATION "."
+ )
endif()
if(WITH_CODEC_SNDFILE)
@@ -851,30 +793,13 @@ elseif(WIN32)
${LIBDIR}/openal/lib/OpenAL32.dll
DESTINATION "."
)
- # MinGW TODO: Need to update to a newer OpenAL version
- # which does not depend on wrap_oal.dll
- if(CMAKE_COMPILER_IS_GNUCC)
- install(
- FILES
- ${LIBDIR}/openal/lib/wrap_oal.dll
- DESTINATION "."
- )
- endif()
endif()
if(WITH_SDL)
- #MinGW TODO: Update to SDL2
- if(NOT CMAKE_COMPILER_IS_GNUCC)
- install(
- FILES ${LIBDIR}/sdl/lib/SDL2.dll
- DESTINATION "."
- )
- else()
- install(
- FILES ${LIBDIR}/sdl/lib/SDL.dll
- DESTINATION "."
- )
- endif()
+ install(
+ FILES ${LIBDIR}/sdl/lib/SDL2.dll
+ DESTINATION "."
+ )
endif()
if(WITH_SYSTEM_AUDASPACE)
@@ -901,19 +826,11 @@ elseif(WIN32)
if(WITH_OPENCOLORIO)
set(OCIOBIN ${LIBDIR}/opencolorio/bin)
- if(NOT MINGW)
install(
FILES
${OCIOBIN}/OpenColorIO.dll
DESTINATION "."
)
- else()
- install(
- FILES
- ${OCIOBIN}/libOpenColorIO.dll
- DESTINATION "."
- )
- endif()
endif()
elseif(APPLE)
@@ -997,21 +914,26 @@ elseif(APPLE)
# python
if(WITH_PYTHON AND NOT WITH_PYTHON_MODULE AND NOT WITH_PYTHON_FRAMEWORK)
- # the python zip is first extract as part of the build process,
+ # the python zip is first extracted as part of the build process,
# and then later installed as part of make install. this is much
# quicker, and means we can easily exclude files on copy
- # Not needed for PYTHON_MODULE or WEB_PLUGIN due uses Pyhon framework
+ # Not needed for PYTHON_MODULE or WEB_PLUGIN due uses Pyhon framework
+ # use a hash of the .zip path to handle switching between different
+ # lib directories without needing a clean build
+ string(SHA1 PYTHON_ZIP_HASH ${LIBDIR}/release/${PYTHON_ZIP})
+ set(PYTHON_EXTRACT_DIR ${CMAKE_CURRENT_BINARY_DIR}/${PYTHON_ZIP_HASH}/python)
+
add_custom_target(
extractpyzip
- DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/python)
+ DEPENDS ${PYTHON_EXTRACT_DIR})
set(PYTHON_ZIP "python_${CMAKE_OSX_ARCHITECTURES}.zip")
add_custom_command(
- OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/python
- COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/python/"
- COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/python/"
- COMMAND ${CMAKE_COMMAND} -E chdir "${CMAKE_CURRENT_BINARY_DIR}/python/"
+ OUTPUT ${PYTHON_EXTRACT_DIR}
+ COMMAND ${CMAKE_COMMAND} -E remove_directory "${PYTHON_EXTRACT_DIR}/"
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${PYTHON_EXTRACT_DIR}/"
+ COMMAND ${CMAKE_COMMAND} -E chdir "${PYTHON_EXTRACT_DIR}/"
${CMAKE_COMMAND} -E tar xzfv "${LIBDIR}/release/${PYTHON_ZIP}"
DEPENDS ${LIBDIR}/release/${PYTHON_ZIP})
@@ -1019,13 +941,13 @@ elseif(APPLE)
# copy extracted python files
install_dir(
- ${CMAKE_CURRENT_BINARY_DIR}/python
+ ${PYTHON_EXTRACT_DIR}
\${TARGETDIR_VER}
)
# copy site-packages files
install_dir(
${LIBDIR}/release/site-packages
- ${CMAKE_CURRENT_BINARY_DIR}/python/lib/python${PYTHON_VERSION}
+ \${TARGETDIR_VER}/python/lib/python${PYTHON_VERSION}
)
install(DIRECTORY ${LIBDIR}/python/bin
@@ -1082,16 +1004,16 @@ elseif(APPLE)
# python
if(WITH_PYTHON AND NOT WITH_PYTHON_FRAMEWORK)
add_custom_command(
- OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/python
- COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/python/"
- COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/python/"
- COMMAND ${CMAKE_COMMAND} -E chdir "${CMAKE_CURRENT_BINARY_DIR}/python/"
+ OUTPUT ${PYTHON_EXTRACT_DIR}
+ COMMAND ${CMAKE_COMMAND} -E remove_directory "${PYTHON_EXTRACT_DIR}/"
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${PYTHON_EXTRACT_DIR}/"
+ COMMAND ${CMAKE_COMMAND} -E chdir "${PYTHON_EXTRACT_DIR}/"
${CMAKE_COMMAND} -E tar xzfv "${LIBDIR}/release/${PYTHON_ZIP}"
DEPENDS ${LIBDIR}/release/${PYTHON_ZIP})
# copy extracted python files
install_dir(
- ${CMAKE_CURRENT_BINARY_DIR}/python
+ ${PYTHON_EXTRACT_DIR}
\${PLAYER_TARGETDIR_VER}
)
endif()
@@ -1151,13 +1073,12 @@ if(WIN32 AND NOT WITH_PYTHON_MODULE)
COMPONENT Blender
DESTINATION "."
)
-
+ if(CMAKE_CL_64)
+ set(_WIN_PLATFORM x64)
+ else()
+ set(_WIN_PLATFORM x86)
+ endif()
if(MSVC12_REDIST_DIR)
- if(CMAKE_CL_64)
- set(_WIN_PLATFORM x64)
- else()
- set(_WIN_PLATFORM x86)
- endif()
install(
FILES
${MSVC12_REDIST_DIR}/${_WIN_PLATFORM}/Microsoft.VC120.CRT/msvcp120.dll
@@ -1171,4 +1092,51 @@ if(WIN32 AND NOT WITH_PYTHON_MODULE)
)
endif()
endif()
+
+ if(MSVC14_REDIST_DIR)
+ set(KITSDIRx86 "$ENV{${ProgramFilesX86_NAME}}/Windows Kits/10/")
+ set(KITSDIR "$ENV{ProgramFiles}/Windows Kits/10/")
+ if(IS_DIRECTORY ${KITSDIR})
+ set(KITSPATH "${KITSDIR}/Redist/ucrt/DLLs/${_WIN_PLATFORM}")
+ else()
+ if(IS_DIRECTORY ${KITSDIRx86})
+ set(KITSPATH "${KITSDIRx86}/Redist/ucrt/DLLs/${_WIN_PLATFORM}")
+ else()
+ message(FATAL_ERROR "Windows 10 SDK directory not found")
+ endif()
+ endif()
+ FILE(TO_CMAKE_PATH ${KITSPATH} KITSPATH)
+ install(
+ FILES
+ ${KITSPATH}/api-ms-win-core-file-l1-2-0.dll
+ ${KITSPATH}/api-ms-win-core-file-l2-1-0.dll
+ ${KITSPATH}/api-ms-win-core-localization-l1-2-0.dll
+ ${KITSPATH}/api-ms-win-core-processthreads-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-core-processthreads-l1-1-1.dll
+ ${KITSPATH}/api-ms-win-core-synch-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-core-synch-l1-2-0.dll
+ ${KITSPATH}/api-ms-win-core-timezone-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-crt-conio-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-crt-convert-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-crt-environment-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-crt-filesystem-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-crt-heap-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-crt-locale-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-crt-math-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-crt-process-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-crt-runtime-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-crt-stdio-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-crt-string-l1-1-0.dll
+ ${KITSPATH}/api-ms-win-crt-time-l1-1-0.dll
+ ${KITSPATH}/ucrtbase.dll
+ ${MSVC14_REDIST_DIR}/${_WIN_PLATFORM}/Microsoft.VC140.CRT/vcruntime140.dll
+ DESTINATION "."
+ )
+ if(WITH_OPENMP)
+ install(
+ FILES ${MSVC14_REDIST_DIR}/${_WIN_PLATFORM}/Microsoft.VC140.OpenMP/vcomp140.dll
+ DESTINATION "."
+ )
+ endif()
+ endif()
endif()
diff --git a/source/creator/creator.c b/source/creator/creator.c
index bfb1dd94dd4..4e090b0b19f 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -54,8 +54,8 @@
#include "BKE_appdir.h"
#include "BKE_blender.h"
#include "BKE_brush.h"
+#include "BKE_cachefile.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h" /* for DAG_init */
#include "BKE_font.h"
#include "BKE_global.h"
#include "BKE_material.h"
@@ -65,6 +65,7 @@
#include "BKE_image.h"
#include "BKE_particle.h"
+#include "DEG_depsgraph.h"
#include "IMB_imbuf.h" /* for IMB_init */
@@ -230,8 +231,7 @@ int main(
/* --- end declarations --- */
- /* ensure we free data on early-exit */
- struct CreatorAtExitData app_init_data = {NULL};
+ /* ensure we free data on early-exit */ struct CreatorAtExitData app_init_data = {NULL};
BKE_blender_atexit_register(callback_main_atexit, &app_init_data);
#ifdef WIN32
@@ -357,9 +357,10 @@ int main(
BKE_blender_globals_init(); /* blender.c */
IMB_init();
+ BKE_cachefiles_init();
BKE_images_init();
BKE_modifier_init();
- DAG_init();
+ DEG_register_node_types();
BKE_brush_system_init();
RE_texture_rng_init();
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index c3c76a0d1d3..f25efbf72e9 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -55,8 +55,6 @@
#include "BKE_sound.h"
#include "BKE_image.h"
-#include "DEG_depsgraph.h"
-
#ifdef WITH_FFMPEG
#include "IMB_imbuf.h"
#endif
@@ -72,9 +70,7 @@
#include "WM_api.h"
-#include "GPU_basic_shader.h"
#include "GPU_draw.h"
-#include "GPU_extensions.h"
/* for passing information between creator and gameengine */
#ifdef WITH_GAMEENGINE
@@ -438,7 +434,7 @@ static void arg_py_context_restore(
* see: `doc/manpage/blender.1.py`
* - Parsed and extracted for the manual,
* which converts our ad-hoc formatting to reStructuredText.
- * see: http://www.blender.org/manual/advanced/command_line.html
+ * see: https://docs.blender.org/manual/en/dev/advanced/command_line.html
*
* \{ */
@@ -554,6 +550,7 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
BLI_argsPrintArgDoc(ba, "--debug-gpumem");
BLI_argsPrintArgDoc(ba, "--debug-wm");
BLI_argsPrintArgDoc(ba, "--debug-all");
+ BLI_argsPrintArgDoc(ba, "--debug-io");
printf("\n");
BLI_argsPrintArgDoc(ba, "--debug-fpe");
@@ -568,7 +565,6 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
BLI_argsPrintArgDoc(ba, "--env-system-python");
printf("\n");
BLI_argsPrintArgDoc(ba, "-nojoystick");
- BLI_argsPrintArgDoc(ba, "-noglsl");
BLI_argsPrintArgDoc(ba, "-noaudio");
BLI_argsPrintArgDoc(ba, "-setaudio");
@@ -585,14 +581,12 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
BLI_argsPrintArgDoc(ba, "--");
printf("\n");
- printf("Other Options:\n");
- BLI_argsPrintOtherDoc(ba);
+ printf("Experimental Features:\n");
- /* keep last args */
+ /* Other options _must_ be last (anything not handled will show here) */
printf("\n");
- printf("Experimental Features:\n");
- BLI_argsPrintArgDoc(ba, "--enable-new-depsgraph");
- BLI_argsPrintArgDoc(ba, "--enable-new-basic-shader-glsl");
+ printf("Other Options:\n");
+ BLI_argsPrintOtherDoc(ba);
printf("\n");
printf("Argument Parsing:\n");
@@ -756,6 +750,14 @@ static int arg_handle_debug_mode_generic_set(int UNUSED(argc), const char **UNUS
return 0;
}
+static const char arg_handle_debug_mode_io_doc[] =
+"\n\tEnable debug messages for I/O (collada, ...)";
+static int arg_handle_debug_mode_io(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ G.debug |= G_DEBUG_IO;
+ return 0;
+}
+
static const char arg_handle_debug_mode_all_doc[] =
"\n\tEnable all debug messages";
static int arg_handle_debug_mode_all(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
@@ -937,7 +939,7 @@ static int arg_handle_native_pixels_set(int UNUSED(argc), const char **UNUSED(ar
}
static const char arg_handle_with_borders_doc[] =
-"\n\tForce opening without borders"
+"\n\tForce opening with borders"
;
static int arg_handle_with_borders(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
{
@@ -1004,15 +1006,6 @@ static int arg_handle_joystick_disable(int UNUSED(argc), const char **UNUSED(arg
return 0;
}
-static const char arg_handle_glsl_disable_doc[] =
-"\n\tDisable GLSL shading"
-;
-static int arg_handle_glsl_disable(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
-{
- GPU_extensions_disable();
- return 0;
-}
-
static const char arg_handle_audio_disable_doc[] =
"\n\tForce sound system to None"
;
@@ -1176,26 +1169,6 @@ static int arg_handle_threads_set(int argc, const char **argv, void *UNUSED(data
}
}
-static const char arg_handle_depsgraph_use_new_doc[] =
-"\n\tUse new dependency graph"
-;
-static int arg_handle_depsgraph_use_new(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
-{
- printf("Using new dependency graph.\n");
- DEG_depsgraph_switch_to_new();
- return 0;
-}
-
-static const char arg_handle_basic_shader_glsl_use_new_doc[] =
-"\n\tUse new GLSL basic shader"
-;
-static int arg_handle_basic_shader_glsl_use_new(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
-{
- printf("Using new GLSL basic shader.\n");
- GPU_basic_shader_use_glsl_set(true);
- return 0;
-}
-
static const char arg_handle_verbosity_set_doc[] =
"<verbose>\n"
"\tSet logging verbosity level."
@@ -1355,7 +1328,7 @@ static int arg_handle_render_frame(int argc, const char **argv, void *data)
re = RE_NewRender(scene->id.name);
BLI_begin_threaded_malloc();
- BKE_reports_init(&reports, RPT_PRINT);
+ BKE_reports_init(&reports, RPT_STORE);
RE_SetReports(re, &reports);
for (int i = 0; i < frames_range_len; i++) {
@@ -1370,6 +1343,7 @@ static int arg_handle_render_frame(int argc, const char **argv, void *data)
}
}
RE_SetReports(re, NULL);
+ BKE_reports_clear(&reports);
BLI_end_threaded_malloc();
MEM_freeN(frame_range_arr);
return 1;
@@ -1397,10 +1371,11 @@ static int arg_handle_render_animation(int UNUSED(argc), const char **UNUSED(arg
Render *re = RE_NewRender(scene->id.name);
ReportList reports;
BLI_begin_threaded_malloc();
- BKE_reports_init(&reports, RPT_PRINT);
+ BKE_reports_init(&reports, RPT_STORE);
RE_SetReports(re, &reports);
RE_BlenderAnim(re, bmain, scene, NULL, scene->lay, scene->r.sfra, scene->r.efra, scene->r.frame_step);
RE_SetReports(re, NULL);
+ BKE_reports_clear(&reports);
BLI_end_threaded_malloc();
}
else {
@@ -1805,6 +1780,8 @@ void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
CB_EX(arg_handle_debug_mode_generic_set, wm), (void *)G_DEBUG_WM);
BLI_argsAdd(ba, 1, NULL, "--debug-all", CB(arg_handle_debug_mode_all), NULL);
+ BLI_argsAdd(ba, 1, NULL, "--debug-io", CB(arg_handle_debug_mode_io), NULL);
+
BLI_argsAdd(ba, 1, NULL, "--debug-fpe",
CB(arg_handle_debug_fpe_set), NULL);
@@ -1829,9 +1806,6 @@ void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
BLI_argsAdd(ba, 1, NULL, "--debug-gpumem",
CB_EX(arg_handle_debug_mode_generic_set, gpumem), (void *)G_DEBUG_GPU_MEM);
- BLI_argsAdd(ba, 1, NULL, "--enable-new-depsgraph", CB(arg_handle_depsgraph_use_new), NULL);
- BLI_argsAdd(ba, 1, NULL, "--enable-new-basic-shader-glsl", CB(arg_handle_basic_shader_glsl_use_new), NULL);
-
BLI_argsAdd(ba, 1, NULL, "--verbose", CB(arg_handle_verbosity_set), NULL);
BLI_argsAdd(ba, 1, NULL, "--factory-startup", CB(arg_handle_factory_startup_set), NULL);
@@ -1852,7 +1826,6 @@ void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
/* third pass: disabling things and forcing settings */
BLI_argsAddCase(ba, 3, "-nojoystick", 1, NULL, 0, CB(arg_handle_joystick_disable), syshandle);
- BLI_argsAddCase(ba, 3, "-noglsl", 1, NULL, 0, CB(arg_handle_glsl_disable), NULL);
BLI_argsAddCase(ba, 3, "-noaudio", 1, NULL, 0, CB(arg_handle_audio_disable), NULL);
BLI_argsAddCase(ba, 3, "-setaudio", 1, NULL, 0, CB(arg_handle_audio_set), NULL);
@@ -1875,7 +1848,7 @@ void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
BLI_argsAdd(ba, 4, "-E", "--engine", CB(arg_handle_engine_set), C);
BLI_argsAdd(ba, 4, "-F", "--render-format", CB(arg_handle_image_type_set), C);
- BLI_argsAdd(ba, 4, "-t", "--threads", CB(arg_handle_threads_set), NULL);
+ BLI_argsAdd(ba, 1, "-t", "--threads", CB(arg_handle_threads_set), NULL);
BLI_argsAdd(ba, 4, "-x", "--use-extension", CB(arg_handle_extension_set), C);
#undef CB
diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
index 91683f4d6e7..99f3d0639f3 100644
--- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
+++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
@@ -40,7 +40,7 @@
# pragma warning (disable:4786)
#endif
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include "KX_BlenderCanvas.h"
#include "KX_BlenderKeyboardDevice.h"
@@ -104,13 +104,13 @@ typedef void * wmUIHandlerRemoveFunc;
# include AUD_DEVICE_H
#endif
-static BlendFileData *load_game_data(char *filename)
+static BlendFileData *load_game_data(const char *filename)
{
ReportList reports;
BlendFileData *bfd;
BKE_reports_init(&reports, RPT_STORE);
- bfd= BLO_read_from_file(filename, &reports);
+ bfd= BLO_read_from_file(filename, &reports, BLO_READ_SKIP_USERDEF);
if (!bfd) {
printf("Loading %s failed: ", filename);
@@ -267,7 +267,7 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c
bool profile = (SYS_GetCommandLineInt(syshandle, "show_profile", 0) != 0);
bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0);
bool animation_record = (SYS_GetCommandLineInt(syshandle, "animation_record", 0) != 0);
- bool displaylists = (SYS_GetCommandLineInt(syshandle, "displaylists", 0) != 0) && GPU_display_list_support();
+ bool displaylists = false; // (SYS_GetCommandLineInt(syshandle, "displaylists", 0) != 0) && GPU_display_list_support();
#ifdef WITH_PYTHON
bool nodepwarnings = (SYS_GetCommandLineInt(syshandle, "ignore_deprecation_warnings", 0) != 0);
#endif
@@ -465,19 +465,9 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c
if (always_use_expand_framing)
sceneconverter->SetAlwaysUseExpandFraming(true);
- bool usemat = false, useglslmat = false;
+ sceneconverter->SetMaterials(true);
- if (GLEW_ARB_multitexture && GLEW_VERSION_1_1)
- usemat = true;
-
- if (GPU_glsl_support())
- useglslmat = true;
- else if (gs.matmode == GAME_MAT_GLSL)
- usemat = false;
-
- if (usemat)
- sceneconverter->SetMaterials(true);
- if (useglslmat && (gs.matmode == GAME_MAT_GLSL))
+ if (gs.matmode == GAME_MAT_GLSL)
sceneconverter->SetGLSLMaterials(true);
if (scene->gm.flag & GAME_NO_MATERIAL_CACHING)
sceneconverter->SetCacheMaterials(false);
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
index 927b26faf8a..6fdc823ba1a 100644
--- a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
+++ b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
@@ -29,7 +29,7 @@
* \ingroup blroutines
*/
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include "MEM_guardedalloc.h"
@@ -324,7 +324,6 @@ static unsigned int *screenshot(ScrArea *curarea, int *dumpsx, int *dumpsy)
void KX_BlenderCanvas::MakeScreenShot(const char *filename)
{
ScrArea area_dummy= {0};
- bScreen *screen = m_win->screen;
unsigned int *dumprect;
int dumpsx, dumpsy;
@@ -340,7 +339,7 @@ void KX_BlenderCanvas::MakeScreenShot(const char *filename)
}
/* initialize image file format data */
- Scene *scene = (screen)? screen->scene: NULL;
+ Scene *scene = WM_window_get_active_scene(m_win);
ImageFormatData *im_format = (ImageFormatData *)MEM_mallocN(sizeof(ImageFormatData), "im_format");
if (scene)
diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp
index a5af525e13a..1f6687c2b67 100644
--- a/source/gameengine/Converter/BL_ArmatureObject.cpp
+++ b/source/gameengine/Converter/BL_ArmatureObject.cpp
@@ -138,7 +138,8 @@ static void game_copy_pose(bPose **dst, bPose *src, int copy_constraint)
if (pchan->prop)
pchan->prop= IDP_CopyProperty(pchan->prop);
#endif
- pchan->prop= NULL;
+ pchan->prop = NULL;
+ pchan->draw_data = NULL;
}
BLI_ghash_free(ghash, NULL, NULL);
diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
index 4751e60996d..6667e6a44c2 100644
--- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp
+++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
@@ -589,17 +589,17 @@ static bool ConvertMaterial(
/* In Multitexture use the face texture if and only if
* it is set in the buttons
* In GLSL is not working yet :/ 3.2011 */
- bool facetex = false;
- if (validface && mat->mode & MA_FACETEXTURE) {
- facetex = true;
- }
// foreach MTex
for (int i = 0; i < MAXTEX; i++) {
// use face tex
- if (i == 0 && facetex ) {
- facetex = false;
+ if (i == 0) {
+#if 0
Image *tmp = (Image *)(tface->tpage);
+#else
+ /* weak but better then nothing */
+ Image *tmp = mat ? mat->edit_image : NULL;
+#endif
if (tmp) {
material->img[i] = tmp;
@@ -789,7 +789,11 @@ static bool ConvertMaterial(
// check for tface tex to fallback on
if (validface) {
+#if 0
material->img[0] = (Image *)(tface->tpage);
+#else
+ material->img[0] = mat ? mat->edit_image : NULL;
+#endif
// ------------------------
if (material->img[0]) {
material->texname[0] = material->img[0]->id.name;
@@ -830,7 +834,7 @@ static bool ConvertMaterial(
/* No material, what to do? let's see what is in the UV and set the material accordingly
* light and visible is always on */
if (validface) {
- material->tile = tface->tile;
+ /* nop */
}
else {
// nothing at all
@@ -869,13 +873,6 @@ static bool ConvertMaterial(
if (validmat) {
material->matname =(mat->id.name);
}
-
- if (tface) {
- ME_MTEXFACE_CPY(&material->mtexpoly, tface);
- }
- else {
- memset(&material->mtexpoly, 0, sizeof(material->mtexpoly));
- }
material->material = mat;
return true;
}
@@ -894,7 +891,7 @@ static RAS_MaterialBucket *material_from_mesh(Material *ma, MFace *mface, MTFace
ConvertMaterial(bl_mat, ma, tface, tfaceName, mface, mcol,
converter->GetGLSLMaterials());
- if (ma && (ma->mode & MA_FACETEXTURE) == 0)
+ if (ma)
converter->CacheBlenderMaterial(scene, ma, bl_mat);
}
@@ -910,7 +907,7 @@ static RAS_MaterialBucket *material_from_mesh(Material *ma, MFace *mface, MTFace
kx_blmat->Initialize(scene, bl_mat, (ma?&ma->game:NULL), lightlayer);
polymat = static_cast<RAS_IPolyMaterial*>(kx_blmat);
- if (ma && (ma->mode & MA_FACETEXTURE) == 0)
+ if (ma)
converter->CachePolyMaterial(scene, ma, polymat);
}
@@ -1740,7 +1737,7 @@ static void blenderSceneSetBackground(Scene *blenderscene)
for (SETLOOPER(blenderscene, it, base)) {
base->object->lay = base->lay;
- base->object->flag = base->flag;
+ BKE_scene_base_flag_sync_from_base(base);
}
}
diff --git a/source/gameengine/Expressions/intern/HashedPtr.cpp b/source/gameengine/Expressions/intern/HashedPtr.cpp
index 005ac16b231..11d9482f993 100644
--- a/source/gameengine/Expressions/intern/HashedPtr.cpp
+++ b/source/gameengine/Expressions/intern/HashedPtr.cpp
@@ -40,10 +40,8 @@ CHashedPtr::CHashedPtr(void* val) : m_valptr(val)
unsigned int CHashedPtr::hash() const
{
-#if defined(_WIN64) && !defined(FREE_WINDOWS64)
+#if defined(_WIN64)
unsigned __int64 key = (unsigned __int64)m_valptr;
-#elif defined(FREE_WINDOWS64)
- unsigned long long key = (unsigned long long)m_valptr;
#else
unsigned long key = (unsigned long)m_valptr;
#endif
diff --git a/source/gameengine/Expressions/intern/InputParser.cpp b/source/gameengine/Expressions/intern/InputParser.cpp
index e8cc7fba284..583d8da63cb 100644
--- a/source/gameengine/Expressions/intern/InputParser.cpp
+++ b/source/gameengine/Expressions/intern/InputParser.cpp
@@ -37,7 +37,7 @@
// cool things like (IF(LOD==1,CCurvedValue,IF(LOD==2,CCurvedValue2)) etc...
#include "EXP_IfExpr.h"
-#if (defined(WIN32) || defined(WIN64)) && !defined(FREE_WINDOWS)
+#if defined(WIN32) || defined(WIN64)
#define strcasecmp _stricmp
#ifndef strtoll
diff --git a/source/gameengine/Expressions/intern/PyObjectPlus.cpp b/source/gameengine/Expressions/intern/PyObjectPlus.cpp
index de45bee76a7..1e4a59aeb5c 100644
--- a/source/gameengine/Expressions/intern/PyObjectPlus.cpp
+++ b/source/gameengine/Expressions/intern/PyObjectPlus.cpp
@@ -335,7 +335,7 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef *
Py_DECREF(resultlist);
return NULL;
}
- // walkthrough
+ ATTR_FALLTHROUGH;
case KX_PYATTRIBUTE_TYPE_INT:
{
int *val = reinterpret_cast<int*>(ptr);
@@ -406,7 +406,7 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef *
{
return NULL;
}
- // walkthrough
+ ATTR_FALLTHROUGH;
case KX_PYATTRIBUTE_TYPE_INT:
{
int *val = reinterpret_cast<int*>(ptr);
@@ -638,7 +638,7 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt
PyErr_Format(PyExc_AttributeError, "Size check error for attribute, \"%s\", report to blender.org", attrdef->m_name);
goto UNDO_AND_ERROR;
}
- // walkthrough
+ ATTR_FALLTHROUGH;
case KX_PYATTRIBUTE_TYPE_INT:
{
int *var = reinterpret_cast<int*>(ptr);
@@ -883,7 +883,7 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt
PyErr_Format(PyExc_AttributeError, "attribute size check error for attribute \"%s\", report to blender.org", attrdef->m_name);
goto FREE_AND_ERROR;
}
- // walkthrough
+ ATTR_FALLTHROUGH;
case KX_PYATTRIBUTE_TYPE_INT:
{
int *var = reinterpret_cast<int*>(ptr);
diff --git a/source/gameengine/GameLogic/SCA_PropertySensor.cpp b/source/gameengine/GameLogic/SCA_PropertySensor.cpp
index abb64cf1733..e34a5296139 100644
--- a/source/gameengine/GameLogic/SCA_PropertySensor.cpp
+++ b/source/gameengine/GameLogic/SCA_PropertySensor.cpp
@@ -133,7 +133,7 @@ bool SCA_PropertySensor::CheckPropertyCondition()
{
case KX_PROPSENSOR_NOTEQUAL:
reverse = true;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case KX_PROPSENSOR_EQUAL:
{
CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
@@ -231,7 +231,7 @@ bool SCA_PropertySensor::CheckPropertyCondition()
}
case KX_PROPSENSOR_LESSTHAN:
reverse = true;
- /* fall-through */
+ ATTR_FALLTHROUGH;
case KX_PROPSENSOR_GREATERTHAN:
{
CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
diff --git a/source/gameengine/GamePlayer/common/GPC_Canvas.h b/source/gameengine/GamePlayer/common/GPC_Canvas.h
index 9a108203ee8..688ed8ac0f4 100644
--- a/source/gameengine/GamePlayer/common/GPC_Canvas.h
+++ b/source/gameengine/GamePlayer/common/GPC_Canvas.h
@@ -40,7 +40,7 @@
# include <windows.h>
#endif /* WIN32 */
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include <map>
diff --git a/source/gameengine/GamePlayer/common/GPC_MouseDevice.h b/source/gameengine/GamePlayer/common/GPC_MouseDevice.h
index 504df2376bb..24922197723 100644
--- a/source/gameengine/GamePlayer/common/GPC_MouseDevice.h
+++ b/source/gameengine/GamePlayer/common/GPC_MouseDevice.h
@@ -67,8 +67,6 @@ public:
* Call this routine to update the mouse device when a button state changes.
* \param button Which button state changes.
* \param isDown The new state of the button.
- * \param x Position x-coordinate of the cursor at the time of the state change.
- * \param y Position y-coordinate of the cursor at the time of the state change.
* \return Indication as to whether the event was processed.
*/
virtual bool ConvertButtonEvent(TButtonId button, bool isDown);
diff --git a/source/gameengine/GamePlayer/ghost/CMakeLists.txt b/source/gameengine/GamePlayer/ghost/CMakeLists.txt
index 6c09af33f9e..6d6d53b1e17 100644
--- a/source/gameengine/GamePlayer/ghost/CMakeLists.txt
+++ b/source/gameengine/GamePlayer/ghost/CMakeLists.txt
@@ -43,6 +43,7 @@ set(INC
../../../blender/blenlib
../../../blender/blenloader
../../../blender/blentranslation
+ ../../../blender/depsgraph
../../../blender/gpu
../../../blender/imbuf
../../../blender/makesdna
@@ -81,6 +82,10 @@ if(WIN32)
blender_include_dirs(../../../../intern/utfconv)
endif()
+if(WITH_INPUT_NDOF)
+ add_definitions(-DWITH_INPUT_NDOF)
+endif(WITH_INPUT_NDOF)
+
if(WITH_CODEC_FFMPEG)
add_definitions(-DWITH_FFMPEG)
endif()
diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
index e697306e038..ddb04e9f84d 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
+++ b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
@@ -36,7 +36,7 @@
# include <windows.h>
#endif
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include "GPU_extensions.h"
#include "GPU_init_exit.h"
@@ -586,17 +586,12 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode)
bool fixed_framerate= (SYS_GetCommandLineInt(syshandle, "fixedtime", (gm->flag & GAME_ENABLE_ALL_FRAMES)) != 0);
bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0);
- bool useLists = (SYS_GetCommandLineInt(syshandle, "displaylists", gm->flag & GAME_DISPLAY_LISTS) != 0) && GPU_display_list_support();
+ bool useLists = false; // (SYS_GetCommandLineInt(syshandle, "displaylists", gm->flag & GAME_DISPLAY_LISTS) != 0) && GPU_display_list_support();
bool nodepwarnings = (SYS_GetCommandLineInt(syshandle, "ignore_deprecation_warnings", 1) != 0);
bool restrictAnimFPS = (gm->flag & GAME_RESTRICT_ANIM_UPDATES) != 0;
- if (GLEW_ARB_multitexture && GLEW_VERSION_1_1)
- m_blendermat = (SYS_GetCommandLineInt(syshandle, "blender_material", 1) != 0);
-
- if (GPU_glsl_support())
- m_blenderglslmat = (SYS_GetCommandLineInt(syshandle, "blender_glsl_material", 1) != 0);
- else if (m_globalSettings->matmode == GAME_MAT_GLSL)
- m_blendermat = false;
+ m_blendermat = (SYS_GetCommandLineInt(syshandle, "blender_material", 1) != 0);
+ m_blenderglslmat = (SYS_GetCommandLineInt(syshandle, "blender_glsl_material", 1) != 0);
// create the canvas, rasterizer and rendertools
m_canvas = new GPG_Canvas(window);
diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
index edbbf93bf7a..998058193bb 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
+++ b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
@@ -68,7 +68,6 @@ extern "C"
#include "BKE_appdir.h"
#include "BKE_blender.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_icons.h"
#include "BKE_image.h"
@@ -81,6 +80,8 @@ extern "C"
#include "BKE_text.h"
#include "BKE_sound.h"
+#include "DEG_depsgraph.h"
+
#include "IMB_imbuf.h"
#include "IMB_moviecache.h"
@@ -355,7 +356,7 @@ static BlendFileData *load_game_data(const char *progname, char *filename = NULL
BLI_strncpy(bfd->main->name, progname, sizeof(bfd->main->name));
}
} else {
- bfd= BLO_read_from_file(progname, &reports);
+ bfd= BLO_read_from_file(progname, &reports, BLO_READ_SKIP_NONE);
}
if (!bfd && filename) {
@@ -509,14 +510,14 @@ int main(
IMB_init();
BKE_images_init();
BKE_modifier_init();
- DAG_init();
+ DEG_register_node_types();
#ifdef WITH_FFMPEG
IMB_ffmpeg_init();
#endif
// Setup builtin font for BLF (mostly copied from creator.c, wm_init_exit.c and interface_style.c)
- BLF_init(11, U.dpi);
+ BLF_init();
BLT_lang_init();
BLT_lang_set("");
@@ -1148,7 +1149,7 @@ int main(
MEM_freeN(python_code);
}
else {
- fprintf(stderr, "ERROR: cannot yield control to Python: no Python text data block named '%s'\n", python_main);
+ fprintf(stderr, "ERROR: cannot yield control to Python: no Python text data-block named '%s'\n", python_main);
}
}
else {
@@ -1201,7 +1202,7 @@ int main(
IMB_exit();
BKE_images_exit();
- DAG_exit();
+ DEG_free_node_types();
IMB_moviecache_destruct();
SYS_DeleteSystem(syshandle);
diff --git a/source/gameengine/Ketsji/BL_BlenderShader.cpp b/source/gameengine/Ketsji/BL_BlenderShader.cpp
index 95679b5d3a6..9cbd61590b6 100644
--- a/source/gameengine/Ketsji/BL_BlenderShader.cpp
+++ b/source/gameengine/Ketsji/BL_BlenderShader.cpp
@@ -169,7 +169,7 @@ void BL_BlenderShader::Update(const RAS_MeshSlot & ms, RAS_IRasterizer* rasty )
rasty->GetViewMatrix().getValue(&viewmat[0][0]);
float auto_bump_scale = ms.m_pDerivedMesh!=0 ? ms.m_pDerivedMesh->auto_bump_scale : 1.0f;
- GPU_material_bind_uniforms(gpumat, obmat, viewmat, obcol, auto_bump_scale, NULL);
+ GPU_material_bind_uniforms(gpumat, obmat, viewmat, obcol, auto_bump_scale, NULL, NULL);
mAlphaBlend = GPU_material_alpha_blend(gpumat, obcol);
}
diff --git a/source/gameengine/Ketsji/BL_Material.cpp b/source/gameengine/Ketsji/BL_Material.cpp
index 4f707e6267f..40384b43054 100644
--- a/source/gameengine/Ketsji/BL_Material.cpp
+++ b/source/gameengine/Ketsji/BL_Material.cpp
@@ -69,7 +69,6 @@ void BL_Material::Initialize()
alpha = 1.f;
emit = 0.f;
material = 0;
- memset(&mtexpoly, 0, sizeof(mtexpoly));
materialindex = 0;
amb=0.5f;
num_enabled = 0;
diff --git a/source/gameengine/Ketsji/BL_Material.h b/source/gameengine/Ketsji/BL_Material.h
index 9207a41f56d..710c02f4871 100644
--- a/source/gameengine/Ketsji/BL_Material.h
+++ b/source/gameengine/Ketsji/BL_Material.h
@@ -84,7 +84,6 @@ public:
Material* material;
- MTexPoly mtexpoly; /* copy of the derived meshes tface */
Image* img[MAXTEX];
EnvMap* cubemap[MAXTEX];
diff --git a/source/gameengine/Ketsji/BL_Shader.cpp b/source/gameengine/Ketsji/BL_Shader.cpp
index 72815cadc70..d344e18c313 100644
--- a/source/gameengine/Ketsji/BL_Shader.cpp
+++ b/source/gameengine/Ketsji/BL_Shader.cpp
@@ -22,7 +22,7 @@
* \ingroup ketsji
*/
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include <iostream>
#include "BL_Shader.h"
diff --git a/source/gameengine/Ketsji/BL_Texture.cpp b/source/gameengine/Ketsji/BL_Texture.cpp
index 730e49c4918..c3b799b9424 100644
--- a/source/gameengine/Ketsji/BL_Texture.cpp
+++ b/source/gameengine/Ketsji/BL_Texture.cpp
@@ -22,7 +22,7 @@
* \ingroup ketsji
*/
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include <iostream>
#include <map>
@@ -420,14 +420,7 @@ int BL_Texture::GetMaxUnits()
{
if (g_max_units < 0) {
GLint unit = 0;
-
- if (GPU_glsl_support()) {
- glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &unit);
- }
- else if (GLEW_ARB_multitexture) {
- glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &unit);
- }
-
+ glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &unit);
g_max_units = (MAXTEX >= unit) ? unit : MAXTEX;
}
diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp
index 476fbd29b8b..98d27ef3685 100644
--- a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp
+++ b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp
@@ -22,7 +22,7 @@
* \ingroup ketsji
*/
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include "KX_BlenderMaterial.h"
#include "BL_Material.h"
@@ -160,12 +160,6 @@ KX_BlenderMaterial::~KX_BlenderMaterial()
OnExit();
}
-MTexPoly *KX_BlenderMaterial::GetMTexPoly() const
-{
- // fonts on polys
- return &mMaterial->mtexpoly;
-}
-
unsigned int* KX_BlenderMaterial::GetMCol() const
{
// fonts on polys
@@ -190,7 +184,7 @@ Material *KX_BlenderMaterial::GetBlenderMaterial() const
Image *KX_BlenderMaterial::GetBlenderImage() const
{
- return mMaterial->mtexpoly.tpage;
+ return mMaterial->material ? mMaterial->material->edit_image : NULL;
}
Scene* KX_BlenderMaterial::GetBlenderScene() const
@@ -290,11 +284,6 @@ void KX_BlenderMaterial::OnExit()
mTextures[i].DeleteTex();
mTextures[i].DisableUnit();
}
-
- /* used to call with 'mMaterial->tface' but this can be a freed array,
- * see: [#30493], so just call with NULL, this is best since it clears
- * the 'lastface' pointer in GPU too - campbell */
- GPU_set_tpage(NULL, 1, mMaterial->alphablend);
}
@@ -310,7 +299,7 @@ void KX_BlenderMaterial::setShaderData( bool enable, RAS_IRasterizer *ras)
mLastShader = NULL;
}
- ras->SetAlphaBlend(TF_SOLID);
+ ras->SetAlphaBlend(GPU_BLEND_SOLID);
BL_Texture::DisableAllTextures();
return;
}
@@ -334,7 +323,7 @@ void KX_BlenderMaterial::setShaderData( bool enable, RAS_IRasterizer *ras)
ras->SetAlphaBlend(mMaterial->alphablend);
}
else {
- ras->SetAlphaBlend(TF_SOLID);
+ ras->SetAlphaBlend(GPU_BLEND_SOLID);
ras->SetAlphaBlend(-1); // indicates custom mode
// tested to be valid enums
@@ -346,7 +335,7 @@ void KX_BlenderMaterial::setShaderData( bool enable, RAS_IRasterizer *ras)
void KX_BlenderMaterial::setBlenderShaderData( bool enable, RAS_IRasterizer *ras)
{
if ( !enable || !mBlenderShader->Ok() ) {
- ras->SetAlphaBlend(TF_SOLID);
+ ras->SetAlphaBlend(GPU_BLEND_SOLID);
// frame cleanup.
if (mLastBlenderShader) {
@@ -377,7 +366,7 @@ void KX_BlenderMaterial::setTexData( bool enable, RAS_IRasterizer *ras)
BL_Texture::DisableAllTextures();
if ( !enable ) {
- ras->SetAlphaBlend(TF_SOLID);
+ ras->SetAlphaBlend(GPU_BLEND_SOLID);
return;
}
@@ -420,7 +409,7 @@ void KX_BlenderMaterial::setTexData( bool enable, RAS_IRasterizer *ras)
ras->SetAlphaBlend(mMaterial->alphablend);
}
else {
- ras->SetAlphaBlend(TF_SOLID);
+ ras->SetAlphaBlend(GPU_BLEND_SOLID);
ras->SetAlphaBlend(-1); // indicates custom mode
glEnable(GL_BLEND);
diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.h b/source/gameengine/Ketsji/KX_BlenderMaterial.h
index a3d10c0a89d..c562ee0c583 100644
--- a/source/gameengine/Ketsji/KX_BlenderMaterial.h
+++ b/source/gameengine/Ketsji/KX_BlenderMaterial.h
@@ -84,7 +84,6 @@ public:
Material* GetBlenderMaterial() const;
Image* GetBlenderImage() const;
- MTexPoly *GetMTexPoly() const;
unsigned int* GetMCol() const;
BL_Texture * getTex (unsigned int idx) {
return (idx < MAXTEX) ? mTextures + idx : NULL;
diff --git a/source/gameengine/Ketsji/KX_Camera.cpp b/source/gameengine/Ketsji/KX_Camera.cpp
index 89aea80bb67..4a97dc09f62 100644
--- a/source/gameengine/Ketsji/KX_Camera.cpp
+++ b/source/gameengine/Ketsji/KX_Camera.cpp
@@ -31,7 +31,7 @@
*/
-#include "glew-mx.h"
+#include "GPU_matrix.h"
#include "KX_Camera.h"
#include "KX_Scene.h"
#include "KX_PythonInit.h"
@@ -1048,19 +1048,21 @@ KX_PYMETHODDEF_DOC_O(KX_Camera, getScreenPosition,
}
const GLint *viewport;
- GLdouble win[3];
- GLdouble modelmatrix[16];
- GLdouble projmatrix[16];
+ GLfloat vec[3];
+ GLfloat win[3];
+ GLfloat modelmatrix[4][4];
+ GLfloat projmatrix[4][4];
MT_Matrix4x4 m_modelmatrix = this->GetWorldToCamera();
MT_Matrix4x4 m_projmatrix = this->GetProjectionMatrix();
- m_modelmatrix.getValue(modelmatrix);
- m_projmatrix.getValue(projmatrix);
+ vect.getValue(vec);
+ m_modelmatrix.getValue((float*) modelmatrix);
+ m_projmatrix.getValue((float*) projmatrix);
viewport = KX_GetActiveEngine()->GetCanvas()->GetViewPort();
- gluProject(vect[0], vect[1], vect[2], modelmatrix, projmatrix, viewport, &win[0], &win[1], &win[2]);
+ gpuProject(vec, modelmatrix, projmatrix, viewport, win);
vect[0] = (win[0] - viewport[0]) / viewport[2];
vect[1] = (win[1] - viewport[1]) / viewport[3];
@@ -1087,36 +1089,33 @@ KX_PYMETHODDEF_DOC_VARARGS(KX_Camera, getScreenVect,
y = 1.0 - y; //to follow Blender window coordinate system (Top-Down)
- MT_Vector3 vect;
- MT_Point3 campos, screenpos;
-
const GLint *viewport;
- GLdouble win[3];
- GLdouble modelmatrix[16];
- GLdouble projmatrix[16];
+ GLfloat vec[3];
+ GLfloat win[3];
+ GLfloat modelmatrix[4][4];
+ GLfloat projmatrix[4][4];
MT_Matrix4x4 m_modelmatrix = this->GetWorldToCamera();
MT_Matrix4x4 m_projmatrix = this->GetProjectionMatrix();
- m_modelmatrix.getValue(modelmatrix);
- m_projmatrix.getValue(projmatrix);
+ m_modelmatrix.getValue((float*) modelmatrix);
+ m_projmatrix.getValue((float*) projmatrix);
viewport = KX_GetActiveEngine()->GetCanvas()->GetViewPort();
- vect[0] = x * viewport[2];
- vect[1] = y * viewport[3];
-
- vect[0] += viewport[0];
- vect[1] += viewport[1];
+ vec[0] = x * viewport[2];
+ vec[1] = y * viewport[3];
- vect[2] = 0.f;
+ vec[0] += viewport[0];
+ vec[1] += viewport[1];
- gluUnProject(vect[0], vect[1], vect[2], modelmatrix, projmatrix, viewport, &win[0], &win[1], &win[2]);
+ vec[2] = 0.f;
- campos = this->GetCameraLocation();
- screenpos = MT_Point3(win[0], win[1], win[2]);
- vect = campos-screenpos;
+ gpuUnProject(vec, modelmatrix, projmatrix, viewport, win);
+ MT_Point3 campos = this->GetCameraLocation();
+ MT_Point3 screenpos(win[0], win[1], win[2]);
+ MT_Vector3 vect = campos - screenpos;
vect.normalize();
return PyObjectFrom(vect);
}
diff --git a/source/gameengine/Ketsji/KX_Dome.cpp b/source/gameengine/Ketsji/KX_Dome.cpp
index d08372e47d4..7abff85d39c 100644
--- a/source/gameengine/Ketsji/KX_Dome.cpp
+++ b/source/gameengine/Ketsji/KX_Dome.cpp
@@ -41,7 +41,7 @@
#include "RAS_CameraData.h"
#include "BLI_math.h"
-#include "glew-mx.h"
+#include "GPU_matrix.h"
// constructor
KX_Dome::KX_Dome (
@@ -1685,7 +1685,7 @@ void KX_Dome::DrawEnvMap(void)
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
- gluLookAt(0.0f,0.0f,1.0f, 0.0f,0.0f,0.0f, 0.0f,1.0f,0.0f);
+ gpuLookAt(0.0f,0.0f,1.0f, 0.0f,0.0f,0.0f, 0.0f,1.0f,0.0f);
glPolygonMode(GL_FRONT, GL_FILL);
glShadeModel(GL_SMOOTH);
@@ -1830,7 +1830,7 @@ void KX_Dome::DrawDomeFisheye(void)
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
- gluLookAt(0.0f,-1.0f,0.0f, 0.0f,0.0f,0.0f, 0.0f,0.0f,1.0f);
+ gpuLookAt(0.0f,-1.0f,0.0f, 0.0f,0.0f,0.0f, 0.0f,0.0f,1.0f);
if (m_drawingmode == RAS_IRasterizer::KX_WIREFRAME)
glPolygonMode(GL_FRONT, GL_LINE);
@@ -1913,7 +1913,7 @@ void KX_Dome::DrawPanorama(void)
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
- gluLookAt(0.0f,-1.0f,0.0f, 0.0f,0.0f,0.0f, 0.0f,0.0f,1.0f);
+ gpuLookAt(0.0f,-1.0f,0.0f, 0.0f,0.0f,0.0f, 0.0f,0.0f,1.0f);
if (m_drawingmode == RAS_IRasterizer::KX_WIREFRAME)
glPolygonMode(GL_FRONT, GL_LINE);
@@ -1981,7 +1981,7 @@ void KX_Dome::DrawDomeWarped(void)
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
- gluLookAt(0.0f, 0.0f, 1.0f, 0.0f,0.0f,0.0f, 0.0f,1.0f,0.0f);
+ gpuLookAt(0.0f, 0.0f, 1.0f, 0.0f,0.0f,0.0f, 0.0f,1.0f,0.0f);
if (m_drawingmode == RAS_IRasterizer::KX_WIREFRAME)
glPolygonMode(GL_FRONT, GL_LINE);
diff --git a/source/gameengine/Ketsji/KX_Dome.h b/source/gameengine/Ketsji/KX_Dome.h
index 420565e62f6..5a0c4588ae2 100644
--- a/source/gameengine/Ketsji/KX_Dome.h
+++ b/source/gameengine/Ketsji/KX_Dome.h
@@ -38,7 +38,7 @@
#include "RAS_IRasterizer.h"
#include "KX_KetsjiEngine.h"
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include <vector>
#include "MEM_guardedalloc.h"
diff --git a/source/gameengine/Ketsji/KX_IPO_SGController.cpp b/source/gameengine/Ketsji/KX_IPO_SGController.cpp
index f3947fdd710..be1a4b4ef3a 100644
--- a/source/gameengine/Ketsji/KX_IPO_SGController.cpp
+++ b/source/gameengine/Ketsji/KX_IPO_SGController.cpp
@@ -31,10 +31,8 @@
*/
-#if defined(_WIN64) && !defined(FREE_WINDOWS64)
+#if defined(_WIN64)
typedef unsigned __int64 uint_ptr;
-#elif defined(FREE_WINDOWS64)
-typedef unsigned long long uint_ptr;
#else
typedef unsigned long uint_ptr;
#endif
diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
index b0a8e376eb6..d82a0fd533b 100644
--- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
+++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
@@ -80,12 +80,6 @@
#define DEFAULT_LOGIC_TIC_RATE 60.0
//#define DEFAULT_PHYSICS_TIC_RATE 60.0
-#ifdef FREE_WINDOWS /* XXX mingw64 (gcc 4.7.0) defines a macro for DrawText that translates to DrawTextA. Not good */
-#ifdef DrawText
-#undef DrawText
-#endif
-#endif
-
const char KX_KetsjiEngine::m_profileLabels[tc_numCategories][15] = {
"Physics:", // tc_physics
"Logic:", // tc_logic
diff --git a/source/gameengine/Ketsji/KX_Light.cpp b/source/gameengine/Ketsji/KX_Light.cpp
index 5f490747c2b..b2a480e99ca 100644
--- a/source/gameengine/Ketsji/KX_Light.cpp
+++ b/source/gameengine/Ketsji/KX_Light.cpp
@@ -34,6 +34,7 @@
#endif
#include <stdio.h>
+#include "DNA_scene_types.h"
#include "KX_Light.h"
#include "KX_Camera.h"
@@ -44,7 +45,6 @@
#include "KX_PyMath.h"
#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
#include "DNA_lamp_types.h"
#include "BKE_scene.h"
diff --git a/source/gameengine/Ketsji/KX_Light.h b/source/gameengine/Ketsji/KX_Light.h
index b446acd6e63..469f2d62b76 100644
--- a/source/gameengine/Ketsji/KX_Light.h
+++ b/source/gameengine/Ketsji/KX_Light.h
@@ -38,7 +38,7 @@
struct GPULamp;
struct Scene;
-struct Base;
+struct BaseLegacy;
class KX_Camera;
class RAS_IRasterizer;
class RAS_ILightObject;
@@ -51,7 +51,7 @@ protected:
RAS_ILightObject* m_lightobj;
class RAS_IRasterizer* m_rasterizer; //needed for registering and replication of lightobj
Scene* m_blenderscene;
- Base* m_base;
+ BaseLegacy* m_base;
public:
KX_LightObject(void* sgReplicationInfo,SG_Callbacks callbacks,RAS_IRasterizer* rasterizer,RAS_ILightObject* lightobj, bool glsl);
diff --git a/source/gameengine/Ketsji/KX_NavMeshObject.cpp b/source/gameengine/Ketsji/KX_NavMeshObject.cpp
index b8907ca5c6b..5beda2e038a 100644
--- a/source/gameengine/Ketsji/KX_NavMeshObject.cpp
+++ b/source/gameengine/Ketsji/KX_NavMeshObject.cpp
@@ -306,7 +306,12 @@ bool KX_NavMeshObject::BuildNavMesh()
|| vertsPerPoly<3)
{
printf("Can't build navigation mesh data for object:%s\n", m_name.ReadPtr());
- if (vertices) delete[] vertices;
+ if (vertices) {
+ delete[] vertices;
+ }
+ if (dvertices) {
+ delete[] dvertices;
+ }
return false;
}
diff --git a/source/gameengine/Ketsji/KX_ObstacleSimulation.cpp b/source/gameengine/Ketsji/KX_ObstacleSimulation.cpp
index 239bfde4c98..c84b2474c90 100644
--- a/source/gameengine/Ketsji/KX_ObstacleSimulation.cpp
+++ b/source/gameengine/Ketsji/KX_ObstacleSimulation.cpp
@@ -345,6 +345,7 @@ static MT_Point3 nearestPointToObstacle(MT_Point3& pos ,KX_Obstacle* obstacle)
MT_Point3 res = obstacle->m_pos + abdir*proj;
return res;
}
+ ATTR_FALLTHROUGH;
}
case KX_OBSTACLE_CIRCLE :
default:
diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp
index cdc2f9f3644..97a7e161e9f 100644
--- a/source/gameengine/Ketsji/KX_PythonInit.cpp
+++ b/source/gameengine/Ketsji/KX_PythonInit.cpp
@@ -30,7 +30,7 @@
* \ingroup ketsji
*/
-#include "glew-mx.h"
+#include "GPU_glew.h"
#ifdef _MSC_VER
# pragma warning (disable:4786)
diff --git a/source/gameengine/Ketsji/KX_SoundActuator.cpp b/source/gameengine/Ketsji/KX_SoundActuator.cpp
index a27f37c0441..d858097abef 100644
--- a/source/gameengine/Ketsji/KX_SoundActuator.cpp
+++ b/source/gameengine/Ketsji/KX_SoundActuator.cpp
@@ -108,7 +108,7 @@ void KX_SoundActuator::play()
case KX_SOUNDACT_LOOPBIDIRECTIONAL:
case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP:
sound = AUD_Sound_pingpong(sound);
- // fall through
+ ATTR_FALLTHROUGH;
case KX_SOUNDACT_LOOPEND:
case KX_SOUNDACT_LOOPSTOP:
loop = true;
@@ -124,7 +124,7 @@ void KX_SoundActuator::play()
AUD_Device_free(device);
// in case of pingpong, we have to free the sound
- if(sound != m_sound)
+ if (sound != m_sound)
AUD_Sound_free(sound);
if (m_handle != NULL) {
diff --git a/source/gameengine/Physics/Bullet/CMakeLists.txt b/source/gameengine/Physics/Bullet/CMakeLists.txt
index e52dc1ba052..8b00f1b47fa 100644
--- a/source/gameengine/Physics/Bullet/CMakeLists.txt
+++ b/source/gameengine/Physics/Bullet/CMakeLists.txt
@@ -37,6 +37,7 @@ set(INC
../../SceneGraph
../../../blender/blenkernel
../../../blender/blenlib
+ ../../../blender/gpu
../../../blender/makesdna
../../../../intern/container
../../../../intern/guardedalloc
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
index c79e1c23ef6..b3cee944880 100644
--- a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
@@ -2234,7 +2234,9 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject *gameobj, class RA
std::vector<int> vert_remap_array(numverts, 0);
for (mf = mface, tf = tface, i = 0; i < numpolys; mf++, tf++, i++) {
- if (tf->mode & TF_DYNAMIC) {
+ // 2.8x TODO: use GEMAT_NOPHYSICS.
+ // if (tf->mode & TF_DYNAMIC)
+ {
int flen;
if (mf->v4) {
@@ -2271,7 +2273,9 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject *gameobj, class RA
int *poly_index_pt = &m_polygonIndexArray[0];
for (mf = mface, tf = tface, i = 0; i < numpolys; mf++, tf++, i++) {
- if (tf->mode & TF_DYNAMIC) {
+ // 2.8x TODO: use GEMAT_NOPHYSICS.
+ // if (tf->mode & TF_DYNAMIC)
+ {
int origi = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, i) : i;
if (mf->v4) {
diff --git a/source/gameengine/Rasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/CMakeLists.txt
index c65fcac5161..fc7dc90e03b 100644
--- a/source/gameengine/Rasterizer/CMakeLists.txt
+++ b/source/gameengine/Rasterizer/CMakeLists.txt
@@ -31,6 +31,7 @@ set(INC
../../blender/makesdna
../../blender/blenlib
../../blender/blenkernel
+ ../../blender/gpu
../../blender/imbuf
../../../intern/container
../../../intern/glew-mx
diff --git a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp
index 82b26749fd1..f379e2eb486 100644
--- a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp
+++ b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp
@@ -24,7 +24,7 @@
* \ingroup bgerast
*/
-#define STRINGIFY(A) #A
+#include "BLI_utildefines.h"
#include "RAS_OpenGLFilters/RAS_Blur2DFilter.h"
#include "RAS_OpenGLFilters/RAS_Sharpen2DFilter.h"
@@ -43,7 +43,7 @@
#include "RAS_2DFilterManager.h"
#include <iostream>
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include <stdio.h>
diff --git a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp
index 2a736aa7deb..1d22d2debf9 100644
--- a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp
+++ b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp
@@ -233,10 +233,6 @@ Image *RAS_IPolyMaterial::GetBlenderImage() const
{
return NULL;
}
-MTexPoly *RAS_IPolyMaterial::GetMTexPoly() const
-{
- return NULL;
-}
unsigned int *RAS_IPolyMaterial::GetMCol() const
{
diff --git a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h
index a34f7a9b390..7023d305510 100644
--- a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h
+++ b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h
@@ -41,7 +41,6 @@
#endif
class RAS_IRasterizer;
-struct MTexPoly;
struct Material;
struct Image;
struct Scene;
@@ -167,7 +166,6 @@ public:
virtual Material* GetBlenderMaterial() const;
virtual Image* GetBlenderImage() const;
- virtual MTexPoly* GetMTexPoly() const;
virtual unsigned int* GetMCol() const;
virtual Scene* GetBlenderScene() const;
virtual void ReleaseMaterial();
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp
index b2d580161ca..71c8cfe745f 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp
@@ -30,7 +30,7 @@
#include <windows.h>
#endif // WIN32
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include "RAS_MaterialBucket.h"
#include "RAS_TexVert.h"
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp
index fff988a07c5..18254357f85 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp
@@ -25,7 +25,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include <stdio.h>
@@ -43,6 +43,7 @@
#include "DNA_lamp_types.h"
#include "DNA_scene_types.h"
+#include "GPU_lamp.h"
#include "GPU_material.h"
RAS_OpenGLLight::RAS_OpenGLLight(RAS_OpenGLRasterizer *ras)
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp
index e589bffcaf1..58b3c61bd05 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp
@@ -25,7 +25,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include <stdio.h>
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
index 3f82c513f7d..80c399fb256 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
@@ -35,7 +35,7 @@
#include "RAS_OpenGLRasterizer.h"
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include "RAS_ICanvas.h"
#include "RAS_Rect.h"
@@ -60,6 +60,7 @@
extern "C"{
#include "BLF_api.h"
#include "BKE_DerivedMesh.h"
+ #include "DNA_material_types.h"
}
@@ -710,7 +711,7 @@ void RAS_OpenGLRasterizer::IndexPrimitives_3DText(RAS_MeshSlot& ms,
glattrib = unit;
GPU_render_text(
- polymat->GetMTexPoly(), polymat->GetDrawingMode(), mytext, mytext.Length(), polymat->GetMCol(),
+ polymat->GetDrawingMode(), mytext, mytext.Length(), polymat->GetMCol(),
v_ptr, uv_ptr, glattrib);
ClearCachingInfo();
@@ -781,33 +782,6 @@ static int CheckMaterialDM(int matnr, void *attribs)
return 1;
}
-static DMDrawOption CheckTexDM(MTexPoly *mtexpoly, const bool has_mcol, int matnr)
-{
-
- // index is the original face index, retrieve the polygon
- if (matnr == current_blmat_nr &&
- (mtexpoly == NULL || mtexpoly->tpage == current_image)) {
- // must handle color.
- if (current_wireframe)
- return DM_DRAW_OPTION_NO_MCOL;
- if (current_ms->m_bObjectColor) {
- MT_Vector4& rgba = current_ms->m_RGBAcolor;
- glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]);
- // don't use mcol
- return DM_DRAW_OPTION_NO_MCOL;
- }
- if (!has_mcol) {
- // we have to set the color from the material
- unsigned char rgba[4];
- current_polymat->GetMaterialRGBAColor(rgba);
- glColor4ubv((const GLubyte *)rgba);
- return DM_DRAW_OPTION_NORMAL;
- }
- return DM_DRAW_OPTION_NORMAL;
- }
- return DM_DRAW_OPTION_SKIP;
-}
-
void RAS_OpenGLRasterizer::DrawDerivedMesh(class RAS_MeshSlot &ms)
{
// mesh data is in derived mesh
@@ -824,7 +798,10 @@ void RAS_OpenGLRasterizer::DrawDerivedMesh(class RAS_MeshSlot &ms)
else
this->SetCullFace(false);
- if (current_polymat->GetFlag() & RAS_BLENDERGLSL) {
+#if 0
+ if (current_polymat->GetFlag() & RAS_BLENDERGLSL)
+#endif
+ {
// GetMaterialIndex return the original mface material index,
// increment by 1 to match what derived mesh is doing
current_blmat_nr = current_polymat->GetMaterialIndex()+1;
@@ -839,11 +816,6 @@ void RAS_OpenGLRasterizer::DrawDerivedMesh(class RAS_MeshSlot &ms)
int current_blend_mode = GPU_get_material_alpha_blend();
ms.m_pDerivedMesh->drawFacesGLSL(ms.m_pDerivedMesh, CheckMaterialDM);
GPU_set_material_alpha_blend(current_blend_mode);
- } else {
- //ms.m_pDerivedMesh->drawMappedFacesTex(ms.m_pDerivedMesh, CheckTexfaceDM, mcol);
- current_blmat_nr = current_polymat->GetMaterialIndex();
- current_image = current_polymat->GetBlenderImage();
- ms.m_pDerivedMesh->drawFacesTex(ms.m_pDerivedMesh, CheckTexDM, NULL, NULL, DM_DRAW_USE_ACTIVE_UV);
}
}
@@ -994,8 +966,8 @@ void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat,
}
bool negX = (scale[0] < 0.0f);
- bool negY = (scale[0] < 0.0f);
- bool negZ = (scale[0] < 0.0f);
+ bool negY = (scale[1] < 0.0f);
+ bool negZ = (scale[2] < 0.0f);
if (negX || negY || negZ) {
m_viewmatrix.tscale((negX)?-1.0f:1.0f, (negY)?-1.0f:1.0f, (negZ)?-1.0f:1.0f, 1.0);
}
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp
index d54b3232067..26b956cd74e 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp
@@ -25,7 +25,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include <stdio.h>
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp
index cf77ebfbeb9..f980116f5f8 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp
@@ -27,7 +27,7 @@
#include "RAS_StorageVA.h"
-#include "glew-mx.h"
+#include "GPU_glew.h"
RAS_StorageVA::RAS_StorageVA(int *texco_num, RAS_IRasterizer::TexCoGen *texco, int *attrib_num, RAS_IRasterizer::TexCoGen *attrib, int *attrib_layer) :
m_drawingmode(RAS_IRasterizer::KX_TEXTURED),
@@ -171,7 +171,7 @@ void RAS_StorageVA::TexCoordPtr(const RAS_TexVert *tv)
glVertexAttribPointerARB(unit, 4, GL_FLOAT, GL_FALSE, sizeof(RAS_TexVert), tv->getTangent());
break;
case RAS_IRasterizer::RAS_TEXCO_VCOL:
- glVertexAttribPointerARB(unit, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(RAS_TexVert), tv->getRGBA());
+ glVertexAttribPointerARB(unit, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(RAS_TexVert), tv->getRGBA());
break;
default:
break;
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp
index cad5b5a508e..4ba5882a46e 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp
@@ -28,7 +28,7 @@
#include "RAS_StorageVBO.h"
#include "RAS_MeshObject.h"
-#include "glew-mx.h"
+#include "GPU_glew.h"
VBO::VBO(RAS_DisplayArray *data, unsigned int indices)
{
@@ -149,6 +149,9 @@ void VBO::Draw(int texco_num, RAS_IRasterizer::TexCoGen* texco, int attrib_num,
glVertexAttribPointerARB(unit, 4, GL_FLOAT, GL_FALSE, this->stride, this->tangent_offset);
glEnableVertexAttribArrayARB(unit);
break;
+ case RAS_IRasterizer::RAS_TEXCO_VCOL:
+ glVertexAttribPointerARB(unit, 4, GL_UNSIGNED_BYTE, GL_TRUE, this->stride, this->color_offset);
+ glEnableVertexAttribArrayARB(unit);
default:
break;
}
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h
index 4c8e4a8931c..c82b6a3206d 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h
@@ -29,7 +29,7 @@
#define __KX_VERTEXBUFFEROBJECTSTORAGE
#include <map>
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include "RAS_IStorage.h"
#include "RAS_IRasterizer.h"
diff --git a/source/gameengine/VideoTexture/FilterColor.cpp b/source/gameengine/VideoTexture/FilterColor.cpp
index eed84a8580c..15a7e9e4cd1 100644
--- a/source/gameengine/VideoTexture/FilterColor.cpp
+++ b/source/gameengine/VideoTexture/FilterColor.cpp
@@ -68,7 +68,7 @@ PyTypeObject FilterGrayType =
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
- "Filter for gray scale effect", /* tp_doc */
+ "Filter for grayscale effect", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
diff --git a/source/gameengine/VideoTexture/FilterColor.h b/source/gameengine/VideoTexture/FilterColor.h
index 350f7270874..d042863d7e8 100644
--- a/source/gameengine/VideoTexture/FilterColor.h
+++ b/source/gameengine/VideoTexture/FilterColor.h
@@ -36,7 +36,7 @@
#include "FilterBase.h"
-/// pixel filter for gray scale
+/// pixel filter for grayscale
class FilterGray : public FilterBase
{
public:
@@ -53,7 +53,7 @@ protected:
// calculate gray value
unsigned int gray = (28 * (VT_B(val)) + 151 * (VT_G(val))
+ 77 * (VT_R(val))) >> 8;
- // return gray scale value
+ // return grayscale value
VT_R(val) = gray;
VT_G(val) = gray;
VT_B(val) = gray;
diff --git a/source/gameengine/VideoTexture/ImageBase.cpp b/source/gameengine/VideoTexture/ImageBase.cpp
index 0db1fa293da..b91a312a5d7 100644
--- a/source/gameengine/VideoTexture/ImageBase.cpp
+++ b/source/gameengine/VideoTexture/ImageBase.cpp
@@ -43,7 +43,7 @@ extern "C" {
#include "Exception.h"
-#if (defined(WIN32) || defined(WIN64)) && !defined(FREE_WINDOWS)
+#if (defined(WIN32) || defined(WIN64))
#define strcasecmp _stricmp
#endif
diff --git a/source/gameengine/VideoTexture/ImageBase.h b/source/gameengine/VideoTexture/ImageBase.h
index 4c9fc5a58fb..5a09c9a67b3 100644
--- a/source/gameengine/VideoTexture/ImageBase.h
+++ b/source/gameengine/VideoTexture/ImageBase.h
@@ -40,7 +40,7 @@
#include "FilterBase.h"
-#include "glew-mx.h"
+#include "GPU_glew.h"
// forward declarations
struct PyImage;
diff --git a/source/gameengine/VideoTexture/ImageRender.cpp b/source/gameengine/VideoTexture/ImageRender.cpp
index 9991bf42a9f..57062343b67 100644
--- a/source/gameengine/VideoTexture/ImageRender.cpp
+++ b/source/gameengine/VideoTexture/ImageRender.cpp
@@ -36,7 +36,7 @@
#include <math.h>
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include "KX_PythonInit.h"
#include "DNA_scene_types.h"
@@ -734,6 +734,7 @@ ImageRender::ImageRender (KX_Scene *scene, KX_GameObject *observer, KX_GameObjec
m_done(false),
m_scene(scene),
m_offscreen(NULL),
+ m_sync(NULL),
m_observer(observer),
m_mirror(mirror),
m_clip(100.f)
diff --git a/source/gameengine/VideoTexture/ImageViewport.cpp b/source/gameengine/VideoTexture/ImageViewport.cpp
index 8852c190053..ad3d8875e28 100644
--- a/source/gameengine/VideoTexture/ImageViewport.cpp
+++ b/source/gameengine/VideoTexture/ImageViewport.cpp
@@ -33,7 +33,7 @@
#include "EXP_PyObjectPlus.h"
#include <structmember.h>
-#include "glew-mx.h"
+#include "GPU_glew.h"
#include "KX_PythonInit.h"
#include "RAS_ICanvas.h"
diff --git a/source/gameengine/VideoTexture/Texture.cpp b/source/gameengine/VideoTexture/Texture.cpp
index bb995747360..48dc4c705bf 100644
--- a/source/gameengine/VideoTexture/Texture.cpp
+++ b/source/gameengine/VideoTexture/Texture.cpp
@@ -55,7 +55,7 @@
#include "Exception.h"
#include <memory.h>
-#include "glew-mx.h"
+#include "GPU_glew.h"
extern "C" {
#include "IMB_imbuf.h"
diff --git a/source/gameengine/VideoTexture/VideoDeckLink.cpp b/source/gameengine/VideoTexture/VideoDeckLink.cpp
index 4f5e34896fc..c588a4b33cf 100644
--- a/source/gameengine/VideoTexture/VideoDeckLink.cpp
+++ b/source/gameengine/VideoTexture/VideoDeckLink.cpp
@@ -544,12 +544,12 @@ HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::QueryInterface(REFIID /*iid*/,
ULONG STDMETHODCALLTYPE PinnedMemoryAllocator::AddRef(void)
{
- return atomic_add_uint32(&mRefCount, 1U);
+ return atomic_add_and_fetch_uint32(&mRefCount, 1U);
}
ULONG STDMETHODCALLTYPE PinnedMemoryAllocator::Release(void)
{
- uint32_t newCount = atomic_sub_uint32(&mRefCount, 1U);
+ uint32_t newCount = atomic_sub_and_fetch_uint32(&mRefCount, 1U);
if (newCount == 0)
delete this;
return (ULONG)newCount;
diff --git a/source/gameengine/VideoTexture/VideoDeckLink.h b/source/gameengine/VideoTexture/VideoDeckLink.h
index 50099d2ead4..d5419176691 100644
--- a/source/gameengine/VideoTexture/VideoDeckLink.h
+++ b/source/gameengine/VideoTexture/VideoDeckLink.h
@@ -47,7 +47,7 @@ extern "C" {
#include "BLI_threads.h"
#include "BLI_blenlib.h"
}
-#include "GL/glew.h"
+#include "GPU_glew.h"
#ifdef WIN32
#include "dvpapi.h"
#endif
diff --git a/source/tools b/source/tools
-Subproject 373945d0978b6601c55c9d5879e0f488b18515c
+Subproject b11375e89061303401376f7aeae42ac2fd64692